ata-validator 1.4.0 → 1.5.1

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,24 @@
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.5.1 - 2026-08-07
6
+
7
+ ### Fixed
8
+
9
+ - `isValid()` on a buffer disagreed with `validate()` on the parsed value for 294 of 2208 cases in the official suite, in both directions. Two causes: the path returned the code generator's `false` directly, which is ambiguous between "invalid" and "the plan stopped at a composition opcode and the walker should finish", so every schema using `allOf`, `anyOf`, `oneOf` or `$ref` was rejected outright; and it ended in a second, simpler walker that had drifted from the one `validate()` uses. It now calls the same walker with all errors off, so there is one set of semantics rather than two kept in step by hand. The disagreement drops to 243 cases, the rest being the on-demand plan answering before the walker runs, which is engine work rather than a setting.
10
+ - `tests/test_buffer_path_parity.js` records that number so it cannot widen, and the README and the edge runtimes guide now state the gap, since `isValid`, `countValid` and `batchIsValid` are shipped APIs and a caller has no way to know otherwise.
11
+
12
+ ### Changed
13
+
14
+ - `ATA_NO_MIMALLOC` skips the bundled `mimalloc-new-delete.h` include. A toolchain that ships the mimalloc headers along with its own `operator new`/`delete` over the same allocator hits a duplicate symbol at link time; Emscripten with `-sMALLOC=mimalloc` is that case, so the source could not be compiled to WebAssembly at all. The native build does not define it and is unchanged.
15
+
16
+ ## 1.5.0 - 2026-08-05
17
+
18
+ ### Added
19
+
20
+ - `propertyDependencies`, a JSON Schema v1 [proposal](https://github.com/json-schema-org/json-schema-spec/blob/main/specs/proposals/propertyDependencies.md), selects a subschema by the value of a property rather than by its presence. It replaces the `oneOf` and `if`/`then` patterns normally used to branch on a discriminator field, and reads as `{ "propertyDependencies": { "type": { "customer": { ... }, "employee": { ... } } } }`. The proposal defines the keyword as equivalent to an `if`/`then` on `const`, and `tests/test_property_dependencies.js` checks that equivalence case by case rather than asserting a separate expectation, alongside the proposal's own test files from the official suite: 36 of 38, the two remaining being a `$dynamicRef` scope gap the `if`/`then` form of the same schema hits identically.
21
+ - The keyword is implemented in the interpreted engine. Both JS compiler paths decline a schema that uses it rather than emitting nothing for a keyword they do not know, which would make the constraint vacuous.
22
+
5
23
  ## 1.4.0 - 2026-08-04
6
24
 
7
25
  ### Fixed
package/README.md CHANGED
@@ -22,6 +22,10 @@ npm install ata-validator --omit=optional
22
22
 
23
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.
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.
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).
28
+
25
29
  In your code:
26
30
 
