@jetio/validator 1.0.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1362 -0
  3. package/dist/cli.js +219 -0
  4. package/dist/compileSchema.d.ts +148 -0
  5. package/dist/compileSchema.js +2199 -0
  6. package/dist/compileSchema.js.map +1 -0
  7. package/dist/formats.d.ts +41 -0
  8. package/dist/formats.js +166 -0
  9. package/dist/formats.js.map +1 -0
  10. package/dist/index.cjs.js +6167 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.esm.js +6148 -0
  13. package/dist/index.js +28 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/jet-validator.d.ts +88 -0
  16. package/dist/jet-validator.js +983 -0
  17. package/dist/jet-validator.js.map +1 -0
  18. package/dist/resolver.d.ts +348 -0
  19. package/dist/resolver.js +2459 -0
  20. package/dist/resolver.js.map +1 -0
  21. package/dist/scripts/load-metaschemas.d.ts +1 -0
  22. package/dist/scripts/metaschema-loader.d.ts +2 -0
  23. package/dist/src/compileSchema.d.ts +148 -0
  24. package/dist/src/formats.d.ts +41 -0
  25. package/dist/src/index.d.ts +9 -0
  26. package/dist/src/jet-validator.d.ts +88 -0
  27. package/dist/src/resolver.d.ts +348 -0
  28. package/dist/src/types/format.d.ts +7 -0
  29. package/dist/src/types/keywords.d.ts +78 -0
  30. package/dist/src/types/schema.d.ts +123 -0
  31. package/dist/src/types/standalone.d.ts +4 -0
  32. package/dist/src/types/validation.d.ts +49 -0
  33. package/dist/src/utilities/index.d.ts +11 -0
  34. package/dist/src/utilities/schema.d.ts +10 -0
  35. package/dist/types/format.d.ts +7 -0
  36. package/dist/types/format.js +3 -0
  37. package/dist/types/format.js.map +1 -0
  38. package/dist/types/keywords.d.ts +78 -0
  39. package/dist/types/keywords.js +4 -0
  40. package/dist/types/keywords.js.map +1 -0
  41. package/dist/types/schema.d.ts +123 -0
  42. package/dist/types/schema.js +3 -0
  43. package/dist/types/schema.js.map +1 -0
  44. package/dist/types/standalone.d.ts +4 -0
  45. package/dist/types/standalone.js +3 -0
  46. package/dist/types/standalone.js.map +1 -0
  47. package/dist/types/validation.d.ts +49 -0
  48. package/dist/types/validation.js +3 -0
  49. package/dist/types/validation.js.map +1 -0
  50. package/dist/utilities/index.d.ts +11 -0
  51. package/dist/utilities/index.js +146 -0
  52. package/dist/utilities/index.js.map +1 -0
  53. package/dist/utilities/schema.d.ts +10 -0
  54. package/dist/utilities/schema.js +232 -0
  55. package/dist/utilities/schema.js.map +1 -0
  56. package/dist/validator.umd.js +6196 -0
  57. package/package.json +79 -0
