ata-validator 1.6.0 → 1.6.2

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 CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to ata-validator are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/), and this project adheres to semantic versioning.
4
4
 
5
+ ## 1.6.2 - 2026-08-19
6
+
7
+ ### Fixed
8
+
9
+ - The Standard Schema surface carried no output type. `~standard.validate()` returned `{ value: unknown }` and the `types` carrier the specification defines for inference was missing, so every consumer that reads the validated type off `~standard` (Fastify, tRPC, TanStack Form, Drizzle) saw `unknown` and needed a cast. `~standard` is now typed against the validator's own data type, and `types.output` carries it. Type-only: the runtime object is unchanged, and the specification defines `types` as never present at runtime.
10
+ - Boolean schemas were rejected by the `Validator` constructor's TypeScript signature. `true` and `false` are schemas anywhere JSON Schema allows one, and both have always worked at runtime; only the types disagreed, which made a schema of unknown shape (`object | boolean`) impossible to pass without a cast. Nested boolean subschemas are still typed as objects, so `{ properties: { a: true } }` needs `defineSchema` or a cast.
11
+ - The `t` builder's option bags rejected vendor keywords. `t.object({}, { instanceof: 'Date' })` is what a custom keyword package expects to be given, and the option types only allowed the keywords the builder itself emits, so callers wrote `as never`. Every option bag now accepts unknown keywords alongside the typed ones.
12
+ - `tests/test_interop_types.ts` covers all three under `tsc --noEmit`.
13
+
14
+ ## 1.6.1 - 2026-08-09
15
+
16
+ ### Fixed
17
+
18
+ - A `$ref` into another document whose own root carries a fragment-only `$ref` validated everything. The code generator has three entry points and only one of them, the boolean path, ran the bail that routes a reference it cannot follow to the interpreted engine. The other two emitted no lines for the reference and returned the empty program as always-valid, so every constraint behind it was dropped without an error. `{ "$ref": "other.json" }` against a document holding its constraints under `#/$defs/...` accepted any input at all. Both paths now run the same two bails the boolean path runs. This is the third silent-accept defect in `$ref` resolution after the two fixed in 1.3.0, and it affects Draft 2020-12 as well as the v1 dialect.
19
+ - `tests/test_cross_doc_root_ref.js` states the case directly, including a cross-document reference to a target that holds its constraints inline, which must stay on the compiled path so the bail is not widened into "any cross-document reference".
20
+
21
+ ### Changed
22
+
23
+ - The official test suite moved on five months, from the March snapshot to 6 August. Every published figure is remeasured against it. Draft 2020-12 is 1294 of 1299, draft 7 is 916 of 927, and the v1 dialect is 1131 of 1133. With code generation blocked, Draft 2020-12 is 1295 of 1299 and v1 is 1132 of 1133. One case that the fix above corrects is no longer a known failure under v1.
24
+ - The buffer path disagrees with `validate()` on 245 of 2222 suite cases rather than 243 of 2208. The two additional disagreements are new suite cases, not a widening: measured against the March snapshot the number is still exactly 243.
25
+
5
26
  ## 1.6.0 - 2026-08-08
6
27
 
7
28
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ata-validator
2
2
 
