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.
@@ -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 `__ataCollapse` may close
13
- // over nothing but `__ataScore` and the severity table: whatever it reaches
14
- // has to be in the embed too.
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 += __ATA_SEVERITY[e.keyword] || 4;
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 __ataMulti(passIdx, br.length, pp, sp, o);
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 = __ataScore(br[i].errors);
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' && /^#[A-Za-z][A-Za-z0-9_.:-]*$/.test(schema.$id)) {
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
- return '(' + m[1].replace(/\bv\b/g, vExpr).replace(/\bn\b/g, nExpr) + ')'
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
- .replace('export function isValid(d){return ', `const FILL=buildDefaultsApplier(${JSON.stringify(ir.schema)})\nexport function isValid(d){FILL(d);return `)
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' : '(_n++,_s+=4)') + body.slice(j)
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
- out += 'let _n=0,_s=0;'
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 += `(_n++,_s+=${SEV[m[1]] || 4})`
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 _n*100+_s'; i += 29; continue }
719
- if (body.startsWith('return{valid:_e.length===0,errors:_e}', i)) { out += 'return _n*100+_s'; i += 37; continue }
720
- if (body.startsWith('_e.length', i)) { out += '_n'; i += 9; continue }
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
- const fmtCode = fc(v, isStr, ctx).replace(/return false/g, `{${failPush};break _fmt${ri}}`)
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 code = fc(v, isStr, ctx).replace(/return false/g, `{${fail('format', 'format', `{format:'${esc(schema.format)}'}`, `'must match format "${esc(schema.format)}"'`)};break _fmt${ri}}`)
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)
@@ -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, emitted from the functions the interpreted engine
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
- // Loaded at the first schema with uniqueItems, not on every cold start.
26
- // Comment lines and indentation are dropped: the text lands in every
27
- // generated function and ahead-of-time module that checks uniqueItems.
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
- lines.push(`if(${ownKeyExpr(ctx, v, trigger)}){${depResult.props.map(k => `${evVar}[${JSON.stringify(k)}]=1`).join(';')}}`)
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
- if (branchAllItems[i]) return `_bi===${i}?${v}.length`
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
@@ -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 `__ataCollapse` may close
13
- // over nothing but `__ataScore` and the severity table: whatever it reaches
14
- // has to be in the embed too.
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 += __ATA_SEVERITY[e.keyword] || 4;
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 __ataMulti(passIdx, br.length, pp, sp, o);
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 = __ataScore(br[i].errors);
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 };
@@ -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. Neither is gated on the declared dialect.
122
- if (bits & (NULLABLE | EXCLUSIVE_BOOL | ENCODED_REF)) return true;
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
@@ -7,4 +7,4 @@
7
7
  //
8
8
  // Kept in lockstep with package.json by `tests/test_version_sync.js`.
9
9
 
10
- module.exports = '1.63.2';
10
+ module.exports = '1.63.3';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.63.2",
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.2",
270
- "@ata-validator/native-darwin-x64": "1.63.2",
271
- "@ata-validator/native-linux-arm64-gnu": "1.63.2",
272
- "@ata-validator/native-linux-arm64-musl": "1.63.2",
273
- "@ata-validator/native-linux-x64-gnu": "1.63.2",
274
- "@ata-validator/native-linux-x64-musl": "1.63.2",
275
- "@ata-validator/native-win32-x64": "1.63.2"
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"