@@ -0,0 +1,2199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Compiler = void 0;
4
+ const utilities_1 = require("./utilities");
5
+ let counter = 0;
6
+ const PRIMITIVE_TYPES = new Set(["number", "string", "boolean", "integer"]);
7
+ const addEvaluatedProperty = (src, prop, options) => {
8
+ if (!options.shouldTrackEvaluatedProperties)
9
+ return;
10
+ src.push(options.hasOwnUnevaluatedProperties &&
11
+ options.parentHasUnevaluatedProperties
12
+ ? `${options.unEvaluatedPropertiesSetVar}.forEach(set => { set?.add(${prop}); });`
13
+ : `${options.unevaluatedPropVar}?.add(${prop});`);
14
+ };
15
+ const addEvaluatedItems = (src, prop, options) => {
16
+ if (!options.shouldTrackEvaluatedItems)
17
+ return;
18
+ src.push(options.hasOwnUnevaluatedItems && options.parentHasUnevaluatedItems
19
+ ? `${options.unEvaluatedItemsSetVar}.forEach(set => { set?.add(${prop}); });`
20
+ : `${options.unevaluatedItemVar}?.add(${prop});`);
21
+ };
22
+ const coerceToNumber = (src, schema, varName) => {
23
+ const isInteger = schema.type === "integer";
24
+ src.push(`if (typeof ${varName} === 'string') {`, ` const trimmed = ${varName}.trim();`, ` if (trimmed !== '' && !isNaN(Number(trimmed))) {`, ` ${varName} = Number(trimmed);`, ...(isInteger
25
+ ? [
26
+ ` if (Number.isInteger(${varName})) {`,
27
+ ` ${varName} = Math.trunc(${varName});`,
28
+ ` }`,
29
+ ]
30
+ : []), ` }`, `} else if (typeof ${varName} === 'boolean') {`, ` ${varName} = ${varName} ? 1 : 0;`, `}`);
31
+ };
32
+ const coerceToString = (src, varName) => {
33
+ src.push(`if (typeof ${varName} === 'number' || typeof ${varName} === 'boolean') {`, ` ${varName} = String(${varName});`, `}`);
34
+ };
35
+ const coerceToBoolean = (src, varName) => {
36
+ src.push(`if (typeof ${varName} === 'string') {`, ` const lower = ${varName}.toLowerCase();`, ` if (lower === 'true' || lower === '1') {`, ` ${varName} = true;`, ` } else if (lower === 'false' || lower === '0' || lower === '') {`, ` ${varName} = false;`, ` }`, `} else if (typeof ${varName} === 'number') {`, ` ${varName} = ${varName} !== 0;`, `}`);
37
+ };
38
+ const coerceToArray = (src, varName) => {
39
+ src.push(`if (!Array.isArray(${varName}) && ${varName} !== null && ${varName} !== undefined) {`, ` ${varName} = [${varName}];`, `}`);
40
+ };
41
+ const resolveDataPointerAtCompileTime = (pointer, currentDataPath, isInSubschema) => {
42
+ const rootVar = isInSubschema ? "data" : "rootData";
43
+ if (pointer.startsWith("/")) {
44
+ const parts = pointer.slice(1).split("/");
45
+ if (parts[0] === "")
46
+ return rootVar;
47
+ const accessPath = parts
48
+ .map((part) => {
49
+ const unescaped = part.replace(/~1/g, "/").replace(/~0/g, "~");
50
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(unescaped)
51
+ ? `.${unescaped}`
52
+ : `[${JSON.stringify(unescaped)}]`;
53
+ })
54
+ .join("");
55
+ return `${rootVar}${accessPath}`;
56
+ }
57
+ const levelsUp = parseInt(pointer[0]);
58
+ const restPath = pointer.slice(2);
59
+ const pathParts = currentDataPath.split("/").filter((p) => p);
60
+ const targetParts = pathParts.slice(0, -levelsUp);
61
+ if (restPath) {
62
+ targetParts.push(...restPath.split("/"));
63
+ }
64
+ if (targetParts.length === 0)
65
+ return rootVar;
66
+ const accessPath = targetParts
67
+ .map((part) => {
68
+ const unescaped = part.replace(/~1/g, "/").replace(/~0/g, "~");
69
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(unescaped))
70
+ return `.${unescaped}`;
71
+ if (/^\d+$/.test(unescaped))
72
+ return `[${unescaped}]`;
73
+ return `[${JSON.stringify(unescaped)}]`;
74
+ })
75
+ .join("");
76
+ return `${rootVar}${accessPath}`;
77
+ };
78
+ const isDataReference = (value) => {
79
+ return (typeof value === "object" &&
80
+ value !== null &&
81
+ "$data" in value &&
82
+ typeof value.$data === "string");
83
+ };
84
+ const generateNumberDataRef = (src, resolvedPath, extra, integer) => {
85
+ const comparisonTarget = "$data" + counter++;
86
+ src.push(`const ${comparisonTarget} = ${resolvedPath};`, `if (${extra.before}typeof ${comparisonTarget} === 'number' && Number.isFinite(${comparisonTarget})${integer ? ` && Number.isInteger(${comparisonTarget})` : ""}) {`);
87
+ return comparisonTarget;
88
+ };
89
+ const generateStringDataRef = (src, resolvedPath, extra) => {
90
+ const comparisonTarget = "$data" + counter++;
91
+ src.push(`const ${comparisonTarget} = ${resolvedPath};`, `if (${extra.before}typeof ${comparisonTarget} === 'string') {`);
92
+ return comparisonTarget;
93
+ };
94
+ const generateUndefinedDataRef = (src, resolvedPath, extra) => {
95
+ const comparisonTarget = "$data" + counter++;
96
+ src.push(`const ${comparisonTarget} = ${resolvedPath};`, `if (${extra.before}${comparisonTarget} !== undefined) {`);
97
+ return comparisonTarget;
98
+ };
99
+ const generateArrayDataRef = (src, resolvedPath, extra) => {
100
+ const comparisonTarget = "$data" + counter++;
101
+ src.push(`const ${comparisonTarget} = ${resolvedPath};`, `if (${extra.before}Array.isArray(${comparisonTarget})) {`);
102
+ return comparisonTarget;
103
+ };
104
+ class Compiler {
105
+ constructor(refables = [], schema, options, jetValidator, allKeywords, compileContext, standalone = false) {
106
+ this.refables = [];
107
+ this.ranRefables = false;
108
+ this.refCall = false;
109
+ this.errorVariableDeclared = false;
110
+ this.errorVariable = "allErrors";
111
+ this.compiledKeywords = new Map();
112
+ this.regexCache = new Map();
113
+ this.validateKeywords = new Set();
114
+ this.notLogic = false;
115
+ this.noreturn = false;
116
+ this.neutralError = false;
117
+ this.standAlone = false;
118
+ this.hasCompileKeyword = false;
119
+ this.needslen_of = false;
120
+ this.needsStringify = false;
121
+ this.needsDeepEqual = false;
122
+ this.mainFunctionName = "validate";
123
+ this.hoistedFunctions = [];
124
+ this.refables = refables;
125
+ this.schema = schema;
126
+ this.options = options;
127
+ this.jetValidator = jetValidator;
128
+ this.allKeywords = allKeywords;
129
+ this.compileContext = compileContext;
130
+ this.standAlone = standalone;
131
+ }
132
+ getCompiledKeywords() {
133
+ return {
134
+ compiledKeywords: this.compiledKeywords,
135
+ validateKeywords: this.validateKeywords,
136
+ hasCompileKeyword: this.hasCompileKeyword,
137
+ };
138
+ }
139
+ createSubschemaOptions(trackingState, pathContext, pathSegment, schema, dataSegment) {
140
+ const parentUnevProp = trackingState.parentHasUnevaluatedProperties === true ||
141
+ schema.unevaluatedProperties !== undefined;
142
+ const parentUnevItem = trackingState.parentHasUnevaluatedItems === true ||
143
+ schema.unevaluatedItems !== undefined;
144
+ return {
145
+ pathContext: {
146
+ schema: `${pathContext.schema}/${pathSegment ?? ""}`,
147
+ data: `${pathContext.data}${dataSegment ?? ""}`,
148
+ $data: `${pathContext.$data}${dataSegment ?? ""}`,
149
+ alt: pathContext.alt,
150
+ alt2: pathContext.alt2,
151
+ },
152
+ trackingState: {
153
+ parentHasUnevaluatedProperties: parentUnevProp,
154
+ parentUnevaluatedPropVar: parentUnevProp
155
+ ? trackingState.unevaluatedPropVar
156
+ : undefined,
157
+ parentHasUnevaluatedItems: trackingState.parentHasUnevaluatedItems === true ||
158
+ schema.unevaluatedItems !== undefined,
159
+ parentUnevaluatedItemVar: parentUnevItem
160
+ ? trackingState.unevaluatedItemVar
161
+ : undefined,
162
+ isSubschema: true,
163
+ },
164
+ };
165
+ }
166
+ handleCustomKeywords(src, schema, varName, pathContext, accessPattern, extra, trackingState) {
167
+ for (const [key, value] of Object.entries(schema)) {
168
+ const keywordDef = this.jetValidator.getKeyword(key);
169
+ if (!keywordDef || !(0, utilities_1.shouldApplyKeyword)(keywordDef, value))
170
+ continue;
171
+ if (keywordDef.metaSchema) {
172
+ (0, utilities_1.validateKeywordValue)(key, value, keywordDef.metaSchema, this.jetValidator);
173
+ }
174
+ if (!("macro" in keywordDef) &&
175
+ "code" in keywordDef &&
176
+ "validate" in keywordDef) {
177
+ continue;
178
+ }
179
+ if (keywordDef.type) {
180
+ const typeChecks = Array.isArray(keywordDef.type)
181
+ ? keywordDef.type
182
+ .map((t) => this.generateTypeCheck(varName, t))
183
+ .join(" || ")
184
+ : this.generateTypeCheck(varName, keywordDef.type);
185
+ src.push(`if ((${typeChecks})) {`);
186
+ }
187
+ if (keywordDef.code) {
188
+ this.handleCodeKeyword(src, keywordDef, value, schema, varName, pathContext, trackingState, extra);
189
+ }
190
+ else if (keywordDef.compile) {
191
+ this.handleCompileKeyword(src, keywordDef, value, schema, varName, pathContext, extra);
192
+ }
193
+ else if (keywordDef.validate) {
194
+ this.handleValidateKeyword(src, keywordDef, value, schema, varName, pathContext, accessPattern, extra);
195
+ }
196
+ if (keywordDef.type) {
197
+ src.push("}");
198
+ }
199
+ }
200
+ }
201
+ handleCodeKeyword(src, keywordDef, keywordValue, schema, varName, pathContext, trackingState, extra) {
202
+ const codeContext = {
203
+ dataVar: varName,
204
+ dataPath: pathContext.data,
205
+ schemaPath: pathContext.schema,
206
+ accessPattern: varName,
207
+ allErrors: this.options.allErrors || false,
208
+ functionName: this.mainFunctionName,
209
+ extra,
210
+ buildError: (error) => {
211
+ const { keyword, message, expected, value, ...extras } = error;
212
+ const spreadCode = Object.keys(extras).length > 0
213
+ ? `...${JSON.stringify(extras)}`
214
+ : undefined;
215
+ let err = this.buildErrorReturn(pathContext, {
216
+ keyword: keyword || keywordDef.keyword,
217
+ message,
218
+ expected,
219
+ value: value || varName,
220
+ }, spreadCode);
221
+ err += extra.after;
222
+ return err;
223
+ },
224
+ addEvaluatedProperty: (prop) => {
225
+ const lines = [];
226
+ addEvaluatedProperty(lines, prop, trackingState);
227
+ return lines.join("\n");
228
+ },
229
+ addEvaluatedItem: (item) => {
230
+ const lines = [];
231
+ addEvaluatedItems(lines, item, trackingState);
232
+ return lines.join("\n");
233
+ },
234
+ };
235
+ const generatedCode = keywordDef.code(keywordValue, schema, codeContext);
236
+ if (typeof generatedCode !== "string") {
237
+ throw new Error(`code keyword '${keywordDef.keyword}' must return a string`);
238
+ }
239
+ if (extra.before != "")
240
+ src.push(`if(${extra.before} true){`);
241
+ src.push(generatedCode);
242
+ if (extra.before != "")
243
+ src.push(`}`);
244
+ }
245
+ handleCompileKeyword(src, keywordDef, keywordValue, schema, varName, pathContext, extra) {
246
+ const keywordId = keywordDef.keyword + counter++;
247
+ const validateFn = keywordDef.compile(keywordValue, schema, {
248
+ schemaPath: pathContext.schema,
249
+ rootSchema: this.schema,
250
+ opts: this.jetValidator.options,
251
+ });
252
+ if (this.standAlone) {
253
+ src.push(`const ${keywordId} = (...args) => {return ${validateFn.toString()}};`);
254
+ }
255
+ else {
256
+ this.compiledKeywords.set(keywordId, validateFn);
257
+ }
258
+ this.hasCompileKeyword = true;
259
+ const call = this.standAlone
260
+ ? `${keywordId}(${JSON.stringify(keywordValue)}, ${JSON.stringify((0, utilities_1.getSchemaAtPath)(this.schema, pathContext.schema))},{schemaPath: '${pathContext.schema}',rootSchema: mainRootSchema,opts: compilerOptions,})`
261
+ : `customKeywords.get('${keywordId}')`;
262
+ if (extra.before != "")
263
+ src.push(`if(${extra.before} true){`);
264
+ src.push(`const ${keywordId}Result = ${keywordDef.async ? "await " : ""}${call}(${varName}, rootData, \`${pathContext.data}\`);`, `if (${keywordId}Result !== true || (typeof ${keywordId}Result === 'object' && ${keywordId}Result !== null)) {${this.buildErrorReturn(pathContext, {
265
+ keyword: keywordDef.keyword,
266
+ value: varName,
267
+ message: `"Failed validation for keyword '${keywordDef.keyword}'"`,
268
+ }, `...${keywordId}Result`)}${extra.after}}`);
269
+ if (extra.before != "")
270
+ src.push(`}`);
271
+ }
272
+ handleValidateKeyword(src, keywordDef, keywordValue, schema, varName, pathContext, accessPattern, extra) {
273
+ const keywordId = keywordDef.keyword + counter++;
274
+ const patharr = pathContext.data.split("/");
275
+ if (extra.before != "")
276
+ src.push(`if(${extra.before} true){`);
277
+ src.push(`const ${keywordId}Result = ${keywordDef.async ? "await " : ""}${this.standAlone
278
+ ? keywordDef.keyword
279
+ : `customKeywords.get('${keywordDef.keyword}')`}(${JSON.stringify(keywordValue)},${varName},${JSON.stringify((0, utilities_1.getSchemaAtPath)(this.schema, pathContext.schema))},{dataPath: \`${pathContext.data}\`,rootData: rootData,schemaPath: '${pathContext.schema}',parentData: ${accessPattern.split("[")[0]},parentDataProperty: \`${patharr[patharr.length - 1]}\`});`, `if (${keywordId}Result !== true || (typeof ${keywordId}Result === 'object' && ${keywordId}Result !== null)) {${this.buildErrorReturn(pathContext, {
280
+ keyword: keywordDef.keyword,
281
+ value: varName,
282
+ message: `"Failed validation for keyword '${keywordDef.keyword}'"`,
283
+ }, `...${keywordId}Result`)}${extra.after}}`);
284
+ if (extra.before != "")
285
+ src.push(`}`);
286
+ this.validateKeywords.add(keywordDef.keyword);
287
+ }
288
+ compileSchema(rootSchema, pathContext = {
289
+ schema: "#",
290
+ $data: "",
291
+ data: "",
292
+ }, trackingState = {}, accessPattern = "data", extra = { before: "", after: "" }, inlined = false, first = false) {
293
+ const src = [];
294
+ if (rootSchema === true)
295
+ return "";
296
+ if (this.options.allErrors && !this.errorVariableDeclared) {
297
+ src.push("let allErrors = [];");
298
+ this.errorVariableDeclared = true;
299
+ }
300
+ if (rootSchema === false) {
301
+ src.push(this.buildErrorReturn(pathContext, {
302
+ keyword: "boolean",
303
+ message: '"Schema is false"',
304
+ value: accessPattern,
305
+ }), extra.after);
306
+ return src.join("");
307
+ }
308
+ const schema = rootSchema;
309
+ const varName = (schema.default === undefined || !this.options.useDefaults) &&
310
+ !this.options.removeAdditional &&
311
+ !this.options.coerceTypes
312
+ ? accessPattern
313
+ : "var" + counter++;
314
+ this.initializeDefault(src, schema, varName, accessPattern, inlined);
315
+ let shouldTrackProps;
316
+ let shouldTrackItems;
317
+ shouldTrackProps =
318
+ schema?.unevaluatedProperties !== undefined ||
319
+ trackingState.parentHasUnevaluatedProperties === true;
320
+ trackingState.shouldTrackEvaluatedProperties = shouldTrackProps;
321
+ shouldTrackItems =
322
+ schema?.unevaluatedItems !== undefined ||
323
+ trackingState.parentHasUnevaluatedItems === true;
324
+ trackingState.shouldTrackEvaluatedItems = shouldTrackItems;
325
+ if (shouldTrackProps) {
326
+ this.initializePropertyTracking(src, schema, trackingState);
327
+ }
328
+ if (shouldTrackItems) {
329
+ this.initializeItemTracking(src, schema, trackingState);
330
+ }
331
+ if (!this.ranRefables && this.refables.length > 0) {
332
+ this.initializeRefables(pathContext);
333
+ }
334
+ if (schema.__inlinedRef !== undefined) {
335
+ this.inilineRefFunction(src, schema, varName, pathContext, trackingState, extra);
336
+ }
337
+ if (!schema.__inlinedRef && !first && schema.__functionName) {
338
+ this.initializeSchemaRefables(src, schema, varName, pathContext, trackingState, extra);
339
+ return src.join("");
340
+ }
341
+ if (schema.$ref || schema.$dynamicRef) {
342
+ this.handleReference(src, schema, varName, pathContext, trackingState, extra);
343
+ }
344
+ if (schema.not || schema.anyOf || schema.allOf || schema.oneOf) {
345
+ this.handleLogicalOperators(src, schema, varName, pathContext, trackingState, extra);
346
+ }
347
+ if (schema.if !== undefined) {
348
+ this.handleConditionalLogic(src, schema, varName, pathContext, trackingState, extra);
349
+ }
350
+ if (this.allKeywords.size > 0) {
351
+ this.handleCustomKeywords(src, schema, varName, pathContext, accessPattern, extra, trackingState);
352
+ }
353
+ this.handleTypeValidation(src, schema, varName, pathContext, trackingState, extra);
354
+ return src.join("");
355
+ }
356
+ initializeDefault(src, schema, varName, accessPattern, inlined) {
357
+ if (schema.default !== undefined && this.options.useDefaults) {
358
+ src.push(`let ${varName} = ${accessPattern};`, `if (${varName} === undefined || ${varName} === null) {`, `${varName} = ${JSON.stringify(schema.default)};`, "}");
359
+ }
360
+ else if (this.options.removeAdditional || this.options.coerceTypes) {
361
+ src.push(`let ${varName} = ${accessPattern};`);
362
+ }
363
+ if (this.options.coerceTypes) {
364
+ if (schema.type === "number" || schema.type === "integer") {
365
+ coerceToNumber(src, schema, varName);
366
+ }
367
+ else if (schema.type === "string") {
368
+ coerceToString(src, varName);
369
+ }
370
+ else if (schema.type === "boolean") {
371
+ coerceToBoolean(src, varName);
372
+ }
373
+ else if (schema.type === "array" &&
374
+ this.options.coerceTypes === "array") {
375
+ coerceToArray(src, varName);
376
+ }
377
+ }
378
+ }
379
+ initializePropertyTracking(src, schema, trackingState) {
380
+ const hasOwn = schema?.unevaluatedProperties !== undefined;
381
+ trackingState.hasOwnUnevaluatedProperties = hasOwn;
382
+ const unEvaluatedPropVar = "evaluatedProperties" + counter++;
383
+ trackingState.unevaluatedPropVar = unEvaluatedPropVar;
384
+ if (hasOwn &&
385
+ trackingState.parentHasUnevaluatedProperties &&
386
+ trackingState.parentUnevaluatedPropVar) {
387
+ trackingState.unEvaluatedPropertiesSetVar =
388
+ "evaluatedPropertySets" + counter++;
389
+ src.push(`const ${unEvaluatedPropVar} = new Set();`, `const ${trackingState.unEvaluatedPropertiesSetVar} = [${trackingState.parentUnevaluatedPropVar}, ${unEvaluatedPropVar}];`);
390
+ }
391
+ else if (hasOwn) {
392
+ src.push(`const ${unEvaluatedPropVar} = new Set();`);
393
+ }
394
+ else if (trackingState.parentHasUnevaluatedProperties &&
395
+ trackingState.parentUnevaluatedPropVar) {
396
+ trackingState.unevaluatedPropVar = trackingState.parentUnevaluatedPropVar;
397
+ }
398
+ }
399
+ initializeItemTracking(src, schema, trackingState) {
400
+ const hasOwn = schema?.unevaluatedItems !== undefined;
401
+ trackingState.hasOwnUnevaluatedItems = hasOwn;
402
+ const unEvaluatedItemVar = "evaluatedItems" + counter++;
403
+ trackingState.unevaluatedItemVar = unEvaluatedItemVar;
404
+ if (hasOwn && trackingState.parentHasUnevaluatedItems) {
405
+ trackingState.unEvaluatedItemsSetVar = "evaluatedItemSets" + counter++;
406
+ src.push(`const ${unEvaluatedItemVar} = new Set();`, `const ${trackingState.unEvaluatedItemsSetVar} = [${trackingState.parentUnevaluatedItemVar}, ${unEvaluatedItemVar}];`);
407
+ }
408
+ else if (hasOwn) {
409
+ src.push(`const ${unEvaluatedItemVar} = new Set();`);
410
+ }
411
+ else if (trackingState.parentHasUnevaluatedItems &&
412
+ trackingState.parentUnevaluatedItemVar) {
413
+ trackingState.unevaluatedItemVar = trackingState.parentUnevaluatedItemVar;
414
+ }
415
+ }
416
+ inilineRefFunction(src, schema, varName, pathContext, trackingState, extra) {
417
+ this.ranRefables = true;
418
+ const def = schema.__inlinedRef;
419
+ const configs = this.createSubschemaOptions(trackingState, pathContext, "", schema);
420
+ const defValidatorFn = this.compileSchema(def, pathContext, configs.trackingState, varName, extra, true);
421
+ src.push(defValidatorFn);
422
+ }
423
+ initializeRefables(pathContext) {
424
+ this.ranRefables = true;
425
+ for (const key of this.refables) {
426
+ if (!this.compileContext.referencedFunctions.includes(key.functionName))
427
+ continue;
428
+ const includesItemsRef = this.compileContext.hasUnevaluatedItems;
429
+ const includesPropRef = this.compileContext.hasUnevaluatedProperties;
430
+ const def = key["schema"];
431
+ this.refCall = true;
432
+ const originalErrVar = this.errorVariable;
433
+ const originalFunctionName = this.mainFunctionName;
434
+ if (this.options.allErrors) {
435
+ this.errorVariable = `${key.functionName}Err`;
436
+ }
437
+ else {
438
+ this.mainFunctionName = key.functionName;
439
+ }
440
+ const parentProp = "evaluatedProperties" + counter++;
441
+ const parentItem = "evaluatedItems" + counter++;
442
+ const defValidatorFn = this.compileSchema(def, {
443
+ schema: `\${path.schema}${key.path.startsWith("#") ? key.path.slice(1) : key.path}`,
444
+ data: "${path.data}",
445
+ $data: pathContext.$data,
446
+ alt: key.path.startsWith("#") ? key : "#" + key.path,
447
+ }, {
448
+ parentHasUnevaluatedProperties: includesPropRef,
449
+ parentUnevaluatedPropVar: includesPropRef ? parentProp : undefined,
450
+ parentHasUnevaluatedItems: includesItemsRef,
451
+ parentUnevaluatedItemVar: includesItemsRef ? parentItem : undefined,
452
+ isSubschema: true,
453
+ }, "data", { before: "", after: "" }, false, true);
454
+ this.mainFunctionName = originalFunctionName;
455
+ this.errorVariable = originalErrVar;
456
+ this.refCall = false;
457
+ const funcParams = ["data"];
458
+ if (includesPropRef)
459
+ funcParams.push(parentProp);
460
+ if (includesItemsRef)
461
+ funcParams.push(parentItem);
462
+ funcParams.push("path");
463
+ const asyncPrefix = this.options.async ? "async " : "";
464
+ this.hoistedFunctions.push(`const ${key.functionName} = ${asyncPrefix}function (${funcParams.join(",")}) {`, this.options.allErrors ? `let ${key.functionName}Err = [];` : "", defValidatorFn, this.options.allErrors
465
+ ? `${key.functionName}.errors = ${key.functionName}Err; return ${key.functionName}Err.length == 0`
466
+ : " return true", "};");
467
+ }
468
+ }
469
+ initializeSchemaRefables(src, schema, varName, pathContext, trackingState, extra) {
470
+ const funcValidator = "func" + counter++;
471
+ const callArgs = this.buildRefCallArgs(varName, pathContext, trackingState, "#");
472
+ const awaitPrefix = this.options.async ? "await " : "";
473
+ if (extra.before != "")
474
+ src.push(`if(${extra.before} true){`);
475
+ src.push(`const ${funcValidator}Result = ${awaitPrefix}${schema.__functionName}${callArgs};`);
476
+ if (this.options.allErrors) {
477
+ src.push(`if (!${funcValidator}Result) {${this.errorVariable} = ${this.errorVariable}.concat(${schema.__functionName}.errors);${extra.refAfter || extra.after}}`);
478
+ }
479
+ else {
480
+ src.push(`if (!${funcValidator}Result){${this.mainFunctionName}.errors = ${schema.__functionName}.errors;${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
481
+ }
482
+ if (extra.before != "")
483
+ src.push(`}`);
484
+ }
485
+ handleReference(src, schema, varName, pathContext, trackingState, extra) {
486
+ const refType = schema.$ref ? "$ref" : "$dynamicRef";
487
+ const refValue = schema.$ref || schema.$dynamicRef;
488
+ if (refValue === "*unavailable") {
489
+ src.push(this.buildErrorReturn(pathContext, {
490
+ keyword: refType,
491
+ value: varName,
492
+ message: `"Invalid ${refType} pointer. ${refType} not found."`,
493
+ }));
494
+ src.push(extra.refAfter || "");
495
+ return;
496
+ }
497
+ const refValidator = (schema.$ref ? "refs" : "drefs") + counter++;
498
+ const [fName, rest] = refValue.split("**");
499
+ const functionName = fName.slice(1);
500
+ const awaitPrefix = this.options.async ? "await " : "";
501
+ const callArgs = this.buildRefCallArgs(varName, pathContext, trackingState, `${pathContext.schema}/${refType}${rest ? `/${rest}` : ""}`);
502
+ if (extra.before != "")
503
+ src.push(`if(${extra.before} true){`);
504
+ src.push(`const ${refValidator}Result = ${awaitPrefix}${functionName}${callArgs};`);
505
+ if (this.options.allErrors) {
506
+ src.push(`if (!${refValidator}Result) {${this.errorVariable} = ${this.errorVariable}.concat(${functionName}.errors);${extra.refAfter || extra.after}}`);
507
+ }
508
+ else {
509
+ src.push(`if (!${refValidator}Result){${this.mainFunctionName}.errors = ${functionName}.errors;${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
510
+ }
511
+ if (extra.before != "")
512
+ src.push(`}`);
513
+ }
514
+ buildRefCallArgs(varName, pathContext, trackingState, path) {
515
+ const args = [varName];
516
+ const includesItemsRef = this.compileContext.hasUnevaluatedItems;
517
+ const includesPropRef = this.compileContext.hasUnevaluatedProperties;
518
+ if (includesPropRef) {
519
+ args.push(trackingState.unevaluatedPropVar || "undefined");
520
+ }
521
+ if (includesItemsRef) {
522
+ args.push(trackingState.unevaluatedItemVar || "undefined");
523
+ }
524
+ args.push(`{schema: \`${path || pathContext.schema}\`, data: \`${pathContext.data}\`}`);
525
+ return `(${args.join(", ")})`;
526
+ }
527
+ handleLogicalOperators(src, schema, varName, pathContext, trackingState, extra) {
528
+ if (schema.not)
529
+ this.handleNotOperator(src, schema, varName, pathContext, extra);
530
+ if (schema.anyOf)
531
+ this.handleAnyOfOperator(src, schema, varName, pathContext, trackingState, extra);
532
+ if (schema.allOf)
533
+ this.handleAllOfOperator(src, schema, varName, pathContext, trackingState, extra);
534
+ if (schema.oneOf)
535
+ this.handleOneOfOperator(src, schema, varName, pathContext, trackingState, extra);
536
+ }
537
+ handleNotOperator(src, schema, varName, pathContext, extra) {
538
+ if (schema.not === undefined)
539
+ return;
540
+ const continuevalidation = `continuevalidation${counter++}`;
541
+ src.push(`let ${continuevalidation} = true;`);
542
+ const originalNotLogic = this.notLogic;
543
+ this.notLogic = true;
544
+ const validatorFn = this.compileSchema(schema.not, undefined, {
545
+ parentHasUnevaluatedItems: false,
546
+ parentHasUnevaluatedProperties: false,
547
+ isSubschema: true,
548
+ }, varName, {
549
+ before: `${continuevalidation} && `,
550
+ after: `${continuevalidation} = false;`,
551
+ });
552
+ this.notLogic = originalNotLogic;
553
+ src.push(validatorFn);
554
+ src.push(`if (${continuevalidation}) {${this.buildErrorReturn(pathContext, {
555
+ keyword: "not",
556
+ value: varName,
557
+ message: '"Data must not validate against the provided schema."',
558
+ expected: '"opposite data"',
559
+ })}${extra.after}};`);
560
+ }
561
+ handleAnyOfOperator(src, schema, varName, pathContext, trackingState, extra) {
562
+ if (!schema.anyOf)
563
+ return;
564
+ let firstLength = "";
565
+ const anyOfValid = "anyOfValid" + counter++;
566
+ src.push(`let ${anyOfValid} = false;`);
567
+ const anyOfError = "anyOfErr" + counter++;
568
+ if (!this.options.allErrors && !this.notLogic)
569
+ src.push(`let ${anyOfError} = [];`);
570
+ schema.anyOf.forEach((subSchema, index) => {
571
+ const branch = `branch${counter++}Valid`;
572
+ if (!this.options.allErrors)
573
+ src.push(`let ${branch} = true;`);
574
+ let validatorFn;
575
+ const noreturn = this.noreturn;
576
+ this.noreturn = true;
577
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `anyOf/${index}`, schema);
578
+ configs.pathContext.alt = `${pathContext.schema}/anyOf/${index}`;
579
+ configs.pathContext.alt2 = `${pathContext.schema}/anyOf`;
580
+ if (this.options.allErrors) {
581
+ validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, extra, true);
582
+ }
583
+ else {
584
+ validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, {
585
+ before: `${branch} && `,
586
+ after: `${branch} = false;${this.notLogic ? "" : `${anyOfError}.push(${this.mainFunctionName}.errors[0]);`}`,
587
+ refAfter: `${branch} = false;${this.notLogic ? "" : `${anyOfError} = ${anyOfError}.concat(${this.mainFunctionName}.errors);`}`,
588
+ }, true);
589
+ }
590
+ this.noreturn = noreturn;
591
+ let errorCountVar;
592
+ if (this.options.allErrors) {
593
+ errorCountVar = "anyErrCnt" + counter++;
594
+ src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
595
+ if (index === 0)
596
+ firstLength = errorCountVar;
597
+ }
598
+ if (index > 0 &&
599
+ !trackingState.shouldTrackEvaluatedProperties &&
600
+ !trackingState.shouldTrackEvaluatedItems) {
601
+ src.push(`if(${anyOfValid} === false){`);
602
+ }
603
+ const propSet = trackingState.unevaluatedPropVar;
604
+ const itemSet = trackingState.unevaluatedItemVar;
605
+ const pVar = "anyOfpSize" + counter++;
606
+ const iVar = "anyOfiSize" + counter++;
607
+ if (propSet)
608
+ src.push(`const ${pVar} = ${propSet}?.size;`);
609
+ if (itemSet)
610
+ src.push(`const ${iVar} = ${itemSet}?.size;`);
611
+ src.push(validatorFn);
612
+ src.push(this.options.allErrors
613
+ ? `if (${this.errorVariable}.length == ${errorCountVar}) { ${anyOfValid} = true; }`
614
+ : `if (${branch}) { ${anyOfValid} = true; }`);
615
+ if (propSet) {
616
+ src.push(`if (${this.options.allErrors
617
+ ? `${this.errorVariable}.length > ${errorCountVar}`
618
+ : `!${branch}`}) if(${propSet})Array.from(${propSet}).slice(${pVar}).forEach(prop => ${propSet}.delete(prop));`);
619
+ }
620
+ if (itemSet) {
621
+ src.push(`if (${this.options.allErrors
622
+ ? `${this.errorVariable}.length > ${errorCountVar}`
623
+ : `!${branch}`}) if(${itemSet})Array.from(${itemSet}).slice(${iVar}).forEach(prop => ${itemSet}.delete(prop));`);
624
+ }
625
+ if (index > 0 &&
626
+ !trackingState.shouldTrackEvaluatedProperties &&
627
+ !trackingState.shouldTrackEvaluatedItems) {
628
+ src.push("};");
629
+ }
630
+ });
631
+ if (this.options.allErrors) {
632
+ src.push(`if (${anyOfValid}) {${this.errorVariable}.length = ${firstLength};}${extra.after != "" ? `else{${extra.after}}` : ""}`);
633
+ }
634
+ else {
635
+ src.push(`if (${anyOfValid}){${this.mainFunctionName}.errors = undefined}else {${this.notLogic ? "" : `${this.mainFunctionName}.errors = ${anyOfError};`}${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
636
+ }
637
+ }
638
+ handleOneOfOperator(src, schema, varName, pathContext, trackingState, extra) {
639
+ if (!schema.oneOf)
640
+ return;
641
+ let firstLength = "";
642
+ const oneOfErrors = `oneOfErrors${counter++}`;
643
+ const validSchemaCount = "validSchemaCount" + counter++;
644
+ src.push(`let ${validSchemaCount} = 0;`);
645
+ if (!this.options.allErrors)
646
+ src.push(`let ${oneOfErrors} = [];`);
647
+ schema.oneOf.forEach((subSchema, index) => {
648
+ const branch = `branch${counter++}Valid`;
649
+ if (!this.options.allErrors && !this.notLogic)
650
+ src.push(`let ${branch} = true;`);
651
+ let validatorFn;
652
+ const noreturn = this.noreturn;
653
+ this.noreturn = true;
654
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `oneOf/${index}`, schema);
655
+ configs.pathContext.alt = `${pathContext.schema}/oneOf/${index}`;
656
+ configs.pathContext.alt2 = `${pathContext.schema}/oneOf`;
657
+ if (this.options.allErrors) {
658
+ validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, extra, true);
659
+ }
660
+ else {
661
+ validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, {
662
+ before: `${branch} && `,
663
+ after: `${branch} = false;${this.notLogic ? "" : `${oneOfErrors}.push(${this.mainFunctionName}.errors[0]);`}`,
664
+ refAfter: `${branch} = false;${this.notLogic ? "" : `${oneOfErrors} = ${oneOfErrors}.concat(${this.mainFunctionName}.errors);`}`,
665
+ }, true);
666
+ }
667
+ this.noreturn = noreturn;
668
+ let errorCountVar;
669
+ if (this.options.allErrors) {
670
+ errorCountVar = "oneErrCnt" + counter;
671
+ src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
672
+ if (index === 0)
673
+ firstLength = errorCountVar;
674
+ }
675
+ if (index > 0 &&
676
+ !trackingState.shouldTrackEvaluatedProperties &&
677
+ !trackingState.shouldTrackEvaluatedItems) {
678
+ src.push(`if(${validSchemaCount} < 2){`);
679
+ }
680
+ const propSet = trackingState.unevaluatedPropVar;
681
+ const itemSet = trackingState.unevaluatedItemVar;
682
+ const pVar = "oneOfpSize" + counter++;
683
+ const iVar = "oneOfiSize" + counter++;
684
+ if (propSet)
685
+ src.push(`const ${pVar} = ${propSet}?.size;`);
686
+ if (itemSet)
687
+ src.push(`const ${iVar} = ${itemSet}?.size;`);
688
+ src.push(validatorFn);
689
+ src.push(this.options.allErrors
690
+ ? `if (${this.errorVariable}.length == ${errorCountVar}) { ${validSchemaCount}++; }`
691
+ : `if (${branch}) { ${validSchemaCount}++; }`);
692
+ if (propSet) {
693
+ src.push(`if (${this.options.allErrors
694
+ ? `${this.errorVariable}.length > ${errorCountVar}`
695
+ : `!${branch}`}) if(${propSet})Array.from(${propSet}).slice(${pVar}).forEach(prop => ${propSet}.delete(prop));`);
696
+ }
697
+ if (itemSet) {
698
+ src.push(`if (${this.options.allErrors
699
+ ? `${this.errorVariable}.length > ${errorCountVar}`
700
+ : `!${branch}`}) if(${itemSet})Array.from(${itemSet}).slice(${iVar}).forEach(prop => ${itemSet}.delete(prop));`);
701
+ }
702
+ if (index > 0 &&
703
+ !trackingState.shouldTrackEvaluatedProperties &&
704
+ !trackingState.shouldTrackEvaluatedItems) {
705
+ src.push(`}`);
706
+ }
707
+ });
708
+ if (this.options.allErrors) {
709
+ src.push(`if (${validSchemaCount} == 1) {${this.errorVariable}.length = ${firstLength};} else{${this.buildErrorReturn(pathContext, {
710
+ keyword: "oneOf",
711
+ value: varName,
712
+ message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
713
+ expected: '"exactly one schema"',
714
+ })}${extra.after}}`);
715
+ }
716
+ else {
717
+ const noreturn = this.noreturn;
718
+ this.noreturn = true;
719
+ src.push(`if (${validSchemaCount} == 1){${this.mainFunctionName}.errors = undefined}else {${this.buildErrorReturn(pathContext, {
720
+ keyword: "oneOf",
721
+ value: varName,
722
+ message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
723
+ expected: '"exactly one schema"',
724
+ })}${this.notLogic ? "" : `${oneOfErrors}.push(${this.mainFunctionName}.errors[0]);${this.mainFunctionName}.errors = ${oneOfErrors};`}${extra.refAfter ?? extra.after}${noreturn ? "" : "return false;"}}`);
725
+ this.noreturn = noreturn;
726
+ }
727
+ }
728
+ handleAllOfOperator(src, schema, varName, pathContext, trackingState, extra) {
729
+ if (!schema.allOf)
730
+ return;
731
+ schema.allOf.forEach((subSchema, index) => {
732
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `allOf/${index}`, schema);
733
+ configs.pathContext.alt = `${pathContext.schema}/allOf/${index}`;
734
+ configs.pathContext.alt2 = `${pathContext.schema}/allOf`;
735
+ const validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, extra, true);
736
+ src.push(validatorFn);
737
+ });
738
+ }
739
+ handleConditionalLogic(src, schema, varName, pathContext, trackingState, extra) {
740
+ if (schema.if === undefined)
741
+ return;
742
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `if`, schema);
743
+ const ifValid = `ifValid${counter++}`;
744
+ src.push(`let ${ifValid} = true;`);
745
+ const elseIfVariableArray = [];
746
+ if (schema.elseIf) {
747
+ for (const subSchema of schema.elseIf) {
748
+ if (subSchema.if) {
749
+ const ifValid = `ifValid${counter++}`;
750
+ src.push(`let ${ifValid} = true;`);
751
+ elseIfVariableArray.push(ifValid);
752
+ }
753
+ }
754
+ }
755
+ const originalNotLogic = this.notLogic;
756
+ this.notLogic = true;
757
+ const subValidator = this.compileSchema(schema.if, configs.pathContext, configs.trackingState, varName, {
758
+ before: `${ifValid} && `,
759
+ after: `${ifValid} = false;`,
760
+ }, true);
761
+ this.notLogic = originalNotLogic;
762
+ const propSet = trackingState.unevaluatedPropVar;
763
+ const itemSet = trackingState.unevaluatedItemVar;
764
+ const pVar = "ifpSize" + counter++;
765
+ const iVar = "ifiSize" + counter++;
766
+ if (propSet)
767
+ src.push(`const ${pVar} = ${propSet}?.size;`);
768
+ if (itemSet)
769
+ src.push(`const ${iVar} = ${itemSet}?.size;`);
770
+ src.push(subValidator);
771
+ if (propSet) {
772
+ src.push(`if (!${ifValid}) if(${propSet})Array.from(${propSet}).slice(${pVar}).forEach(prop => ${propSet}.delete(prop));`);
773
+ }
774
+ if (itemSet) {
775
+ src.push(`if (!${ifValid}) if(${itemSet}) Array.from(${itemSet}).slice(${iVar}).forEach(prop => ${itemSet}.delete(prop));`);
776
+ }
777
+ this.handleElseIfConditions(src, schema, varName, pathContext, trackingState, ifValid, elseIfVariableArray);
778
+ src.push(`if (${ifValid}) {`);
779
+ if (schema.then !== undefined) {
780
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `then`, schema);
781
+ configs.pathContext.alt = `${pathContext.schema}/then`;
782
+ configs.pathContext.alt2 = undefined;
783
+ const thenValidatorFn = this.compileSchema(schema.then, configs.pathContext, configs.trackingState, varName, extra);
784
+ src.push(thenValidatorFn);
785
+ }
786
+ src.push("}");
787
+ this.handleElseIfThen(src, schema, varName, pathContext, trackingState, elseIfVariableArray, extra);
788
+ if (schema.else !== undefined) {
789
+ src.push("else {");
790
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `else`, schema);
791
+ configs.pathContext.alt = `${pathContext.schema}/else`;
792
+ configs.pathContext.alt2 = undefined;
793
+ const elseValidatorFn = this.compileSchema(schema.else, configs.pathContext, configs.trackingState, varName, extra);
794
+ src.push(elseValidatorFn, "}");
795
+ }
796
+ }
797
+ handleElseIfConditions(src, schema, varName, pathContext, trackingState, previousIfValid, elseIfVariableArray) {
798
+ if (!schema.elseIf)
799
+ return;
800
+ const functionNames = {};
801
+ schema.elseIf.forEach((cond, index) => {
802
+ if (cond.if) {
803
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `elseIf/${index}/if`, schema);
804
+ const ifValid = elseIfVariableArray[index];
805
+ const originalNotLogic = this.notLogic;
806
+ this.notLogic = true;
807
+ const subValidator = this.compileSchema(cond.if, configs.pathContext, configs.trackingState, varName, {
808
+ before: `${ifValid} && `,
809
+ after: `${ifValid} = false;`,
810
+ }, true);
811
+ this.notLogic = originalNotLogic;
812
+ const propSet = trackingState.unevaluatedPropVar;
813
+ const itemSet = trackingState.unevaluatedItemVar;
814
+ const pVar = "ifpSize" + counter++;
815
+ const iVar = "ifiSize" + counter++;
816
+ src.push(`if(!${previousIfValid}){`);
817
+ if (propSet)
818
+ src.push(`const ${pVar} = ${propSet}?.size;`);
819
+ if (itemSet)
820
+ src.push(`const ${iVar} = ${itemSet}?.size;`);
821
+ src.push(subValidator);
822
+ if (propSet) {
823
+ src.push(`if (!${ifValid}) if(${propSet})Array.from(${propSet}).slice(${pVar}).forEach(prop => ${propSet}.delete(prop));`);
824
+ }
825
+ if (itemSet) {
826
+ src.push(`if (!${ifValid}) if(${itemSet}) Array.from(${itemSet}).slice(${iVar}).forEach(prop => ${itemSet}.delete(prop));`);
827
+ }
828
+ src.push("}");
829
+ previousIfValid = ifValid;
830
+ }
831
+ });
832
+ return functionNames;
833
+ }
834
+ handleElseIfThen(src, schema, varName, pathContext, trackingState, elseIfVariableArray, extra) {
835
+ if (!schema.elseIf)
836
+ return;
837
+ schema.elseIf.forEach((cond, index) => {
838
+ if (!cond.if)
839
+ return;
840
+ src.push(`else if (${elseIfVariableArray[index]}) {`);
841
+ if (cond.then) {
842
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `elseIf/${index}/then`, schema);
843
+ configs.pathContext.alt = `${pathContext.schema}/elseIf/${index}/then`;
844
+ configs.pathContext.alt2 = undefined;
845
+ const thenValidatorFn = this.compileSchema(cond.then, configs.pathContext, configs.trackingState, varName, extra);
846
+ src.push(thenValidatorFn);
847
+ }
848
+ src.push("}");
849
+ });
850
+ }
851
+ handleTypeValidation(src, schema, varName, pathContext, trackingState, extra) {
852
+ if (schema.type === "null") {
853
+ src.push(`if (${extra.before}${varName} !== null) {${this.buildErrorReturn(pathContext, {
854
+ keyword: "type",
855
+ value: varName,
856
+ message: '"Invalid type"',
857
+ expected: '"null"',
858
+ })}${extra.after}}`);
859
+ }
860
+ if (Array.isArray(schema.type)) {
861
+ const typeChecks = schema.type
862
+ .map((t) => this.generateTypeCheck(varName, t))
863
+ .join(" || ");
864
+ src.push(`if (${extra.before}!(${typeChecks})) {${this.buildErrorReturn(pathContext, {
865
+ keyword: "type",
866
+ value: varName,
867
+ message: `"Invalid type. Must be ${schema.type.join(" or ")}"`,
868
+ expected: JSON.stringify(schema.type.join(" or ")),
869
+ })}${extra.after}}`);
870
+ }
871
+ const objectConditions = schema.required !== undefined ||
872
+ schema.properties !== undefined ||
873
+ schema.minProperties !== undefined ||
874
+ schema.maxProperties !== undefined ||
875
+ schema.dependentSchemas !== undefined ||
876
+ schema.dependentRequired !== undefined ||
877
+ schema.unevaluatedProperties !== undefined ||
878
+ schema.additionalProperties !== undefined ||
879
+ schema.patternProperties !== undefined ||
880
+ schema.propertyNames !== undefined ||
881
+ schema.dependencies !== undefined;
882
+ const arrayConditions = schema.prefixItems !== undefined ||
883
+ schema.items !== undefined ||
884
+ schema.additionalItems !== undefined ||
885
+ schema.contains !== undefined ||
886
+ schema.unevaluatedItems !== undefined ||
887
+ schema.minItems !== undefined ||
888
+ schema.maxItems !== undefined ||
889
+ schema.uniqueItems === true;
890
+ this.handlePrimitive(src, schema, varName, pathContext, extra);
891
+ if ((schema.type && schema.type === "object") ||
892
+ (Array.isArray(schema.type) && schema.type.includes("object")) ||
893
+ objectConditions) {
894
+ this.handleObject(src, schema, varName, pathContext, trackingState, objectConditions, extra);
895
+ }
896
+ if ((schema.type && schema.type === "array") ||
897
+ (Array.isArray(schema.type) && schema.type.includes("array")) ||
898
+ arrayConditions) {
899
+ this.handleArray(src, schema, varName, pathContext, trackingState, arrayConditions, extra);
900
+ }
901
+ }
902
+ generateTypeCheck(varName, type) {
903
+ switch (type) {
904
+ case "integer":
905
+ return `(typeof ${varName} === "number" && Number.isInteger(${varName}))`;
906
+ case "null":
907
+ return `${varName} === null`;
908
+ case "array":
909
+ return `(Array.isArray(${varName}) && ${varName} !== null)`;
910
+ case "object":
911
+ return `(typeof ${varName} === 'object' && !Array.isArray(${varName}) && ${varName} !== null)`;
912
+ case "number":
913
+ return `(typeof ${varName} === "number" && Number.isFinite(${varName}))`;
914
+ default:
915
+ return `typeof ${varName} === "${type}"`;
916
+ }
917
+ }
918
+ handlePrimitive(src, schema, varName, pathContext, extra) {
919
+ if (typeof schema.type === "string" && PRIMITIVE_TYPES.has(schema.type)) {
920
+ const checkType = schema.type;
921
+ let check;
922
+ let error;
923
+ if (checkType === "number") {
924
+ const strict = this.options.strict || this.options.strictNumbers;
925
+ check = `typeof ${varName} !== "${checkType}" ${strict ? `|| !Number.isFinite(${varName})` : ""}`;
926
+ error = `"Invalid type, must be number${strict
927
+ ? ", value must be finite. NaN, Infinity or -Infinity is not allowed"
928
+ : ""}"`;
929
+ }
930
+ else if (checkType === "integer") {
931
+ check = `!Number.isInteger(${varName})`;
932
+ error = '"Must be an integer or integer exceeds safe range"';
933
+ }
934
+ else {
935
+ error = `"Invalid type, must be ${checkType}"`;
936
+ check = `typeof ${varName} !== '${checkType}'`;
937
+ }
938
+ src.push(`if (${extra.before}${check}) {${this.buildErrorReturn(pathContext, {
939
+ keyword: "type",
940
+ value: varName,
941
+ message: error,
942
+ expected: JSON.stringify(schema.type),
943
+ })}${extra.after}}`);
944
+ }
945
+ const numberCondition = schema.minimum !== undefined ||
946
+ schema.maximum !== undefined ||
947
+ schema.exclusiveMaximum !== undefined ||
948
+ schema.exclusiveMinimum !== undefined ||
949
+ schema.multipleOf !== undefined;
950
+ const stringCondition = schema.minLength !== undefined ||
951
+ schema.maxLength !== undefined ||
952
+ schema.pattern !== undefined ||
953
+ (schema.format !== undefined && this.options.validateFormats);
954
+ if (schema.type === "string" && stringCondition)
955
+ src.push("else{");
956
+ if (schema.type !== "string" && stringCondition) {
957
+ src.push(`if(${extra.before}${this.generateTypeCheck(varName, "string")}){`);
958
+ }
959
+ if (!this.needslen_of &&
960
+ (schema.minLength !== undefined || schema.maxLength !== undefined))
961
+ this.needslen_of = true;
962
+ if (schema.minLength !== undefined) {
963
+ this.handleMinLength(src, schema, varName, pathContext, extra);
964
+ }
965
+ if (schema.maxLength !== undefined) {
966
+ this.handleMaxLength(src, schema, varName, pathContext, extra);
967
+ }
968
+ if (schema.pattern !== undefined) {
969
+ this.handlePattern(src, schema, varName, pathContext, extra);
970
+ }
971
+ if (schema.format !== undefined && this.options.validateFormats === true) {
972
+ this.handleFormat(src, schema, varName, pathContext, extra);
973
+ }
974
+ if (schema.type !== "string" && stringCondition) {
975
+ src.push(`}`);
976
+ }
977
+ if (schema.type === "string" && stringCondition)
978
+ src.push("}");
979
+ if (schema.type === "number" && numberCondition)
980
+ src.push("else{");
981
+ if (schema.type !== "number" && numberCondition) {
982
+ src.push(`if(${extra.before}${this.generateTypeCheck(varName, "number")}){`);
983
+ }
984
+ if (schema.minimum !== undefined) {
985
+ this.handleMinimum(src, schema, varName, pathContext, extra);
986
+ }
987
+ if (schema.maximum !== undefined) {
988
+ this.handleMaximum(src, schema, varName, pathContext, extra);
989
+ }
990
+ if (schema.exclusiveMinimum !== undefined) {
991
+ this.handleExclusiveMinimum(src, schema, varName, pathContext, extra);
992
+ }
993
+ if (schema.exclusiveMaximum !== undefined) {
994
+ this.handleExclusiveMaximum(src, schema, varName, pathContext, extra);
995
+ }
996
+ if (schema.multipleOf !== undefined) {
997
+ this.handleMultipleOf(src, schema, varName, pathContext, extra);
998
+ }
999
+ if (schema.type !== "number" && numberCondition) {
1000
+ src.push(`}`);
1001
+ }
1002
+ if (schema.type === "number" && numberCondition)
1003
+ src.push("}");
1004
+ if (schema.const !== undefined) {
1005
+ this.handleConst(src, schema, varName, pathContext, extra);
1006
+ }
1007
+ if (schema.enum &&
1008
+ ((Array.isArray(schema.enum) && schema.enum.length > 0) ||
1009
+ "$data" in schema.enum)) {
1010
+ this.handleEnum(src, schema, varName, pathContext, extra);
1011
+ }
1012
+ }
1013
+ handleConst(src, schema, varName, pathContext, extra) {
1014
+ const isDataRef = this.options.$data && isDataReference(schema.const);
1015
+ let comparisonTarget;
1016
+ if (isDataRef && typeof schema.const === "object") {
1017
+ const pointer = schema.const.$data;
1018
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1019
+ comparisonTarget = generateUndefinedDataRef(src, resolvedPath, extra);
1020
+ }
1021
+ else {
1022
+ comparisonTarget = JSON.stringify(schema.const);
1023
+ }
1024
+ if (isDataRef) {
1025
+ this.needsDeepEqual = true;
1026
+ src.push(`if (${extra.before}typeof ${comparisonTarget} === 'object' && ${comparisonTarget} !== null ? !deepEqual(${varName}, ${comparisonTarget}) : ${varName} !== ${comparisonTarget}) {`);
1027
+ }
1028
+ else {
1029
+ const constValue = schema.const;
1030
+ if (typeof constValue === "object" && constValue !== null) {
1031
+ this.needsDeepEqual = true;
1032
+ src.push(`if (${extra.before}!deepEqual(${varName}, ${comparisonTarget})) {`);
1033
+ }
1034
+ else {
1035
+ src.push(`if (${extra.before}${varName} !== ${comparisonTarget}) {`);
1036
+ }
1037
+ }
1038
+ src.push(this.buildErrorReturn(pathContext, {
1039
+ keyword: "const",
1040
+ value: varName,
1041
+ message: `"Value or type does not match " + ${comparisonTarget}`,
1042
+ expected: isDataRef
1043
+ ? comparisonTarget
1044
+ : typeof comparisonTarget === "boolean" ||
1045
+ typeof comparisonTarget === "number"
1046
+ ? comparisonTarget
1047
+ : JSON.stringify(comparisonTarget),
1048
+ }), extra.after, "}");
1049
+ if (isDataRef) {
1050
+ src.push("}");
1051
+ }
1052
+ }
1053
+ handleMinLength(src, schema, varName, pathContext, extra) {
1054
+ const isDataRef = this.options.$data && isDataReference(schema.minLength);
1055
+ let comparisonTarget;
1056
+ if (isDataRef && typeof schema.minLength === "object") {
1057
+ const pointer = schema.minLength.$data;
1058
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1059
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1060
+ }
1061
+ else {
1062
+ comparisonTarget = schema.minLength;
1063
+ }
1064
+ src.push(`if (${extra.before}len_of(${varName}) < ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1065
+ keyword: "minLength",
1066
+ value: varName,
1067
+ message: `"Length of value must be at least " + ${comparisonTarget} + " characters."`,
1068
+ expected: comparisonTarget,
1069
+ })}${extra.after}}`);
1070
+ if (isDataRef) {
1071
+ src.push("}");
1072
+ }
1073
+ }
1074
+ handleMaxLength(src, schema, varName, pathContext, extra) {
1075
+ const isDataRef = this.options.$data && isDataReference(schema.maxLength);
1076
+ let comparisonTarget;
1077
+ if (isDataRef && typeof schema.maxLength === "object") {
1078
+ const pointer = schema.maxLength.$data;
1079
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1080
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1081
+ }
1082
+ else {
1083
+ comparisonTarget = schema.maxLength;
1084
+ }
1085
+ src.push(`if (${extra.before}len_of(${varName}) > ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1086
+ keyword: "maxLength",
1087
+ value: varName,
1088
+ message: `"Length of value must be at most " + ${comparisonTarget} + " characters."`,
1089
+ expected: comparisonTarget,
1090
+ })}${extra.after}}`);
1091
+ if (isDataRef) {
1092
+ src.push("}");
1093
+ }
1094
+ }
1095
+ handleMinimum(src, schema, varName, pathContext, extra) {
1096
+ const isDataRef = this.options.$data && isDataReference(schema.minimum);
1097
+ let comparisonTarget;
1098
+ if (isDataRef && typeof schema.minimum === "object") {
1099
+ const pointer = schema.minimum.$data;
1100
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1101
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra);
1102
+ }
1103
+ else {
1104
+ comparisonTarget = schema.minimum;
1105
+ }
1106
+ src.push(`if (${extra.before}${varName} < ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1107
+ keyword: "minimum",
1108
+ value: varName,
1109
+ message: `"Value must be at least " + ${comparisonTarget}`,
1110
+ expected: comparisonTarget,
1111
+ })}${extra.after}}`);
1112
+ if (isDataRef) {
1113
+ src.push("}");
1114
+ }
1115
+ }
1116
+ handleMaximum(src, schema, varName, pathContext, extra) {
1117
+ const isDataRef = this.options.$data && isDataReference(schema.maximum);
1118
+ let comparisonTarget;
1119
+ if (isDataRef && typeof schema.maximum === "object") {
1120
+ const pointer = schema.maximum.$data;
1121
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1122
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra);
1123
+ }
1124
+ else {
1125
+ comparisonTarget = schema.maximum;
1126
+ }
1127
+ src.push(`if (${extra.before}${varName} > ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1128
+ keyword: "maximum",
1129
+ value: varName,
1130
+ message: `"Value must be at most " + ${comparisonTarget}`,
1131
+ expected: comparisonTarget,
1132
+ })}${extra.after}}`);
1133
+ if (isDataRef) {
1134
+ src.push("}");
1135
+ }
1136
+ }
1137
+ handleExclusiveMinimum(src, schema, varName, pathContext, extra) {
1138
+ const isDataRef = this.options.$data && isDataReference(schema.exclusiveMinimum);
1139
+ let comparisonTarget;
1140
+ if (isDataRef && typeof schema.exclusiveMinimum === "object") {
1141
+ const pointer = schema.exclusiveMinimum.$data;
1142
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1143
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra);
1144
+ }
1145
+ else {
1146
+ comparisonTarget = schema.exclusiveMinimum;
1147
+ }
1148
+ src.push(`if (${extra.before}${varName} <= ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1149
+ keyword: "exclusiveMinimum",
1150
+ value: varName,
1151
+ message: `"Value must be at least "+(${comparisonTarget} + 1)`,
1152
+ expected: comparisonTarget,
1153
+ })}${extra.after}}`);
1154
+ if (isDataRef) {
1155
+ src.push("}");
1156
+ }
1157
+ }
1158
+ handleExclusiveMaximum(src, schema, varName, pathContext, extra) {
1159
+ const isDataRef = this.options.$data && isDataReference(schema.exclusiveMaximum);
1160
+ let comparisonTarget;
1161
+ if (isDataRef && typeof schema.exclusiveMaximum === "object") {
1162
+ const pointer = schema.exclusiveMaximum.$data;
1163
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1164
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra);
1165
+ }
1166
+ else {
1167
+ comparisonTarget = schema.exclusiveMaximum;
1168
+ }
1169
+ src.push(`if (${extra.before}${varName} >= ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1170
+ keyword: "exclusiveMaximum",
1171
+ value: varName,
1172
+ message: `"Value must be at most "+(${comparisonTarget} - 1)`,
1173
+ expected: comparisonTarget,
1174
+ })}${extra.after}}`);
1175
+ if (isDataRef) {
1176
+ src.push("}");
1177
+ }
1178
+ }
1179
+ handleMultipleOf(src, schema, varName, pathContext, extra) {
1180
+ const isDataRef = this.options.$data && isDataReference(schema.multipleOf);
1181
+ let comparisonTarget;
1182
+ if (isDataRef && typeof schema.multipleOf === "object") {
1183
+ const pointer = schema.multipleOf.$data;
1184
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1185
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra);
1186
+ }
1187
+ else {
1188
+ comparisonTarget = schema.multipleOf;
1189
+ }
1190
+ src.push(`const multipleOf = ${comparisonTarget};
1191
+ const quotient = ${varName} / multipleOf;
1192
+ const rounded = Math.round(quotient);
1193
+ const tolerance = Math.abs(quotient) * Number.EPSILON;
1194
+ if (${extra.before}multipleOf === 0 || !isFinite(quotient) || Math.abs(quotient - rounded) > tolerance) {${this.buildErrorReturn(pathContext, {
1195
+ keyword: "multipleOf",
1196
+ value: varName,
1197
+ message: `"Value must be a multiple of " + ${comparisonTarget}`,
1198
+ expected: comparisonTarget,
1199
+ })}${extra.after}}`);
1200
+ if (isDataRef) {
1201
+ src.push("}");
1202
+ }
1203
+ }
1204
+ handlePattern(src, schema, varName, pathContext, extra) {
1205
+ const isDataRef = this.options.$data && isDataReference(schema.pattern);
1206
+ let comparisonTarget;
1207
+ if (isDataRef && typeof schema.pattern === "object") {
1208
+ const pointer = schema.pattern.$data;
1209
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1210
+ comparisonTarget = generateStringDataRef(src, resolvedPath, extra);
1211
+ src.push("try {");
1212
+ src.push(`if (${extra.before}!new RegExp(${comparisonTarget}, 'u').test(${varName})) {${this.buildErrorReturn(pathContext, {
1213
+ keyword: "pattern",
1214
+ value: varName,
1215
+ message: `"Value does not match the required pattern"`,
1216
+ expected: comparisonTarget,
1217
+ })}${extra.after}}`);
1218
+ }
1219
+ else {
1220
+ comparisonTarget = JSON.stringify(schema.pattern);
1221
+ let pname = this.regexCache.get(schema.pattern);
1222
+ if (!pname) {
1223
+ pname = "pattern" + counter++;
1224
+ this.regexCache.set(schema.pattern, pname);
1225
+ }
1226
+ src.push(`if (${extra.before}!${pname}.test(${varName})) {${this.buildErrorReturn(pathContext, {
1227
+ keyword: "pattern",
1228
+ value: varName,
1229
+ message: `"Value does not match the required pattern"`,
1230
+ expected: JSON.stringify(comparisonTarget),
1231
+ })}${extra.after}}`);
1232
+ }
1233
+ if (isDataRef) {
1234
+ src.push("} catch (e) {}", "}");
1235
+ }
1236
+ }
1237
+ handleEnum(src, schema, varName, pathContext, extra) {
1238
+ const isDataRef = this.options.$data && isDataReference(schema.enum);
1239
+ let enumArrayExpr;
1240
+ let enumCheckCloseExpr = "";
1241
+ if (isDataRef &&
1242
+ typeof schema.enum === "object" &&
1243
+ !Array.isArray(schema.enum)) {
1244
+ const pointer = schema.enum.$data;
1245
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1246
+ enumArrayExpr = generateArrayDataRef(src, resolvedPath, extra);
1247
+ enumCheckCloseExpr = "}";
1248
+ }
1249
+ else {
1250
+ if (!Array.isArray(schema.enum))
1251
+ return;
1252
+ enumArrayExpr = JSON.stringify(schema.enum);
1253
+ }
1254
+ if (isDataRef ||
1255
+ (Array.isArray(schema.enum) &&
1256
+ schema.enum.length >= (this.options.loopEnum ?? 200))) {
1257
+ this.needsStringify = true;
1258
+ src.push(`if (${extra.before}!${enumArrayExpr}.some(enumValue => typeof enumValue === 'object' && enumValue!== null ? canonicalStringify(${varName}) === canonicalStringify(enumValue) : enumValue === ${varName})) {`);
1259
+ }
1260
+ else {
1261
+ const conditions = schema.enum.map((enumValue) => {
1262
+ if (typeof enumValue === "object" && enumValue !== null) {
1263
+ this.needsStringify = true;
1264
+ return `(typeof ${varName} === 'object' && ${varName} !== null && canonicalStringify(${varName}) === canonicalStringify(${JSON.stringify(enumValue)}))`;
1265
+ }
1266
+ else {
1267
+ return `${varName} === ${JSON.stringify(enumValue)}`;
1268
+ }
1269
+ });
1270
+ src.push(`if (${extra.before}!(${conditions.join(" || ")})) {`);
1271
+ }
1272
+ const expectedValue = isDataRef
1273
+ ? `${enumArrayExpr}`
1274
+ : JSON.stringify(schema.enum);
1275
+ src.push(this.buildErrorReturn(pathContext, {
1276
+ keyword: "enum",
1277
+ value: varName,
1278
+ message: '"Value must be one of the items listed in enum"',
1279
+ expected: expectedValue,
1280
+ }), extra.after, "}");
1281
+ if (isDataRef) {
1282
+ src.push(enumCheckCloseExpr);
1283
+ }
1284
+ }
1285
+ handleFormat(src, schema, varName, pathContext, extra) {
1286
+ const isDataRef = this.options.$data && isDataReference(schema.format);
1287
+ if (isDataRef && typeof schema.format === "object") {
1288
+ const pointer = schema.format.$data;
1289
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1290
+ const formatKeyVar = generateStringDataRef(src, resolvedPath, extra);
1291
+ if (this.standAlone) {
1292
+ src.push(`const formatValidator = formatValidators[${formatKeyVar}];`);
1293
+ }
1294
+ else {
1295
+ src.push(`const formatValidator = formatValidators[${formatKeyVar}].validate ?? formatValidators[${formatKeyVar}];`);
1296
+ }
1297
+ src.push(`if (${extra.before}formatValidator && typeof ${varName} === 'string') {`, ` const isValid = typeof formatValidator === 'function' ? ${this.options.async ? "async" : ""}formatValidator(${varName}) : formatValidator.test(${varName});`, ` if (!isValid) {${this.buildErrorReturn(pathContext, {
1298
+ keyword: "format",
1299
+ value: varName,
1300
+ message: `"Failed to validate value against format "+${formatKeyVar}`,
1301
+ expected: `${formatKeyVar}`,
1302
+ })}}${extra.after}}}`);
1303
+ }
1304
+ else {
1305
+ const data = this.jetValidator.getFormat(schema.format);
1306
+ if (!data) {
1307
+ throw new Error(`Format '${schema.format}' not found`);
1308
+ }
1309
+ const format = typeof data === "object" && "validate" in data ? data.validate : data;
1310
+ const formatType = typeof data === "object" &&
1311
+ !Array.isArray(data) &&
1312
+ !(data instanceof RegExp) &&
1313
+ data.type
1314
+ ? data.type
1315
+ : "string";
1316
+ const formatKey = schema.format;
1317
+ let testCode;
1318
+ let formatRef;
1319
+ if (typeof format === "function") {
1320
+ formatRef = this.standAlone
1321
+ ? `format_${formatKey.replace(/[^a-zA-Z0-9]/g, "_")}`
1322
+ : `formatValidators['${formatKey}']`;
1323
+ testCode =
1324
+ this.options.async && typeof data === "object" && "async" in data
1325
+ ? `!(await ${formatRef}(${varName}))`
1326
+ : `!${formatRef}(${varName})`;
1327
+ }
1328
+ else if (format instanceof RegExp) {
1329
+ formatRef = this.standAlone
1330
+ ? `format_${formatKey.replace(/[^a-zA-Z0-9]/g, "_")}`
1331
+ : `formatValidators['${formatKey}']`;
1332
+ testCode = `!${formatRef}.test(${varName})`;
1333
+ }
1334
+ const typeCheck = Array.isArray(formatType)
1335
+ ? `(${formatType
1336
+ .map((t) => this.generateTypeCheck(varName, t))
1337
+ .join(" || ")})`
1338
+ : `typeof ${varName} === '${formatType}'`;
1339
+ src.push(`if (${extra.before}${typeCheck} && ${testCode}) {${this.buildErrorReturn(pathContext, {
1340
+ keyword: "format",
1341
+ value: varName,
1342
+ message: `"Failed to validate value against format ${schema.format}"`,
1343
+ expected: `"${schema.format}"`,
1344
+ })}${extra.after}}`);
1345
+ }
1346
+ }
1347
+ handleObject(src, schema, varName, pathContext, trackingState, condition, extra) {
1348
+ if (schema.type === "object") {
1349
+ src.push(`if (${extra.before}(!${varName} || typeof ${varName} != 'object' || Array.isArray(${varName}))) {${this.buildErrorReturn(pathContext, {
1350
+ keyword: "type",
1351
+ value: varName,
1352
+ message: '"Invalid type, expected object"',
1353
+ expected: '"object"',
1354
+ })}${extra.after}}`);
1355
+ }
1356
+ if (schema.type === "object" && condition)
1357
+ src.push("else{");
1358
+ if (schema.type !== "object" && condition) {
1359
+ src.push(`if (${extra.before}${varName} && typeof ${varName} == 'object' && !Array.isArray(${varName})) {`);
1360
+ }
1361
+ if (schema.required !== undefined) {
1362
+ this.handleRequiredProperties(src, schema, varName, pathContext, trackingState, extra);
1363
+ }
1364
+ if (schema.properties !== undefined && schema.properties !== null) {
1365
+ const propertyKeys = Object.keys(schema.properties);
1366
+ if (propertyKeys.length > 0) {
1367
+ this.handleObjectProperties(src, schema, varName, pathContext, trackingState, propertyKeys, extra);
1368
+ }
1369
+ }
1370
+ if (schema.minProperties !== undefined ||
1371
+ schema.maxProperties !== undefined) {
1372
+ this.handlePropertyConstraints(src, schema, varName, pathContext, extra);
1373
+ }
1374
+ if (schema.dependentSchemas !== undefined ||
1375
+ schema.dependentRequired !== undefined ||
1376
+ schema.dependencies !== undefined) {
1377
+ this.handleDependentSchemas(src, schema, varName, pathContext, trackingState, extra);
1378
+ }
1379
+ if (schema.propertyNames !== undefined) {
1380
+ this.handlePropertyNames(src, schema, varName, pathContext, extra);
1381
+ }
1382
+ if (schema.additionalProperties !== undefined) {
1383
+ this.handleAdditionalProperties(src, schema, varName, pathContext, trackingState, extra);
1384
+ }
1385
+ if (schema.patternProperties !== undefined) {
1386
+ this.handlePatternProperties(src, schema, varName, pathContext, trackingState, extra);
1387
+ }
1388
+ if (schema.unevaluatedProperties !== undefined) {
1389
+ this.handleUnevaluatedProperties(src, schema, varName, pathContext, trackingState, extra);
1390
+ }
1391
+ if (schema.type !== "object" && condition) {
1392
+ src.push(`}`);
1393
+ }
1394
+ if (schema.type === "object" && condition)
1395
+ src.push("}");
1396
+ }
1397
+ handleRequiredProperties(src, schema, varName, pathContext, trackingState, extra) {
1398
+ const isDataRef = this.options.$data && isDataReference(schema.required);
1399
+ if (isDataRef &&
1400
+ typeof schema.required === "object" &&
1401
+ !Array.isArray(schema.required)) {
1402
+ const pointer = schema.required.$data;
1403
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1404
+ const requiredArrayExpr = generateArrayDataRef(src, resolvedPath, extra);
1405
+ src.push(`if (${extra.before}${requiredArrayExpr}) {`);
1406
+ src.push(`for (let i = 0; i < ${requiredArrayExpr}.length; i++) {`);
1407
+ src.push(`const prop = ${requiredArrayExpr}[i];`);
1408
+ addEvaluatedProperty(src, "prop", trackingState);
1409
+ src.push(`if (${extra.before}${varName}[prop] === undefined) {${this.buildErrorReturn(pathContext, {
1410
+ keyword: "required",
1411
+ value: varName,
1412
+ message: `"Missing required field: " + prop + " in data."`,
1413
+ expected: "prop",
1414
+ schemaPath: `${pathContext.schema}`,
1415
+ })}${extra.after}}`);
1416
+ src.push(`}`);
1417
+ src.push(`}`);
1418
+ src.push("}");
1419
+ }
1420
+ else {
1421
+ const required = Array.isArray(schema.required) ? schema.required : [];
1422
+ if (required.length === 0)
1423
+ return;
1424
+ if (Array.isArray(schema.required)) {
1425
+ if (this.options.allErrors ||
1426
+ schema.required.length > this.options.loopRequired) {
1427
+ const arr = JSON.stringify(schema.required);
1428
+ const arrVar = `arr${src.length}${counter++}`;
1429
+ const iVar = `i${src.length}${counter++}`;
1430
+ src.push(`const ${arrVar} = ${arr};`);
1431
+ if (extra.before != "")
1432
+ src.push(`if(${extra.before} true){`);
1433
+ src.push(`for (let ${iVar} = 0; ${iVar} < ${arrVar}.length; ${iVar}++) {`);
1434
+ src.push(`const prop = ${arrVar}[${iVar}];`);
1435
+ addEvaluatedProperty(src, "prop", trackingState);
1436
+ src.push(`if (${extra.before}${varName}[prop] === undefined) {${this.buildErrorReturn(pathContext, {
1437
+ keyword: "required",
1438
+ value: varName,
1439
+ message: `"Missing required field: " + prop + " in data."`,
1440
+ expected: "prop",
1441
+ schemaPath: `${pathContext.schema}`,
1442
+ })}${extra.after}}`);
1443
+ src.push(`}`);
1444
+ if (extra.before != "")
1445
+ src.push(`}`);
1446
+ }
1447
+ else {
1448
+ const missing = "missing" + counter++;
1449
+ src.push(`let ${missing};`);
1450
+ const stringReq = JSON.stringify(schema.required);
1451
+ src.push(`if(${extra.before}(${schema.required
1452
+ .map((prop) => {
1453
+ const stringified = JSON.stringify(prop);
1454
+ return `(${varName}[${stringified}] === undefined &&(${missing} = ${stringified}))`;
1455
+ })
1456
+ .join(" || ")})){${trackingState.shouldTrackEvaluatedProperties
1457
+ ? trackingState.hasOwnUnevaluatedProperties &&
1458
+ trackingState.parentHasUnevaluatedProperties
1459
+ ? `${trackingState.unEvaluatedPropertiesSetVar}.forEach(set => { set?.add(${missing}); });`
1460
+ : `${trackingState.unevaluatedPropVar}?.add(${missing});`
1461
+ : ""}${this.buildErrorReturn(pathContext, {
1462
+ keyword: "required",
1463
+ value: varName,
1464
+ message: `"Missing required field: " + ${missing} + " in data"`,
1465
+ expected: missing,
1466
+ schemaPath: `${pathContext.schema}`,
1467
+ })}${extra.after}};`);
1468
+ if (trackingState.shouldTrackEvaluatedProperties) {
1469
+ src.push(`for (const k of ${stringReq}){`);
1470
+ addEvaluatedProperty(src, "k", trackingState);
1471
+ src.push("}");
1472
+ }
1473
+ }
1474
+ }
1475
+ }
1476
+ }
1477
+ collectAllAllowedProperties(schema) {
1478
+ const allowedProperties = new Set();
1479
+ const patternProperties = [];
1480
+ if (typeof schema === "boolean") {
1481
+ return { allowedProperties, patternProperties };
1482
+ }
1483
+ if (schema.properties !== undefined) {
1484
+ Object.keys(schema.properties).forEach((prop) => allowedProperties.add(prop));
1485
+ }
1486
+ if (schema.patternProperties !== undefined) {
1487
+ Object.keys(schema.patternProperties).forEach((pattern) => {
1488
+ patternProperties.push(pattern);
1489
+ });
1490
+ }
1491
+ return { allowedProperties, patternProperties };
1492
+ }
1493
+ handlePatternProperties(src, schema, varName, pathContext, trackingState, extra) {
1494
+ if (extra.before != "")
1495
+ src.push(`if(${extra.before} true){`);
1496
+ src.push(`for (const key in ${varName}) {`);
1497
+ Object.getOwnPropertyNames(schema.patternProperties).forEach((pattern) => {
1498
+ let pname = this.regexCache.get(pattern);
1499
+ if (!pname) {
1500
+ pname = "patternProp" + counter++;
1501
+ this.regexCache.set(pattern, pname);
1502
+ }
1503
+ src.push(`if (${pname}.test(key)) {`);
1504
+ addEvaluatedProperty(src, "key", trackingState);
1505
+ const parent = trackingState.parentHasUnevaluatedProperties ||
1506
+ trackingState.hasOwnUnevaluatedProperties;
1507
+ const patternValidation = this.compileSchema(schema.patternProperties[pattern], {
1508
+ schema: `${pathContext.schema}/patternProperties/${JSON.stringify(pattern)}`,
1509
+ data: `${pathContext.data}/\${key}`,
1510
+ $data: `${pathContext.$data}/\${key}`,
1511
+ alt: pathContext.alt,
1512
+ alt2: pathContext.alt2,
1513
+ }, {
1514
+ isSubschema: true,
1515
+ parentHasUnevaluatedProperties: parent,
1516
+ parentUnevaluatedPropVar: parent
1517
+ ? trackingState.unevaluatedPropVar
1518
+ : undefined,
1519
+ }, `${varName}[key]`, extra);
1520
+ src.push(patternValidation, "}");
1521
+ });
1522
+ src.push("}");
1523
+ if (extra.before != "")
1524
+ src.push(`}`);
1525
+ }
1526
+ handleAdditionalProperties(src, schema, varName, pathContext, trackingState, extra) {
1527
+ const { allowedProperties, patternProperties } = this.collectAllAllowedProperties(schema);
1528
+ const explicitProps = Array.from(allowedProperties);
1529
+ if (extra.before != "")
1530
+ src.push(`if(${extra.before} true){`);
1531
+ src.push(`for (const key in ${varName}) {`);
1532
+ addEvaluatedProperty(src, "key", trackingState);
1533
+ let checks = [];
1534
+ if (explicitProps.length > 0) {
1535
+ const allowedCheck = explicitProps
1536
+ .map((key) => `key === ${JSON.stringify(key)}`)
1537
+ .join(" || ");
1538
+ checks.push(allowedCheck);
1539
+ }
1540
+ if (patternProperties.length > 0) {
1541
+ const patternCheck = patternProperties
1542
+ .map((pattern) => {
1543
+ let pname = this.regexCache.get(pattern);
1544
+ if (!pname) {
1545
+ pname = "patternProp" + counter++;
1546
+ this.regexCache.set(pattern, pname);
1547
+ }
1548
+ return `${pname}.test(key)`;
1549
+ })
1550
+ .join(" || ");
1551
+ checks.push(patternCheck);
1552
+ }
1553
+ if (checks.length > 0) {
1554
+ const condition = checks.join(" || ");
1555
+ src.push(`if (${condition}) continue;`);
1556
+ }
1557
+ const additionalPropValidation = this.compileSchema(schema.additionalProperties, {
1558
+ schema: `${pathContext.schema}/additionalProperties`,
1559
+ data: `${pathContext.data}/\${key}`,
1560
+ $data: `${pathContext.$data}/\${key}`,
1561
+ alt: pathContext.alt,
1562
+ alt2: pathContext.alt2,
1563
+ }, {}, `${varName}[key]`, extra);
1564
+ src.push(additionalPropValidation, "}");
1565
+ if (extra.before != "")
1566
+ src.push(`}`);
1567
+ }
1568
+ handlePropertyConstraints(src, schema, varName, pathContext, extra) {
1569
+ src.push(`const objKeys = Object.keys(${varName});`);
1570
+ if (schema.minProperties !== undefined) {
1571
+ const isDataRef = this.options.$data && isDataReference(schema.minProperties);
1572
+ let comparisonTarget;
1573
+ if (isDataRef && typeof schema.minProperties === "object") {
1574
+ const pointer = schema.minProperties.$data;
1575
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1576
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1577
+ }
1578
+ else {
1579
+ comparisonTarget = schema.minProperties;
1580
+ }
1581
+ src.push(`if (${extra.before}objKeys.length < ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1582
+ keyword: "minProperties",
1583
+ value: "objKeys.length",
1584
+ message: `"Object must have at least " + ${comparisonTarget} + " properties."`,
1585
+ expected: comparisonTarget,
1586
+ })}${extra.after}}`);
1587
+ if (isDataRef) {
1588
+ src.push("}");
1589
+ }
1590
+ }
1591
+ if (schema.maxProperties !== undefined) {
1592
+ const isDataRef = this.options.$data && isDataReference(schema.maxProperties);
1593
+ let comparisonTarget;
1594
+ if (isDataRef && typeof schema.maxProperties === "object") {
1595
+ const pointer = schema.maxProperties.$data;
1596
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1597
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1598
+ }
1599
+ else {
1600
+ comparisonTarget = schema.maxProperties;
1601
+ }
1602
+ src.push(`if (${extra.before}objKeys.length > ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1603
+ keyword: "maxProperties",
1604
+ value: "objKeys.length",
1605
+ message: `"Object must have at most " + ${comparisonTarget} + " properties."`,
1606
+ expected: comparisonTarget,
1607
+ })}${extra.after}}`);
1608
+ if (isDataRef) {
1609
+ src.push("}");
1610
+ }
1611
+ }
1612
+ }
1613
+ handlePropertyNames(src, schema, varName, pathContext, extra) {
1614
+ if (extra.before != "")
1615
+ src.push(`if(${extra.before} true){`);
1616
+ src.push(`for (const key in ${varName}) {`);
1617
+ const propertyNameValidation = this.compileSchema(schema.propertyNames, {
1618
+ schema: `${pathContext.schema}/propertyNames`,
1619
+ data: `${pathContext.data}/\${key}`,
1620
+ $data: `${pathContext.$data}/\${key}`,
1621
+ alt: pathContext.alt,
1622
+ alt2: pathContext.alt2,
1623
+ }, {}, `key`, extra);
1624
+ src.push(propertyNameValidation, "}");
1625
+ if (extra.before != "")
1626
+ src.push(`}`);
1627
+ }
1628
+ handleDependentSchemas(src, schema, varName, pathContext, trackingState, extra) {
1629
+ const dependencyMap = new Map();
1630
+ if (schema.dependencies !== undefined) {
1631
+ for (const property of Object.getOwnPropertyNames(schema.dependencies)) {
1632
+ const dep = schema.dependencies[property];
1633
+ if (Array.isArray(dep)) {
1634
+ dependencyMap.set(property, {
1635
+ required: dep,
1636
+ requiredSource: "dependencies",
1637
+ });
1638
+ }
1639
+ else {
1640
+ dependencyMap.set(property, {
1641
+ schema: dep,
1642
+ schemaSource: "dependencies",
1643
+ });
1644
+ }
1645
+ }
1646
+ }
1647
+ if (schema.dependentRequired !== undefined) {
1648
+ for (const property of Object.getOwnPropertyNames(schema.dependentRequired)) {
1649
+ const existing = dependencyMap.get(property) || {};
1650
+ dependencyMap.set(property, {
1651
+ ...existing,
1652
+ required: schema.dependentRequired[property],
1653
+ requiredSource: "dependentRequired",
1654
+ });
1655
+ }
1656
+ }
1657
+ if (schema.dependentSchemas !== undefined) {
1658
+ for (const property of Object.getOwnPropertyNames(schema.dependentSchemas)) {
1659
+ const existing = dependencyMap.get(property) || {};
1660
+ dependencyMap.set(property, {
1661
+ ...existing,
1662
+ schema: schema.dependentSchemas[property],
1663
+ schemaSource: "dependentSchemas",
1664
+ });
1665
+ }
1666
+ }
1667
+ for (const [property, dependency] of dependencyMap) {
1668
+ const stringifiedProperty = JSON.stringify(property);
1669
+ src.push(`if (${extra.before}${varName}[${stringifiedProperty}] !== undefined) {`);
1670
+ if (dependency.required) {
1671
+ this.handleRequiredFields(src, dependency.required, property, varName, pathContext, trackingState, extra, dependency.requiredSource);
1672
+ }
1673
+ if (dependency.schema !== undefined) {
1674
+ this.handleDependentSchema(src, dependency.schema, schema, property, varName, pathContext, trackingState, extra, dependency.schemaSource);
1675
+ }
1676
+ src.push("}");
1677
+ }
1678
+ }
1679
+ handleRequiredFields(src, requiredFields, triggerProperty, varName, pathContext, trackingState, extra, requiredSource) {
1680
+ for (let i = 0; i < requiredFields.length; i++) {
1681
+ const field = requiredFields[i];
1682
+ const stringifiedField = JSON.stringify(field);
1683
+ addEvaluatedProperty(src, stringifiedField, trackingState);
1684
+ const currentSchemaPath = pathContext.schema;
1685
+ pathContext.schema = `${pathContext.schema}/${requiredSource}/${triggerProperty}/`;
1686
+ src.push(`if (${extra.before}${varName}[${stringifiedField}] === undefined) {${this.buildErrorReturn(pathContext, {
1687
+ keyword: requiredSource,
1688
+ value: varName,
1689
+ message: `"Property (" + ${stringifiedField} + ") is required when " + ${JSON.stringify(triggerProperty)} + " is present."`,
1690
+ dataPath: `${pathContext.data}/${field}`,
1691
+ schemaPath: `${currentSchemaPath}/${requiredSource}/${triggerProperty}`,
1692
+ })}${extra.after}}`);
1693
+ pathContext.schema = currentSchemaPath;
1694
+ }
1695
+ }
1696
+ handleDependentSchema(src, depSchema, rootSchema, property, varName, pathContext, trackingState, extra, requiredSource) {
1697
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `${requiredSource}/${property}`, rootSchema);
1698
+ const depValidatorFn = this.compileSchema(depSchema, configs.pathContext, configs.trackingState, varName, extra);
1699
+ src.push(depValidatorFn);
1700
+ }
1701
+ handleObjectProperties(src, schema, varName, pathContext, trackingState, propertyKeys, extra) {
1702
+ const properties = schema.properties || {};
1703
+ const dependentSchemasProps = new Set();
1704
+ if (schema.dependentSchemas !== undefined) {
1705
+ for (const key of Object.getOwnPropertyNames(schema.dependentSchemas)) {
1706
+ const depProperties = schema.dependentSchemas[key]?.properties || {};
1707
+ for (const propName in depProperties) {
1708
+ dependentSchemasProps.add(propName);
1709
+ }
1710
+ }
1711
+ }
1712
+ if (this.options.removeAdditional) {
1713
+ const newObjName = "newObj" + counter++;
1714
+ src.push(`const ${newObjName} = {};`, `${JSON.stringify(propertyKeys)}.forEach(prop => {`, `if (${varName}[prop] !== undefined) {`, `${newObjName}[prop] = ${varName}[prop];`, `}`, `});`, `${varName} = ${newObjName};`);
1715
+ }
1716
+ for (const key of propertyKeys) {
1717
+ const stringified = JSON.stringify(key);
1718
+ if (dependentSchemasProps.has(key))
1719
+ continue;
1720
+ src.push(`if (${extra.before}${varName}[${stringified}] !== undefined) {`);
1721
+ addEvaluatedProperty(src, stringified, trackingState);
1722
+ if (properties[key] !== undefined) {
1723
+ const configs = this.createSubschemaOptions(trackingState, pathContext, `properties/${key}`, schema, `/${key}`);
1724
+ const propertyValidation = this.compileSchema(properties[key], configs.pathContext, configs.trackingState, `${varName}[${stringified}]`, extra);
1725
+ src.push(propertyValidation);
1726
+ }
1727
+ src.push("}");
1728
+ }
1729
+ }
1730
+ handleUnevaluatedProperties(src, schema, varName, pathContext, trackingState, extra) {
1731
+ const unName = "unevaluatedProp" + counter++;
1732
+ const evalSet = trackingState.unevaluatedPropVar;
1733
+ if (extra.before != "")
1734
+ src.push(`if(${extra.before} true){`);
1735
+ src.push(`const ${unName} = [];`, `for (const key in ${varName}) {`, `if (!${evalSet}.has(key)) {`, `${unName}.push(key);`, `}`, `}`);
1736
+ if (schema.unevaluatedProperties === false) {
1737
+ src.push(`if (${unName}.length > 0) {${this.buildErrorReturn(pathContext, {
1738
+ keyword: "unevaluatedProperties",
1739
+ value: varName,
1740
+ message: `"Unevaluated properties: [" + ${unName} + "] in schema."`,
1741
+ expected: '"All properties to be evaluated"',
1742
+ dataPath: pathContext.data,
1743
+ schemaPath: `${pathContext.schema}/unevaluatedProperties`,
1744
+ })}${extra.after}}`);
1745
+ }
1746
+ else if (schema.unevaluatedProperties === true) {
1747
+ if (trackingState.parentHasUnevaluatedProperties) {
1748
+ src.push(`for(const key in ${varName}){${trackingState.parentUnevaluatedPropVar}.add(key)}`);
1749
+ }
1750
+ }
1751
+ else {
1752
+ const unKeyName = "unKey" + counter++;
1753
+ const configs = this.createSubschemaOptions(trackingState, pathContext, ``, schema, ``);
1754
+ const unpValidatorFn = this.compileSchema(schema.unevaluatedProperties, {
1755
+ data: `${pathContext.data}/\${${unKeyName}}`,
1756
+ $data: `${pathContext.$data}/\${${unKeyName}}`,
1757
+ schema: `${pathContext.schema}/unevaluatedProperties/\${${unKeyName}}`,
1758
+ alt: pathContext.alt,
1759
+ alt2: pathContext.alt2,
1760
+ }, configs.trackingState, `${varName}[${unKeyName}]`, extra);
1761
+ src.push(`for(const ${unKeyName} of ${unName}) {`);
1762
+ src.push(unpValidatorFn);
1763
+ if (trackingState.parentHasUnevaluatedProperties) {
1764
+ src.push(`${trackingState.parentUnevaluatedPropVar}.add(${unKeyName});`);
1765
+ }
1766
+ src.push("}");
1767
+ }
1768
+ if (extra.before != "")
1769
+ src.push(`}`);
1770
+ }
1771
+ handleArray(src, schema, varName, pathContext, trackingState, condition, extra) {
1772
+ if (schema.type === "array") {
1773
+ src.push(`if (${extra.before}(!Array.isArray(${varName}) || ${varName} === null)) {${this.buildErrorReturn(pathContext, {
1774
+ keyword: "type",
1775
+ value: varName,
1776
+ message: '"Invalid type, expected array"',
1777
+ expected: '"array"',
1778
+ })}${extra.after}}`);
1779
+ }
1780
+ if (schema.type === "array" && condition)
1781
+ src.push("else{");
1782
+ if (schema.type !== "array" && condition) {
1783
+ src.push(`if(${extra.before}Array.isArray(${varName})){`);
1784
+ }
1785
+ if (schema.minItems !== undefined ||
1786
+ schema.maxItems !== undefined ||
1787
+ schema.uniqueItems === true) {
1788
+ this.handleArrayConstraints(src, schema, varName, pathContext, extra);
1789
+ }
1790
+ if (schema.prefixItems !== undefined ||
1791
+ schema.items !== undefined ||
1792
+ schema.additionalItems !== undefined) {
1793
+ this.handleArrayItems(src, schema, varName, pathContext, trackingState, extra);
1794
+ }
1795
+ if (schema.contains !== undefined) {
1796
+ this.handleArrayContains(src, schema, varName, pathContext, trackingState, extra);
1797
+ }
1798
+ if (schema.unevaluatedItems !== undefined &&
1799
+ schema.additionalItems !== true &&
1800
+ schema.items !== true) {
1801
+ this.handleUnevaluatedItems(src, schema, varName, pathContext, trackingState, extra);
1802
+ }
1803
+ if (schema.type !== "array" && condition) {
1804
+ src.push(`}`);
1805
+ }
1806
+ if (schema.type === "array" && condition)
1807
+ src.push("}");
1808
+ }
1809
+ handleArrayConstraints(src, schema, varName, pathContext, extra) {
1810
+ if (schema.minItems !== undefined) {
1811
+ const isDataRef = this.options.$data && isDataReference(schema.minItems);
1812
+ let comparisonTarget;
1813
+ if (isDataRef && typeof schema.minItems === "object") {
1814
+ const pointer = schema.minItems.$data;
1815
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1816
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1817
+ }
1818
+ else {
1819
+ comparisonTarget = schema.minItems;
1820
+ }
1821
+ src.push(`if (${extra.before}${varName}.length < ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1822
+ keyword: "minItems",
1823
+ value: `${varName}.length`,
1824
+ message: `"Array must have at least " +${comparisonTarget}+" items"`,
1825
+ expected: comparisonTarget,
1826
+ })}${extra.after}}`);
1827
+ if (isDataRef) {
1828
+ src.push("}");
1829
+ }
1830
+ }
1831
+ if (schema.maxItems !== undefined) {
1832
+ const isDataRef = this.options.$data && isDataReference(schema.maxItems);
1833
+ let comparisonTarget;
1834
+ if (isDataRef && typeof schema.maxItems === "object") {
1835
+ const pointer = schema.maxItems.$data;
1836
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1837
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
1838
+ }
1839
+ else {
1840
+ comparisonTarget = schema.maxItems;
1841
+ }
1842
+ src.push(`if (${extra.before}${varName}.length > ${comparisonTarget}) {${this.buildErrorReturn(pathContext, {
1843
+ keyword: "maxItems",
1844
+ value: `${varName}.length`,
1845
+ message: `"Array must have at most " + ${comparisonTarget} + " items"`,
1846
+ expected: comparisonTarget,
1847
+ })}${extra.after}}`);
1848
+ if (isDataRef) {
1849
+ src.push("}");
1850
+ }
1851
+ }
1852
+ const isDataRef = this.options.$data && isDataReference(schema.uniqueItems);
1853
+ if (schema.uniqueItems === true || isDataRef) {
1854
+ let comparisonTarget;
1855
+ this.needsStringify = true;
1856
+ if (isDataRef && typeof schema.uniqueItems === "object") {
1857
+ comparisonTarget = "$data" + counter++;
1858
+ const pointer = schema.uniqueItems.$data;
1859
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
1860
+ src.push(`const ${comparisonTarget} = ${resolvedPath};`, `if (${comparisonTarget} === true) {`);
1861
+ }
1862
+ else {
1863
+ comparisonTarget = schema.uniqueItems;
1864
+ }
1865
+ const unique = "unique" + counter++;
1866
+ if (extra.before != "" && !isDataRef)
1867
+ src.push(`if(${extra.before} true){`);
1868
+ src.push(`const ${unique}_uniqueValues = new Set();let ${unique}_hasDuplicates = false;for (let ${unique} = 0; ${unique} < ${varName}.length; ${unique}++) {const itemStr = typeof ${varName}[${unique}] == 'object' ? canonicalStringify(${varName}[${unique}]) : '"'+${varName}[${unique}]+'"';if (${unique}_uniqueValues.has(itemStr)) {
1869
+ ${unique}_hasDuplicates = true;break;};${unique}_uniqueValues.add(itemStr);}if (${unique}_hasDuplicates) {${this.buildErrorReturn(pathContext, {
1870
+ keyword: "uniqueItems",
1871
+ value: varName,
1872
+ message: '"Array items must be unique"',
1873
+ expected: '"unique values"',
1874
+ })}${extra.after}}`);
1875
+ if (extra.before != "" && !isDataRef)
1876
+ src.push(`}`);
1877
+ if (isDataRef) {
1878
+ src.push("}");
1879
+ }
1880
+ }
1881
+ }
1882
+ handleArrayItems(src, schema, varName, pathContext, trackingState, extra) {
1883
+ const ischema = schema.prefixItems ||
1884
+ (Array.isArray(schema.items) ? schema.items : undefined);
1885
+ if (ischema && ischema.length > 0) {
1886
+ ischema.forEach((itemSchema, index) => {
1887
+ src.push(`if (${extra.before}${varName}.length > ${index}) {`);
1888
+ addEvaluatedItems(src, index, trackingState);
1889
+ const parent = trackingState.hasOwnUnevaluatedItems ||
1890
+ trackingState.parentHasUnevaluatedItems;
1891
+ const itemValidation = this.compileSchema(itemSchema, {
1892
+ schema: `${pathContext.schema}/${schema.prefixItems !== undefined ? "prefixItems" : "items"}/${index}`,
1893
+ alt: `${pathContext.schema}/${schema.prefixItems !== undefined ? "prefixItems" : "items"}/${index}`,
1894
+ alt2: `${pathContext.schema}/${schema.prefixItems !== undefined ? "prefixItems" : "items"}`,
1895
+ data: `${pathContext.data}/${index}`,
1896
+ $data: `${pathContext.$data}/${index}`,
1897
+ }, {
1898
+ isSubschema: true,
1899
+ parentHasUnevaluatedItems: parent,
1900
+ parentUnevaluatedItemVar: parent
1901
+ ? trackingState.unevaluatedItemVar
1902
+ : undefined,
1903
+ }, `${varName}[${index}]`, extra);
1904
+ src.push(itemValidation, "}");
1905
+ });
1906
+ }
1907
+ if (Array.isArray(schema.items)) {
1908
+ if (schema.additionalItems === false) {
1909
+ src.push(`if (${extra.before}${varName}.length > ${schema.items.length}) {${this.buildErrorReturn(pathContext, {
1910
+ keyword: "additionalItems",
1911
+ value: `${varName}.length`,
1912
+ message: `"Array has too many items. Expected at most ${schema.items.length}"`,
1913
+ expected: schema.items.length,
1914
+ })}${extra.after}}`);
1915
+ }
1916
+ else if (schema.additionalItems &&
1917
+ typeof schema.additionalItems === "object") {
1918
+ const itemValidator = "i" + counter++;
1919
+ src.push(`for (let ${itemValidator} = ${schema.items.length}; ${itemValidator} < ${varName}.length; ${itemValidator}++) {`);
1920
+ addEvaluatedItems(src, itemValidator, trackingState);
1921
+ const additionalValidation = this.compileSchema(schema.additionalItems, {
1922
+ schema: `${pathContext.schema}/additionalItems/\${${itemValidator}}`,
1923
+ data: `${pathContext.data}/\${${itemValidator}}`,
1924
+ $data: `${pathContext.$data}/\${${itemValidator}}`,
1925
+ alt: pathContext.alt,
1926
+ alt2: pathContext.alt2,
1927
+ }, {}, `${varName}[${itemValidator}]`, extra);
1928
+ src.push(additionalValidation, "}");
1929
+ }
1930
+ else if (schema.additionalItems === true &&
1931
+ trackingState.parentHasUnevaluatedItems) {
1932
+ src.push(`${varName}.forEach((_, index) => ${trackingState.parentUnevaluatedItemVar}.add(index));`);
1933
+ }
1934
+ }
1935
+ if (schema.items === true && trackingState.parentHasUnevaluatedItems) {
1936
+ src.push(`${varName}.forEach((_, index) => ${trackingState.parentUnevaluatedItemVar}.add(index));`);
1937
+ }
1938
+ if (!Array.isArray(schema.items) &&
1939
+ schema.items !== undefined &&
1940
+ schema.items !== true) {
1941
+ const itemValidator = "i" + counter++;
1942
+ src.push(`const len${itemValidator} = ${varName}.length;`);
1943
+ if (schema.prefixItems !== undefined && schema.prefixItems.length > 0) {
1944
+ if (schema.items === false) {
1945
+ src.push(`if (${extra.before}len${itemValidator} > ${schema.prefixItems.length}) {${this.buildErrorReturn(pathContext, {
1946
+ keyword: "items",
1947
+ value: `${varName}.length`,
1948
+ message: `"Array has too many items. Expected at most ${schema.prefixItems.length}."`,
1949
+ expected: String(schema.prefixItems.length),
1950
+ })}${extra.after}}`);
1951
+ }
1952
+ else {
1953
+ if (extra.before != "")
1954
+ src.push(`if(${extra.before} true){`);
1955
+ src.push(`for (let ${itemValidator} = ${schema.prefixItems.length}; ${itemValidator} < len${itemValidator}; ${itemValidator}++) {`);
1956
+ }
1957
+ }
1958
+ else {
1959
+ if (extra.before != "")
1960
+ src.push(`if(${extra.before} true){`);
1961
+ src.push(`for (let ${itemValidator} = 0; ${itemValidator} < len${itemValidator}; ${itemValidator}++) {`);
1962
+ }
1963
+ addEvaluatedItems(src, itemValidator, trackingState);
1964
+ if (schema.prefixItems === undefined ||
1965
+ schema.prefixItems.length < 1 ||
1966
+ (schema.items !== undefined && typeof schema.items !== "boolean")) {
1967
+ const itemValidation = this.compileSchema(schema.items, {
1968
+ schema: `${pathContext.schema}/items`,
1969
+ data: `${pathContext.data}/\${${itemValidator}}`,
1970
+ $data: `${pathContext.$data}/\${${itemValidator}}`,
1971
+ alt: pathContext.alt,
1972
+ alt2: pathContext.alt2,
1973
+ }, {}, `${varName}[${itemValidator}]`, extra);
1974
+ src.push(itemValidation, "};");
1975
+ }
1976
+ if (extra.before != "")
1977
+ src.push(`}`);
1978
+ }
1979
+ }
1980
+ handleArrayContains(src, schema, varName, pathContext, trackingState, extra) {
1981
+ const containsValid = "containsValid" + counter++;
1982
+ const containsCount = "containsCount" + counter++;
1983
+ const conValid = `conValid${counter++}`;
1984
+ const i = "i" + counter++;
1985
+ const originalNotLogic = this.notLogic;
1986
+ this.notLogic = true;
1987
+ const containsValidation = this.compileSchema(schema.contains, undefined, undefined, `${varName}[${i}]`, {
1988
+ before: `${conValid} && `,
1989
+ after: `${conValid} = false;`,
1990
+ });
1991
+ this.notLogic = originalNotLogic;
1992
+ const hasMinMax = schema.maxContains !== undefined || schema.minContains !== undefined;
1993
+ src.push(hasMinMax ? `let ${containsCount} = 0;` : `let ${containsValid} = false;`);
1994
+ src.push(`for (let ${i} = 0; ${i} < ${varName}.length; ${i}++) {`, `let ${conValid} = true;`, containsValidation, `if (${conValid}) {`);
1995
+ addEvaluatedItems(src, i, trackingState);
1996
+ if (hasMinMax) {
1997
+ src.push(`${containsCount}++;`);
1998
+ if (schema.maxContains !== undefined) {
1999
+ src.push(`if (${containsCount} > ${schema.maxContains}) break;`);
2000
+ }
2001
+ }
2002
+ else {
2003
+ src.push(`${containsValid} = true;`);
2004
+ if (!trackingState.shouldTrackEvaluatedProperties &&
2005
+ !trackingState.shouldTrackEvaluatedItems) {
2006
+ src.push("break;");
2007
+ }
2008
+ }
2009
+ src.push("}", "}");
2010
+ if (hasMinMax) {
2011
+ if (schema.minContains === undefined)
2012
+ schema.minItems = 0;
2013
+ if (schema.minContains !== undefined) {
2014
+ const isDataRef = this.options.$data && isDataReference(schema.minContains);
2015
+ let comparisonTarget;
2016
+ if (isDataRef && typeof schema.minContains === "object") {
2017
+ const pointer = schema.minContains.$data;
2018
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
2019
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
2020
+ }
2021
+ else {
2022
+ comparisonTarget = schema.minContains;
2023
+ }
2024
+ src.push(`if (${extra.before}${containsCount} < ${comparisonTarget ?? 1}) {${this.buildErrorReturn(pathContext, {
2025
+ keyword: "minContains",
2026
+ value: varName,
2027
+ message: `"Array must contain at least " + ${comparisonTarget} + " item matching the schema."`,
2028
+ expected: comparisonTarget,
2029
+ })}${extra.after}}`);
2030
+ }
2031
+ if (schema.maxContains !== undefined) {
2032
+ const isDataRef = this.options.$data && isDataReference(schema.maxContains);
2033
+ let comparisonTarget;
2034
+ if (isDataRef && typeof schema.maxContains === "object") {
2035
+ const pointer = schema.maxContains.$data;
2036
+ const resolvedPath = resolveDataPointerAtCompileTime(pointer, pathContext.$data, this.refCall);
2037
+ comparisonTarget = generateNumberDataRef(src, resolvedPath, extra, true);
2038
+ }
2039
+ else {
2040
+ comparisonTarget = schema.maxContains;
2041
+ }
2042
+ const condition = schema.minContains === 0
2043
+ ? `${containsCount} > ${comparisonTarget}`
2044
+ : `(${containsCount} > ${comparisonTarget} || ${varName}.length < 1)`;
2045
+ src.push(`if (${extra.before}${condition}) {${this.buildErrorReturn(pathContext, {
2046
+ keyword: "maxContains",
2047
+ value: varName,
2048
+ message: `"Array must contain at most " + ${comparisonTarget} + " item matching the schema."`,
2049
+ expected: comparisonTarget,
2050
+ })}${extra.after}}`);
2051
+ }
2052
+ }
2053
+ else {
2054
+ src.push(`if (${extra.before}!${containsValid}) {${this.buildErrorReturn(pathContext, {
2055
+ keyword: "contains",
2056
+ value: varName,
2057
+ message: '"Array must contain at least one item matching the schema"',
2058
+ })}${extra.after}}`);
2059
+ }
2060
+ }
2061
+ handleUnevaluatedItems(src, schema, varName, pathContext, trackingState, extra) {
2062
+ const unName = "unevaluatedItn" + counter++;
2063
+ const evalSet = trackingState.unevaluatedItemVar;
2064
+ if (extra.before != "")
2065
+ src.push(`if(${extra.before} true){`);
2066
+ src.push(`const ${unName} = [];`, `for (let i = 0; i < ${varName}.length; i++) {`, `if (!${evalSet}.has(i)) {`, `${unName}.push(i);`, `}`, `}`);
2067
+ if (schema.unevaluatedItems === false) {
2068
+ src.push(`if (${extra.before}${unName}.length > 0) {${this.buildErrorReturn(pathContext, {
2069
+ keyword: "unevaluatedItems",
2070
+ value: varName,
2071
+ message: `"Unevaluated items: [" + ${unName} + "] in schema, in array."`,
2072
+ expected: '"All items to be evaluated"',
2073
+ dataPath: pathContext.data,
2074
+ schemaPath: `${pathContext.schema}/unevaluatedItems`,
2075
+ })}${extra.after}}`);
2076
+ }
2077
+ else if (schema.unevaluatedItems === true) {
2078
+ if (trackingState.parentHasUnevaluatedItems) {
2079
+ src.push(`${varName}.forEach((_, index) => ${trackingState.parentUnevaluatedItemVar}.add(index));`);
2080
+ }
2081
+ }
2082
+ else {
2083
+ const unKeyName = "unKey" + counter++;
2084
+ const configs = this.createSubschemaOptions(trackingState, pathContext, ``, schema, ``);
2085
+ const unpValidatorFn = this.compileSchema(schema.unevaluatedItems, {
2086
+ data: `${pathContext.data}/\${${unKeyName}}`,
2087
+ $data: `${pathContext.$data}/\${${unKeyName}}`,
2088
+ schema: `${pathContext.schema}/unevaluatedItems/\${${unKeyName}}`,
2089
+ alt: pathContext.alt,
2090
+ alt2: pathContext.alt2,
2091
+ }, configs.trackingState, `${varName}[${unKeyName}]`, extra);
2092
+ src.push(`for(const ${unKeyName} of ${unName}) {`, unpValidatorFn);
2093
+ if (trackingState.parentHasUnevaluatedProperties) {
2094
+ src.push(`${trackingState.parentUnevaluatedItemVar}.add(${unKeyName});`);
2095
+ }
2096
+ src.push("}");
2097
+ }
2098
+ if (extra.before != "")
2099
+ src.push(`}`);
2100
+ }
2101
+ buildErrorReturn(pathContext, error, spreads) {
2102
+ if (this.notLogic)
2103
+ return "";
2104
+ if (this.neutralError)
2105
+ return "return false;";
2106
+ let result = this.options.allErrors
2107
+ ? `${this.errorVariable}.push({`
2108
+ : `${this.mainFunctionName}.errors = [{`;
2109
+ const escapedDataPath = (0, utilities_1.escapeTemplateString)(error.dataPath || pathContext.data || "/");
2110
+ const escapedSchemaPath = (0, utilities_1.escapeTemplateString)(error.schemaPath ?? pathContext.schema);
2111
+ result += `dataPath: \`${escapedDataPath}\`,`;
2112
+ result += `schemaPath: \`${escapedSchemaPath}\`,`;
2113
+ result += `keyword: "${error.keyword}",`;
2114
+ if (this.options.verbose) {
2115
+ result += `value: ${error.value},`;
2116
+ if (error.expected) {
2117
+ result += `expected: ${error.expected},`;
2118
+ }
2119
+ }
2120
+ let errorMessage;
2121
+ if (this.options.errorMessage && typeof this.schema !== "boolean") {
2122
+ let schemaAtPath = (0, utilities_1.getSchemaAtPath)(this.schema, pathContext.schema);
2123
+ if (schemaAtPath &&
2124
+ typeof schemaAtPath === "object" &&
2125
+ "errorMessage" in schemaAtPath) {
2126
+ if (typeof schemaAtPath.errorMessage === "string") {
2127
+ errorMessage = schemaAtPath.errorMessage;
2128
+ }
2129
+ else if (typeof schemaAtPath.errorMessage === "object") {
2130
+ errorMessage = schemaAtPath.errorMessage[error.keyword];
2131
+ if (!errorMessage)
2132
+ errorMessage = schemaAtPath.errorMessage["_jetError"];
2133
+ }
2134
+ }
2135
+ if (pathContext.alt && !errorMessage) {
2136
+ schemaAtPath = (0, utilities_1.getSchemaAtPath)(this.schema, pathContext.alt);
2137
+ if (typeof schemaAtPath === "object" &&
2138
+ "errorMessage" in schemaAtPath) {
2139
+ let presentAtPath = schemaAtPath.errorMessage;
2140
+ if (typeof schemaAtPath.errorMessage === "object") {
2141
+ const errorPath = "#" + pathContext.schema.replace(pathContext.alt, "");
2142
+ presentAtPath = (0, utilities_1.getSchemaAtPath)(schemaAtPath.errorMessage, errorPath);
2143
+ }
2144
+ if (typeof presentAtPath === "string") {
2145
+ errorMessage = presentAtPath;
2146
+ }
2147
+ else if (typeof presentAtPath === "object") {
2148
+ errorMessage = presentAtPath[error.keyword];
2149
+ if (!errorMessage)
2150
+ errorMessage = presentAtPath["_jetError"];
2151
+ }
2152
+ }
2153
+ }
2154
+ if (this.schema.errorMessage && !errorMessage) {
2155
+ const rootErrorMessage = this.schema.errorMessage;
2156
+ if (typeof rootErrorMessage === "string") {
2157
+ errorMessage = rootErrorMessage;
2158
+ }
2159
+ else if (typeof rootErrorMessage === "object") {
2160
+ let errorAtPath = (0, utilities_1.getSchemaAtPath)(rootErrorMessage, pathContext.schema);
2161
+ if (typeof errorAtPath === "object" &&
2162
+ Object.keys(errorAtPath).length === 0 &&
2163
+ pathContext.alt) {
2164
+ errorAtPath = (0, utilities_1.getSchemaAtPath)(rootErrorMessage, pathContext.alt);
2165
+ }
2166
+ if (typeof errorAtPath === "object" &&
2167
+ Object.keys(errorAtPath).length === 0 &&
2168
+ pathContext.alt2) {
2169
+ errorAtPath = (0, utilities_1.getSchemaAtPath)(rootErrorMessage, pathContext.alt2);
2170
+ }
2171
+ if (typeof errorAtPath === "string") {
2172
+ errorMessage = errorAtPath;
2173
+ }
2174
+ else if (typeof errorAtPath === "object") {
2175
+ errorMessage = errorAtPath[error.keyword];
2176
+ if (!errorMessage)
2177
+ errorMessage = errorAtPath["_jetError"];
2178
+ }
2179
+ }
2180
+ }
2181
+ }
2182
+ result += `message: ${JSON.stringify(errorMessage) || error.message}`;
2183
+ if (spreads) {
2184
+ result += `,${spreads}`;
2185
+ }
2186
+ result += "}";
2187
+ if (this.options.allErrors) {
2188
+ result += ");";
2189
+ }
2190
+ else {
2191
+ result += "];";
2192
+ if (!this.noreturn)
2193
+ result += "return false;";
2194
+ }
2195
+ return result;
2196
+ }
2197
+ }
2198
+ exports.Compiler = Compiler;
2199
+ //# sourceMappingURL=compileSchema.js.map