ata-validator 1.63.2 → 1.63.3
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/lib/branch-collapse.js +16 -8
- package/lib/draft7.js +14 -1
- package/lib/ir/emit.mjs +9 -3
- package/lib/js-compiler-errors.js +14 -8
- package/lib/js-compiler.js +33 -13
- package/lib/kernels/collapse.mjs +16 -8
- package/lib/schema-scan.js +3 -2
- package/lib/unique-items-source.js +3 -0
- package/lib/version.js +1 -1
- package/package.json +8 -8
package/lib/branch-collapse.js
CHANGED
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
// module imports nothing, so the generated code cannot require this file; it
|
|
10
10
|
// carries a copy emitted by `embedSource()` from these very functions instead
|
|
11
11
|
// of a second hand-written one. That is why the internals are written in the
|
|
12
|
-
// positional form the generated code calls, and why
|
|
13
|
-
//
|
|
14
|
-
//
|
|
12
|
+
// positional form the generated code calls, and why each function reaches the
|
|
13
|
+
// others only through properties on itself (`__ataCollapse.F`, `.M`,
|
|
14
|
+
// `__ataScore.S`): a bundler that minifies names renames a function and every
|
|
15
|
+
// call to it, and the text toString() gives then called names the embed did
|
|
16
|
+
// not declare. A function's reference to its own name stays consistent, and
|
|
17
|
+
// property names are not renamed.
|
|
15
18
|
|
|
16
19
|
// How much a failing keyword says about intent. A branch that fails on `type`
|
|
17
20
|
// was probably not the branch the author meant; one that fails on `minLength`
|
|
@@ -35,10 +38,12 @@ const __ATA_SEVERITY = {
|
|
|
35
38
|
|
|
36
39
|
function __ataScore (errs) {
|
|
37
40
|
if (!errs || !errs.length) return 0;
|
|
41
|
+
const sev = __ataScore.S;
|
|
38
42
|
let s = 0;
|
|
39
|
-
for (const e of errs) s +=
|
|
43
|
+
for (const e of errs) s += sev[e.keyword] || 4;
|
|
40
44
|
return errs.length * 100 + s; // primary: count, secondary: severity
|
|
41
45
|
}
|
|
46
|
+
__ataScore.S = __ATA_SEVERITY;
|
|
42
47
|
|
|
43
48
|
// `br` is one entry per branch in declaration order: {valid, errors} and a
|
|
44
49
|
// `title`, or the titles in `titles` when given (the generated code passes
|
|
@@ -68,7 +73,7 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
68
73
|
if (pass.length > 1) {
|
|
69
74
|
const passIdx = [];
|
|
70
75
|
for (let i = 0; i < br.length; i++) if (br[i].valid) passIdx.push(i);
|
|
71
|
-
return
|
|
76
|
+
return __ataCollapse.M(passIdx, br.length, pp, sp, o);
|
|
72
77
|
}
|
|
73
78
|
} else if (pass.length >= 1) {
|
|
74
79
|
return null;
|
|
@@ -76,7 +81,7 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
76
81
|
let bi = 0;
|
|
77
82
|
let bs = Infinity;
|
|
78
83
|
for (let i = 0; i < br.length; i++) {
|
|
79
|
-
const s =
|
|
84
|
+
const s = __ataCollapse.F(br[i].errors);
|
|
80
85
|
if (s < bs) { bs = s; bi = i; }
|
|
81
86
|
}
|
|
82
87
|
const best = br[bi];
|
|
@@ -97,6 +102,9 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
97
102
|
return none;
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
__ataCollapse.M = __ataMulti;
|
|
106
|
+
__ataCollapse.F = __ataScore;
|
|
107
|
+
|
|
100
108
|
// The named-argument form the interpreter and the tests call.
|
|
101
109
|
function collapseBranches ({ keyword, branchResults, parentPath, parentSchemaPath, ordinal }) {
|
|
102
110
|
return __ataCollapse(keyword, branchResults, parentPath, parentSchemaPath, ordinal === undefined ? null : ordinal);
|
|
@@ -107,9 +115,9 @@ function collapseBranches ({ keyword, branchResults, parentPath, parentSchemaPat
|
|
|
107
115
|
// cannot miss the other. `tests/test_branch_collapse.js` runs both.
|
|
108
116
|
function embedSource () {
|
|
109
117
|
return 'const __ATA_SEVERITY=' + JSON.stringify(__ATA_SEVERITY) + ';' +
|
|
110
|
-
'const __ataScore=' + __ataScore.toString() + ';' +
|
|
118
|
+
'const __ataScore=' + __ataScore.toString() + ';__ataScore.S=__ATA_SEVERITY;' +
|
|
111
119
|
'const __ataMulti=' + __ataMulti.toString() + ';' +
|
|
112
|
-
'const __ataCollapse=' + __ataCollapse.toString() + ';';
|
|
120
|
+
'const __ataCollapse=' + __ataCollapse.toString() + ';__ataCollapse.M=__ataMulti;__ataCollapse.F=__ataScore;';
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
module.exports = { collapseBranches, scoreBranch: __ataScore, SEVERITY: __ATA_SEVERITY, embedSource, _collapse: __ataCollapse, _multi: __ataMulti };
|
package/lib/draft7.js
CHANGED
|
@@ -20,6 +20,7 @@ function isDraft6(schema) {
|
|
|
20
20
|
// of its own, which is how a retrieved schema inherits the root's draft.
|
|
21
21
|
// `draft6` says the document, or the root it inherits from, is draft-06.
|
|
22
22
|
// `draft4`: draft-04, read as draft-06 plus its own differences (below).
|
|
23
|
+
const PLAIN_NAME_ID = /^#[A-Za-z][A-Za-z0-9_.:-]*$/
|
|
23
24
|
function normalizeDraft7(schema, force, draft6, draft4) {
|
|
24
25
|
if (!force && !isDraft7(schema)) return schema
|
|
25
26
|
const d4 = draft4 === true || (typeof schema.$schema === 'string' && DRAFT4_SCHEMAS.has(schema.$schema))
|
|
@@ -57,7 +58,7 @@ function _normalize(schema, d6, d4) {
|
|
|
57
58
|
|
|
58
59
|
// A fragment-only `$id` is a plain-name anchor in draft-07; 2020-12 spells
|
|
59
60
|
// it `$anchor`, which every engine already resolves.
|
|
60
|
-
if (typeof schema.$id === 'string' &&
|
|
61
|
+
if (typeof schema.$id === 'string' && PLAIN_NAME_ID.test(schema.$id)) {
|
|
61
62
|
if (schema.$anchor === undefined) schema.$anchor = schema.$id.slice(1)
|
|
62
63
|
delete schema.$id
|
|
63
64
|
}
|
|
@@ -214,6 +215,18 @@ function _normalizeNullable(schema, st) {
|
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
if ('nullable' in schema) delete schema.nullable
|
|
218
|
+
// A fragment-only `$id` (`#name`) is draft-07's spelling of an anchor, and
|
|
219
|
+
// schemas that declare no dialect are written with it too. normalizeDraft7
|
|
220
|
+
// folds it into `$anchor` under a declared older dialect; without one each
|
|
221
|
+
// engine read it its own way: the code generators took it as an anchor on
|
|
222
|
+
// the root and the root's definitions only, and where such a schema
|
|
223
|
+
// referred to itself they wrote nothing at the cycle, so every constraint
|
|
224
|
+
// past the first level was dropped and the document accepted. Folded here,
|
|
225
|
+
// on the walk every dialect runs, there is one spelling for every engine.
|
|
226
|
+
if (typeof schema.$id === 'string' && PLAIN_NAME_ID.test(schema.$id)) {
|
|
227
|
+
if (schema.$anchor === undefined) schema.$anchor = schema.$id.slice(1)
|
|
228
|
+
delete schema.$id
|
|
229
|
+
}
|
|
217
230
|
// A JSON Pointer in a URI fragment is percent-encoded, so a definition named
|
|
218
231
|
// `Node<Row>` is reached by `#/definitions/Node%3CRow%3E` (RFC 6901, section
|
|
219
232
|
// 6). The interpreter decodes the fragment; the code generator compared the
|
package/lib/ir/emit.mjs
CHANGED
|
@@ -48,7 +48,11 @@ function inline (fn, vExpr, nExpr) {
|
|
|
48
48
|
const src = fn.toString()
|
|
49
49
|
const m = /^\(\s*v\s*(?:,\s*n\s*)?\)\s*=>\s*([\s\S]+)$/.exec(src)
|
|
50
50
|
if (!m) throw new Error('ir: kernel ok() must be (v, n) => expression: ' + src)
|
|
51
|
-
|
|
51
|
+
// One pass, by function: the expressions carry text from the schema (a
|
|
52
|
+
// property name inside `d["..."]`), which a second pass would search for
|
|
53
|
+
// `n`, and which replace() would search for `$&` and its kin if it were
|
|
54
|
+
// given as the replacement itself.
|
|
55
|
+
return '(' + m[1].replace(/\b[vn]\b/g, (x) => x === 'v' ? vExpr : nExpr) + ')'
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
// How many names an object must list before a module visits the object's own
|
|
@@ -685,14 +689,16 @@ export function specialize (schema, opts = {}) {
|
|
|
685
689
|
const own = typeof opts.fillSource === 'function' && !opts.schemas ? opts.fillSource(schema) : null
|
|
686
690
|
if (typeof own === 'string') {
|
|
687
691
|
return src
|
|
688
|
-
.replace('export function isValid(d){return ', `function FILL(d){\n${own}\n}\nexport function isValid(d){FILL(d);return `)
|
|
692
|
+
.replace('export function isValid(d){return ', () => `function FILL(d){\n${own}\n}\nexport function isValid(d){FILL(d);return `)
|
|
689
693
|
.replace('export function validate(d){', 'export function validate(d){FILL(d);')
|
|
690
694
|
}
|
|
691
695
|
// The shared default pass (lib/defaults.js), built from the normalized
|
|
692
696
|
// schema at load.
|
|
693
697
|
return src
|
|
694
698
|
.replace(/^import \{([^}]*)\} from /m, (m, list) => `import {${['buildDefaultsApplier', ...list.split(',')].filter(Boolean).sort().join(',')}} from `)
|
|
695
|
-
|
|
699
|
+
// By function: a replacement given as text is searched for `$&`, `` $` ``,
|
|
700
|
+
// `$'` and `$$`, and a schema's descriptions and defaults hold them.
|
|
701
|
+
.replace('export function isValid(d){return ', () => `const FILL=buildDefaultsApplier(${JSON.stringify(ir.schema)})\nexport function isValid(d){FILL(d);return `)
|
|
696
702
|
.replace('export function validate(d){', 'export function validate(d){FILL(d);')
|
|
697
703
|
}
|
|
698
704
|
|
|
@@ -683,7 +683,7 @@ function countingBody (body) {
|
|
|
683
683
|
j++
|
|
684
684
|
}
|
|
685
685
|
if (depth !== 0) return null
|
|
686
|
-
body = body.slice(0, b) + (unknown ? 'return -1' : '(
|
|
686
|
+
body = body.slice(0, b) + (unknown ? 'return -1' : '(_scn++,_scs+=4)') + body.slice(j)
|
|
687
687
|
}
|
|
688
688
|
if (/\b(?:_defE\d|__ataCollapse|__ataMulti|_brf\d|_bsf\d)/.test(body)) return null
|
|
689
689
|
const SEV = require('./branch-collapse').SEVERITY
|
|
@@ -691,7 +691,8 @@ function countingBody (body) {
|
|
|
691
691
|
let i = 0
|
|
692
692
|
const head = 'const _e=[];'
|
|
693
693
|
if (!body.startsWith(head)) return null
|
|
694
|
-
|
|
694
|
+
// Not `_n`: the inline format checks declare it as a const.
|
|
695
|
+
out += 'let _scn=0,_scs=0;'
|
|
695
696
|
i = head.length
|
|
696
697
|
while (i < body.length) {
|
|
697
698
|
const ch = body[i]
|
|
@@ -711,13 +712,13 @@ function countingBody (body) {
|
|
|
711
712
|
// The literal may still carry its `code` (the shape pass strips it).
|
|
712
713
|
const m = /^\{(?:code:'ATA\d{4}',)?keyword:'([A-Za-z$][\w$]*)',/.exec(arg)
|
|
713
714
|
if (m === null) return null
|
|
714
|
-
out += `(
|
|
715
|
+
out += `(_scn++,_scs+=${SEV[m[1]] || 4})`
|
|
715
716
|
i = j
|
|
716
717
|
continue
|
|
717
718
|
}
|
|
718
|
-
if (body.startsWith('return{valid:false,errors:_e}', i)) { out += 'return
|
|
719
|
-
if (body.startsWith('return{valid:_e.length===0,errors:_e}', i)) { out += 'return
|
|
720
|
-
if (body.startsWith('_e.length', i)) { out += '
|
|
719
|
+
if (body.startsWith('return{valid:false,errors:_e}', i)) { out += 'return _scn*100+_scs'; i += 29; continue }
|
|
720
|
+
if (body.startsWith('return{valid:_e.length===0,errors:_e}', i)) { out += 'return _scn*100+_scs'; i += 37; continue }
|
|
721
|
+
if (body.startsWith('_e.length', i)) { out += '_scn'; i += 9; continue }
|
|
721
722
|
out += ch
|
|
722
723
|
i++
|
|
723
724
|
}
|
|
@@ -1275,7 +1276,11 @@ function genCodeENode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
1275
1276
|
// let every later statement of the same check push the same error again.
|
|
1276
1277
|
if (fc) {
|
|
1277
1278
|
const ri = ctx.varCounter++
|
|
1278
|
-
|
|
1279
|
+
// By function: the pushed error carries the property's name in its
|
|
1280
|
+
// paths, and a replacement given as text is searched for `$&` and its
|
|
1281
|
+
// kin (a property named `a$&b` reported `/areturn falseb`).
|
|
1282
|
+
const fmtFail = `{${failPush};break _fmt${ri}}`
|
|
1283
|
+
const fmtCode = fc(v, isStr, ctx).replace(/return false/g, () => fmtFail)
|
|
1279
1284
|
lines.push(`_fmt${ri}:{${fmtCode}}`)
|
|
1280
1285
|
} else if (uf !== null) {
|
|
1281
1286
|
// User-supplied format checker on the error path: the same closure
|
|
@@ -2563,7 +2568,8 @@ function genCodeCNode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
2563
2568
|
// Same rule as the error codegen: one violation, one error. The first
|
|
2564
2569
|
// failing statement pushes and leaves the labeled block.
|
|
2565
2570
|
const ri = ctx.varCounter++
|
|
2566
|
-
const
|
|
2571
|
+
const fmtFail = `{${fail('format', 'format', `{format:'${esc(schema.format)}'}`, `'must match format "${esc(schema.format)}"'`)};break _fmt${ri}}`
|
|
2572
|
+
const code = fc(v, isStr, ctx).replace(/return false/g, () => fmtFail)
|
|
2567
2573
|
lines.push(`_fmt${ri}:{${code}}`)
|
|
2568
2574
|
} else if (uf !== null) {
|
|
2569
2575
|
const closureName = bindUserFormat(ctx, schema.format, uf)
|
package/lib/js-compiler.js
CHANGED
|
@@ -20,18 +20,16 @@ const seqTag = () => `/*${++_compileSeq}*/`
|
|
|
20
20
|
// forms answers a different question and costs a string per call.
|
|
21
21
|
const DEQ_HELPER = "function _deq(a,b){if(a===b)return true;if(a===null||b===null||typeof a!=='object'||typeof b!=='object')return false;var aa=Array.isArray(a);if(aa!==Array.isArray(b))return false;var i,k,x,y;if(aa){if(a.length!==b.length)return false;for(i=a.length;i--!==0;)if(!_deq(a[i],b[i]))return false;return true}var ka=Object.keys(a);if(ka.length!==Object.keys(b).length)return false;for(i=ka.length;i--!==0;){k=ka[i];if(!Object.prototype.hasOwnProperty.call(b,k))return false;x=a[k];y=b[k];if(x!==y&&(x===null||y===null||typeof x!=='object'||typeof y!=='object'))return false}for(i=ka.length;i--!==0;){k=ka[i];x=a[k];if(x!==null&&typeof x==='object'&&!_deq(x,b[k]))return false}return true}"
|
|
22
22
|
|
|
23
|
-
// uniqueItems helpers,
|
|
23
|
+
// uniqueItems helpers, the text of the functions the interpreted engine
|
|
24
24
|
// calls (lib/unique-items.js): `_uq` answers whether every item is distinct.
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// The text is written at build time (lib/unique-items-source.js) rather than
|
|
26
|
+
// read with String(fn) here: in a bundle whose identifiers were minified the
|
|
27
|
+
// functions and their calls to each other had other names, and generated
|
|
28
|
+
// code that called `_uq` threw on every array. Loaded at the first schema
|
|
29
|
+
// with uniqueItems, not on every cold start.
|
|
28
30
|
let _uqSources = null
|
|
29
31
|
function uqSources () {
|
|
30
|
-
if (_uqSources === null)
|
|
31
|
-
const u = require('./unique-items')
|
|
32
|
-
const compact = (fn) => String(fn).replace(/\n\s*\/\/[^\n]*/g, '').replace(/\n\s*/g, '\n')
|
|
33
|
-
_uqSources = { uq: compact(u._uqh) + compact(u._uq), uqp: 'var _uqpI=0;' + compact(u._uqp) }
|
|
34
|
-
}
|
|
32
|
+
if (_uqSources === null) _uqSources = require('./unique-items-source')
|
|
35
33
|
return _uqSources
|
|
36
34
|
}
|
|
37
35
|
|
|
@@ -3471,7 +3469,7 @@ function tryGenCombined(schema, access, ctx) {
|
|
|
3471
3469
|
// or similar), skip the `{const _v = access}` wrapping and use it directly.
|
|
3472
3470
|
const isIdent = /^_[a-zA-Z]\w*$/.test(access)
|
|
3473
3471
|
const bind = (conds) => isIdent
|
|
3474
|
-
? `if(${conds.join('||').replace(/\b_v\b/g, access)})return false`
|
|
3472
|
+
? `if(${conds.join('||').replace(/\b_v\b/g, () => access)})return false`
|
|
3475
3473
|
: `{const _v=${access};if(${conds.join('||')})return false}`
|
|
3476
3474
|
|
|
3477
3475
|
if (t === 'string') {
|
|
@@ -4347,7 +4345,7 @@ function inlineBranchBody (body, param, label, local) {
|
|
|
4347
4345
|
else return null
|
|
4348
4346
|
if (/\breturn\b(?! false\b)/.test(core)) return null
|
|
4349
4347
|
const re = new RegExp('\\b' + param + '\\b', 'g')
|
|
4350
|
-
return core.replace(/\breturn false\b/g, 'break ' + label).replace(re, local)
|
|
4348
|
+
return core.replace(/\breturn false\b/g, () => 'break ' + label).replace(re, () => local)
|
|
4351
4349
|
}
|
|
4352
4350
|
|
|
4353
4351
|
// A single-branch anyOf or oneOf holds exactly when its branch does, so the
|
|
@@ -5177,7 +5175,8 @@ function genUnevaluatedPropertiesNode(schema, v, lines, ctx, knownType, isObj, h
|
|
|
5177
5175
|
for (const [trigger, depSchema] of Object.entries(schema.dependentSchemas)) {
|
|
5178
5176
|
const depResult = collectEvaluated(depSchema, ctx.schemaMap, ctx.rootDefs)
|
|
5179
5177
|
if (depResult.props && depResult.props.length > 0) {
|
|
5180
|
-
|
|
5178
|
+
// Asked of an object only: untyped, the document may be null.
|
|
5179
|
+
lines.push(`if(${isObj ? '' : `typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&`}${ownKeyExpr(ctx, v, trigger)}){${depResult.props.map(k => `${evVar}[${JSON.stringify(k)}]=1`).join(';')}}`)
|
|
5181
5180
|
}
|
|
5182
5181
|
}
|
|
5183
5182
|
const inner = `for(var _k in ${v}){if(!${evVar}[_k]&&${ownFail(ctx, v)})return false}`
|
|
@@ -5372,7 +5371,8 @@ function genUnevaluatedItemsNode(schema, v, lines, ctx, knownType, isArr) {
|
|
|
5372
5371
|
lines.push(`{let ${evVar}=${baseIdx}`)
|
|
5373
5372
|
lines.push(`const _bf${bfi}=[${fns.join(',')}]`)
|
|
5374
5373
|
const maxExprs = branchMaxIdx.map((m, i) => {
|
|
5375
|
-
|
|
5374
|
+
// An array's length only: `items` passes null too.
|
|
5375
|
+
if (branchAllItems[i]) return isArr ? `_bi===${i}?${v}.length` : `_bi===${i}?(Array.isArray(${v})?${v}.length:0)`
|
|
5376
5376
|
return `_bi===${i}?${Math.max(m, baseIdx)}`
|
|
5377
5377
|
}).join(':') + `:${baseIdx}`
|
|
5378
5378
|
if (branchKeyword === 'oneOf') {
|
|
@@ -5551,6 +5551,26 @@ const FORMAT_CODEGEN = Object.assign(Object.create(null), {
|
|
|
5551
5551
|
hostname: (...a) => getFormats().hostnameSource(...a),
|
|
5552
5552
|
})
|
|
5553
5553
|
|
|
5554
|
+
// An inline check declares locals (`_n`, `_c2`), and the generator names the
|
|
5555
|
+
// value it reads (`_c2` for a property). Where the two are one name the
|
|
5556
|
+
// check's declaration shadows its own input and throws, so that value is
|
|
5557
|
+
// renamed first. Only then; tests/test_no_throw_on_any_document.js.
|
|
5558
|
+
function declares (code, name) {
|
|
5559
|
+
for (const before of ['const ', 'let ', 'var ', ',']) {
|
|
5560
|
+
const text = before + name + '='
|
|
5561
|
+
for (let i = code.indexOf(text); i !== -1; i = code.indexOf(text, i + 1)) if (code[i + text.length] !== '=') return true
|
|
5562
|
+
}
|
|
5563
|
+
return false
|
|
5564
|
+
}
|
|
5565
|
+
for (const name of Object.keys(FORMAT_CODEGEN)) {
|
|
5566
|
+
const write = FORMAT_CODEGEN[name]
|
|
5567
|
+
FORMAT_CODEGEN[name] = (v, isStr, ctx) => {
|
|
5568
|
+
const code = write(v, isStr, ctx)
|
|
5569
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(v) || !declares(code, v)) return code
|
|
5570
|
+
return `{const _fmv=${v};${write('_fmv', isStr, ctx)}}`
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
|
|
5554
5574
|
// `^[class]+$`, `^[class]{m,n}$` and `^[class]{n}$` for a class of ASCII
|
|
5555
5575
|
// letters, digits, `_` and `-`: a function in the preamble that reads each
|
|
5556
5576
|
// character once and looks it up in a 128-entry table. The inline form below
|
package/lib/kernels/collapse.mjs
CHANGED
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
// module imports nothing, so the generated code cannot require this file; it
|
|
10
10
|
// carries a copy emitted by `embedSource()` from these very functions instead
|
|
11
11
|
// of a second hand-written one. That is why the internals are written in the
|
|
12
|
-
// positional form the generated code calls, and why
|
|
13
|
-
//
|
|
14
|
-
//
|
|
12
|
+
// positional form the generated code calls, and why each function reaches the
|
|
13
|
+
// others only through properties on itself (`__ataCollapse.F`, `.M`,
|
|
14
|
+
// `__ataScore.S`): a bundler that minifies names renames a function and every
|
|
15
|
+
// call to it, and the text toString() gives then called names the embed did
|
|
16
|
+
// not declare. A function's reference to its own name stays consistent, and
|
|
17
|
+
// property names are not renamed.
|
|
15
18
|
|
|
16
19
|
// How much a failing keyword says about intent. A branch that fails on `type`
|
|
17
20
|
// was probably not the branch the author meant; one that fails on `minLength`
|
|
@@ -35,10 +38,12 @@ const __ATA_SEVERITY = {
|
|
|
35
38
|
|
|
36
39
|
function __ataScore (errs) {
|
|
37
40
|
if (!errs || !errs.length) return 0;
|
|
41
|
+
const sev = __ataScore.S;
|
|
38
42
|
let s = 0;
|
|
39
|
-
for (const e of errs) s +=
|
|
43
|
+
for (const e of errs) s += sev[e.keyword] || 4;
|
|
40
44
|
return errs.length * 100 + s; // primary: count, secondary: severity
|
|
41
45
|
}
|
|
46
|
+
__ataScore.S = __ATA_SEVERITY;
|
|
42
47
|
|
|
43
48
|
// `br` is one entry per branch in declaration order: {valid, errors} and a
|
|
44
49
|
// `title`, or the titles in `titles` when given (the generated code passes
|
|
@@ -68,7 +73,7 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
68
73
|
if (pass.length > 1) {
|
|
69
74
|
const passIdx = [];
|
|
70
75
|
for (let i = 0; i < br.length; i++) if (br[i].valid) passIdx.push(i);
|
|
71
|
-
return
|
|
76
|
+
return __ataCollapse.M(passIdx, br.length, pp, sp, o);
|
|
72
77
|
}
|
|
73
78
|
} else if (pass.length >= 1) {
|
|
74
79
|
return null;
|
|
@@ -76,7 +81,7 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
76
81
|
let bi = 0;
|
|
77
82
|
let bs = Infinity;
|
|
78
83
|
for (let i = 0; i < br.length; i++) {
|
|
79
|
-
const s =
|
|
84
|
+
const s = __ataCollapse.F(br[i].errors);
|
|
80
85
|
if (s < bs) { bs = s; bi = i; }
|
|
81
86
|
}
|
|
82
87
|
const best = br[bi];
|
|
@@ -97,6 +102,9 @@ function __ataCollapse (kw, br, pp, sp, o, titles) {
|
|
|
97
102
|
return none;
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
__ataCollapse.M = __ataMulti;
|
|
106
|
+
__ataCollapse.F = __ataScore;
|
|
107
|
+
|
|
100
108
|
// The named-argument form the interpreter and the tests call.
|
|
101
109
|
function collapseBranches ({ keyword, branchResults, parentPath, parentSchemaPath, ordinal }) {
|
|
102
110
|
return __ataCollapse(keyword, branchResults, parentPath, parentSchemaPath, ordinal === undefined ? null : ordinal);
|
|
@@ -107,8 +115,8 @@ function collapseBranches ({ keyword, branchResults, parentPath, parentSchemaPat
|
|
|
107
115
|
// cannot miss the other. `tests/test_branch_collapse.js` runs both.
|
|
108
116
|
function embedSource () {
|
|
109
117
|
return 'const __ATA_SEVERITY=' + JSON.stringify(__ATA_SEVERITY) + ';' +
|
|
110
|
-
'const __ataScore=' + __ataScore.toString() + ';' +
|
|
118
|
+
'const __ataScore=' + __ataScore.toString() + ';__ataScore.S=__ATA_SEVERITY;' +
|
|
111
119
|
'const __ataMulti=' + __ataMulti.toString() + ';' +
|
|
112
|
-
'const __ataCollapse=' + __ataCollapse.toString() + ';';
|
|
120
|
+
'const __ataCollapse=' + __ataCollapse.toString() + ';__ataCollapse.M=__ataMulti;__ataCollapse.F=__ataScore;';
|
|
113
121
|
}
|
|
114
122
|
export { __ataCollapse };
|
package/lib/schema-scan.js
CHANGED
|
@@ -118,8 +118,9 @@ function needsNormalization(schema, isDraft7) {
|
|
|
118
118
|
// The boolean form of the exclusive bounds is draft-04's, and it is
|
|
119
119
|
// unambiguous wherever it appears: no later dialect gives a boolean any
|
|
120
120
|
// meaning there. Percent-encoded fragments mean the same in every dialect
|
|
121
|
-
// too.
|
|
122
|
-
|
|
121
|
+
// too. A fragment-only `$id` is folded into `$anchor` in every dialect, by
|
|
122
|
+
// the walk that folds `nullable`. None is gated on the declared dialect.
|
|
123
|
+
if (bits & (NULLABLE | EXCLUSIVE_BOOL | ENCODED_REF | ANCHOR_ID)) return true;
|
|
123
124
|
return isDraft7 ? (bits & DRAFT7_WORK) !== 0 : false;
|
|
124
125
|
}
|
|
125
126
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Generated by scripts/gen-unique-items-source.js from lib/unique-items.js. Do not edit.
|
|
3
|
+
module.exports = { uq: "function _uqh(x) {\nif (x === null) return 1;\nvar t = typeof x, h, i;\nif (t === 'boolean') return x ? 2 : 3;\nif (t === 'number') {\nif (x === 0) return 4;\nh = x | 0;\nif (h === x) return Math.imul(h, 0x9e3779b1) ^ 5;\nvar f = _uqh.f || (_uqh.f = new Float64Array(1)), w = _uqh.w || (_uqh.w = new Uint32Array(f.buffer));\nf[0] = x;\nreturn Math.imul(w[0] ^ Math.imul(w[1], 0x9e3779b1), 0x85ebca6b) ^ 5;\n}\nif (t === 'string') {\nh = 0x811c9dc5 ^ x.length;\nfor (i = 0; i < x.length; i++) h = Math.imul(h ^ x.charCodeAt(i), 16777619);\nreturn h;\n}\nif (t !== 'object') return 6;\nif (Array.isArray(x)) {\nh = 0x2545f491 ^ x.length;\nfor (i = 0; i < x.length; i++) h = Math.imul(h ^ _uqh(x[i]), 16777619);\nreturn h;\n}\nvar ks = Object.keys(x);\nh = 0x6c8e9cf5 ^ ks.length;\nfor (i = 0; i < ks.length; i++) h = (h + Math.imul(_uqh(ks[i]) ^ Math.imul(_uqh(x[ks[i]]), 0x5bd1e995), 0x27d4eb2d)) | 0;\nreturn h;\n}function _uq(a) {\nvar n = a.length, i, k;\nif (n < 2) return true;\nif (n <= 12) {\nfor (i = 1; i < n; i++) for (k = 0; k < i; k++) if (_deq(a[i], a[k])) return false;\nreturn true;\n}\nvar prim = true;\nfor (i = 0; i < n; i++) { var x = a[i]; if (x !== null && typeof x === 'object') { prim = false; break; } }\nif (prim) {\nvar s = new Set();\nfor (i = 0; i < n; i++) { if (s.has(a[i])) return false; s.add(a[i]); }\nreturn true;\n}\nvar m = new Map();\nfor (i = 0; i < n; i++) {\nvar hh = _uqh(a[i]), b = m.get(hh);\nif (b === undefined) m.set(hh, i);\nelse if (typeof b === 'number') { if (_deq(a[b], a[i])) return false; m.set(hh, [b, i]); }\nelse { for (k = 0; k < b.length; k++) if (_deq(a[b[k]], a[i])) return false; b.push(i); }\n}\nreturn true;\n}", uqp: "var _uqpI=0;function _uqp(a) {\nvar n = a.length, i, k;\nif (n < 2) return -1;\nif (n <= 12) {\nfor (i = 0; i < n - 1; i++) for (k = i + 1; k < n; k++) if (_deq(a[i], a[k])) { _uqpI = i; return k; }\nreturn -1;\n}\nvar prim = true;\nfor (i = 0; i < n; i++) { var x = a[i]; if (x !== null && typeof x === 'object') { prim = false; break; } }\nvar bi = -1, bj = -1, m = new Map();\nif (prim) {\nfor (i = 0; i < n; i++) {\nvar p = m.get(a[i]);\nif (p === undefined) m.set(a[i], i);\nelse if (p >= 0) { if (bi < 0 || p < bi) { bi = p; bj = i; } m.set(a[i], -1); }\n}\n} else {\nvar paired = null;\nfor (i = 0; i < n; i++) {\nvar hh = _uqh(a[i]), b = m.get(hh), r = -1;\nif (b === undefined) { m.set(hh, i); continue; }\nif (typeof b === 'number') { if (_deq(a[b], a[i])) r = b; else m.set(hh, [b, i]); }\nelse { for (k = 0; k < b.length; k++) if (_deq(a[b[k]], a[i])) { r = b[k]; break; } if (r < 0) b.push(i); }\nif (r >= 0) {\nif (paired === null) paired = new Set();\nif (!paired.has(r)) { paired.add(r); if (bi < 0 || r < bi) { bi = r; bj = i; } }\n}\n}\n}\nif (bi < 0) return -1;\n_uqpI = bi;\nreturn bj;\n}" };
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.63.
|
|
3
|
+
"version": "1.63.3",
|
|
4
4
|
"description": "JSON Schema validator that compiles to plain JavaScript, still runs where code generation is blocked, and can be compiled away at build time. Passes the full official test suite.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "index.js",
|
|
@@ -266,13 +266,13 @@
|
|
|
266
266
|
"codegen.d.ts"
|
|
267
267
|
],
|
|
268
268
|
"optionalDependencies": {
|
|
269
|
-
"@ata-validator/native-darwin-arm64": "1.63.
|
|
270
|
-
"@ata-validator/native-darwin-x64": "1.63.
|
|
271
|
-
"@ata-validator/native-linux-arm64-gnu": "1.63.
|
|
272
|
-
"@ata-validator/native-linux-arm64-musl": "1.63.
|
|
273
|
-
"@ata-validator/native-linux-x64-gnu": "1.63.
|
|
274
|
-
"@ata-validator/native-linux-x64-musl": "1.63.
|
|
275
|
-
"@ata-validator/native-win32-x64": "1.63.
|
|
269
|
+
"@ata-validator/native-darwin-arm64": "1.63.3",
|
|
270
|
+
"@ata-validator/native-darwin-x64": "1.63.3",
|
|
271
|
+
"@ata-validator/native-linux-arm64-gnu": "1.63.3",
|
|
272
|
+
"@ata-validator/native-linux-arm64-musl": "1.63.3",
|
|
273
|
+
"@ata-validator/native-linux-x64-gnu": "1.63.3",
|
|
274
|
+
"@ata-validator/native-linux-x64-musl": "1.63.3",
|
|
275
|
+
"@ata-validator/native-win32-x64": "1.63.3"
|
|
276
276
|
},
|
|
277
277
|
"peerDependencies": {
|
|
278
278
|
"yaml": "^2.0.0"
|