From 2c6dd541ef5f6dd9c8a8de018c100eaa064aff58 Mon Sep 17 00:00:00 2001 From: David Blass Date: Wed, 1 May 2024 20:54:11 -0400 Subject: [PATCH] refactor: fix some .d.ts output, avoid writing attest snapshots early (#939) --- .github/actions/setup/action.yml | 4 +-- .github/workflows/pr.yml | 6 ---- ark/attest/__tests__/demo.test.ts | 6 +--- ark/attest/__tests__/utils.ts | 4 +-- ark/attest/bench/baseline.ts | 9 ++++-- ark/attest/cache/snapshots.ts | 44 +++++++++------------------ ark/attest/main.ts | 4 +-- ark/attest/package.json | 2 +- ark/repo/.eslintrc.cjs | 8 ++++- ark/repo/mocha.globalSetup.ts | 2 ++ ark/schema/constraints/constraint.ts | 3 +- ark/schema/constraints/props/index.ts | 6 +++- ark/schema/node.ts | 29 +++++++++--------- ark/schema/schema.ts | 17 ++++++----- ark/schema/shared/errors.ts | 6 ++-- ark/type/parser/objectLiteral.ts | 19 +++++++----- ark/type/parser/tuple.ts | 32 +++++++++---------- package.json | 2 +- tsconfig.json | 2 +- 19 files changed, 101 insertions(+), 104 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 14a1535004..cdf847ba7f 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -9,9 +9,9 @@ runs: using: composite steps: - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: - version: 8.3.1 + version: 9 - name: Setup Node (${{ inputs.node }}) uses: actions/setup-node@v3 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index b684715292..ad15a2ef48 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -24,12 +24,6 @@ jobs: - name: prChecks run: pnpm prChecks - - name: TSC Diagnostics Diff - uses: beerose/tsc-diff-action@v0.0.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - leave-comment: true - compatibility: needs: core timeout-minutes: 20 diff --git a/ark/attest/__tests__/demo.test.ts b/ark/attest/__tests__/demo.test.ts index c4e5aba0aa..bd718e701b 100644 --- a/ark/attest/__tests__/demo.test.ts +++ b/ark/attest/__tests__/demo.test.ts @@ -1,8 +1,4 @@ -import { - attest, - contextualize, - getPrimaryTsVersionUnderTest -} from "@arktype/attest" +import { attest, contextualize } from "@arktype/attest" import { type } from "arktype" const o = { ark: "type" } as const diff --git a/ark/attest/__tests__/utils.ts b/ark/attest/__tests__/utils.ts index 0e1bd2dd7c..1339c8c6a9 100644 --- a/ark/attest/__tests__/utils.ts +++ b/ark/attest/__tests__/utils.ts @@ -1,11 +1,11 @@ -import { readFile, shell } from "@arktype/fs" +import { dirName, readFile, shell } from "@arktype/fs" import { copyFileSync, rmSync } from "node:fs" export const runThenGetContents = (templatePath: string): string => { const tempPath = templatePath + ".temp.ts" copyFileSync(templatePath, tempPath) try { - shell(`pnpm tsx ${tempPath}`) + shell(`node --import=tsx ${tempPath}`, { cwd: dirName() }) } catch (e) { console.error(e) } diff --git a/ark/attest/bench/baseline.ts b/ark/attest/bench/baseline.ts index 1c081625d3..f48afaf2e6 100644 --- a/ark/attest/bench/baseline.ts +++ b/ark/attest/bench/baseline.ts @@ -1,6 +1,9 @@ import { snapshot } from "@arktype/util" import process from "node:process" -import { queueSnapshotUpdate } from "../cache/snapshots.js" +import { + queueSnapshotUpdate, + writeSnapshotUpdatesOnExit +} from "../cache/snapshots.js" import type { BenchAssertionContext, BenchContext } from "./bench.js" import { stringifyMeasure, @@ -29,6 +32,8 @@ export const queueBaselineUpdateIfNeeded = ( snapFunctionName: ctx.kind, baselinePath: ctx.qualifiedPath }) + + if (ctx.kind === "types") writeSnapshotUpdatesOnExit() } /** Pretty print comparison and set the process.exitCode to 1 if delta threshold is exceeded */ @@ -69,4 +74,4 @@ const handleNegativeDelta = (formattedDelta: string, ctx: BenchContext) => { 1 )}! Consider setting a new baseline.` ) -} \ No newline at end of file +} diff --git a/ark/attest/cache/snapshots.ts b/ark/attest/cache/snapshots.ts index 5be8c08dc0..0f7b837be1 100644 --- a/ark/attest/cache/snapshots.ts +++ b/ark/attest/cache/snapshots.ts @@ -51,8 +51,15 @@ export const getSnapshotByName = ( */ export const queueSnapshotUpdate = (args: SnapshotArgs): void => { const config = getConfig() - writeSnapUpdate(config.defaultAssertionCachePath, args) - writeSnapshotUpdatesOnExit() + const path = config.defaultAssertionCachePath + if (existsSync(path)) { + const existing = readJson(path) + writeJson(path, { + ...existing, + updates: + Array.isArray(existing.updates) ? [...existing.updates, args] : [args] + }) + } else writeJson(path, { updates: [args] }) } export type QueuedUpdate = { @@ -112,38 +119,23 @@ export const writeSnapshotUpdatesOnExit = (): void => { const writeCachedInlineSnapshotUpdates = () => { const config = getConfig() - const updates: QueuedUpdate[] = [] - if (existsSync(config.assertionCacheDir)) - updates.push(...getQueuedUpdates(config.defaultAssertionCachePath)) - - writeUpdates(updates) - writeSnapUpdate(config.defaultAssertionCachePath) -} - -const writeSnapUpdate = (path: string, update?: SnapshotArgs) => { - const assertions = - existsSync(path) ? readJson(path) : { updates: [] as SnapshotArgs[] } + let snapshotData: SnapshotArgs[] | undefined - assertions.updates = - update !== undefined ? [...(assertions.updates ?? []), update] : [] + if (!existsSync(config.defaultAssertionCachePath)) return - writeJson(path, assertions) -} -const updateQueue = (queue: QueuedUpdate[], path: string) => { - let snapshotData: SnapshotArgs[] | undefined try { - snapshotData = readJson(path).updates + snapshotData = readJson(config.defaultAssertionCachePath).updates } catch { // If we can't read the snapshot, log an error and move onto the next update console.error( - `Unable to read snapshot data from expected location ${path}.` + `Unable to read snapshot data from expected location ${config.defaultAssertionCachePath}.` ) } if (snapshotData) { try { - snapshotData.forEach(snapshot => - queue.push(snapshotArgsToQueuedUpdate(snapshot)) + writeUpdates( + snapshotData.map(snapshot => snapshotArgsToQueuedUpdate(snapshot)) ) } catch (error) { // If writeInlineSnapshotToFile throws an error, log it and move on to the next update @@ -152,12 +144,6 @@ const updateQueue = (queue: QueuedUpdate[], path: string) => { } } -const getQueuedUpdates = (path: string) => { - const queuedUpdates: QueuedUpdate[] = [] - updateQueue(queuedUpdates, path) - return queuedUpdates -} - const snapshotArgsToQueuedUpdate = ({ position, serializedValue, diff --git a/ark/attest/main.ts b/ark/attest/main.ts index 557abdbd53..14557f43c4 100644 --- a/ark/attest/main.ts +++ b/ark/attest/main.ts @@ -2,8 +2,8 @@ export { caller, type CallerOfOptions } from "@arktype/fs" export { attest } from "./assert/attest.js" export { bench } from "./bench/bench.js" export { - getBenchAssertionsAtPosition as getTypeBenchAssertionsAtPosition, - getTypeAssertionsAtPosition as getTypeRelationshipAssertionsAtPosition + getBenchAssertionsAtPosition, + getTypeAssertionsAtPosition } from "./cache/getCachedAssertions.js" export type { ArgAssertionData, diff --git a/ark/attest/package.json b/ark/attest/package.json index 4b29c1e8ea..a4c3a69495 100644 --- a/ark/attest/package.json +++ b/ark/attest/package.json @@ -39,7 +39,7 @@ "@typescript/analyze-trace": "0.10.1" }, "devDependencies": { - "typescript": "5.5.0-beta" + "typescript": "5.4.5" }, "peerDependencies": { "typescript": "*" diff --git a/ark/repo/.eslintrc.cjs b/ark/repo/.eslintrc.cjs index a15354cf04..8142b92e02 100644 --- a/ark/repo/.eslintrc.cjs +++ b/ark/repo/.eslintrc.cjs @@ -118,7 +118,13 @@ module.exports = defineConfig({ "no-case-declarations": "off", /** In tests we use expect-error constantly, but in src if we * ever have to there should be an explanation */ - "@typescript-eslint/ban-ts-comment": "warn" + "@typescript-eslint/ban-ts-comment": [ + "warn", + { + // some errors are environment dependent or e.g. don't appear in build output + "ts-ignore": "allow-with-description" + } + ] }, overrides: [ { diff --git a/ark/repo/mocha.globalSetup.ts b/ark/repo/mocha.globalSetup.ts index b73626e38a..70d2e57425 100644 --- a/ark/repo/mocha.globalSetup.ts +++ b/ark/repo/mocha.globalSetup.ts @@ -1,5 +1,7 @@ import { cleanup, setup } from "@arktype/attest" +process.env.TZ = "America/New_York" + export const mochaGlobalSetup = setup export const mochaGlobalTeardown = cleanup diff --git a/ark/schema/constraints/constraint.ts b/ark/schema/constraints/constraint.ts index ac599bb226..2088092f24 100644 --- a/ark/schema/constraints/constraint.ts +++ b/ark/schema/constraints/constraint.ts @@ -17,7 +17,8 @@ export interface BaseConstraintDeclaration extends RawNodeDeclaration { } export abstract class RawConstraint< - /** @ts-expect-error allow instantiation assignment to the base type */ + /** uses -ignore rather than -expect-error because this is not an error in .d.ts + * @ts-ignore allow instantiation assignment to the base type */ out d extends BaseConstraintDeclaration = BaseConstraintDeclaration > extends RawNode { readonly [arkKind] = "constraint" diff --git a/ark/schema/constraints/props/index.ts b/ark/schema/constraints/props/index.ts index d7681505fd..f3dfb10528 100644 --- a/ark/schema/constraints/props/index.ts +++ b/ark/schema/constraints/props/index.ts @@ -5,6 +5,7 @@ import { } from "@arktype/util" import type { Node, SchemaDef } from "../../node.js" import type { RawSchema } from "../../schema.js" +import type { UnitNode } from "../../schemas/unit.js" import type { BaseMeta, declareNode } from "../../shared/declare.js" import { Disjoint } from "../../shared/disjoint.js" import { implementNode, type SchemaKind } from "../../shared/implement.js" @@ -47,7 +48,10 @@ export const indexImplementation = implementNode({ const key = ctx.$.schema(def) if (!key.extends(ctx.$.keywords.propertyKey)) return throwParseError(writeInvalidPropertyKeyMessage(key.expression)) - const enumerableBranches = key.branches.filter(b => b.hasKind("unit")) + // TODO: explicit manual annotation once we can upgrade to 5.5 + const enumerableBranches = key.branches.filter((b): b is UnitNode => + b.hasKind("unit") + ) if (enumerableBranches.length) { return throwParseError( writeEnumerableIndexBranches( diff --git a/ark/schema/node.ts b/ark/schema/node.ts index 58c9861ab6..e263d38e0a 100644 --- a/ark/schema/node.ts +++ b/ark/schema/node.ts @@ -1,15 +1,15 @@ import { Callable, - type Dict, - type Guardable, - type Json, - type conform, flatMorph, includes, isArray, - type listable, shallowClone, - throwError + throwError, + type Dict, + type Guardable, + type Json, + type conform, + type listable } from "@arktype/util" import type { RawConstraint } from "./constraints/constraint.js" import type { PredicateNode } from "./constraints/predicate.js" @@ -36,19 +36,19 @@ import type { attachmentsOf } from "./shared/declare.js" import { + basisKinds, + constraintKinds, + precedenceOfKind, + propKinds, + refinementKinds, + schemaKinds, type BasisKind, type NodeKind, type OpenNodeKind, type PropKind, type RefinementKind, type SchemaKind, - type UnknownAttachments, - basisKinds, - constraintKinds, - precedenceOfKind, - propKinds, - refinementKinds, - schemaKinds + type UnknownAttachments } from "./shared/implement.js" import { TraversalContext, @@ -59,7 +59,8 @@ import { export type UnknownNode = RawNode | Schema export abstract class RawNode< - /** @ts-expect-error allow instantiation assignment to the base type */ + /** uses -ignore rather than -expect-error because this is not an error in .d.ts + * @ts-ignore allow instantiation assignment to the base type */ out d extends RawNodeDeclaration = RawNodeDeclaration > extends Callable<(data: d["prerequisite"]) => unknown, attachmentsOf> { constructor(public attachments: UnknownAttachments) { diff --git a/ark/schema/schema.ts b/ark/schema/schema.ts index 9c0eb549d9..254e35bff3 100644 --- a/ark/schema/schema.ts +++ b/ark/schema/schema.ts @@ -1,17 +1,17 @@ import { + throwParseError, type Callable, type Json, - type conform, - throwParseError + type conform } from "@arktype/util" import type { constrain } from "./constraints/ast.js" import type { Predicate } from "./constraints/predicate.js" import { - type PrimitiveConstraintKind, - throwInvalidOperandError + throwInvalidOperandError, + type PrimitiveConstraintKind } from "./constraints/util.js" import type { NodeDef, reducibleKindOf } from "./kinds.js" -import { type Node, RawNode } from "./node.js" +import { RawNode, type Node } from "./node.js" import type { constraintKindOf } from "./schemas/intersection.js" import type { Morph, @@ -29,9 +29,9 @@ import { Disjoint } from "./shared/disjoint.js" import { ArkErrors } from "./shared/errors.js" import type { NodeKind, SchemaKind, kindRightOf } from "./shared/implement.js" import { - type inferIntersection, intersectNodesRoot, - pipeNodesRoot + pipeNodesRoot, + type inferIntersection } from "./shared/intersections.js" import { arkKind, @@ -55,7 +55,8 @@ export type TypeOnlySchemaKey = | "tOut" export abstract class RawSchema< - /** @ts-expect-error allow instantiation assignment to the base type */ + /** uses -ignore rather than -expect-error because this is not an error in .d.ts + * @ts-ignore allow instantiation assignment to the base type */ out d extends RawSchemaDeclaration = RawSchemaDeclaration > extends RawNode diff --git a/ark/schema/shared/errors.ts b/ark/schema/shared/errors.ts index 87407a3702..1a2ef56ddc 100644 --- a/ark/schema/shared/errors.ts +++ b/ark/schema/shared/errors.ts @@ -9,10 +9,8 @@ import type { NodeKind } from "./implement.js" import type { TraversalContext } from "./traversal.js" import { arkKind, pathToPropString, type TraversalPath } from "./utils.js" -export const throwArkError = ( - ...args: ConstructorParameters -): never => { - throw new ArkError(...args) +export const throwArkError = (message: string): never => { + throw new ArkError(message) } export class ArkError extends TypeError { diff --git a/ark/type/parser/objectLiteral.ts b/ark/type/parser/objectLiteral.ts index 92d13e5d31..b6367b558e 100644 --- a/ark/type/parser/objectLiteral.ts +++ b/ark/type/parser/objectLiteral.ts @@ -1,19 +1,20 @@ import { + tsKeywords, type NodeDef, type RawSchema, - tsKeywords, + type UnitNode, type writeInvalidPropertyKeyMessage } from "@arktype/schema" import { + printable, + spliterate, + stringAndSymbolicEntriesOf, + throwParseError, type Dict, type ErrorMessage, type Key, type merge, - printable, - type show, - spliterate, - stringAndSymbolicEntriesOf, - throwParseError + type show } from "@arktype/util" import type { ParseContext } from "../scope.js" import type { inferDefinition, validateDefinition } from "./definition.js" @@ -62,8 +63,10 @@ export const parseObjectLiteral = (def: Dict, ctx: ParseContext): RawSchema => { const value = ctx.$.parse(entry.value, ctx) // extract enumerable named props from the index signature - const [enumerable, nonEnumerable] = spliterate(key.branches, k => - k.hasKind("unit") + // TODO: remove explicit annotation once we can use TS 5.5 + const [enumerable, nonEnumerable] = spliterate( + key.branches, + (k): k is UnitNode => k.hasKind("unit") ) if (enumerable.length) { diff --git a/ark/type/parser/tuple.ts b/ark/type/parser/tuple.ts index c3d1b026a9..433083d3bf 100644 --- a/ark/type/parser/tuple.ts +++ b/ark/type/parser/tuple.ts @@ -1,4 +1,7 @@ import { + jsObjects, + makeRootAndArrayPropertiesMutable, + tsKeywords, type BaseMeta, type Morph, type MutableInner, @@ -12,22 +15,19 @@ import { type distillConstrainableOut, type inferIntersection, type inferMorphOut, - type inferNarrow, - jsObjects, - makeRootAndArrayPropertiesMutable, - tsKeywords + type inferNarrow } from "@arktype/schema" import { + append, + objectKindOrDomainOf, + throwParseError, type BuiltinObjectKind, type Constructor, type Domain, type ErrorMessage, - append, type array, type conform, - objectKindOrDomainOf, - type show, - throwParseError + type show } from "@arktype/util" import type { ParseContext } from "../scope.js" import type { inferDefinition, validateDefinition } from "./definition.js" @@ -194,15 +194,15 @@ export type validateTuple = ] : validateTupleLiteral -export type validateTupleLiteral = Readonly< - parseSequence["validated"] -> +export type validateTupleLiteral = + parseSequence extends infer s extends SequenceParseState ? + Readonly + : never -type inferTupleLiteral = parseSequence< - def, - $, - args ->["inferred"] +type inferTupleLiteral = + parseSequence extends infer s extends SequenceParseState ? + s["inferred"] + : never type SequenceParseState = { unscanned: array diff --git a/package.json b/package.json index ae5b630053..c12ea81959 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "c8": "9.1.0", "knip": "5.9.4", "tsx": "4.7.2", - "typescript": "5.5.0-beta", + "typescript": "5.4.5", "mocha": "10.4.0", "@types/mocha": "10.0.6" }, diff --git a/tsconfig.json b/tsconfig.json index 224f4d7dc3..05cc6df32b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,5 +23,5 @@ }, "types": ["mocha", "node"] }, - "exclude": ["**/out", "node_modules", "./ark/docs", "./ark/repo"] + "exclude": ["**/out", "**/node_modules", "./ark/docs", "./ark/repo"] }