ata-validator
1.61.3 · 29 Oct 2026MIT21.8k / weekRepositoryHomepagenpmAtom feed
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, andtests/test_compile_cache_order.jsruns 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).errors3.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()reportedclosurefor a schema that compiles, once a valid document had been validated first. It now reportscodegenin 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 intests/test_no_eval.jswere raised so the new cases cannot be lost silently.uriis 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 anduriwas 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 withsliceand asking the copy forlastIndexOfand two regular expressions.format: urion one string, through a compiled validator: 92 to 42 ns. The same product schema's document: 697 to 423 ns. End to end, whereJSON.parseis 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
emailalready had.tests/test_uri_helper_parity.jsholds 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.
receiveddescribes the offending value in at most 60 characters, and it used to find out whether a value fitted by serialising it whole, so arequirederror on a large payload cost aJSON.stringifyof 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, wherevalidate()reports 16 errors, reading.errorswent 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 owntoJSON.The error's value is resolved from its pointer once and handed to both the
receivedrepr and the suggestion sources.lib/suggestions.jshad a second pointer walk that split the string and mapped over the segments; both paths now useresolvePointerinlib/pointer.js.levenshteinreads 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.jsholds enrichment to within 4x across a hundredfold increase in document volume. Before this change the same measurement was 122x.