ata-validator 1.53.0 → 1.55.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 +35 -26
- package/compat.js +13 -2
- package/error-runtime.d.ts +7 -0
- package/error-runtime.js +10 -1
- package/error-runtime.mjs +1 -1
- package/lib/aot-impl.js +26 -3
- 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 +9 -4
- package/lib/formats-source.js +50 -66
- package/lib/formats.js +37 -231
- package/lib/interpreter-compat.js +144 -0
- package/lib/interpreter-core.js +55 -144
- 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 +113 -33
- 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/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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"description": "JSON Schema validator that compiles to plain JavaScript, still runs where code generation is blocked, and can be compiled away at build time. Passes the full official test suite.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "index.js",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"rebuild": "cmake-js rebuild --target ata",
|
|
89
89
|
"test": "node tests/run.js",
|
|
90
90
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
91
|
-
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1 && node tests/run_suite.js draft6 && node tests/run_suite.js draft2019-09",
|
|
91
|
+
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1 && node tests/run_suite.js draft6 && node tests/run_suite.js draft2019-09 && node tests/run_suite.js draft4",
|
|
92
92
|
"test:compat": "node tests/test_compat.js",
|
|
93
93
|
"test:standard-schema": "node tests/test_standard_schema.js",
|
|
94
94
|
"test:browser": "node tests/test_browser.js",
|
|
@@ -174,13 +174,13 @@
|
|
|
174
174
|
"LICENSE"
|
|
175
175
|
],
|
|
176
176
|
"optionalDependencies": {
|
|
177
|
-
"@ata-validator/native-darwin-arm64": "1.
|
|
178
|
-
"@ata-validator/native-darwin-x64": "1.
|
|
179
|
-
"@ata-validator/native-linux-arm64-gnu": "1.
|
|
180
|
-
"@ata-validator/native-linux-arm64-musl": "1.
|
|
181
|
-
"@ata-validator/native-linux-x64-gnu": "1.
|
|
182
|
-
"@ata-validator/native-linux-x64-musl": "1.
|
|
183
|
-
"@ata-validator/native-win32-x64": "1.
|
|
177
|
+
"@ata-validator/native-darwin-arm64": "1.55.0",
|
|
178
|
+
"@ata-validator/native-darwin-x64": "1.55.0",
|
|
179
|
+
"@ata-validator/native-linux-arm64-gnu": "1.55.0",
|
|
180
|
+
"@ata-validator/native-linux-arm64-musl": "1.55.0",
|
|
181
|
+
"@ata-validator/native-linux-x64-gnu": "1.55.0",
|
|
182
|
+
"@ata-validator/native-linux-x64-musl": "1.55.0",
|
|
183
|
+
"@ata-validator/native-win32-x64": "1.55.0"
|
|
184
184
|
},
|
|
185
185
|
"peerDependencies": {
|
|
186
186
|
"yaml": "^2.0.0"
|