ata-validator 1.47.0 → 1.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -3
- package/index.js +22 -4
- package/lib/aot-impl.js +9 -1
- package/lib/draft7.js +106 -8
- package/lib/enrich-error.js +88 -12
- package/lib/enrich-site.js +1 -1
- package/lib/js-compiler-errors.js +103 -8
- package/lib/js-compiler.js +119 -7
- package/lib/metaschemas.js +21 -2
- package/lib/regex-linear.js +194 -37
- package/lib/rejections.js +27 -11
- package/lib/safe-regex.js +23 -9
- package/lib/scan-compiler.js +14 -6
- package/lib/validator-core.js +23 -16
- package/lib/version.js +1 -1
- package/lib/vocabularies.js +12 -0
- package/lite.d.ts +12 -0
- package/lite.js +20 -0
- package/lite.mjs +3 -0
- package/package.json +18 -9
|
@@ -9,7 +9,7 @@ const { compileFunction } = require('./compile-fn')
|
|
|
9
9
|
// the first call that compiles errors. Everything here was written as part
|
|
10
10
|
// of js-compiler.js and reads its helpers from that module's _internal.
|
|
11
11
|
const core = require('./js-compiler')
|
|
12
|
-
const { hasConstraints, assertEmitted, prepareForCodegen, sharedCodegenGate, codegenSafe, isSimplePN, hasUnresolvableRef, needsBaseTracking, _cpLen, sharedRt, DECLINE, bindRt, compileSafe, emitGuardState, withPlain, REF_NEUTRAL_SIBLINGS, resolveCrossSchemaRef, enumCondition, emitDeq, emitConstant, ownGuard, ownKeyExpr, multipleOfBad, compilePatternInline, useSafeEngine, reFlags, FORMAT_CODEGEN, PROTO_NAMES, setOwn, nestedGenCode, compileToJSCodegen, SKIP_VALUE_KEYS, skipString, CYCLE_DEPTH, cyclicDefNames, sharedDefNames, reFlagArg, hoistOnce, PTR_ESC_HELPER, unevalContributions, emitUq, uqSources, safeReClosure, fastPrefixCheck, replaceTopLevel, refTargetFor, genCode, addLocalAnnotations, addTopApplicatorAnnotations, protoIs, ANNOT_APPLICATORS, SIZE_SKIPS, emitRootGuard, emitGuardedRun } = core._internal
|
|
12
|
+
const { hasConstraints, assertEmitted, prepareForCodegen, sharedCodegenGate, codegenSafe, isSimplePN, hasUnresolvableRef, needsBaseTracking, _cpLen, sharedRt, DECLINE, bindRt, compileSafe, emitGuardState, withPlain, REF_NEUTRAL_SIBLINGS, resolveCrossSchemaRef, enumCondition, enumOperand, emitDeq, emitConstant, ownGuard, ownKeyExpr, multipleOfBad, compilePatternInline, useSafeEngine, reFlags, FORMAT_CODEGEN, PROTO_NAMES, setOwn, nestedGenCode, compileToJSCodegen, SKIP_VALUE_KEYS, skipString, CYCLE_DEPTH, cyclicDefNames, sharedDefNames, reFlagArg, hoistOnce, PTR_ESC_HELPER, unevalContributions, emitUq, uqSources, safeReClosure, fastPrefixCheck, replaceTopLevel, refTargetFor, genCode, addLocalAnnotations, addTopApplicatorAnnotations, protoIs, ANNOT_APPLICATORS, SIZE_SKIPS, emitRootGuard, emitGuardedRun } = core._internal
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
function emitPtrEsc(ctx) {
|
|
@@ -289,7 +289,7 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
|
|
|
289
289
|
if (hasUnresolvableRef(schema, eRootDefs, eAnchors, schemaMap, new Set())) return null
|
|
290
290
|
if (needsBaseTracking(schema, schemaMap, new Set())) return null
|
|
291
291
|
|
|
292
|
-
const ctx = { varCounter: 0, helperCode: [], rootDefs: eRootDefs, shared: [], refStack: new Set(), schemaMap: schemaMap || null, anchors: eAnchors, rootE: schema, rootSchema: inputSchema, userFormats: userFormats || null,
|
|
292
|
+
const ctx = { noOrdinal: !!(sourceOpts && sourceOpts.noOrdinal), varCounter: 0, helperCode: [], rootDefs: eRootDefs, shared: [], refStack: new Set(), schemaMap: schemaMap || null, anchors: eAnchors, rootE: schema, rootSchema: inputSchema, userFormats: userFormats || null,
|
|
293
293
|
// Custom format checkers referenced by the body, bound as
|
|
294
294
|
// closure parameters below the way the other entry points do.
|
|
295
295
|
closureVars: [], closureVals: [],
|
|
@@ -1143,7 +1143,8 @@ function genCodeENode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
1143
1143
|
|
|
1144
1144
|
// enum
|
|
1145
1145
|
if (schema.enum) {
|
|
1146
|
-
|
|
1146
|
+
const ev = enumOperand(ctx, schema.enum, v, lines)
|
|
1147
|
+
lines.push(`if(!(${enumCondition(ctx, schema.enum, ev)})){${fail('enum', 'enum', `{allowedValues:${JSON.stringify(schema.enum)}}`, "'must be equal to one of the allowed values'")}}`)
|
|
1147
1148
|
}
|
|
1148
1149
|
|
|
1149
1150
|
// const — use canonical (sorted-key) comparison for objects
|
|
@@ -1351,9 +1352,15 @@ function genCodeENode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
1351
1352
|
if (schema.properties) {
|
|
1352
1353
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1353
1354
|
const childPath = childPathExpr(pathExpr, ptrSeg(key))
|
|
1355
|
+
const sp = schemaPrefix+'/properties/'+ptrSeg(key)
|
|
1356
|
+
const from = lines.length
|
|
1354
1357
|
lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&${ownKeyExpr(ctx, v, key)}){`)
|
|
1355
|
-
|
|
1358
|
+
// A large subschema as a function of its own (emitPropFnE); false means inline.
|
|
1359
|
+
if (!propFnCandidateE(prop, ctx, sp) || !emitPropFnE(prop, `${v}[${JSON.stringify(key)}]`, childPath, lines, ctx, sp)) {
|
|
1360
|
+
genCodeE(prop, `${v}[${JSON.stringify(key)}]`, childPath, lines, ctx, sp)
|
|
1361
|
+
}
|
|
1356
1362
|
lines.push(`}`)
|
|
1363
|
+
countInlineE(lines, from, ctx)
|
|
1357
1364
|
}
|
|
1358
1365
|
}
|
|
1359
1366
|
|
|
@@ -2039,6 +2046,86 @@ function emitSharedDefC(defName, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
2039
2046
|
return true
|
|
2040
2047
|
}
|
|
2041
2048
|
|
|
2049
|
+
// The same split for the error collector (genCodeE): a large property
|
|
2050
|
+
// subschema becomes `_pe<n>(d,_p,_all,_e)` in the helper code, pushing into
|
|
2051
|
+
// the caller's list as an inlined body would, generated against the real
|
|
2052
|
+
// schema path since it has one call site. Not inside a shared definition's
|
|
2053
|
+
// body, whose placeholder path is substituted after the fact.
|
|
2054
|
+
function propFnCandidateE (prop, ctx, schemaPrefix) {
|
|
2055
|
+
if (!ctx || ctx.nestedBoolean || ctx.condDepth) return false
|
|
2056
|
+
if (typeof schemaPrefix !== 'string' || schemaPrefix.includes(SP_PLACEHOLDER)) return false
|
|
2057
|
+
if (!prop || typeof prop !== 'object' || Array.isArray(prop)) return false
|
|
2058
|
+
let size = 0
|
|
2059
|
+
try { size = JSON.stringify(prop).length } catch { return false }
|
|
2060
|
+
return size >= SPLIT_C_SCHEMA || ((ctx.fnBytesE || 0) > SPLIT_C_BUDGET && size >= SPLIT_C_SMALL)
|
|
2061
|
+
}
|
|
2062
|
+
function emitPropFnE (prop, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
2063
|
+
const outerBytes = ctx.fnBytesE
|
|
2064
|
+
ctx.fnBytesE = 0
|
|
2065
|
+
const bodyLines = []
|
|
2066
|
+
try { genCodeE(prop, 'd', '_p', bodyLines, ctx, schemaPrefix) } finally { ctx.fnBytesE = outerBytes }
|
|
2067
|
+
if (bodyLines.length === 0) return false
|
|
2068
|
+
const body = bodyLines.join('\n ')
|
|
2069
|
+
if (body.includes(SP_PLACEHOLDER)) return false
|
|
2070
|
+
const fnName = '_pe' + (ctx.propFnsE = (ctx.propFnsE || 0) + 1)
|
|
2071
|
+
ctx.helperCode.push(`function ${fnName}(d,_p,_all,_e){${body}}`)
|
|
2072
|
+
lines.push(`${fnName}(${v},${pathExpr || '""'},_all,_e);if(!_all&&_e.length)return{valid:false,errors:_e}`)
|
|
2073
|
+
return true
|
|
2074
|
+
}
|
|
2075
|
+
function countInlineE (lines, from, ctx) {
|
|
2076
|
+
let n = 0
|
|
2077
|
+
for (let i = from; i < lines.length; i++) n += lines[i].length
|
|
2078
|
+
ctx.fnBytesE = (ctx.fnBytesE || 0) + n
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// A large property subschema as a function of its own, for the reason the
|
|
2082
|
+
// verdict generator has (emitPropFn in js-compiler.js): one function per
|
|
2083
|
+
// schema outgrew what V8 optimizes, and a 167 KB configuration schema's
|
|
2084
|
+
// one-pass function was 3.8 MB of source that ran in the interpreter. The
|
|
2085
|
+
// function is used at one site, so it is generated against the real schema
|
|
2086
|
+
// path and its errors keep their precise ordinal keys; it is not written
|
|
2087
|
+
// inside a shared definition's body, whose placeholder path is substituted
|
|
2088
|
+
// after the fact and would not reach a helper of its own.
|
|
2089
|
+
const SPLIT_C_SCHEMA = 1500
|
|
2090
|
+
const SPLIT_C_SMALL = 160
|
|
2091
|
+
const SPLIT_C_BUDGET = 16 * 1024
|
|
2092
|
+
function propFnCandidateC (prop, ctx, schemaPrefix) {
|
|
2093
|
+
if (!ctx || ctx.inDefC || ctx.nestedBoolean || ctx.condDepth) return false
|
|
2094
|
+
if (typeof schemaPrefix !== 'string' || schemaPrefix.includes(SP_PLACEHOLDER)) return false
|
|
2095
|
+
if (!prop || typeof prop !== 'object' || Array.isArray(prop)) return false
|
|
2096
|
+
let size = 0
|
|
2097
|
+
try { size = JSON.stringify(prop).length } catch { return false }
|
|
2098
|
+
return size >= SPLIT_C_SCHEMA || ((ctx.fnBytesC || 0) > SPLIT_C_BUDGET && size >= SPLIT_C_SMALL)
|
|
2099
|
+
}
|
|
2100
|
+
function emitPropFnC (prop, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
2101
|
+
const outerHoisted = ctx.hoisted
|
|
2102
|
+
ctx.hoisted = []
|
|
2103
|
+
const outerBytes = ctx.fnBytesC
|
|
2104
|
+
ctx.fnBytesC = 0
|
|
2105
|
+
const bodyLines = []
|
|
2106
|
+
let hoisted
|
|
2107
|
+
try {
|
|
2108
|
+
genGuardedC(prop, '_dv', '_p', bodyLines, ctx, schemaPrefix)
|
|
2109
|
+
} finally {
|
|
2110
|
+
hoisted = ctx.hoisted
|
|
2111
|
+
ctx.hoisted = outerHoisted
|
|
2112
|
+
ctx.fnBytesC = outerBytes
|
|
2113
|
+
}
|
|
2114
|
+
if (bodyLines.length === 0) return false
|
|
2115
|
+
const body = bodyLines.join('\n ')
|
|
2116
|
+
if (body.includes(SP_PLACEHOLDER) || /\b_so\b/.test(body)) return false
|
|
2117
|
+
const decl = hoisted.length ? `let ${hoisted.map((n) => n + '=null').join(',')};` : ''
|
|
2118
|
+
const fnName = '_pc' + (ctx.propFnsC = (ctx.propFnsC || 0) + 1)
|
|
2119
|
+
ctx.helperCode.push(`function ${fnName}(_dv,_p,d){const _all=true;${decl}let _e;\n ${body}\n return _e}`)
|
|
2120
|
+
lines.push(`{const _r=${fnName}(${v},${pathExpr || '""'},d);if(_r!==undefined){if(_e===undefined)_e=_r;else for(let _i=0;_i<_r.length;_i++)_e.push(_r[_i])}}`)
|
|
2121
|
+
return true
|
|
2122
|
+
}
|
|
2123
|
+
function countInlineC (lines, from, ctx) {
|
|
2124
|
+
let n = 0
|
|
2125
|
+
for (let i = from; i < lines.length; i++) n += lines[i].length
|
|
2126
|
+
ctx.fnBytesC = (ctx.fnBytesC || 0) + n
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2042
2129
|
// One schema as a function of its own in the combined function (see
|
|
2043
2130
|
// emitSharedDefC). The name is registered before the body is written, so a
|
|
2044
2131
|
// reference back to it inside becomes a call. One that can re-enter itself,
|
|
@@ -2244,7 +2331,8 @@ function genCodeCNode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
2244
2331
|
const emitEnumConst = () => {
|
|
2245
2332
|
// enum
|
|
2246
2333
|
if (schema.enum) {
|
|
2247
|
-
|
|
2334
|
+
const ev = enumOperand(ctx, schema.enum, v, lines)
|
|
2335
|
+
lines.push(`if(!(${enumCondition(ctx, schema.enum, ev)})){${fail('enum', 'enum', `{allowedValues:${JSON.stringify(schema.enum)}}`, "'must be equal to one of the allowed values'")}}`)
|
|
2248
2336
|
}
|
|
2249
2337
|
|
|
2250
2338
|
// const
|
|
@@ -2507,21 +2595,28 @@ function genCodeCNode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
2507
2595
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
2508
2596
|
const pv = hoisted[key] || `${v}[${JSON.stringify(key)}]`
|
|
2509
2597
|
const childPath = childPathExpr(pathExpr, ptrSeg(key))
|
|
2598
|
+
const sp = schemaPrefix+'/properties/'+ptrSeg(key)
|
|
2599
|
+
const from = lines.length
|
|
2600
|
+
const split = propFnCandidateC(prop, ctx, sp)
|
|
2601
|
+
// A large subschema as a function of its own (emitPropFnC), called
|
|
2602
|
+
// where the inline code would be; false means it is written inline.
|
|
2603
|
+
const sub = (pvExpr) => { if (!split || !emitPropFnC(prop, pvExpr, childPath, lines, ctx, sp)) genGuardedC(prop, pvExpr, childPath, lines, ctx, sp) }
|
|
2510
2604
|
if (requiredSet.has(key) && isObj) {
|
|
2511
2605
|
// A hoisted local was already cleared if the value is only inherited.
|
|
2512
2606
|
lines.push(`if(${pv}!==undefined${hoisted[key] ? '' : '&&' + ownGuard(ctx, v, key)}){`)
|
|
2513
|
-
|
|
2607
|
+
sub(pv)
|
|
2514
2608
|
lines.push(`}`)
|
|
2515
2609
|
} else if (isObj) {
|
|
2516
2610
|
const oi = ctx.varCounter++
|
|
2517
2611
|
lines.push(`{const _o${oi}=${v}[${JSON.stringify(key)}];if(_o${oi}!==undefined&&${ownGuard(ctx, v, key)}){`)
|
|
2518
|
-
|
|
2612
|
+
sub(`_o${oi}`)
|
|
2519
2613
|
lines.push(`}}`)
|
|
2520
2614
|
} else {
|
|
2521
2615
|
lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})&&${ownKeyExpr(ctx, v, key)}){`)
|
|
2522
|
-
|
|
2616
|
+
sub(`${v}[${JSON.stringify(key)}]`)
|
|
2523
2617
|
lines.push(`}`)
|
|
2524
2618
|
}
|
|
2619
|
+
countInlineC(lines, from, ctx)
|
|
2525
2620
|
}
|
|
2526
2621
|
}
|
|
2527
2622
|
|
package/lib/js-compiler.js
CHANGED
|
@@ -135,6 +135,21 @@ function emitConstant(ctx, value) {
|
|
|
135
135
|
return name
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// The operand an `enum` test compares: `v` itself when it is a plain
|
|
139
|
+
// identifier, otherwise a local bound once. The test is a chain of `===`,
|
|
140
|
+
// one per member, and each used to repeat the access expression, so a
|
|
141
|
+
// 32-member enum on a required property read `_e3["tool"]` 32 times; on an
|
|
142
|
+
// array of items in several shapes those reads are polymorphic and cost
|
|
143
|
+
// 59 ns against 20 with the value in a local. The binding goes to `lines`
|
|
144
|
+
// ahead of the test.
|
|
145
|
+
const IDENT_RE = /^[A-Za-z_$][\w$]*$/
|
|
146
|
+
function enumOperand(ctx, vals, v, lines) {
|
|
147
|
+
if (IDENT_RE.test(v) || vals.length < 2) return v
|
|
148
|
+
const name = `_ev${ctx.varCounter++}`
|
|
149
|
+
lines.push(`const ${name}=${v}`)
|
|
150
|
+
return name
|
|
151
|
+
}
|
|
152
|
+
|
|
138
153
|
// One `enum` test: primitives compare with `===`, which needs no call, and
|
|
139
154
|
// object members go through structural equality.
|
|
140
155
|
function enumCondition(ctx, vals, v) {
|
|
@@ -1161,6 +1176,60 @@ function _setCodeBudget (n) { codeBudget = n === undefined ? CODE_BUDGET : n }
|
|
|
1161
1176
|
// document that reached it, and the second cut the cycle, so the reference
|
|
1162
1177
|
// checked nothing. While `nestedBoolean` is set, genCode declines at those
|
|
1163
1178
|
// points instead, and the caller's generator declines the schema.
|
|
1179
|
+
// A property whose subschema is large becomes a function of its own in the
|
|
1180
|
+
// preamble, called where the property is checked, instead of its code inline.
|
|
1181
|
+
// V8 does not optimize a function past its bytecode budget (about 60 KB), and
|
|
1182
|
+
// a configuration schema of a few hundred properties compiled to one function
|
|
1183
|
+
// of a megabyte or more that ran in the interpreter for its whole life: on a
|
|
1184
|
+
// 167 KB schema the verdict took 407 us where the same checks in functions of
|
|
1185
|
+
// their own take 40. The threshold is on the schema's own size, which is
|
|
1186
|
+
// known before any code is written, so nothing is generated twice. A
|
|
1187
|
+
// property moves out on its own only when its schema is plainly large; the
|
|
1188
|
+
// usual case is the budget: once a function holds SPLIT_FN_BUDGET bytes of
|
|
1189
|
+
// inline code, every property past SPLIT_PROP_SMALL moves out, so a schema
|
|
1190
|
+
// of many middling properties splits after its first functions' worth and a
|
|
1191
|
+
// small or medium one, whose whole program fits the budget, never does and
|
|
1192
|
+
// pays no call.
|
|
1193
|
+
const SPLIT_PROP_SCHEMA = 2000
|
|
1194
|
+
const SPLIT_PROP_SMALL = 220
|
|
1195
|
+
const SPLIT_FN_BUDGET = 24 * 1024
|
|
1196
|
+
function propSchemaSize (prop) {
|
|
1197
|
+
try { return JSON.stringify(prop).length } catch { return 0 }
|
|
1198
|
+
}
|
|
1199
|
+
function propFnCandidate (prop, ctx) {
|
|
1200
|
+
if (!ctx.preamble || ctx.nestedBoolean || ctx.condDepth) return false
|
|
1201
|
+
if (!prop || typeof prop !== 'object' || Array.isArray(prop)) return false
|
|
1202
|
+
const size = propSchemaSize(prop)
|
|
1203
|
+
return size >= SPLIT_PROP_SCHEMA || ((ctx.fnBytes || 0) > SPLIT_FN_BUDGET && size >= SPLIT_PROP_SMALL)
|
|
1204
|
+
}
|
|
1205
|
+
// Generated over its own `d`, the way a shared definition is (see the $ref
|
|
1206
|
+
// case in genCodeNode): the deferred checks belong to this body, and the
|
|
1207
|
+
// plain-object reuse state must not leak in or out. Null means "write it
|
|
1208
|
+
// inline after all": an empty body (the inline path then asserts it the
|
|
1209
|
+
// usual way) or one that calls the recursive entry, which is out of scope
|
|
1210
|
+
// in the preamble.
|
|
1211
|
+
function emitPropFn (prop, ctx) {
|
|
1212
|
+
const bodyLines = []
|
|
1213
|
+
const outerDeferred = ctx.deferredChecks
|
|
1214
|
+
ctx.deferredChecks = null
|
|
1215
|
+
const outerReuse = ctx.plainReuse
|
|
1216
|
+
ctx.plainReuse = undefined
|
|
1217
|
+
const outerBytes = ctx.fnBytes
|
|
1218
|
+
ctx.fnBytes = 0
|
|
1219
|
+
try { genCode(prop, 'd', bodyLines, ctx) } finally { ctx.plainReuse = outerReuse; ctx.fnBytes = outerBytes }
|
|
1220
|
+
if (ctx.deferredChecks) for (const dc of ctx.deferredChecks) bodyLines.push(dc)
|
|
1221
|
+
ctx.deferredChecks = outerDeferred
|
|
1222
|
+
if (bodyLines.length === 0 || bodyLines.some((l) => /\b_validate\b/.test(l))) return null
|
|
1223
|
+
const fnName = '_pf' + (ctx.propFns = (ctx.propFns || 0) + 1)
|
|
1224
|
+
hoist(ctx, `function ${fnName}(d){${bodyLines.join('\n ')}\n return true}`)
|
|
1225
|
+
return fnName
|
|
1226
|
+
}
|
|
1227
|
+
function countInline (lines, from, ctx) {
|
|
1228
|
+
let n = 0
|
|
1229
|
+
for (let i = from; i < lines.length; i++) n += lines[i].length
|
|
1230
|
+
ctx.fnBytes = (ctx.fnBytes || 0) + n
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1164
1233
|
function nestedGenCode(schema, v, lines, ctx) {
|
|
1165
1234
|
ctx.nestedBoolean = (ctx.nestedBoolean || 0) + 1
|
|
1166
1235
|
const before = lines.length
|
|
@@ -1262,6 +1331,14 @@ function sharedDefNames (root, defs) {
|
|
|
1262
1331
|
}
|
|
1263
1332
|
return out
|
|
1264
1333
|
}
|
|
1334
|
+
// Raising this to inline small definitions at every site was measured and
|
|
1335
|
+
// rejected: SchemaStore's detekt applies one 200-character rule definition
|
|
1336
|
+
// at 293 sites, and inlining it took the verdict from 5287 ns to 452 but the
|
|
1337
|
+
// standalone module from 168 KB to 1692 KB and its compile to 33 ms. The
|
|
1338
|
+
// slowness of the shared function is megamorphic property reads (474 objects
|
|
1339
|
+
// of 72 shapes through one function); a for-in body for the shared function
|
|
1340
|
+
// was tried too and gave 1.5x, not enough to carry its complexity. Left as a
|
|
1341
|
+
// known trade: on that shape the shared function costs 27 ns a call.
|
|
1265
1342
|
const SHARED_DEF_MIN_CHARS = 120
|
|
1266
1343
|
|
|
1267
1344
|
function cyclicDefNames (defs) {
|
|
@@ -1932,8 +2009,32 @@ function sharedCodegenGate(schema, schemaMap) {
|
|
|
1932
2009
|
_gateSchema = schema; _gateMap = schemaMap; _gateOk = ok
|
|
1933
2010
|
return ok
|
|
1934
2011
|
}
|
|
2012
|
+
// `unevaluatedProperties` or `unevaluatedItems` beside a `$ref` back to the
|
|
2013
|
+
// document root: the generated evaluated-set tracking does not credit what
|
|
2014
|
+
// the root evaluates through that reference, so a tree whose branches say
|
|
2015
|
+
// `{ unevaluatedProperties: false, $ref: '#' }` rejected valid branches (a
|
|
2016
|
+
// wrong reject, found through the 2019-09 `$recursiveRef` tests, and the same
|
|
2017
|
+
// in 2020-12). The interpreted engine answers it. A text check first: almost
|
|
2018
|
+
// no schema has both.
|
|
2019
|
+
function unevaluatedBesideRootRef(schema) {
|
|
2020
|
+
const text = JSON.stringify(schema)
|
|
2021
|
+
if (!text.includes('"$ref":"#"') || !/"unevaluated(?:Properties|Items)"/.test(text)) return false
|
|
2022
|
+
let found = false
|
|
2023
|
+
const seen = new Set()
|
|
2024
|
+
const walk = (n) => {
|
|
2025
|
+
if (found || n === null || typeof n !== 'object' || seen.has(n)) return
|
|
2026
|
+
seen.add(n)
|
|
2027
|
+
if (Array.isArray(n)) { for (const x of n) walk(x); return }
|
|
2028
|
+
if (n.$ref === '#' && (n.unevaluatedProperties !== undefined || n.unevaluatedItems !== undefined)) { found = true; return }
|
|
2029
|
+
for (const [k, v] of Object.entries(n)) if (k !== 'enum' && k !== 'const' && k !== 'default' && k !== 'examples') walk(v)
|
|
2030
|
+
}
|
|
2031
|
+
walk(schema)
|
|
2032
|
+
return found
|
|
2033
|
+
}
|
|
2034
|
+
|
|
1935
2035
|
function sharedCodegenGateUncached(schema, schemaMap) {
|
|
1936
2036
|
if (bothDefsContainers(schema)) return false
|
|
2037
|
+
if (unevaluatedBesideRootRef(schema)) return false
|
|
1937
2038
|
if (hasSameInstanceRefCycle(schema)) return false
|
|
1938
2039
|
if (!codegenSafe(schema, schemaMap)) return false
|
|
1939
2040
|
if (needsBaseTracking(schema, schemaMap, new Set())) return false
|
|
@@ -3243,7 +3344,8 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
|
|
|
3243
3344
|
|
|
3244
3345
|
// enum
|
|
3245
3346
|
if (schema.enum) {
|
|
3246
|
-
|
|
3347
|
+
const ev = enumOperand(ctx, schema.enum, v, lines)
|
|
3348
|
+
lines.push(`if(!(${enumCondition(ctx, schema.enum, ev)}))return false`)
|
|
3247
3349
|
}
|
|
3248
3350
|
|
|
3249
3351
|
// const
|
|
@@ -3498,11 +3600,17 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
|
|
|
3498
3600
|
// properties — use hoisted vars for required props, hoist optional to locals too
|
|
3499
3601
|
if (schema.properties) {
|
|
3500
3602
|
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
3603
|
+
const from = lines.length
|
|
3604
|
+
// A large subschema as a function of its own (emitPropFn); the call
|
|
3605
|
+
// takes the place of the inline code in each of the three shapes below.
|
|
3606
|
+
const fn = propFnCandidate(prop, ctx) ? emitPropFn(prop, ctx) : null
|
|
3501
3607
|
if (requiredSet.has(key) && isObj) {
|
|
3502
3608
|
// Required + type:object — hoist to local to reduce repeated property lookups
|
|
3503
3609
|
const access = hoisted[key] || `${v}[${JSON.stringify(key)}]`
|
|
3504
|
-
const combined = tryGenCombined(prop, access, ctx)
|
|
3505
|
-
if (
|
|
3610
|
+
const combined = fn ? null : tryGenCombined(prop, access, ctx)
|
|
3611
|
+
if (fn) {
|
|
3612
|
+
lines.push(`if(!${fn}(${access}))return false`)
|
|
3613
|
+
} else if (combined) {
|
|
3506
3614
|
lines.push(combined)
|
|
3507
3615
|
} else if (needsLocal(prop) || isPlainContainer(prop)) {
|
|
3508
3616
|
const oi = ctx.varCounter++
|
|
@@ -3518,8 +3626,10 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
|
|
|
3518
3626
|
const oi = ctx.varCounter++
|
|
3519
3627
|
const local = `_o${oi}`
|
|
3520
3628
|
lines.push(`{const ${local}=${v}[${JSON.stringify(key)}];if(${local}!==undefined&&${ownGuard(ctx, v, key)}){`)
|
|
3521
|
-
const combined = tryGenCombined(prop, local, ctx)
|
|
3522
|
-
if (
|
|
3629
|
+
const combined = fn ? null : tryGenCombined(prop, local, ctx)
|
|
3630
|
+
if (fn) {
|
|
3631
|
+
lines.push(`if(!${fn}(${local}))return false`)
|
|
3632
|
+
} else if (combined) {
|
|
3523
3633
|
lines.push(combined)
|
|
3524
3634
|
} else {
|
|
3525
3635
|
genCode(prop, local, lines, ctx)
|
|
@@ -3527,9 +3637,11 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
|
|
|
3527
3637
|
lines.push(`}}`)
|
|
3528
3638
|
} else {
|
|
3529
3639
|
lines.push(`if(typeof ${v}==='object'&&${v}!==null&&${ownKeyExpr(ctx, v, key)}){`)
|
|
3530
|
-
|
|
3640
|
+
if (fn) lines.push(`if(!${fn}(${v}[${JSON.stringify(key)}]))return false`)
|
|
3641
|
+
else genCode(prop, `${v}[${JSON.stringify(key)}]`, lines, ctx)
|
|
3531
3642
|
lines.push(`}`)
|
|
3532
3643
|
}
|
|
3644
|
+
countInline(lines, from, ctx)
|
|
3533
3645
|
}
|
|
3534
3646
|
}
|
|
3535
3647
|
|
|
@@ -5307,4 +5419,4 @@ Object.defineProperty(module.exports, '_expandDynamicScopes', { value: expandDyn
|
|
|
5307
5419
|
// For tests/test_custom_keyword_codegen.js, which holds these copies to the interpreter's.
|
|
5308
5420
|
Object.defineProperty(module.exports, '_kwTypeBits', { value: { kwTypeBit, kwDataBits, KW_T_ANY }, enumerable: false })
|
|
5309
5421
|
|
|
5310
|
-
module.exports._internal = { hasConstraints, assertEmitted, prepareForCodegen, sharedCodegenGate, codegenSafe, isSimplePN, hasUnresolvableRef, needsBaseTracking, _cpLen, sharedRt, DECLINE, bindRt, compileSafe, emitGuardState, withPlain, REF_NEUTRAL_SIBLINGS, resolveCrossSchemaRef, enumCondition, emitDeq, emitConstant, ownGuard, ownKeyExpr, multipleOfBad, compilePatternInline, useSafeEngine, reFlags, FORMAT_CODEGEN, PROTO_NAMES, setOwn, nestedGenCode, compileToJSCodegen, SKIP_VALUE_KEYS, skipString, CYCLE_DEPTH, cyclicDefNames, sharedDefNames, reFlagArg, hoistOnce, PTR_ESC_HELPER, unevalContributions, emitUq, uqSources, safeReClosure, fastPrefixCheck, replaceTopLevel, refTargetFor, genCode, addLocalAnnotations, addTopApplicatorAnnotations, protoIs, ANNOT_APPLICATORS, SIZE_SKIPS, emitRootGuard, emitGuardedRun }
|
|
5422
|
+
module.exports._internal = { hasConstraints, assertEmitted, prepareForCodegen, sharedCodegenGate, codegenSafe, isSimplePN, hasUnresolvableRef, needsBaseTracking, _cpLen, sharedRt, DECLINE, bindRt, compileSafe, emitGuardState, withPlain, REF_NEUTRAL_SIBLINGS, resolveCrossSchemaRef, enumCondition, enumOperand, emitDeq, emitConstant, ownGuard, ownKeyExpr, multipleOfBad, compilePatternInline, useSafeEngine, reFlags, FORMAT_CODEGEN, PROTO_NAMES, setOwn, nestedGenCode, compileToJSCodegen, SKIP_VALUE_KEYS, skipString, CYCLE_DEPTH, cyclicDefNames, sharedDefNames, reFlagArg, hoistOnce, PTR_ESC_HELPER, unevalContributions, emitUq, uqSources, safeReClosure, fastPrefixCheck, replaceTopLevel, refTargetFor, genCode, addLocalAnnotations, addTopApplicatorAnnotations, protoIs, ANNOT_APPLICATORS, SIZE_SKIPS, emitRootGuard, emitGuardedRun }
|
package/lib/metaschemas.js
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// The official meta-schemas, vendored so a `$ref` to one of them resolves
|
|
4
4
|
// without a network. Draft 2020-12 is eight documents joined by $dynamicRef;
|
|
5
|
-
// draft-07
|
|
6
|
-
//
|
|
5
|
+
// draft-07 and draft-06 are one each; 2019-09 is seven. Sources:
|
|
6
|
+
// https://json-schema.org/draft/2020-12/schema and
|
|
7
|
+
// http://json-schema.org/draft-07/schema, fetched 2026-08-23, and
|
|
8
|
+
// http://json-schema.org/draft-06/schema and
|
|
9
|
+
// https://json-schema.org/draft/2019-09/schema, fetched 2026-10-10, unmodified.
|
|
10
|
+
// The 2019-09 documents are read through the same 2019-09 rewrite as a
|
|
11
|
+
// caller's schema (lib/draft7.js) once, at load, since they use
|
|
12
|
+
// `$recursiveRef`, which the engines read as `$dynamicRef`.
|
|
7
13
|
// Keyed by $id; index.js also registers the http/https and trailing-# spellings.
|
|
8
14
|
|
|
9
15
|
const METASCHEMAS = new Map([
|
|
@@ -16,6 +22,19 @@ const METASCHEMAS = new Map([
|
|
|
16
22
|
["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
23
|
["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
24
|
["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}],
|
|
25
|
+
["http://json-schema.org/draft-06/schema#", {"$schema":"http://json-schema.org/draft-06/schema#","$id":"http://json-schema.org/draft-06/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"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"examples":{"type":"array","items":{}},"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":{}},"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":{},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":{}}],
|
|
26
|
+
["https://json-schema.org/draft/2019-09/schema", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/schema","$vocabulary":{"https://json-schema.org/draft/2019-09/vocab/core":true,"https://json-schema.org/draft/2019-09/vocab/applicator":true,"https://json-schema.org/draft/2019-09/vocab/validation":true,"https://json-schema.org/draft/2019-09/vocab/meta-data":true,"https://json-schema.org/draft/2019-09/vocab/format":false,"https://json-schema.org/draft/2019-09/vocab/content":true},"$recursiveAnchor":true,"title":"Core and Validation specifications meta-schema","allOf":[{"$ref":"meta/core"},{"$ref":"meta/applicator"},{"$ref":"meta/validation"},{"$ref":"meta/meta-data"},{"$ref":"meta/format"},{"$ref":"meta/content"}],"type":["object","boolean"],"properties":{"definitions":{"$comment":"While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.","type":"object","additionalProperties":{"$recursiveRef":"#"},"default":{}},"dependencies":{"$comment":"\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"","type":"object","additionalProperties":{"anyOf":[{"$recursiveRef":"#"},{"$ref":"meta/validation#/$defs/stringArray"}]}}}}],
|
|
27
|
+
["https://json-schema.org/draft/2019-09/meta/core", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/core","$recursiveAnchor":true,"title":"Core vocabulary meta-schema","type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference","$comment":"Non-empty fragments not allowed.","pattern":"^[^#]*#?$"},"$schema":{"type":"string","format":"uri"},"$anchor":{"type":"string","pattern":"^[A-Za-z][-A-Za-z0-9.:_]*$"},"$ref":{"type":"string","format":"uri-reference"},"$recursiveRef":{"type":"string","format":"uri-reference"},"$recursiveAnchor":{"type":"boolean","default":false},"$vocabulary":{"type":"object","propertyNames":{"type":"string","format":"uri"},"additionalProperties":{"type":"boolean"}},"$comment":{"type":"string"},"$defs":{"type":"object","additionalProperties":{"$recursiveRef":"#"},"default":{}}}}],
|
|
28
|
+
["https://json-schema.org/draft/2019-09/meta/applicator", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/applicator","$recursiveAnchor":true,"title":"Applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"additionalItems":{"$recursiveRef":"#"},"unevaluatedItems":{"$recursiveRef":"#"},"items":{"anyOf":[{"$recursiveRef":"#"},{"$ref":"#/$defs/schemaArray"}]},"contains":{"$recursiveRef":"#"},"additionalProperties":{"$recursiveRef":"#"},"unevaluatedProperties":{"$recursiveRef":"#"},"properties":{"type":"object","additionalProperties":{"$recursiveRef":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$recursiveRef":"#"},"propertyNames":{"format":"regex"},"default":{}},"dependentSchemas":{"type":"object","additionalProperties":{"$recursiveRef":"#"}},"propertyNames":{"$recursiveRef":"#"},"if":{"$recursiveRef":"#"},"then":{"$recursiveRef":"#"},"else":{"$recursiveRef":"#"},"allOf":{"$ref":"#/$defs/schemaArray"},"anyOf":{"$ref":"#/$defs/schemaArray"},"oneOf":{"$ref":"#/$defs/schemaArray"},"not":{"$recursiveRef":"#"}},"$defs":{"schemaArray":{"type":"array","minItems":1,"items":{"$recursiveRef":"#"}}}}],
|
|
29
|
+
["https://json-schema.org/draft/2019-09/meta/validation", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/validation","$recursiveAnchor":true,"title":"Validation vocabulary meta-schema","type":["object","boolean"],"properties":{"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"}},"const":true,"enum":{"type":"array","items":true},"type":{"anyOf":[{"$ref":"#/$defs/simpleTypes"},{"type":"array","items":{"$ref":"#/$defs/simpleTypes"},"minItems":1,"uniqueItems":true}]}},"$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":[]}}}],
|
|
30
|
+
["https://json-schema.org/draft/2019-09/meta/meta-data", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/meta-data","$recursiveAnchor":true,"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}}}],
|
|
31
|
+
["https://json-schema.org/draft/2019-09/meta/format", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/format","$recursiveAnchor":true,"title":"Format vocabulary meta-schema","type":["object","boolean"],"properties":{"format":{"type":"string"}}}],
|
|
32
|
+
["https://json-schema.org/draft/2019-09/meta/content", {"$schema":"https://json-schema.org/draft/2019-09/schema","$id":"https://json-schema.org/draft/2019-09/meta/content","$recursiveAnchor":true,"title":"Content vocabulary meta-schema","type":["object","boolean"],"properties":{"contentMediaType":{"type":"string"},"contentEncoding":{"type":"string"},"contentSchema":{"$recursiveRef":"#"}}}],
|
|
19
33
|
]);
|
|
20
34
|
|
|
35
|
+
{
|
|
36
|
+
const { isDraft2019, normalizeDraft2019 } = require('./draft7')
|
|
37
|
+
for (const [id, doc] of METASCHEMAS) if (isDraft2019(doc)) METASCHEMAS.set(id, normalizeDraft2019(JSON.parse(JSON.stringify(doc)), true))
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
module.exports = { METASCHEMAS };
|