ata-validator 1.39.1 → 1.39.2
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 +8 -7
- package/index.js +12 -28
- package/lib/aot-impl.js +21 -2
- package/lib/js-compiler.js +38 -8
- package/lib/rejections.js +42 -35
- package/lib/render-pretty.js +15 -11
- package/lib/schema-order.js +18 -2
- package/lib/validator-core.js +99 -13
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@ JSON Schema validation that compiles for speed and still runs where code generat
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/ata-validator)
|
|
6
6
|
[](LICENSE)
|
|
7
|
+
[](https://scorecard.dev/viewer/?uri=github.com/ata-core/ata-validator)
|
|
7
8
|
|
|
8
9
|
1.0 is a stability commitment: see [docs/STABILITY.md](docs/STABILITY.md) for the semver, deprecation, and error-code guarantees.
|
|
9
10
|
|
|
@@ -187,16 +188,16 @@ const v = new Validator(schema, { source: { path: 'schemas/user.json', content:
|
|
|
187
188
|
const r = v.validateJSON(input)
|
|
188
189
|
if (!r.valid) {
|
|
189
190
|
console.error(renderPretty(r.errors))
|
|
190
|
-
// error[ATA3001]:
|
|
191
|
-
// --> schemas/user.json:5:
|
|
191
|
+
// error[ATA3001]: not a valid email: "not-an-email"
|
|
192
|
+
// --> schemas/user.json:5:44
|
|
192
193
|
// |
|
|
193
|
-
// 5 |
|
|
194
|
-
// |
|
|
194
|
+
// 5 | "email": { "type": "string", "format": "email" },
|
|
195
|
+
// | ^ expected format 'email'
|
|
195
196
|
// |
|
|
196
|
-
// --> input
|
|
197
|
+
// --> input:1:24 (body.email)
|
|
197
198
|
// |
|
|
198
|
-
// 1 | {"name":"
|
|
199
|
-
// |
|
|
199
|
+
// 1 | {"name":"Mert","email":"not-an-email","age":26}
|
|
200
|
+
// | ^^^^^^^^^^^^^^ found "not-an-email"
|
|
200
201
|
// |
|
|
201
202
|
// = help: missing '@' and domain part
|
|
202
203
|
// = note: see https://ata-validator.com/e/ATA3001
|
package/index.js
CHANGED
|
@@ -36,7 +36,7 @@ class TextRejection {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function installCodegenPaths (ctx) {
|
|
39
|
-
const { ABORT_EARLY_RESULT, HYBRID_TIER_CALLS, SIMDJSON_THRESHOLD, VALID_RESULT, _bindVerdict, _jsonSyntaxRejection, _mustReject, getNative, isV1Dialect, resolveSchemaByPath } = core._internals;
|
|
39
|
+
const { ABORT_EARLY_RESULT, HYBRID_TIER_CALLS, SIMDJSON_THRESHOLD, VALID_RESULT, _bindVerdict, _jsonSyntaxRejection, _mustReject, _verboseWrap, getNative, isV1Dialect, resolveSchemaByPath } = core._internals;
|
|
40
40
|
const { jsFn, _isCodegen, preprocess, fusedRemove, options, schemaObj, useSimdjsonForLarge, _buildCombined, _buildErr } = ctx;
|
|
41
41
|
// errFn: the generated error function when it is safe, else the
|
|
42
42
|
// interpreted engine, on every platform alike.
|
|
@@ -222,6 +222,11 @@ function installCodegenPaths (ctx) {
|
|
|
222
222
|
this.validate = preprocess
|
|
223
223
|
? (data) => { preprocess(data); return run(data); }
|
|
224
224
|
: run;
|
|
225
|
+
// What validate() returns for a document already known to fail, without
|
|
226
|
+
// deciding again: the lazy layer in lib/validator-core.js has its verdict
|
|
227
|
+
// and used to call validate() to get the errors, which ran the verdict a
|
|
228
|
+
// second time and built a second rejection around it.
|
|
229
|
+
if (!preprocess) ctx.rejectBase = onReject;
|
|
225
230
|
} else {
|
|
226
231
|
// No hybrid factory, so the assembly needs the function itself rather
|
|
227
232
|
// than a reference it can call later: build it now.
|
|
@@ -230,6 +235,7 @@ function installCodegenPaths (ctx) {
|
|
|
230
235
|
this.validate = preprocess
|
|
231
236
|
? (data) => { preprocess(data); return safeCombinedFn(data); }
|
|
232
237
|
: safeCombinedFn;
|
|
238
|
+
if (!preprocess) ctx.rejectBase = (data) => _mustReject(safeCombinedFn(data));
|
|
233
239
|
} else {
|
|
234
240
|
this.validate = preprocess
|
|
235
241
|
? (data) => {
|
|
@@ -237,6 +243,7 @@ function installCodegenPaths (ctx) {
|
|
|
237
243
|
return jsFn(data) ? VALID_RESULT : errOnly(data);
|
|
238
244
|
}
|
|
239
245
|
: (data) => (jsFn(data) ? VALID_RESULT : errOnly(data));
|
|
246
|
+
if (!preprocess) ctx.rejectBase = errOnly;
|
|
240
247
|
}
|
|
241
248
|
}
|
|
242
249
|
// Verbose mode: populate parentSchema, schema and data on each error, the
|
|
@@ -246,33 +253,10 @@ function installCodegenPaths (ctx) {
|
|
|
246
253
|
// migration ended up writing by hand. Errors may be frozen, so clone
|
|
247
254
|
// them with the extra fields.
|
|
248
255
|
if (this._verbose) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.validate = (
|
|
253
|
-
const result = inner(data);
|
|
254
|
-
if (result && !result.valid && result.errors) {
|
|
255
|
-
const enriched = result.errors.map((err) => {
|
|
256
|
-
if (!err || err.parentSchema !== undefined) return err;
|
|
257
|
-
const parentSchema = resolveSchemaByPath(root, err.schemaPath);
|
|
258
|
-
// The last segment of the schema path is the keyword that
|
|
259
|
-
// failed, so its value on the parent is that keyword's schema.
|
|
260
|
-
const sp = typeof err.schemaPath === 'string' ? err.schemaPath : '';
|
|
261
|
-
const last = sp.slice(sp.lastIndexOf('/') + 1).replace(/~1/g, '/').replace(/~0/g, '~');
|
|
262
|
-
const keywordSchema = (parentSchema !== null && typeof parentSchema === 'object' && last)
|
|
263
|
-
? parentSchema[last]
|
|
264
|
-
: undefined;
|
|
265
|
-
return {
|
|
266
|
-
...err,
|
|
267
|
-
parentSchema,
|
|
268
|
-
schema: keywordSchema,
|
|
269
|
-
data: resolvePointer(data, err.instancePath, undefined),
|
|
270
|
-
};
|
|
271
|
-
});
|
|
272
|
-
return { valid: false, errors: enriched };
|
|
273
|
-
}
|
|
274
|
-
return result;
|
|
275
|
-
};
|
|
256
|
+
// The verbose fields are added here, so a path around this layer would
|
|
257
|
+
// miss them.
|
|
258
|
+
ctx.rejectBase = null;
|
|
259
|
+
this.validate = _verboseWrap(this.validate, this._schemaObj);
|
|
276
260
|
}
|
|
277
261
|
// The verdict methods answer validate()'s question without building the
|
|
278
262
|
// error list, so they run the same preprocess pass. Skipping it made the
|
package/lib/aot-impl.js
CHANGED
|
@@ -186,6 +186,24 @@ function emitFormatDecls(closures, mode, declKW) {
|
|
|
186
186
|
|
|
187
187
|
const { emitClone, inlineRefsForClone } = require('./clone-emit');
|
|
188
188
|
|
|
189
|
+
// The schema-source frames the error function names, as `__ataSS[i]`. Each
|
|
190
|
+
// is built once, frozen, from a [line, col, text index] row, with every source
|
|
191
|
+
// line's text written once. Frozen, so sharing one object between reads is safe.
|
|
192
|
+
function sourceFrameDecls(frames, schemaFile) {
|
|
193
|
+
if (!frames || frames.size === 0) return '';
|
|
194
|
+
const texts = [];
|
|
195
|
+
const textIndex = new Map();
|
|
196
|
+
const rows = [];
|
|
197
|
+
for (const f of frames.values()) {
|
|
198
|
+
let i = textIndex.get(f.text);
|
|
199
|
+
if (i === undefined) { i = texts.length; texts.push(f.text); textIndex.set(f.text, i); }
|
|
200
|
+
rows[f.index] = `[${f.line},${f.col},${i}]`;
|
|
201
|
+
}
|
|
202
|
+
return `const __ataSF = ${JSON.stringify(schemaFile)};\n` +
|
|
203
|
+
`const __ataSL = ${JSON.stringify(texts)};\n` +
|
|
204
|
+
`const __ataSS = [${rows.join(',')}].map((r) => Object.freeze({ file: __ataSF, line: r[0], col: r[1], text: __ataSL[r[2]] }));\n`;
|
|
205
|
+
}
|
|
206
|
+
|
|
189
207
|
function toStandaloneModule(validator, opts) {
|
|
190
208
|
assertEmittable(validator, 'toStandaloneModule');
|
|
191
209
|
validator._ensureCompiled();
|
|
@@ -200,12 +218,13 @@ function toStandaloneModule(validator, opts) {
|
|
|
200
218
|
|
|
201
219
|
let errCore = '';
|
|
202
220
|
let jsErrFn = null;
|
|
221
|
+
const sourceFrames = new Map();
|
|
203
222
|
if (!abortEarly) {
|
|
204
223
|
jsErrFn = compileToJSCodegenWithErrors(
|
|
205
224
|
typeof validator._schemaObj === 'object' ? validator._schemaObj : {},
|
|
206
225
|
null,
|
|
207
226
|
validator._userFormats,
|
|
208
|
-
(source && sourceMap && schemaFile) ? { sourceMap, schemaFile } : null,
|
|
227
|
+
(source && sourceMap && schemaFile) ? { sourceMap, schemaFile, frames: sourceFrames } : null,
|
|
209
228
|
);
|
|
210
229
|
const errSrc = jsErrFn && jsErrFn._errSource ? jsErrFn._errSource : '';
|
|
211
230
|
if (errSrc && jsErrFn._errFactory) {
|
|
@@ -245,7 +264,7 @@ function toStandaloneModule(validator, opts) {
|
|
|
245
264
|
// entirely so size budgets and grep-based "is this source-mapped?" checks
|
|
246
265
|
// both work.
|
|
247
266
|
const schemaSourceConst = (source && schemaFile)
|
|
248
|
-
? `const __ATA_SCHEMA_SOURCE__ = ${JSON.stringify({ file: schemaFile })};\n`
|
|
267
|
+
? `const __ATA_SCHEMA_SOURCE__ = ${JSON.stringify({ file: schemaFile })};\n` + sourceFrameDecls(sourceFrames, schemaFile)
|
|
249
268
|
: '';
|
|
250
269
|
|
|
251
270
|
// Serialize closure vars referenced in _fn body: regex, sub-validators, sets.
|
package/lib/js-compiler.js
CHANGED
|
@@ -173,6 +173,7 @@ const DOC_BASE = 'https://ata-validator.com/e/'
|
|
|
173
173
|
// reader sorts by without deriving it from the path. Empty when the path is
|
|
174
174
|
// not into the root document.
|
|
175
175
|
function ordinalField (ctx, schemaPath) {
|
|
176
|
+
if (ctx && ctx.noOrdinal) return ''
|
|
176
177
|
const o = ctx && ctx.rootSchema ? ordinalFor(ctx.rootSchema, unescapeSp(schemaPath)) : null
|
|
177
178
|
return o === null ? '' : `,_o:${o}`
|
|
178
179
|
}
|
|
@@ -198,6 +199,8 @@ function unescapeSp (sp) {
|
|
|
198
199
|
return sp.indexOf('\\') === -1 ? sp : sp.replace(/\\(.)/g, '$1')
|
|
199
200
|
}
|
|
200
201
|
|
|
202
|
+
const FRAME_INLINE_MAX = 120
|
|
203
|
+
|
|
201
204
|
function buildErrorLiteral (opts) {
|
|
202
205
|
const { keyword, format, schemaPath, sourceMap } = opts
|
|
203
206
|
let code = (keyword === 'format' && format) ? codeFor('format', format) : codeFor(keyword)
|
|
@@ -214,10 +217,24 @@ function buildErrorLiteral (opts) {
|
|
|
214
217
|
const line = Array.isArray(hit) ? hit[0] : hit.line
|
|
215
218
|
const col = Array.isArray(hit) ? hit[1] : hit.col
|
|
216
219
|
const text = Array.isArray(hit) ? hit[2] : hit.text
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
if (sourceMap.frames && text.length > FRAME_INLINE_MAX) {
|
|
221
|
+
// A long source line is written once at module scope (see
|
|
222
|
+
// sourceFrameDecls in aot-impl.js) and the literal names it. Inlined,
|
|
223
|
+
// every error site carried the whole line, and a schema kept on one
|
|
224
|
+
// line is one line of all of it: 181 KB minified for a 2 KB schema.
|
|
225
|
+
// Short lines stay inline: gzip folds the repeats, and measured on
|
|
226
|
+
// the 50-field fixture the table cost 1206 gzipped bytes where the
|
|
227
|
+
// inline frames cost 696.
|
|
228
|
+
const key = line + ':' + col
|
|
229
|
+
let f = sourceMap.frames.get(key)
|
|
230
|
+
if (!f) { f = { line, col, text, index: sourceMap.frames.size }; sourceMap.frames.set(key, f) }
|
|
231
|
+
frame = ',schemaSource:__ataSS[' + f.index + ']'
|
|
232
|
+
} else {
|
|
233
|
+
frame = ',schemaSource:Object.freeze({file:' + JSON.stringify(sourceMap.file) +
|
|
234
|
+
',line:' + line +
|
|
235
|
+
',col:' + col +
|
|
236
|
+
',text:' + JSON.stringify(text) + '})'
|
|
237
|
+
}
|
|
221
238
|
}
|
|
222
239
|
}
|
|
223
240
|
return { codeStr: code, docUrl, frame }
|
|
@@ -4315,7 +4332,7 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
|
|
|
4315
4332
|
// closure parameters below the way the other entry points do.
|
|
4316
4333
|
closureVars: [], closureVals: [],
|
|
4317
4334
|
sourceMap: (sourceOpts && sourceOpts.sourceMap && sourceOpts.schemaFile)
|
|
4318
|
-
? { file: sourceOpts.schemaFile, map: sourceOpts.sourceMap }
|
|
4335
|
+
? { file: sourceOpts.schemaFile, map: sourceOpts.sourceMap, frames: sourceOpts.frames || null }
|
|
4319
4336
|
: null }
|
|
4320
4337
|
ctx.helperCode.push('const _cpLen=s=>{let n=0;for(const _ of s)n++;return n}')
|
|
4321
4338
|
const lines = []
|
|
@@ -4393,6 +4410,18 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
|
|
|
4393
4410
|
factoryBody = helpersE + 'return function(d,_all){const _e=[];\n ' + checkStr +
|
|
4394
4411
|
'\n return{valid:_e.length===0,errors:_e}}'
|
|
4395
4412
|
}
|
|
4413
|
+
// For the runtime, the literals take the legacy shape directly. `code` and
|
|
4414
|
+
// `docUrl` are there for standalone modules, which return errors as they
|
|
4415
|
+
// are; the runtime derives both from the keyword when it enriches, and
|
|
4416
|
+
// orders errors by schemaPath, so the literals carried three fields that
|
|
4417
|
+
// every read then copied the error to remove. The patterns are this
|
|
4418
|
+
// generator's own spelling; the collapse helper writes its fields with a
|
|
4419
|
+
// space and keeps them.
|
|
4420
|
+
if (sourceOpts && sourceOpts.runtimeShape) {
|
|
4421
|
+
const shape = (src) => src.replace(/code:'ATA\d{4}',/g, '').replace(/,docUrl:'https:\/\/ata-validator\.com\/e\/ATA\d{4}'/g, '').replace(/,_o:\d+/g, '')
|
|
4422
|
+
body = shape(body)
|
|
4423
|
+
factoryBody = shape(factoryBody)
|
|
4424
|
+
}
|
|
4396
4425
|
const hoistable = !ctx.usesRecursion && defSetsE.length === 0 && helpersE !== ''
|
|
4397
4426
|
if (hoistable || needsGuardE) {
|
|
4398
4427
|
const params = [...cvars, '__ataSafeRe']
|
|
@@ -5177,7 +5206,7 @@ function genIfE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
5177
5206
|
// Returns VALID_RESULT for valid data, {valid:false, errors} for invalid.
|
|
5178
5207
|
// Avoids double-pass (jsFn → false → errFn runs same checks again).
|
|
5179
5208
|
// Uses type-aware optimizations: after type check passes, skip guards.
|
|
5180
|
-
function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats) {
|
|
5209
|
+
function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats, opts) {
|
|
5181
5210
|
const inputSchema = schema
|
|
5182
5211
|
schema = normalizePropertyNames(schema)
|
|
5183
5212
|
// Same provably-local rule as the error generator above.
|
|
@@ -5257,7 +5286,8 @@ function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats) {
|
|
|
5257
5286
|
if (hasUnresolvableRef(schema, cRootDefs, cAnchors, schemaMap, new Set())) return null
|
|
5258
5287
|
if (needsBaseTracking(schema, schemaMap, new Set())) return null
|
|
5259
5288
|
|
|
5260
|
-
|
|
5289
|
+
// runtimeShape: errors without the ordinal, see compileToJSCodegenWithErrors.
|
|
5290
|
+
const ctx = { noOrdinal: !!(opts && opts.runtimeShape), varCounter: 0, helperCode: [], shared: [], closureVars: ['_cpLen'], closureVals: [_cpLen],
|
|
5261
5291
|
rootDefs: cRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: cAnchors, rootSchema: inputSchema, userFormats: userFormats || null }
|
|
5262
5292
|
const lines = []
|
|
5263
5293
|
try {
|
|
@@ -5392,7 +5422,7 @@ function genCodeCNode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
5392
5422
|
if (pathVal !== undefined) {
|
|
5393
5423
|
const spVal = unescapeSp(sp)
|
|
5394
5424
|
ctx.closureVars.push(errVar)
|
|
5395
|
-
const o = ordinalFor(ctx.rootSchema, spVal)
|
|
5425
|
+
const o = ctx.noOrdinal ? null : ordinalFor(ctx.rootSchema, spVal)
|
|
5396
5426
|
const lit = {keyword, instancePath: pathVal, schemaPath: spVal, params: Object.freeze(paramsVal), message: msgVal}
|
|
5397
5427
|
if (o !== null) lit._o = o
|
|
5398
5428
|
ctx.closureVals.push(Object.freeze(lit))
|
package/lib/rejections.js
CHANGED
|
@@ -80,49 +80,53 @@ class RichRejection {
|
|
|
80
80
|
return raw;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
// Orders a raw error list and gives it the shape the caller asked for: the
|
|
84
|
+
// legacy key set, or enriched. Shared by both rejection classes below.
|
|
85
|
+
function presentErrors(raw, data, rawInput, self, root, enrich) {
|
|
86
|
+
if (needsOrdering(raw)) raw = sortErrorsBySchemaOrder(root, raw);
|
|
87
|
+
// The position map, resolved now that an error is actually being read.
|
|
88
|
+
let positions = null;
|
|
89
|
+
if (enrich && raw.length && rawInput != null) {
|
|
90
|
+
positions = self._pos().targeted(rawInput, wantedPointersFor(raw));
|
|
91
|
+
if (positions) self._posCache.reset();
|
|
92
|
+
}
|
|
93
|
+
// One options object for the whole list, not one per error.
|
|
94
|
+
const opts = enrich && raw.length
|
|
95
|
+
? {
|
|
96
|
+
data,
|
|
97
|
+
positions,
|
|
98
|
+
schemaPositions: self._schemaPositions,
|
|
99
|
+
schemaFile: self._source ? self._source.path : undefined,
|
|
100
|
+
}
|
|
101
|
+
: null;
|
|
102
|
+
const cached = opts
|
|
103
|
+
? raw.map((e) => enrich(e, opts))
|
|
104
|
+
// The v0.14 shape is a fixed key set; the ordering key the
|
|
105
|
+
// generated code carries is dropped from it here.
|
|
106
|
+
: raw.map(stripOrdinal);
|
|
107
|
+
// Correlation is published, never applied. Both halves of a typo pair
|
|
108
|
+
// stay in the array; `related` only says they are one mistake, so a
|
|
109
|
+
// wrong pairing costs a sentence rather than a hidden violation.
|
|
110
|
+
if (enrich && cached.length > 1) attachRelated(cached);
|
|
111
|
+
// No diagnostic payload here. validate(data) is the library hot path,
|
|
112
|
+
// and attaching one cost about 100 ns per rejection for a consumer
|
|
113
|
+
// that never renders. The text path attaches it, and a renderer given
|
|
114
|
+
// `{ data }` builds frames for object input on request.
|
|
115
|
+
return cached;
|
|
116
|
+
}
|
|
117
|
+
|
|
83
118
|
Object.defineProperty(RichRejection.prototype, 'errors', {
|
|
84
119
|
enumerable: true,
|
|
85
120
|
configurable: true,
|
|
86
121
|
get() {
|
|
87
122
|
if (this._cached === null) {
|
|
88
|
-
|
|
89
|
-
const enrich = this._enrich;
|
|
90
|
-
let raw = this._result.errors || [];
|
|
91
|
-
if (needsOrdering(raw)) raw = sortErrorsBySchemaOrder(this._root, raw);
|
|
92
|
-
// The position map, resolved now that an error is actually being read.
|
|
93
|
-
let positions = null;
|
|
94
|
-
if (enrich && raw.length && this._rawInput != null) {
|
|
95
|
-
positions = self._pos().targeted(this._rawInput, wantedPointersFor(raw));
|
|
96
|
-
if (positions) self._posCache.reset();
|
|
97
|
-
}
|
|
98
|
-
// One options object for the whole list, not one per error.
|
|
99
|
-
const opts = enrich && raw.length
|
|
100
|
-
? {
|
|
101
|
-
data: this._data,
|
|
102
|
-
positions,
|
|
103
|
-
schemaPositions: self._schemaPositions,
|
|
104
|
-
schemaFile: self._source ? self._source.path : undefined,
|
|
105
|
-
}
|
|
106
|
-
: null;
|
|
107
|
-
const cached = opts
|
|
108
|
-
? raw.map((e) => enrich(e, opts))
|
|
109
|
-
// The v0.14 shape is a fixed key set; the ordering key the
|
|
110
|
-
// generated code carries is dropped from it here.
|
|
111
|
-
: raw.map(stripOrdinal);
|
|
112
|
-
// Correlation is published, never applied. Both halves of a typo pair
|
|
113
|
-
// stay in the array; `related` only says they are one mistake, so a
|
|
114
|
-
// wrong pairing costs a sentence rather than a hidden violation.
|
|
115
|
-
if (enrich && cached.length > 1) attachRelated(cached);
|
|
116
|
-
// No diagnostic payload here. validate(data) is the library hot path,
|
|
117
|
-
// and attaching one cost about 100 ns per rejection for a consumer
|
|
118
|
-
// that never renders. The text path attaches it, and a renderer given
|
|
119
|
-
// `{ data }` builds frames for object input on request.
|
|
120
|
-
this._cached = cached;
|
|
123
|
+
this._cached = presentErrors(this._result.errors || [], this._data, this._rawInput, this._self, this._root, this._enrich);
|
|
121
124
|
}
|
|
122
125
|
return this._cached;
|
|
123
126
|
},
|
|
124
127
|
});
|
|
125
128
|
|
|
129
|
+
|
|
126
130
|
// The rejection validateJSON returns. Everything the text path adds over
|
|
127
131
|
// validate(data), the value tree enrichment needs, the position map, the
|
|
128
132
|
// diagnostic payload, happens on first access to `.errors`. Reading `.valid`
|
|
@@ -256,7 +260,10 @@ function wantedPointersFor (errors) {
|
|
|
256
260
|
const COLLAPSE_CODES = new Set(['ATA4001', 'ATA4002', 'ATA4003']);
|
|
257
261
|
function stripOrdinal(e) {
|
|
258
262
|
if (e === null || typeof e !== 'object') return e;
|
|
259
|
-
|
|
263
|
+
// Generated code keeps errors at a fixed path as frozen literals shared by
|
|
264
|
+
// every call. The caller gets its own copy, as it always has, so an error it
|
|
265
|
+
// edits (a translated message) is its own and editing it does not throw.
|
|
266
|
+
if (e._o === undefined && e.docUrl === undefined && (e.code === undefined || COLLAPSE_CODES.has(e.code)) && !e.branchErrors) return Object.isFrozen(e) ? { ...e } : e;
|
|
260
267
|
const out = {};
|
|
261
268
|
for (const k in e) {
|
|
262
269
|
if (k === '_o' || k === 'docUrl') continue;
|
|
@@ -364,4 +371,4 @@ function attachRelated (errors) {
|
|
|
364
371
|
return errors;
|
|
365
372
|
}
|
|
366
373
|
|
|
367
|
-
module.exports = { LazyRejection, RichRejection, LazyJsonRejection, _enrichLazy, attachRelated, sortErrorsBySchemaOrder, stripOrdinal, wantedPointersFor };
|
|
374
|
+
module.exports = { LazyRejection, RichRejection, presentErrors, needsOrdering, LazyJsonRejection, _enrichLazy, attachRelated, sortErrorsBySchemaOrder, stripOrdinal, wantedPointersFor };
|
package/lib/render-pretty.js
CHANGED
|
@@ -42,7 +42,11 @@ function caretSuffix (d, raw, useColor) {
|
|
|
42
42
|
function renderOne (d, useColor, opts) {
|
|
43
43
|
const lines = [];
|
|
44
44
|
const width = terminalWidth();
|
|
45
|
-
|
|
45
|
+
// The bar sits one column past the widest line number, so the source line,
|
|
46
|
+
// the blank rows and the caret row share it and a caret lands on the first
|
|
47
|
+
// character of the value, not one column to its left.
|
|
48
|
+
const bar = (line) => ' '.repeat(Math.max(3, String(line).length + 1)) + '|';
|
|
49
|
+
const src = (line, text) => String(line).padStart(Math.max(2, String(line).length)) + ' | ' + text;
|
|
46
50
|
|
|
47
51
|
// Headline carries the code when there is one. A code-less error, which the
|
|
48
52
|
// LazyRejection fallback can produce, must not render as "error[undefined]".
|
|
@@ -57,12 +61,12 @@ function renderOne (d, useColor, opts) {
|
|
|
57
61
|
if (raw && raw.schemaSource) {
|
|
58
62
|
const f = trimCwd(raw.schemaSource.file, opts.cwd);
|
|
59
63
|
lines.push(` --> ${color(useColor, ANSI.cyan, `${f}:${raw.schemaSource.line}:${raw.schemaSource.col}`)}`);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
lines.push(
|
|
64
|
+
const sl = raw.schemaSource.line;
|
|
65
|
+
lines.push(bar(sl));
|
|
66
|
+
lines.push(src(sl, truncateLine(raw.schemaSource.text, width - 8)));
|
|
63
67
|
const inlineHint = raw.expected ? ' ' + color(useColor, ANSI.dim, `expected ${raw.expected}`) : '';
|
|
64
|
-
lines.push(caretLine(raw.schemaSource.col, 1,
|
|
65
|
-
lines.push(
|
|
68
|
+
lines.push(caretLine(raw.schemaSource.col, 1, bar(sl).length - 1) + inlineHint);
|
|
69
|
+
lines.push(bar(sl));
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// Data location, always, even without a frame. This is the single most
|
|
@@ -70,11 +74,11 @@ function renderOne (d, useColor, opts) {
|
|
|
70
74
|
if (d.frame) {
|
|
71
75
|
const where = `input:${d.frame.line}:${d.frame.col}`;
|
|
72
76
|
lines.push(` --> ${color(useColor, ANSI.cyan, where)} ${color(useColor, ANSI.dim, '(' + d.dotted + ')')}`);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
lines.push(
|
|
76
|
-
lines.push(caretLine(d.frame.col, d.frame.length,
|
|
77
|
-
lines.push(
|
|
77
|
+
const fl = d.frame.line;
|
|
78
|
+
lines.push(bar(fl));
|
|
79
|
+
lines.push(src(fl, truncateLine(d.frame.text, width - 8)));
|
|
80
|
+
lines.push(caretLine(d.frame.col, d.frame.length, bar(fl).length - 1) + caretSuffix(d, raw, useColor));
|
|
81
|
+
lines.push(bar(fl));
|
|
78
82
|
} else {
|
|
79
83
|
lines.push(` --> ${color(useColor, ANSI.cyan, 'at ' + d.dotted)}`);
|
|
80
84
|
}
|
package/lib/schema-order.js
CHANGED
|
@@ -156,6 +156,14 @@ function ordinalFor(rootSchema, schemaPath) {
|
|
|
156
156
|
const map = ordinals(rootSchema);
|
|
157
157
|
const hit = map.get(schemaPath);
|
|
158
158
|
if (hit !== undefined) return hit;
|
|
159
|
+
// A path that is not a node is answered from the cache below, filled by the
|
|
160
|
+
// walk after it: every error behind a `$ref`, which is every error of a
|
|
161
|
+
// schema the interpreter answers through references, used to walk its path
|
|
162
|
+
// back segment by segment on every read.
|
|
163
|
+
let misses = _missCache.get(rootSchema);
|
|
164
|
+
if (misses === undefined) { misses = new Map(); _missCache.set(rootSchema, misses); }
|
|
165
|
+
const known = misses.get(schemaPath);
|
|
166
|
+
if (known !== undefined) return known;
|
|
159
167
|
// Walk back to the longest prefix that exists. Paths through a keyword's
|
|
160
168
|
// value that is a primitive, or through a key the schema does not have,
|
|
161
169
|
// land on the nearest enclosing node.
|
|
@@ -163,16 +171,24 @@ function ordinalFor(rootSchema, schemaPath) {
|
|
|
163
171
|
// behind a reference sort where the `$ref` is declared among its siblings;
|
|
164
172
|
// rankFor orders them among themselves.
|
|
165
173
|
let p = schemaPath;
|
|
174
|
+
let found = 0;
|
|
166
175
|
while (true) {
|
|
167
176
|
const cut = p.lastIndexOf('/');
|
|
168
|
-
if (cut < 0)
|
|
177
|
+
if (cut < 0) break;
|
|
169
178
|
p = p.slice(0, cut);
|
|
170
179
|
const o = map.get(p);
|
|
171
180
|
if (o !== undefined) {
|
|
172
181
|
const r = map.get(p + '/$ref');
|
|
173
|
-
|
|
182
|
+
found = r !== undefined ? r : o;
|
|
183
|
+
break;
|
|
174
184
|
}
|
|
175
185
|
}
|
|
186
|
+
// Bounded: behind a recursive reference the paths grow with the document's
|
|
187
|
+
// depth, and the cache must not grow with them.
|
|
188
|
+
if (misses.size < MISS_CACHE_LIMIT) misses.set(schemaPath, found);
|
|
189
|
+
return found;
|
|
176
190
|
}
|
|
191
|
+
const _missCache = new WeakMap();
|
|
192
|
+
const MISS_CACHE_LIMIT = 4096;
|
|
177
193
|
|
|
178
194
|
module.exports = { rankFor, ordinalFor, unescapePointerSegment };
|
package/lib/validator-core.js
CHANGED
|
@@ -292,7 +292,7 @@ function resolveSchemaByPath(rootSchema, schemaPath) {
|
|
|
292
292
|
//
|
|
293
293
|
// A failing route sees the same handful of schemaPaths over and over, which is
|
|
294
294
|
// what makes the first one worth having.
|
|
295
|
-
const { LazyRejection, RichRejection, LazyJsonRejection, _enrichLazy } = require('./rejections');
|
|
295
|
+
const { LazyRejection, RichRejection, LazyJsonRejection, _enrichLazy, presentErrors, needsOrdering, sortErrorsBySchemaOrder } = require('./rejections');
|
|
296
296
|
|
|
297
297
|
// Text that does not parse, reported the same way on every path and platform:
|
|
298
298
|
// ATA9001 with the parser's own message. The native addon used to say only
|
|
@@ -991,20 +991,28 @@ class Validator {
|
|
|
991
991
|
};
|
|
992
992
|
const _buildCombined = () => {
|
|
993
993
|
if (jsCombinedFn !== undefined) return;
|
|
994
|
-
jsCombinedFn = compileToJSCombined(schemaObj, VALID_RESULT, sm, this._userFormats) || null;
|
|
994
|
+
jsCombinedFn = compileToJSCombined(schemaObj, VALID_RESULT, sm, this._userFormats, { runtimeShape: true }) || null;
|
|
995
995
|
_upgradeCacheEntry();
|
|
996
996
|
};
|
|
997
997
|
const _buildErr = () => {
|
|
998
998
|
if (jsErrFn !== undefined) return;
|
|
999
|
-
jsErrFn = compileToJSCodegenWithErrors(schemaObj, sm, this._userFormats) || null;
|
|
999
|
+
jsErrFn = compileToJSCodegenWithErrors(schemaObj, sm, this._userFormats, { runtimeShape: true }) || null;
|
|
1000
1000
|
_upgradeCacheEntry();
|
|
1001
1001
|
};
|
|
1002
1002
|
|
|
1003
|
+
// What validate() returns for a document already known to fail, without
|
|
1004
|
+
// deciding again, when the codegen paths can say (see index.js). Kept in
|
|
1005
|
+
// locals and on this object rather than on the instance: every call reads
|
|
1006
|
+
// `validate` off the instance, and three more own properties made that
|
|
1007
|
+
// read slower across the suite's validators.
|
|
1008
|
+
let _rejectBase = null, _rejectPresented = null, _rejectPlain = false;
|
|
1003
1009
|
if (jsFn) {
|
|
1004
|
-
|
|
1010
|
+
const _cg = {
|
|
1005
1011
|
jsFn, _isCodegen, preprocess, fusedRemove, options, schemaObj, useSimdjsonForLarge, _buildCombined, _buildErr,
|
|
1006
|
-
combined: () => jsCombinedFn, err: () => jsErrFn,
|
|
1007
|
-
}
|
|
1012
|
+
combined: () => jsCombinedFn, err: () => jsErrFn, rejectBase: null,
|
|
1013
|
+
};
|
|
1014
|
+
_codegen.installPaths.call(this, _cg);
|
|
1015
|
+
_rejectBase = _cg.rejectBase;
|
|
1008
1016
|
} else {
|
|
1009
1017
|
// No JS codegen: the interpreted engine, with or without the addon. The
|
|
1010
1018
|
// buffer APIs come from _installBufferApis on first use, as they do on
|
|
@@ -1030,7 +1038,9 @@ class Validator {
|
|
|
1030
1038
|
: (preprocess
|
|
1031
1039
|
? (data) => { preprocess(data); return interp.validate(data); }
|
|
1032
1040
|
: (data) => interp.validate(data));
|
|
1033
|
-
this.validate = run;
|
|
1041
|
+
this.validate = this._verbose ? _verboseWrap(run, schemaObj) : run;
|
|
1042
|
+
// Reading errors runs the interpreter once, directly; see _rejectBase.
|
|
1043
|
+
if (!preprocess && !options.abortEarly && !this._verbose) _rejectBase = (data) => interp.validate(data);
|
|
1034
1044
|
_bindVerdict(this, this._fastVerdict
|
|
1035
1045
|
? this._fastVerdict
|
|
1036
1046
|
: (data) => run(data).valid);
|
|
@@ -1059,8 +1069,7 @@ class Validator {
|
|
|
1059
1069
|
const enrich = this._richErrors ? _enrichLazy : null;
|
|
1060
1070
|
const root = this._schemaObj;
|
|
1061
1071
|
const self = this;
|
|
1062
|
-
|
|
1063
|
-
const result = inner(data);
|
|
1072
|
+
const present = (result, data) => {
|
|
1064
1073
|
// abortEarly returns the shared ATA9000 stub; preserve it as-is so the
|
|
1065
1074
|
// perf fast path stays allocation-free and the documented code stays stable.
|
|
1066
1075
|
if (result && result.valid === false && result !== ABORT_EARLY_RESULT) {
|
|
@@ -1076,6 +1085,13 @@ class Validator {
|
|
|
1076
1085
|
}
|
|
1077
1086
|
return result;
|
|
1078
1087
|
};
|
|
1088
|
+
this.validate = (data) => present(inner(data), data);
|
|
1089
|
+
// The same presentation for a document already known to fail.
|
|
1090
|
+
const rejectBase = _rejectBase;
|
|
1091
|
+
_rejectPresented = rejectBase ? (data) => present(rejectBase(data), data) : null;
|
|
1092
|
+
// True while nothing but this layer stands between a rejection and the
|
|
1093
|
+
// caller; the lazy layer below can then build the rejection itself.
|
|
1094
|
+
_rejectPlain = !!rejectBase;
|
|
1079
1095
|
|
|
1080
1096
|
// validateJSON also enriches: set _lastRawInput so the position cache
|
|
1081
1097
|
// can lazily build a map for dataFrame attachment. Only validateJSON
|
|
@@ -1149,6 +1165,8 @@ class Validator {
|
|
|
1149
1165
|
return result;
|
|
1150
1166
|
};
|
|
1151
1167
|
if (this.validate) this.validate = wrap(this.validate);
|
|
1168
|
+
if (_rejectPresented) _rejectPresented = wrap(_rejectPresented);
|
|
1169
|
+
_rejectPlain = false;
|
|
1152
1170
|
if (this.validateJSON) this.validateJSON = wrap(this.validateJSON);
|
|
1153
1171
|
// validateAndParse routes through self.validate on the codegen path, but
|
|
1154
1172
|
// the native-only path returns directly from the addon — wrap it so both
|
|
@@ -1185,7 +1203,13 @@ class Validator {
|
|
|
1185
1203
|
const _vx = this._validateTail !== null ? this._validateTail() : null;
|
|
1186
1204
|
let _vxApplied = false;
|
|
1187
1205
|
if (this._fastVerdict && !preprocess && !options.abortEarly && this.validate) {
|
|
1188
|
-
|
|
1206
|
+
// The errors of a document the verdict rejected come from the rejection
|
|
1207
|
+
// path directly, not from validate() deciding a second time. Not with a
|
|
1208
|
+
// check from _extendValidate: that check can reject what the schema
|
|
1209
|
+
// accepts, and then the schema's own errors must come from a verdict.
|
|
1210
|
+
// Not with removeAdditional's fused pass either, which edits the
|
|
1211
|
+
// document before the errors are read.
|
|
1212
|
+
const _full = (_vx === null && !fusedRemove && _rejectPresented) ? _rejectPresented : this.validate;
|
|
1189
1213
|
const _fast = _vx ? _fuseTail(this._fastVerdict, _vx.check) : this._fastVerdict;
|
|
1190
1214
|
const _extra = _vx ? _vx.errors : null;
|
|
1191
1215
|
_vxApplied = true;
|
|
@@ -1198,11 +1222,19 @@ class Validator {
|
|
|
1198
1222
|
// verdict and say so rather than inventing a specific error.
|
|
1199
1223
|
return own || _verdictFallback;
|
|
1200
1224
|
};
|
|
1201
|
-
|
|
1225
|
+
// The common case: the verdict decides, and reading `errors` runs the
|
|
1226
|
+
// error function and presents its list directly. Through the layers it
|
|
1227
|
+
// took a second verdict and a second rejection object, about 75 ns of a
|
|
1228
|
+
// 96 ns read on a two-error document. validate() below is the same code
|
|
1229
|
+
// either way, so reading only `.valid` costs what it did.
|
|
1230
|
+
const _plain = (_vx === null && !fusedRemove && _rejectPlain)
|
|
1231
|
+
? _plainBuilders(_rejectBase, this._richErrors ? _enrichLazy : null, this._schemaObj, this, _verdictFallback)
|
|
1232
|
+
: null;
|
|
1233
|
+
const _buildErrors = _plain !== null ? _plain.errors : (data) => {
|
|
1202
1234
|
const r = _full(data);
|
|
1203
1235
|
return _withExtra((r && r.valid === false && r.errors && r.errors.length) ? r.errors : null, data);
|
|
1204
1236
|
};
|
|
1205
|
-
const _buildRawErrors = (data) => {
|
|
1237
|
+
const _buildRawErrors = _plain !== null ? _plain.raw : (data) => {
|
|
1206
1238
|
const r = _full(data);
|
|
1207
1239
|
let raw = null;
|
|
1208
1240
|
if (r && r.valid === false) {
|
|
@@ -1700,6 +1732,60 @@ const _VERDICT_DISAGREES = Object.freeze({
|
|
|
1700
1732
|
valid: false,
|
|
1701
1733
|
errors: Object.freeze([Object.freeze({ keyword: 'validation', instancePath: '', schemaPath: '#', params: Object.freeze({}), message: 'schema validation failed' })]),
|
|
1702
1734
|
});
|
|
1735
|
+
// The error builders of the common rejection path (see _ensureCompiled): run
|
|
1736
|
+
// the error function behind `reject` for a document the verdict rejected, and
|
|
1737
|
+
// order and present its list. Out here so the closures capture only this.
|
|
1738
|
+
function _plainBuilders(reject, enrich, root, self, fallback) {
|
|
1739
|
+
const rawOf = (data) => {
|
|
1740
|
+
const r = reject(data);
|
|
1741
|
+
const errors = r && r.errors;
|
|
1742
|
+
return errors && errors.length ? errors : fallback;
|
|
1743
|
+
};
|
|
1744
|
+
return {
|
|
1745
|
+
errors: (data) => presentErrors(rawOf(data), data, null, self, root, enrich),
|
|
1746
|
+
raw: (data) => {
|
|
1747
|
+
const raw = rawOf(data);
|
|
1748
|
+
return needsOrdering(raw) ? sortErrorsBySchemaOrder(root, raw) : raw;
|
|
1749
|
+
},
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// Verbose mode: populate parentSchema, schema and data on each error, the
|
|
1754
|
+
// three fields the default error shape carries under the same option. `data`
|
|
1755
|
+
// is the value the error points at; without it a caller has to walk the
|
|
1756
|
+
// document by the instance path itself, which is what one migration ended up
|
|
1757
|
+
// writing by hand. Errors may be frozen, so they are cloned with the extra
|
|
1758
|
+
// fields. Both engines go through this; the interpreted one used to skip it,
|
|
1759
|
+
// so the same validator reported different fields depending on which engine
|
|
1760
|
+
// answered.
|
|
1761
|
+
function _verboseWrap(inner, root) {
|
|
1762
|
+
const { resolvePointer } = require('./pointer.js');
|
|
1763
|
+
return (data) => {
|
|
1764
|
+
const result = inner(data);
|
|
1765
|
+
if (result && !result.valid && result.errors) {
|
|
1766
|
+
const enriched = result.errors.map((err) => {
|
|
1767
|
+
if (!err || err.parentSchema !== undefined) return err;
|
|
1768
|
+
const parentSchema = resolveSchemaByPath(root, err.schemaPath);
|
|
1769
|
+
// The last segment of the schema path is the keyword that
|
|
1770
|
+
// failed, so its value on the parent is that keyword's schema.
|
|
1771
|
+
const sp = typeof err.schemaPath === 'string' ? err.schemaPath : '';
|
|
1772
|
+
const last = sp.slice(sp.lastIndexOf('/') + 1).replace(/~1/g, '/').replace(/~0/g, '~');
|
|
1773
|
+
const keywordSchema = (parentSchema !== null && typeof parentSchema === 'object' && last)
|
|
1774
|
+
? parentSchema[last]
|
|
1775
|
+
: undefined;
|
|
1776
|
+
return {
|
|
1777
|
+
...err,
|
|
1778
|
+
parentSchema,
|
|
1779
|
+
schema: keywordSchema,
|
|
1780
|
+
data: resolvePointer(data, err.instancePath, undefined),
|
|
1781
|
+
};
|
|
1782
|
+
});
|
|
1783
|
+
return { valid: false, errors: enriched };
|
|
1784
|
+
}
|
|
1785
|
+
return result;
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1703
1789
|
function _mustReject(r) {
|
|
1704
1790
|
return r && r.valid === false ? r : _VERDICT_DISAGREES;
|
|
1705
1791
|
}
|
|
@@ -2063,4 +2149,4 @@ module.exports = {
|
|
|
2063
2149
|
// surface of `require('ata-validator')` is what it was.
|
|
2064
2150
|
Object.defineProperty(module.exports, '_registerCodegen', { value: _registerCodegen, enumerable: false });
|
|
2065
2151
|
// What the compiled paths in index.js need from this module.
|
|
2066
|
-
Object.defineProperty(module.exports, '_internals', { value: { _jsonSyntaxRejection, ABORT_EARLY_RESULT, HYBRID_TIER_CALLS, SIMDJSON_THRESHOLD, VALID_RESULT, _bindEntry, _bindVerdict, _compileCache, _mustReject, _rememberInstance, compileCacheKey, getNative, isV1Dialect, resolveSchemaByPath }, enumerable: false });
|
|
2152
|
+
Object.defineProperty(module.exports, '_internals', { value: { _jsonSyntaxRejection, ABORT_EARLY_RESULT, HYBRID_TIER_CALLS, SIMDJSON_THRESHOLD, VALID_RESULT, _bindEntry, _bindVerdict, _compileCache, _mustReject, _rememberInstance, _verboseWrap, compileCacheKey, getNative, isV1Dialect, resolveSchemaByPath }, enumerable: false });
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.39.
|
|
3
|
+
"version": "1.39.2",
|
|
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",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"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",
|
|
60
60
|
"build": "cmake-js build --target ata",
|
|
61
61
|
"rebuild": "cmake-js rebuild --target ata",
|
|
62
|
-
"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_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_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_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_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",
|
|
62
|
+
"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_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_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_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",
|
|
63
63
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
64
64
|
"test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
|
|
65
65
|
"test:compat": "node tests/test_compat.js",
|
|
@@ -135,13 +135,13 @@
|
|
|
135
135
|
"LICENSE"
|
|
136
136
|
],
|
|
137
137
|
"optionalDependencies": {
|
|
138
|
-
"@ata-validator/native-darwin-arm64": "1.39.
|
|
139
|
-
"@ata-validator/native-darwin-x64": "1.39.
|
|
140
|
-
"@ata-validator/native-linux-arm64-gnu": "1.39.
|
|
141
|
-
"@ata-validator/native-linux-arm64-musl": "1.39.
|
|
142
|
-
"@ata-validator/native-linux-x64-gnu": "1.39.
|
|
143
|
-
"@ata-validator/native-linux-x64-musl": "1.39.
|
|
144
|
-
"@ata-validator/native-win32-x64": "1.39.
|
|
138
|
+
"@ata-validator/native-darwin-arm64": "1.39.2",
|
|
139
|
+
"@ata-validator/native-darwin-x64": "1.39.2",
|
|
140
|
+
"@ata-validator/native-linux-arm64-gnu": "1.39.2",
|
|
141
|
+
"@ata-validator/native-linux-arm64-musl": "1.39.2",
|
|
142
|
+
"@ata-validator/native-linux-x64-gnu": "1.39.2",
|
|
143
|
+
"@ata-validator/native-linux-x64-musl": "1.39.2",
|
|
144
|
+
"@ata-validator/native-win32-x64": "1.39.2"
|
|
145
145
|
},
|
|
146
146
|
"peerDependencies": {
|
|
147
147
|
"yaml": "^2.0.0"
|