Packages

ata-validator

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

Your version

1.25.0

16 Sep 2026Where it was published

1.61.3 is the newest release of 1.x.

In short

6 new1 fixed

Release note

Fixed

  • Emitted standalone modules compiled their regex patterns on every call. The compiler stores each pattern both as a closure variable and as an inline const _reN = __ataSafeRe(...) in the stored source; in process the inline line never runs (the closure binds the compiled matcher once), but every emitter placed it inside the emitted function, where it shadowed the module-scope binding and rebuilt the matcher per call. A schema with one pattern validated at 202 thousand ops/s as a standalone module while the in-process path ran at millions. Patterns are now declared once at load scope in all four emitters (toStandalone, toStandaloneModule, bundleStandalone, bundleCompact); the same document on the same schema now measures 27.0 million ops/s, 134x. bundleCompact needed care: its deduplication keyed on body text alone, and with the pattern no longer in the body, two schemas differing only in their pattern would have merged, so the key now includes the factory-scope declarations.

Added

  • Provably local unevaluated* compiles real error detail on the generated-code path, and therefore in standalone modules. When every occurrence of unevaluatedProperties/unevaluatedItems sits on a node with no $ref and no patternProperties, and every in-place applicator (allOf, anyOf, oneOf, if/then/else) contributes only property names the node's own properties already declares, the keyword is exactly additionalProperties/items in disguise and both the error and combined generators now emit it as such, keeping the keyword's own identity: one error per stray key with params.unevaluatedProperty (ATA7003), one error with params.limit for extra items. toStandaloneModule with error detail requested no longer degrades on these schemas; a config schema of the common if/then/else plus root unevaluatedProperties: false shape ships an AOT module with the same per-field errors the runtime reports. Schemas where the annotations cannot be proven local (unevaluated* next to a $ref, cousin-visible shapes) still decline, loudly, as before. Verified by the error-shape differential (2,816 cases), the engine differential (18,126 cases) and the official suite on all three dialects.

  • toStandaloneModule(schema, { positions: true }) also exports validateJSON(text): parse, validate, and on failure attach a dataFrame (byteOffset, length, line, col, text) to every error by walking the original text once. The mapping goes through instancePath, so a key that appears in several sections frames each error on its own occurrence, which a first-occurrence string search does not. A syntax error is the single ATA9001 error with a frame on the document. The walker is the runtime's own buildDataPositionMap, embedded verbatim so the two cannot drift, and it costs about 5 KB in the module (1.7 KB gzipped), which is why it is opt-in.

  • toStandaloneModule(schema, { parse: true })'s parse(data) now fills declared default values for absent optional properties (object and array defaults are fresh per call) and is emitted for composed schemas under the same proof the unevaluated* error generators use: in-place applicators are admitted when every property name they mention is already declared in the node's own properties. The common config shape, if/then/else over declared fields with root unevaluatedProperties: false, now gets a parse that enforces the conditional, rejects undeclared keys, and returns the ready object. Two default shapes decline because they are where parse and the runtime would disagree: a required property with a default, and a default the property's own schema rejects.

  • Every emitted module exports schemaHash, a 16 character content hash of the schema it was compiled from, over canonical JSON so key order does not matter, computed from the schema as the caller wrote it so dialect normalization does not break the comparison. schemaHash(schema) from ata-validator/build computes the same value; a build detects a stale artifact by comparing the two instead of embedding its own fingerprint.

  • The agreement between compiled modules and the runtime is now a stated contract, in docs/STABILITY.md and the API reference: same version, same verdict on every document, enforced by the differential test in every CI run, with the emitters declining or degrading loudly where they cannot prove equivalence.

  • The compat shim exports attachDataFrames(errors, text): the same one-pass mapping for Ajv-shaped errors, for callers that keep the source text around. Not an Ajv API; it exists because hand-written line finders based on a string search get repeated keys wrong.