3
- JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile your schemas to per-schema ESM modules with no validator dependency. `Validator<T>` composes with TypeBox, Zod-from-JSON-Schema, Valibot, or hand-written types. Runtime API available for dynamic schemas.
3
+ JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile your schemas to per-schema ESM modules with no validator dependency. `Validator<T>` composes with TypeBox, Zod-from-JSON-Schema, Valibot, or hand-written types. Runtime API available for dynamic schemas. Draft 2020-12, draft 7 and the [JSON Schema v1 dialect](#dialects).
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/ata-validator)](https://www.npmjs.com/package/ata-validator)
6
6
  [![License](https://img.shields.io/npm/l/ata-validator)](LICENSE)
@@ -20,11 +20,11 @@ The `ata-validator` package itself is pure JavaScript. The native accelerator (s
20
20
  npm install ata-validator --omit=optional
21
21
  ```
22
22
 
23
- or set `ATA_NO_NATIVE=1` at runtime. Typical schemas compile to specialized JS; shapes the compiler cannot represent (some `$dynamicRef`, cyclic `$ref`, unusual keyword interactions) fall back to an interpreted engine, so every schema validates in every environment. The pure-JS setup scores the same on the official suite as the native one, 1285 of 1290 Draft 2020-12 cases; the two miss a different `$dynamicRef` scope corner each. Only the buffer and parallel APIs (`isValid` on raw buffers, `countValid`, `batchIsValid`, `validateAndParse`) need the native engine and say so with a clear error.
23
+ or set `ATA_NO_NATIVE=1` at runtime. Typical schemas compile to specialized JS; shapes the compiler cannot represent (some `$dynamicRef`, cyclic `$ref`, unusual keyword interactions) fall back to an interpreted engine, so every schema validates in every environment. The pure-JS setup scores the same on the official suite as the native one, 1294 of 1299 Draft 2020-12 cases; the two miss a different `$dynamicRef` scope corner each. Only the buffer and parallel APIs (`isValid` on raw buffers, `countValid`, `batchIsValid`, `validateAndParse`) need the native engine and say so with a clear error.
24
24
 
25
- Those four also do not yet agree with `validate()`. Over the official suite they differ on 243 of 2208 cases, in both directions, concentrated in `unevaluatedProperties`, `contains`, `const` and the `$ref` family. `npm test` measures the gap on every run so it cannot widen, and `docs/edge-runtimes.md` has the detail. Until it is closed, use them where throughput matters more than exactness, and use `validate()` or `isValidObject()` as the check on untrusted input.
25
+ Those four also do not yet agree with `validate()`. Over the official suite they differ on 245 of 2222 cases, in both directions, concentrated in `unevaluatedProperties`, `contains`, `const` and the `$ref` family. `npm test` measures the gap on every run so it cannot widen, and `docs/edge-runtimes.md` has the detail. Until it is closed, use them where throughput matters more than exactness, and use `validate()` or `isValidObject()` as the check on untrusted input.
26
26
 
27
- Where `new Function` is refused altogether, on Cloudflare Workers, Deno Deploy or under a strict Content-Security-Policy, ata drops to the interpreted engine and scores 1286 of 1290 with code generation blocked. No flags, and on Workers no `nodejs_compat` either. See [docs/edge-runtimes.md](docs/edge-runtimes.md).
27
+ Where `new Function` is refused altogether, on Cloudflare Workers, Deno Deploy or under a strict Content-Security-Policy, ata drops to the interpreted engine and scores 1295 of 1299 with code generation blocked. No flags, and on Workers no `nodejs_compat` either. See [docs/edge-runtimes.md](docs/edge-runtimes.md).
28
28
 
29
29
  In your code:
30
30
 
@@ -43,15 +43,29 @@ The `.compiled.mjs` modules are self-contained: zero runtime dependency on ata-v
43
43
 
44
44
  | Dimension | Schema | ata-AOT | AJV-runtime | Difference |
45
45
  |---|---|---|---|---|
46
- | Bundle (gzipped) | simple | 955 B | 52.7 KB | 56x smaller |
47
- | Bundle (gzipped) | complex | 1.6 KB | 52.7 KB | 32x smaller |
48
- | Cold start | simple | 21 ms | 38 ms | 1.8x faster |
49
- | Throughput (10M ops) | simple | 345 Mops/s | 116 Mops/s | 3.0x faster |
50
- | Compile time | simple | 6 µs | 1.5 ms | 246x faster |
51
-
52
- Reproduce on your machine with `npm run bench:aot-vs-ajv`. Numbers measured on Apple M4 Pro, Node 25.2.1.
53
-
54
- The wins are largest on bundle size and compile time because AOT moves work from runtime to build time. Throughput and cold start are also faster because the compiled validator is a tight straight-line function with no schema-walk overhead.
46
+ | Bundle (gzipped) | simple | 1.0 KB | 52.7 KB | 50.5x smaller |
47
+ | Bundle (gzipped) | complex | 4.8 KB | 52.7 KB | 11.0x smaller |
48
+ | Bundle (gzipped) | nested | 2.3 KB | 52.7 KB | 23.1x smaller |
49
+ | Cold start | simple | 21 ms | 40 ms | 1.9x faster |
50
+ | Throughput (1M ops) | simple | 258 Mops/s | 102 Mops/s | 2.5x faster |
51
+ | Compile time | simple | 8 µs | 1.61 ms | 191x faster |
52
+
53
+ Reproduce on your machine with `npm run bench:aot-vs-ajv`. Numbers from one run on Apple
54
+ M4 Pro, Node 25.2.1, 2026-08-13. Across three runs throughput moved between 258 and 278
55
+ Mops/s and the compile ratio between 150x and 199x, so treat the last two rows as an order
56
+ of magnitude rather than a constant.
57
+
58
+ The wins are largest on bundle size and compile time because AOT moves work from runtime to
59
+ build time. Throughput and cold start are also faster because the compiled validator is a
60
+ tight straight-line function with no schema-walk overhead.
61
+
62
+ What the table does not cover is data that fails. It measures compiled modules on input that
63
+ passes, and a rejection costs more than a verdict: ata builds an error carrying a code, the
64
+ offending value, a documentation link and a suggestion. On a five-field object schema a
65
+ passing payload costs about 17 ns and a rejected one about 155 ns. `abortEarly: true` or
66
+ `isValidObject()` skips that work when only the verdict matters. Schemas ata declines to
67
+ compile, mostly cross-document `$ref`, `$dynamicRef` and `unevaluated*`, run on the
68
+ interpreted engine and are slower again.
55
69
 
56
70
  ## Error messages
57
71
 
@@ -385,7 +399,10 @@ const { toStandaloneModule } = require('ata-validator/build');
385
399
  fs.writeFileSync('./user.validator.mjs', toStandaloneModule(schema, { format: 'esm' }));
386
400
  ```
387
401
 
388
- **Fastify startup (10 routes cold): ajv 12.6ms → ata 0.5ms (24x faster boot, no build step required)**
402
+ **Fastify startup, 10 route schemas, from a cold process to the first validated request:
403
+ ajv 19.6 ms, ata 3.1 ms, no build step required.** ata registers in 1.1 ms of that and
404
+ compiles on the first request, so counting only registration would overstate the gap.
405
+ Reproduce with `node benchmark/bench_fastify_boot.mjs`.
389
406
 
390
407
  ### Standard Schema V1
391
408
 
@@ -479,7 +496,7 @@ Both are implemented in the interpreted engine, so a v1 schema that uses `$dynam
479
496
 
480
497
  ### Known limitations
481
498
 
482
- Running the whole Draft 2020-12 suite with nothing excluded, `format` and `default` under specification semantics (`assertFormat: false`, `useDefaults: false`), gives 1285 of 1290 cases, 99.6%. Draft 7 gives 911 of 922, 98.8%. The v1 dialect gives 1123 of 1127, 99.6%, and the four it misses are the same four that fail on 2020-12. `npm run test:suite` reproduces all three and lists the remaining failures by name.
499
+ Running the whole Draft 2020-12 suite with nothing excluded, `format` and `default` under specification semantics (`assertFormat: false`, `useDefaults: false`), gives 1294 of 1299 cases, 99.6%. Draft 7 gives 916 of 927, 98.8%. The v1 dialect gives 1131 of 1133, 99.8%, and the two it misses are among the five that fail on 2020-12. `npm run test:suite` reproduces all three and lists the remaining failures by name.
483
500
 
484
501
  Areas that remain deliberate scope decisions for 1.x:
485
502
 
package/index.d.ts CHANGED
@@ -364,13 +364,13 @@ export interface BundleStandaloneOptions extends ValidatorOptions {
364
364
  format?: 'esm' | 'cjs';
365
365
  }
366
366
 
367
- export interface StandardSchemaV1Props {
367
+ export interface StandardSchemaV1Props<Output = unknown, Input = unknown> {
368
368
  version: 1;
369
369
  vendor: "ata-validator";
370
370
  validate(
371
371
  value: unknown
372
372
  ):
373
- | { value: unknown }
373
+ | { value: Output }
374
374
  | {
375
375
  issues: Array<{
376
376
  message: string;
@@ -378,6 +378,11 @@ export interface StandardSchemaV1Props {
378
378
  path?: ReadonlyArray<{ key: PropertyKey }>;
379
379
  }>;
380
380
  };
381
+ /**
382
+ * Type-only carrier the Standard Schema spec uses for inference: consumers
383
+ * read the validated type off `types.output`. Never present at runtime.
384
+ */
385
+ readonly types?: { readonly input: Input; readonly output: Output } | undefined;
381
386
  }
382
387
 
383
388
  export interface StandaloneModule {
@@ -425,7 +430,7 @@ export interface Validator<T = unknown> {
425
430
  isValidNDJSON(ndjsonBuffer: Buffer): boolean[];
426
431
 
427
432
  /** Standard Schema V1 interface, compatible with Fastify, tRPC, TanStack, etc. */
428
- readonly "~standard": StandardSchemaV1Props;
433
+ readonly "~standard": StandardSchemaV1Props<T>;
429
434
  }
430
435
 
431
436
  /** Constructor + statics for {@link Validator}. */
@@ -433,7 +438,7 @@ export interface ValidatorConstructor {
433
438
  /** Construct from a JSON Schema literal; the validated data type is inferred. */
434
439
  new <const S extends JSONSchema>(schema: S, options?: ValidatorOptions): Validator<Infer<S>>;
435
440
  /** Construct from a plain object/string schema, or with an explicit data type. */
436
- new <T = unknown>(schema: object | string, options?: ValidatorOptions): Validator<T>;
441
+ new <T = unknown>(schema: object | string | boolean, options?: ValidatorOptions): Validator<T>;
437
442
 
438
443
  /** Load a pre-compiled standalone module. Zero schema compilation at startup. */
439
444
  fromStandalone<T = unknown>(mod: StandaloneModule, schema: object | string, options?: ValidatorOptions): Validator<T>;
@@ -46,14 +46,24 @@ function expectedFor (err) {
46
46
 
47
47
  function pickReceived (err, data) {
48
48
  if (!data && data !== 0 && data !== false) return undefined;
49
- // Walk JSON pointer to extract the actual offending value
49
+ // Walk JSON pointer to extract the actual offending value. This runs for
50
+ // every error on every rejected payload, so the walk reads segments straight
51
+ // out of the pointer: no leading-slash regex, no parts array, and no unescape
52
+ // pass on the segments that carry no `~`.
50
53
  const p = err.instancePath || err.path || '';
51
54
  if (!p) return reprValue(data);
52
- const parts = p.replace(/^\//, '').split('/').map(s => s.replace(/~1/g, '/').replace(/~0/g, '~'));
55
+ const len = p.length;
53
56
  let cur = data;
54
- for (const part of parts) {
57
+ let i = p.charCodeAt(0) === 47 ? 1 : 0; // 47 is '/'
58
+ for (;;) {
59
+ let j = p.indexOf('/', i);
60
+ if (j === -1) j = len;
61
+ let seg = p.slice(i, j);
62
+ if (seg.indexOf('~') !== -1) seg = seg.replace(/~1/g, '/').replace(/~0/g, '~');
55
63
  if (cur == null) return undefined;
56
- cur = cur[part];
64
+ cur = cur[seg];
65
+ if (j === len) break;
66
+ i = j + 1;
57
67
  }
58
68
  return reprValue(cur);
59
69
  }
@@ -77,20 +77,27 @@ function all () {
77
77
  return Object.keys(CODES).sort();
78
78
  }
79
79
 
80
+ // Reverse lookups, built once. codeFor runs per error on every failing
81
+ // validation, so walking the table there showed up as most of the cost of
82
+ // enriching a rejected payload. Insertion follows sorted code order, so the
83
+ // first writer wins and each keyword keeps the lowest code that carries it.
84
+ const BY_KEYWORD = new Map();
85
+ const BY_FORMAT = new Map();
86
+ for (const c of Object.keys(CODES).sort()) {
87
+ const meta = CODES[c];
88
+ if (!BY_KEYWORD.has(meta.keyword)) BY_KEYWORD.set(meta.keyword, c);
89
+ if (meta.keyword === 'format' && meta.format && !BY_FORMAT.has(meta.format)) BY_FORMAT.set(meta.format, c);
90
+ }
91
+
80
92
  // Map a (keyword, optional format) tuple back to a code. Used by the codegen
81
93
  // integration to attach codes to existing error sites without rewriting them all.
82
94
  function codeFor (keyword, format) {
83
95
  if (keyword === 'format' && format) {
84
- for (const c of all()) {
85
- const meta = CODES[c];
86
- if (meta.keyword === 'format' && meta.format === format) return c;
87
- }
88
- return 'ATA3099';
89
- }
90
- for (const c of all()) {
91
- if (CODES[c].keyword === keyword) return c;
96
+ const hit = BY_FORMAT.get(format);
97
+ return hit === undefined ? 'ATA3099' : hit;
92
98
  }
93
- return null;
99
+ const hit = BY_KEYWORD.get(keyword);
100
+ return hit === undefined ? null : hit;
94
101
  }
95
102
 
96
103
  module.exports = { CODES, get, all, codeFor };
@@ -845,6 +845,16 @@ function codegenSafe(schema, schemaMap) {
845
845
  if (typeof schema.unevaluatedProperties === 'object' && schema.unevaluatedProperties !== null) {
846
846
  if (!codegenSafe(schema.unevaluatedProperties, schemaMap)) return false
847
847
  }
848
+ // When evaluation is both dynamic (branch-dependent) and some branch
849
+ // unconditionally evaluates all properties, static tracking cannot
850
+ // correctly determine which properties are unevaluated at runtime.
851
+ // For example, a oneOf whose branches include both patternProperties
852
+ // and unevaluatedProperties:true requires annotation-aware evaluation
853
+ // that only the interpreted engine provides.
854
+ if (schema.unevaluatedProperties === false || (typeof schema.unevaluatedProperties === 'object' && schema.unevaluatedProperties !== null)) {
855
+ const evalResult = collectEvaluated(schema, schemaMap)
856
+ if (evalResult.dynamic && evalResult.allProps) return false
857
+ }
848
858
  }
849
859
  // unevaluatedItems: allow boolean and schema values
850
860
  if (schema.unevaluatedItems !== undefined) {
@@ -861,15 +871,52 @@ function codegenSafe(schema, schemaMap) {
861
871
  const defs = schema.$defs || schema.definitions
862
872
  if (defs) {
863
873
  const defNames = new Set(Object.keys(defs))
864
- // Detect cyclic local refs: if any def's own body references back to a sibling
865
- // def, the schema contains a cycle. The JS codegen returns (() => true) on cycle
866
- // (permissive), so cyclic schemas must route to the interpreted engine instead.
867
- // We check only the def bodies, not the top-level schema, so that a plain
868
- // { $ref: '#/$defs/Name', $defs: { Name: { type: 'string' } } } (no cycle)
869
- // still compiles.
870
- const hasCycle = Object.values(defs).some(
871
- (def) => typeof def === 'object' && def !== null && subtreeRefersToLocalDef(def, defNames)
872
- )
874
+ // Detect cyclic local refs: build a directed graph of def->def references and
875
+ // check for cycles using DFS. A plain cross-reference (A -> B where B doesn't
876
+ // refer back to A) is fine; only true cycles (A -> B -> A) must be rejected.
877
+ // The JS codegen returns (() => true) on cycle (permissive), so cyclic schemas
878
+ // must route to the interpreted engine instead.
879
+ const defRefs = {}
880
+ for (const [name, def] of Object.entries(defs)) {
881
+ defRefs[name] = []
882
+ if (typeof def === 'object' && def !== null) {
883
+ const refs = []
884
+ const seen = new WeakSet()
885
+ const collectRefs = (node) => {
886
+ if (typeof node !== 'object' || node === null) return
887
+ if (seen.has(node)) return
888
+ seen.add(node)
889
+ if (node.$ref) {
890
+ const m = /^#\/(?:\$defs|definitions)\/([^/]+)$/.exec(node.$ref)
891
+ if (m && defNames.has(m[1])) refs.push(m[1])
892
+ }
893
+ for (const val of Object.values(node)) {
894
+ if (typeof val === 'object' && val !== null) {
895
+ if (Array.isArray(val)) { for (const item of val) collectRefs(item) }
896
+ else collectRefs(val)
897
+ }
898
+ }
899
+ }
900
+ collectRefs(def)
901
+ defRefs[name] = refs
902
+ }
903
+ }
904
+ const hasCycle = (() => {
905
+ const visited = new Set()
906
+ const inStack = new Set()
907
+ const dfs = (node) => {
908
+ if (inStack.has(node)) return true
909
+ if (visited.has(node)) return false
910
+ visited.add(node)
911
+ inStack.add(node)
912
+ for (const neighbor of (defRefs[node] || [])) {
913
+ if (dfs(neighbor)) return true
914
+ }
915
+ inStack.delete(node)
916
+ return false
917
+ }
918
+ return Object.keys(defRefs).some(dfs)
919
+ })()
873
920
  if (hasCycle) return false
874
921
  for (const [name, def] of Object.entries(defs)) {
875
922
  if (/[~/"']/.test(name)) return false // special chars in def name
@@ -2828,6 +2875,11 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
2828
2875
  }
2829
2876
  }
2830
2877
 
2878
+ // As in the boolean generator: a reference this path cannot resolve or follow
2879
+ // emits no lines, and an empty program is returned below as always-valid.
2880
+ if (hasUnresolvableRef(schema, eRootDefs, eAnchors, schemaMap, new Set())) return null
2881
+ if (needsBaseTracking(schema, schemaMap, new Set())) return null
2882
+
2831
2883
  const ctx = { varCounter: 0, helperCode: [], rootDefs: eRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: eAnchors, rootSchema: schema, userFormats: userFormats || null,
2832
2884
  sourceMap: (sourceOpts && sourceOpts.sourceMap && sourceOpts.schemaFile)
2833
2885
  ? { file: sourceOpts.schemaFile, map: sourceOpts.sourceMap }
@@ -3449,6 +3501,14 @@ function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats) {
3449
3501
  }
3450
3502
  }
3451
3503
 
3504
+ // The same two bails the boolean generator makes. Without them this path
3505
+ // emits nothing for a reference it cannot resolve or follow, and an empty
3506
+ // program is returned below as `() => VALID_RESULT`, so every constraint
3507
+ // behind the reference is dropped instead of the schema routing to the
3508
+ // interpreted engine.
3509
+ if (hasUnresolvableRef(schema, cRootDefs, cAnchors, schemaMap, new Set())) return null
3510
+ if (needsBaseTracking(schema, schemaMap, new Set())) return null
3511
+
3452
3512
  const ctx = { varCounter: 0, helperCode: [], closureVars: ['_cpLen'], closureVals: [_cpLen],
3453
3513
  rootDefs: cRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: cAnchors, rootSchema: schema, userFormats: userFormats || null }
3454
3514
  const lines = []
package/lib/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  //
8
8
  // Kept in lockstep with package.json by `tests/test_version_sync.js`.
9
9
 
10
- module.exports = '1.6.0';
10
+ module.exports = '1.6.2';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile to per-schema ESM modules with zero validator dependency. Generic Validator<T> for TypeBox/Zod/Valibot composition. Optional runtime API. Standard Schema V1 compatible.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -44,7 +44,7 @@
44
44
  "release:check": "node scripts/regen-safe-regex-source.js && node tests/test_pack_purity.js && node scripts/check-doc-coverage.js && node tests/test_error_codes_lock.js && node tests/test_safe_regex_source_sync.js && node tests/test_version_sync.js",
45
45
  "build": "cmake-js build --target ata",
46
46
  "rebuild": "cmake-js rebuild --target ata",
47
- "test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_format_engine_parity.js && node tests/test_defs_pointer_alias.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_order.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_data_positions.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node benchmark/bench_aot_size.mjs",
47
+ "test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_format_engine_parity.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_code_lookup.js && node tests/test_error_order.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_enrich_received.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_data_positions.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node benchmark/bench_aot_size.mjs",
48
48
  "bench:size": "node benchmark/bench_aot_size.mjs",
49
49
  "test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
50
50
  "test:compat": "node tests/test_compat.js",
@@ -112,12 +112,12 @@
112
112
  "LICENSE"
113
113
  ],
114
114
  "optionalDependencies": {
115
- "@ata-validator/native-darwin-arm64": "1.6.0",
116
- "@ata-validator/native-linux-x64-gnu": "1.6.0",
117
- "@ata-validator/native-linux-arm64-gnu": "1.6.0",
118
- "@ata-validator/native-linux-x64-musl": "1.6.0",
119
- "@ata-validator/native-linux-arm64-musl": "1.6.0",
120
- "@ata-validator/native-win32-x64": "1.6.0"
115
+ "@ata-validator/native-darwin-arm64": "1.6.2",
116
+ "@ata-validator/native-linux-x64-gnu": "1.6.2",
117
+ "@ata-validator/native-linux-arm64-gnu": "1.6.2",
118
+ "@ata-validator/native-linux-x64-musl": "1.6.2",
119
+ "@ata-validator/native-linux-arm64-musl": "1.6.2",
120
+ "@ata-validator/native-win32-x64": "1.6.2"
121
121
  },
122
122
  "peerDependencies": {
123
123
  "yaml": "^2.0.0"
package/t.d.ts CHANGED
@@ -34,7 +34,18 @@ export type TOptional<S> = S & { readonly [OPTIONAL]: true };
34
34
 
35
35
  export type TSchema = JSONSchema;
36
36
 
37
- export interface StringOptions {
37
+ /**
38
+ * Shared by every builder option bag. Annotations and vendor keywords (custom
39
+ * keywords outside the JSON Schema vocabulary) are carried through to the
40
+ * emitted schema, so the option types accept them.
41
+ */
42
+ export interface CommonOptions {
43
+ description?: string;
44
+ title?: string;
45
+ [keyword: string]: unknown;
46
+ }
47
+
48
+ export interface StringOptions extends CommonOptions {
38
49
  minLength?: number;
39
50
  maxLength?: number;
40
51
  pattern?: string;
@@ -45,7 +56,7 @@ export interface StringOptions {
45
56
  examples?: readonly string[];
46
57
  }
47
58
 
48
- export interface NumericOptions {
59
+ export interface NumericOptions extends CommonOptions {
49
60
  minimum?: number;
50
61
  maximum?: number;
51
62
  exclusiveMinimum?: number;
@@ -57,7 +68,7 @@ export interface NumericOptions {
57
68
  examples?: readonly number[];
58
69
  }
59
70
 
60
- export interface ArrayOptions {
71
+ export interface ArrayOptions extends CommonOptions {
61
72
  minItems?: number;
62
73
  maxItems?: number;
63
74
  uniqueItems?: boolean;
@@ -65,13 +76,13 @@ export interface ArrayOptions {
65
76
  title?: string;
66
77
  }
67
78
 
68
- export interface ObjectOptions {
79
+ export interface ObjectOptions extends CommonOptions {
69
80
  additionalProperties?: boolean | JSONSchema;
70
81
  description?: string;
71
82
  title?: string;
72
83
  }
73
84
 
74
- export interface RecordOptions {
85
+ export interface RecordOptions extends CommonOptions {
75
86
  minProperties?: number;
76
87
  maxProperties?: number;
77
88
  description?: string;