Packages

ata-validator

1.61.3 · 29 Oct 2026MIT21.8k / weekRepositoryHomepagenpmAtom feed

Your version

1.22.0

14 Sep 2026Where it was published

1.61.3 is the newest release of 1.x.

In short

1 fixed7 changed1 internal

Release note

Fixed

  • A schema validated once with isValidObject() lost its generated error function for the rest of the process. The verdict-only fast path compiles that one function and seeds the shared compile cache with the other two set to null, meaning "not built yet"; the full compile read those nulls as "the compiler declined this schema" and never tried again, so errors fell back to the interpreted engine or the addon. Every server hits that order, because most documents are valid. Cache entries now record whether they are complete. Verdicts and error content were never affected, and tests/test_compile_cache_order.js runs both orders in separate processes and holds the engine and the error list equal.

    • Measured on a five-field schema with an enum and a format, after validating one valid document: validate(bad).errors 3.89 µs to 0.66 µs, the Standard Schema path 3.52 µs to 0.07 µs. With no addon installed at all (ATA_NO_NATIVE=1), where the fallback was the interpreter rather than the addon, 1.05 µs to 0.66 µs and 0.42 µs to 0.07 µs.

    • engine() reported closure for a schema that compiles, once a valid document had been validated first. It now reports codegen in either order.

Changed

  • The official test suite submodule moved 60 commits forward, to 2026-09-13. All three dialects stay at zero regressions and the case counts rose: Draft 2020-12 1299 to 1301, draft 7 927 to 929, the v1 dialect 1133 to 1135, identical with code generation blocked. The buffer path agrees with validate() on all 3365 of them. Every figure in the README, the docs and the contributor notes was remeasured and updated together, and the floors in tests/test_no_eval.js were raised so the new cases cannot be lost silently.

  • uri is one walk over the string instead of three, and reads its character classes out of tables instead of comparison chains. It was the most expensive thing an ordinary document carried: on a schema with five formats over a 1.6 KB payload, format assertion was 94 percent of the validation cost and uri was most of that, while the structural check of the whole nested document was 43 ns. The authority's landmarks, the last @, the colons after it and whether a bracket came before it, are now recorded during the character scan rather than by cutting the authority out with slice and asking the copy for lastIndexOf and two regular expressions.

    • format: uri on one string, through a compiled validator: 92 to 42 ns. The same product schema's document: 697 to 423 ns. End to end, where JSON.parse is the other 75 percent: 2.98 to 2.69 µs.

    • Measured, and not taken: nine === tests per character cost more than the loop they guarded, a lookup table is 2.3x that chain, and a three-regex formulation of the whole rule landed at 65 ns against the table walk's 41.

    • The code generator hoists the walk once per compiled function and calls it, rather than inlining it at each call site where the tables would have to be rebuilt. This is the shape email already had. tests/test_uri_helper_parity.js holds the function, the generated text and a compiled validator to the same answer over 35,677 strings built from the walk's own boundaries.

  • Enriching a rejection no longer reads more of the document than the diagnostic it produces. received describes the offending value in at most 60 characters, and it used to find out whether a value fitted by serialising it whole, so a required error on a large payload cost a JSON.stringify of that payload, once per error. Sizing is now bounded by those 60 characters and stops as soon as they are spent. Enriching one error on a document holding a thousand rows: 61.5 µs to 160 ns, and flat in the size of the document rather than linear. On the schema-benchmarks product schema, where validate() reports 16 errors, reading .errors went from 9.84 to 5.10 µs (48 percent less) on the same machine, separate processes. Verdict paths, isValidObject() and the Standard Schema bridge are unchanged.

  • An object too large to show reports its shape rather than its serialised size: [object, 5 keys] where it used to say [object, ~0.1KB]. This is the only change to error output; every value that printed its body before prints the same body now, including nested objects, arrays and values with their own toJSON.

  • The error's value is resolved from its pointer once and handed to both the received repr and the suggestion sources. lib/suggestions.js had a second pointer walk that split the string and mapped over the segments; both paths now use resolvePointer in lib/pointer.js.

  • levenshtein reads characters by code and swaps its two rows through a temporary. The destructured swap it used built an array per row. About 9 percent faster on the key pairs the suggestion sources compare.

  • tests/test_enrich_received.js holds enrichment to within 4x across a hundredfold increase in document volume. Before this change the same measurement was 122x.