ata-validator
1.61.3 · 29 Oct 2026MIT21.8k / weekRepositoryHomepagenpmAtom feed
1.61.3 is the newest release of 1.x.
In short
3 new1 fixed4 changed
Release note
Large schemas compile to code V8 can optimize, which makes a 167 KB configuration schema three to seven times faster to validate; the lite entry is published at last; the text scanner stops at the first member it can refuse; the package is run under Deno in CI and published on JSR; and parseJSON works with the native engine loaded.
Measured against 1.47.0 on an Apple M4 Pro, Node 25.2.1, pure JS: cold start 7.2 to 6.9 ms and require alone 4.8 to 4.5 ms; a served request, hot validation, compile time, heap per validator and every ata build module unchanged, the modules byte for byte. A 69 KB request body whose first item is wrong is refused from the text in 26 µs where 1.47.0 took 112.
Added
ata-validator/liteis published: theValidatorand the one-shot functions on the interpreted engine alone, without the code generator, for pages and workers where the size of what ships matters. It existed in the repository with its parity test since 1.19.0 and was never in the tarball or theexportsmap, so nothing could import it. In a Hono app bundled for Workers the runtime entry is 136 KB gzipped and the lite entry 58 KB, with the same verdicts and errors.A JSR package,
@ata/validator, fromjsr/: it re-exports the npm package of the same version, sojsr:@ata/validatorandnpm:ata-validatorare one engine. Published by.github/workflows/jsr.ymlafter the npm version is visible;tests/test_version_sync.jsholds its version and specifiers topackage.json.CI runs the package under Deno on every change: a smoke test with dynamic code refused the way Deno Deploy refuses it (
tests/deno_smoke.ts), the suite withevalandnew Functionblocked, and the official suite in three dialects.
Fixed
parseJSONthrewnative.parseJSON is not a functionwhenever the native engine was loaded: the addon has not carried that function since the per-platform packages, and the pure-JS fallback hid it. It parses with JSON.parse, and a Buffer is decoded first (tests/test_parse_json.js).
Changed
validateJSON()resolves the position map on the first read of an error'sdataFrameoranchor, not when the error list is read. The map is a walk of the document that a caller reading messages and paths never needs; on a 60 KB document with 137 errors reading the list went from 907 to 505 µs, and reading every frame costs what it did. The frames are the same shape: present when the text has the value, absent otherwise, enumerable and serialized, and assignable.Large property subschemas compile to functions of their own instead of inline code, in all three generators (the verdict, the error collector and the one-pass function). V8 does not optimize a function past its bytecode budget, and a configuration schema of a few hundred properties compiled to one function of a megabyte or more that ran in the interpreter for its whole life. Measured on a 167 KB schema of 140 sections with a 60 KB document, fresh
JSON.parseon every call: the runtime verdict 522 to 154 µs (the parse alone is 115), a rejected document with its errors read 335 to 71 µs; a standalone module'svalidate()on the rejected document 891 to 146 µs, itsvalidateJSON()with positions 1249 to 494, and with--one-pass613 to 402. The threshold is on the schema's own size, so small schemas compile exactly as before; a property of fewer than 700 bytes of schema stays inline unless the function around it already holds 24 KB of code.The JSON text scanner behind
isValidJSON()andvalidateJSON()ends the scan when a member fails and its key cannot repeat later in the object: two native searches over the rest of the text, for the key as written and for any backslash, which is the only way to spell it differently, replace the full pass the duplicate-key rule required. A 69 KB request body whose first item is wrong is refused in 26 µs where it took 112, against 149 for JSON.parse alone; a wrong top-level shape stays at 1.5 µs. Verdicts are unchanged: a key that does repeat, plain or escaped, still goes to the parser (tests/test_scanner_early_exit.js, and the scanner differential's 413,178 comparisons agree).package.jsondeclares"type": "commonjs", which it already was. Deno reads a.jsfile as ESM without it; Node's default is unchanged.