ata-validator 1.27.1 → 1.28.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 CHANGED
@@ -2,6 +2,16 @@
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.28.0 - 2026-09-23
6
+
7
+ ### Added
8
+
9
+ - `engine: 'interpreter'`, a per-validator setting that keeps a schema off code generation: no `new Function`, no shared compile cache; the eval-free interpreted engine answers `validate()`, `isValidObject()` and `validateJSON()`. The default is the right trade for a schema the application wrote. A schema that arrives at runtime from a plugin or a tenant is input, and until now the only way to validate against one without executing source derived from it was the process-wide `ATA_FORCE_NAPI` switch. `engine()` reports `'interpreter'` for such a validator; any value other than `'auto'` or `'interpreter'` throws, so a misspelling cannot fall through to the generator. `tests/test_engine_option.js` holds the verdicts equal across engines and proves, with `Function` guarded, that the interpreter validator never builds a function from source while the default one does. Contributed by @d4tocchini in #43.
10
+
11
+ ### Changed
12
+
13
+ - The position map behind `dataFrame` is built without per-node work, which makes an invalid document cheaper to report on. It used to record an entry for every node in the document: a JSON pointer rebuilt from a path array with `concat`, `map` and `join`, a binary search and an object allocation for the value and another pair for its key, and a `JSON.parse` of every string value whose result was then discarded. String values are now spanned and not decoded, a key decodes only when its token holds an escape or a raw control character, the pointer is carried down the walk instead of being rebuilt, and line and column are resolved at the end for the nodes that were recorded. On a 132 KB config with three errors the map went from 2800 to about 1040 microseconds, which is 19.8x down to 7.3x the cost of `JSON.parse` on the same text, and the whole `validateJSON` call went from 3673 to 1825 microseconds. Output is unchanged: 112661 fuzzed documents, random and truncated and CRLF and BOM-prefixed and byte-punched, map identically against the previous walker, field order and throws included, so a document that declined to map still declines. Standalone modules built with `{ positions: true }` embed this walk, so they carry the same improvement once rebuilt. `tests/test_position_map_cost.js` gates it as a ratio to `JSON.parse` rather than as a time, because the cost is what regressed.
14
+
5
15
  ## 1.27.1 - 2026-09-17
6
16
 
7
17
  ### Fixed
package/README.md CHANGED
@@ -445,11 +445,14 @@ const v = new Validator(schema, {
445
445
  removeAdditional: true, // strip properties not in schema
446
446
  schemas: [otherSchema], // cross-schema $ref registry
447
447
  abortEarly: true, // skip detailed error collection on failure (~4x faster on invalid data)
448
+ engine: 'interpreter', // eval-free interpreted engine only: for a schema from outside the trust boundary
448
449
  });