27
31
  ```ts
package/index.js CHANGED
@@ -1061,8 +1061,11 @@ class Validator {
1061
1061
  this._ensureNative();
1062
1062
  const _hasDynRef = this._schemaStr.includes('"$dynamicRef"') || this._schemaStr.includes('"$dynamicAnchor"')
1063
1063
  const _hasUneval = this._schemaStr.includes('"unevaluatedProperties"') || this._schemaStr.includes('"unevaluatedItems"')
1064
+ // propertyDependencies exists only in the interpreted engine, so a schema
1065
+ // using it goes there even when it also uses $dynamicRef.
1066
+ const _hasPropDeps = this._schemaStr.includes('"propertyDependencies"')
1064
1067
  let _validate;
1065
- if (_hasDynRef && !_hasUneval) {
1068
+ if (_hasDynRef && !_hasUneval && !_hasPropDeps) {
1066
1069
  // validateJSON is the C++ path with full anchor-map support; the NAPI
1067
1070
  // direct V8 `validate` path has no anchor maps.
1068
1071
  _validate = (data) => this._compiled.validateJSON(JSON.stringify(data));
@@ -102,6 +102,16 @@ function walkSchema(node, baseUri, state, isResourceRoot) {
102
102
  const list = node[kw];
103
103
  if (Array.isArray(list)) for (const sub of list) walkSchema(sub, baseUri, state, false);
104
104
  }
105
+ // propertyDependencies nests one level deeper than the other maps:
106
+ // property name -> property value -> schema.
107
+ const propDeps = node.propertyDependencies;
108
+ if (propDeps && typeof propDeps === 'object' && !Array.isArray(propDeps)) {
109
+ for (const choices of Object.values(propDeps)) {
110
+ if (choices && typeof choices === 'object' && !Array.isArray(choices)) {
111
+ for (const sub of Object.values(choices)) walkSchema(sub, baseUri, state, false);
112
+ }
113
+ }
114
+ }
105
115
  }
106
116
 
107
117
  // ---------- ref resolution ----------
@@ -504,6 +514,23 @@ class Interpreter {
504
514
  }
505
515
  }
506
516
  }
517
+ // propertyDependencies: like dependentSchemas but keyed on the property's
518
+ // value rather than its presence. Only string values can match, since the
519
+ // inner keys are object keys. Equivalent to
520
+ // `if: { properties: { p: { const: v } }, required: [p] }, then: <schema>`.
521
+ if (schema.propertyDependencies && typeof schema.propertyDependencies === 'object') {
522
+ for (const [key, choices] of Object.entries(schema.propertyDependencies)) {
523
+ if (!choices || typeof choices !== 'object' || Array.isArray(choices)) continue;
524
+ if (!Object.prototype.hasOwnProperty.call(data, key)) continue;
525
+ const value = data[key];
526
+ if (typeof value !== 'string') continue;
527
+ if (!Object.prototype.hasOwnProperty.call(choices, value)) continue;
528
+ const sub = { props: null, items: null };
529
+ const branchPath = schemaPath + '/propertyDependencies/' + escapePointer(key) + '/' + escapePointer(value);
530
+ if (!this.eval(choices[value], data, base, dynScope, errors, instancePath, branchPath, stack, sub)) valid = false;
531
+ else mergeAnnotations(local, sub);
532
+ }
533
+ }
507
534
  }
508
535
 
509
536
  // in-place applicators
@@ -115,6 +115,7 @@ function compileToJS(schema, defs, schemaMap) {
115
115
  // Bail on features that are too complex for JS fast path
116
116
  if (schema.patternProperties ||
117
117
  schema.dependentSchemas ||
118
+ schema.propertyDependencies ||
118
119
  schema.propertyNames) {
119
120
  return null
120
121
  }
@@ -749,6 +750,11 @@ function codegenSafe(schema, schemaMap) {
749
750
  if (typeof schema === 'boolean') return true
750
751
  if (typeof schema !== 'object' || schema === null) return true
751
752
 
753
+ // propertyDependencies is a proposal the interpreted engine implements and
754
+ // neither JS path does. Emitting nothing for it would make the keyword
755
+ // vacuous, so hand the schema over rather than silently ignore a constraint.
756
+ if (schema.propertyDependencies !== undefined) return false
757
+
752
758
  // Only bail on $dynamicRef if it can't be resolved at compile time
753
759
  if (schema.$dynamicRef && !schema.$dynamicRef.startsWith('#')) return false
754
760
 
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.4.0';
10
+ module.exports = '1.5.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
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_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_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",
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",
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.4.0",
116
- "@ata-validator/native-linux-x64-gnu": "1.4.0",
117
- "@ata-validator/native-linux-arm64-gnu": "1.4.0",
118
- "@ata-validator/native-linux-x64-musl": "1.4.0",
119
- "@ata-validator/native-linux-arm64-musl": "1.4.0",
120
- "@ata-validator/native-win32-x64": "1.4.0"
115
+ "@ata-validator/native-darwin-arm64": "1.5.1",
116
+ "@ata-validator/native-linux-x64-gnu": "1.5.1",
117
+ "@ata-validator/native-linux-arm64-gnu": "1.5.1",
118
+ "@ata-validator/native-linux-x64-musl": "1.5.1",
119
+ "@ata-validator/native-linux-arm64-musl": "1.5.1",
120
+ "@ata-validator/native-win32-x64": "1.5.1"
121
121
  },
122
122
  "peerDependencies": {
123
123
  "yaml": "^2.0.0"