ata-validator 1.43.0 → 1.45.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 +10 -10
- package/index.js +54 -0
- package/lib/clone-emit.js +5 -2
- package/lib/data-position-cache.js +12 -6
- package/lib/draft7.js +5 -7
- package/lib/formats.js +8 -2
- package/lib/interpreter.js +44 -51
- package/lib/js-compiler.js +197 -76
- package/lib/levenshtein.js +34 -22
- package/lib/native-positions.js +100 -0
- package/lib/plan-compiler.js +23 -25
- package/lib/rejections.js +14 -7
- package/lib/suggestions.js +27 -20
- package/lib/unique-items.js +139 -0
- package/lib/validator-core.js +71 -10
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/lib/validator-core.js
CHANGED
|
@@ -604,8 +604,10 @@ function resolveSchemaForPreprocess(schema, schemaMap) {
|
|
|
604
604
|
if (p && typeof p === 'object' && p.$ref && !p.type) {
|
|
605
605
|
const t = resolveRefForPreprocess(p.$ref, schemaMap)
|
|
606
606
|
if (t && typeof t === 'object') {
|
|
607
|
-
|
|
608
|
-
|
|
607
|
+
// Spread and defineProperty: a property named "__proto__" stays an own
|
|
608
|
+
// key of the copy (assignment would set the copy's prototype).
|
|
609
|
+
if (!cloned) { cloned = { ...s }; cloned.properties = { ...s.properties } }
|
|
610
|
+
Object.defineProperty(cloned.properties, key, { value: t, writable: true, enumerable: true, configurable: true })
|
|
609
611
|
}
|
|
610
612
|
}
|
|
611
613
|
}
|
|
@@ -775,6 +777,7 @@ class Validator {
|
|
|
775
777
|
// to attach dataFrame entries to each enriched error.
|
|
776
778
|
this._posCache = null; // created by _pos() on first use, only the JSON text path needs it
|
|
777
779
|
this._lastRawInput = null;
|
|
780
|
+
this._lastParsed = undefined;
|
|
778
781
|
// undefined: not built yet. null: this schema has no scanner.
|
|
779
782
|
this._scanner = undefined;
|
|
780
783
|
// Checks a wrapper registered through _extendChecks. Declared here so
|
|
@@ -815,7 +818,7 @@ class Validator {
|
|
|
815
818
|
}
|
|
816
819
|
|
|
817
820
|
_pos() {
|
|
818
|
-
return this._posCache || (this._posCache = require('./data-position-cache').createCache());
|
|
821
|
+
return this._posCache || (this._posCache = require('./data-position-cache').createCache(_codegen !== null && _codegen.nativePositions ? _codegen.nativePositions() : null));
|
|
819
822
|
}
|
|
820
823
|
|
|
821
824
|
_ensureVocabularies() {
|
|
@@ -847,7 +850,12 @@ class Validator {
|
|
|
847
850
|
// "validate this schema against its dialect" needs no network and no
|
|
848
851
|
// caller-supplied registry. Only schemas that mention json-schema.org in a
|
|
849
852
|
// reference pay for the lookup.
|
|
850
|
-
|
|
853
|
+
// A reference, not `$schema`: nearly every schema names its dialect, and
|
|
854
|
+
// matching that loaded the vendored meta-schemas into every validator's
|
|
855
|
+
// map, 27 entries that made its compile cache key a 30 KB string, rebuilt
|
|
856
|
+
// in 20 microseconds at each compile, and sent every compile through the
|
|
857
|
+
// external-document checks.
|
|
858
|
+
if (this._schemaStr.includes('json-schema.org/') && /"\$(?:ref|dynamicRef|recursiveRef)":"[^"]*json-schema\.org\//.test(this._schemaStr)) {
|
|
851
859
|
const { METASCHEMAS } = require('./metaschemas');
|
|
852
860
|
this._ownSchemaMap();
|
|
853
861
|
for (const [id, meta] of METASCHEMAS) {
|
|
@@ -1104,6 +1112,17 @@ class Validator {
|
|
|
1104
1112
|
_bindVerdict(this, this._fastVerdict
|
|
1105
1113
|
? this._fastVerdict
|
|
1106
1114
|
: (data) => run(data).valid);
|
|
1115
|
+
// Parsed, then the verdict first and the errors only for a document that
|
|
1116
|
+
// fails: collecting them on every document cost an accepted 5 MB one 9 ms
|
|
1117
|
+
// over JSON.parse and validate(). At this layer, below the presentation
|
|
1118
|
+
// that the text path wraps around it: going through validate() as it
|
|
1119
|
+
// stands once every layer is in place handed the text path errors
|
|
1120
|
+
// already presented, and they lost their source anchor.
|
|
1121
|
+
const runText = options.abortEarly
|
|
1122
|
+
? run
|
|
1123
|
+
: (preprocess
|
|
1124
|
+
? (data) => { preprocess(data); return interp.isValid(data) ? VALID_RESULT : interp.validate(data); }
|
|
1125
|
+
: (data) => (interp.isValid(data) ? VALID_RESULT : interp.validate(data)));
|
|
1107
1126
|
this.validateJSON = (jsonStr) => {
|
|
1108
1127
|
let data;
|
|
1109
1128
|
try {
|
|
@@ -1112,9 +1131,19 @@ class Validator {
|
|
|
1112
1131
|
if (!(e instanceof SyntaxError)) throw e;
|
|
1113
1132
|
return _jsonSyntaxRejection(e);
|
|
1114
1133
|
}
|
|
1115
|
-
|
|
1134
|
+
this._lastParsed = data;
|
|
1135
|
+
return runText(data);
|
|
1136
|
+
};
|
|
1137
|
+
this.isValidJSON = (jsonStr) => {
|
|
1138
|
+
let data;
|
|
1139
|
+
try {
|
|
1140
|
+
data = JSON.parse(jsonStr);
|
|
1141
|
+
} catch (e) {
|
|
1142
|
+
if (!(e instanceof SyntaxError)) throw e;
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
1145
|
+
return this.isValidObject(data);
|
|
1116
1146
|
};
|
|
1117
|
-
this.isValidJSON = (jsonStr) => this.validateJSON(jsonStr).valid;
|
|
1118
1147
|
}
|
|
1119
1148
|
|
|
1120
1149
|
// Error presentation, one lazy layer: declaration-order sorting, rich
|
|
@@ -1163,21 +1192,38 @@ class Validator {
|
|
|
1163
1192
|
// rejection it builds. Cleared as soon as it returns: the rejection
|
|
1164
1193
|
// carries the text itself, so nothing outlives the call.
|
|
1165
1194
|
this._lastRawInput = jsonStr;
|
|
1166
|
-
|
|
1195
|
+
this._lastParsed = undefined;
|
|
1196
|
+
let result, parsed;
|
|
1167
1197
|
try {
|
|
1168
1198
|
result = innerJson(jsonStr);
|
|
1169
1199
|
} finally {
|
|
1170
1200
|
this._lastRawInput = null;
|
|
1201
|
+
parsed = this._lastParsed;
|
|
1202
|
+
this._lastParsed = undefined;
|
|
1171
1203
|
}
|
|
1172
1204
|
// Every diagnostic the text path adds is deferred. Deciding here
|
|
1173
1205
|
// whether there is anything to add would mean reading `result.errors`,
|
|
1174
1206
|
// and on the codegen path that realizes the inner lazy layer, which is
|
|
1175
1207
|
// the document walk this exists to avoid.
|
|
1176
1208
|
if (result && result.valid === false) {
|
|
1177
|
-
return new LazyJsonRejection(result, jsonStr, this, enrich);
|
|
1209
|
+
return new LazyJsonRejection(result, jsonStr, this, enrich, parsed);
|
|
1178
1210
|
}
|
|
1179
1211
|
return result;
|
|
1180
1212
|
};
|
|
1213
|
+
} else if (this.validateJSON) {
|
|
1214
|
+
// Without enrichment the text path still presents its errors as
|
|
1215
|
+
// validate() does, in declaration order: on generated code they came
|
|
1216
|
+
// out in the order the function found them, so the same document gave
|
|
1217
|
+
// its errors in one order from validate() and another from here.
|
|
1218
|
+
const innerJson = this.validateJSON;
|
|
1219
|
+
this.validateJSON = (jsonStr) => {
|
|
1220
|
+
this._lastParsed = undefined;
|
|
1221
|
+
const result = innerJson(jsonStr);
|
|
1222
|
+
const parsed = this._lastParsed;
|
|
1223
|
+
this._lastParsed = undefined;
|
|
1224
|
+
if (!(result && result.valid === false && parsed !== undefined)) return result;
|
|
1225
|
+
return present(result, parsed);
|
|
1226
|
+
};
|
|
1181
1227
|
}
|
|
1182
1228
|
}
|
|
1183
1229
|
|
|
@@ -1211,10 +1257,12 @@ class Validator {
|
|
|
1211
1257
|
// errorMessage keep the validate hot path untouched. Layered after rich
|
|
1212
1258
|
// enrichment so `code`/`keyword`/`path` are already final and only the
|
|
1213
1259
|
// human-facing message changes.
|
|
1260
|
+
// The module loads only for a schema that has the keyword: loading it
|
|
1261
|
+
// to ask was a file read on every process's first compile.
|
|
1214
1262
|
{
|
|
1215
|
-
const emLib = require('./error-messages');
|
|
1216
1263
|
const schemaStr = this._schemaStr || (this._schemaObj ? JSON.stringify(this._schemaObj) : '');
|
|
1217
|
-
if (
|
|
1264
|
+
if (schemaStr.indexOf('"errorMessage"') !== -1) {
|
|
1265
|
+
const emLib = require('./error-messages');
|
|
1218
1266
|
const root = this._schemaObj;
|
|
1219
1267
|
const wrap = (inner) => (arg) => {
|
|
1220
1268
|
const result = inner(arg);
|
|
@@ -2184,7 +2232,15 @@ for (const [name, pick] of [
|
|
|
2184
2232
|
});
|
|
2185
2233
|
}
|
|
2186
2234
|
|
|
2235
|
+
// Cold start: an interpreted twin answers a large schema's first calls where
|
|
2236
|
+
// the code generator is registered (see coldTwin in index.js). Lite has none.
|
|
2237
|
+
Validator.prototype._coldTwin = function () {
|
|
2238
|
+
return _codegen === null || _codegen.coldTwin === undefined ? null : _codegen.coldTwin(this, Validator);
|
|
2239
|
+
};
|
|
2240
|
+
|
|
2187
2241
|
_defineLazyMethod('validate', (self) => (data) => {
|
|
2242
|
+
const t = self._coldTwin();
|
|
2243
|
+
if (t !== null) return t.validate(data);
|
|
2188
2244
|
self._ensureCompiled();
|
|
2189
2245
|
return self.validate(data);
|
|
2190
2246
|
});
|
|
@@ -2195,6 +2251,7 @@ _defineLazyMethod('isValidObject', (self) => {
|
|
|
2195
2251
|
// again on every call, about 200 ns, ten times the check.
|
|
2196
2252
|
let bound = false;
|
|
2197
2253
|
return (data) => {
|
|
2254
|
+
if (!bound) { const t = self._coldTwin(); if (t !== null) return t.isValidObject(data); }
|
|
2198
2255
|
if (bound) return self.isValidObject(data);
|
|
2199
2256
|
bound = true;
|
|
2200
2257
|
// A validator that rewrites its input goes through the full compile, which
|
|
@@ -2234,10 +2291,14 @@ _defineLazyMethod('isValidObject', (self) => {
|
|
|
2234
2291
|
};
|
|
2235
2292
|
});
|
|
2236
2293
|
_defineLazyMethod('validateJSON', (self) => (jsonStr) => {
|
|
2294
|
+
const t = self._coldTwin();
|
|
2295
|
+
if (t !== null) return t.validateJSON(jsonStr);
|
|
2237
2296
|
self._ensureCompiled();
|
|
2238
2297
|
return self.validateJSON(jsonStr);
|
|
2239
2298
|
});
|
|
2240
2299
|
_defineLazyMethod('isValidJSON', (self) => (jsonStr) => {
|
|
2300
|
+
const t = self._coldTwin();
|
|
2301
|
+
if (t !== null) return t.isValidJSON(jsonStr);
|
|
2241
2302
|
self._ensureCompiled();
|
|
2242
2303
|
return self.isValidJSON(jsonStr);
|
|
2243
2304
|
});
|
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.45.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
|
|
67
|
+
"test": "node tests/run.js",
|
|
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.45.0",
|
|
147
|
+
"@ata-validator/native-darwin-x64": "1.45.0",
|
|
148
|
+
"@ata-validator/native-linux-arm64-gnu": "1.45.0",
|
|
149
|
+
"@ata-validator/native-linux-arm64-musl": "1.45.0",
|
|
150
|
+
"@ata-validator/native-linux-x64-gnu": "1.45.0",
|
|
151
|
+
"@ata-validator/native-linux-x64-musl": "1.45.0",
|
|
152
|
+
"@ata-validator/native-win32-x64": "1.45.0"
|
|
153
153
|
},
|
|
154
154
|
"peerDependencies": {
|
|
155
155
|
"yaml": "^2.0.0"
|