ata-validator 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -108,6 +108,14 @@ function compileToJS(schema, defs, schemaMap) {
108
108
  }
109
109
 
110
110
  if (!defs && needsBaseTracking(schema, schemaMap, new Set())) return null
111
+ if (!defs && externalDocsNeedInterpreter(schema, schemaMap)) return null
112
+
113
+ // unevaluatedProperties / unevaluatedItems need annotation tracking this
114
+ // path does not do. Decline so the schema reaches an engine that does.
115
+ if (!defs) {
116
+ const str = JSON.stringify(schema)
117
+ if (str.includes('"unevaluatedProperties"') || str.includes('"unevaluatedItems"')) return null
118
+ }
111
119
 
112
120
  // Collect $defs early so sub-schemas can resolve $ref
113
121
  const rootDefs = defs || collectDefs(schema)
@@ -158,13 +166,13 @@ function compileToJS(schema, defs, schemaMap) {
158
166
  const primitives = vals.filter(v => v === null || typeof v !== 'object')
159
167
  const objects = vals.filter(v => v !== null && typeof v === 'object')
160
168
  const primSet = new Set(primitives.map(v => v === null ? 'null' : typeof v === 'string' ? 's:' + v : 'n:' + v))
161
- const objStrs = objects.map(v => JSON.stringify(v))
169
+ const objStrs = objects.map(v => _canonical(v))
162
170
  checks.push((d) => {
163
171
  // Fast primitive check
164
172
  const key = d === null ? 'null' : typeof d === 'string' ? 's:' + d : typeof d === 'number' || typeof d === 'boolean' ? 'n:' + d : null
165
173
  if (key !== null && primSet.has(key)) return true
166
- // Slow object check
167
- const ds = JSON.stringify(d)
174
+ // Slow object check, key order independent
175
+ const ds = _canonical(d)
168
176
  for (let i = 0; i < objStrs.length; i++) {
169
177
  if (ds === objStrs[i]) return true
170
178
  }
@@ -182,15 +190,15 @@ function compileToJS(schema, defs, schemaMap) {
182
190
  if (cv === null || typeof cv !== 'object') {
183
191
  checks.push((d) => d === cv)
184
192
  } else {
185
- const cs = JSON.stringify(cv)
186
- checks.push((d) => JSON.stringify(d) === cs)
193
+ const cs = _canonical(cv)
194
+ checks.push((d) => _canonical(d) === cs)
187
195
  }
188
196
  }
189
197
 
190
- // required
198
+ // required applies to objects only; other types are ignored.
191
199
  if (schema.required && Array.isArray(schema.required)) {
192
200
  for (const key of schema.required) {
193
- checks.push((d) => typeof d === 'object' && d !== null && key in d)
201
+ checks.push((d) => typeof d !== 'object' || d === null || Array.isArray(d) || d[key] !== undefined)
194
202
  }
195
203
  }
196
204
 
@@ -206,10 +214,10 @@ function compileToJS(schema, defs, schemaMap) {
206
214
  }
207
215
  }
208
216
 
209
- // additionalProperties
210
- if (schema.additionalProperties !== undefined && schema.properties) {
217
+ // additionalProperties (with or without a properties map)
218
+ if (schema.additionalProperties !== undefined) {
211
219
  if (schema.additionalProperties === false) {
212
- const allowed = new Set(Object.keys(schema.properties))
220
+ const allowed = new Set(Object.keys(schema.properties || {}))
213
221
  checks.push((d) => {
214
222
  if (typeof d !== 'object' || d === null || Array.isArray(d)) return true
215
223
  const keys = Object.keys(d)
@@ -246,13 +254,14 @@ function compileToJS(schema, defs, schemaMap) {
246
254
  }
247
255
  }
248
256
 
249
- // items
257
+ // items, applied after the prefixItems positions
250
258
  if (schema.items) {
251
259
  const itemCheck = compileToJS(schema.items, rootDefs)
252
260
  if (!itemCheck) return null
261
+ const start = Array.isArray(schema.prefixItems) ? schema.prefixItems.length : 0
253
262
  checks.push((d) => {
254
263
  if (!Array.isArray(d)) return true
255
- for (let i = 0; i < d.length; i++) {
264
+ for (let i = start; i < d.length; i++) {
256
265
  if (!itemCheck(d[i])) return false
257
266
  }
258
267
  return true
@@ -330,7 +339,11 @@ function compileToJS(schema, defs, schemaMap) {
330
339
  }
331
340
  if (schema.multipleOf !== undefined) {
332
341
  const div = schema.multipleOf
333
- checks.push((d) => typeof d !== 'number' || d % div === 0)
342
+ checks.push((d) => {
343
+ if (typeof d !== 'number') return true
344
+ const r = d % div
345
+ return Math.abs(r) <= 1e-8 || Math.abs(r - div) <= 1e-8
346
+ })
334
347
  }
335
348
 
336
349
  // string
@@ -352,10 +365,12 @@ function compileToJS(schema, defs, schemaMap) {
352
365
  }
353
366
  }
354
367
 
355
- // format — hand-written fast checks
368
+ // format — hand-written fast checks. A format the code generator asserts
369
+ // but this path cannot is a decline, not a pass.
356
370
  if (schema.format) {
357
371
  const fc = FORMAT_CHECKS[schema.format]
358
372
  if (fc) checks.push((d) => typeof d !== 'string' || fc(d))
373
+ else if (FORMAT_CODEGEN[schema.format]) return null
359
374
  }
360
375
 
361
376
  // array size
@@ -371,11 +386,11 @@ function compileToJS(schema, defs, schemaMap) {
371
386
  // object size
372
387
  if (schema.minProperties !== undefined) {
373
388
  const min = schema.minProperties
374
- checks.push((d) => typeof d !== 'object' || d === null || Object.keys(d).length >= min)
389
+ checks.push((d) => typeof d !== 'object' || d === null || Array.isArray(d) || Object.keys(d).length >= min)
375
390
  }
376
391
  if (schema.maxProperties !== undefined) {
377
392
  const max = schema.maxProperties
378
- checks.push((d) => typeof d !== 'object' || d === null || Object.keys(d).length <= max)
393
+ checks.push((d) => typeof d !== 'object' || d === null || Array.isArray(d) || Object.keys(d).length <= max)
379
394
  }
380
395
 
381
396
  // allOf
@@ -558,7 +573,7 @@ function walkJsonPointer(root, fragment) {
558
573
  for (const p of parts) {
559
574
  if (target == null || typeof target !== 'object') return null
560
575
  if (!(p in target)) {
561
- const alt = p === 'definitions' ? '$defs' : p === '$defs' ? 'definitions' : null
576
+ const alt = p === 'definitions' ? '$defs' : p === '$defs' ? 'definitions' : p === 'items' && Array.isArray(target.prefixItems) ? 'prefixItems' : null
562
577
  if (alt !== null && alt in target) { target = target[alt]; continue }
563
578
  return null
564
579
  }
@@ -597,8 +612,9 @@ function resolveCrossSchemaRef(ref, schemaMap) {
597
612
  }
598
613
 
599
614
  function resolveRef(ref, defs, schemaMap) {
600
- // Self-reference: "#" — treat as permissive to avoid infinite recursion
601
- if (ref === '#') return () => true
615
+ // Self-reference: "#" cannot be expressed as a closure without a recursion
616
+ // guard. Decline rather than substitute a vacuous check.
617
+ if (ref === '#') return null
602
618
 
603
619
  // 1. Local ref
604
620
  if (defs) {
@@ -660,6 +676,13 @@ const TYPE_CHECKS = {
660
676
  object: (d) => typeof d === 'object' && d !== null && !Array.isArray(d),
661
677
  }
662
678
 
679
+ // Key-order independent JSON rendering for const/enum comparison.
680
+ function _canonical(x) {
681
+ if (x === null || typeof x !== 'object') return JSON.stringify(x)
682
+ if (Array.isArray(x)) return '[' + x.map(_canonical).join(',') + ']'
683
+ return '{' + Object.keys(x).sort().map((k) => JSON.stringify(k) + ':' + _canonical(x[k])).join(',') + '}'
684
+ }
685
+
663
686
  const FORMAT_CHECKS = {
664
687
  email: (s) => { const at = s.indexOf('@'); return at > 0 && at < s.length - 1 && s.indexOf('.', at) > at + 1 },
665
688
  date: (s) => { if (s.length !== 10 || !/^\d{4}-\d{2}-\d{2}$/.test(s)) return false; const m = +s.slice(5, 7), d = +s.slice(8, 10); return m >= 1 && m <= 12 && d >= 1 && d <= 31 },
@@ -845,6 +868,16 @@ function codegenSafe(schema, schemaMap) {
845
868
  if (typeof schema.unevaluatedProperties === 'object' && schema.unevaluatedProperties !== null) {
846
869
  if (!codegenSafe(schema.unevaluatedProperties, schemaMap)) return false
847
870
  }
871
+ // When evaluation is both dynamic (branch-dependent) and some branch
872
+ // unconditionally evaluates all properties, static tracking cannot
873
+ // correctly determine which properties are unevaluated at runtime.
874
+ // For example, a oneOf whose branches include both patternProperties
875
+ // and unevaluatedProperties:true requires annotation-aware evaluation
876
+ // that only the interpreted engine provides.
877
+ if (schema.unevaluatedProperties === false || (typeof schema.unevaluatedProperties === 'object' && schema.unevaluatedProperties !== null)) {
878
+ const evalResult = collectEvaluated(schema, schemaMap)
879
+ if (evalResult.dynamic && evalResult.allProps) return false
880
+ }
848
881
  }
849
882
  // unevaluatedItems: allow boolean and schema values
850
883
  if (schema.unevaluatedItems !== undefined) {
@@ -861,15 +894,52 @@ function codegenSafe(schema, schemaMap) {
861
894
  const defs = schema.$defs || schema.definitions
862
895
  if (defs) {
863
896
  const defNames = new Set(Object.keys(defs))
864
- // Detect cyclic local refs: if any def's own body references back to a sibling
865
- // def, the schema contains a cycle. The JS codegen returns (() => true) on cycle
866
- // (permissive), so cyclic schemas must route to the interpreted engine instead.
867
- // We check only the def bodies, not the top-level schema, so that a plain
868
- // { $ref: '#/$defs/Name', $defs: { Name: { type: 'string' } } } (no cycle)
869
- // still compiles.
870
- const hasCycle = Object.values(defs).some(
871
- (def) => typeof def === 'object' && def !== null && subtreeRefersToLocalDef(def, defNames)
872
- )
897
+ // Detect cyclic local refs: build a directed graph of def->def references and
898
+ // check for cycles using DFS. A plain cross-reference (A -> B where B doesn't
899
+ // refer back to A) is fine; only true cycles (A -> B -> A) must be rejected.
900
+ // The JS codegen returns (() => true) on cycle (permissive), so cyclic schemas
901
+ // must route to the interpreted engine instead.
902
+ const defRefs = {}
903
+ for (const [name, def] of Object.entries(defs)) {
904
+ defRefs[name] = []
905
+ if (typeof def === 'object' && def !== null) {
906
+ const refs = []
907
+ const seen = new WeakSet()
908
+ const collectRefs = (node) => {
909
+ if (typeof node !== 'object' || node === null) return
910
+ if (seen.has(node)) return
911
+ seen.add(node)
912
+ if (node.$ref) {
913
+ const m = /^#\/(?:\$defs|definitions)\/([^/]+)$/.exec(node.$ref)
914
+ if (m && defNames.has(m[1])) refs.push(m[1])
915
+ }
916
+ for (const val of Object.values(node)) {
917
+ if (typeof val === 'object' && val !== null) {
918
+ if (Array.isArray(val)) { for (const item of val) collectRefs(item) }
919
+ else collectRefs(val)
920
+ }
921
+ }
922
+ }
923
+ collectRefs(def)
924
+ defRefs[name] = refs
925
+ }
926
+ }
927
+ const hasCycle = (() => {
928
+ const visited = new Set()
929
+ const inStack = new Set()
930
+ const dfs = (node) => {
931
+ if (inStack.has(node)) return true
932
+ if (visited.has(node)) return false
933
+ visited.add(node)
934
+ inStack.add(node)
935
+ for (const neighbor of (defRefs[node] || [])) {
936
+ if (dfs(neighbor)) return true
937
+ }
938
+ inStack.delete(node)
939
+ return false
940
+ }
941
+ return Object.keys(defRefs).some(dfs)
942
+ })()
873
943
  if (hasCycle) return false
874
944
  for (const [name, def] of Object.entries(defs)) {
875
945
  if (/[~/"']/.test(name)) return false // special chars in def name
@@ -1100,14 +1170,85 @@ function hasUnresolvableRef(node, rootDefs, anchors, schemaMap, seen) {
1100
1170
  return false
1101
1171
  }
1102
1172
 
1173
+
1174
+ // --- The one gate every code generation entry point runs first ---
1175
+ //
1176
+ // Four entry points build four contexts, and three times a bail present in
1177
+ // one was missing from another; each time the generator emitted nothing for
1178
+ // a construct it could not represent and returned the empty program as
1179
+ // always-valid. The checks that do not depend on an entry point's own anchor
1180
+ // map live here, so adding a bail is one edit. Entry-point-specific checks
1181
+ // (hasUnresolvableRef against each path's anchors) still run after this.
1182
+ // tests/test_codegen_entrypoint_agreement.js holds the four to one verdict.
1183
+
1184
+ function collectExternalRefKeys(node, out, seen) {
1185
+ if (typeof node !== 'object' || node === null) return
1186
+ if (seen.has(node)) return
1187
+ seen.add(node)
1188
+ if (Array.isArray(node)) { for (const n of node) collectExternalRefKeys(n, out, seen); return }
1189
+ for (const key of Object.keys(node)) {
1190
+ const v = node[key]
1191
+ if ((key === '$ref' || key === '$dynamicRef') && typeof v === 'string' && !v.startsWith('#')) out.add(v.split('#')[0])
1192
+ else if (typeof v === 'object' && v !== null && key !== 'enum' && key !== 'const' && key !== 'default' && key !== 'examples') collectExternalRefKeys(v, out, seen)
1193
+ }
1194
+ }
1195
+
1196
+ function lookupExternal(key, schemaMap) {
1197
+ if (schemaMap.has(key)) return schemaMap.get(key)
1198
+ if (!key.includes('://')) {
1199
+ for (const [id, doc] of schemaMap) if (id.endsWith('/' + key)) return doc
1200
+ }
1201
+ return null
1202
+ }
1203
+
1204
+ // Documents reachable from `schema` through cross-document references.
1205
+ function reachableExternalDocs(schema, schemaMap) {
1206
+ const docs = new Set()
1207
+ if (!schemaMap || schemaMap.size === 0) return docs
1208
+ const queue = [schema]
1209
+ const seenDocs = new Set([schema])
1210
+ while (queue.length) {
1211
+ const doc = queue.shift()
1212
+ const keys = new Set()
1213
+ collectExternalRefKeys(doc, keys, new Set())
1214
+ for (const key of keys) {
1215
+ const target = lookupExternal(key, schemaMap)
1216
+ if (target && !seenDocs.has(target)) { seenDocs.add(target); docs.add(target); queue.push(target) }
1217
+ }
1218
+ }
1219
+ return docs
1220
+ }
1221
+
1222
+ // Dynamic scope and annotation tracking across documents is interpreter
1223
+ // work. A referenced document that uses either must decline the whole
1224
+ // schema, or the generator emits a vacuous check for the reference.
1225
+ function externalDocsNeedInterpreter(schema, schemaMap) {
1226
+ for (const doc of reachableExternalDocs(schema, schemaMap)) {
1227
+ const str = JSON.stringify(doc)
1228
+ if (str.includes('"$dynamicRef"') || str.includes('"$dynamicAnchor"') ||
1229
+ str.includes('"unevaluatedProperties"') || str.includes('"unevaluatedItems"')) return true
1230
+ // An embedded $id inside a referenced document opens a resource the
1231
+ // generator never registers, so references to it would be vacuous.
1232
+ if (typeof doc === 'object' && doc !== null && hasNestedIdScope(doc)) return true
1233
+ }
1234
+ return false
1235
+ }
1236
+
1237
+ function sharedCodegenGate(schema, schemaMap) {
1238
+ if (typeof schema !== 'object' || schema === null) return true
1239
+ if (!codegenSafe(schema, schemaMap)) return false
1240
+ if (needsBaseTracking(schema, schemaMap, new Set())) return false
1241
+ if (externalDocsNeedInterpreter(schema, schemaMap)) return false
1242
+ return true
1243
+ }
1244
+
1103
1245
  // --- Codegen mode: generates a single Function (NOT CSP-safe) ---
1104
1246
  // This matches ajv's approach: one monolithic function, V8 JIT fully inlines it
1105
1247
  function compileToJSCodegen(schema, schemaMap, userFormats) {
1106
1248
  if (typeof schema === 'boolean') return schema ? () => true : () => false
1107
1249
  if (typeof schema !== 'object' || schema === null) return null
1108
1250
 
1109
- // Bail if schema contains features that codegen can't handle correctly
1110
- if (!codegenSafe(schema, schemaMap)) return null
1251
+ if (!sharedCodegenGate(schema, schemaMap)) return null
1111
1252
 
1112
1253
  // Collect defs for $ref resolution
1113
1254
  const rootDefs = schema.$defs || schema.definitions || null
@@ -1243,7 +1384,13 @@ function compileToJSCodegen(schema, schemaMap, userFormats) {
1243
1384
  const fmtEntries = []
1244
1385
  for (let i = 0; i < closureNames.length; i++) {
1245
1386
  if (closureNames[i].startsWith('_uf_')) {
1246
- fmtEntries.push({ name: closureNames[i], fn: closureValues[i] })
1387
+ // The format's own name, so an emitter can look it up at runtime
1388
+ // instead of embedding the function.
1389
+ let format = null
1390
+ for (const key of Object.keys(ctx.userFormats)) {
1391
+ if (ctx.userFormats[key] === closureValues[i]) { format = key; break }
1392
+ }
1393
+ fmtEntries.push({ name: closureNames[i], fn: closureValues[i], format })
1247
1394
  }
1248
1395
  }
1249
1396
  if (fmtEntries.length) boolFn._formatClosures = fmtEntries
@@ -1387,7 +1534,7 @@ function tryGenCombined(schema, access, ctx) {
1387
1534
  if (schema.maximum !== undefined) conds.push(`_v>${schema.maximum}`)
1388
1535
  if (schema.exclusiveMinimum !== undefined) conds.push(`_v<=${schema.exclusiveMinimum}`)
1389
1536
  if (schema.exclusiveMaximum !== undefined) conds.push(`_v>=${schema.exclusiveMaximum}`)
1390
- if (schema.multipleOf !== undefined) conds.push(`_v%${schema.multipleOf}!==0`)
1537
+ if (schema.multipleOf !== undefined) conds.push(`(Math.abs(_v%${schema.multipleOf})>1e-8&&Math.abs(_v%${schema.multipleOf}-${schema.multipleOf})>1e-8)`)
1391
1538
  if (conds.length < 2) return null
1392
1539
  return bind(conds)
1393
1540
  }
@@ -1398,7 +1545,7 @@ function tryGenCombined(schema, access, ctx) {
1398
1545
  if (schema.maximum !== undefined) conds.push(`_v>${schema.maximum}`)
1399
1546
  if (schema.exclusiveMinimum !== undefined) conds.push(`_v<=${schema.exclusiveMinimum}`)
1400
1547
  if (schema.exclusiveMaximum !== undefined) conds.push(`_v>=${schema.exclusiveMaximum}`)
1401
- if (schema.multipleOf !== undefined) conds.push(`_v%${schema.multipleOf}!==0`)
1548
+ if (schema.multipleOf !== undefined) conds.push(`(Math.abs(_v%${schema.multipleOf})>1e-8&&Math.abs(_v%${schema.multipleOf}-${schema.multipleOf})>1e-8)`)
1402
1549
  if (conds.length < 2) return null
1403
1550
  return bind(conds)
1404
1551
  }
@@ -1411,7 +1558,9 @@ function tryGenCombined(schema, access, ctx) {
1411
1558
  // function is only safe when we're at the root (`v === 'd'`). For nested
1412
1559
  // nodes, emit inline so block-scoped variables like `_o0` stay in scope.
1413
1560
  function _deferOrInline(ctx, lines, v, check) {
1414
- if (v === 'd') {
1561
+ // Deferring is only sound at the top level of the root function. Inside a
1562
+ // conditional applicator (dependentSchemas) the check must stay in its block.
1563
+ if (v === 'd' && !ctx.condDepth) {
1415
1564
  if (!ctx.deferredChecks) ctx.deferredChecks = []
1416
1565
  ctx.deferredChecks.push(check)
1417
1566
  } else {
@@ -1552,7 +1701,7 @@ function genCode(schema, v, lines, ctx, knownType) {
1552
1701
  const isArr = effectiveType === 'array'
1553
1702
  const isStr = effectiveType === 'string'
1554
1703
  const isNum = effectiveType === 'number' || effectiveType === 'integer'
1555
- const objGuard = isObj ? '' : `typeof ${v}==='object'&&${v}!==null&&`
1704
+ const objGuard = isObj ? '' : `typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&`
1556
1705
  const objCheck = isObj ? '' : `if(typeof ${v}!=='object'||${v}===null)return false;`
1557
1706
 
1558
1707
  // enum
@@ -1572,7 +1721,12 @@ function genCode(schema, v, lines, ctx, knownType) {
1572
1721
  if (cv === null || typeof cv !== 'object') {
1573
1722
  lines.push(`if(${v}!==${JSON.stringify(cv)})return false`)
1574
1723
  } else {
1575
- lines.push(`if(JSON.stringify(${v})!==${JSON.stringify(JSON.stringify(cv))})return false`)
1724
+ // Key-order independent comparison, defined inline so every emitter
1725
+ // (runtime, hybrid, standalone) carries it.
1726
+ const ci = ctx.varCounter++
1727
+ const canonFn = `_cnB${ci}`
1728
+ const expected = _canonical(cv)
1729
+ lines.push(`{const ${canonFn}=function(x){if(x===null||typeof x!=='object')return JSON.stringify(x);if(Array.isArray(x))return'['+x.map(${canonFn}).join(',')+']';return'{'+Object.keys(x).sort().map(function(k){return JSON.stringify(k)+':'+${canonFn}(x[k])}).join(',')+'}'};if(${canonFn}(${v})!==${JSON.stringify(expected)})return false}`)
1576
1730
  }
1577
1731
  }
1578
1732
 
@@ -1600,9 +1754,9 @@ function genCode(schema, v, lines, ctx, knownType) {
1600
1754
  const checks = schema.required.map(key => `${v}[${JSON.stringify(key)}]===undefined`)
1601
1755
  lines.push(`if(${checks.join('||')})return false`)
1602
1756
  } else {
1603
- for (const key of schema.required) {
1604
- lines.push(`if(typeof ${v}!=='object'||${v}===null||!(${JSON.stringify(key)} in ${v}))return false`)
1605
- }
1757
+ // required applies to objects only; other types are ignored.
1758
+ const checks = schema.required.map(key => `${v}[${JSON.stringify(key)}]===undefined`)
1759
+ lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&(${checks.join('||')}))return false`)
1606
1760
  }
1607
1761
  }
1608
1762
 
@@ -1632,7 +1786,11 @@ function genCode(schema, v, lines, ctx, knownType) {
1632
1786
  if (schema.maximum !== undefined) lines.push(isNum ? `if(${v}>${schema.maximum})return false` : `if(typeof ${v}==='number'&&${v}>${schema.maximum})return false`)
1633
1787
  if (schema.exclusiveMinimum !== undefined) lines.push(isNum ? `if(${v}<=${schema.exclusiveMinimum})return false` : `if(typeof ${v}==='number'&&${v}<=${schema.exclusiveMinimum})return false`)
1634
1788
  if (schema.exclusiveMaximum !== undefined) lines.push(isNum ? `if(${v}>=${schema.exclusiveMaximum})return false` : `if(typeof ${v}==='number'&&${v}>=${schema.exclusiveMaximum})return false`)
1635
- if (schema.multipleOf !== undefined) lines.push(isNum ? `if(${v}%${schema.multipleOf}!==0)return false` : `if(typeof ${v}==='number'&&${v}%${schema.multipleOf}!==0)return false`)
1789
+ if (schema.multipleOf !== undefined) {
1790
+ const m = schema.multipleOf
1791
+ const bad = `(Math.abs(${v}%${m})>1e-8&&Math.abs(${v}%${m}-${m})>1e-8)`
1792
+ lines.push(isNum ? `if${bad}return false` : `if(typeof ${v}==='number'&&${bad})return false`)
1793
+ }
1636
1794
 
1637
1795
  // string length — skip type guard if known string.
1638
1796
  // s.length (UTF-16 code units) is an upper bound on cpLen, and at least cpLen
@@ -1891,7 +2049,9 @@ function genCode(schema, v, lines, ctx, knownType) {
1891
2049
  for (const [key, depSchema] of Object.entries(schema.dependentSchemas)) {
1892
2050
  const guard = isObj ? '' : `typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&`
1893
2051
  lines.push(`if(${guard}${JSON.stringify(key)} in ${v}){`)
2052
+ ctx.condDepth = (ctx.condDepth || 0) + 1
1894
2053
  genCode(depSchema, v, lines, ctx, effectiveType)
2054
+ ctx.condDepth--
1895
2055
  lines.push(`}`)
1896
2056
  }
1897
2057
  }
@@ -1968,9 +2128,11 @@ function genCode(schema, v, lines, ctx, knownType) {
1968
2128
  const idx = `_j${ctx.varCounter}`
1969
2129
  const elem = `_e${ctx.varCounter}`
1970
2130
  ctx.varCounter++
2131
+ // items applies after the prefixItems positions (Draft 2020-12).
2132
+ const start = Array.isArray(schema.prefixItems) ? schema.prefixItems.length : 0
1971
2133
  lines.push(isArr
1972
- ? `for(let ${idx}=0;${idx}<${v}.length;${idx}++){const ${elem}=${v}[${idx}]`
1973
- : `if(Array.isArray(${v})){for(let ${idx}=0;${idx}<${v}.length;${idx}++){const ${elem}=${v}[${idx}]`)
2134
+ ? `for(let ${idx}=${start};${idx}<${v}.length;${idx}++){const ${elem}=${v}[${idx}]`
2135
+ : `if(Array.isArray(${v})){for(let ${idx}=${start};${idx}<${v}.length;${idx}++){const ${elem}=${v}[${idx}]`)
1974
2136
  genCode(schema.items, elem, lines, ctx)
1975
2137
  lines.push(isArr ? `}` : `}}`)
1976
2138
  }
@@ -2635,6 +2797,9 @@ const FORMAT_CODEGEN = {
2635
2797
 
2636
2798
  // Safe key escaping: use JSON.stringify to handle all special chars (newlines, null bytes, etc.)
2637
2799
  function esc(s) { return JSON.stringify(s).slice(1, -1) }
2800
+ // A schema pointer segment for a pattern: JSON Pointer escaping, then made
2801
+ // safe for the single-quoted literal the error emitters use.
2802
+ function ptrSeg(s) { return s.replace(/~/g, '~0').replace(/\//g, '~1').replace(/\\/g, '\\\\').replace(/'/g, "\\'") }
2638
2803
 
2639
2804
  // Resolve child path at codegen time when parent is a static string literal.
2640
2805
  // This enables frozen pre-allocation for ALL nested error objects.
@@ -2781,7 +2946,7 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
2781
2946
  : () => ({ valid: false, errors: [{ keyword: 'false schema', instancePath: '', schemaPath: '#', params: {}, message: 'boolean schema is false' }] })
2782
2947
  }
2783
2948
  if (typeof schema !== 'object' || schema === null) return null
2784
- if (!codegenSafe(schema, schemaMap)) return null
2949
+ if (!sharedCodegenGate(schema, schemaMap)) return null
2785
2950
  if (schema.patternProperties) {
2786
2951
  for (const [pat, sub] of Object.entries(schema.patternProperties)) {
2787
2952
  if (typeof sub === 'boolean') return null
@@ -3179,13 +3344,30 @@ function genCodeE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
3179
3344
  lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&Object.keys(${v}).length>${schema.maxProperties}){${fail('maxProperties', 'maxProperties', `{limit:${schema.maxProperties}}`, `'must NOT have more than ${schema.maxProperties} properties'`)}}`)
3180
3345
  }
3181
3346
 
3182
- // additionalProperties: false
3183
- if (schema.additionalProperties === false && schema.properties) {
3184
- const allowed = Object.keys(schema.properties).map(k => `${JSON.stringify(k)}`).join(',')
3347
+ // additionalProperties: false. A key matched by any patternProperties
3348
+ // entry is not additional, so those patterns are consulted here as well.
3349
+ if (schema.additionalProperties === false && (schema.properties || schema.patternProperties)) {
3350
+ const allowed = Object.keys(schema.properties || {}).map(k => `${JSON.stringify(k)}`).join(',')
3185
3351
  const ci = ctx.varCounter++
3186
3352
  const apSp = `${schemaPrefix}/additionalProperties`
3187
3353
  const apLit = buildErrorLiteral({ keyword: 'additionalProperties', schemaPath: apSp, sourceMap: ctx.sourceMap })
3188
- const inner = `const _k${ci}=Object.keys(${v});const _a${ci}=new Set([${allowed}]);for(let _i=0;_i<_k${ci}.length;_i++){if(!_a${ci}.has(_k${ci}[_i])){_e.push({code:'${apLit.codeStr}',keyword:'additionalProperties',instancePath:${pathExpr||'""'},schemaPath:'${apSp}',params:{additionalProperty:_k${ci}[_i]},message:'must NOT have additional properties',docUrl:'${apLit.docUrl}'${apLit.frame}});if(!_all)return{valid:false,errors:_e}}}`
3354
+ const patChecks = []
3355
+ for (const pat of Object.keys(schema.patternProperties || {})) {
3356
+ const pattern = JSON.stringify(pat)
3357
+ if (!ctx.regExpMap.has(pattern)) {
3358
+ const ri = ctx.varCounter++
3359
+ ctx.regExpMap.set(pattern, ri)
3360
+ if (patternIsSafe(pat)) {
3361
+ ctx.helperCode.push(`const _re${ri}=__ataSafeRe(${pattern})`)
3362
+ ctx.usesSafeRe = true
3363
+ } else {
3364
+ ctx.helperCode.push(`const _re${ri}=new RegExp(${pattern})`)
3365
+ }
3366
+ }
3367
+ patChecks.push(`_re${ctx.regExpMap.get(pattern)}.test(_k${ci}[_i])`)
3368
+ }
3369
+ const isAdditional = patChecks.length ? `!_a${ci}.has(_k${ci}[_i])&&!(${patChecks.join('||')})` : `!_a${ci}.has(_k${ci}[_i])`
3370
+ const inner = `const _k${ci}=Object.keys(${v});const _a${ci}=new Set([${allowed}]);for(let _i=0;_i<_k${ci}.length;_i++){if(${isAdditional}){_e.push({code:'${apLit.codeStr}',keyword:'additionalProperties',instancePath:${pathExpr||'""'},schemaPath:'${apSp}',params:{additionalProperty:_k${ci}[_i]},message:'must NOT have additional properties',docUrl:'${apLit.docUrl}'${apLit.frame}});if(!_all)return{valid:false,errors:_e}}}`
3189
3371
  lines.push(isObj ? `{${inner}}` : `if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})){${inner}}`)
3190
3372
  }
3191
3373
 
@@ -3228,7 +3410,8 @@ function genCodeE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
3228
3410
  const ki = ctx.varCounter++
3229
3411
  lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})){for(const _k${ki} in ${v}){if(_re${ri}.test(_k${ki})){`)
3230
3412
  const p = pathExpr ? `${pathExpr}+'/'+_k${ki}` : `'/'+_k${ki}`
3231
- genCodeE(sub, `${v}[_k${ki}]`, p, lines, ctx, schemaPrefix+'/patternProperties')
3413
+ // The real pointer, so source maps can locate the failing keyword.
3414
+ genCodeE(sub, `${v}[_k${ki}]`, p, lines, ctx, schemaPrefix + '/patternProperties/' + pat.replace(/~/g, '~0').replace(/\//g, '~1'))
3232
3415
  lines.push(`}}}`)
3233
3416
  }
3234
3417
  }
@@ -3407,7 +3590,7 @@ function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats) {
3407
3590
  : () => ({ valid: false, errors: [{ keyword: 'false schema', instancePath: '', schemaPath: '#', params: {}, message: 'boolean schema is false' }] })
3408
3591
  }
3409
3592
  if (typeof schema !== 'object' || schema === null) return null
3410
- if (!codegenSafe(schema, schemaMap)) return null
3593
+ if (!sharedCodegenGate(schema, schemaMap)) return null
3411
3594
  if (schema.patternProperties) {
3412
3595
  for (const [pat, sub] of Object.entries(schema.patternProperties)) {
3413
3596
  if (typeof sub === 'boolean') return null
@@ -3841,17 +4024,6 @@ function genCodeC(schema, v, pathExpr, lines, ctx, schemaPrefix) {
3841
4024
  }
3842
4025
  }
3843
4026
 
3844
- // Build sub-schema validators as closure vars
3845
- for (let i = 0; i < ppEntries.length; i++) {
3846
- const [, sub] = ppEntries[i]
3847
- const subLines = []
3848
- genCode(sub, `_ppv`, subLines, ctx)
3849
- const fnBody = subLines.length === 0 ? `return true` : `${subLines.join(';')};return true`
3850
- const fnVar = `_ppf${pi}_${i}`
3851
- ctx.closureVars.push(fnVar)
3852
- ctx.closureVals.push(new Function('_ppv', fnBody))
3853
- }
3854
-
3855
4027
  const guard = isObj ? '' : `if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v}))`
3856
4028
  const kVar = `_k${pi}`
3857
4029
 
@@ -3895,7 +4067,11 @@ function genCodeC(schema, v, pathExpr, lines, ctx, schemaPrefix) {
3895
4067
  const matchExpr = keyCheck || `_as${pi}.has(${kVar})`
3896
4068
  lines.push(`let _m${pi}=${matchExpr}`)
3897
4069
  for (let i = 0; i < ppEntries.length; i++) {
3898
- lines.push(`if(${matchers[i].check}){_m${pi}=true;if(!_ppf${pi}_${i}(${v}[${kVar}])){${fail('pattern', 'patternProperties', `{pattern:'${ppEntries[i][0]}'}`, `'patternProperties: value invalid for key '+${kVar}`)}}}`)
4070
+ // The subschema is generated in place so its own keywords report
4071
+ // the real instance path and schema pointer.
4072
+ lines.push(`if(${matchers[i].check}){_m${pi}=true;{const _ppv${pi}_${i}=${v}[${kVar}]`)
4073
+ genCodeC(ppEntries[i][1], `_ppv${pi}_${i}`, childPathDynExpr(pathExpr, kVar), lines, ctx, schemaPrefix + '/patternProperties/' + ptrSeg(ppEntries[i][0]))
4074
+ lines.push(`}}`)
3899
4075
  }
3900
4076
  lines.push(`if(!_m${pi}){${fail('additionalProperties', 'additionalProperties', `{additionalProperty:${kVar}}`, "'must NOT have additional properties'")}}`)
3901
4077
  lines.push(`}}`)
@@ -3925,7 +4101,9 @@ function genCodeC(schema, v, pathExpr, lines, ctx, schemaPrefix) {
3925
4101
  }
3926
4102
  }
3927
4103
  for (let i = 0; i < ppEntries.length; i++) {
3928
- lines.push(`if(${matchers[i].check}&&!_ppf${pi}_${i}(${v}[${kVar}])){${fail('pattern', 'patternProperties', `{pattern:'${ppEntries[i][0]}'}`, `'patternProperties: value invalid for key '+${kVar}`)}}`)
4104
+ lines.push(`if(${matchers[i].check}){const _ppv${pi}_${i}=${v}[${kVar}]`)
4105
+ genCodeC(ppEntries[i][1], `_ppv${pi}_${i}`, childPathDynExpr(pathExpr, kVar), lines, ctx, schemaPrefix + '/patternProperties/' + ptrSeg(ppEntries[i][0]))
4106
+ lines.push(`}`)
3929
4107
  }
3930
4108
  lines.push(`}}`)
3931
4109
  }
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ // The official meta-schemas, vendored so a `$ref` to one of them resolves
4
+ // without a network. Draft 2020-12 is eight documents joined by $dynamicRef;
5
+ // draft-07 is one. Sources: https://json-schema.org/draft/2020-12/schema and
6
+ // http://json-schema.org/draft-07/schema, fetched 2026-08-23, unmodified.
7
+ // Keyed by $id; index.js also registers the http/https and trailing-# spellings.
8
+
9
+ const METASCHEMAS = new Map([
10
+ ["https://json-schema.org/draft/2020-12/schema", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/schema","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/core":true,"https://json-schema.org/draft/2020-12/vocab/applicator":true,"https://json-schema.org/draft/2020-12/vocab/unevaluated":true,"https://json-schema.org/draft/2020-12/vocab/validation":true,"https://json-schema.org/draft/2020-12/vocab/meta-data":true,"https://json-schema.org/draft/2020-12/vocab/format-annotation":true,"https://json-schema.org/draft/2020-12/vocab/content":true},"$dynamicAnchor":"meta","title":"Core and Validation specifications meta-schema","allOf":[{"$ref":"meta/core"},{"$ref":"meta/applicator"},{"$ref":"meta/unevaluated"},{"$ref":"meta/validation"},{"$ref":"meta/meta-data"},{"$ref":"meta/format-annotation"},{"$ref":"meta/content"}],"type":["object","boolean"],"$comment":"This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.","properties":{"definitions":{"$comment":"\"definitions\" has been replaced by \"$defs\".","type":"object","additionalProperties":{"$dynamicRef":"#meta"},"deprecated":true,"default":{}},"dependencies":{"$comment":"\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.","type":"object","additionalProperties":{"anyOf":[{"$dynamicRef":"#meta"},{"$ref":"meta/validation#/$defs/stringArray"}]},"deprecated":true,"default":{}},"$recursiveAnchor":{"$comment":"\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".","$ref":"meta/core#/$defs/anchorString","deprecated":true},"$recursiveRef":{"$comment":"\"$recursiveRef\" has been replaced by \"$dynamicRef\".","$ref":"meta/core#/$defs/uriReferenceString","deprecated":true}}}],
11
+ ["https://json-schema.org/draft/2020-12/meta/core", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/core","$dynamicAnchor":"meta","title":"Core vocabulary meta-schema","type":["object","boolean"],"properties":{"$id":{"$ref":"#/$defs/uriReferenceString","$comment":"Non-empty fragments not allowed.","pattern":"^[^#]*#?$"},"$schema":{"$ref":"#/$defs/uriString"},"$ref":{"$ref":"#/$defs/uriReferenceString"},"$anchor":{"$ref":"#/$defs/anchorString"},"$dynamicRef":{"$ref":"#/$defs/uriReferenceString"},"$dynamicAnchor":{"$ref":"#/$defs/anchorString"},"$vocabulary":{"type":"object","propertyNames":{"$ref":"#/$defs/uriString"},"additionalProperties":{"type":"boolean"}},"$comment":{"type":"string"},"$defs":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"}}},"$defs":{"anchorString":{"type":"string","pattern":"^[A-Za-z_][-A-Za-z0-9._]*$"},"uriString":{"type":"string","format":"uri"},"uriReferenceString":{"type":"string","format":"uri-reference"}}}],
12
+ ["https://json-schema.org/draft/2020-12/meta/applicator", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/applicator","$dynamicAnchor":"meta","title":"Applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"prefixItems":{"$ref":"#/$defs/schemaArray"},"items":{"$dynamicRef":"#meta"},"contains":{"$dynamicRef":"#meta"},"additionalProperties":{"$dynamicRef":"#meta"},"properties":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"propertyNames":{"format":"regex"},"default":{}},"dependentSchemas":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"default":{}},"propertyNames":{"$dynamicRef":"#meta"},"if":{"$dynamicRef":"#meta"},"then":{"$dynamicRef":"#meta"},"else":{"$dynamicRef":"#meta"},"allOf":{"$ref":"#/$defs/schemaArray"},"anyOf":{"$ref":"#/$defs/schemaArray"},"oneOf":{"$ref":"#/$defs/schemaArray"},"not":{"$dynamicRef":"#meta"}},"$defs":{"schemaArray":{"type":"array","minItems":1,"items":{"$dynamicRef":"#meta"}}}}],
13
+ ["https://json-schema.org/draft/2020-12/meta/validation", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/validation","$dynamicAnchor":"meta","title":"Validation vocabulary meta-schema","type":["object","boolean"],"properties":{"type":{"anyOf":[{"$ref":"#/$defs/simpleTypes"},{"type":"array","items":{"$ref":"#/$defs/simpleTypes"},"minItems":1,"uniqueItems":true}]},"const":true,"enum":{"type":"array","items":true},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/$defs/nonNegativeInteger"},"minLength":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"maxItems":{"$ref":"#/$defs/nonNegativeInteger"},"minItems":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"maxContains":{"$ref":"#/$defs/nonNegativeInteger"},"minContains":{"$ref":"#/$defs/nonNegativeInteger","default":1},"maxProperties":{"$ref":"#/$defs/nonNegativeInteger"},"minProperties":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"required":{"$ref":"#/$defs/stringArray"},"dependentRequired":{"type":"object","additionalProperties":{"$ref":"#/$defs/stringArray"}}},"$defs":{"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"$ref":"#/$defs/nonNegativeInteger","default":0},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}}}],
14
+ ["https://json-schema.org/draft/2020-12/meta/meta-data", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/meta-data","$dynamicAnchor":"meta","title":"Meta-data vocabulary meta-schema","type":["object","boolean"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"default":true,"deprecated":{"type":"boolean","default":false},"readOnly":{"type":"boolean","default":false},"writeOnly":{"type":"boolean","default":false},"examples":{"type":"array","items":true}}}],
15
+ ["https://json-schema.org/draft/2020-12/meta/format-annotation", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/format-annotation","$dynamicAnchor":"meta","title":"Format vocabulary meta-schema for annotation results","type":["object","boolean"],"properties":{"format":{"type":"string"}}}],
16
+ ["https://json-schema.org/draft/2020-12/meta/content", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/content","$dynamicAnchor":"meta","title":"Content vocabulary meta-schema","type":["object","boolean"],"properties":{"contentEncoding":{"type":"string"},"contentMediaType":{"type":"string"},"contentSchema":{"$dynamicRef":"#meta"}}}],
17
+ ["https://json-schema.org/draft/2020-12/meta/unevaluated", {"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/unevaluated","$dynamicAnchor":"meta","title":"Unevaluated applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"unevaluatedItems":{"$dynamicRef":"#meta"},"unevaluatedProperties":{"$dynamicRef":"#meta"}}}],
18
+ ["http://json-schema.org/draft-07/schema#", {"$schema":"http://json-schema.org/draft-07/schema#","$id":"http://json-schema.org/draft-07/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"$comment":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":true,"readOnly":{"type":"boolean","default":false},"writeOnly":{"type":"boolean","default":false},"examples":{"type":"array","items":true},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":true},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"propertyNames":{"format":"regex"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":true,"enum":{"type":"array","items":true,"minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"contentMediaType":{"type":"string"},"contentEncoding":{"type":"string"},"if":{"$ref":"#"},"then":{"$ref":"#"},"else":{"$ref":"#"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":true}],
19
+ ]);
20
+
21
+ module.exports = { METASCHEMAS };