ata-validator 1.35.0 → 1.36.0
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/build.d.ts +23 -0
- package/build.mjs +4 -0
- package/index.d.ts +6 -0
- package/index.js +138 -47
- package/index.node.mjs +10 -0
- package/lib/aot-build.js +12 -6
- package/lib/compiled.js +17 -5
- package/lib/defaults.js +88 -0
- package/lib/js-compiler.js +211 -123
- package/lib/rejections.js +26 -6
- package/lib/schema-order.js +53 -3
- package/lib/validator-core.js +97 -118
- package/lib/version.js +1 -1
- package/package.json +16 -11
package/lib/rejections.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// and by the wrapper around a compiled module, so both report errors through
|
|
7
7
|
// the same code.
|
|
8
8
|
|
|
9
|
-
const { ordinalFor: schemaOrdinal } = require('./schema-order');
|
|
9
|
+
const { ordinalFor: schemaOrdinal, rankFor: schemaRank } = require('./schema-order');
|
|
10
10
|
const { setDiagnosticSource: attachDiagnosticSource } = require('./diagnostic-source');
|
|
11
11
|
|
|
12
12
|
// Rejection result with errors materialized on first read. The accessor
|
|
@@ -256,13 +256,17 @@ function stripOrdinal(e) {
|
|
|
256
256
|
|
|
257
257
|
// Errors in schema declaration order. Each error's key is its schemaPath's
|
|
258
258
|
// pre-order ordinal in the root schema: written into the literal by the code
|
|
259
|
-
// generator (`_o`), looked up once per path otherwise.
|
|
260
|
-
//
|
|
259
|
+
// generator (`_o`), looked up once per path otherwise. Errors behind the same
|
|
260
|
+
// `$ref` share the ordinal of that `$ref`, and among themselves go by their
|
|
261
|
+
// place in the target (rankFor), so they come out in the order they would
|
|
262
|
+
// inline, whichever engine produced them. Most rejections come out already
|
|
263
|
+
// ordered, and those return without sorting or allocating.
|
|
261
264
|
function sortErrorsBySchemaOrder(rootSchema, errors) {
|
|
262
265
|
const n = errors.length;
|
|
263
266
|
const keys = new Array(n);
|
|
264
267
|
let sorted = true;
|
|
265
268
|
let prev = -1;
|
|
269
|
+
let prevPath = null;
|
|
266
270
|
for (let i = 0; i < n; i++) {
|
|
267
271
|
const e = errors[i];
|
|
268
272
|
let o = typeof e._o === 'number' ? e._o : schemaOrdinal(rootSchema, e.schemaPath);
|
|
@@ -271,24 +275,40 @@ function sortErrorsBySchemaOrder(rootSchema, errors) {
|
|
|
271
275
|
// which is where the rank comparison left it too.
|
|
272
276
|
if (o === null) o = prev < 0 ? 0 : prev;
|
|
273
277
|
keys[i] = o;
|
|
274
|
-
if (o < prev) sorted = false;
|
|
278
|
+
if (o < prev || (o === prev && sorted && e.schemaPath !== prevPath && tieOrder(rootSchema, prevPath, e.schemaPath) > 0)) sorted = false;
|
|
275
279
|
prev = o;
|
|
280
|
+
prevPath = e.schemaPath;
|
|
276
281
|
}
|
|
277
282
|
if (sorted) return errors;
|
|
278
283
|
// Error lists are short. A stable insertion sort over the integer keys
|
|
279
|
-
// moves the errors in tandem with no
|
|
284
|
+
// moves the errors in tandem with no index array; equal keys fall back to
|
|
285
|
+
// the rank only when the paths differ.
|
|
280
286
|
const out = errors.slice();
|
|
281
287
|
for (let i = 1; i < n; i++) {
|
|
282
288
|
const k = keys[i];
|
|
283
289
|
const e = out[i];
|
|
284
290
|
let j = i - 1;
|
|
285
|
-
while (j >= 0 && keys[j] > k
|
|
291
|
+
while (j >= 0 && (keys[j] > k || (keys[j] === k && tieOrder(rootSchema, out[j].schemaPath, e.schemaPath) > 0))) {
|
|
292
|
+
keys[j + 1] = keys[j]; out[j + 1] = out[j]; j--;
|
|
293
|
+
}
|
|
286
294
|
keys[j + 1] = k;
|
|
287
295
|
out[j + 1] = e;
|
|
288
296
|
}
|
|
289
297
|
return out;
|
|
290
298
|
}
|
|
291
299
|
|
|
300
|
+
// Order of two paths with the same ordinal: positive when `a` belongs after
|
|
301
|
+
// `b`. Zero keeps them as they are, for identical paths and for paths
|
|
302
|
+
// outside this document.
|
|
303
|
+
function tieOrder(rootSchema, a, b) {
|
|
304
|
+
if (a === b) return 0;
|
|
305
|
+
const ra = schemaRank(rootSchema, a), rb = schemaRank(rootSchema, b);
|
|
306
|
+
if (ra === null || rb === null) return 0;
|
|
307
|
+
const m = Math.min(ra.length, rb.length);
|
|
308
|
+
for (let k = 0; k < m; k++) if (ra[k] !== rb[k]) return ra[k] - rb[k];
|
|
309
|
+
return ra.length - rb.length;
|
|
310
|
+
}
|
|
311
|
+
|
|
292
312
|
// Resolved once. A require() inside the function was re-resolving the path
|
|
293
313
|
// on every rejection, which the profile showed as internalModuleStat at the
|
|
294
314
|
// top of the reject path, above the correlation it was loading.
|
package/lib/schema-order.js
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
// generator can compute it once per error site instead of the reader
|
|
12
12
|
// deriving it from the path string on every rejection.
|
|
13
13
|
//
|
|
14
|
+
// A path that runs on through a `$ref` names keys the referencing node does
|
|
15
|
+
// not have. Its ordinal is that of the `$ref` key, which several paths then
|
|
16
|
+
// share; its rank carries on inside the target, and the reader uses the rank
|
|
17
|
+
// to order the paths that share an ordinal.
|
|
18
|
+
//
|
|
14
19
|
// Both are memoized per root schema; a validator's root never changes.
|
|
15
20
|
|
|
16
21
|
const _keyIndexCache = new WeakMap();
|
|
@@ -56,12 +61,12 @@ function computeRank(rootSchema, schemaPath) {
|
|
|
56
61
|
const rank = [];
|
|
57
62
|
let node = rootSchema;
|
|
58
63
|
let start = 1;
|
|
64
|
+
let hops = 0;
|
|
59
65
|
while (start <= schemaPath.length) {
|
|
60
66
|
let end = schemaPath.indexOf('/', start);
|
|
61
67
|
if (end < 0) end = schemaPath.length;
|
|
62
68
|
if (end === start) { start = end + 1; continue; }
|
|
63
69
|
const seg = unescapePointerSegment(schemaPath.slice(start, end));
|
|
64
|
-
start = end + 1;
|
|
65
70
|
if (node == null || typeof node !== 'object') break;
|
|
66
71
|
if (Array.isArray(node)) {
|
|
67
72
|
const idx = Number(seg);
|
|
@@ -70,14 +75,53 @@ function computeRank(rootSchema, schemaPath) {
|
|
|
70
75
|
node = node[idx];
|
|
71
76
|
} else {
|
|
72
77
|
const idx = keyIndex(node, seg);
|
|
73
|
-
if (idx < 0)
|
|
78
|
+
if (idx < 0) {
|
|
79
|
+
// An evaluation path runs on through a `$ref` into its target without
|
|
80
|
+
// naming it. Ranking the rest inside the target, as if the target sat
|
|
81
|
+
// under the `$ref` key, orders errors behind a reference by the
|
|
82
|
+
// target's declaration order, as they are ordered inline.
|
|
83
|
+
const target = hops < 64 ? localTarget(rootSchema, node) : null;
|
|
84
|
+
if (target === null) break;
|
|
85
|
+
hops++;
|
|
86
|
+
rank.push(keyIndex(node, '$ref'));
|
|
87
|
+
node = target;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
74
90
|
rank.push(idx);
|
|
75
91
|
node = node[seg];
|
|
76
92
|
}
|
|
93
|
+
start = end + 1;
|
|
77
94
|
}
|
|
78
95
|
return rank;
|
|
79
96
|
}
|
|
80
97
|
|
|
98
|
+
// The schema a node's `$ref` names, when it is a pointer into this document.
|
|
99
|
+
function localTarget(rootSchema, node) {
|
|
100
|
+
const ref = node.$ref;
|
|
101
|
+
if (typeof ref !== 'string' || ref.charCodeAt(0) !== 35) return null;
|
|
102
|
+
if (ref.length > 1 && ref.charCodeAt(1) !== 47) return null;
|
|
103
|
+
let t = rootSchema;
|
|
104
|
+
let start = 2;
|
|
105
|
+
while (start <= ref.length && ref.length > 1) {
|
|
106
|
+
let end = ref.indexOf('/', start);
|
|
107
|
+
if (end < 0) end = ref.length;
|
|
108
|
+
let seg = ref.slice(start, end);
|
|
109
|
+
if (seg.indexOf('%') >= 0) { try { seg = decodeURIComponent(seg); } catch { return null; } }
|
|
110
|
+
seg = unescapePointerSegment(seg);
|
|
111
|
+
if (t === null || typeof t !== 'object') return null;
|
|
112
|
+
// Normalization renames draft-07 `definitions` to `$defs` and leaves the
|
|
113
|
+
// pointers as written; the resolvers read either name as the other.
|
|
114
|
+
if (!Object.prototype.hasOwnProperty.call(t, seg)) {
|
|
115
|
+
const alias = seg === 'definitions' ? '$defs' : seg === '$defs' ? 'definitions' : null;
|
|
116
|
+
if (alias === null || !Object.prototype.hasOwnProperty.call(t, alias)) return null;
|
|
117
|
+
seg = alias;
|
|
118
|
+
}
|
|
119
|
+
t = t[seg];
|
|
120
|
+
start = end + 1;
|
|
121
|
+
}
|
|
122
|
+
return t !== null && typeof t === 'object' && t !== node ? t : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
81
125
|
// Pre-order numbering of every node in the schema, keyed by its pointer as
|
|
82
126
|
// it appears in a schemaPath (segments escaped). Built once per root, on the
|
|
83
127
|
// first ask. Cyclic structures are guarded; a schema object can contain
|
|
@@ -115,13 +159,19 @@ function ordinalFor(rootSchema, schemaPath) {
|
|
|
115
159
|
// Walk back to the longest prefix that exists. Paths through a keyword's
|
|
116
160
|
// value that is a primitive, or through a key the schema does not have,
|
|
117
161
|
// land on the nearest enclosing node.
|
|
162
|
+
// A path that runs on through a `$ref` lands on its `$ref` key, so errors
|
|
163
|
+
// behind a reference sort where the `$ref` is declared among its siblings;
|
|
164
|
+
// rankFor orders them among themselves.
|
|
118
165
|
let p = schemaPath;
|
|
119
166
|
while (true) {
|
|
120
167
|
const cut = p.lastIndexOf('/');
|
|
121
168
|
if (cut < 0) return 0;
|
|
122
169
|
p = p.slice(0, cut);
|
|
123
170
|
const o = map.get(p);
|
|
124
|
-
if (o !== undefined)
|
|
171
|
+
if (o !== undefined) {
|
|
172
|
+
const r = map.get(p + '/$ref');
|
|
173
|
+
return r !== undefined ? r : o;
|
|
174
|
+
}
|
|
125
175
|
}
|
|
126
176
|
}
|
|
127
177
|
|
package/lib/validator-core.js
CHANGED
|
@@ -30,137 +30,83 @@ const { isV1Dialect } = require("./dialect");
|
|
|
30
30
|
const { classify } = require("./shape-classifier");
|
|
31
31
|
const { buildTier0Plan, tier0Validate } = require("./tier0");
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
//
|
|
33
|
+
// The closure defaults pass. Only a validator without the generated
|
|
34
|
+
// preprocess pass calls it, so it loads on that first call; loading it with
|
|
35
|
+
// the core measured 0.07 ms of every process's start.
|
|
36
|
+
let _defaults = null;
|
|
35
37
|
function buildDefaultsApplier(schema) {
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
collectDefaults(schema, actions);
|
|
39
|
-
if (actions.length === 0) return null;
|
|
40
|
-
return (data) => {
|
|
41
|
-
for (let i = 0; i < actions.length; i++) actions[i](data);
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Write an own property. Plain assignment of a key named `__proto__` does
|
|
46
|
-
// not create a property at all: it hits the Object.prototype setter and
|
|
47
|
-
// rewrites the object's prototype, which is how a schema could reach
|
|
48
|
-
// Object.prototype itself. defineProperty has no such special case.
|
|
49
|
-
function setOwn(obj, key, val) {
|
|
50
|
-
if (key === "__proto__") {
|
|
51
|
-
Object.defineProperty(obj, key, {
|
|
52
|
-
value: val,
|
|
53
|
-
writable: true,
|
|
54
|
-
enumerable: true,
|
|
55
|
-
configurable: true,
|
|
56
|
-
});
|
|
57
|
-
} else {
|
|
58
|
-
obj[key] = val;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function collectDefaults(schema, actions, path) {
|
|
63
|
-
if (typeof schema !== "object" || schema === null) return;
|
|
64
|
-
const props = schema.properties;
|
|
65
|
-
if (!props) return;
|
|
66
|
-
for (const [key, prop] of Object.entries(props)) {
|
|
67
|
-
if (prop && typeof prop === "object" && prop.default !== undefined) {
|
|
68
|
-
const defaultVal = prop.default;
|
|
69
|
-
if (!path) {
|
|
70
|
-
actions.push((data) => {
|
|
71
|
-
if (typeof data === "object" && data !== null && !Object.hasOwn(data, key)) {
|
|
72
|
-
setOwn(data,
|
|
73
|
-
key,
|
|
74
|
-
typeof defaultVal === "object" && defaultVal !== null
|
|
75
|
-
? JSON.parse(JSON.stringify(defaultVal))
|
|
76
|
-
: defaultVal);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
} else {
|
|
80
|
-
const parentPath = path;
|
|
81
|
-
actions.push((data) => {
|
|
82
|
-
let target = data;
|
|
83
|
-
for (let j = 0; j < parentPath.length; j++) {
|
|
84
|
-
if (typeof target !== "object" || target === null) return;
|
|
85
|
-
// Own keys only. `target[key]` for an inherited name walks the
|
|
86
|
-
// prototype chain: a parent named `__proto__` that the instance
|
|
87
|
-
// does not carry resolved to Object.prototype, and the child
|
|
88
|
-
// defaults were written onto it, for every object in the realm.
|
|
89
|
-
if (!Object.hasOwn(target, parentPath[j])) return;
|
|
90
|
-
target = target[parentPath[j]];
|
|
91
|
-
}
|
|
92
|
-
if (
|
|
93
|
-
typeof target === "object" &&
|
|
94
|
-
target !== null &&
|
|
95
|
-
!Object.hasOwn(target, key)
|
|
96
|
-
) {
|
|
97
|
-
setOwn(target,
|
|
98
|
-
key,
|
|
99
|
-
typeof defaultVal === "object" && defaultVal !== null
|
|
100
|
-
? JSON.parse(JSON.stringify(defaultVal))
|
|
101
|
-
: defaultVal);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// Recurse into nested object schemas
|
|
107
|
-
if (prop && typeof prop === "object" && prop.properties) {
|
|
108
|
-
collectDefaults(prop, actions, (path || []).concat(key));
|
|
109
|
-
}
|
|
110
|
-
}
|
|
38
|
+
if (_defaults === null) _defaults = require('./defaults');
|
|
39
|
+
return _defaults.buildDefaultsApplier(schema);
|
|
111
40
|
}
|
|
112
41
|
|
|
113
42
|
// Build a function that coerces property values to match schema types in-place.
|
|
114
43
|
// Handles string→number, string→integer, string→boolean, number→string, boolean→string.
|
|
115
44
|
function buildCoercer(schema) {
|
|
116
45
|
if (typeof schema !== "object" || schema === null) return null;
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
return (data) => {
|
|
121
|
-
for (let i = 0; i < actions.length; i++) actions[i](data);
|
|
122
|
-
};
|
|
46
|
+
const node = buildNodeCoercer(schema, new Set());
|
|
47
|
+
if (node === null) return null;
|
|
48
|
+
return (data) => { if (typeof data === "object" && data !== null) node(data); };
|
|
123
49
|
}
|
|
124
50
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (!
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const coerce = buildSingleCoercion(targetType);
|
|
135
|
-
if (!coerce) continue;
|
|
51
|
+
// What to do with a value that sits at `schema`: coerce it (`scalar`) and then
|
|
52
|
+
// visit what is inside it (`inner`). Null when there is nothing.
|
|
53
|
+
function coercionFor(schema, seen) {
|
|
54
|
+
if (!schema || typeof schema !== "object") return null;
|
|
55
|
+
const scalar = schema.type && !Array.isArray(schema.type) ? buildSingleCoercion(schema.type) : null;
|
|
56
|
+
const inner = buildNodeCoercer(schema, seen);
|
|
57
|
+
return scalar || inner ? { scalar, inner } : null;
|
|
58
|
+
}
|
|
136
59
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
60
|
+
// The steps for the object or array at `schema`. `seen` stops a schema that
|
|
61
|
+
// contains itself through an inline cycle.
|
|
62
|
+
function buildNodeCoercer(schema, seen) {
|
|
63
|
+
if (seen.has(schema)) return null;
|
|
64
|
+
seen.add(schema);
|
|
65
|
+
const steps = [];
|
|
66
|
+
if (schema.properties) {
|
|
67
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
68
|
+
// Assignment to `__proto__` would replace the prototype; the generated
|
|
69
|
+
// pass skips it for the same reason.
|
|
70
|
+
if (key === "__proto__") continue;
|
|
71
|
+
const c = coercionFor(prop, seen);
|
|
72
|
+
if (!c) continue;
|
|
73
|
+
const { scalar, inner } = c;
|
|
74
|
+
steps.push((o) => {
|
|
75
|
+
if (!(key in o)) return;
|
|
76
|
+
if (scalar) {
|
|
77
|
+
const v = scalar(o[key]);
|
|
78
|
+
if (v !== undefined) o[key] = v;
|
|
151
79
|
}
|
|
152
|
-
if (
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
80
|
+
if (inner) {
|
|
81
|
+
const x = o[key];
|
|
82
|
+
if (typeof x === "object" && x !== null) inner(x);
|
|
155
83
|
}
|
|
156
84
|
});
|
|
157
85
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
86
|
+
}
|
|
87
|
+
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
88
|
+
const c = coercionFor(schema.items, seen);
|
|
89
|
+
if (c) {
|
|
90
|
+
const { scalar, inner } = c;
|
|
91
|
+
steps.push((o) => {
|
|
92
|
+
if (!Array.isArray(o)) return;
|
|
93
|
+
for (let i = 0; i < o.length; i++) {
|
|
94
|
+
if (scalar) {
|
|
95
|
+
const v = scalar(o[i]);
|
|
96
|
+
if (v !== undefined) o[i] = v;
|
|
97
|
+
}
|
|
98
|
+
if (inner) {
|
|
99
|
+
const x = o[i];
|
|
100
|
+
if (typeof x === "object" && x !== null) inner(x);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
162
104
|
}
|
|
163
105
|
}
|
|
106
|
+
seen.delete(schema);
|
|
107
|
+
if (steps.length === 0) return null;
|
|
108
|
+
if (steps.length === 1) return steps[0];
|
|
109
|
+
return (o) => { for (let i = 0; i < steps.length; i++) steps[i](o); };
|
|
164
110
|
}
|
|
165
111
|
|
|
166
112
|
function buildSingleCoercion(targetType) {
|
|
@@ -271,6 +217,9 @@ function codegenAvailable() {
|
|
|
271
217
|
|
|
272
218
|
// Schema compilation cache: same schema string -> reuse compiled functions
|
|
273
219
|
const _compileCache = new Map();
|
|
220
|
+
// Generated preprocess passes, keyed like _compileCache plus the options that
|
|
221
|
+
// shape the pass. `null` records that the generator produced none.
|
|
222
|
+
const _preprocessCache = new Map();
|
|
274
223
|
|
|
275
224
|
// Object identity cache: same schema object reference -> reuse entire compiled state
|
|
276
225
|
// Skips JSON.stringify, cache lookup, and all setup. Near-zero cost for repeated schemas.
|
|
@@ -644,6 +593,16 @@ function _materializeSchema(self) {
|
|
|
644
593
|
const raw = self._rawSchema;
|
|
645
594
|
const options = self._options;
|
|
646
595
|
let schemaObj = _normalizeCallerSchema(raw);
|
|
596
|
+
// `baseURI` is where the schema was retrieved from, the base its relative
|
|
597
|
+
// references resolve against when it declares no `$id` of its own. Draft-07
|
|
598
|
+
// ignores an `$id` beside a root `$ref`, so SchemaStore's schemas, which are
|
|
599
|
+
// written that way, lost their base and every relative reference in them
|
|
600
|
+
// failed to resolve; an editor always knows the address it downloaded a
|
|
601
|
+
// schema from. Set on a shallow copy, never on the caller's object.
|
|
602
|
+
if (typeof options.baseURI === 'string' && options.baseURI !== '' &&
|
|
603
|
+
schemaObj && typeof schemaObj === 'object' && !Array.isArray(schemaObj) && typeof schemaObj.$id !== 'string') {
|
|
604
|
+
schemaObj = { ...schemaObj, $id: options.baseURI };
|
|
605
|
+
}
|
|
647
606
|
const isCallers = self._rawIsCallers && schemaObj === raw;
|
|
648
607
|
if (options.assertFormat === false) {
|
|
649
608
|
schemaObj = stripFormatAssertions(isCallers ? _deepCloneWithSymbols(schemaObj) : schemaObj);
|
|
@@ -935,10 +894,30 @@ class Validator {
|
|
|
935
894
|
const preprocessSchema = resolveSchemaForPreprocess(schemaObj, this._schemaMap);
|
|
936
895
|
// The mutator pass (defaults, coercion, removal) is generated source too,
|
|
937
896
|
// with the schema's `default` values embedded; an interpreter-only
|
|
938
|
-
// validator takes the closure mutators instead.
|
|
939
|
-
|
|
897
|
+
// validator takes the closure mutators instead. The generated pass is a
|
|
898
|
+
// function of the schema text, the referenced schemas and three options,
|
|
899
|
+
// and holds no state, so validators that share those share it, as they
|
|
900
|
+
// share the verdict function: a Fastify app repeats a body schema across
|
|
901
|
+
// routes, and generating and compiling the pass again for each was most of
|
|
902
|
+
// what a repeated schema cost to set up.
|
|
903
|
+
let preprocess = null;
|
|
904
|
+
if (!this._interpretOnly && _codegen !== null) {
|
|
905
|
+
const cacheable = !this._userFormats && !this._usesKeywords;
|
|
906
|
+
const ppKey = cacheable ? mapKey + '\u0000' + String(options.coerceTypes) + '|' + (options.useDefaults !== false) + '|' + String(options.removeAdditional) : null;
|
|
907
|
+
const hit = ppKey !== null ? _preprocessCache.get(ppKey) : undefined;
|
|
908
|
+
if (hit !== undefined) preprocess = hit;
|
|
909
|
+
else {
|
|
910
|
+
preprocess = _codegen.buildPreprocess(preprocessSchema, options) || null;
|
|
911
|
+
if (ppKey !== null) _preprocessCache.set(ppKey, preprocess);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
940
914
|
if (!preprocess) {
|
|
941
|
-
|
|
915
|
+
// A root schema whose text has no `default` has none to fill, and the
|
|
916
|
+
// defaults module then stays unloaded. One reached through a reference
|
|
917
|
+
// into another document is walked, since its defaults are not in this
|
|
918
|
+
// text.
|
|
919
|
+
const mayHaveDefaults = preprocessSchema !== schemaObj || this._schemaStr.includes('"default"');
|
|
920
|
+
const applyDefaults = options.useDefaults === false || !mayHaveDefaults ? null : buildDefaultsApplier(preprocessSchema);
|
|
942
921
|
const applyCoerce = options.coerceTypes ? buildCoercer(preprocessSchema) : null;
|
|
943
922
|
const applyRemove = options.removeAdditional
|
|
944
923
|
? buildRemover(preprocessSchema)
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
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",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"import": "./index.browser.mjs",
|
|
13
13
|
"require": "./index.js"
|
|
14
14
|
},
|
|
15
|
-
"import":
|
|
15
|
+
"import": {
|
|
16
|
+
"module-sync": "./index.node.mjs",
|
|
17
|
+
"default": "./index.mjs"
|
|
18
|
+
},
|
|
16
19
|
"require": "./index.js"
|
|
17
20
|
},
|
|
18
21
|
"./compat": {
|
|
@@ -56,7 +59,7 @@
|
|
|
56
59
|
"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",
|
|
57
60
|
"build": "cmake-js build --target ata",
|
|
58
61
|
"rebuild": "cmake-js rebuild --target ata",
|
|
59
|
-
"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_text_path_errors.js && node tests/test_compiled_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_esm_exports.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_native_lazy.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_first_rejection_builds_one.js && node tests/test_container_local.js && node tests/test_one_shot_validate.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_lite_parity.js && node tests/test_lite_bundle_size.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",
|
|
62
|
+
"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_text_path_errors.js && node tests/test_compiled_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_esm_exports.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_native_lazy.js && node tests/test_cold_start_modules.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_first_rejection_builds_one.js && node tests/test_container_local.js && node tests/test_one_shot_validate.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_ref_annotation_siblings.js && node tests/test_gate_wrapped_schemas.js && node tests/test_pattern_message_escape.js && node tests/test_nested_defaults_engines.js && node tests/test_nested_coercion_parity.js && node tests/test_preprocess_cache.js && node tests/test_large_schema_codegen.js && node tests/test_base_uri.js && node tests/test_hoisted_def_recursion.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_ref_error_order.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_lite_parity.js && node tests/test_lite_bundle_size.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",
|
|
60
63
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
61
64
|
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
|
|
62
65
|
"test:compat": "node tests/test_compat.js",
|
|
@@ -73,7 +76,8 @@
|
|
|
73
76
|
"test:aot-differential": "node tests/test_aot_differential.js",
|
|
74
77
|
"test:aot-cli": "node tests/test_aot_cli_build.js",
|
|
75
78
|
"test:json-suite": "node tests/run_json_test_suite.js",
|
|
76
|
-
"bench:aot-vs-ajv": "node benchmark/bench_aot_vs_ajv.mjs"
|
|
79
|
+
"bench:aot-vs-ajv": "node benchmark/bench_aot_vs_ajv.mjs",
|
|
80
|
+
"test:schemastore": "node scripts/schemastore-differential.js"
|
|
77
81
|
},
|
|
78
82
|
"keywords": [
|
|
79
83
|
"json",
|
|
@@ -106,6 +110,7 @@
|
|
|
106
110
|
"files": [
|
|
107
111
|
"index.js",
|
|
108
112
|
"index.mjs",
|
|
113
|
+
"index.node.mjs",
|
|
109
114
|
"index.browser.mjs",
|
|
110
115
|
"index.d.ts",
|
|
111
116
|
"aot.js",
|
|
@@ -129,13 +134,13 @@
|
|
|
129
134
|
"LICENSE"
|
|
130
135
|
],
|
|
131
136
|
"optionalDependencies": {
|
|
132
|
-
"@ata-validator/native-darwin-arm64": "1.
|
|
133
|
-
"@ata-validator/native-darwin-x64": "1.
|
|
134
|
-
"@ata-validator/native-linux-arm64-gnu": "1.
|
|
135
|
-
"@ata-validator/native-linux-arm64-musl": "1.
|
|
136
|
-
"@ata-validator/native-linux-x64-gnu": "1.
|
|
137
|
-
"@ata-validator/native-linux-x64-musl": "1.
|
|
138
|
-
"@ata-validator/native-win32-x64": "1.
|
|
137
|
+
"@ata-validator/native-darwin-arm64": "1.36.0",
|
|
138
|
+
"@ata-validator/native-darwin-x64": "1.36.0",
|
|
139
|
+
"@ata-validator/native-linux-arm64-gnu": "1.36.0",
|
|
140
|
+
"@ata-validator/native-linux-arm64-musl": "1.36.0",
|
|
141
|
+
"@ata-validator/native-linux-x64-gnu": "1.36.0",
|
|
142
|
+
"@ata-validator/native-linux-x64-musl": "1.36.0",
|
|
143
|
+
"@ata-validator/native-win32-x64": "1.36.0"
|
|
139
144
|
},
|
|
140
145
|
"peerDependencies": {
|
|
141
146
|
"yaml": "^2.0.0"
|