ata-validator 1.62.1 → 1.63.1
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 +63 -8
- package/build.mjs +1 -0
- package/index.browser.mjs +23 -4
- package/index.bundle.mjs +14 -4
- package/index.edge.mjs +14 -4
- package/index.js +7 -2
- package/lib/aot-build.js +18 -0
- package/lib/codegen-engine.js +72 -3
- package/lib/compiled-common.js +2 -1
- package/lib/email-literal.js +4 -1
- package/lib/formats-source.js +39 -40
- package/lib/interpreter-core.js +148 -70
- package/lib/ir/emit-deps.mjs +131 -0
- package/lib/ir/emit.mjs +707 -0
- package/lib/ir/front.mjs +865 -0
- package/lib/ir/index.mjs +10 -0
- package/lib/ir/refs.mjs +108 -0
- package/lib/ir/run.mjs +520 -0
- package/lib/ir/table.mjs +233 -0
- package/lib/js-compiler-errors.js +9 -4
- package/lib/kernels/collapse.mjs +114 -0
- package/lib/kernels/custom.mjs +70 -0
- package/lib/kernels/fill.mjs +6 -0
- package/lib/kernels/formats-small.mjs +40 -0
- package/lib/kernels/formats.mjs +29 -0
- package/lib/kernels/index.mjs +11 -0
- package/lib/kernels/kernels.mjs +285 -0
- package/lib/kernels/leaves.mjs +28 -0
- package/lib/kernels/order.mjs +25 -0
- package/lib/kernels/plan-rich.mjs +17 -0
- package/lib/kernels/plan.d.ts +9 -0
- package/lib/kernels/plan.mjs +128 -0
- package/lib/kernels/preprocess.mjs +223 -0
- package/lib/kernels/rank.mjs +97 -0
- package/lib/kernels/rt.mjs +249 -0
- package/lib/kernels/table.mjs +182 -0
- package/lib/kernels/unique.mjs +157 -0
- package/lib/native-positions.js +1 -1
- package/lib/openapi.d.ts +2 -0
- package/lib/openapi.js +128 -0
- package/lib/plan-compiler.js +113 -14
- package/lib/public-api.js +7 -2
- package/lib/rejections.js +3 -1
- package/lib/schema-helpers.js +12 -0
- package/lib/schema-helpers.mjs +20 -0
- package/lib/schema-order.js +4 -2
- package/lib/shape-classifier.js +13 -1
- package/lib/standard-schema.js +1 -1
- package/lib/tier0.js +38 -8
- package/lib/validator-core.js +59 -36
- package/lib/version.js +1 -1
- package/lite.js +7 -2
- package/package.json +26 -8
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Generated by scripts/gen-kernels-preprocess.js from lib/validator-core.js. Do not edit.
|
|
2
|
+
const _hasOwn = Object.prototype.hasOwnProperty;
|
|
3
|
+
function buildCoercer(schema, arrayMode) {
|
|
4
|
+
if (typeof schema !== "object" || schema === null) return null;
|
|
5
|
+
const node = buildNodeCoercer(schema, new Set(), arrayMode === true);
|
|
6
|
+
if (node === null) return null;
|
|
7
|
+
return (data) => { if (typeof data === "object" && data !== null) node(data); };
|
|
8
|
+
}
|
|
9
|
+
function coercionFor(schema, seen) {
|
|
10
|
+
if (!schema || typeof schema !== "object") return null;
|
|
11
|
+
const scalar = schema.type && !Array.isArray(schema.type) ? buildSingleCoercion(schema.type) : null;
|
|
12
|
+
const inner = buildNodeCoercer(schema, seen);
|
|
13
|
+
return scalar || inner ? { scalar, inner } : null;
|
|
14
|
+
}
|
|
15
|
+
function buildNodeCoercer(schema, seen, arrayMode) {
|
|
16
|
+
if (seen.has(schema)) return null;
|
|
17
|
+
seen.add(schema);
|
|
18
|
+
const steps = [];
|
|
19
|
+
if (schema.properties) {
|
|
20
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
21
|
+
if (key === "__proto__") continue;
|
|
22
|
+
const wrap = arrayMode === true && prop && prop.type === "array";
|
|
23
|
+
const c = coercionFor(prop, seen);
|
|
24
|
+
if (!c && !wrap) continue;
|
|
25
|
+
const { scalar, inner } = c || {};
|
|
26
|
+
steps.push((o) => {
|
|
27
|
+
if (!_hasOwn.call(o, key)) return;
|
|
28
|
+
if (wrap && o[key] !== undefined && !Array.isArray(o[key])) o[key] = [o[key]];
|
|
29
|
+
if (scalar) {
|
|
30
|
+
const v = scalar(o[key]);
|
|
31
|
+
if (v !== undefined) o[key] = v;
|
|
32
|
+
}
|
|
33
|
+
if (inner) {
|
|
34
|
+
const x = o[key];
|
|
35
|
+
if (typeof x === "object" && x !== null) inner(x);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
41
|
+
const c = coercionFor(schema.items, seen);
|
|
42
|
+
if (c) {
|
|
43
|
+
const { scalar, inner } = c;
|
|
44
|
+
steps.push((o) => {
|
|
45
|
+
if (!Array.isArray(o)) return;
|
|
46
|
+
for (let i = 0; i < o.length; i++) {
|
|
47
|
+
if (scalar) {
|
|
48
|
+
const v = scalar(o[i]);
|
|
49
|
+
if (v !== undefined) o[i] = v;
|
|
50
|
+
}
|
|
51
|
+
if (inner) {
|
|
52
|
+
const x = o[i];
|
|
53
|
+
if (typeof x === "object" && x !== null) inner(x);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
seen.delete(schema);
|
|
60
|
+
if (steps.length === 0) return null;
|
|
61
|
+
if (steps.length === 1) return steps[0];
|
|
62
|
+
return (o) => { for (let i = 0; i < steps.length; i++) steps[i](o); };
|
|
63
|
+
}
|
|
64
|
+
function buildSingleCoercion(targetType) {
|
|
65
|
+
switch (targetType) {
|
|
66
|
+
case "number":
|
|
67
|
+
return (v) => {
|
|
68
|
+
if (typeof v === "string") {
|
|
69
|
+
const n = Number(v);
|
|
70
|
+
if (v !== "" && !isNaN(n)) return n;
|
|
71
|
+
}
|
|
72
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
73
|
+
};
|
|
74
|
+
case "integer":
|
|
75
|
+
return (v) => {
|
|
76
|
+
if (typeof v === "string") {
|
|
77
|
+
const n = Number(v);
|
|
78
|
+
if (v !== "" && Number.isInteger(n)) return n;
|
|
79
|
+
}
|
|
80
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
81
|
+
};
|
|
82
|
+
case "string":
|
|
83
|
+
return (v) => {
|
|
84
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
85
|
+
};
|
|
86
|
+
case "boolean":
|
|
87
|
+
return (v) => {
|
|
88
|
+
if (v === "true" || v === "1") return true;
|
|
89
|
+
if (v === "false" || v === "0") return false;
|
|
90
|
+
};
|
|
91
|
+
default:
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function buildRemover(schema) {
|
|
96
|
+
if (typeof schema !== "object" || schema === null) return null;
|
|
97
|
+
const actions = [];
|
|
98
|
+
collectRemovals(schema, actions);
|
|
99
|
+
if (actions.length === 0) return null;
|
|
100
|
+
return (data) => {
|
|
101
|
+
for (let i = 0; i < actions.length; i++) actions[i](data);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function collectRemovals(schema, actions, path) {
|
|
105
|
+
if (typeof schema !== "object" || schema === null || !schema.properties)
|
|
106
|
+
return;
|
|
107
|
+
if (schema.additionalProperties === false) {
|
|
108
|
+
const allowed = new Set(Object.keys(schema.properties));
|
|
109
|
+
if (!path) {
|
|
110
|
+
actions.push((data) => {
|
|
111
|
+
if (typeof data !== "object" || data === null || Array.isArray(data))
|
|
112
|
+
return;
|
|
113
|
+
const keys = Object.keys(data);
|
|
114
|
+
for (let i = 0; i < keys.length; i++) {
|
|
115
|
+
if (!allowed.has(keys[i])) delete data[keys[i]];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
const parentPath = path;
|
|
120
|
+
actions.push((data) => {
|
|
121
|
+
let target = data;
|
|
122
|
+
for (let j = 0; j < parentPath.length; j++) {
|
|
123
|
+
if (typeof target !== "object" || target === null || !_hasOwn.call(target, parentPath[j])) return;
|
|
124
|
+
target = target[parentPath[j]];
|
|
125
|
+
}
|
|
126
|
+
if (
|
|
127
|
+
typeof target !== "object" ||
|
|
128
|
+
target === null ||
|
|
129
|
+
Array.isArray(target)
|
|
130
|
+
)
|
|
131
|
+
return;
|
|
132
|
+
const keys = Object.keys(target);
|
|
133
|
+
for (let i = 0; i < keys.length; i++) {
|
|
134
|
+
if (!allowed.has(keys[i])) delete target[keys[i]];
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
140
|
+
if (prop && typeof prop === "object" && prop.properties) {
|
|
141
|
+
collectRemovals(prop, actions, (path || []).concat(key));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function resolveRefForPreprocess(ref, schemaMap) {
|
|
146
|
+
if (!schemaMap || schemaMap.size === 0 || typeof ref !== 'string') return null
|
|
147
|
+
const hashIdx = ref.indexOf('#')
|
|
148
|
+
const baseId = hashIdx >= 0 ? ref.slice(0, hashIdx) : ref
|
|
149
|
+
const fragment = hashIdx >= 0 ? ref.slice(hashIdx + 1) : ''
|
|
150
|
+
if (!baseId) return null
|
|
151
|
+
let base = null
|
|
152
|
+
if (schemaMap.has(baseId)) base = schemaMap.get(baseId)
|
|
153
|
+
else if (!ref.includes('://')) {
|
|
154
|
+
for (const [id, s] of schemaMap) {
|
|
155
|
+
if (id.endsWith('/' + baseId)) { base = s; break }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!base) return null
|
|
159
|
+
if (!fragment) return base
|
|
160
|
+
let target = base
|
|
161
|
+
for (const part of fragment.split('/')) {
|
|
162
|
+
if (part === '') continue
|
|
163
|
+
if (target == null || typeof target !== 'object') return null
|
|
164
|
+
target = target[part.replace(/~1/g, '/').replace(/~0/g, '~')]
|
|
165
|
+
}
|
|
166
|
+
return target == null ? null : target
|
|
167
|
+
}
|
|
168
|
+
function resolveSchemaForPreprocess(schema, schemaMap) {
|
|
169
|
+
if (!schema || typeof schema !== 'object' || !schemaMap || schemaMap.size === 0) return schema
|
|
170
|
+
let s = schema
|
|
171
|
+
if (s.$ref && !s.properties) {
|
|
172
|
+
const t = resolveRefForPreprocess(s.$ref, schemaMap)
|
|
173
|
+
if (t && typeof t === 'object') s = t
|
|
174
|
+
}
|
|
175
|
+
if (!s.properties) return s
|
|
176
|
+
let cloned = null
|
|
177
|
+
for (const key of Object.keys(s.properties)) {
|
|
178
|
+
const p = s.properties[key]
|
|
179
|
+
if (p && typeof p === 'object' && p.$ref && !p.type) {
|
|
180
|
+
const t = resolveRefForPreprocess(p.$ref, schemaMap)
|
|
181
|
+
if (t && typeof t === 'object') {
|
|
182
|
+
if (!cloned) { cloned = { ...s }; cloned.properties = { ...s.properties } }
|
|
183
|
+
Object.defineProperty(cloned.properties, key, { value: t, writable: true, enumerable: true, configurable: true })
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return cloned || s
|
|
188
|
+
}
|
|
189
|
+
function resolveSchemaByPath(rootSchema, schemaPath) {
|
|
190
|
+
if (!schemaPath || typeof schemaPath !== 'string' || !schemaPath.startsWith('#')) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
const stripped = schemaPath.slice(1);
|
|
194
|
+
if (!stripped || stripped === '/') return rootSchema;
|
|
195
|
+
const parts = stripped.split('/').filter(Boolean).map(s => s.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
196
|
+
let target = rootSchema;
|
|
197
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
198
|
+
if (target == null || typeof target !== 'object') return undefined;
|
|
199
|
+
target = target[parts[i]];
|
|
200
|
+
}
|
|
201
|
+
return target;
|
|
202
|
+
}
|
|
203
|
+
const COLLAPSE_CODES = new Set(['ATA4001', 'ATA4002', 'ATA4003']);
|
|
204
|
+
function stripOrdinal(e) {
|
|
205
|
+
if (e === null || typeof e !== 'object') return e;
|
|
206
|
+
if (e._s === true && e.code === undefined && e.docUrl === undefined && e.branchErrors === undefined) {
|
|
207
|
+
return { keyword: e.keyword, instancePath: e.instancePath, schemaPath: e.schemaPath, params: e.params, message: e.message };
|
|
208
|
+
}
|
|
209
|
+
if (e.path !== undefined && e.docUrl === undefined && COLLAPSE_CODES.has(e.code) && !('parentSchema' in e)) {
|
|
210
|
+
const out = { code: e.code, keyword: e.keyword, instancePath: e.instancePath, path: e.path, schemaPath: e.schemaPath, message: e.message, params: e.params };
|
|
211
|
+
if ('branchErrors' in e) out.branchErrors = Array.isArray(e.branchErrors) ? e.branchErrors.map(stripOrdinal) : e.branchErrors;
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
if (e._o === undefined && e.docUrl === undefined && (e.code === undefined || COLLAPSE_CODES.has(e.code)) && !e.branchErrors) return e._s === true ? { ...e } : e;
|
|
215
|
+
const out = {};
|
|
216
|
+
for (const k in e) {
|
|
217
|
+
if (k === '_o' || k === 'docUrl') continue;
|
|
218
|
+
if (k === 'code' && !COLLAPSE_CODES.has(e.code)) continue;
|
|
219
|
+
out[k] = k === 'branchErrors' && Array.isArray(e[k]) ? e[k].map(stripOrdinal) : e[k];
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
export { buildCoercer, buildRemover, resolveSchemaForPreprocess, resolveSchemaByPath, stripOrdinal };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Generated by scripts/gen-kernels-rank.js from lib/schema-order.js. Do not edit.
|
|
2
|
+
const _keyIndexCache = new WeakMap();
|
|
3
|
+
const _rankCache = new WeakMap();
|
|
4
|
+
const _documents = new WeakMap();
|
|
5
|
+
const CONFLICT = null;
|
|
6
|
+
const remoteTarget = () => null;
|
|
7
|
+
function keyIndex(node, seg) {
|
|
8
|
+
let index = _keyIndexCache.get(node);
|
|
9
|
+
if (index === undefined) {
|
|
10
|
+
index = new Map();
|
|
11
|
+
const keys = Object.keys(node);
|
|
12
|
+
for (let i = 0; i < keys.length; i++) index.set(keys[i], i);
|
|
13
|
+
_keyIndexCache.set(node, index);
|
|
14
|
+
}
|
|
15
|
+
const at = index.get(seg);
|
|
16
|
+
return at === undefined ? -1 : at;
|
|
17
|
+
}
|
|
18
|
+
function unescapePointerSegment(seg) {
|
|
19
|
+
return seg.indexOf('~') < 0 ? seg : seg.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
20
|
+
}
|
|
21
|
+
function rankFor(rootSchema, schemaPath) {
|
|
22
|
+
if (!schemaPath || typeof schemaPath !== 'string' || !schemaPath.startsWith('#')) return null;
|
|
23
|
+
if (rootSchema === null || typeof rootSchema !== 'object') return null;
|
|
24
|
+
let byPath = _rankCache.get(rootSchema);
|
|
25
|
+
if (byPath === undefined) { byPath = new Map(); _rankCache.set(rootSchema, byPath); }
|
|
26
|
+
const hit = byPath.get(schemaPath);
|
|
27
|
+
if (hit !== undefined) return hit;
|
|
28
|
+
const rank = computeRank(rootSchema, schemaPath);
|
|
29
|
+
byPath.set(schemaPath, rank);
|
|
30
|
+
return rank;
|
|
31
|
+
}
|
|
32
|
+
function computeRank(rootSchema, schemaPath) {
|
|
33
|
+
const rank = [];
|
|
34
|
+
let node = rootSchema;
|
|
35
|
+
let start = 1;
|
|
36
|
+
let hops = 0;
|
|
37
|
+
const docs = _documents.get(rootSchema);
|
|
38
|
+
let doc = rootSchema;
|
|
39
|
+
const follow = docs !== undefined && docs !== CONFLICT;
|
|
40
|
+
let base = follow && typeof rootSchema.$id === 'string' ? resolveUri(rootSchema.$id, null) : null;
|
|
41
|
+
while (start <= schemaPath.length) {
|
|
42
|
+
let end = schemaPath.indexOf('/', start);
|
|
43
|
+
if (end < 0) end = schemaPath.length;
|
|
44
|
+
if (end === start) { start = end + 1; continue; }
|
|
45
|
+
const seg = unescapePointerSegment(schemaPath.slice(start, end));
|
|
46
|
+
if (node == null || typeof node !== 'object') break;
|
|
47
|
+
if (follow && node !== doc && !Array.isArray(node) && typeof node.$id === 'string' && node.$id[0] !== '#') base = resolveUri(node.$id, base);
|
|
48
|
+
if (Array.isArray(node)) {
|
|
49
|
+
const idx = Number(seg);
|
|
50
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= node.length) break;
|
|
51
|
+
rank.push(idx);
|
|
52
|
+
node = node[idx];
|
|
53
|
+
} else {
|
|
54
|
+
const idx = keyIndex(node, seg);
|
|
55
|
+
if (idx < 0) {
|
|
56
|
+
let target = hops < 64 ? localTarget(doc, node) : null;
|
|
57
|
+
if (target === null && hops < 64 && follow) {
|
|
58
|
+
const remote = remoteTarget(docs, base, node);
|
|
59
|
+
if (remote !== null) { target = remote.node; doc = remote.doc; base = remote.base; }
|
|
60
|
+
}
|
|
61
|
+
if (target === null) break;
|
|
62
|
+
hops++;
|
|
63
|
+
rank.push(keyIndex(node, '$ref'));
|
|
64
|
+
node = target;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
rank.push(idx);
|
|
68
|
+
node = node[seg];
|
|
69
|
+
}
|
|
70
|
+
start = end + 1;
|
|
71
|
+
}
|
|
72
|
+
return rank;
|
|
73
|
+
}
|
|
74
|
+
function localTarget(rootSchema, node) {
|
|
75
|
+
const ref = node.$ref;
|
|
76
|
+
if (typeof ref !== 'string' || ref.charCodeAt(0) !== 35) return null;
|
|
77
|
+
if (ref.length > 1 && ref.charCodeAt(1) !== 47) return null;
|
|
78
|
+
let t = rootSchema;
|
|
79
|
+
let start = 2;
|
|
80
|
+
while (start <= ref.length && ref.length > 1) {
|
|
81
|
+
let end = ref.indexOf('/', start);
|
|
82
|
+
if (end < 0) end = ref.length;
|
|
83
|
+
let seg = ref.slice(start, end);
|
|
84
|
+
if (seg.indexOf('%') >= 0) { try { seg = decodeURIComponent(seg); } catch { return null; } }
|
|
85
|
+
seg = unescapePointerSegment(seg);
|
|
86
|
+
if (t === null || typeof t !== 'object') return null;
|
|
87
|
+
if (!Object.prototype.hasOwnProperty.call(t, seg)) {
|
|
88
|
+
const alias = seg === 'definitions' ? '$defs' : seg === '$defs' ? 'definitions' : null;
|
|
89
|
+
if (alias === null || !Object.prototype.hasOwnProperty.call(t, alias)) return null;
|
|
90
|
+
seg = alias;
|
|
91
|
+
}
|
|
92
|
+
t = t[seg];
|
|
93
|
+
start = end + 1;
|
|
94
|
+
}
|
|
95
|
+
return t !== null && typeof t === 'object' && t !== node ? t : null;
|
|
96
|
+
}
|
|
97
|
+
export { rankFor };
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// the helpers every keyword kernel shares, one export each so a bundle
|
|
2
|
+
// keeps only what its kernels call. Each mirrors the function named beside it
|
|
3
|
+
// in lib/, output for output; tests/test_ir_differential.mjs holds them to
|
|
4
|
+
// the current engine.
|
|
5
|
+
|
|
6
|
+
const hop = Object.prototype.hasOwnProperty
|
|
7
|
+
export const own = (o, k) => hop.call(o, k)
|
|
8
|
+
export const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
|
|
9
|
+
|
|
10
|
+
// lib/js-compiler.js _cpLen: code points, a lone surrogate counting as one.
|
|
11
|
+
export function cpLen (s) {
|
|
12
|
+
const n = s.length
|
|
13
|
+
for (let i = 0; i < n; i++) {
|
|
14
|
+
if (((s.charCodeAt(i) - 0xD800) >>> 0) < 0x800) { let c = 0; for (const _ of s) c++; return c }
|
|
15
|
+
}
|
|
16
|
+
return n
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// lib/enrich-error.js jsonSizeWithin and reprValue, without the per-run count
|
|
20
|
+
// cache, which changes the time a wide object takes and not the text.
|
|
21
|
+
function sizeWithin (v, b) {
|
|
22
|
+
if (b < 0) return -1
|
|
23
|
+
if (v === null) return 4
|
|
24
|
+
const t = typeof v
|
|
25
|
+
if (t === 'number') return Number.isFinite(v) ? String(v).length : 4
|
|
26
|
+
if (t === 'boolean') return v ? 4 : 5
|
|
27
|
+
if (t === 'string') return v.length + 2 > b ? -1 : v.length + 2
|
|
28
|
+
if (t !== 'object') return -1
|
|
29
|
+
if (typeof v.toJSON === 'function') return 2
|
|
30
|
+
let n = 2
|
|
31
|
+
if (Array.isArray(v)) {
|
|
32
|
+
for (let i = 0; i < v.length; i++) {
|
|
33
|
+
n += i === 0 ? 0 : 1
|
|
34
|
+
if (n > b) return -1
|
|
35
|
+
const c = sizeWithin(v[i], b - n)
|
|
36
|
+
if (c < 0 || (n += c) > b) return -1
|
|
37
|
+
}
|
|
38
|
+
return n
|
|
39
|
+
}
|
|
40
|
+
const p = Object.getPrototypeOf(v)
|
|
41
|
+
if (p !== Object.prototype && p !== null) return -1
|
|
42
|
+
let first = true
|
|
43
|
+
for (const k in v) {
|
|
44
|
+
const x = v[k]
|
|
45
|
+
if (x === undefined || typeof x === 'function' || typeof x === 'symbol') continue
|
|
46
|
+
n += k.length + 3 + (first ? 0 : 1)
|
|
47
|
+
if (n > b) return -1
|
|
48
|
+
first = false
|
|
49
|
+
const c = sizeWithin(x, b - n)
|
|
50
|
+
if (c < 0 || (n += c) > b) return -1
|
|
51
|
+
}
|
|
52
|
+
return n
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function repr (v) {
|
|
56
|
+
if (v === undefined) return 'undefined'
|
|
57
|
+
if (v === null) return 'null'
|
|
58
|
+
const t = typeof v
|
|
59
|
+
if (t === 'string') { const s = JSON.stringify(v); return s.length > 60 ? s.slice(0, 57) + '..."' : s }
|
|
60
|
+
if (t === 'number' || t === 'boolean') return String(v)
|
|
61
|
+
if (Array.isArray(v)) return `[array, ${v.length} items]`
|
|
62
|
+
if (t === 'object') {
|
|
63
|
+
let n
|
|
64
|
+
try { n = Object.keys(v).length } catch { return '[object, unserializable]' }
|
|
65
|
+
if (n <= 12 && sizeWithin(v, 60) >= 0) {
|
|
66
|
+
try { const s = JSON.stringify(v); if (s !== undefined && s.length <= 60) return s } catch { return '[object, unserializable]' }
|
|
67
|
+
}
|
|
68
|
+
return `[object, ${n} ${n === 1 ? 'key' : 'keys'}]`
|
|
69
|
+
}
|
|
70
|
+
return `[${t}]`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The value an error names when the enrichment has none to show.
|
|
74
|
+
export const MISSING = Symbol('missing')
|
|
75
|
+
|
|
76
|
+
// lib/enrich-error.js typeNameOfValue, then typeNameOf on the repr.
|
|
77
|
+
export function typeName (v, received) {
|
|
78
|
+
if (v !== MISSING) {
|
|
79
|
+
if (v === null) return 'null'
|
|
80
|
+
switch (typeof v) {
|
|
81
|
+
case 'boolean': return 'boolean'
|
|
82
|
+
case 'string': return 'string'
|
|
83
|
+
case 'number': return Number.isFinite(v) ? 'number' : 'value'
|
|
84
|
+
case 'object': if (Array.isArray(v)) return 'array'; if (typeof v.toJSON !== 'function') return 'object'; break
|
|
85
|
+
default: return 'value'
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (received === undefined) return 'nothing'
|
|
89
|
+
if (received === 'null') return 'null'
|
|
90
|
+
if (received === 'true' || received === 'false') return 'boolean'
|
|
91
|
+
if (received.startsWith('"')) return 'string'
|
|
92
|
+
if (received.startsWith('[array')) return 'array'
|
|
93
|
+
if (received.startsWith('{') || received.startsWith('[object')) return 'object'
|
|
94
|
+
if (/^-?\d/.test(received)) return 'number'
|
|
95
|
+
return 'value'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// lib/levenshtein.js: optimal string alignment distance (a swap is one edit),
|
|
99
|
+
// bounded: past `max` the answer is Infinity. Only the cells within the bound
|
|
100
|
+
// of the diagonal are computed, on three rows of scratch reused across calls,
|
|
101
|
+
// reading characters by code: a full matrix of fresh arrays and one-character
|
|
102
|
+
// strings was 90% of a rejected document's time on a schema whose objects
|
|
103
|
+
// have many keys (codex-plugin-manifest).
|
|
104
|
+
let rowA = /* @__PURE__ */ new Int32Array(64); let rowB = /* @__PURE__ */ new Int32Array(64); let rowC = /* @__PURE__ */ new Int32Array(64)
|
|
105
|
+
export function osa (a, b, max) {
|
|
106
|
+
if (a === b) return 0
|
|
107
|
+
const n = a.length; const m = b.length
|
|
108
|
+
if (max === undefined || max > n + m) max = n + m
|
|
109
|
+
if (Math.abs(n - m) > max) return Infinity
|
|
110
|
+
if (n === 0) return m
|
|
111
|
+
if (m === 0) return n
|
|
112
|
+
const big = max + 1
|
|
113
|
+
if (rowA.length < m + 2) { rowA = new Int32Array(m + 2); rowB = new Int32Array(m + 2); rowC = new Int32Array(m + 2) }
|
|
114
|
+
let prev2 = rowC; let prev = rowA; let curr = rowB
|
|
115
|
+
for (let j = 0; j <= m; j++) prev[j] = j <= max ? j : big
|
|
116
|
+
for (let i = 1; i <= n; i++) {
|
|
117
|
+
const lo = i - max > 1 ? i - max : 1
|
|
118
|
+
const hi = i + max < m ? i + max : m
|
|
119
|
+
curr[lo - 1] = lo === 1 ? i : big
|
|
120
|
+
let rowMin = curr[lo - 1]
|
|
121
|
+
const ca = a.charCodeAt(i - 1)
|
|
122
|
+
const pa = i > 1 ? a.charCodeAt(i - 2) : -1
|
|
123
|
+
for (let j = lo; j <= hi; j++) {
|
|
124
|
+
const cb = b.charCodeAt(j - 1)
|
|
125
|
+
let v = prev[j - 1] + (ca === cb ? 0 : 1)
|
|
126
|
+
const del = curr[j - 1] + 1
|
|
127
|
+
if (del < v) v = del
|
|
128
|
+
const ins = prev[j] + 1
|
|
129
|
+
if (ins < v) v = ins
|
|
130
|
+
if (j > 1 && ca !== cb && ca === b.charCodeAt(j - 2) && pa === cb) {
|
|
131
|
+
const swap = prev2[j - 2] + 1
|
|
132
|
+
if (swap < v) v = swap
|
|
133
|
+
}
|
|
134
|
+
if (v > big) v = big
|
|
135
|
+
curr[j] = v
|
|
136
|
+
if (v < rowMin) rowMin = v
|
|
137
|
+
}
|
|
138
|
+
if (hi < m) curr[hi + 1] = big
|
|
139
|
+
if (rowMin > max) return Infinity
|
|
140
|
+
const t = prev2; prev2 = prev; prev = curr; curr = t
|
|
141
|
+
}
|
|
142
|
+
return prev[m] > max ? Infinity : prev[m]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// lib/suggestions.js nearest with its typo budget.
|
|
146
|
+
export function nearest (target, candidates) {
|
|
147
|
+
const n = target.length
|
|
148
|
+
const budget = n < 3 ? 0 : n < 5 ? 1 : 2
|
|
149
|
+
let best = null; let bestD = budget + 1; let tied = false
|
|
150
|
+
for (const c of candidates) {
|
|
151
|
+
if (typeof c !== 'string') continue
|
|
152
|
+
if (Math.abs(c.length - n) > budget) continue
|
|
153
|
+
const d = osa(target, c, budget)
|
|
154
|
+
if (d === 0 || d > budget) continue
|
|
155
|
+
if (d < bestD) { best = c; bestD = d; tied = false } else if (d === bestD) tied = true
|
|
156
|
+
}
|
|
157
|
+
return tied ? null : best
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const DOC = 'https://ata-validator.com/e/'
|
|
161
|
+
|
|
162
|
+
// One error in the order and shape lib/enrich-error.js enrich() writes them.
|
|
163
|
+
// `seen` is false when the root value is one the enrichment treats as absent
|
|
164
|
+
// (a falsy root other than 0 and false): then nothing is received.
|
|
165
|
+
export function E (code, keyword, path, schemaPath, params, message, expected, rank, v, seen, detail, suggest, branchErrors) {
|
|
166
|
+
const received = seen ? repr(v) : undefined
|
|
167
|
+
const o = { code, message, keyword, path, expected, received, schemaPath, docUrl: DOC + code, instancePath: path, dataPath: path, params, parentSchema: undefined }
|
|
168
|
+
if (branchErrors) o.branchErrors = branchErrors
|
|
169
|
+
const at = seen ? v : MISSING
|
|
170
|
+
const s = suggest ? suggest(at, params) : null
|
|
171
|
+
if (s) o.suggestion = s
|
|
172
|
+
const d = detail ? detail(received, at, params) : (expected === undefined ? undefined : `expected ${expected}, found ${received}`)
|
|
173
|
+
if (d !== undefined) o.detail = d
|
|
174
|
+
o.rank = rank
|
|
175
|
+
return o
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// lib/correlate.js correlateTypos, applied as lib/rejections.js attachRelated
|
|
179
|
+
// does: a required error and an additionalProperties error in one container
|
|
180
|
+
// whose names are one unambiguous typo apart point at each other.
|
|
181
|
+
const far = (a, b) => osa(a, b, 2)
|
|
182
|
+
export function relate (errors) {
|
|
183
|
+
let m = false; let x = false
|
|
184
|
+
for (const e of errors) { if (e.keyword === 'required') m = true; else if (e.keyword === 'additionalProperties') x = true }
|
|
185
|
+
if (!m || !x) return errors
|
|
186
|
+
const byPath = new Map()
|
|
187
|
+
errors.forEach((e, i) => {
|
|
188
|
+
const miss = e.keyword === 'required' ? e.params.missingProperty : undefined
|
|
189
|
+
const extra = e.keyword === 'additionalProperties' ? e.params.additionalProperty : undefined
|
|
190
|
+
if (typeof miss !== 'string' && typeof extra !== 'string') return
|
|
191
|
+
let b = byPath.get(e.instancePath)
|
|
192
|
+
if (!b) byPath.set(e.instancePath, b = { miss: [], extra: [] })
|
|
193
|
+
if (typeof miss === 'string') b.miss.push([i, miss]); else b.extra.push([i, extra])
|
|
194
|
+
})
|
|
195
|
+
for (const b of byPath.values()) {
|
|
196
|
+
if (!b.miss.length || !b.extra.length) continue
|
|
197
|
+
const dist = b.miss.map(([, a]) => b.extra.map(([, c]) => far(a, c)))
|
|
198
|
+
for (let mi = 0; mi < b.miss.length; mi++) {
|
|
199
|
+
let bx = -1; let bd = Infinity; let tied = false
|
|
200
|
+
for (let xi = 0; xi < b.extra.length; xi++) { const d = dist[mi][xi]; if (d < bd) { bd = d; bx = xi; tied = false } else if (d === bd && d !== Infinity) tied = true }
|
|
201
|
+
if (bx === -1 || tied || !(bd > 0 && bd <= 2)) continue
|
|
202
|
+
let bm = -1; let bk = Infinity; let btied = false
|
|
203
|
+
for (let m2 = 0; m2 < b.miss.length; m2++) { const d = dist[m2][bx]; if (d < bk) { bk = d; bm = m2; btied = false } else if (d === bk && d !== Infinity) btied = true }
|
|
204
|
+
if (btied || bm !== mi) continue
|
|
205
|
+
const a = errors[b.miss[mi][0]]; const c = errors[b.extra[bx][0]]
|
|
206
|
+
;(a.related || (a.related = [])).includes(b.extra[bx][0]) || a.related.push(b.extra[bx][0])
|
|
207
|
+
;(c.related || (c.related = [])).includes(b.miss[mi][0]) || c.related.push(b.miss[mi][0])
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return errors
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Own keys in the order the current engine reports additional properties:
|
|
214
|
+
// insertion order, with an own "__proto__" (JSON.parse makes one) last.
|
|
215
|
+
export function keysOf (v) {
|
|
216
|
+
const k = Object.keys(v)
|
|
217
|
+
const i = k.indexOf('__proto__')
|
|
218
|
+
if (i !== -1) { k.splice(i, 1); k.push('__proto__') }
|
|
219
|
+
return k
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export const seg = (k) => k.replace(/~/g, '~0').replace(/\//g, '~1')
|
|
223
|
+
|
|
224
|
+
// What a schema evaluated at one instance location: property names, and for
|
|
225
|
+
// arrays a prefix length, single indices (contains) or everything. The two
|
|
226
|
+
// sets are made on the first name or index written: most collectors take
|
|
227
|
+
// none (a branch that fails, an object with no listed names), and making
|
|
228
|
+
// two Sets for each was most of a verdict's time on a schema built on
|
|
229
|
+
// unevaluatedProperties (yamllint).
|
|
230
|
+
export const newAnn = () => ({ p: null, n: 0, at: null, all: false })
|
|
231
|
+
export function mergeAnn (into, from) {
|
|
232
|
+
if (from.p !== null) { if (into.p === null) into.p = new Set(from.p); else for (const k of from.p) into.p.add(k) }
|
|
233
|
+
if (from.n > into.n) into.n = from.n
|
|
234
|
+
if (from.at !== null) { if (into.at === null) into.at = new Set(from.at); else for (const i of from.at) into.at.add(i) }
|
|
235
|
+
if (from.all) into.all = true
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// The first index unevaluatedItems reports: past the evaluated prefix and
|
|
239
|
+
// the single indices contains matched.
|
|
240
|
+
export function firstUneval (A, x) { let j = A.n; if (A.at !== null) while (j < x.length && A.at.has(j)) j++; return j }
|
|
241
|
+
|
|
242
|
+
// lib/defaults.js setOwn and copyOf: write an own property (a key named
|
|
243
|
+
// __proto__ through defineProperty, so it never reaches the prototype), and
|
|
244
|
+
// a fresh copy of a default for each value it fills.
|
|
245
|
+
export function setOwn (o, k, v) {
|
|
246
|
+
if (k === '__proto__') Object.defineProperty(o, k, { value: v, writable: true, enumerable: true, configurable: true })
|
|
247
|
+
else o[k] = v
|
|
248
|
+
}
|
|
249
|
+
export const copyOf = (v) => typeof v !== 'object' || v === null ? v : Array.isArray(v) && v.length === 0 ? [] : JSON.parse(JSON.stringify(v))
|