ata-validator 1.53.0 → 1.54.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/README.md +7 -0
- package/compat.js +13 -2
- package/lib/codegen-engine.js +2 -1
- package/lib/dialect.js +36 -1
- package/lib/draft7.js +17 -28
- package/lib/enrich-site.js +29 -2
- package/lib/error-runtime.js +6 -2
- package/lib/formats-source.js +43 -66
- package/lib/formats.js +37 -231
- package/lib/interpreter-compat.js +144 -0
- package/lib/interpreter-core.js +46 -142
- package/lib/js-compiler-errors.js +52 -16
- package/lib/js-compiler.js +537 -65
- package/lib/metaschemas.js +5 -3
- package/lib/plan-compiler.js +24 -7
- package/lib/regex-linear.js +81 -1
- package/lib/safe-regex.js +14 -11
- package/lib/schema-scan.js +19 -28
- package/lib/tier0.js +1 -0
- package/lib/unique-items.js +16 -5
- package/lib/uri-core.js +155 -0
- package/lib/validator-core.js +20 -11
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/lib/metaschemas.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// The official meta-schemas, vendored so a `$ref` to one of them resolves
|
|
4
4
|
// without a network. Draft 2020-12 is eight documents joined by $dynamicRef;
|
|
5
|
-
// draft-07 and draft-
|
|
5
|
+
// draft-07, draft-06 and draft-04 are one each; 2019-09 is seven. Sources:
|
|
6
6
|
// https://json-schema.org/draft/2020-12/schema and
|
|
7
|
-
// http://json-schema.org/draft-07/schema, fetched 2026-08-23,
|
|
7
|
+
// http://json-schema.org/draft-07/schema, fetched 2026-08-23,
|
|
8
8
|
// http://json-schema.org/draft-06/schema and
|
|
9
|
-
// https://json-schema.org/draft/2019-09/schema, fetched 2026-10-10,
|
|
9
|
+
// https://json-schema.org/draft/2019-09/schema, fetched 2026-10-10, and
|
|
10
|
+
// http://json-schema.org/draft-04/schema, fetched 2026-10-14, unmodified.
|
|
10
11
|
// The 2019-09 documents are read through the same 2019-09 rewrite as a
|
|
11
12
|
// caller's schema (lib/draft7.js) once, at load, since they use
|
|
12
13
|
// `$recursiveRef`, which the engines read as `$dynamicRef`.
|
|
@@ -22,6 +23,7 @@ const METASCHEMAS = new Map([
|
|
|
22
23
|
["https://json-schema.org/draft/2020-12/meta/content", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/content","$dynamicAnchor":"meta","title":"Content vocabulary meta-schema","type":["object","boolean"],"properties":{"contentEncoding":{"type":"string"},"contentMediaType":{"type":"string"},"contentSchema":{"$dynamicRef":"#meta"}}}],
|
|
23
24
|
["https://json-schema.org/draft/2020-12/meta/unevaluated", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/unevaluated","$dynamicAnchor":"meta","title":"Unevaluated applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"unevaluatedItems":{"$dynamicRef":"#meta"},"unevaluatedProperties":{"$dynamicRef":"#meta"}}}],
|
|
24
25
|
["http://json-schema.org/draft-07/schema#", {"$schema":"http://json-schema.org/draft-07/schema#","$id":"http://json-schema.org/draft-07/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"$comment":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":true,"readOnly":{"type":"boolean","default":false},"writeOnly":{"type":"boolean","default":false},"examples":{"type":"array","items":true},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":true},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"propertyNames":{"format":"regex"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":true,"enum":{"type":"array","items":true,"minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"contentMediaType":{"type":"string"},"contentEncoding":{"type":"string"},"if":{"$ref":"#"},"then":{"$ref":"#"},"else":{"$ref":"#"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":true}],
|
|
26
|
+
["http://json-schema.org/draft-04/schema#", {"id":"http://json-schema.org/draft-04/schema#","$schema":"http://json-schema.org/draft-04/schema#","description":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"positiveInteger":{"type":"integer","minimum":0},"positiveIntegerDefault0":{"allOf":[{"$ref":"#/definitions/positiveInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"minItems":1,"uniqueItems":true}},"type":"object","properties":{"id":{"type":"string"},"$schema":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"multipleOf":{"type":"number","minimum":0,"exclusiveMinimum":true},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"boolean","default":false},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"boolean","default":false},"maxLength":{"$ref":"#/definitions/positiveInteger"},"minLength":{"$ref":"#/definitions/positiveIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/positiveInteger"},"minItems":{"$ref":"#/definitions/positiveIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"maxProperties":{"$ref":"#/definitions/positiveInteger"},"minProperties":{"$ref":"#/definitions/positiveIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"dependencies":{"exclusiveMaximum":["maximum"],"exclusiveMinimum":["minimum"]},"default":{}}],
|
|
25
27
|
["http://json-schema.org/draft-06/schema#", {"$schema":"http://json-schema.org/draft-06/schema#","$id":"http://json-schema.org/draft-06/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"examples":{"type":"array","items":{}},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"propertyNames":{"format":"regex"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":{},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":{}}],
|
|
26
28
|
["https://json-schema.org/draft/2019-09/schema", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/schema","$vocabulary":{"https://json-schema.org/draft/2019-09/vocab/core":true,"https://json-schema.org/draft/2019-09/vocab/applicator":true,"https://json-schema.org/draft/2019-09/vocab/validation":true,"https://json-schema.org/draft/2019-09/vocab/meta-data":true,"https://json-schema.org/draft/2019-09/vocab/format":false,"https://json-schema.org/draft/2019-09/vocab/content":true},"$recursiveAnchor":true,"title":"Core and Validation specifications meta-schema","allOf":[{"$ref":"meta/core"},{"$ref":"meta/applicator"},{"$ref":"meta/validation"},{"$ref":"meta/meta-data"},{"$ref":"meta/format"},{"$ref":"meta/content"}],"type":["object","boolean"],"properties":{"definitions":{"$comment":"While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.","type":"object","additionalProperties":{"$recursiveRef":"#"},"default":{}},"dependencies":{"$comment":"\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"","type":"object","additionalProperties":{"anyOf":[{"$recursiveRef":"#"},{"$ref":"meta/validation#/$defs/stringArray"}]}}}}],
|
|
27
29
|
["https://json-schema.org/draft/2019-09/meta/core", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/core","$recursiveAnchor":true,"title":"Core vocabulary meta-schema","type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference","$comment":"Non-empty fragments not allowed.","pattern":"^[^#]*#?$"},"$schema":{"type":"string","format":"uri"},"$anchor":{"type":"string","pattern":"^[A-Za-z][-A-Za-z0-9.:_]*$"},"$ref":{"type":"string","format":"uri-reference"},"$recursiveRef":{"type":"string","format":"uri-reference"},"$recursiveAnchor":{"type":"boolean","default":false},"$vocabulary":{"type":"object","propertyNames":{"type":"string","format":"uri"},"additionalProperties":{"type":"boolean"}},"$comment":{"type":"string"},"$defs":{"type":"object","additionalProperties":{"$recursiveRef":"#"},"default":{}}}}],
|
package/lib/plan-compiler.js
CHANGED
|
@@ -213,11 +213,18 @@ function install(deps) {
|
|
|
213
213
|
const objs = [];
|
|
214
214
|
if (P.required !== null) {
|
|
215
215
|
const req = P.required;
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
// A required key holding undefined is missing; for a declared
|
|
217
|
+
// property the property step finds it (requiredInProps).
|
|
218
|
+
const undef = P.requiredUndef;
|
|
219
|
+
if (req.length === 1) { const k = req[0]; objs.push(undef !== null && undef[0] ? (d) => Object.hasOwn(d, k) && d[k] !== undefined : (d) => Object.hasOwn(d, k)); }
|
|
220
|
+
else if (undef === null) objs.push((d) => {
|
|
218
221
|
for (let i = 0; i < req.length; i++) if (!Object.hasOwn(d, req[i])) return false;
|
|
219
222
|
return true;
|
|
220
223
|
});
|
|
224
|
+
else objs.push((d) => {
|
|
225
|
+
for (let i = 0; i < req.length; i++) if (!Object.hasOwn(d, req[i]) || (undef[i] && d[req[i]] === undefined)) return false;
|
|
226
|
+
return true;
|
|
227
|
+
});
|
|
221
228
|
}
|
|
222
229
|
if (P.minProperties !== undefined) { const m = P.minProperties; objs.push((d) => Object.keys(d).length >= m); }
|
|
223
230
|
if (P.maxProperties !== undefined) { const m = P.maxProperties; objs.push((d) => Object.keys(d).length <= m); }
|
|
@@ -490,8 +497,10 @@ function install(deps) {
|
|
|
490
497
|
// Declared properties: a linear scan over a short list beats a Map
|
|
491
498
|
// lookup, and most schemas declare a handful.
|
|
492
499
|
const propKeys = props !== null ? [...props.keys()] : null;
|
|
500
|
+
// req: the key is also required, so holding undefined it is missing.
|
|
501
|
+
const reqIn = P.requiredInProps;
|
|
493
502
|
const propList = props !== null
|
|
494
|
-
? [...props
|
|
503
|
+
? [...props].map(([key, entry]) => ({ fn: child(entry.node), seg: entry.seg, schemaSeg: entry.schemaSeg, req: reqIn !== null && reqIn.has(key) }))
|
|
495
504
|
: null;
|
|
496
505
|
const propMap = props !== null && props.size > 8 ? new Map(propKeys.map((k, i) => [k, propList[i]])) : null;
|
|
497
506
|
const lookup = propMap !== null
|
|
@@ -533,12 +542,18 @@ function install(deps) {
|
|
|
533
542
|
let evaluated = false;
|
|
534
543
|
const prop = lookup !== null ? lookup(key) : undefined;
|
|
535
544
|
// A declared property whose value is undefined is not checked (see
|
|
536
|
-
// the interpreter's eval).
|
|
545
|
+
// the interpreter's eval); required, it is missing.
|
|
537
546
|
if (prop !== undefined) {
|
|
538
547
|
const value = data[key];
|
|
539
|
-
if (value !== undefined
|
|
548
|
+
if (value !== undefined) {
|
|
549
|
+
if (!((prop.fn.leaf && prop.fn.v(value, stack)) || prop.fn.c(value, errors, instancePath + prop.seg, schemaPath + prop.schemaSeg, stack))) {
|
|
550
|
+
ok = false;
|
|
551
|
+
if (errors === NOERRORS) return false;
|
|
552
|
+
}
|
|
553
|
+
} else if (prop.req) {
|
|
540
554
|
ok = false;
|
|
541
555
|
if (errors === NOERRORS) return false;
|
|
556
|
+
errors.push(err('required', 'required', instancePath, schemaPath + '/required', { missingProperty: key }, `must have required property '${key}'`));
|
|
542
557
|
}
|
|
543
558
|
evaluated = true;
|
|
544
559
|
}
|
|
@@ -582,7 +597,8 @@ function install(deps) {
|
|
|
582
597
|
const key = propKeys[i];
|
|
583
598
|
if (!Object.hasOwn(data, key)) continue;
|
|
584
599
|
const value = data[key];
|
|
585
|
-
if (value !== undefined
|
|
600
|
+
if (value !== undefined) { if (!propList[i].fn.v(value, stack)) return false; }
|
|
601
|
+
else if (propList[i].req) return false;
|
|
586
602
|
if (collect) addProp(rec, key);
|
|
587
603
|
}
|
|
588
604
|
return true;
|
|
@@ -599,7 +615,8 @@ function install(deps) {
|
|
|
599
615
|
const prop = lookup !== null ? lookup(key) : undefined;
|
|
600
616
|
if (prop !== undefined) {
|
|
601
617
|
const value = data[key];
|
|
602
|
-
if (value !== undefined
|
|
618
|
+
if (value !== undefined) { if (!prop.fn.v(value, stack)) return false; }
|
|
619
|
+
else if (prop.req) return false;
|
|
603
620
|
evaluated = true;
|
|
604
621
|
}
|
|
605
622
|
if (patterns !== null) {
|
package/lib/regex-linear.js
CHANGED
|
@@ -210,6 +210,86 @@ function deterministicRule (ast) {
|
|
|
210
210
|
return unbounded === 0 || anchored(ast)
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// Two more shapes the rules above decline, both anchored with `^` and `$`
|
|
214
|
+
// around one top-level sequence.
|
|
215
|
+
//
|
|
216
|
+
// One choice: characters and classes, each repeated a fixed or bounded number
|
|
217
|
+
// of times, with only one of the repeats able to vary, by at most 256
|
|
218
|
+
// (`^[a-z0-9_-]{1,128}$`).
|
|
219
|
+
// The engine backtracks through that one repeat and nowhere else, at most its
|
|
220
|
+
// width per attempt, and the anchor allows one attempt.
|
|
221
|
+
//
|
|
222
|
+
// A delimited loop: `^P(Xd)*Q$` or with `+`, where d is one character or
|
|
223
|
+
// class, X and Q match nothing d matches (Q may end with d, or an optional
|
|
224
|
+
// d), and P holds no unbounded quantifier. Dotted identifiers and paths are
|
|
225
|
+
// written so: `^([A-Za-z_$][\w$]*\.)*[A-Za-z_$][\w$]*$`, `^/?([^/]+/)*[^/]+/?$`.
|
|
226
|
+
// Every iteration and Q's match end at a d or at the end, so each wrong
|
|
227
|
+
// choice between another iteration and Q fails within one segment, and the
|
|
228
|
+
// segments together are the input once. X and Q each hold at most one
|
|
229
|
+
// unbounded quantifier, over a character or class, so a segment is not split
|
|
230
|
+
// two ways either.
|
|
231
|
+
function sequenceOf (ast) {
|
|
232
|
+
if (ast.t !== 'concat') return null
|
|
233
|
+
const parts = ast.parts
|
|
234
|
+
if (parts.length < 3 || parts[0].t !== 'bol' || parts[parts.length - 1].t !== 'eol') return null
|
|
235
|
+
return parts.slice(1, -1)
|
|
236
|
+
}
|
|
237
|
+
const repeatOfAtom = (n) => (n.t === 'star' || n.t === 'plus' || n.t === 'quest' || n.t === 'repeat') && atom(n.child)
|
|
238
|
+
const unboundedNode = (n) => n.t === 'star' || n.t === 'plus' || (n.t === 'repeat' && n.max === Infinity)
|
|
239
|
+
|
|
240
|
+
function oneChoiceRule (ast) {
|
|
241
|
+
const seq = sequenceOf(ast)
|
|
242
|
+
if (seq === null) return false
|
|
243
|
+
let varying = 0
|
|
244
|
+
for (const n of seq) {
|
|
245
|
+
if (atom(n)) continue
|
|
246
|
+
if (n.t === 'repeat' && atom(n.child) && n.max !== Infinity) {
|
|
247
|
+
if (n.max > 256) return false
|
|
248
|
+
if (n.max > n.min) varying++
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
return false
|
|
252
|
+
}
|
|
253
|
+
return varying <= 1
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function delimitedLoopRule (ast) {
|
|
257
|
+
const seq = sequenceOf(ast)
|
|
258
|
+
if (seq === null) return false
|
|
259
|
+
const loopAt = seq.findIndex((n) => unboundedNode(n) && !atom(n.child))
|
|
260
|
+
if (loopAt < 0) return false
|
|
261
|
+
let body = seq[loopAt].child
|
|
262
|
+
while (body.t === 'group') body = body.child
|
|
263
|
+
if (body.t !== 'concat' || body.parts.length < 2) return false
|
|
264
|
+
const d = body.parts[body.parts.length - 1]
|
|
265
|
+
if (!atom(d)) return false
|
|
266
|
+
const D = charSet(d)
|
|
267
|
+
// A run of characters, classes and their repeats that matches nothing in
|
|
268
|
+
// D, with at most one unbounded quantifier.
|
|
269
|
+
const run = (nodes) => {
|
|
270
|
+
let unbounded = 0
|
|
271
|
+
for (const n of nodes) {
|
|
272
|
+
const a = atom(n) ? n : repeatOfAtom(n) ? n.child : null
|
|
273
|
+
if (a === null || overlap(charSet(a), D)) return false
|
|
274
|
+
if (unboundedNode(n)) unbounded++
|
|
275
|
+
if (n.t === 'repeat' && n.max !== Infinity && n.max - n.min > 64) return false
|
|
276
|
+
}
|
|
277
|
+
return unbounded <= 1
|
|
278
|
+
}
|
|
279
|
+
if (!run(body.parts.slice(0, -1))) return false
|
|
280
|
+
const prefix = seq.slice(0, loopAt)
|
|
281
|
+
if (prefix.some(hasUnbounded)) return false
|
|
282
|
+
const pb = simpleRule({ t: 'concat', parts: prefix })
|
|
283
|
+
if (!pb && prefix.length > 0) return false
|
|
284
|
+
let suffix = seq.slice(loopAt + 1)
|
|
285
|
+
const last = suffix[suffix.length - 1]
|
|
286
|
+
if (last !== undefined) {
|
|
287
|
+
const tail = atom(last) ? last : last.t === 'quest' && atom(last.child) ? last.child : null
|
|
288
|
+
if (tail !== null && !overlap(charSet(tail), { bits: D.bits.map((b) => b ^ 1), high: D.high ? 0 : 1 })) suffix = suffix.slice(0, -1)
|
|
289
|
+
}
|
|
290
|
+
return run(suffix)
|
|
291
|
+
}
|
|
292
|
+
|
|
213
293
|
function nativeIsLinear (src) {
|
|
214
294
|
if (typeof src !== 'string' || src.length > 512) return false
|
|
215
295
|
for (let i = 0; i < src.length; i++) {
|
|
@@ -225,7 +305,7 @@ function nativeIsLinear (src) {
|
|
|
225
305
|
}
|
|
226
306
|
let ast
|
|
227
307
|
try { ast = parse(src) } catch { return false }
|
|
228
|
-
return simpleRule(ast) || deterministicRule(ast)
|
|
308
|
+
return simpleRule(ast) || deterministicRule(ast) || oneChoiceRule(ast) || delimitedLoopRule(ast)
|
|
229
309
|
}
|
|
230
310
|
|
|
231
311
|
module.exports = { nativeIsLinear }
|
package/lib/safe-regex.js
CHANGED
|
@@ -473,25 +473,28 @@ function __ataSafeRegex () {
|
|
|
473
473
|
}
|
|
474
474
|
if (id < 0) return testNFA(s)
|
|
475
475
|
if (len === 0) return (flags[id] & 1) === 1
|
|
476
|
-
|
|
477
|
-
//
|
|
478
|
-
//
|
|
476
|
+
if ((flags[id] & 1) === 1) return true
|
|
477
|
+
// The last character, with the end flag, is stepped after the loop.
|
|
478
|
+
// Tables are locals, reread after `step` (which may grow them).
|
|
479
479
|
const last = len - 1
|
|
480
|
+
let T = trans
|
|
481
|
+
let F = flags
|
|
480
482
|
for (let pos = 0; pos < last; pos++) {
|
|
481
|
-
if ((flags[id] & 1) === 1) return true
|
|
482
483
|
const c = s.charCodeAt(pos)
|
|
483
|
-
let nid
|
|
484
|
-
if (
|
|
485
|
-
nid = trans[(id << 7) | c]
|
|
486
|
-
if (nid === -2) { nid = step(states[id], c, false); if (nid >= 0 || overflow) trans[(id << 7) | c] = nid }
|
|
487
|
-
} else {
|
|
484
|
+
let nid = c < 128 ? T[(id << 7) | c] : -2
|
|
485
|
+
if (nid === -2) {
|
|
488
486
|
nid = step(states[id], c, false)
|
|
487
|
+
T = trans; F = flags
|
|
488
|
+
if (c < 128 && (nid >= 0 || overflow)) T[(id << 7) | c] = nid
|
|
489
489
|
}
|
|
490
490
|
if (nid < 0) return testNFA(s)
|
|
491
491
|
id = nid
|
|
492
|
-
|
|
492
|
+
const f = F[id]
|
|
493
|
+
if (f !== 0) {
|
|
494
|
+
if ((f & 2) === 2) return false
|
|
495
|
+
return true
|
|
496
|
+
}
|
|
493
497
|
}
|
|
494
|
-
if ((flags[id] & 1) === 1) return true
|
|
495
498
|
const c = s.charCodeAt(last)
|
|
496
499
|
let nid
|
|
497
500
|
if (c < 128) {
|
package/lib/schema-scan.js
CHANGED
|
@@ -30,23 +30,10 @@ const TUPLE_ITEMS = 1 << 5; // array-valued `items`, split into `prefixItem
|
|
|
30
30
|
const EXCLUSIVE_BOOL = 1 << 6; // draft-04's boolean `exclusiveMinimum`/`exclusiveMaximum`
|
|
31
31
|
const ENCODED_REF = 1 << 7; // a fragment `$ref` holding a percent escape, decoded by normalizeNullable's walk
|
|
32
32
|
|
|
33
|
-
// Questions compat asks of a schema it is about to compile
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const DISCRIMINATOR = 1 << 10; // `discriminator` anywhere
|
|
38
|
-
const HAS_DEFAULT = 1 << 11; // `default` anywhere
|
|
39
|
-
const HAS_ALLOF = 1 << 12; // `allOf` anywhere
|
|
40
|
-
const HAS_FORMAT = 1 << 13; // `format` anywhere
|
|
41
|
-
const KEY_BITS = new Map([
|
|
42
|
-
['$ref', HAS_REF | BEYOND_ITEMS], ['$dynamicRef', BEYOND_ITEMS], ['allOf', HAS_ALLOF | BEYOND_ITEMS],
|
|
43
|
-
['anyOf', BEYOND_ITEMS], ['oneOf', BEYOND_ITEMS], ['not', BEYOND_ITEMS], ['if', BEYOND_ITEMS],
|
|
44
|
-
['then', BEYOND_ITEMS], ['else', BEYOND_ITEMS], ['additionalProperties', BEYOND_ITEMS],
|
|
45
|
-
['patternProperties', BEYOND_ITEMS], ['prefixItems', BEYOND_ITEMS], ['additionalItems', BEYOND_ITEMS],
|
|
46
|
-
['contains', BEYOND_ITEMS], ['dependentSchemas', BEYOND_ITEMS], ['dependencies', BEYOND_ITEMS],
|
|
47
|
-
['propertyNames', BEYOND_ITEMS], ['unevaluatedProperties', BEYOND_ITEMS], ['unevaluatedItems', BEYOND_ITEMS],
|
|
48
|
-
['discriminator', DISCRIMINATOR], ['default', HAS_DEFAULT], ['format', HAS_FORMAT],
|
|
49
|
-
]);
|
|
33
|
+
// Questions compat asks of a schema it is about to compile, read on the same
|
|
34
|
+
// walk so that a document is not walked again for them. compat sets the keys
|
|
35
|
+
// and their bits (setExtraKeys); without compat the walk reads none.
|
|
36
|
+
let EXTRA = null;
|
|
50
37
|
|
|
51
38
|
// Everything only draft-07 normalization acts on. A schema of another dialect
|
|
52
39
|
// can carry these without them meaning anything, so they are read together
|
|
@@ -71,7 +58,7 @@ const ANCHOR_ID_RE = /^#[A-Za-z][A-Za-z0-9_.:-]*$/;
|
|
|
71
58
|
// This assumes a schema is not mutated after being handed to a Validator,
|
|
72
59
|
// which is already true of everything else here: the compile cache, the
|
|
73
60
|
// identity cache and the schema map would all be stale too.
|
|
74
|
-
|
|
61
|
+
let CACHE = new WeakMap();
|
|
75
62
|
|
|
76
63
|
function scan(schema) {
|
|
77
64
|
if (typeof schema !== 'object' || schema === null) return 0;
|
|
@@ -110,11 +97,13 @@ function scan(schema) {
|
|
|
110
97
|
}
|
|
111
98
|
// Every key, not just the subschema keywords, so this cannot miss a place
|
|
112
99
|
// the normalizers would reach.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
100
|
+
if (EXTRA !== null) {
|
|
101
|
+
for (let i = 0; i < keys.length; i++) {
|
|
102
|
+
const b = EXTRA.get(keys[i]);
|
|
103
|
+
if (b !== undefined) bits |= b;
|
|
104
|
+
}
|
|
117
105
|
}
|
|
106
|
+
for (let i = 0; i < keys.length; i++) walk(node[keys[i]]);
|
|
118
107
|
};
|
|
119
108
|
|
|
120
109
|
walk(schema);
|
|
@@ -146,10 +135,12 @@ module.exports = {
|
|
|
146
135
|
EXCLUSIVE_BOOL,
|
|
147
136
|
ENCODED_REF,
|
|
148
137
|
DRAFT7_WORK,
|
|
149
|
-
HAS_REF,
|
|
150
|
-
BEYOND_ITEMS,
|
|
151
|
-
DISCRIMINATOR,
|
|
152
|
-
HAS_DEFAULT,
|
|
153
|
-
HAS_ALLOF,
|
|
154
|
-
HAS_FORMAT,
|
|
155
138
|
};
|
|
139
|
+
|
|
140
|
+
// A schema scanned before the keys were set is scanned again: what was
|
|
141
|
+
// remembered for it does not answer the new questions.
|
|
142
|
+
function setExtraKeys(map) {
|
|
143
|
+
EXTRA = map;
|
|
144
|
+
CACHE = new WeakMap();
|
|
145
|
+
}
|
|
146
|
+
Object.defineProperty(module.exports, '_setExtraKeys', { value: setExtraKeys, enumerable: false });
|
package/lib/tier0.js
CHANGED
|
@@ -173,6 +173,7 @@ function tier0ValidateObject(plan, data) {
|
|
|
173
173
|
// treated as absent, as the interpreted engine treats it.
|
|
174
174
|
if (v !== undefined && (c.protoName || (_PN ? data.__proto__ : Object.getPrototypeOf(data)) !== Object.prototype) && !_hop.call(data, c.key)) v = undefined;
|
|
175
175
|
if (v === undefined) {
|
|
176
|
+
// A required key holding undefined is missing, as in every engine.
|
|
176
177
|
if (reqMask & (1 << i)) return false;
|
|
177
178
|
continue;
|
|
178
179
|
}
|
package/lib/unique-items.js
CHANGED
|
@@ -22,17 +22,28 @@ function _deq(a, b) {
|
|
|
22
22
|
if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false;
|
|
23
23
|
var aa = Array.isArray(a);
|
|
24
24
|
if (aa !== Array.isArray(b)) return false;
|
|
25
|
-
var i;
|
|
25
|
+
var i, k, x, y;
|
|
26
26
|
if (aa) {
|
|
27
27
|
if (a.length !== b.length) return false;
|
|
28
|
-
for (i =
|
|
28
|
+
for (i = a.length; i-- !== 0;) if (!_deq(a[i], b[i])) return false;
|
|
29
29
|
return true;
|
|
30
30
|
}
|
|
31
31
|
var ka = Object.keys(a);
|
|
32
32
|
if (ka.length !== Object.keys(b).length) return false;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Keys and scalar values first, nested values after, from the last key back:
|
|
34
|
+
// two items of a list most often differ in a name, a path or an id, and
|
|
35
|
+
// walking a nested list first made each comparison of rust-project's crates
|
|
36
|
+
// three times what it needed (250 against 78 ns for the three; the default
|
|
37
|
+
// validator's deep equal takes 115).
|
|
38
|
+
for (i = ka.length; i-- !== 0;) {
|
|
39
|
+
k = ka[i];
|
|
40
|
+
if (!Object.prototype.hasOwnProperty.call(b, k)) return false;
|
|
41
|
+
x = a[k]; y = b[k];
|
|
42
|
+
if (x !== y && (x === null || y === null || typeof x !== 'object' || typeof y !== 'object')) return false;
|
|
43
|
+
}
|
|
44
|
+
for (i = ka.length; i-- !== 0;) {
|
|
45
|
+
k = ka[i]; x = a[k];
|
|
46
|
+
if (x !== null && typeof x === 'object' && !_deq(x, b[k])) return false;
|
|
36
47
|
}
|
|
37
48
|
return true;
|
|
38
49
|
}
|
package/lib/uri-core.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// RFC 3986 URI and URI-reference, RFC 3987 IRI and IRI-reference, as one walk
|
|
4
|
+
// over the string with no slicing. `mode` bit 1 asks for a scheme (uri, iri),
|
|
5
|
+
// bit 2 lets non-ASCII through (iri, iri-reference). The rules the walk holds
|
|
6
|
+
// that a character-class scan does not: a second "@" in the authority, a port
|
|
7
|
+
// that is not digits, square brackets anywhere but around an IP literal, the
|
|
8
|
+
// literal itself (RFC 3986 IPv6 with an embedded IPv4 of no leading zeros, an
|
|
9
|
+
// RFC 6874 zone id, IPvFuture), a colon in the first segment of a relative
|
|
10
|
+
// path, and a second "#". A reference made only of unreserved characters,
|
|
11
|
+
// sub-delimiters, "/" and "@" (a file name, a path) is one whatever its
|
|
12
|
+
// shape, and is answered by one scan before any of that.
|
|
13
|
+
//
|
|
14
|
+
// A factory, like lib/safe-regex.js: the interpreted engine calls the
|
|
15
|
+
// function it returns, and the code generator emits the factory's source
|
|
16
|
+
// text (`source`) into the program it builds, so a standalone module carries
|
|
17
|
+
// the same walk without importing it. Nothing inside the factory reads a
|
|
18
|
+
// free variable, and no comments inside it: its text is what gets emitted.
|
|
19
|
+
// `ip6` is the IPv6 check for a bracketed host, one string in: lib/formats.js
|
|
20
|
+
// gives its own and the generator emits ipv6Source, so neither carries a
|
|
21
|
+
// second copy. The slice it costs happens only on an IP literal.
|
|
22
|
+
function __ataUri (ip6) {
|
|
23
|
+
const C = new Uint8Array(128);
|
|
24
|
+
for (let i = 48; i < 58; i++) C[i] = 3;
|
|
25
|
+
for (let i = 65; i < 91; i++) C[i] = 3;
|
|
26
|
+
for (let i = 97; i < 123; i++) C[i] = 3;
|
|
27
|
+
C[43] = 3; C[45] = 3; C[46] = 3;
|
|
28
|
+
C[95] = 1; C[126] = 1;
|
|
29
|
+
C[33] = 1; C[36] = 1; C[38] = 1; C[39] = 1; C[40] = 1; C[41] = 1; C[42] = 1; C[44] = 1; C[59] = 1; C[61] = 1;
|
|
30
|
+
const H = new Uint8Array(128);
|
|
31
|
+
for (let i = 48; i < 58; i++) H[i] = 1;
|
|
32
|
+
for (let i = 65; i < 71; i++) H[i] = 1;
|
|
33
|
+
for (let i = 97; i < 103; i++) H[i] = 1;
|
|
34
|
+
function pct (s, i) {
|
|
35
|
+
const a = s.charCodeAt(i + 1), b = s.charCodeAt(i + 2);
|
|
36
|
+
return a < 128 && b < 128 && H[a] === 1 && H[b] === 1;
|
|
37
|
+
}
|
|
38
|
+
const P = new Uint8Array(128);
|
|
39
|
+
for (let i = 0; i < 128; i++) P[i] = C[i] & 1;
|
|
40
|
+
P[58] = 1; P[64] = 1; P[47] = 1;
|
|
41
|
+
const Q = new Uint8Array(P);
|
|
42
|
+
Q[63] = 1;
|
|
43
|
+
const S = new Uint8Array(P);
|
|
44
|
+
S[58] = 0;
|
|
45
|
+
function literal (s, from, to) {
|
|
46
|
+
if (from >= to) return false;
|
|
47
|
+
const f = s.charCodeAt(from);
|
|
48
|
+
if (f === 118 || f === 86) {
|
|
49
|
+
let i = from + 1, h = 0;
|
|
50
|
+
for (; i < to; i++) { const c = s.charCodeAt(i); if (c < 128 && H[c] === 1) h++; else break; }
|
|
51
|
+
if (h === 0 || s.charCodeAt(i) !== 46 || i + 1 >= to) return false;
|
|
52
|
+
for (i++; i < to; i++) { const c = s.charCodeAt(i); if (!(c < 128 && ((C[c] & 1) === 1 || c === 58))) return false; }
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
let z = -1;
|
|
56
|
+
for (let i = from; i < to; i++) if (s.charCodeAt(i) === 37) { z = i; break; }
|
|
57
|
+
if (z === -1) return ip6(s.slice(from, to));
|
|
58
|
+
if (s.charCodeAt(z + 1) !== 50 || s.charCodeAt(z + 2) !== 53 || z + 3 >= to) return false;
|
|
59
|
+
for (let i = z + 3; i < to; i++) {
|
|
60
|
+
const c = s.charCodeAt(i);
|
|
61
|
+
if (c === 37) { if (!pct(s, i)) return false; i += 2; continue; }
|
|
62
|
+
if (!(c < 128 && (C[c] & 1) === 1)) return false;
|
|
63
|
+
}
|
|
64
|
+
return ip6(s.slice(from, z));
|
|
65
|
+
}
|
|
66
|
+
return function (s, mode) {
|
|
67
|
+
const n = s.length;
|
|
68
|
+
const wide = (mode & 2) !== 0;
|
|
69
|
+
if ((mode & 1) === 0 && !(s.charCodeAt(0) === 47 && s.charCodeAt(1) === 47)) {
|
|
70
|
+
let k = 0;
|
|
71
|
+
for (; k < n; k++) { const c = s.charCodeAt(k); if (c > 127 || S[c] === 0) break; }
|
|
72
|
+
if (k === n) return true;
|
|
73
|
+
}
|
|
74
|
+
let i = 0, c = s.charCodeAt(0), scheme = false;
|
|
75
|
+
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) {
|
|
76
|
+
let j = 1;
|
|
77
|
+
while (j < n) { c = s.charCodeAt(j); if (c === 58 || c > 127 || (C[c] & 2) === 0) break; j++; }
|
|
78
|
+
if (j < n && c === 58) { scheme = true; i = j + 1; }
|
|
79
|
+
}
|
|
80
|
+
if (!scheme && (mode & 1) !== 0) return false;
|
|
81
|
+
let auth = false;
|
|
82
|
+
if (s.charCodeAt(i) === 47 && s.charCodeAt(i + 1) === 47) {
|
|
83
|
+
auth = true;
|
|
84
|
+
const st = i + 2;
|
|
85
|
+
let end = n, at = -1, br = false, brAt = false, colon = -1;
|
|
86
|
+
for (let k = st; k < n; k++) {
|
|
87
|
+
c = s.charCodeAt(k);
|
|
88
|
+
if (c === 47 || c === 63 || c === 35) { end = k; break; }
|
|
89
|
+
if (c < 128) {
|
|
90
|
+
if ((C[c] & 1) === 1) continue;
|
|
91
|
+
if (c === 37) { if (!pct(s, k)) return false; k += 2; continue; }
|
|
92
|
+
if (c === 58) { if (colon === -1) colon = k; continue; }
|
|
93
|
+
if (c === 64) { if (at !== -1) return false; at = k; brAt = br; colon = -1; continue; }
|
|
94
|
+
if (c === 91 || c === 93) { br = true; continue; }
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (!wide) return false;
|
|
98
|
+
}
|
|
99
|
+
if (brAt) return false;
|
|
100
|
+
const hs = at === -1 ? st : at + 1;
|
|
101
|
+
if (s.charCodeAt(hs) === 91) {
|
|
102
|
+
let close = -1;
|
|
103
|
+
for (let k = hs + 1; k < end; k++) if (s.charCodeAt(k) === 93) { close = k; break; }
|
|
104
|
+
if (close === -1 || !literal(s, hs + 1, close)) return false;
|
|
105
|
+
if (close + 1 < end) {
|
|
106
|
+
if (s.charCodeAt(close + 1) !== 58) return false;
|
|
107
|
+
for (let k = close + 2; k < end; k++) { c = s.charCodeAt(k); if (c < 48 || c > 57) return false; }
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
if (br) return false;
|
|
111
|
+
if (colon !== -1) for (let k = colon + 1; k < end; k++) { c = s.charCodeAt(k); if (c < 48 || c > 57) return false; }
|
|
112
|
+
}
|
|
113
|
+
i = end;
|
|
114
|
+
}
|
|
115
|
+
if (!scheme && !auth && s.charCodeAt(i) !== 47) {
|
|
116
|
+
for (; i < n; i++) {
|
|
117
|
+
c = s.charCodeAt(i);
|
|
118
|
+
if (c === 47 || c === 63 || c === 35) break;
|
|
119
|
+
if (c === 58) return false;
|
|
120
|
+
if (c === 37) { if (!pct(s, i)) return false; i += 2; continue; }
|
|
121
|
+
if (c < 128 ? P[c] === 0 : !wide) return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (; i < n; i++) {
|
|
125
|
+
c = s.charCodeAt(i);
|
|
126
|
+
if (c < 128 ? P[c] === 0 : !wide) {
|
|
127
|
+
if (c === 63 || c === 35) break;
|
|
128
|
+
if (c === 37) { const a = s.charCodeAt(i + 1), b = s.charCodeAt(i + 2); if (!(a < 128 && b < 128 && H[a] === 1 && H[b] === 1)) return false; i += 2; continue; }
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (i >= n) return true;
|
|
133
|
+
if (c === 63) {
|
|
134
|
+
for (i++; i < n; i++) {
|
|
135
|
+
c = s.charCodeAt(i);
|
|
136
|
+
if (c < 128 ? Q[c] === 0 : !wide) {
|
|
137
|
+
if (c === 35) break;
|
|
138
|
+
if (c === 37) { if (!pct(s, i)) return false; i += 2; continue; }
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (i >= n) return true;
|
|
143
|
+
}
|
|
144
|
+
for (i++; i < n; i++) {
|
|
145
|
+
c = s.charCodeAt(i);
|
|
146
|
+
if (c < 128 ? Q[c] === 0 : !wide) {
|
|
147
|
+
if (c === 37) { if (!pct(s, i)) return false; i += 2; continue; }
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = { __ataUri };
|
package/lib/validator-core.js
CHANGED
|
@@ -33,12 +33,13 @@ let _aotLoader = null;
|
|
|
33
33
|
function _registerAot(load) {
|
|
34
34
|
_aotLoader = load;
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
// draft7.js, vocabularies.js, shape-classifier.js and tier0.js load where
|
|
37
|
+
// they are first used: a fresh process validating a 2020-12 schema runs none
|
|
38
|
+
// of their code, and reading them cost it about a tenth of what it loads.
|
|
39
|
+
const _draft7 = () => require("./draft7");
|
|
40
|
+
const _vocabularies = () => require("./vocabularies");
|
|
38
41
|
const { needsNormalization } = require("./schema-scan");
|
|
39
|
-
const { isV1Dialect } = require("./dialect");
|
|
40
|
-
const { classify } = require("./shape-classifier");
|
|
41
|
-
const { buildTier0Plan, tier0Validate } = require("./tier0");
|
|
42
|
+
const { isV1Dialect, draftCode } = require("./dialect");
|
|
42
43
|
|
|
43
44
|
// The closure defaults pass. Only a validator without the generated
|
|
44
45
|
// preprocess pass calls it, so it loads on that first call; loading it with
|
|
@@ -470,8 +471,9 @@ function _normalizeCallerSchema(s, inheritDraft7) {
|
|
|
470
471
|
function _normalizeCallerSchemaUncached(s, inheritDraft7) {
|
|
471
472
|
const declared = s && typeof s === 'object' ? s.$schema : undefined
|
|
472
473
|
const code = declared !== undefined ? draftCode(declared) : (inheritDraft7 || 0)
|
|
473
|
-
const needsDraft7 = code === 1 || code === 2
|
|
474
|
-
const
|
|
474
|
+
const needsDraft7 = code === 1 || code === 2 || code === 4
|
|
475
|
+
const draft4 = code === 4
|
|
476
|
+
const draft6 = code === 2 || draft4
|
|
475
477
|
const draft2019 = code === 3
|
|
476
478
|
// One walk answers whether there is anything to do. Almost always there is
|
|
477
479
|
// not, and then the serialize, clone, normalize, serialize, compare below is
|
|
@@ -482,7 +484,8 @@ function _normalizeCallerSchemaUncached(s, inheritDraft7) {
|
|
|
482
484
|
if (!draft6 && !draft2019 && !needsNormalization(s, needsDraft7)) return s
|
|
483
485
|
|
|
484
486
|
const copy = _deepCloneWithSymbols(s)
|
|
485
|
-
|
|
487
|
+
const { normalizeDraft7, normalizeDraft2019, normalizeNullable, normalizeExclusiveBounds } = _draft7()
|
|
488
|
+
if (needsDraft7) normalizeDraft7(copy, true, draft6, draft4)
|
|
486
489
|
if (draft2019) normalizeDraft2019(copy, true)
|
|
487
490
|
normalizeNullable(copy)
|
|
488
491
|
normalizeExclusiveBounds(copy)
|
|
@@ -615,7 +618,11 @@ function _applyVocabularies(schemaObj, original, schemaMap) {
|
|
|
615
618
|
if (!schemaObj || typeof schemaObj !== 'object') return schemaObj
|
|
616
619
|
const declared = schemaObj.$schema
|
|
617
620
|
if (typeof declared !== 'string') return schemaObj
|
|
618
|
-
|
|
621
|
+
// Only a meta-schema with a $vocabulary can disable a keyword.
|
|
622
|
+
const meta = schemaMap.get(declared)
|
|
623
|
+
if (!meta || typeof meta !== 'object' || !meta.$vocabulary || typeof meta.$vocabulary !== 'object') return schemaObj
|
|
624
|
+
const { enabledKeywords, stripDisabledKeywords } = _vocabularies()
|
|
625
|
+
const enabled = enabledKeywords(meta)
|
|
619
626
|
if (!enabled) return schemaObj
|
|
620
627
|
// `original` is the caller's own object when it reached here unchanged, and
|
|
621
628
|
// that one is never mutated.
|
|
@@ -724,7 +731,7 @@ function _materializeSchema(self) {
|
|
|
724
731
|
// Always on a copy: a normalized schema is shared by every validator built
|
|
725
732
|
// from the same object (see _normalizeCallerSchema), so stripping in place
|
|
726
733
|
// would take format checks away from the others.
|
|
727
|
-
schemaObj = stripFormatAssertions(_deepCloneWithSymbols(schemaObj));
|
|
734
|
+
schemaObj = _draft7().stripFormatAssertions(_deepCloneWithSymbols(schemaObj));
|
|
728
735
|
}
|
|
729
736
|
// A keyword used only in a schema reached through $ref counts too: the
|
|
730
737
|
// interpreted engine applies it there, and every path that does not know the
|
|
@@ -2395,8 +2402,10 @@ _defineLazyMethod('isValidObject', (self) => {
|
|
|
2395
2402
|
return self.isValidObject(data);
|
|
2396
2403
|
}
|
|
2397
2404
|
// Lazy: classify + build tier 0 plan on first call, not in constructor.
|
|
2398
|
-
const _tier = classify(self._schemaObj);
|
|
2405
|
+
const _tier = require("./shape-classifier").classify(self._schemaObj);
|
|
2399
2406
|
if (_tier.tier === 0) {
|
|
2407
|
+
// Bound once here, so the verdict below reads a local, not the module.
|
|
2408
|
+
const { buildTier0Plan, tier0Validate } = require("./tier0");
|
|
2400
2409
|
const _plan = buildTier0Plan(self._schemaObj);
|
|
2401
2410
|
let _n = 0;
|
|
2402
2411
|
_bindVerdict(self, (d) => {
|
package/lib/version.js
CHANGED