@nekostack/schema 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +422 -0
- package/LICENSE +202 -0
- package/README.md +656 -0
- package/dist/src/builders/array.d.ts +12 -0
- package/dist/src/builders/array.d.ts.map +1 -0
- package/dist/src/builders/array.js +29 -0
- package/dist/src/builders/array.js.map +1 -0
- package/dist/src/builders/object.d.ts +62 -0
- package/dist/src/builders/object.d.ts.map +1 -0
- package/dist/src/builders/object.js +263 -0
- package/dist/src/builders/object.js.map +1 -0
- package/dist/src/builders/primitives.d.ts +37 -0
- package/dist/src/builders/primitives.d.ts.map +1 -0
- package/dist/src/builders/primitives.js +125 -0
- package/dist/src/builders/primitives.js.map +1 -0
- package/dist/src/builders/s.d.ts +27 -0
- package/dist/src/builders/s.d.ts.map +1 -0
- package/dist/src/builders/s.js +39 -0
- package/dist/src/builders/s.js.map +1 -0
- package/dist/src/builders/schema.d.ts +70 -0
- package/dist/src/builders/schema.d.ts.map +1 -0
- package/dist/src/builders/schema.js +98 -0
- package/dist/src/builders/schema.js.map +1 -0
- package/dist/src/cli-integration.d.ts +43 -0
- package/dist/src/cli-integration.d.ts.map +1 -0
- package/dist/src/cli-integration.js +48 -0
- package/dist/src/cli-integration.js.map +1 -0
- package/dist/src/errors/issue.d.ts +34 -0
- package/dist/src/errors/issue.d.ts.map +1 -0
- package/dist/src/errors/issue.js +89 -0
- package/dist/src/errors/issue.js.map +1 -0
- package/dist/src/generators/errors.d.ts +31 -0
- package/dist/src/generators/errors.d.ts.map +1 -0
- package/dist/src/generators/errors.js +34 -0
- package/dist/src/generators/errors.js.map +1 -0
- package/dist/src/generators/header.d.ts +42 -0
- package/dist/src/generators/header.d.ts.map +1 -0
- package/dist/src/generators/header.js +43 -0
- package/dist/src/generators/header.js.map +1 -0
- package/dist/src/generators/json-schema-meta.d.ts +36 -0
- package/dist/src/generators/json-schema-meta.d.ts.map +1 -0
- package/dist/src/generators/json-schema-meta.js +35 -0
- package/dist/src/generators/json-schema-meta.js.map +1 -0
- package/dist/src/generators/json-schema.d.ts +26 -0
- package/dist/src/generators/json-schema.d.ts.map +1 -0
- package/dist/src/generators/json-schema.js +88 -0
- package/dist/src/generators/json-schema.js.map +1 -0
- package/dist/src/generators/openapi.d.ts +33 -0
- package/dist/src/generators/openapi.d.ts.map +1 -0
- package/dist/src/generators/openapi.js +61 -0
- package/dist/src/generators/openapi.js.map +1 -0
- package/dist/src/generators/schema-fragment.d.ts +55 -0
- package/dist/src/generators/schema-fragment.d.ts.map +1 -0
- package/dist/src/generators/schema-fragment.js +253 -0
- package/dist/src/generators/schema-fragment.js.map +1 -0
- package/dist/src/generators/ts.d.ts +19 -0
- package/dist/src/generators/ts.d.ts.map +1 -0
- package/dist/src/generators/ts.js +252 -0
- package/dist/src/generators/ts.js.map +1 -0
- package/dist/src/generators/types.d.ts +96 -0
- package/dist/src/generators/types.d.ts.map +1 -0
- package/dist/src/generators/types.js +10 -0
- package/dist/src/generators/types.js.map +1 -0
- package/dist/src/generators/version.d.ts +11 -0
- package/dist/src/generators/version.d.ts.map +1 -0
- package/dist/src/generators/version.js +11 -0
- package/dist/src/generators/version.js.map +1 -0
- package/dist/src/generators/zod-mapping.d.ts +90 -0
- package/dist/src/generators/zod-mapping.d.ts.map +1 -0
- package/dist/src/generators/zod-mapping.js +174 -0
- package/dist/src/generators/zod-mapping.js.map +1 -0
- package/dist/src/generators/zod.d.ts +17 -0
- package/dist/src/generators/zod.d.ts.map +1 -0
- package/dist/src/generators/zod.js +118 -0
- package/dist/src/generators/zod.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +43 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ir/hash.d.ts +19 -0
- package/dist/src/ir/hash.d.ts.map +1 -0
- package/dist/src/ir/hash.js +22 -0
- package/dist/src/ir/hash.js.map +1 -0
- package/dist/src/ir/nodes.d.ts +121 -0
- package/dist/src/ir/nodes.d.ts.map +1 -0
- package/dist/src/ir/nodes.js +14 -0
- package/dist/src/ir/nodes.js.map +1 -0
- package/dist/src/ir/serialize.d.ts +8 -0
- package/dist/src/ir/serialize.d.ts.map +1 -0
- package/dist/src/ir/serialize.js +23 -0
- package/dist/src/ir/serialize.js.map +1 -0
- package/dist/src/migrations/build-migration-registry.d.ts +46 -0
- package/dist/src/migrations/build-migration-registry.d.ts.map +1 -0
- package/dist/src/migrations/build-migration-registry.js +134 -0
- package/dist/src/migrations/build-migration-registry.js.map +1 -0
- package/dist/src/migrations/handlers/list.d.ts +35 -0
- package/dist/src/migrations/handlers/list.d.ts.map +1 -0
- package/dist/src/migrations/handlers/list.js +55 -0
- package/dist/src/migrations/handlers/list.js.map +1 -0
- package/dist/src/migrations/handlers/plan.d.ts +26 -0
- package/dist/src/migrations/handlers/plan.d.ts.map +1 -0
- package/dist/src/migrations/handlers/plan.js +28 -0
- package/dist/src/migrations/handlers/plan.js.map +1 -0
- package/dist/src/migrations/handlers/stub.d.ts +22 -0
- package/dist/src/migrations/handlers/stub.d.ts.map +1 -0
- package/dist/src/migrations/handlers/stub.js +24 -0
- package/dist/src/migrations/handlers/stub.js.map +1 -0
- package/dist/src/migrations/handlers/verify.d.ts +25 -0
- package/dist/src/migrations/handlers/verify.d.ts.map +1 -0
- package/dist/src/migrations/handlers/verify.js +27 -0
- package/dist/src/migrations/handlers/verify.js.map +1 -0
- package/dist/src/migrations/parse-provenance.d.ts +78 -0
- package/dist/src/migrations/parse-provenance.d.ts.map +1 -0
- package/dist/src/migrations/parse-provenance.js +157 -0
- package/dist/src/migrations/parse-provenance.js.map +1 -0
- package/dist/src/migrations/plan-migration.d.ts +50 -0
- package/dist/src/migrations/plan-migration.d.ts.map +1 -0
- package/dist/src/migrations/plan-migration.js +256 -0
- package/dist/src/migrations/plan-migration.js.map +1 -0
- package/dist/src/migrations/stub.d.ts +55 -0
- package/dist/src/migrations/stub.d.ts.map +1 -0
- package/dist/src/migrations/stub.js +201 -0
- package/dist/src/migrations/stub.js.map +1 -0
- package/dist/src/migrations/types.d.ts +297 -0
- package/dist/src/migrations/types.d.ts.map +1 -0
- package/dist/src/migrations/types.js +28 -0
- package/dist/src/migrations/types.js.map +1 -0
- package/dist/src/migrations/verify-provenance.d.ts +46 -0
- package/dist/src/migrations/verify-provenance.d.ts.map +1 -0
- package/dist/src/migrations/verify-provenance.js +158 -0
- package/dist/src/migrations/verify-provenance.js.map +1 -0
- package/dist/src/registry/build-registry.d.ts +65 -0
- package/dist/src/registry/build-registry.d.ts.map +1 -0
- package/dist/src/registry/build-registry.js +172 -0
- package/dist/src/registry/build-registry.js.map +1 -0
- package/dist/src/registry/diff.d.ts +25 -0
- package/dist/src/registry/diff.d.ts.map +1 -0
- package/dist/src/registry/diff.js +497 -0
- package/dist/src/registry/diff.js.map +1 -0
- package/dist/src/registry/handlers/check.d.ts +57 -0
- package/dist/src/registry/handlers/check.d.ts.map +1 -0
- package/dist/src/registry/handlers/check.js +181 -0
- package/dist/src/registry/handlers/check.js.map +1 -0
- package/dist/src/registry/handlers/diff.d.ts +33 -0
- package/dist/src/registry/handlers/diff.d.ts.map +1 -0
- package/dist/src/registry/handlers/diff.js +61 -0
- package/dist/src/registry/handlers/diff.js.map +1 -0
- package/dist/src/registry/handlers/generate.d.ts +87 -0
- package/dist/src/registry/handlers/generate.d.ts.map +1 -0
- package/dist/src/registry/handlers/generate.js +223 -0
- package/dist/src/registry/handlers/generate.js.map +1 -0
- package/dist/src/registry/handlers/list.d.ts +36 -0
- package/dist/src/registry/handlers/list.d.ts.map +1 -0
- package/dist/src/registry/handlers/list.js +84 -0
- package/dist/src/registry/handlers/list.js.map +1 -0
- package/dist/src/registry/parse-provenance.d.ts +63 -0
- package/dist/src/registry/parse-provenance.d.ts.map +1 -0
- package/dist/src/registry/parse-provenance.js +182 -0
- package/dist/src/registry/parse-provenance.js.map +1 -0
- package/dist/src/registry/source-hash.d.ts +28 -0
- package/dist/src/registry/source-hash.d.ts.map +1 -0
- package/dist/src/registry/source-hash.js +32 -0
- package/dist/src/registry/source-hash.js.map +1 -0
- package/dist/src/registry/types.d.ts +185 -0
- package/dist/src/registry/types.d.ts.map +1 -0
- package/dist/src/registry/types.js +22 -0
- package/dist/src/registry/types.js.map +1 -0
- package/dist/src/runtime/compile.d.ts +38 -0
- package/dist/src/runtime/compile.d.ts.map +1 -0
- package/dist/src/runtime/compile.js +45 -0
- package/dist/src/runtime/compile.js.map +1 -0
- package/dist/src/runtime/errors.d.ts +25 -0
- package/dist/src/runtime/errors.d.ts.map +1 -0
- package/dist/src/runtime/errors.js +43 -0
- package/dist/src/runtime/errors.js.map +1 -0
- package/dist/src/runtime/normalize-issues.d.ts +65 -0
- package/dist/src/runtime/normalize-issues.d.ts.map +1 -0
- package/dist/src/runtime/normalize-issues.js +208 -0
- package/dist/src/runtime/normalize-issues.js.map +1 -0
- package/dist/src/runtime/parse.d.ts +62 -0
- package/dist/src/runtime/parse.d.ts.map +1 -0
- package/dist/src/runtime/parse.js +107 -0
- package/dist/src/runtime/parse.js.map +1 -0
- package/dist/src/runtime/strip-defaults.d.ts +51 -0
- package/dist/src/runtime/strip-defaults.d.ts.map +1 -0
- package/dist/src/runtime/strip-defaults.js +81 -0
- package/dist/src/runtime/strip-defaults.js.map +1 -0
- package/dist/src/runtime/zod-compile.d.ts +27 -0
- package/dist/src/runtime/zod-compile.d.ts.map +1 -0
- package/dist/src/runtime/zod-compile.js +92 -0
- package/dist/src/runtime/zod-compile.js.map +1 -0
- package/dist/src/types.d.ts +116 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/docs/ABSENCE_SEMANTICS.md +37 -0
- package/docs/BENCHMARKS.md +64 -0
- package/docs/COMPOSITION.md +206 -0
- package/docs/DIFF_CLASSIFICATION.md +137 -0
- package/docs/EXAMPLES.md +221 -0
- package/docs/HEADER_FORMAT.md +66 -0
- package/docs/INVARIANTS.md +58 -0
- package/docs/IR_CONTRACT.md +67 -0
- package/docs/ISSUE_CODES.md +99 -0
- package/docs/JSON_SCHEMA_MAPPING.md +149 -0
- package/docs/MIGRATIONS.md +406 -0
- package/docs/MIGRATION_GUIDE.md +150 -0
- package/docs/OPENAPI_MAPPING.md +66 -0
- package/docs/REGISTRY.md +336 -0
- package/docs/RUNTIME.md +279 -0
- package/docs/SCOPE.md +119 -0
- package/docs/USAGE.md +376 -0
- package/docs/ZOD_MODIFIER_ORDERING.md +77 -0
- package/package.json +45 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate-only IR variant (Decision #8 of v0.6 plan).
|
|
3
|
+
*
|
|
4
|
+
* `stripDefaultsForValidate(node)` produces a new `SchemaNode` tree
|
|
5
|
+
* with every default-bearing modifier removed and `optional: true`
|
|
6
|
+
* set at that same level. The original IR is not mutated (the builder
|
|
7
|
+
* deep-freezes the IR; this transform is non-destructive by
|
|
8
|
+
* construction).
|
|
9
|
+
*
|
|
10
|
+
* **Why both at once.** Per v0.1 (Invariant 4 + the absence-semantics
|
|
11
|
+
* table), `default(v)` means *input-optional + output-required* — a
|
|
12
|
+
* missing default-bearing field is a valid input. So `validate` (which
|
|
13
|
+
* returns `Result<s.input<S>>`, no fill) must (a) accept the absence,
|
|
14
|
+
* which means flipping `optional: true`, and (b) NOT fill the default
|
|
15
|
+
* value, which means dropping the `default` modifier. The combined
|
|
16
|
+
* "strip default + flip to optional" is the only rule consistent with
|
|
17
|
+
* both halves of the v0.1 absence-semantics contract for the validate
|
|
18
|
+
* path.
|
|
19
|
+
*
|
|
20
|
+
* **What stays.** `nullable` / `nullish` modifiers, refinements,
|
|
21
|
+
* metadata (`id`, `version`, `description`, `deprecated`), and every
|
|
22
|
+
* field's `unknownKeys` policy are preserved verbatim. This is a
|
|
23
|
+
* runtime compilation variant of the same schema, not a composition
|
|
24
|
+
* operation — schema-level identity (id / version / description) may
|
|
25
|
+
* matter for issue normalization downstream.
|
|
26
|
+
*
|
|
27
|
+
* **Recursion.** Object fields and array elements are walked
|
|
28
|
+
* recursively. Other composite kinds (`union`, `transform`,
|
|
29
|
+
* `recursiveRef`, `date`) are passed through unchanged here; the
|
|
30
|
+
* compile layer (`runtime/compile.ts` → `runtime/zod-compile.ts`)
|
|
31
|
+
* throws `UnsupportedNodeKindError` for those, so the strip transform
|
|
32
|
+
* does not need to gate them itself.
|
|
33
|
+
*
|
|
34
|
+
* The returned tree has different object identity from the original
|
|
35
|
+
* for every level that was touched. The compile cache keys on
|
|
36
|
+
* `SchemaNode` identity (Decision #7), so the validate variant is
|
|
37
|
+
* cached on its own slot automatically — no second `WeakMap` is
|
|
38
|
+
* needed at this layer.
|
|
39
|
+
*/
|
|
40
|
+
import type { SchemaNode } from "../ir/nodes.js";
|
|
41
|
+
/**
|
|
42
|
+
* Return a new `SchemaNode` tree suitable for `validate`. For every
|
|
43
|
+
* default-bearing modifier in the tree:
|
|
44
|
+
* - drops `modifiers.default`
|
|
45
|
+
* - sets `modifiers.optional = true` at that same level
|
|
46
|
+
*
|
|
47
|
+
* Leaves `nullable` / `nullish`, refinements, metadata, and
|
|
48
|
+
* unrelated fields untouched. Does not mutate the input.
|
|
49
|
+
*/
|
|
50
|
+
export declare function stripDefaultsForValidate(node: SchemaNode): SchemaNode;
|
|
51
|
+
//# sourceMappingURL=strip-defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-defaults.d.ts","sourceRoot":"","sources":["../../../src/runtime/strip-defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAGV,UAAU,EACX,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAGrE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate-only IR variant (Decision #8 of v0.6 plan).
|
|
3
|
+
*
|
|
4
|
+
* `stripDefaultsForValidate(node)` produces a new `SchemaNode` tree
|
|
5
|
+
* with every default-bearing modifier removed and `optional: true`
|
|
6
|
+
* set at that same level. The original IR is not mutated (the builder
|
|
7
|
+
* deep-freezes the IR; this transform is non-destructive by
|
|
8
|
+
* construction).
|
|
9
|
+
*
|
|
10
|
+
* **Why both at once.** Per v0.1 (Invariant 4 + the absence-semantics
|
|
11
|
+
* table), `default(v)` means *input-optional + output-required* — a
|
|
12
|
+
* missing default-bearing field is a valid input. So `validate` (which
|
|
13
|
+
* returns `Result<s.input<S>>`, no fill) must (a) accept the absence,
|
|
14
|
+
* which means flipping `optional: true`, and (b) NOT fill the default
|
|
15
|
+
* value, which means dropping the `default` modifier. The combined
|
|
16
|
+
* "strip default + flip to optional" is the only rule consistent with
|
|
17
|
+
* both halves of the v0.1 absence-semantics contract for the validate
|
|
18
|
+
* path.
|
|
19
|
+
*
|
|
20
|
+
* **What stays.** `nullable` / `nullish` modifiers, refinements,
|
|
21
|
+
* metadata (`id`, `version`, `description`, `deprecated`), and every
|
|
22
|
+
* field's `unknownKeys` policy are preserved verbatim. This is a
|
|
23
|
+
* runtime compilation variant of the same schema, not a composition
|
|
24
|
+
* operation — schema-level identity (id / version / description) may
|
|
25
|
+
* matter for issue normalization downstream.
|
|
26
|
+
*
|
|
27
|
+
* **Recursion.** Object fields and array elements are walked
|
|
28
|
+
* recursively. Other composite kinds (`union`, `transform`,
|
|
29
|
+
* `recursiveRef`, `date`) are passed through unchanged here; the
|
|
30
|
+
* compile layer (`runtime/compile.ts` → `runtime/zod-compile.ts`)
|
|
31
|
+
* throws `UnsupportedNodeKindError` for those, so the strip transform
|
|
32
|
+
* does not need to gate them itself.
|
|
33
|
+
*
|
|
34
|
+
* The returned tree has different object identity from the original
|
|
35
|
+
* for every level that was touched. The compile cache keys on
|
|
36
|
+
* `SchemaNode` identity (Decision #7), so the validate variant is
|
|
37
|
+
* cached on its own slot automatically — no second `WeakMap` is
|
|
38
|
+
* needed at this layer.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Return a new `SchemaNode` tree suitable for `validate`. For every
|
|
42
|
+
* default-bearing modifier in the tree:
|
|
43
|
+
* - drops `modifiers.default`
|
|
44
|
+
* - sets `modifiers.optional = true` at that same level
|
|
45
|
+
*
|
|
46
|
+
* Leaves `nullable` / `nullish`, refinements, metadata, and
|
|
47
|
+
* unrelated fields untouched. Does not mutate the input.
|
|
48
|
+
*/
|
|
49
|
+
export function stripDefaultsForValidate(node) {
|
|
50
|
+
const recursed = recurseChildren(node);
|
|
51
|
+
return stripOwnDefault(recursed);
|
|
52
|
+
}
|
|
53
|
+
function recurseChildren(node) {
|
|
54
|
+
if (node.kind === "array") {
|
|
55
|
+
const arr = node;
|
|
56
|
+
const stripped = stripDefaultsForValidate(arr.element);
|
|
57
|
+
return { ...arr, element: stripped };
|
|
58
|
+
}
|
|
59
|
+
if (node.kind === "object") {
|
|
60
|
+
const obj = node;
|
|
61
|
+
const nextFields = {};
|
|
62
|
+
for (const [key, child] of Object.entries(obj.fields)) {
|
|
63
|
+
nextFields[key] = stripDefaultsForValidate(child);
|
|
64
|
+
}
|
|
65
|
+
return { ...obj, fields: nextFields };
|
|
66
|
+
}
|
|
67
|
+
return node;
|
|
68
|
+
}
|
|
69
|
+
function stripOwnDefault(node) {
|
|
70
|
+
const mods = node.modifiers;
|
|
71
|
+
if (!mods?.default)
|
|
72
|
+
return node;
|
|
73
|
+
// Drop `default`, force `optional: true`. Preserve `nullable` (and
|
|
74
|
+
// therefore `nullish`, which is `optional + nullable`).
|
|
75
|
+
const { default: _dropped, ...rest } = mods;
|
|
76
|
+
return {
|
|
77
|
+
...node,
|
|
78
|
+
modifiers: { ...rest, optional: true },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=strip-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-defaults.js","sourceRoot":"","sources":["../../../src/runtime/strip-defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAQH;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAgB;IACvD,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,eAAe,CAAC,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,eAAe,CAAC,IAAgB;IACvC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAiB,CAAC;QAC9B,MAAM,QAAQ,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvD,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAkB,CAAC;QAC/B,MAAM,UAAU,GAA+B,EAAE,CAAC;QAClD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACtD,UAAU,CAAC,GAAG,CAAC,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,IAAgB;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IAChC,mEAAmE;IACnE,wDAAwD;IACxD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC5C,OAAO;QACL,GAAG,IAAI;QACP,SAAS,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;KACzB,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Zod compiler — value consumer of the shared semantic mapping
|
|
3
|
+
* in `src/generators/zod-mapping.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Produces a live `ZodTypeAny` from a `SchemaNode`. Used by
|
|
6
|
+
* `parse` / `safeParse` / `validate` (lands in subsequent commits).
|
|
7
|
+
*
|
|
8
|
+
* **No source involvement.** This consumer never parses generated
|
|
9
|
+
* source text; the source generator (`src/generators/zod.ts`) never
|
|
10
|
+
* stringifies a compiled value. Their only shared surface is the
|
|
11
|
+
* `ZodEmitter` interface and the traversal order in `zod-mapping.ts`.
|
|
12
|
+
*
|
|
13
|
+
* No caching at this layer — the per-`SchemaNode` `WeakMap` lives in
|
|
14
|
+
* `runtime/compile.ts` (next commit). Repeated calls here re-build.
|
|
15
|
+
*/
|
|
16
|
+
import { type ZodTypeAny } from "zod";
|
|
17
|
+
import type { SchemaNode } from "../ir/nodes.js";
|
|
18
|
+
/**
|
|
19
|
+
* Compile an IR `SchemaNode` into a live Zod schema.
|
|
20
|
+
*
|
|
21
|
+
* Same semantic mapping and modifier ordering as `generateZod`; differs
|
|
22
|
+
* only in producing a `ZodTypeAny` value instead of TypeScript source.
|
|
23
|
+
*/
|
|
24
|
+
export declare function compileZodSchema(node: SchemaNode): ZodTypeAny;
|
|
25
|
+
/** Alias matching the v0.6 plan's naming. */
|
|
26
|
+
export declare const irToZodSchema: typeof compileZodSchema;
|
|
27
|
+
//# sourceMappingURL=zod-compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-compile.d.ts","sourceRoot":"","sources":["../../../src/runtime/zod-compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAa,UAAU,EAAqB,MAAM,gBAAgB,CAAC;AAG/E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAE7D;AAED,6CAA6C;AAC7C,eAAO,MAAM,aAAa,yBAAmB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Zod compiler — value consumer of the shared semantic mapping
|
|
3
|
+
* in `src/generators/zod-mapping.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Produces a live `ZodTypeAny` from a `SchemaNode`. Used by
|
|
6
|
+
* `parse` / `safeParse` / `validate` (lands in subsequent commits).
|
|
7
|
+
*
|
|
8
|
+
* **No source involvement.** This consumer never parses generated
|
|
9
|
+
* source text; the source generator (`src/generators/zod.ts`) never
|
|
10
|
+
* stringifies a compiled value. Their only shared surface is the
|
|
11
|
+
* `ZodEmitter` interface and the traversal order in `zod-mapping.ts`.
|
|
12
|
+
*
|
|
13
|
+
* No caching at this layer — the per-`SchemaNode` `WeakMap` lives in
|
|
14
|
+
* `runtime/compile.ts` (next commit). Repeated calls here re-build.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { emit } from "../generators/zod-mapping.js";
|
|
18
|
+
/**
|
|
19
|
+
* Compile an IR `SchemaNode` into a live Zod schema.
|
|
20
|
+
*
|
|
21
|
+
* Same semantic mapping and modifier ordering as `generateZod`; differs
|
|
22
|
+
* only in producing a `ZodTypeAny` value instead of TypeScript source.
|
|
23
|
+
*/
|
|
24
|
+
export function compileZodSchema(node) {
|
|
25
|
+
return emit(node, /*depth*/ 0, valueEmitter);
|
|
26
|
+
}
|
|
27
|
+
/** Alias matching the v0.6 plan's naming. */
|
|
28
|
+
export const irToZodSchema = compileZodSchema;
|
|
29
|
+
const valueEmitter = {
|
|
30
|
+
stringBase: () => z.string(),
|
|
31
|
+
numberBase: () => z.number(),
|
|
32
|
+
booleanBase: () => z.boolean(),
|
|
33
|
+
literalBase: (value) => z.literal(value),
|
|
34
|
+
enumStringsBase: (values) => {
|
|
35
|
+
// z.enum requires a non-empty tuple; the shared traversal guarantees
|
|
36
|
+
// length >= 1 by the time it reaches here.
|
|
37
|
+
return z.enum(values);
|
|
38
|
+
},
|
|
39
|
+
enumSingleLiteralBase: (value) => z.literal(value),
|
|
40
|
+
enumUnionBase: (values) => {
|
|
41
|
+
const options = values.map((v) => z.literal(v));
|
|
42
|
+
// z.union requires at least 2 options — the shared traversal already
|
|
43
|
+
// collapses length === 1 to z.literal via enumSingleLiteralBase.
|
|
44
|
+
return z.union(options);
|
|
45
|
+
},
|
|
46
|
+
arrayBase: (element) => z.array(element),
|
|
47
|
+
objectBase: (fields, _depth) => {
|
|
48
|
+
const shape = {};
|
|
49
|
+
for (const [key, value] of fields)
|
|
50
|
+
shape[key] = value;
|
|
51
|
+
return z.object(shape);
|
|
52
|
+
},
|
|
53
|
+
applyUnknownKeys: (prev, policy) => {
|
|
54
|
+
// Mirror the source generator's explicit-policy emission: every
|
|
55
|
+
// object gets an explicit modifier, no implicit "strip" fallback.
|
|
56
|
+
const obj = prev;
|
|
57
|
+
switch (policy) {
|
|
58
|
+
case "strict":
|
|
59
|
+
return obj.strict();
|
|
60
|
+
case "stripUnknown":
|
|
61
|
+
return obj.strip();
|
|
62
|
+
case "passthrough":
|
|
63
|
+
return obj.passthrough();
|
|
64
|
+
default:
|
|
65
|
+
return assertUnreachable(policy);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
applyMinLength: (prev, value) => prev.min(value),
|
|
69
|
+
applyMaxLength: (prev, value) => prev.max(value),
|
|
70
|
+
applyLength: (prev, value) => prev.length(value),
|
|
71
|
+
applyRegex: (prev, source, flags) => prev.regex(new RegExp(source, flags)),
|
|
72
|
+
applyEmail: (prev) => prev.email(),
|
|
73
|
+
applyUuid: (prev) => prev.uuid(),
|
|
74
|
+
applyUrl: (prev) => prev.url(),
|
|
75
|
+
applyInt: (prev) => prev.int(),
|
|
76
|
+
applyMin: (prev, value) => prev.min(value),
|
|
77
|
+
applyMax: (prev, value) => prev.max(value),
|
|
78
|
+
applyGt: (prev, value) => prev.gt(value),
|
|
79
|
+
applyLt: (prev, value) => prev.lt(value),
|
|
80
|
+
applyMultipleOf: (prev, value) => prev.multipleOf(value),
|
|
81
|
+
applyMinItems: (prev, value) => prev.min(value),
|
|
82
|
+
applyMaxItems: (prev, value) => prev.max(value),
|
|
83
|
+
applyDescribe: (prev, text) => prev.describe(text),
|
|
84
|
+
applyNullable: (prev) => prev.nullable(),
|
|
85
|
+
applyOptional: (prev) => prev.optional(),
|
|
86
|
+
applyNullish: (prev) => prev.nullish(),
|
|
87
|
+
applyDefault: (prev, value) => prev.default(value),
|
|
88
|
+
};
|
|
89
|
+
function assertUnreachable(value) {
|
|
90
|
+
throw new Error(`Unreachable: unknown unknownKeys policy ${String(value)}`);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=zod-compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-compile.js","sourceRoot":"","sources":["../../../src/runtime/zod-compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Schema, AnySchema } from "./builders/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Marks how a schema participates in object composition.
|
|
4
|
+
* - "required": object field is `key: T`
|
|
5
|
+
* - "optional": object field is `key?: T`
|
|
6
|
+
*
|
|
7
|
+
* Input and output keys are tracked separately because `.default()` accepts a
|
|
8
|
+
* missing input but produces a required output. See the absence-semantics
|
|
9
|
+
* table in the package README.
|
|
10
|
+
*/
|
|
11
|
+
export type ObjectKey = "required" | "optional";
|
|
12
|
+
/** Standard "prettify intersection" trick to make hover types readable. */
|
|
13
|
+
export type Identity<T> = {
|
|
14
|
+
[K in keyof T]: T[K];
|
|
15
|
+
} & {};
|
|
16
|
+
export type Input<S> = S extends Schema<infer I, unknown, ObjectKey, ObjectKey> ? I : never;
|
|
17
|
+
export type Output<S> = S extends Schema<unknown, infer O, ObjectKey, ObjectKey> ? O : never;
|
|
18
|
+
/** `s.infer<T>` resolves to the *output* type — same default as Zod. */
|
|
19
|
+
export type Infer<S> = Output<S>;
|
|
20
|
+
export type RawShape = Record<string, AnySchema>;
|
|
21
|
+
type OptionalInputKeys<S extends RawShape> = {
|
|
22
|
+
[K in keyof S]: S[K] extends Schema<unknown, unknown, "optional", ObjectKey> ? K : never;
|
|
23
|
+
}[keyof S];
|
|
24
|
+
type RequiredInputKeys<S extends RawShape> = Exclude<keyof S, OptionalInputKeys<S>>;
|
|
25
|
+
type OptionalOutputKeys<S extends RawShape> = {
|
|
26
|
+
[K in keyof S]: S[K] extends Schema<unknown, unknown, ObjectKey, "optional"> ? K : never;
|
|
27
|
+
}[keyof S];
|
|
28
|
+
type RequiredOutputKeys<S extends RawShape> = Exclude<keyof S, OptionalOutputKeys<S>>;
|
|
29
|
+
export type InferObjectInput<S extends RawShape> = Identity<{
|
|
30
|
+
[K in RequiredInputKeys<S>]: Input<S[K]>;
|
|
31
|
+
} & {
|
|
32
|
+
[K in OptionalInputKeys<S>]?: Input<S[K]>;
|
|
33
|
+
}>;
|
|
34
|
+
export type InferObjectOutput<S extends RawShape> = Identity<{
|
|
35
|
+
[K in RequiredOutputKeys<S>]: Output<S[K]>;
|
|
36
|
+
} & {
|
|
37
|
+
[K in OptionalOutputKeys<S>]?: Output<S[K]>;
|
|
38
|
+
}>;
|
|
39
|
+
/** `{ key: true }` subset mask over an existing shape. Used by pick/omit/partial/required. */
|
|
40
|
+
export type Mask<S extends RawShape> = {
|
|
41
|
+
[K in keyof S]?: true;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Constraint for `override`. Keys must be a subset of `keyof S`, but VALUES
|
|
45
|
+
* may be any `AnySchema` — `override` exists to replace a field's schema
|
|
46
|
+
* with a different one (e.g., `override({ id: s.number() })` on a previously-
|
|
47
|
+
* string `id`). A `Partial<S>` constraint would force values to keep the old
|
|
48
|
+
* field types and defeat the purpose.
|
|
49
|
+
*/
|
|
50
|
+
export type OverrideMask<S extends RawShape> = {
|
|
51
|
+
[K in keyof S]?: AnySchema;
|
|
52
|
+
};
|
|
53
|
+
/** Merge resolution knobs — both default to `"throw"`. See `merge` overloads. */
|
|
54
|
+
export type MergeOptions = {
|
|
55
|
+
conflict?: "throw" | "left" | "right";
|
|
56
|
+
unknownKeys?: "throw" | "left" | "right";
|
|
57
|
+
};
|
|
58
|
+
export type ExtendShape<S extends RawShape, E extends RawShape> = Identity<S & E>;
|
|
59
|
+
export type PickShape<S extends RawShape, M extends Mask<S>> = Identity<{
|
|
60
|
+
[K in keyof S as M[K] extends true ? K : never]: S[K];
|
|
61
|
+
}>;
|
|
62
|
+
export type OmitShape<S extends RawShape, M extends Mask<S>> = Identity<{
|
|
63
|
+
[K in keyof S as M[K] extends true ? never : K]: S[K];
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Decision #6 + #15: `partial()` sets the field's TInputKey AND TOutputKey
|
|
67
|
+
* to "optional" and widens TInput/TOutput to include `undefined`. Mirrors
|
|
68
|
+
* what `.optional()` does on Schema at the type level. Default-stripping
|
|
69
|
+
* happens at the IR layer; it's not visible in the type because v0.1
|
|
70
|
+
* `default()` already sets `_outputKey: "required"` while v0.5 `partial`
|
|
71
|
+
* forces it to `"optional"`.
|
|
72
|
+
*/
|
|
73
|
+
type PartialField<F> = F extends Schema<infer I, infer O, ObjectKey, ObjectKey> ? Schema<I | undefined, O | undefined, "optional", "optional"> : never;
|
|
74
|
+
export type PartialShape<S extends RawShape> = {
|
|
75
|
+
[K in keyof S]: PartialField<S[K]>;
|
|
76
|
+
};
|
|
77
|
+
export type PartialByShape<S extends RawShape, M extends Mask<S>> = Identity<{
|
|
78
|
+
[K in keyof S]: M[K] extends true ? PartialField<S[K]> : S[K];
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Decision #8 + #15: `required()` sets both keys to "required" and excludes
|
|
82
|
+
* `undefined` from TInput/TOutput. Default-stripping happens at the IR layer.
|
|
83
|
+
*/
|
|
84
|
+
type RequiredField<F> = F extends Schema<infer I, infer O, ObjectKey, ObjectKey> ? Schema<Exclude<I, undefined>, Exclude<O, undefined>, "required", "required"> : never;
|
|
85
|
+
export type RequiredShape<S extends RawShape> = {
|
|
86
|
+
[K in keyof S]: RequiredField<S[K]>;
|
|
87
|
+
};
|
|
88
|
+
export type RequiredByShape<S extends RawShape, M extends Mask<S>> = Identity<{
|
|
89
|
+
[K in keyof S]: M[K] extends true ? RequiredField<S[K]> : S[K];
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Throw-shape: TS-level intersection of both shapes (`Identity<S & Other>`).
|
|
93
|
+
* Preserves disjoint merges; lets TypeScript surface some conflicts through
|
|
94
|
+
* normal intersection behavior where possible. **Runtime conflict detection
|
|
95
|
+
* is the load-bearing guarantee** — consumers MUST NOT rely on
|
|
96
|
+
* `MergeThrowShape` as the sole conflict detector. Use explicit
|
|
97
|
+
* `conflict: "left" | "right"` on `merge` when intentionally resolving
|
|
98
|
+
* overlaps; let the runtime throw catch the unintended ones.
|
|
99
|
+
*
|
|
100
|
+
* (Original design used a per-key conditional that mapped all overlapping
|
|
101
|
+
* keys to `never`. That broke variance for `ObjectSchema<{...}>` vs.
|
|
102
|
+
* `ObjectSchema<RawShape>` because `RawShape` overlaps with every key. The
|
|
103
|
+
* intersection form preserves variance.)
|
|
104
|
+
*/
|
|
105
|
+
export type MergeThrowShape<S extends RawShape, Other extends RawShape> = Identity<S & Other>;
|
|
106
|
+
export type MergeLeftShape<S extends RawShape, Other extends RawShape> = Identity<{
|
|
107
|
+
[K in keyof S | keyof Other]: K extends keyof S ? S[K] : K extends keyof Other ? Other[K] : never;
|
|
108
|
+
}>;
|
|
109
|
+
export type MergeRightShape<S extends RawShape, Other extends RawShape> = Identity<{
|
|
110
|
+
[K in keyof S | keyof Other]: K extends keyof Other ? Other[K] : K extends keyof S ? S[K] : never;
|
|
111
|
+
}>;
|
|
112
|
+
export type OverrideShape<S extends RawShape, O extends OverrideMask<S>> = Identity<{
|
|
113
|
+
[K in keyof S]: K extends keyof O ? O[K] extends AnySchema ? O[K] : S[K] : S[K];
|
|
114
|
+
}>;
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAEhD,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAIxD,MAAM,MAAM,KAAK,CAAC,CAAC,IACjB,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEvE,MAAM,MAAM,MAAM,CAAC,CAAC,IAClB,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEvE,wEAAwE;AACxE,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AAIjC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEjD,KAAK,iBAAiB,CAAC,CAAC,SAAS,QAAQ,IAAI;KAC1C,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,GACxE,CAAC,GACD,KAAK;CACV,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,iBAAiB,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAClD,MAAM,CAAC,EACP,iBAAiB,CAAC,CAAC,CAAC,CACrB,CAAC;AAEF,KAAK,kBAAkB,CAAC,CAAC,SAAS,QAAQ,IAAI;KAC3C,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,GACxE,CAAC,GACD,KAAK;CACV,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,kBAAkB,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CACnD,MAAM,CAAC,EACP,kBAAkB,CAAC,CAAC,CAAC,CACtB,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,QAAQ,IAAI,QAAQ,CACzD;KAAG,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG;KAC5C,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC1C,CACF,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,QAAQ,IAAI,QAAQ,CAC1D;KAAG,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG;KAC9C,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5C,CACF,CAAC;AASF,8FAA8F;AAC9F,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,QAAQ,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI;CAAE,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS;CAC3B,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;CAC1C,CAAC;AAIF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,IAAI,QAAQ,CACxE,CAAC,GAAG,CAAC,CACN,CAAC;AAIF,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;KACrE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;CACtD,CAAC,CAAC;AAEH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;KACrE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACtD,CAAC,CAAC;AAIH;;;;;;;GAOG;AACH,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CACrC,MAAM,CAAC,EACP,MAAM,CAAC,EACP,SAAS,EACT,SAAS,CACV,GACG,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,GAC5D,KAAK,CAAC;AAEV,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,IAAI;KAC5C,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;KAC1E,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC9D,CAAC,CAAC;AAEH;;;GAGG;AACH,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CACtC,MAAM,CAAC,EACP,MAAM,CAAC,EACP,SAAS,EACT,SAAS,CACV,GACG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,GAC5E,KAAK,CAAC;AAEV,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,QAAQ,IAAI;KAC7C,CAAC,IAAI,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;KAC3E,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/D,CAAC,CAAC;AAIH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,SAAS,QAAQ,IACpE,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAEtB,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,SAAS,QAAQ,IACnE,QAAQ,CAAC;KACN,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,KAAK,GAAG,CAAC,SAAS,MAAM,CAAC,GAC3C,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,SAAS,MAAM,KAAK,GACnB,KAAK,CAAC,CAAC,CAAC,GACR,KAAK;CACZ,CAAC,CAAC;AAEL,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,SAAS,QAAQ,IACpE,QAAQ,CAAC;KACN,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,KAAK,GAAG,CAAC,SAAS,MAAM,KAAK,GAC/C,KAAK,CAAC,CAAC,CAAC,GACR,CAAC,SAAS,MAAM,CAAC,GACf,CAAC,CAAC,CAAC,CAAC,GACJ,KAAK;CACZ,CAAC,CAAC;AAIL,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,IACrE,QAAQ,CAAC;KACN,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAC7B,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,GACpB,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC,CAAC,GACN,CAAC,CAAC,CAAC,CAAC;CACT,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Absence Semantics
|
|
2
|
+
|
|
3
|
+
The single most under-specified part of any schema system. This package pins it.
|
|
4
|
+
|
|
5
|
+
`null` is a value. Missing is the absence of a value. They are different. Conflating them is the most common source of API drift.
|
|
6
|
+
|
|
7
|
+
## The table
|
|
8
|
+
|
|
9
|
+
| DSL | TypeScript (output) | Runtime accepts | JSON Schema `required`? | OpenAPI `nullable`? |
|
|
10
|
+
|---|---|---|---|---|
|
|
11
|
+
| `s.string()` | `field: string` | string only | yes | no |
|
|
12
|
+
| `s.string().optional()` | `field?: string` | missing or undefined | no | no |
|
|
13
|
+
| `s.string().nullable()` | `field: string \| null` | string or null; missing rejected | yes | yes |
|
|
14
|
+
| `s.string().nullish()` | `field?: string \| null` | missing, undefined, or null | no | yes |
|
|
15
|
+
| `s.string().default("x")` | input `field?: string`; output `field: string` | missing accepted; replaced | no (default emitted) | no |
|
|
16
|
+
|
|
17
|
+
## Input vs output
|
|
18
|
+
|
|
19
|
+
Critical distinction. The schema's *input* is what `parse`/`validate` accepts; the *output* is what `parse` returns (post-defaults, post-transforms).
|
|
20
|
+
|
|
21
|
+
- `optional()`: input is `T | undefined`, output is `T | undefined`. Object key is optional in *both*.
|
|
22
|
+
- `nullable()`: input is `T | null`, output is `T | null`. Object key is required in *both*.
|
|
23
|
+
- `nullish()`: input is `T | null | undefined`, output is `T | null | undefined`. Object key is optional in *both*.
|
|
24
|
+
- `default(v)`: input is `T | undefined` (object-optional), output is `T` (object-**required** — the default has been applied).
|
|
25
|
+
|
|
26
|
+
## Why default's asymmetry matters
|
|
27
|
+
|
|
28
|
+
A `default()`-bearing field accepts a missing input, but downstream code receives a fully-populated value. If the output type were also optional, every consumer of `parse(Schema, ...)` would have to defensively check for `undefined` despite the default making that impossible.
|
|
29
|
+
|
|
30
|
+
This is enforced by tracking `TInputKey` and `TOutputKey` as separate type parameters on `Schema` — see [`IR_CONTRACT.md`](./IR_CONTRACT.md).
|
|
31
|
+
|
|
32
|
+
## Tests that prove this
|
|
33
|
+
|
|
34
|
+
- [`tests/inference.test-d.ts`](../tests/inference.test-d.ts) — `describe("audit User example — proves the absence-semantics contract verbatim")` mirrors this table at the type level.
|
|
35
|
+
- [`tests/builders.test.ts`](../tests/builders.test.ts) — `describe("absence modifiers")` proves the IR modifiers (`optional`, `nullable`, `default`) are encoded correctly.
|
|
36
|
+
|
|
37
|
+
If you change `Schema`'s modifier methods, those tests are the gate. They are deliberately written against the spec table, not against implementation details.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Performance Benchmarks
|
|
2
|
+
|
|
3
|
+
> "High Integrity shouldn't mean High Latency."
|
|
4
|
+
|
|
5
|
+
This document outlines the performance characteristics of `@nekostack/schema` (v0.6+). Because NekoStack introduces an Intermediate Representation (IR) and normalizes all errors into a strict `Issue` vocabulary, a common concern is the overhead this adds on top of the underlying execution engine (Zod).
|
|
6
|
+
|
|
7
|
+
We track these metrics using Vitest's benchmarking suite. The results below are run against a standard "User" schema containing UUIDs, nested objects, and arrays.
|
|
8
|
+
|
|
9
|
+
To run the benchmarks yourself:
|
|
10
|
+
```bash
|
|
11
|
+
cd packages/schema
|
|
12
|
+
npm run build
|
|
13
|
+
npx vitest bench tests/performance.bench.ts --run
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Runtime Validation Overhead
|
|
19
|
+
|
|
20
|
+
The primary concern for any schema engine is the "Hot Path"—validating incoming API requests or database reads.
|
|
21
|
+
|
|
22
|
+
**NekoStack achieves Near-Native Parity with Zod.**
|
|
23
|
+
|
|
24
|
+
| Operation | Ops/sec (Hz) | Overhead vs Zod | Note |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| `z.safeParse()` (Raw Zod) | ~865,000 | Baseline | The fastest possible path. |
|
|
27
|
+
| `z.parse()` (Raw Zod) | ~833,000 | 1.04x slower | Throws exceptions. |
|
|
28
|
+
| **NekoStack `parse()`** | **~819,000** | **1.06x slower** | Includes WeakMap compile-cache lookup + Issue normalization. |
|
|
29
|
+
| **NekoStack `validate()`** | **~764,000** | **1.13x slower** | Runs the stripped-defaults variant of the schema. |
|
|
30
|
+
|
|
31
|
+
### The Verdict: S-Tier Performance
|
|
32
|
+
NekoStack adds a mere **~6% overhead** to the hot path (`parse()`) compared to raw Zod `safeParse`.
|
|
33
|
+
|
|
34
|
+
For that 6%, you get:
|
|
35
|
+
1. Guarantee of structural purity (no Silent Lies).
|
|
36
|
+
2. Predictable, normalized `IssueCode` arrays instead of Zod's internal error tree.
|
|
37
|
+
3. The ability to generate TS, OpenAPI, and JSON Schema from the exact same definition.
|
|
38
|
+
|
|
39
|
+
At 800,000+ operations per second, the validation step will **never** be the bottleneck in your web application.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. Generator Throughput
|
|
44
|
+
|
|
45
|
+
NekoStack doesn't just parse data; it generates code. Generator speed matters for CI pipelines (`neko schema check`) and local Developer Experience.
|
|
46
|
+
|
|
47
|
+
| Generator | Ops/sec (Hz) | Time per 10k Schemas |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `generateZod` | ~92,000 | ~108ms |
|
|
50
|
+
| `generateTypeScript` | ~91,000 | ~110ms |
|
|
51
|
+
| `generateJsonSchema` | ~83,000 | ~120ms |
|
|
52
|
+
| `generateOpenApiSchemaComponent` | ~81,000 | ~122ms |
|
|
53
|
+
|
|
54
|
+
### The Verdict: Instantaneous Generation
|
|
55
|
+
All four generators operate at >80,000 ops/sec. Generating the entire artifact suite (TS, Zod, OpenAPI, JSON Schema) for a massive 1,000-schema monorepo takes less than **50 milliseconds**.
|
|
56
|
+
|
|
57
|
+
This proves that `neko schema generate` and `neko schema check` will feel completely instantaneous to the developer, and add zero noticeable overhead to CI/CD pipelines.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Conclusion
|
|
62
|
+
`@nekostack/schema` is mathematically proven to be structurally safe (via property-based fuzzing) and empirically proven to be production-fast.
|
|
63
|
+
|
|
64
|
+
You do not have to choose between architecture and latency.
|