ata-validator 1.32.1 → 1.32.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -33
- package/index.js +29 -7
- package/lib/clone-emit.js +11 -0
- package/lib/js-compiler.js +133 -30
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -7,6 +7,24 @@ JSON Schema validation that compiles for speed and still runs where code generat
|
|
|
7
7
|
|
|
8
8
|
1.0 is a stability commitment: see [docs/STABILITY.md](docs/STABILITY.md) for the semver, deprecation, and error-code guarantees.
|
|
9
9
|
|
|
10
|
+
## Who uses ata
|
|
11
|
+
|
|
12
|
+
Projects whose code depends on ata, from GitHub's dependency graph, and the framework that lists
|
|
13
|
+
its plugin, with what each does with it:
|
|
14
|
+
|
|
15
|
+
- [Socket](https://github.com/SocketDev) uses ata, compiled ahead of time, in the shared build
|
|
16
|
+
tooling of its repositories.
|
|
17
|
+
- [Fastify](https://fastify.dev/ecosystem/) lists the
|
|
18
|
+
[`fastify-ata`](https://github.com/ata-core/fastify-ata) plugin in its ecosystem.
|
|
19
|
+
- [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form) ships an ata
|
|
20
|
+
validator in its main repository, in a runtime and a precompiled form.
|
|
21
|
+
- [JollyPixel](https://github.com/JollyPixel/editor) parses and validates JSON on its back end
|
|
22
|
+
with ata, compiled ahead of time.
|
|
23
|
+
- [better-drizzle](https://github.com/almeidazs/better-drizzle) ships an ata plugin for queries
|
|
24
|
+
and rows.
|
|
25
|
+
- [svelte-jsonschema-form](https://github.com/x0k/svelte-jsonschema-form) publishes an ata
|
|
26
|
+
validator package, runtime and precompiled.
|
|
27
|
+
|
|
10
28
|
## Quick start
|
|
11
29
|
|
|
12
30
|
```bash
|
|
@@ -53,15 +71,24 @@ The `.compiled.mjs` modules are self-contained: zero runtime dependency on ata-v
|
|
|
53
71
|
|
|
54
72
|
## Measured by others
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
Public harnesses run ata without ata's involvement. Quote these before anything in this
|
|
57
75
|
file.
|
|
58
76
|
|
|
77
|
+
- The [runtime type benchmark](https://moltar.github.io/typescript-runtime-type-benchmarks/)
|
|
78
|
+
maintained by moltar, 44 to 56 libraries per test. In its official run on Node 24, with ata
|
|
79
|
+
1.32.0, ata is first of 45 on assertStrict at 37.2M operations a second, and its
|
|
80
|
+
ahead-of-time entry is first of 44 on parseStrict at 36.3M, with the runtime entry second.
|
|
81
|
+
On assertLoose ata is fifth of 56 and on parseSafe sixth of 45. Some of the entries ahead
|
|
82
|
+
of it on those two rows skip checks JSON Schema requires there, such as rejecting an array
|
|
83
|
+
where an object is declared or NaN where a number is. On Deno the same run puts ata between
|
|
84
|
+
12th and 23rd; 1.32.1 makes it about 2.5 times faster there, locally, and had not been
|
|
85
|
+
through the harness yet at the time of writing.
|
|
59
86
|
- [schemabenchmarks.dev](https://schemabenchmarks.dev), a benchmark of runtime validation
|
|
60
|
-
libraries
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
87
|
+
libraries. Its published run of 2026-09-25 still uses ata 1.29.0 and puts it sixth of 30 on
|
|
88
|
+
valid data at 870 ns and tenth on invalid data at 67 ns. Most of that time was the `uri`
|
|
89
|
+
format check and a wrapper in the keywords package, both rewritten since. Run locally on an
|
|
90
|
+
Apple M4 Pro, the same harness takes ata from 365 ns on 1.29.0 to 240 ns on 1.32.1 for valid
|
|
91
|
+
data, with invalid data at 21 ns on both; those are local figures, not the site's.
|
|
65
92
|
- [Bowtie](https://bowtie.report/), the cross-implementation JSON Schema test harness. ata's
|
|
66
93
|
harness runs Draft 2020-12 and draft 7 there; on the harness at ata 1.16.1 the official suite
|
|
67
94
|
passes with nothing failed, errored or skipped under Bowtie's own runner. The v1 dialect is
|
|
@@ -71,19 +98,20 @@ file.
|
|
|
71
98
|
|
|
72
99
|
| Dimension | Schema | ata-AOT | runtime validator | Difference |
|
|
73
100
|
|---|---|---|---|---|
|
|
74
|
-
| Bundle (gzipped) | simple | 1.
|
|
75
|
-
| Bundle (gzipped) | complex | 7.
|
|
76
|
-
| Bundle (gzipped) | nested | 4.
|
|
77
|
-
| Cold start | simple |
|
|
78
|
-
| Throughput (1M ops) | simple |
|
|
79
|
-
| Compile time | simple |
|
|
101
|
+
| Bundle (gzipped) | simple | 1.3 KB | 52.7 KB | 39.8x smaller |
|
|
102
|
+
| Bundle (gzipped) | complex | 7.8 KB | 52.7 KB | 6.7x smaller |
|
|
103
|
+
| Bundle (gzipped) | nested | 4.5 KB | 52.7 KB | 11.8x smaller |
|
|
104
|
+
| Cold start | simple | 22 ms | 48 ms | 2.2x faster |
|
|
105
|
+
| Throughput (1M ops) | simple | 307 Mops/s | 100 Mops/s | 3.1x faster |
|
|
106
|
+
| Compile time | simple | 17 µs | 1.62 ms | 93x faster |
|
|
80
107
|
|
|
81
108
|
The runtime column is the default validator most frameworks ship. Reproduce on your machine
|
|
82
|
-
with `npm run bench:aot-vs-ajv`. Numbers from one run on Apple M4 Pro, Node 25.2.1, 2026-09-
|
|
83
|
-
on ata-validator 1.
|
|
84
|
-
is
|
|
85
|
-
between
|
|
86
|
-
rows as an order of
|
|
109
|
+
with `npm run bench:aot-vs-ajv`. Numbers from one run on Apple M4 Pro, Node 25.2.1, 2026-09-27,
|
|
110
|
+
on ata-validator 1.32.1. Emitted modules are about 0.2 to 0.4 KB larger gzipped than on 1.25.0,
|
|
111
|
+
which is what the exact own-property checks added in 1.31.2 cost. Across three runs throughput
|
|
112
|
+
moved between 296 and 307 Mops/s against 99 to 107, cold start between 21 and 22 ms against 41
|
|
113
|
+
to 48, and the compile ratio between 87x and 95x, so treat the last three rows as an order of
|
|
114
|
+
magnitude rather than a constant.
|
|
87
115
|
|
|
88
116
|
The wins are largest on bundle size and compile time because AOT moves work from runtime to
|
|
89
117
|
build time. Throughput and cold start are also faster because the compiled validator is a
|
|
@@ -211,19 +239,20 @@ is the most common way to get a misleading number out of this library.
|
|
|
211
239
|
|
|
212
240
|
| | compiled with `ata build` | runtime `new Validator(schema)` |
|
|
213
241
|
|---|---|---|
|
|
214
|
-
| In a bundle, gzipped | **
|
|
215
|
-
| Time to a served request | **3.4 ms** |
|
|
242
|
+
| In a bundle, gzipped | **2.3 KB** | 91.4 KB |
|
|
243
|
+
| Time to a served request | **3.4 ms** | 11.2 ms |
|
|
216
244
|
| Schema known when | build time | any time |
|
|
217
245
|
|
|
218
|
-
The bundle row is
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
246
|
+
The bundle row is the ten-field user schema in `tests/fixtures/error-dx/user.schema.json`,
|
|
247
|
+
every export of the compiled module against `new Validator(schema)`, built with
|
|
248
|
+
`bun build --minify --target=browser` on ata 1.32.1. The startup row is a Hono route on
|
|
249
|
+
Bun 1.4, best of seven, from `benchmark/bundle`, against 3.5 ms for the same app doing no
|
|
250
|
+
validation at all, so the compiled path costs nothing measurable to start. The runtime
|
|
222
251
|
figure is what it is because a schema that arrives at run time can use any keyword, so
|
|
223
252
|
the whole engine has to be there. The compiled module imports nothing and contains only
|
|
224
253
|
the checks your schema asks for.
|
|
225
254
|
|
|
226
|
-
**On a server, use whichever fits your schemas.**
|
|
255
|
+
**On a server, use whichever fits your schemas.** 91 KB of JavaScript on a Node or Bun
|
|
227
256
|
process is not a cost anyone notices, and the runtime API is the simpler thing to reach
|
|
228
257
|
for. Speed is the same either way once warm.
|
|
229
258
|
|
|
@@ -262,7 +291,7 @@ const v = new Validator({
|
|
|
262
291
|
required: ['name', 'email']
|
|
263
292
|
});
|
|
264
293
|
|
|
265
|
-
// Fast boolean check
|
|
294
|
+
// Fast boolean check, compiled to JS
|
|
266
295
|
v.isValidObject({ name: 'Mert', email: 'mert@example.com', age: 26 }); // true
|
|
267
296
|
|
|
268
297
|
// Full validation with error details + defaults applied
|
|
@@ -279,7 +308,7 @@ v.isValid(Buffer.from('{"name": "Mert", "email": "mert@example.com"}'));
|
|
|
279
308
|
// Which engine answers this schema: 'codegen', 'closure', 'native' or 'interpreter'
|
|
280
309
|
v.engine(); // 'codegen'
|
|
281
310
|
|
|
282
|
-
// Parallel batch
|
|
311
|
+
// Parallel batch, multi-core, NDJSON
|
|
283
312
|
const ndjson = Buffer.from(lines.join('\n'));
|
|
284
313
|
v.isValidParallel(ndjson); // bool[]
|
|
285
314
|
v.countValid(ndjson); // number
|
|
@@ -455,7 +484,7 @@ const v = new Validator(schema, {
|
|
|
455
484
|
|
|
456
485
|
### Build-time compile (`ata compile`)
|
|
457
486
|
|
|
458
|
-
The `ata` CLI turns a JSON Schema file into a self-contained JavaScript module. No runtime dependency on `ata-validator`, so only the generated validator ships to the browser.
|
|
487
|
+
The `ata` CLI turns a JSON Schema file into a self-contained JavaScript module. No runtime dependency on `ata-validator`, so only the generated validator ships to the browser. For the ten-field user schema in `tests/fixtures/error-dx/user.schema.json` the module is 2.6 KB gzipped, full error detail included, against 91 KB for the runtime bundled for the browser.
|
|
459
488
|
|
|
460
489
|
```bash
|
|
461
490
|
npx ata compile schemas/user.json -o src/generated/user.validator.mjs
|
|
@@ -496,14 +525,14 @@ npx ata build 'schemas/*.json' --out-dir build/validators --check
|
|
|
496
525
|
|
|
497
526
|
Run with `--watch` during development for incremental rebuilds.
|
|
498
527
|
|
|
499
|
-
Bundle sizes for
|
|
500
|
-
`bun build --minify --target=browser
|
|
528
|
+
Bundle sizes for the 10-field user schema in `tests/fixtures/error-dx/user.schema.json`,
|
|
529
|
+
minified and gzipped, measured with `bun build --minify --target=browser` on ata 1.32.1:
|
|
501
530
|
|
|
502
531
|
| What the app imports | Size | Notes |
|
|
503
532
|
|---|---|---|
|
|
504
|
-
| `Validator` from `ata-validator` |
|
|
505
|
-
| `isValid` from the compiled module | **1.
|
|
506
|
-
| `validate` from the compiled module | **
|
|
533
|
+
| `Validator` from `ata-validator` | 91.3 KB | The compiler ships with it, because a runtime schema can use any keyword |
|
|
534
|
+
| `isValid` from the compiled module | **1.2 KB** | Nothing else is reachable, so the error collector is dropped |
|
|
535
|
+
| `validate` from the compiled module | **2.1 KB** | Adds the detailed error collector |
|
|
507
536
|
|
|
508
537
|
`--abort-early` makes the generated source about three times smaller, and after
|
|
509
538
|
bundling it makes no difference: importing only `isValid` already leaves the error
|
|
@@ -526,7 +555,7 @@ through a `setFormats()` export the module carries. `docs/API.md` has the
|
|
|
526
555
|
details.
|
|
527
556
|
|
|
528
557
|
**Fastify startup, 10 route schemas, from a cold process to the first validated request:
|
|
529
|
-
ajv
|
|
558
|
+
ajv 20.2 ms, ata 3.9 ms, no build step required.** ata registers in 0.2 ms of that and
|
|
530
559
|
compiles on the first request, so counting only registration would overstate the gap.
|
|
531
560
|
Reproduce with `node benchmark/bench_fastify_boot.mjs`.
|
|
532
561
|
|
package/index.js
CHANGED
|
@@ -371,6 +371,9 @@ const _identityCache = new WeakMap();
|
|
|
371
371
|
|
|
372
372
|
const SIMDJSON_PADDING = 64;
|
|
373
373
|
const VALID_RESULT = Object.freeze({ valid: true, errors: Object.freeze([]) });
|
|
374
|
+
// How many calls a validator answers through its verdict function before its
|
|
375
|
+
// validate() and validateJSON() compile the single-function hybrid.
|
|
376
|
+
const HYBRID_TIER_CALLS = 64;
|
|
374
377
|
const ABORT_EARLY_RESULT = Object.freeze({
|
|
375
378
|
valid: false,
|
|
376
379
|
errors: Object.freeze([Object.freeze({
|
|
@@ -1543,8 +1546,20 @@ class Validator {
|
|
|
1543
1546
|
if (combined) { impl = combined; return _mustReject(combined(data)); }
|
|
1544
1547
|
return errOnly(data);
|
|
1545
1548
|
};
|
|
1546
|
-
|
|
1547
|
-
|
|
1549
|
+
// Tiered: the first calls go through the verdict function and the
|
|
1550
|
+
// resolver, and the hybrid is compiled once the validator is in use.
|
|
1551
|
+
// Compiling it up front was a second parse of the whole schema on
|
|
1552
|
+
// every validator, most of which answer a handful of requests or only
|
|
1553
|
+
// verdicts. A refused compile stays on the first tier.
|
|
1554
|
+
let warm = 0;
|
|
1555
|
+
const first = (data) => {
|
|
1556
|
+
if (++warm >= HYBRID_TIER_CALLS && impl === first) {
|
|
1557
|
+
impl = jsFn._hybridFactory(VALID_RESULT, onReject) || ((d) => (jsFn(d) ? VALID_RESULT : onReject(d)));
|
|
1558
|
+
return impl(data);
|
|
1559
|
+
}
|
|
1560
|
+
return jsFn(data) ? VALID_RESULT : onReject(data);
|
|
1561
|
+
};
|
|
1562
|
+
impl = first;
|
|
1548
1563
|
const run = (data) => impl(data);
|
|
1549
1564
|
this.validate = preprocess
|
|
1550
1565
|
? (data) => { preprocess(data); return run(data); }
|
|
@@ -1613,11 +1628,18 @@ class Validator {
|
|
|
1613
1628
|
// it validates and collects in one pass, and the error generator behind
|
|
1614
1629
|
// it. `errPreferCombined` is that order, resolved on the first rejection
|
|
1615
1630
|
// instead of at compile time.
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
const jsonValidateInner =
|
|
1620
|
-
|
|
1631
|
+
// Tiered the same way as validate() above.
|
|
1632
|
+
let jsonHybrid = null;
|
|
1633
|
+
let jsonWarm = 0;
|
|
1634
|
+
const jsonValidateInner = (obj) => {
|
|
1635
|
+
if (jsonHybrid !== null) return jsonHybrid(obj);
|
|
1636
|
+
if (++jsonWarm >= HYBRID_TIER_CALLS) {
|
|
1637
|
+
jsonHybrid = (jsFn._hybridFactory && jsFn._hybridFactory(VALID_RESULT, errPreferCombined))
|
|
1638
|
+
|| ((o) => (jsFn(o) ? VALID_RESULT : errPreferCombined(o)));
|
|
1639
|
+
return jsonHybrid(obj);
|
|
1640
|
+
}
|
|
1641
|
+
return jsFn(obj) ? VALID_RESULT : errPreferCombined(obj);
|
|
1642
|
+
};
|
|
1621
1643
|
// Parsed text takes the same preprocess pass as a parsed object, so
|
|
1622
1644
|
// validate(obj) and validateJSON(text) answer the same for the same
|
|
1623
1645
|
// document. Without it, coercion, removal and defaults applied on one
|
package/lib/clone-emit.js
CHANGED
|
@@ -272,6 +272,17 @@ function emitValueExpr(prop, read, depth) {
|
|
|
272
272
|
if (prop.$ref) return null;
|
|
273
273
|
const types = Array.isArray(prop.type) ? prop.type : [prop.type];
|
|
274
274
|
if (types.every((t) => _CLONE_PRIMITIVE.has(t))) return read;
|
|
275
|
+
// No type, but an enum or const whose values are all primitives: whatever
|
|
276
|
+
// passes can only be one of those values, so there is nothing inside it to
|
|
277
|
+
// strip and the value is copied as it is. `{ enum: ['USD', 'EUR'] }` is how
|
|
278
|
+
// such a field is usually written, and it declined parse() for the whole
|
|
279
|
+
// schema.
|
|
280
|
+
if (prop.type === undefined) {
|
|
281
|
+
const isPrim = (v) => v === null || (typeof v !== 'object' && typeof v !== 'function');
|
|
282
|
+
if (Array.isArray(prop.enum) && prop.enum.length > 0 && prop.enum.every(isPrim) &&
|
|
283
|
+
prop.const === undefined) return read;
|
|
284
|
+
if (prop.const !== undefined && isPrim(prop.const) && prop.enum === undefined) return read;
|
|
285
|
+
}
|
|
275
286
|
const isRecordable = (s) => s.properties ||
|
|
276
287
|
(s.additionalProperties && typeof s.additionalProperties === 'object');
|
|
277
288
|
if (prop.type === 'object' && isRecordable(prop)) {
|
package/lib/js-compiler.js
CHANGED
|
@@ -924,10 +924,22 @@ const PROTO_NAMES = new Set([...Object.getOwnPropertyNames(Object.prototype), '_
|
|
|
924
924
|
// hasOwnProperty path, and a ten-field check went from 2.5 to 40 ns. Where the
|
|
925
925
|
// accessor is missing the prototype comes from Object.getPrototypeOf instead,
|
|
926
926
|
// chosen by a constant the engine folds, so Node pays nothing for the branch.
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
927
|
+
// Each helper is hoisted only where something emitted uses it, with what it
|
|
928
|
+
// depends on. Hoisting all of them as one block put five declarations into
|
|
929
|
+
// every module that asked about presence at all, about a sixth of a small
|
|
930
|
+
// schema's compiled module.
|
|
931
|
+
const OWN_HELPER_CODE = {
|
|
932
|
+
_PN: 'const _PN=({}).__proto__===Object.prototype;const _OP=Object.prototype;const _gp=Object.getPrototypeOf;',
|
|
933
|
+
_hop: 'const _hop=Object.prototype.hasOwnProperty;',
|
|
934
|
+
_h: 'function _h(o,k){return _hop.call(o,k)}',
|
|
935
|
+
_ok: 'function _ok(o,k){return (_PN?o.__proto__:_gp(o))===_OP||_hop.call(o,k)}',
|
|
936
|
+
_hall: 'function _hall(o,ks){for(let i=0;i<ks.length;i++)if(!_hop.call(o,ks[i]))return false;return true}',
|
|
937
|
+
}
|
|
938
|
+
const OWN_HELPER_DEPS = { _h: ['_hop'], _ok: ['_PN', '_hop'], _hall: ['_hop'] }
|
|
939
|
+
function useOwnHelper (ctx, name) {
|
|
940
|
+
for (const dep of OWN_HELPER_DEPS[name] || []) useOwnHelper(ctx, dep)
|
|
941
|
+
hoistOnce(ctx, '_own' + name, OWN_HELPER_CODE[name])
|
|
942
|
+
}
|
|
931
943
|
//
|
|
932
944
|
// Better still, the prototype is read once per object: a node that asks about
|
|
933
945
|
// presence declares `_pkN`, whether its value is an ordinary object, before
|
|
@@ -936,24 +948,25 @@ const OWN_HELPERS = 'const _PN=({}).__proto__===Object.prototype;' +
|
|
|
936
948
|
// object shape in the document, and cost the error path about a microsecond
|
|
937
949
|
// on a product document.
|
|
938
950
|
// Whether `v`, already known to be an object, has Object.prototype as its
|
|
939
|
-
// prototype, read without depending on the __proto__ accessor.
|
|
940
|
-
function protoIs (v) {
|
|
941
|
-
|
|
951
|
+
// prototype, read without depending on the __proto__ accessor.
|
|
952
|
+
function protoIs (ctx, v) {
|
|
953
|
+
useOwnHelper(ctx, '_PN')
|
|
954
|
+
return `((_PN?${v}.__proto__:_gp(${v}))===_OP)`
|
|
942
955
|
}
|
|
943
956
|
function ownKeyExpr (ctx, v, key) {
|
|
944
|
-
hoistOnce(ctx, '_ownHoisted', OWN_HELPERS)
|
|
945
957
|
const k = JSON.stringify(key)
|
|
946
|
-
if (PROTO_NAMES.has(key)) return `_h(${v},${k})`
|
|
947
958
|
const pk = ctx.plainOf ? ctx.plainOf.get(v) : undefined
|
|
959
|
+
useOwnHelper(ctx, PROTO_NAMES.has(key) || pk !== undefined ? '_h' : '_ok')
|
|
960
|
+
if (PROTO_NAMES.has(key)) return `_h(${v},${k})`
|
|
948
961
|
return pk !== undefined ? `(${pk}?${k} in ${v}:_h(${v},${k}))` : `(${k} in ${v}&&_ok(${v},${k}))`
|
|
949
962
|
}
|
|
950
963
|
// For a value already read as `v[key]` and found not to be undefined: whether
|
|
951
964
|
// it came from `v` itself. `in` is known to hold, so only the second half runs.
|
|
952
965
|
function ownGuard (ctx, v, key) {
|
|
953
|
-
hoistOnce(ctx, '_ownHoisted', OWN_HELPERS)
|
|
954
966
|
const k = JSON.stringify(key)
|
|
955
|
-
if (PROTO_NAMES.has(key)) return `_h(${v},${k})`
|
|
956
967
|
const pk = ctx.plainOf ? ctx.plainOf.get(v) : undefined
|
|
968
|
+
useOwnHelper(ctx, PROTO_NAMES.has(key) || pk !== undefined ? '_h' : '_ok')
|
|
969
|
+
if (PROTO_NAMES.has(key)) return `_h(${v},${k})`
|
|
957
970
|
return pk !== undefined ? `(${pk}||_h(${v},${k}))` : `_ok(${v},${k})`
|
|
958
971
|
}
|
|
959
972
|
|
|
@@ -969,7 +982,7 @@ function withPlain (schema, v, lines, ctx, run) {
|
|
|
969
982
|
if (!ctx.plainOf) ctx.plainOf = new Map()
|
|
970
983
|
const name = '_pk' + ctx.varCounter++
|
|
971
984
|
const at = lines.length
|
|
972
|
-
const decl = `const ${name}=typeof ${v}==='object'&&${v}!==null&&${protoIs(v)}`
|
|
985
|
+
const decl = `const ${name}=typeof ${v}==='object'&&${v}!==null&&${protoIs(ctx, v)}`
|
|
973
986
|
lines.push(decl)
|
|
974
987
|
const prev = ctx.plainOf.get(v)
|
|
975
988
|
ctx.plainOf.set(v, name)
|
|
@@ -1765,7 +1778,11 @@ function compileToJSCodegen(schema, schemaMap, userFormats, opts) {
|
|
|
1765
1778
|
const defSets = ctx.defFns ? Array.from(ctx.defFns.values()) : []
|
|
1766
1779
|
const needsGuard = ctx.usesRecursion || defSets.length > 0
|
|
1767
1780
|
|
|
1768
|
-
|
|
1781
|
+
// The hybrid and tail forms are the same checks with different returns. They
|
|
1782
|
+
// are built when first asked for, not here: most validators never call
|
|
1783
|
+
// validateJSON or get extended, and rewriting and compiling the source twice
|
|
1784
|
+
// more on every schema was about a third of what a first call cost.
|
|
1785
|
+
let body, hybridThunk, tailThunk
|
|
1769
1786
|
if (ctx.usesRecursion) {
|
|
1770
1787
|
// Self-recursive: a named body reached through the cycle guard, so data
|
|
1771
1788
|
// that points back at itself settles instead of exhausting the stack.
|
|
@@ -1774,23 +1791,25 @@ function compileToJSCodegen(schema, schemaMap, userFormats, opts) {
|
|
|
1774
1791
|
const run = emitGuardedRun('return _validate(d)', '', defSets)
|
|
1775
1792
|
body = `${decl}function _run(d){\n ${run}\n }\n return _run(d)`
|
|
1776
1793
|
// Hybrid: keep the boolean answer, wrap only the outer call
|
|
1777
|
-
|
|
1778
|
-
|
|
1794
|
+
hybridThunk = () => `${decl}function _run(d){\n ${run}\n }\n return _run(d)?R:E(d)`
|
|
1795
|
+
tailThunk = () => `${decl}function _run(d){\n ${run}\n }\n return _run(d)&&__ataTail(d)`
|
|
1779
1796
|
} else if (defSets.length > 0) {
|
|
1780
1797
|
// No self-reference at the root, but a def on a cycle can still be
|
|
1781
1798
|
// re-entered with the same value; the guarded functions need their state.
|
|
1782
1799
|
const run = emitGuardedRun(`return _body(d)`, '', defSets)
|
|
1783
1800
|
body = `function _body(d){\n ${checkStr}\n return true\n }\n function _run(d){\n ${run}\n }\n return _run(d)`
|
|
1784
|
-
|
|
1785
|
-
|
|
1801
|
+
hybridThunk = () => `function _body(d){\n ${checkStr}\n return true\n }\n function _run(d){\n ${run}\n }\n return _run(d)?R:E(d)`
|
|
1802
|
+
tailThunk = () => `function _body(d){\n ${checkStr}\n return true\n }\n function _run(d){\n ${run}\n }\n return _run(d)&&__ataTail(d)`
|
|
1786
1803
|
} else {
|
|
1787
1804
|
body = checkStr + '\n return true'
|
|
1788
|
-
|
|
1805
|
+
hybridThunk = () => replaceTopLevel(checkStr + '\n return R')
|
|
1789
1806
|
// An early accept inside the checks has to reach the tail too, so every
|
|
1790
1807
|
// top-level `return true` becomes the tail call, by the same rewrite the
|
|
1791
1808
|
// hybrid above relies on and test_hybrid_agreement holds to the suite.
|
|
1792
|
-
|
|
1809
|
+
tailThunk = () => replaceTopLevel(checkStr + '\n return true', 'return __ataTail(d)', 'return false')
|
|
1793
1810
|
}
|
|
1811
|
+
let hybridBodyMemo
|
|
1812
|
+
const hybridBody = () => (hybridBodyMemo === undefined ? (hybridBodyMemo = hybridThunk()) : hybridBodyMemo)
|
|
1794
1813
|
|
|
1795
1814
|
const guardStr = needsGuard ? emitGuardState() : ''
|
|
1796
1815
|
const preambleStr = guardStr +
|
|
@@ -1808,11 +1827,20 @@ function compileToJSCodegen(schema, schemaMap, userFormats, opts) {
|
|
|
1808
1827
|
boolFn = new Function('d', body)
|
|
1809
1828
|
}
|
|
1810
1829
|
|
|
1811
|
-
//
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1830
|
+
// The hybrid: same body, return R instead of true, return E(d) instead of
|
|
1831
|
+
// false. Compiled on first request; null when that compile is refused, and
|
|
1832
|
+
// the caller then assembles from the error functions instead.
|
|
1833
|
+
let hybridFactory
|
|
1834
|
+
boolFn._hybridFactory = (R, E) => {
|
|
1835
|
+
if (hybridFactory === undefined) {
|
|
1836
|
+
try {
|
|
1837
|
+
hybridFactory = new Function(...closureNames, 'R', 'E', `${preambleStr}return function(d){${hybridBody()}}`)
|
|
1838
|
+
} catch {
|
|
1839
|
+
hybridFactory = null
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
return hybridFactory === null ? null : hybridFactory(...closureValues, R, E)
|
|
1843
|
+
}
|
|
1816
1844
|
|
|
1817
1845
|
// The same function with one more check where it would return true, for a
|
|
1818
1846
|
// wrapper that enforces something the schema does not carry (see
|
|
@@ -1826,7 +1854,7 @@ function compileToJSCodegen(schema, schemaMap, userFormats, opts) {
|
|
|
1826
1854
|
boolFn._withTail = (tail) => {
|
|
1827
1855
|
if (tailFactory === undefined) {
|
|
1828
1856
|
try {
|
|
1829
|
-
tailFactory = new Function(...closureNames, '__ataTail', `${preambleStr}return function(d){${
|
|
1857
|
+
tailFactory = new Function(...closureNames, '__ataTail', `${preambleStr}return function(d){${tailThunk()}}`)
|
|
1830
1858
|
} catch {
|
|
1831
1859
|
tailFactory = null
|
|
1832
1860
|
}
|
|
@@ -1847,7 +1875,11 @@ function compileToJSCodegen(schema, schemaMap, userFormats, opts) {
|
|
|
1847
1875
|
boolFn._preambleGuard = guardStr
|
|
1848
1876
|
boolFn._preambleParts = ctx.preamble ? ctx.preamble.slice() : []
|
|
1849
1877
|
boolFn._sharedHelpers = ctx.shared ? ctx.shared.slice() : []
|
|
1850
|
-
boolFn
|
|
1878
|
+
Object.defineProperty(boolFn, '_hybridSource', {
|
|
1879
|
+
get: () => helperStr + hybridBody(),
|
|
1880
|
+
configurable: true,
|
|
1881
|
+
enumerable: false,
|
|
1882
|
+
})
|
|
1851
1883
|
boolFn._usesSafeRe = !!ctx.usesSafeRe
|
|
1852
1884
|
// Custom-format closure entries that the bundle output needs to recreate.
|
|
1853
1885
|
// Stored as { name, fn } so consumers can serialize via Function#toString.
|
|
@@ -2280,11 +2312,11 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
|
|
|
2280
2312
|
}
|
|
2281
2313
|
// On an object with another prototype the typed ones may be inherited.
|
|
2282
2314
|
if (typed.length > 0) {
|
|
2283
|
-
|
|
2315
|
+
useOwnHelper(ctx, '_hall')
|
|
2284
2316
|
// Read directly: the object type is already established here, and a
|
|
2285
2317
|
// flag declared for this alone costs more than it saves. The list is
|
|
2286
2318
|
// built only on that path, which an ordinary object never takes.
|
|
2287
|
-
lines.push(`if(!${protoIs(v)}&&!_hall(${v},${JSON.stringify(typed)}))return false`)
|
|
2319
|
+
lines.push(`if(!${protoIs(ctx, v)}&&!_hall(${v},${JSON.stringify(typed)}))return false`)
|
|
2288
2320
|
}
|
|
2289
2321
|
} else if (schema.required && schema.required.length > 0) {
|
|
2290
2322
|
const checks = schema.required.map(key => `!${ownKeyExpr(ctx, v, key)}`)
|
|
@@ -3477,7 +3509,75 @@ function compilePatternInline(pattern, varName) {
|
|
|
3477
3509
|
const min = parseInt(m[2]), max = parseInt(m[3])
|
|
3478
3510
|
return `${varName}.length>=${min}&&${varName}.length<=${max}&&(()=>{for(let _pi=0;_pi<${varName}.length;_pi++){if(!(${rangeCheck}))return false}return true})()`
|
|
3479
3511
|
}
|
|
3480
|
-
return
|
|
3512
|
+
return fixedSequenceInline(pattern, varName)
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
// A pattern that matches exactly one fixed-length sequence of single
|
|
3516
|
+
// characters, such as `^[A-Z]{3}-\d{4}$` for a SKU or `^\d{3}-\d{4}$` for a
|
|
3517
|
+
// code, unrolled into one character test per position. Each piece is a class
|
|
3518
|
+
// of letters, digits, `_` and `-`, a `\d`, or a literal character, repeated a
|
|
3519
|
+
// fixed number of times; anything else, including every variable-length
|
|
3520
|
+
// quantifier and any negated or escaped class, returns null and keeps the
|
|
3521
|
+
// regular path. Each piece matches exactly one UTF-16 unit in the ASCII range,
|
|
3522
|
+
// so comparing the length and each code unit is the same test the regex
|
|
3523
|
+
// makes. Such patterns went through the safe-regex matcher, which is
|
|
3524
|
+
// linear but slower than both this and the native engine: a quarter of the
|
|
3525
|
+
// time of an order body with one SKU per line item.
|
|
3526
|
+
const FIXED_LITERAL = /[A-Za-z0-9 _\-:@#%&=,;'"<>!~`\/]/
|
|
3527
|
+
function fixedSequenceInline(pattern, varName) {
|
|
3528
|
+
if (pattern.length < 3 || pattern[0] !== '^' || pattern[pattern.length - 1] !== '$' || pattern[pattern.length - 2] === '\\') return null
|
|
3529
|
+
const end = pattern.length - 1
|
|
3530
|
+
const pieces = []
|
|
3531
|
+
let i = 1
|
|
3532
|
+
while (i < end) {
|
|
3533
|
+
let piece
|
|
3534
|
+
const c = pattern[i]
|
|
3535
|
+
if (c === '[') {
|
|
3536
|
+
const j = pattern.indexOf(']', i)
|
|
3537
|
+
if (j < 0 || j >= end) return null
|
|
3538
|
+
const cls = pattern.slice(i, j + 1)
|
|
3539
|
+
if (!/^\[[\w-]+\]$/.test(cls)) return null
|
|
3540
|
+
piece = { cls }
|
|
3541
|
+
i = j + 1
|
|
3542
|
+
} else if (c === '\\') {
|
|
3543
|
+
const e = pattern[i + 1]
|
|
3544
|
+
if (e === 'd') piece = { cls: '[0-9]' }
|
|
3545
|
+
// Only the escapes that stay valid under the u flag: an escaped `-`
|
|
3546
|
+
// outside a class is a syntax error there, and the regex path is the
|
|
3547
|
+
// one that decides what to do about it.
|
|
3548
|
+
else if (e !== undefined && './()[]{}+*?^$|\\'.includes(e)) piece = { lit: e }
|
|
3549
|
+
else return null
|
|
3550
|
+
i += 2
|
|
3551
|
+
} else if (FIXED_LITERAL.test(c)) {
|
|
3552
|
+
piece = { lit: c }
|
|
3553
|
+
i += 1
|
|
3554
|
+
} else {
|
|
3555
|
+
return null
|
|
3556
|
+
}
|
|
3557
|
+
let count = 1
|
|
3558
|
+
if (pattern[i] === '{') {
|
|
3559
|
+
const q = /^\{(\d+)\}/.exec(pattern.slice(i))
|
|
3560
|
+
if (!q) return null
|
|
3561
|
+
count = Number(q[1])
|
|
3562
|
+
i += q[0].length
|
|
3563
|
+
} else if (i < end && '*+?'.includes(pattern[i])) {
|
|
3564
|
+
return null
|
|
3565
|
+
}
|
|
3566
|
+
for (let k = 0; k < count; k++) pieces.push(piece)
|
|
3567
|
+
if (pieces.length > 32) return null
|
|
3568
|
+
}
|
|
3569
|
+
if (pieces.length === 0) return null
|
|
3570
|
+
const checks = []
|
|
3571
|
+
for (let k = 0; k < pieces.length; k++) {
|
|
3572
|
+
const at = `${varName}.charCodeAt(${k})`
|
|
3573
|
+
if (pieces[k].lit !== undefined) checks.push(`${at}===${pieces[k].lit.charCodeAt(0)}`)
|
|
3574
|
+
else {
|
|
3575
|
+
const ck = charClassToCheck(pieces[k].cls, at)
|
|
3576
|
+
if (!ck) return null
|
|
3577
|
+
checks.push(`(${ck})`)
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
return `${varName}.length===${pieces.length}&&${checks.join('&&')}`
|
|
3481
3581
|
}
|
|
3482
3582
|
|
|
3483
3583
|
// Convert [charclass] to charCode range check expression.
|
|
@@ -3502,7 +3602,10 @@ function charClassToCheck(charClass, codeExpr) {
|
|
|
3502
3602
|
const checks = ranges.map(([lo, hi]) =>
|
|
3503
3603
|
lo === hi ? `${codeExpr}===${lo}` : `(${codeExpr}>=${lo}&&${codeExpr}<=${hi})`
|
|
3504
3604
|
)
|
|
3505
|
-
|
|
3605
|
+
// Parenthesised as a whole: the unrolled form joins one of these per
|
|
3606
|
+
// position with &&, and a bare a||b there bound as (len&&a)||(b&&...), so
|
|
3607
|
+
// ^[A-Za-z]{2}$ accepted "xyz" and "1a" from 0.12.1 on.
|
|
3608
|
+
return `(${checks.join('||')})`
|
|
3506
3609
|
}
|
|
3507
3610
|
|
|
3508
3611
|
// Same but for dynamic segments (array indices)
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.32.
|
|
3
|
+
"version": "1.32.3",
|
|
4
4
|
"description": "JSON Schema validation that compiles for speed and still runs where code generation is blocked. Compiled and interpreted engines answer identically at 100% of the official suite. TypeScript inference, Standard Schema V1, and a build step that emits dependency-free modules.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"release:check": "node scripts/regen-safe-regex-source.js && node tests/test_pack_purity.js && node scripts/check-doc-coverage.js && node tests/test_error_codes_lock.js && node tests/test_safe_regex_source_sync.js && node tests/test_version_sync.js",
|
|
52
52
|
"build": "cmake-js build --target ata",
|
|
53
53
|
"rebuild": "cmake-js rebuild --target ata",
|
|
54
|
-
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_validate_json_scanner_cost.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_proto_accessor.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.js && node tests/test_additional_props_combined_cost.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_single_pass_errors.js && node tests/test_lazy_json_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_enrich_received.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node benchmark/bench_aot_size.mjs",
|
|
54
|
+
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_validate_json_scanner_cost.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_proto_accessor.js && node tests/test_hybrid_tier.js && node tests/test_fixed_pattern_inline.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.js && node tests/test_additional_props_combined_cost.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_single_pass_errors.js && node tests/test_lazy_json_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_enrich_received.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node benchmark/bench_aot_size.mjs",
|
|
55
55
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
56
56
|
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
|
|
57
57
|
"test:compat": "node tests/test_compat.js",
|
|
@@ -121,13 +121,13 @@
|
|
|
121
121
|
"LICENSE"
|
|
122
122
|
],
|
|
123
123
|
"optionalDependencies": {
|
|
124
|
-
"@ata-validator/native-darwin-arm64": "1.32.
|
|
125
|
-
"@ata-validator/native-darwin-x64": "1.32.
|
|
126
|
-
"@ata-validator/native-linux-arm64-gnu": "1.32.
|
|
127
|
-
"@ata-validator/native-linux-arm64-musl": "1.32.
|
|
128
|
-
"@ata-validator/native-linux-x64-gnu": "1.32.
|
|
129
|
-
"@ata-validator/native-linux-x64-musl": "1.32.
|
|
130
|
-
"@ata-validator/native-win32-x64": "1.32.
|
|
124
|
+
"@ata-validator/native-darwin-arm64": "1.32.3",
|
|
125
|
+
"@ata-validator/native-darwin-x64": "1.32.3",
|
|
126
|
+
"@ata-validator/native-linux-arm64-gnu": "1.32.3",
|
|
127
|
+
"@ata-validator/native-linux-arm64-musl": "1.32.3",
|
|
128
|
+
"@ata-validator/native-linux-x64-gnu": "1.32.3",
|
|
129
|
+
"@ata-validator/native-linux-x64-musl": "1.32.3",
|
|
130
|
+
"@ata-validator/native-win32-x64": "1.32.3"
|
|
131
131
|
},
|
|
132
132
|
"peerDependencies": {
|
|
133
133
|
"yaml": "^2.0.0"
|