ata-validator 1.40.1 → 1.42.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 +2 -0
- package/index.js +129 -3
- package/lib/aot-build.js +7 -3
- package/lib/aot-impl.js +22 -5
- package/lib/branch-collapse.js +17 -8
- package/lib/draft7.js +16 -0
- package/lib/enrich-error.js +46 -30
- package/lib/enrich-site.js +58 -0
- package/lib/interpreter.js +7 -1
- package/lib/js-compiler.js +945 -112
- package/lib/plan-compiler.js +7 -2
- package/lib/rejections.js +20 -3
- package/lib/schema-scan.js +6 -3
- package/lib/validator-core.js +127 -17
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/lib/plan-compiler.js
CHANGED
|
@@ -135,10 +135,15 @@ function install(deps) {
|
|
|
135
135
|
// Rollback marks: the two array lengths and the contiguous count.
|
|
136
136
|
function pLen(rec) { return rec.props === null ? 0 : rec.props.length; }
|
|
137
137
|
function xLen(rec) { return rec.x === null ? 0 : rec.x.length; }
|
|
138
|
+
// Writing an array's length is a slow path in V8 even when it does not
|
|
139
|
+
// change it, and most undos change nothing: a branch that failed before
|
|
140
|
+
// marking anything. So the length is written only when it moves.
|
|
138
141
|
function undo(rec, pl, n0, xl) {
|
|
139
|
-
|
|
142
|
+
const p = rec.props;
|
|
143
|
+
if (p !== null && p.length !== pl) p.length = pl;
|
|
140
144
|
rec.n = n0;
|
|
141
|
-
|
|
145
|
+
const x = rec.x;
|
|
146
|
+
if (x !== null && x.length !== xl) x.length = xl;
|
|
142
147
|
}
|
|
143
148
|
|
|
144
149
|
// The value-level keywords of one node, compiled. evalLeafV() answers the
|
package/lib/rejections.js
CHANGED
|
@@ -261,9 +261,26 @@ const COLLAPSE_CODES = new Set(['ATA4001', 'ATA4002', 'ATA4003']);
|
|
|
261
261
|
function stripOrdinal(e) {
|
|
262
262
|
if (e === null || typeof e !== 'object') return e;
|
|
263
263
|
// Generated code keeps errors at a fixed path as frozen literals shared by
|
|
264
|
-
// every call
|
|
265
|
-
//
|
|
266
|
-
|
|
264
|
+
// every call, marked with a non-enumerable `_s` (see sharedErr in
|
|
265
|
+
// lib/js-compiler.js). The caller gets its own copy, as it always has, so an
|
|
266
|
+
// error it edits (a translated message) is its own and editing it does not
|
|
267
|
+
// throw. Those literals hold the five keys of this shape and nothing else
|
|
268
|
+
// enumerable, so a literal of the same shape copies them: spreading one cost
|
|
269
|
+
// twice as much, and Object.isFrozen, which used to pick them out, more than
|
|
270
|
+
// the copy itself.
|
|
271
|
+
if (e._s === true && e.code === undefined && e.docUrl === undefined && e.branchErrors === undefined) {
|
|
272
|
+
return { keyword: e.keyword, instancePath: e.instancePath, schemaPath: e.schemaPath, params: e.params, message: e.message };
|
|
273
|
+
}
|
|
274
|
+
// A collapsed oneOf/anyOf error has one of the two shapes __ataCollapse in
|
|
275
|
+
// lib/branch-collapse.js builds, the only place these codes come from. Its
|
|
276
|
+
// fields are copied by name, in that order, without the ordinal: walking
|
|
277
|
+
// its keys with for-in was most of the cost of reading such an error.
|
|
278
|
+
if (e.path !== undefined && e.docUrl === undefined && COLLAPSE_CODES.has(e.code)) {
|
|
279
|
+
const out = { code: e.code, keyword: e.keyword, instancePath: e.instancePath, path: e.path, schemaPath: e.schemaPath, message: e.message, params: e.params };
|
|
280
|
+
if ('branchErrors' in e) out.branchErrors = Array.isArray(e.branchErrors) ? e.branchErrors.map(stripOrdinal) : e.branchErrors;
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
if (e._o === undefined && e.docUrl === undefined && (e.code === undefined || COLLAPSE_CODES.has(e.code)) && !e.branchErrors) return e._s === true ? { ...e } : e;
|
|
267
284
|
const out = {};
|
|
268
285
|
for (const k in e) {
|
|
269
286
|
if (k === '_o' || k === 'docUrl') continue;
|
package/lib/schema-scan.js
CHANGED
|
@@ -28,6 +28,7 @@ const DEFINITIONS = 1 << 3; // `definitions`, renamed to `$defs`
|
|
|
28
28
|
const DEPENDENCIES = 1 << 4; // `dependencies`, split into two keywords
|
|
29
29
|
const TUPLE_ITEMS = 1 << 5; // array-valued `items`, split into `prefixItems`
|
|
30
30
|
const EXCLUSIVE_BOOL = 1 << 6; // draft-04's boolean `exclusiveMinimum`/`exclusiveMaximum`
|
|
31
|
+
const ENCODED_REF = 1 << 7; // a fragment `$ref` holding a percent escape, decoded by normalizeNullable's walk
|
|
31
32
|
|
|
32
33
|
// Everything only draft-07 normalization acts on. A schema of another dialect
|
|
33
34
|
// can carry these without them meaning anything, so they are read together
|
|
@@ -84,6 +85,7 @@ function scan(schema) {
|
|
|
84
85
|
// to contribute here, and walking it is the slower path in V8.
|
|
85
86
|
const keys = Object.keys(node);
|
|
86
87
|
if (typeof node.$ref === 'string') {
|
|
88
|
+
if (node.$ref[0] === '#' && node.$ref.includes('%')) bits |= ENCODED_REF;
|
|
87
89
|
for (let i = 0; i < keys.length; i++) {
|
|
88
90
|
if (!REF_SIBLINGS_KEPT.has(keys[i])) { bits |= REF_SIBLINGS; break; }
|
|
89
91
|
}
|
|
@@ -102,11 +104,11 @@ function scan(schema) {
|
|
|
102
104
|
// rules apply at all, which the caller already knows.
|
|
103
105
|
function needsNormalization(schema, isDraft7) {
|
|
104
106
|
const bits = scan(schema);
|
|
105
|
-
if (bits & NULLABLE) return true;
|
|
106
107
|
// The boolean form of the exclusive bounds is draft-04's, and it is
|
|
107
108
|
// unambiguous wherever it appears: no later dialect gives a boolean any
|
|
108
|
-
// meaning there.
|
|
109
|
-
|
|
109
|
+
// meaning there. Percent-encoded fragments mean the same in every dialect
|
|
110
|
+
// too. Neither is gated on the declared dialect.
|
|
111
|
+
if (bits & (NULLABLE | EXCLUSIVE_BOOL | ENCODED_REF)) return true;
|
|
110
112
|
return isDraft7 ? (bits & DRAFT7_WORK) !== 0 : false;
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -120,5 +122,6 @@ module.exports = {
|
|
|
120
122
|
DEPENDENCIES,
|
|
121
123
|
TUPLE_ITEMS,
|
|
122
124
|
EXCLUSIVE_BOOL,
|
|
125
|
+
ENCODED_REF,
|
|
123
126
|
DRAFT7_WORK,
|
|
124
127
|
};
|
package/lib/validator-core.js
CHANGED
|
@@ -232,9 +232,16 @@ const VALID_RESULT = Object.freeze({ valid: true, errors: Object.freeze([]) });
|
|
|
232
232
|
// How many calls a validator answers through its verdict function before its
|
|
233
233
|
// validate() and validateJSON() compile the single-function hybrid.
|
|
234
234
|
const HYBRID_TIER_CALLS = 64;
|
|
235
|
+
// A frozen error object shared between calls carries a non-enumerable `_s`, so
|
|
236
|
+
// the reader that hands errors out copies it (lib/rejections.js stripOrdinal)
|
|
237
|
+
// without asking Object.isFrozen, which costs more than the copy.
|
|
238
|
+
function _sharedError(e) {
|
|
239
|
+
Object.defineProperty(e, '_s', { value: true });
|
|
240
|
+
return Object.freeze(e);
|
|
241
|
+
}
|
|
235
242
|
const ABORT_EARLY_RESULT = Object.freeze({
|
|
236
243
|
valid: false,
|
|
237
|
-
errors: Object.freeze([
|
|
244
|
+
errors: Object.freeze([_sharedError({
|
|
238
245
|
code: 'ATA9000',
|
|
239
246
|
message: 'validation failed',
|
|
240
247
|
keyword: '__abort_early__',
|
|
@@ -292,7 +299,7 @@ function resolveSchemaByPath(rootSchema, schemaPath) {
|
|
|
292
299
|
//
|
|
293
300
|
// A failing route sees the same handful of schemaPaths over and over, which is
|
|
294
301
|
// what makes the first one worth having.
|
|
295
|
-
const { LazyRejection, RichRejection, LazyJsonRejection, _enrichLazy, presentErrors, needsOrdering, sortErrorsBySchemaOrder } = require('./rejections');
|
|
302
|
+
const { LazyRejection, RichRejection, LazyJsonRejection, _enrichLazy, presentErrors, needsOrdering, sortErrorsBySchemaOrder, stripOrdinal } = require('./rejections');
|
|
296
303
|
|
|
297
304
|
// Text that does not parse, reported the same way on every path and platform:
|
|
298
305
|
// ATA9001 with the parser's own message. The native addon used to say only
|
|
@@ -609,7 +616,17 @@ function _materializeSchema(self) {
|
|
|
609
616
|
if (options.assertFormat === false) {
|
|
610
617
|
schemaObj = stripFormatAssertions(isCallers ? _deepCloneWithSymbols(schemaObj) : schemaObj);
|
|
611
618
|
}
|
|
612
|
-
|
|
619
|
+
// A keyword used only in a schema reached through $ref counts too: the
|
|
620
|
+
// interpreted engine applies it there, and every path that does not know the
|
|
621
|
+
// keyword has to stand aside for it. Looking at the root alone, a keyword in
|
|
622
|
+
// a referenced schema was skipped by every compiled path and accepted
|
|
623
|
+
// whatever it should have rejected.
|
|
624
|
+
let usesKeywords = self._keywords !== null && schemaUsesKeywords(schemaObj, self._keywords);
|
|
625
|
+
if (!usesKeywords && self._keywords !== null && self._schemaMap && self._schemaMap.size > 0) {
|
|
626
|
+
for (const ext of self._schemaMap.values()) {
|
|
627
|
+
if (schemaUsesKeywords(ext, self._keywords)) { usesKeywords = true; break; }
|
|
628
|
+
}
|
|
629
|
+
}
|
|
613
630
|
Object.defineProperty(self, '_schemaObj', { value: schemaObj, writable: true, configurable: true, enumerable: true });
|
|
614
631
|
Object.defineProperty(self, '_usesKeywords', { value: usesKeywords, writable: true, configurable: true, enumerable: true });
|
|
615
632
|
Object.defineProperty(self, '_schemaIsCallers', { value: isCallers && schemaObj === raw, writable: true, configurable: true, enumerable: true });
|
|
@@ -849,7 +866,7 @@ class Validator {
|
|
|
849
866
|
// interpreted engine is both eval-free and more correct, so go straight
|
|
850
867
|
// there. The forced case is decided before the probe: the probe is a
|
|
851
868
|
// `new Function` too, and a validator that promised none must not run it.
|
|
852
|
-
if (_forceNapi || this._v1Dynamic ||
|
|
869
|
+
if (_forceNapi || this._v1Dynamic || !codegenAvailable()) {
|
|
853
870
|
jsFn = null; jsCombinedFn = null; jsErrFn = null;
|
|
854
871
|
// `full` separates an entry that holds every compiled function from one
|
|
855
872
|
// the verdict-only fast path seeded, where `combined` and `errFn` are null
|
|
@@ -871,8 +888,17 @@ class Validator {
|
|
|
871
888
|
this._engine = _isCodegen ? 'codegen' : jsFn ? 'closure' : null;
|
|
872
889
|
} else {
|
|
873
890
|
const uf = this._userFormats;
|
|
874
|
-
|
|
875
|
-
|
|
891
|
+
// Custom keywords compile into the verdict function as calls to the
|
|
892
|
+
// caller's functions. Only the verdict: the error and combined
|
|
893
|
+
// generators, the closure compiler and the text scanner know nothing of
|
|
894
|
+
// them and would skip the keyword, accepting what it rejects, so for a
|
|
895
|
+
// schema that uses one they are not built, and errors come from the
|
|
896
|
+
// interpreted engine, which applies the keywords. Where the generator
|
|
897
|
+
// declines the schema, so does everything else, and the interpreted
|
|
898
|
+
// engine answers alone, as it always did.
|
|
899
|
+
const kw = this._keywords ? { keywords: this._keywords } : undefined;
|
|
900
|
+
const _cgFn = compileToJSCodegen(schemaObj, sm, uf, kw);
|
|
901
|
+
jsFn = _cgFn || (this._usesKeywords ? null : compileToJS(schemaObj, null, sm));
|
|
876
902
|
// Only the verdict is compiled here. The error and combined generators
|
|
877
903
|
// are the other two thirds of a cold first call (8.2, 10.4 and 7.8 ms on
|
|
878
904
|
// a 120-property config schema, most of it V8 compiling each generator
|
|
@@ -882,7 +908,9 @@ class Validator {
|
|
|
882
908
|
jsErrFn = undefined;
|
|
883
909
|
_isCodegen = !!_cgFn;
|
|
884
910
|
this._engine = _cgFn ? 'codegen' : jsFn ? 'closure' : null;
|
|
885
|
-
|
|
911
|
+
// A function bound to this validator's keyword functions or formats is
|
|
912
|
+
// not the schema's alone, so it is not shared through the cache.
|
|
913
|
+
if (!uf && !this._keywords) {
|
|
886
914
|
_compileCache.set(mapKey, { jsFn, combined: undefined, errFn: undefined, isCodegen: _isCodegen, full: false });
|
|
887
915
|
}
|
|
888
916
|
}
|
|
@@ -991,12 +1019,12 @@ class Validator {
|
|
|
991
1019
|
};
|
|
992
1020
|
const _buildCombined = () => {
|
|
993
1021
|
if (jsCombinedFn !== undefined) return;
|
|
994
|
-
jsCombinedFn = compileToJSCombined(schemaObj, VALID_RESULT, sm, this._userFormats, { runtimeShape: true }) || null;
|
|
1022
|
+
jsCombinedFn = this._usesKeywords ? null : (compileToJSCombined(schemaObj, VALID_RESULT, sm, this._userFormats, { runtimeShape: true }) || null);
|
|
995
1023
|
_upgradeCacheEntry();
|
|
996
1024
|
};
|
|
997
1025
|
const _buildErr = () => {
|
|
998
1026
|
if (jsErrFn !== undefined) return;
|
|
999
|
-
jsErrFn = compileToJSCodegenWithErrors(schemaObj, sm, this._userFormats, { runtimeShape: true }) || null;
|
|
1027
|
+
jsErrFn = this._usesKeywords ? null : (compileToJSCodegenWithErrors(schemaObj, sm, this._userFormats, { runtimeShape: true }) || null);
|
|
1000
1028
|
_upgradeCacheEntry();
|
|
1001
1029
|
};
|
|
1002
1030
|
|
|
@@ -1005,14 +1033,27 @@ class Validator {
|
|
|
1005
1033
|
// locals and on this object rather than on the instance: every call reads
|
|
1006
1034
|
// `validate` off the instance, and three more own properties made that
|
|
1007
1035
|
// read slower across the suite's validators.
|
|
1008
|
-
let _rejectBase = null, _rejectPresented = null, _rejectPlain = false;
|
|
1036
|
+
let _rejectBase = null, _rejectPresented = null, _rejectPlain = false, _oneShotRich = null, _richBuilder = null, _oneShotPlain = false, _isCleanShape = null, _onePassOf = null, _isCombined = null;
|
|
1009
1037
|
if (jsFn) {
|
|
1010
1038
|
const _cg = {
|
|
1011
1039
|
jsFn, _isCodegen, preprocess, fusedRemove, options, schemaObj, useSimdjsonForLarge, _buildCombined, _buildErr,
|
|
1012
|
-
combined: () => jsCombinedFn, err: () => jsErrFn, rejectBase: null,
|
|
1040
|
+
combined: () => jsCombinedFn, err: () => jsErrFn, rejectBase: null, richBuilder: null, oneShotPlain: false, isCleanShape: null, isCombined: null, onePassOf: null,
|
|
1041
|
+
// The combined function with errors built enriched where they happen,
|
|
1042
|
+
// for a validator whose errors are read with richErrors on and no
|
|
1043
|
+
// schema source to attach frames from (see makeRich).
|
|
1044
|
+
buildRich: (this._richErrors && !this._schemaPositions && !this._usesKeywords)
|
|
1045
|
+
? () => compileToJSCombined(schemaObj, VALID_RESULT, sm, this._userFormats, { runtimeShape: true, rich: true }) || null
|
|
1046
|
+
: null,
|
|
1047
|
+
oneShotRich: null,
|
|
1013
1048
|
};
|
|
1014
1049
|
_codegen.installPaths.call(this, _cg);
|
|
1015
1050
|
_rejectBase = _cg.rejectBase;
|
|
1051
|
+
_oneShotRich = _cg.oneShotRich;
|
|
1052
|
+
_richBuilder = _cg.richBuilder;
|
|
1053
|
+
_oneShotPlain = _cg.oneShotPlain;
|
|
1054
|
+
_isCleanShape = _cg.isCleanShape;
|
|
1055
|
+
_onePassOf = _cg.onePassOf;
|
|
1056
|
+
_isCombined = _cg.isCombined;
|
|
1016
1057
|
} else {
|
|
1017
1058
|
// No JS codegen: the interpreted engine, with or without the addon. The
|
|
1018
1059
|
// buffer APIs come from _installBufferApis on first use, as they do on
|
|
@@ -1243,10 +1284,67 @@ class Validator {
|
|
|
1243
1284
|
}
|
|
1244
1285
|
return _withExtra(raw, data);
|
|
1245
1286
|
};
|
|
1246
|
-
|
|
1287
|
+
// validate() answers from the verdict and builds the errors when they
|
|
1288
|
+
// are read. What builds them improves once they are being read: from
|
|
1289
|
+
// the third read the combined function is called directly, without the
|
|
1290
|
+
// rejection layers, and with richErrors on it builds the errors
|
|
1291
|
+
// enriched where they fail (see makeRich in lib/enrich-site.js) rather
|
|
1292
|
+
// than plain and enriched afterwards. Built on the second read, not the
|
|
1293
|
+
// first, so a first rejection still compiles one generator. The rejection
|
|
1294
|
+
// holds `_errorsOf`, which dispatches to whichever builder is current.
|
|
1295
|
+
let _errorsNow = _buildErrors;
|
|
1296
|
+
let _onePass = null;
|
|
1297
|
+
let _richLater = (_plain !== null && _oneShotRich !== null && _richBuilder !== null && !_extra) ? 1 : 0;
|
|
1298
|
+
const _errorsOf = (data) => {
|
|
1299
|
+
if (_richLater !== 0 && ++_richLater > 2) {
|
|
1300
|
+
_richLater = 0;
|
|
1301
|
+
const combRich = _oneShotRich();
|
|
1302
|
+
if (combRich) {
|
|
1303
|
+
const clean = !this._richErrors && _isCleanShape !== null && _isCleanShape(combRich);
|
|
1304
|
+
_errorsNow = _richBuilder(combRich, this._schemaObj, (raw, d) => presentErrors(raw, d, null, this, this._schemaObj, this._richErrors ? _enrichLazy : null), _verdictFallback, _oneShotPlain, clean);
|
|
1305
|
+
_errorsOf.final = !_oneShotPlain;
|
|
1306
|
+
// Plain errors from the combined function: from here validate()
|
|
1307
|
+
// is that function in its result shape, one pass that decides,
|
|
1308
|
+
// collects and returns, instead of a verdict now and a second
|
|
1309
|
+
// pass when the errors are read. A caller reading only `.valid`
|
|
1310
|
+
// pays the collecting pass (about twice the verdict on a document
|
|
1311
|
+
// that fails); with richErrors on the errors stay lazy, since
|
|
1312
|
+
// enriching costs far more.
|
|
1313
|
+
// Collapsed branches are presented inside the one-pass function
|
|
1314
|
+
// (see onePassOf), so any plain combined function qualifies.
|
|
1315
|
+
// Plain errors only. With richErrors on, enriching is most of what
|
|
1316
|
+
// a read costs and the lazy path answers an accepted document from
|
|
1317
|
+
// the verdict, so one pass measured no faster on rejections and
|
|
1318
|
+
// slower on acceptances.
|
|
1319
|
+
const onePass = !this._richErrors && _onePassOf !== null && _isCombined !== null && _isCombined(combRich) ? _onePassOf(EMPTY_ERRORS, _plainValidate) : null;
|
|
1320
|
+
if (onePass) { _onePass = onePass; self.validate = onePass; }
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
return _errorsNow(data);
|
|
1324
|
+
};
|
|
1325
|
+
_errorsOf.final = false;
|
|
1326
|
+
const _plainValidate = (data) => {
|
|
1247
1327
|
if (_fast(data)) return { valid: true, data, errors: EMPTY_ERRORS };
|
|
1248
|
-
return new LazyRejection(
|
|
1328
|
+
return new LazyRejection(_errorsOf, data, _buildRawErrors);
|
|
1249
1329
|
};
|
|
1330
|
+
// Past its first calls, validate() is the generated checks returning
|
|
1331
|
+
// these same results directly (jsFn._resultFactory): no wrapper between
|
|
1332
|
+
// the caller and the checks, and allocation sites of its own. Compiled
|
|
1333
|
+
// only once the validator is in use, as the hybrid is.
|
|
1334
|
+
const self = this;
|
|
1335
|
+
const _factory = (_vx === null && _fast === this._fastVerdict && typeof _fast._resultFactory === 'function') ? _fast._resultFactory : null;
|
|
1336
|
+
if (_factory !== null) {
|
|
1337
|
+
let calls = 0;
|
|
1338
|
+
this.validate = (data) => {
|
|
1339
|
+
if (++calls === HYBRID_TIER_CALLS && _onePass === null) {
|
|
1340
|
+
const gen = _factory(LazyRejection, _errorsOf, _buildRawErrors, EMPTY_ERRORS);
|
|
1341
|
+
if (gen) self.validate = gen;
|
|
1342
|
+
}
|
|
1343
|
+
return _plainValidate(data);
|
|
1344
|
+
};
|
|
1345
|
+
} else {
|
|
1346
|
+
this.validate = _plainValidate;
|
|
1347
|
+
}
|
|
1250
1348
|
}
|
|
1251
1349
|
if (_vx && !_vxApplied && this.validate) {
|
|
1252
1350
|
const inner = this.validate;
|
|
@@ -1730,7 +1828,7 @@ Object.defineProperty(Validator.prototype, "~standard", {
|
|
|
1730
1828
|
// reported as a generic failure rather than hidden.
|
|
1731
1829
|
const _VERDICT_DISAGREES = Object.freeze({
|
|
1732
1830
|
valid: false,
|
|
1733
|
-
errors: Object.freeze([
|
|
1831
|
+
errors: Object.freeze([_sharedError({ keyword: 'validation', instancePath: '', schemaPath: '#', params: Object.freeze({}), message: 'schema validation failed' })]),
|
|
1734
1832
|
});
|
|
1735
1833
|
// The error builders of the common rejection path (see _ensureCompiled): run
|
|
1736
1834
|
// the error function behind `reject` for a document the verdict rejected, and
|
|
@@ -1743,9 +1841,12 @@ function _plainBuilders(reject, enrich, root, self, fallback) {
|
|
|
1743
1841
|
};
|
|
1744
1842
|
return {
|
|
1745
1843
|
errors: (data) => presentErrors(rawOf(data), data, null, self, root, enrich),
|
|
1844
|
+
// The raw list in the plain shape: a collapsed branch error carried its
|
|
1845
|
+
// ordering key out to `_ataRaw()` callers, and a shared literal was
|
|
1846
|
+
// handed out as it is.
|
|
1746
1847
|
raw: (data) => {
|
|
1747
1848
|
const raw = rawOf(data);
|
|
1748
|
-
return needsOrdering(raw) ? sortErrorsBySchemaOrder(root, raw) : raw;
|
|
1849
|
+
return (needsOrdering(raw) ? sortErrorsBySchemaOrder(root, raw) : raw).map(stripOrdinal);
|
|
1749
1850
|
},
|
|
1750
1851
|
};
|
|
1751
1852
|
}
|
|
@@ -1838,7 +1939,7 @@ function _jsonEntryWrappers({ check, errors }) {
|
|
|
1838
1939
|
},
|
|
1839
1940
|
};
|
|
1840
1941
|
}
|
|
1841
|
-
const _EXT_FALLBACK =
|
|
1942
|
+
const _EXT_FALLBACK = _sharedError({ keyword: 'validation', instancePath: '', schemaPath: '#', params: {}, message: 'schema validation failed' });
|
|
1842
1943
|
|
|
1843
1944
|
// A verdict function that also runs `tail` on what it accepts. The generated
|
|
1844
1945
|
// function can take the check in place of its final `return true`, one call
|
|
@@ -2068,7 +2169,15 @@ _defineLazyMethod('validate', (self) => (data) => {
|
|
|
2068
2169
|
self._ensureCompiled();
|
|
2069
2170
|
return self.validate(data);
|
|
2070
2171
|
});
|
|
2071
|
-
_defineLazyMethod('isValidObject', (self) =>
|
|
2172
|
+
_defineLazyMethod('isValidObject', (self) => {
|
|
2173
|
+
// A caller can hold this stub itself: `const check = v.isValidObject`, or a
|
|
2174
|
+
// bound copy, taken before the first call. Once the first call has bound the
|
|
2175
|
+
// real method, the stub hands straight to it; it used to classify the schema
|
|
2176
|
+
// again on every call, about 200 ns, ten times the check.
|
|
2177
|
+
let bound = false;
|
|
2178
|
+
return (data) => {
|
|
2179
|
+
if (bound) return self.isValidObject(data);
|
|
2180
|
+
bound = true;
|
|
2072
2181
|
// A validator that rewrites its input goes through the full compile, which
|
|
2073
2182
|
// binds a verdict method that runs the rewrite first. So does one whose
|
|
2074
2183
|
// schema uses a custom keyword: neither the tier-0 plan nor the code
|
|
@@ -2103,6 +2212,7 @@ _defineLazyMethod('isValidObject', (self) => (data) => {
|
|
|
2103
2212
|
if (!self._jsFn) self._ensureCompiled();
|
|
2104
2213
|
}
|
|
2105
2214
|
return self.isValidObject(data);
|
|
2215
|
+
};
|
|
2106
2216
|
});
|
|
2107
2217
|
_defineLazyMethod('validateJSON', (self) => (jsonStr) => {
|
|
2108
2218
|
self._ensureCompiled();
|
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.42.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
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"release:check": "node tests/test_pack_purity.js && node scripts/check-doc-coverage.js && node tests/test_error_codes_lock.js && node tests/test_safe_regex_embed.js && node tests/test_version_sync.js",
|
|
65
65
|
"build": "cmake-js build --target ata",
|
|
66
66
|
"rebuild": "cmake-js rebuild --target ata",
|
|
67
|
-
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_text_path_errors.js && node tests/test_compiled_parity.js && node tests/test_compiled_extension_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_validate_json_scanner_cost.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_error_list_differential.js && node tests/test_output_format.js && node tests/test_standard_json_schema.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_esm_exports.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_native_lazy.js && node tests/test_buffer_apis_without_native.js && node tests/test_cold_start_modules.js && node tests/test_safe_regex_embed.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_regex_ecma_whitespace.js && node tests/test_regex_native_linear.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_proto_accessor.js && node tests/test_hybrid_tier.js && node tests/test_first_rejection_builds_one.js && node tests/test_container_local.js && node tests/test_one_shot_validate.js && node tests/test_fixed_pattern_inline.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_schema_code_injection.js && node tests/test_ref_annotation_siblings.js && node tests/test_gate_wrapped_schemas.js && node tests/test_pattern_message_escape.js && node tests/test_nested_defaults_engines.js && node tests/test_nested_coercion_parity.js && node tests/test_preprocess_cache.js && node tests/test_large_schema_codegen.js && node tests/test_base_uri.js && node tests/test_hoisted_def_recursion.js && node tests/test_alias_definitions.js && node tests/test_property_names_ref.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_unevaluated_differential.js && node tests/fuzz_differential.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.js && node tests/test_additional_props_combined_cost.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_ref_error_order.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_single_pass_errors.js && node tests/test_lazy_json_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_lite_parity.js && node tests/test_lite_bundle_size.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_enrich_received.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_render_without_process.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_aot_source_frames.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node tests/test_collect_evaluated.js && node tests/test_differential_tiers.js && node tests/test_draft7.js && node tests/test_dual_path.js && node tests/test_keywords_codegen.js && node tests/test_ref_cross.js && node tests/test_shape_classifier.js && node tests/test_tier0.js && node benchmark/bench_aot_size.mjs",
|
|
67
|
+
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_number_text_parity.js && node tests/test_text_path_errors.js && node tests/test_compiled_parity.js && node tests/test_compiled_extension_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_validate_json_scanner_cost.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_error_list_differential.js && node tests/test_output_format.js && node tests/test_standard_json_schema.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_esm_exports.js && node tests/test_version_sync.js && node tests/test_native_loaded.js && node tests/test_native_lazy.js && node tests/test_buffer_apis_without_native.js && node tests/test_cold_start_modules.js && node tests/test_safe_regex_embed.js && node tests/test_t_builder.js && node tests/test_async_refine.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.js && node tests/test_regex_ecma_whitespace.js && node tests/test_regex_native_linear.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_proto_accessor.js && node tests/test_hybrid_tier.js && node tests/test_first_rejection_builds_one.js && node tests/test_container_local.js && node tests/test_one_shot_validate.js && node tests/test_fixed_pattern_inline.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_encoded_refs.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_schema_code_injection.js && node tests/test_aot_html_safe.js && node tests/test_ref_annotation_siblings.js && node tests/test_gate_wrapped_schemas.js && node tests/test_pattern_message_escape.js && node tests/test_nested_defaults_engines.js && node tests/test_nested_coercion_parity.js && node tests/test_preprocess_cache.js && node tests/test_large_schema_codegen.js && node tests/test_base_uri.js && node tests/test_hoisted_def_recursion.js && node tests/test_alias_definitions.js && node tests/test_property_names_ref.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_custom_keyword_codegen.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_unevaluated_differential.js && node tests/fuzz_differential.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.js && node tests/test_additional_props_combined_cost.js && node tests/test_no_input_mutation.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_ref_error_order.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_error_read_paths.js && node tests/test_unique_items_error_pair.js && node tests/test_rich_errors_generated.js && node tests/test_captured_verdict_stub.js && node tests/test_generated_returns_rewrite.js && node tests/test_deep_pointer_refs.js && node tests/test_uneval_props_dynamic.js && node tests/test_one_pass_no_fallback.js && node tests/test_single_pass_errors.js && node tests/test_lazy_json_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_lite_parity.js && node tests/test_lite_bundle_size.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_enrich_received.js && node tests/test_rich_errors_optout.js && node tests/test_error_messages.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_render_without_process.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_aot_source_frames.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node tests/test_collect_evaluated.js && node tests/test_differential_tiers.js && node tests/test_draft7.js && node tests/test_dual_path.js && node tests/test_keywords_codegen.js && node tests/test_ref_cross.js && node tests/test_shape_classifier.js && node tests/test_tier0.js && node benchmark/bench_aot_size.mjs",
|
|
68
68
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
69
69
|
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
|
|
70
70
|
"test:compat": "node tests/test_compat.js",
|
|
@@ -143,13 +143,13 @@
|
|
|
143
143
|
"LICENSE"
|
|
144
144
|
],
|
|
145
145
|
"optionalDependencies": {
|
|
146
|
-
"@ata-validator/native-darwin-arm64": "1.
|
|
147
|
-
"@ata-validator/native-darwin-x64": "1.
|
|
148
|
-
"@ata-validator/native-linux-arm64-gnu": "1.
|
|
149
|
-
"@ata-validator/native-linux-arm64-musl": "1.
|
|
150
|
-
"@ata-validator/native-linux-x64-gnu": "1.
|
|
151
|
-
"@ata-validator/native-linux-x64-musl": "1.
|
|
152
|
-
"@ata-validator/native-win32-x64": "1.
|
|
146
|
+
"@ata-validator/native-darwin-arm64": "1.42.0",
|
|
147
|
+
"@ata-validator/native-darwin-x64": "1.42.0",
|
|
148
|
+
"@ata-validator/native-linux-arm64-gnu": "1.42.0",
|
|
149
|
+
"@ata-validator/native-linux-arm64-musl": "1.42.0",
|
|
150
|
+
"@ata-validator/native-linux-x64-gnu": "1.42.0",
|
|
151
|
+
"@ata-validator/native-linux-x64-musl": "1.42.0",
|
|
152
|
+
"@ata-validator/native-win32-x64": "1.42.0"
|
|
153
153
|
},
|
|
154
154
|
"peerDependencies": {
|
|
155
155
|
"yaml": "^2.0.0"
|