ata-validator 1.50.0 → 1.52.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 +26 -20
- package/aot.d.ts +11 -1
- package/aot.mjs +1 -1
- package/bin/ata.js +21 -0
- package/index.bundle.mjs +15 -0
- package/lib/aot-build.js +183 -9
- package/lib/aot-impl.js +49 -16
- package/lib/combined-runtime.js +4 -1
- package/lib/error-runtime.js +5 -1
- package/lib/js-compiler-errors.js +15 -15
- package/lib/js-compiler.js +193 -44
- package/lib/safe-regex.js +33 -14
- package/lib/schema-order.js +64 -2
- package/lib/schema-runtime-entry.js +25 -1
- package/lib/validator-core.js +3 -0
- package/lib/version.js +1 -1
- package/package.json +10 -8
package/lib/schema-order.js
CHANGED
|
@@ -57,17 +57,53 @@ function rankFor(rootSchema, schemaPath) {
|
|
|
57
57
|
return rank;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// The documents a root's references reach beyond itself, id to schema, from
|
|
61
|
+
// the validators that own the root (the `schemas` option, addSchema) or a
|
|
62
|
+
// schema module's registry. Several validators of one root schema register
|
|
63
|
+
// their maps into one; an id that two of them give different schemas makes the
|
|
64
|
+
// root resolve nothing outside itself, as it did before any was registered.
|
|
65
|
+
const _documents = new WeakMap();
|
|
66
|
+
const CONFLICT = new Map();
|
|
67
|
+
function registerDocuments(rootSchema, map) {
|
|
68
|
+
if (rootSchema === null || typeof rootSchema !== 'object' || !map || map.size === 0) return;
|
|
69
|
+
const had = _documents.get(rootSchema);
|
|
70
|
+
if (had === CONFLICT) return;
|
|
71
|
+
if (had === undefined) { _documents.set(rootSchema, new Map(map)); _rankCache.delete(rootSchema); return; }
|
|
72
|
+
let added = false;
|
|
73
|
+
for (const [id, doc] of map) {
|
|
74
|
+
const cur = had.get(id);
|
|
75
|
+
if (cur === undefined) { had.set(id, doc); added = true; } else if (cur !== doc) { _documents.set(rootSchema, CONFLICT); _rankCache.delete(rootSchema); return; }
|
|
76
|
+
}
|
|
77
|
+
if (added) _rankCache.delete(rootSchema);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function withoutEmptyFragment(uri) {
|
|
81
|
+
return uri.endsWith('#') ? uri.slice(0, -1) : uri;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function resolveUri(ref, base) {
|
|
85
|
+
try { return base ? new URL(ref, base).href : new URL(ref).href; } catch { return null; }
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
function computeRank(rootSchema, schemaPath) {
|
|
61
89
|
const rank = [];
|
|
62
90
|
let node = rootSchema;
|
|
63
91
|
let start = 1;
|
|
64
92
|
let hops = 0;
|
|
93
|
+
const docs = _documents.get(rootSchema);
|
|
94
|
+
// The document the walk is in and the base URI references resolve against,
|
|
95
|
+
// for following a reference into another document.
|
|
96
|
+
let doc = rootSchema;
|
|
97
|
+
// A root without an $id can still name another document by absolute URI.
|
|
98
|
+
const follow = docs !== undefined && docs !== CONFLICT;
|
|
99
|
+
let base = follow && typeof rootSchema.$id === 'string' ? resolveUri(rootSchema.$id, null) : null;
|
|
65
100
|
while (start <= schemaPath.length) {
|
|
66
101
|
let end = schemaPath.indexOf('/', start);
|
|
67
102
|
if (end < 0) end = schemaPath.length;
|
|
68
103
|
if (end === start) { start = end + 1; continue; }
|
|
69
104
|
const seg = unescapePointerSegment(schemaPath.slice(start, end));
|
|
70
105
|
if (node == null || typeof node !== 'object') break;
|
|
106
|
+
if (follow && node !== doc && !Array.isArray(node) && typeof node.$id === 'string' && node.$id[0] !== '#') base = resolveUri(node.$id, base);
|
|
71
107
|
if (Array.isArray(node)) {
|
|
72
108
|
const idx = Number(seg);
|
|
73
109
|
if (!Number.isInteger(idx) || idx < 0 || idx >= node.length) break;
|
|
@@ -80,7 +116,11 @@ function computeRank(rootSchema, schemaPath) {
|
|
|
80
116
|
// naming it. Ranking the rest inside the target, as if the target sat
|
|
81
117
|
// under the `$ref` key, orders errors behind a reference by the
|
|
82
118
|
// target's declaration order, as they are ordered inline.
|
|
83
|
-
|
|
119
|
+
let target = hops < 64 ? localTarget(doc, node) : null;
|
|
120
|
+
if (target === null && hops < 64 && follow) {
|
|
121
|
+
const remote = remoteTarget(docs, base, node);
|
|
122
|
+
if (remote !== null) { target = remote.node; doc = remote.doc; base = remote.base; }
|
|
123
|
+
}
|
|
84
124
|
if (target === null) break;
|
|
85
125
|
hops++;
|
|
86
126
|
rank.push(keyIndex(node, '$ref'));
|
|
@@ -95,6 +135,28 @@ function computeRank(rootSchema, schemaPath) {
|
|
|
95
135
|
return rank;
|
|
96
136
|
}
|
|
97
137
|
|
|
138
|
+
// The schema a node's `$ref` names in a registered document: { node, doc,
|
|
139
|
+
// base }, or null when it names none (an anchor, an unknown document).
|
|
140
|
+
function remoteTarget(docs, base, node) {
|
|
141
|
+
const ref = node.$ref;
|
|
142
|
+
if (typeof ref !== 'string' || ref.charCodeAt(0) === 35) return null;
|
|
143
|
+
const abs = resolveUri(ref, base);
|
|
144
|
+
if (abs === null) return null;
|
|
145
|
+
const hash = abs.indexOf('#');
|
|
146
|
+
const uri = hash < 0 ? abs : abs.slice(0, hash);
|
|
147
|
+
let target = docs.get(uri);
|
|
148
|
+
if (target === undefined) target = docs.get(uri + '#');
|
|
149
|
+
if (target === undefined) {
|
|
150
|
+
for (const [id, s] of docs) if (withoutEmptyFragment(resolveUri(id, null) || '') === uri) { target = s; break; }
|
|
151
|
+
}
|
|
152
|
+
if (target === null || typeof target !== 'object') return null;
|
|
153
|
+
const frag = hash < 0 ? '' : abs.slice(hash + 1);
|
|
154
|
+
if (frag === '') return { node: target, doc: target, base: uri };
|
|
155
|
+
if (frag.charCodeAt(0) !== 47) return null;
|
|
156
|
+
const t = localTarget(target, { $ref: '#' + frag });
|
|
157
|
+
return t === null ? null : { node: t, doc: target, base: uri };
|
|
158
|
+
}
|
|
159
|
+
|
|
98
160
|
// The schema a node's `$ref` names, when it is a pointer into this document.
|
|
99
161
|
function localTarget(rootSchema, node) {
|
|
100
162
|
const ref = node.$ref;
|
|
@@ -191,4 +253,4 @@ function ordinalFor(rootSchema, schemaPath) {
|
|
|
191
253
|
const _missCache = new WeakMap();
|
|
192
254
|
const MISS_CACHE_LIMIT = 4096;
|
|
193
255
|
|
|
194
|
-
module.exports = { rankFor, ordinalFor, unescapePointerSegment };
|
|
256
|
+
module.exports = { rankFor, ordinalFor, unescapePointerSegment, registerDocuments };
|
|
@@ -10,8 +10,32 @@
|
|
|
10
10
|
const { createInterpreter } = require('./interpreter');
|
|
11
11
|
const { errorsOf, interpreterOptions } = require('./error-runtime-entry');
|
|
12
12
|
|
|
13
|
+
// A registry is the array of schemas a build writes beside schema modules
|
|
14
|
+
// whose schemas reference each other by `$id` (ata-registry.mjs). It becomes
|
|
15
|
+
// one Map, id to schema, shared by every module of the build.
|
|
16
|
+
const _maps = new WeakMap();
|
|
17
|
+
function registryMap(registry) {
|
|
18
|
+
let map = _maps.get(registry);
|
|
19
|
+
if (map === undefined) {
|
|
20
|
+
map = new Map();
|
|
21
|
+
for (const s of registry) map.set(s.$id, s);
|
|
22
|
+
_maps.set(registry, map);
|
|
23
|
+
}
|
|
24
|
+
return map;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// options.registry and options.id: the module's schema is the registry entry
|
|
28
|
+
// with that `$id`, and its references resolve against the registry.
|
|
13
29
|
function createValidator(schema, codeOf, options) {
|
|
14
|
-
const
|
|
30
|
+
const opts = interpreterOptions(options);
|
|
31
|
+
if (options && options.registry) {
|
|
32
|
+
const map = registryMap(options.registry);
|
|
33
|
+
if (schema === null || schema === undefined) schema = map.get(options.id);
|
|
34
|
+
opts.schemaMap = map;
|
|
35
|
+
opts.flat = false;
|
|
36
|
+
require('./schema-order').registerDocuments(schema, map);
|
|
37
|
+
}
|
|
38
|
+
const interp = createInterpreter(schema, opts);
|
|
15
39
|
return {
|
|
16
40
|
isValid: (data) => interp.isValid(data),
|
|
17
41
|
errors: (data) => errorsOf(interp, schema, codeOf, data),
|
package/lib/validator-core.js
CHANGED
|
@@ -864,6 +864,9 @@ class Validator {
|
|
|
864
864
|
if (this._initialized) return;
|
|
865
865
|
this._ensureVocabularies();
|
|
866
866
|
this._initialized = true;
|
|
867
|
+
// Errors behind a reference into a registered document are ordered as
|
|
868
|
+
// they would be inline: the ordering follows the reference there.
|
|
869
|
+
if (this._schemaMap && this._schemaMap.size > 0) require('./schema-order').registerDocuments(this._schemaObj, this._schemaMap);
|
|
867
870
|
|
|
868
871
|
const schemaObj = this._schemaObj;
|
|
869
872
|
const options = this._options;
|
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.52.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",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"require": "./index.js"
|
|
25
25
|
},
|
|
26
26
|
"import": {
|
|
27
|
+
"module": "./index.bundle.mjs",
|
|
27
28
|
"module-sync": "./index.node.mjs",
|
|
28
29
|
"default": "./index.mjs"
|
|
29
30
|
},
|
|
@@ -137,6 +138,7 @@
|
|
|
137
138
|
"index.js",
|
|
138
139
|
"index.mjs",
|
|
139
140
|
"index.node.mjs",
|
|
141
|
+
"index.bundle.mjs",
|
|
140
142
|
"index.browser.mjs",
|
|
141
143
|
"index.edge.js",
|
|
142
144
|
"index.edge.mjs",
|
|
@@ -172,13 +174,13 @@
|
|
|
172
174
|
"LICENSE"
|
|
173
175
|
],
|
|
174
176
|
"optionalDependencies": {
|
|
175
|
-
"@ata-validator/native-darwin-arm64": "1.
|
|
176
|
-
"@ata-validator/native-darwin-x64": "1.
|
|
177
|
-
"@ata-validator/native-linux-arm64-gnu": "1.
|
|
178
|
-
"@ata-validator/native-linux-arm64-musl": "1.
|
|
179
|
-
"@ata-validator/native-linux-x64-gnu": "1.
|
|
180
|
-
"@ata-validator/native-linux-x64-musl": "1.
|
|
181
|
-
"@ata-validator/native-win32-x64": "1.
|
|
177
|
+
"@ata-validator/native-darwin-arm64": "1.52.0",
|
|
178
|
+
"@ata-validator/native-darwin-x64": "1.52.0",
|
|
179
|
+
"@ata-validator/native-linux-arm64-gnu": "1.52.0",
|
|
180
|
+
"@ata-validator/native-linux-arm64-musl": "1.52.0",
|
|
181
|
+
"@ata-validator/native-linux-x64-gnu": "1.52.0",
|
|
182
|
+
"@ata-validator/native-linux-x64-musl": "1.52.0",
|
|
183
|
+
"@ata-validator/native-win32-x64": "1.52.0"
|
|
182
184
|
},
|
|
183
185
|
"peerDependencies": {
|
|
184
186
|
"yaml": "^2.0.0"
|