449
450
  ```
450
451
 
451
452
  `abortEarly` returns a shared `{ valid: false, errors: [{ message: 'validation failed' }] }` on failure instead of running the detailed error collector. Useful when the caller only needs a pass/fail decision (Fastify route guards, high-throughput gatekeepers, request rejection at the edge).
452
453
 
454
+ `engine: 'interpreter'` keeps one validator off code generation: no `new Function`, no shared compile cache, the interpreted engine answers every call. The default turns a schema into JavaScript source, which is the right trade for a schema you wrote; a schema that arrives at runtime from a plugin or a tenant is input, and this option validates against it without ever executing anything derived from it. Same verdict, higher per-call cost; `ATA_FORCE_NAPI=1` does the same for a whole process.
455
+
453
456
  ### Build-time compile (`ata compile`)
454
457
 
455
458
  The `ata` CLI turns a JSON Schema file into a self-contained JavaScript module. No runtime dependency on `ata-validator`, so only the generated validator ships to the browser. Typical output is about 4.5 KB gzipped for a ten-field schema, full error detail included, against 87 KB for the runtime bundled for the browser.
package/index.d.ts CHANGED
@@ -425,6 +425,17 @@ export interface ValidatorOptions {
425
425
  * v0.14 error shape.
426
426
  */
427
427
  richErrors?: boolean;
428
+ /**
429
+ * Which engine may answer this validator. 'auto' (default) picks the fastest
430
+ * engine that handles the schema, generated JavaScript for most schemas.
431
+ * 'interpreter' keeps the schema off code generation entirely: no
432
+ * `new Function`, no shared compile cache; the eval-free interpreted engine
433
+ * answers `validate()`, `isValidObject()` and `validateJSON()`. For a schema
434
+ * that arrives from outside the trust boundary. The verdict is the same on
435
+ * every engine; the cost is not. The buffer APIs (`isValid`, `countValid`,
436
+ * `batchIsValid`) are native-only and unaffected.
437
+ */
438
+ engine?: 'auto' | 'interpreter';
428
439
  }
429
440
 
430
441
  export interface BundleStandaloneOptions extends ValidatorOptions {
@@ -473,7 +484,7 @@ export interface Validator<T = unknown> {
473
484
  * Which engine answers `validate()` for this schema: 'codegen' (generated
474
485
  * JS), 'closure' (the closure compiler) or 'interpreter'; 'native' is
475
486
  * reserved. The verdict is the same on every engine; the cost is not.
476
- * A diagnostic, not a configuration.
487
+ * A diagnostic; the `engine` option is the setting.
477
488
  */
478
489
  engine(): 'codegen' | 'closure' | 'native' | 'interpreter';
479
490
 
package/index.js CHANGED
@@ -896,6 +896,18 @@ class Validator {
896
896
  this._rawIsCallers = typeof schema !== "string";
897
897
  this._options = options;
898
898
  this._noOpts = !opts;
899
+ // engine: 'interpreter' keeps this validator off code generation: no
900
+ // `new Function`, no shared compile cache, the eval-free interpreted
901
+ // engine answers validate(), isValidObject() and validateJSON(). For a
902
+ // schema that arrives from outside the trust boundary (a plugin's
903
+ // declared config shape, a tenant's upload), where turning it into source
904
+ // is not an acceptable execution model. ATA_FORCE_NAPI does this for the
905
+ // whole process; the option does it for one validator. A misspelling
906
+ // must not fall through to codegen, so anything else is refused.
907
+ if (options.engine !== undefined && options.engine !== 'auto' && options.engine !== 'interpreter') {
908
+ throw new TypeError("engine must be 'auto' or 'interpreter', got " + JSON.stringify(options.engine));
909
+ }
910
+ this._interpretOnly = options.engine === 'interpreter';
899
911
  this._initialized = false;
900
912
  this._nativeReady = false;
901
913
  this._compiled = null;
@@ -1044,11 +1056,14 @@ class Validator {
1044
1056
  // Check cache first -- reuse compiled functions for same schema
1045
1057
  const sm = this._schemaMap.size > 0 ? this._schemaMap : null;
1046
1058
  const mapKey = compileCacheKey(this._schemaStr, this._schemaMap);
1059
+ var _forceNapi = this._interpretOnly || (typeof process !== 'undefined' && process.env && process.env.ATA_FORCE_NAPI);
1047
1060
  // Custom formats are JS functions: bypass the compile cache since they can
1048
- // differ between validators that share the same schema string.
1049
- const cached = (this._userFormats || this._usesKeywords) ? null : _compileCache.get(mapKey);
1061
+ // differ between validators that share the same schema string. An
1062
+ // interpreter-only validator never touches it either way: a function a
1063
+ // trusted validator compiled for the same schema string must not answer
1064
+ // for it.
1065
+ const cached = (this._userFormats || this._usesKeywords || _forceNapi) ? null : _compileCache.get(mapKey);
1050
1066
  let jsFn, jsCombinedFn, jsErrFn, _isCodegen = false;
1051
- var _forceNapi = typeof process !== 'undefined' && process.env && process.env.ATA_FORCE_NAPI;
1052
1067
  // v1 removes the bookending requirement for $dynamicRef. Only the
1053
1068
  // interpreted engine implements that; the JS compiler and the native
1054
1069
  // engine both resolve the 2020-12 way, so a v1 schema using the keyword
@@ -1063,15 +1078,16 @@ class Validator {
1063
1078
  // either. The closure path does not call `new Function` itself, so it
1064
1079
  // survives the block and would quietly handle schemas it gets wrong; the
1065
1080
  // interpreted engine is both eval-free and more correct, so go straight
1066
- // there.
1067
- if (this._v1Dynamic || this._usesKeywords || !codegenAvailable()) {
1081
+ // there. The forced case is decided before the probe: the probe is a
1082
+ // `new Function` too, and a validator that promised none must not run it.
1083
+ if (_forceNapi || this._v1Dynamic || this._usesKeywords || !codegenAvailable()) {
1068
1084
  jsFn = null; jsCombinedFn = null; jsErrFn = null;
1069
1085
  // `full` separates an entry that holds every compiled function from one
1070
1086
  // the verdict-only fast path seeded, where `combined` and `errFn` are null
1071
1087
  // because nothing has tried to build them yet. Both halves of that
1072
1088
  // distinction are null, and reading the second as the first costs this
1073
1089
  // schema its generated error function for the life of the process.
1074
- } else if (cached && cached.jsFn !== undefined && !_forceNapi) {
1090
+ } else if (cached && cached.jsFn !== undefined) {
1075
1091
  // `full` says the error and combined functions exist too. An entry
1076
1092
  // without it still carries a verdict function worth reusing; the pair is
1077
1093
  // built by _buildDeferred below if something asks for an error, and the
@@ -1084,7 +1100,7 @@ class Validator {
1084
1100
  jsErrFn = cached.errFn;
1085
1101
  _isCodegen = !!cached.isCodegen;
1086
1102
  this._engine = _isCodegen ? 'codegen' : jsFn ? 'closure' : null;
1087
- } else if (!_forceNapi) {
1103
+ } else {
1088
1104
  const uf = this._userFormats;
1089
1105
  const _cgFn = compileToJSCodegen(schemaObj, sm, uf);
1090
1106
  jsFn = _cgFn || compileToJS(schemaObj, null, sm);
@@ -1100,8 +1116,6 @@ class Validator {
1100
1116
  if (!uf) {
1101
1117
  _compileCache.set(mapKey, { jsFn, combined: undefined, errFn: undefined, isCodegen: _isCodegen, full: false });
1102
1118
  }
1103
- } else {
1104
- jsFn = null; jsCombinedFn = null; jsErrFn = null;
1105
1119
  }
1106
1120
  this._jsFn = jsFn;
1107
1121
  if (this._engine === undefined) this._engine = null;
@@ -1111,7 +1125,10 @@ class Validator {
1111
1125
  // shape (e.g. Fastify `params: { $ref: 'shared#' }` or property refs like
1112
1126
  // `{ id: { $ref: 'shared#/properties/id' } }`).
1113
1127
  const preprocessSchema = resolveSchemaForPreprocess(schemaObj, this._schemaMap);
1114
- let preprocess = buildPreprocessCodegen(preprocessSchema, options);
1128
+ // The mutator pass (defaults, coercion, removal) is generated source too,
1129
+ // with the schema's `default` values embedded; an interpreter-only
1130
+ // validator takes the closure mutators instead.
1131
+ let preprocess = this._interpretOnly ? null : buildPreprocessCodegen(preprocessSchema, options);
1115
1132
  if (!preprocess) {
1116
1133
  const applyDefaults = options.useDefaults === false ? null : buildDefaultsApplier(preprocessSchema);
1117
1134
  const applyCoerce = options.coerceTypes ? buildCoercer(preprocessSchema) : null;
@@ -1999,7 +2016,7 @@ class Validator {
1999
2016
  return;
2000
2017
  }
2001
2018
  this._ensureVocabularies();
2002
- if (typeof process !== 'undefined' && process.env && process.env.ATA_FORCE_NAPI) return;
2019
+ if (this._interpretOnly || (typeof process !== 'undefined' && process.env && process.env.ATA_FORCE_NAPI)) return;
2003
2020
  if (!this._schemaStr) this._schemaStr = JSON.stringify(this._schemaObj);
2004
2021
  const sm = this._schemaMap.size > 0 ? this._schemaMap : null;
2005
2022
  const mapKey = compileCacheKey(this._schemaStr, this._schemaMap);
@@ -9,27 +9,22 @@
9
9
  // Self-contained on purpose: `toStandaloneModule({ positions: true })` embeds
10
10
  // this function verbatim via Function.prototype.toString, so it may not close
11
11
  // over anything in this module and may not assume Node globals. The inlined
12
- // escapePtr below duplicates lib/source-positions.js for that reason.
12
+ // pointer escaping below duplicates lib/source-positions.js for that reason.
13
13
  function buildDataPositionMap (input) {
14
- const escapePtr = (s) => s.replace(/~/g, '~0').replace(/\//g, '~1');
15
14
  const text = (typeof Buffer !== 'undefined' && Buffer.isBuffer(input)) ? input.toString('utf8') : String(input);
16
15
  const map = Object.create(null);
17
- const lines = text.split('\n');
18
- const lineStart = new Array(lines.length + 1);
19
- lineStart[0] = 0;
20
- for (let i = 0; i < lines.length; i++) lineStart[i + 1] = lineStart[i] + lines[i].length + 1;
16
+ const n = text.length;
21
17
 
22
- function offsetToLineCol (off) {
23
- let lo = 0, hi = lineStart.length - 1;
24
- while (lo < hi) {
25
- const mid = (lo + hi + 1) >> 1;
26
- if (lineStart[mid] <= off) lo = mid; else hi = mid - 1;
27
- }
28
- return { line: lo + 1, col: off - lineStart[lo] + 1, text: lines[lo] || '' };
29
- }
18
+ // Offsets during the walk, line and column afterwards. Resolving them here
19
+ // cost a binary search and an object allocation for every node in the
20
+ // document, when only the nodes an error names are ever read.
21
+ const ptrs = [];
22
+ const starts = [];
23
+ const lens = [];
24
+ const keyStarts = [];
25
+ const keyLens = [];
30
26
 
31
27
  let i = 0;
32
- const n = text.length;
33
28
 
34
29
  function skipWs () {
35
30
  while (i < n) {
@@ -38,28 +33,40 @@ function buildDataPositionMap (input) {
38
33
  }
39
34
  }
40
35
 
41
- function readString () {
36
+ // Span the string token, leaving `i` just past the closing quote. A plain
37
+ // token is sliced; one holding an escape or a raw control character goes
38
+ // through JSON.parse, which is what decodes `é` and what rejects a
39
+ // literal newline or a bad escape. Values are spanned and not decoded, but a
40
+ // malformed one still has to be rejected, so it is parsed for the throw.
41
+ //
42
+ // A token that does not open with a quote is not simple either. Object keys
43
+ // are read here unconditionally, so a document whose opening quote is missing
44
+ // (`{ mo": 1 }`) arrives with `m` under the cursor, and slicing it would map a
45
+ // key nobody wrote. Parsing the span rejects it instead.
46
+ function readString (decode) {
42
47
  const start = i;
48
+ let simple = text.charCodeAt(i) === 0x22;
43
49
  i++;
50
+ let closed = false;
44
51
  while (i < n) {
45
52
  const ch = text.charCodeAt(i);
46
- if (ch === 0x5c) { i += 2; continue; }
47
- if (ch === 0x22) { i++; return JSON.parse(text.slice(start, i)); }
53
+ if (ch === 0x5c) { simple = false; i += 2; continue; }
54
+ if (ch === 0x22) { i++; closed = true; break; }
55
+ if (ch < 0x20) simple = false;
48
56
  i++;
49
57
  }
50
- throw new Error('unterminated string at offset ' + start);
58
+ if (!closed) throw new Error('unterminated string at offset ' + start);
59
+ if (simple) return decode ? text.slice(start + 1, i - 1) : null;
60
+ const decoded = JSON.parse(text.slice(start, i));
61
+ return decode ? decoded : null;
51
62
  }
52
63
 
53
- function pointerOf (path) {
54
- if (path.length === 0) return '';
55
- return '/' + path.map(escapePtr).join('/');
56
- }
57
-
58
- function walk (path, keySpan) {
64
+ // The pointer is carried down the walk. Rebuilding it per node from a path
65
+ // array cost an array copy, a map and a join for every node.
66
+ function walk (ptr, keyStart, keyLen) {
59
67
  skipWs();
60
68
  if (i >= n) return;
61
69
  const start = i;
62
- const pos = offsetToLineCol(start);
63
70
 
64
71
  const ch = text.charCodeAt(i);
65
72
  if (ch === 0x7b) {
@@ -76,19 +83,16 @@ function buildDataPositionMap (input) {
76
83
  // Record the key token before consuming it. The caret for an error
77
84
  // that names a property belongs on the property, not on the value and
78
85
  // not on the enclosing object.
79
- const keyStart = i;
80
- const keyPos = offsetToLineCol(keyStart);
81
- const key = readString();
82
- const span = {
83
- keyOffset: keyStart,
84
- keyLength: i - keyStart,
85
- keyLine: keyPos.line,
86
- keyCol: keyPos.col,
87
- };
86
+ const memberKeyStart = i;
87
+ const key = readString(true);
88
+ const memberKeyLen = i - memberKeyStart;
88
89
  skipWs();
89
90
  if (text.charCodeAt(i) !== 0x3a) throw new Error('expected ":" at offset ' + i);
90
91
  i++;
91
- walk(path.concat([key]), span);
92
+ const seg = (key.indexOf('~') === -1 && key.indexOf('/') === -1)
93
+ ? key
94
+ : key.replace(/~/g, '~0').replace(/\//g, '~1');
95
+ walk(ptr + '/' + seg, memberKeyStart, memberKeyLen);
92
96
  }
93
97
  } else if (ch === 0x5b) {
94
98
  i++;
@@ -99,7 +103,7 @@ function buildDataPositionMap (input) {
99
103
  if (text.charCodeAt(i) === 0x5d) { i++; break; }
100
104
  if (text.charCodeAt(i) === 0x2c) { i++; continue; }
101
105
  const before = i;
102
- walk(path.concat([String(idx)]));
106
+ walk(ptr + '/' + idx, -1, 0);
103
107
  // A character that begins no value at all, a stray `}` for instance,
104
108
  // leaves the position where it was, and a loop that does not advance
105
109
  // does not end. `validateJSON('[')` hung here on one byte.
@@ -107,7 +111,7 @@ function buildDataPositionMap (input) {
107
111
  idx++;
108
112
  }
109
113
  } else if (ch === 0x22) {
110
- readString();
114
+ readString(false);
111
115
  } else {
112
116
  while (i < n) {
113
117
  const c = text.charCodeAt(i);
@@ -116,19 +120,51 @@ function buildDataPositionMap (input) {
116
120
  }
117
121
  }
118
122
 
119
- const length = i - start;
120
- const entry = { byteOffset: start, length, line: pos.line, col: pos.col, text: pos.text };
121
- if (keySpan) {
122
- entry.keyOffset = keySpan.keyOffset;
123
- entry.keyLength = keySpan.keyLength;
124
- entry.keyLine = keySpan.keyLine;
125
- entry.keyCol = keySpan.keyCol;
126
- }
127
- map[pointerOf(path)] = entry;
123
+ ptrs.push(ptr);
124
+ starts.push(start);
125
+ lens.push(i - start);
126
+ keyStarts.push(keyStart);
127
+ keyLens.push(keyLen);
128
128
  }
129
129
 
130
130
  if (text.charCodeAt(0) === 0xfeff) i = 1;
131
- walk([]);
131
+ walk('', -1, 0);
132
+
133
+ if (ptrs.length === 0) return map;
134
+
135
+ const lines = text.split('\n');
136
+ const lineStart = new Array(lines.length + 1);
137
+ lineStart[0] = 0;
138
+ for (let k = 0; k < lines.length; k++) lineStart[k + 1] = lineStart[k] + lines[k].length + 1;
139
+
140
+ function lineOf (off) {
141
+ let lo = 0, hi = lineStart.length - 1;
142
+ while (lo < hi) {
143
+ const mid = (lo + hi + 1) >> 1;
144
+ if (lineStart[mid] <= off) lo = mid; else hi = mid - 1;
145
+ }
146
+ return lo;
147
+ }
148
+
149
+ for (let k = 0; k < ptrs.length; k++) {
150
+ const off = starts[k];
151
+ const line = lineOf(off);
152
+ const entry = {
153
+ byteOffset: off,
154
+ length: lens[k],
155
+ line: line + 1,
156
+ col: off - lineStart[line] + 1,
157
+ text: lines[line] || '',
158
+ };
159
+ if (keyStarts[k] >= 0) {
160
+ const keyLine = lineOf(keyStarts[k]);
161
+ entry.keyOffset = keyStarts[k];
162
+ entry.keyLength = keyLens[k];
163
+ entry.keyLine = keyLine + 1;
164
+ entry.keyCol = keyStarts[k] - lineStart[keyLine] + 1;
165
+ }
166
+ map[ptrs[k]] = entry;
167
+ }
132
168
  return map;
133
169
  }
134
170
 
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.27.1';
10
+ module.exports = '1.28.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.27.1",
3
+ "version": "1.28.0",
4
4
  "description": "JSON Schema validation that compiles for speed and still runs where code generation is blocked. Compiled and interpreted engines answer identically at 100% of the official suite. TypeScript inference, Standard Schema V1, and a build step that emits dependency-free modules.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -51,7 +51,7 @@
51
51
  "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",
52
52
  "build": "cmake-js build --target ata",
53
53
  "rebuild": "cmake-js rebuild --target ata",
54
- "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_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.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_native_loaded.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_format_mode.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_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_uri_helper_parity.js && node tests/test_formats_single_pass.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.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_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.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_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_file_positions.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.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",
54
+ "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_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.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_native_loaded.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_format_mode.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_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_uri_helper_parity.js && node tests/test_formats_single_pass.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.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_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.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_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_position_map_cost.js && node tests/test_file_positions.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.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",
55
55
  "bench:size": "node benchmark/bench_aot_size.mjs",
56
56
  "test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
57
57
  "test:compat": "node tests/test_compat.js",
@@ -122,13 +122,13 @@
122
122
  "LICENSE"
123
123
  ],
124
124
  "optionalDependencies": {
125
- "@ata-validator/native-darwin-arm64": "1.27.1",
126
- "@ata-validator/native-darwin-x64": "1.27.1",
127
- "@ata-validator/native-linux-arm64-gnu": "1.27.1",
128
- "@ata-validator/native-linux-arm64-musl": "1.27.1",
129
- "@ata-validator/native-linux-x64-gnu": "1.27.1",
130
- "@ata-validator/native-linux-x64-musl": "1.27.1",
131
- "@ata-validator/native-win32-x64": "1.27.1"
125
+ "@ata-validator/native-darwin-arm64": "1.28.0",
126
+ "@ata-validator/native-darwin-x64": "1.28.0",
127
+ "@ata-validator/native-linux-arm64-gnu": "1.28.0",
128
+ "@ata-validator/native-linux-arm64-musl": "1.28.0",
129
+ "@ata-validator/native-linux-x64-gnu": "1.28.0",
130
+ "@ata-validator/native-linux-x64-musl": "1.28.0",
131
+ "@ata-validator/native-win32-x64": "1.28.0"
132
132
  },
133
133
  "peerDependencies": {
134
134
  "yaml": "^2.0.0"