Packages

ata-validator

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

Upgrading ata-validator from 1.53.0 to 1.54.0

1 release in betweenevery note read

Reading releases, release notes and advisories…

Other targets from 1.53.0Newest 1.x, Latest1.61.3
0
changes to make
0
advisories fixed
0
new
7
fixes

Release by release

  1. 1.54.0

    15 Oct 20267 fixes
    • fixed

      The uri, uri-reference, iri and iri-reference formats follow RFC 3986 in full. They checked the characters and, for uri, the shape of the authority; a bracketed host was not read, so http://[::ffff:01.2.3.4] passed, and uri-reference checked only the characters, so //example.com:abc/p, //a@b@example.com/, /[::1] and 1:b passed. One walk now parses scheme, authority (userinfo, a host that is a name, an IPv6 literal with its embedded IPv4, an RFC 6874 zone id or an IPvFuture, and a digits-only port), path, query and fragment, and rejects brackets outside the host, a colon in the first segment of a relative path and a second #. It lives in lib/uri-core.js and is the same text in the interpreted engine, generated code and standalone modules. The uri expression in front of it now takes a host with a port, which most of SchemaStore's misses were (http://localhost:5000, 73 to 34 ns in generated code), and a reference made only of plain characters, a file name or a path, is answered by one scan before the walk, so those checks cost what the character scan did. On the 26321 strings in SchemaStore's sample documents uri and iri give the same answers as before; uri-reference now rejects 346 of them, every one a string that is not a URI reference ([string], 00:00:01, 2022-01-19T22:02:33Z), 277 of which the default validator still accepts.

    • fixed

      uri-template: a % in a literal or a variable name must start a percent-encoded triplet (a%, a%4, a%GG, {%} were accepted).

    • fixed

      idn-email: a domain label that starts or ends with a hyphen is refused, as email refuses it (the official suite's 7de0e6a adds these cases).

    • fixed

      email: the inside of a quoted local part is checked ("test\©"@iana.org was accepted, a quoted pair takes one printable ASCII character), and the IPv6: tag of an address literal is read in any case (a@[ipv6:::1] was rejected).

    • fixed

      A node without type: object checked an array against its properties: [1, 2] was rejected by { properties: { length: { maximum: 1 } } }, through the array's own length, while the interpreter and the default validator accept it. Generated code now skips arrays there when a property name is one an array can own (length or an index); other names were already safe, since an array only inherits them. A required key on such a node is also read before it is asked whether it is the object's own, which saves a test. tests/test_untyped_properties.js covers both on 189 documents.

    • fixed

      Draft-04 is read as draft-04. A schema that declared it was read as 2020-12: id did not set the base URI, tuple items, additionalItems and dependencies were not applied, and const, contains and propertyNames, which draft-04 does not have, were. It now goes through the draft-06 rules plus its own (id for $id, those three keywords dropped), and its meta-schema is vendored with the others. The official suite's draft-04 tests pass, 618 of 618, also with code generation blocked; npm run test:suite runs them. SchemaStore's draft-04 schemas answer their sample documents as before.

    • fixed

      A declared property holding undefined still got different answers in 1.53.0: the generated code checked the value where the key was required, where the node had no type, and inside if, not and similar subschemas, and the engines disagreed on whether a required key holding undefined was there. Every engine now reads such a key as the default validator does, and as it reads once serialized: absent. Its value is not checked, and a required key holding it is missing, so { a: undefined } no longer passes required: ['a'] on any engine. { if: { properties: { t: { const: 'x' } } }, then: false } accepted { t: undefined } on generated code and rejected it on the interpreter; both reject it now. tests/test_undefined_property.js covers 21 shapes on every engine, with and without code generation.

19 other lines we could not sort, mostly version bumps
  • Two schemas that generate the same code no longer slow each other down. V8 keeps one compiled function per source text of a new Function call, with one set of inline caches, so two copies of a record schema under different $ids, each validating lists of a different shape, ran each other's caches megamorphic: 500 records took 2.8 us alone and 18.0 with the twin in the same process. Every program compiled at run time now opens with a comment that differs per compile, 2.8 us either way. Standalone builds carry no such comment, so a build is the same text whatever was compiled before it.

    1.54.0
  • Reading the errors of a list of records with many optional properties, where the records do not share one shape, took 20.6 ms for 2000 records and now takes 0.57. The error program guards each record with a verdict and collects only the one that fails; the guard for a 150-property record was written one read per property, 16.9 KB, over the size the program accepts, so there was no guard and every record was collected in full with reads that change shape at each one. The guard now takes the key-loop form the verdict uses for such records, 10 KB, and runs only on a list whose first, middle and last records list different keys: records of one shape are read as before (16 us for the same 2000). On the way the key loop's switch, pushed as separate lines, read switch(k){;case once joined with ;, a syntax error that made the rich error program fall back to the plain one without a word; it is one line now and tests/test_rich_key_loop_guard.js holds the compile.

    1.54.0
  • A oneOf under type: object writes its branches for an object already checked, without the type test and the second own-key read each branch made for its required keys (vercel's now.json spends 23% of a validation in two such branches). A branch reached where the type is not known keeps its test, as a separate function.

    1.54.0
  • A pattern that only names keys, ^cdn$ or ^(cdn|Cdn)$, is a string comparison in generated code, and .* is no test at all. appsettings carries eight such patterns and answered each with a regex run per key; its samples validate 15% faster. tests/test_pattern_literal_keys.js holds the shapes that must still be a regex (^a|b$, ^(a|b)c$, a $ not at the end).

    1.54.0
  • The linear regex engine's matcher loop reads its state tables through locals and reads one flag per character for both a match and a dead state. The tables live in the matcher's closure and were reloaded on every character, about a third of the loop; SchemaStore's popxf-1.0, whose eleven patterns all run on this engine, validates its samples 18% faster. The engine's answers are unchanged (88000 random strings against the platform RegExp, 0 differences).

    1.54.0
  • A definition on a reference cycle that refers back to the root ($ref: "#") compiles. Such a definition is a function above the entry, where the entry is not in scope, so the schema declined code generation and ran on the interpreter: SchemaStore's jsone, the one schema with sample documents that did, was 0.60x the default validator's speed. The definition now reaches the root through a forwarder the entry fills in, named per compile, so two such schemas in one bundle do not share it. tests/test_def_root_forwarder.js holds generated code, a standalone module and a two-schema bundle to the interpreter's answers.

    1.54.0
  • An array of records with 32 or more optional properties is checked one of two ways per call. When three of its records (first, middle, last) list their keys alike, which records of one shape do, each declared property is read as before; when they do not, each record is checked from its own keys. Reading every declared property is fastest while the records share a shape and slowest once their shapes vary, because V8's property reads then stop being specialised. On 2000 records of 150 typed fields, records that each carry a different handful of keys go from 20.13 ms to 0.29 ms an array, and records of one shape from 7.41 to 7.19 µs. tests/test_item_key_loop.js holds both forms to the interpreter's answers on 648 arrays. Error lists for such arrays are still built the old way.

    1.54.0
  • A patternProperties entry whose schema checks nothing ({} or true), as OpenAPI's ^x- extensions are on nearly every object, no longer writes a loop over the object's keys: the loop read each matching key's value and did nothing with it. A valid OpenAPI 3.1 document goes from 4.49 to 3.47 µs and a rejected one with its errors read from 3.73 to 3.35 µs; the first validation is unchanged (10.82 against 10.81 ms, median of 21). A pattern that still checks something, a propertyNames and additionalProperties keep the loop.

    1.54.0
  • OpenAPI 3.1's own schema runs on generated code. It has a property named examples whose schema is a $ref, and the passes that rewrite references skipped examples, default, enum and const as value keywords even where they are property names, so the copy pointed at a definition it no longer had and the whole schema fell back to the interpreted engine. A valid OpenAPI document goes from 9.81 to 4.62 µs, and to 3.47 µs with the next entry, a rejected one with its errors read from 14.06 to 3.85 µs; the first validation is unchanged (10.83 to 10.69 ms). tests/test_name_map_value_keys.js holds those four names as properties, through $dynamicRef and through a reference into another document, to generated code and to the interpreter's answers.

    1.54.0
  • Reading a rejected document's errors costs about half what it did when the list has more than one error. The detail text is worked out where each error site is compiled, as far as the site allows, instead of from the keyword at every failure, and the list built where the errors happen says whether it came out in schema order, so it is sorted only when it did not. A migration-style schema with two errors goes from 159.9 to 79.6 ns a document; the request benchmark's rejected body with its error list read from 135.3 to 96.1 µs against 1.53.0. The errors are unchanged: tests/test_rich_errors_generated.js compares them with enrich() on 10,553 rejections, and SchemaStore's 26,563 rejections keep their order with the order check on.

    1.54.0