@amritk/generate-validators 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI.md +13 -6
- package/README.md +36 -16
- package/dist/generators/build-schema.d.ts +2 -2
- package/dist/generators/build-schema.js +23 -3
- package/dist/generators/emit-format-checks.d.ts +50 -0
- package/dist/generators/emit-format-checks.js +248 -0
- package/dist/generators/enforced-keywords.d.ts +16 -4
- package/dist/generators/enforced-keywords.js +13 -3
- package/dist/generators/folds-to-constant.d.ts +1 -1
- package/dist/generators/folds-to-constant.js +6 -2
- package/dist/generators/generate-files.d.ts +7 -0
- package/dist/generators/generate-files.js +10 -2
- package/dist/generators/generate-validator-function.d.ts +2 -2
- package/dist/generators/generate-validator-function.js +103 -75
- package/package.json +4 -4
|
@@ -11,7 +11,8 @@ import { unknownKeyCheck } from "@amritk/helpers/unknown-key-check";
|
|
|
11
11
|
import { DEFAULT_UNKNOWN_KEYS } from "@amritk/helpers/unknown-keys-strategy";
|
|
12
12
|
import { assertGeneratableRefs } from "./assert-generatable-refs.js";
|
|
13
13
|
import { assertUnevaluatedGeneratable, UNPROVABLE_COVERAGE_MESSAGE } from "./assert-unevaluated-generatable.js";
|
|
14
|
-
import {
|
|
14
|
+
import { formatCheckName, formatFamily } from "./emit-format-checks.js";
|
|
15
|
+
import { declaresKeywordOutside, enforcesFormat, NO_FORMATS } from "./enforced-keywords.js";
|
|
15
16
|
import { tupleShapeOf } from "./tuple-shape.js";
|
|
16
17
|
import { unevaluatedItemsExpr, unevaluatedPropertiesExpr } from "./unevaluated-match.js";
|
|
17
18
|
const validatorName = (typeName) => `validate${typeName}`;
|
|
@@ -97,14 +98,17 @@ const getTypeArray = (schema) => {
|
|
|
97
98
|
return schema.type;
|
|
98
99
|
};
|
|
99
100
|
const ROOT_ERROR_SINK = "(errors ??= [])";
|
|
101
|
+
const pushError = (sink, message, path, keyword, params = "{}") => `${sink}.push({ message: ${message}, path: ${path}, keyword: ${JSON.stringify(keyword)}, params: ${params} })`;
|
|
102
|
+
const returnError = (message, path, keyword, params = "{}") => `return { valid: false, errors: [{ message: ${message}, path: ${path}, keyword: ${JSON.stringify(keyword)}, params: ${params} }] }`;
|
|
100
103
|
const MATCH_ERROR_SINK = "_m";
|
|
101
|
-
const createRootContext = (rootSchema) => ({
|
|
104
|
+
const createRootContext = (rootSchema, formats = NO_FORMATS) => ({
|
|
102
105
|
objVar: "obj",
|
|
103
106
|
pathPrefix: "${_path}",
|
|
104
107
|
depth: 0,
|
|
105
108
|
hoisted: [],
|
|
106
109
|
rootSchema,
|
|
107
|
-
sink: ROOT_ERROR_SINK
|
|
110
|
+
sink: ROOT_ERROR_SINK,
|
|
111
|
+
formats
|
|
108
112
|
});
|
|
109
113
|
const pointerSegment = (key) => {
|
|
110
114
|
const pointer = key.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
@@ -157,7 +161,7 @@ const generateStrictKeyChecks = (schema, ctx) => {
|
|
|
157
161
|
return [
|
|
158
162
|
` for (const _key${d} in ${ctx.objVar}) {`,
|
|
159
163
|
` if (${unknownTest}${patternGuard}) {`,
|
|
160
|
-
` ${ctx.sink
|
|
164
|
+
` ${pushError(ctx.sink, "'must NOT have additional properties'", `\`${ctx.pathPrefix}/\${escapePointer(_key${d})}\``, "additionalProperties", `{ additionalProperty: _key${d} }`)}`,
|
|
161
165
|
` }`,
|
|
162
166
|
` }`
|
|
163
167
|
];
|
|
@@ -172,7 +176,7 @@ const generateMissingRequiredChecks = (schema, ctx) => {
|
|
|
172
176
|
if (Object.hasOwn(props, key))
|
|
173
177
|
continue;
|
|
174
178
|
lines.push(` if (${missingCheck(ctx.objVar, key)}) {`);
|
|
175
|
-
lines.push(` ${ctx.sink
|
|
179
|
+
lines.push(` ${pushError(ctx.sink, JSON.stringify(`must have required property '${key}'`), parentPath, "required", JSON.stringify({ missingProperty: key }))}`);
|
|
176
180
|
lines.push(` }`);
|
|
177
181
|
}
|
|
178
182
|
return lines;
|
|
@@ -184,15 +188,15 @@ const generatePropertyChecks = (key, propSchema, isRequired, suffix, ctx) => {
|
|
|
184
188
|
if (isRequired) {
|
|
185
189
|
return [
|
|
186
190
|
` if (${missingCheck(ctx.objVar, key)}) {`,
|
|
187
|
-
` ${ctx.sink
|
|
191
|
+
` ${pushError(ctx.sink, JSON.stringify(`must have required property '${key}'`), parentPath, "required", JSON.stringify({ missingProperty: key }))}`,
|
|
188
192
|
` } else {`,
|
|
189
|
-
` ${ctx.sink
|
|
193
|
+
` ${pushError(ctx.sink, JSON.stringify(FALSE_SCHEMA_MESSAGE), path, "false schema")}`,
|
|
190
194
|
` }`
|
|
191
195
|
];
|
|
192
196
|
}
|
|
193
197
|
return [
|
|
194
198
|
` if (${hasOwnCheck(ctx.objVar, key)}) {`,
|
|
195
|
-
` ${ctx.sink
|
|
199
|
+
` ${pushError(ctx.sink, JSON.stringify(FALSE_SCHEMA_MESSAGE), path, "false schema")}`,
|
|
196
200
|
` }`
|
|
197
201
|
];
|
|
198
202
|
}
|
|
@@ -236,26 +240,26 @@ const generateKeywordChecks = (key, raw, path, schema, suffix, ctx, presence) =>
|
|
|
236
240
|
const instanceOf = getMjstInstanceOf(schema);
|
|
237
241
|
if (instanceOf) {
|
|
238
242
|
lines.push(` if (${presence}!(${raw} instanceof ${instanceOf})) {`);
|
|
239
|
-
lines.push(` ${ctx.sink
|
|
243
|
+
lines.push(` ${pushError(ctx.sink, `'must be ${instanceOf}'`, path, "type", JSON.stringify({ type: instanceOf }))}`);
|
|
240
244
|
lines.push(` }`);
|
|
241
245
|
}
|
|
242
246
|
const primitive = getMjstPrimitive(schema);
|
|
243
247
|
if (primitive) {
|
|
244
248
|
lines.push(` if (${presence}typeof ${raw} !== "${primitive}") {`);
|
|
245
|
-
lines.push(` ${ctx.sink
|
|
249
|
+
lines.push(` ${pushError(ctx.sink, `'must be ${primitive}'`, path, "type", JSON.stringify({ type: primitive }))}`);
|
|
246
250
|
lines.push(` }`);
|
|
247
251
|
}
|
|
248
252
|
if (hasConst(schema)) {
|
|
249
253
|
const mismatch = constMismatchCondition(raw, schema.const);
|
|
250
254
|
const msg = JSON.stringify(`must be ${JSON.stringify(schema.const)}`);
|
|
251
255
|
lines.push(` if (${presence}${mismatch}) {`);
|
|
252
|
-
lines.push(` ${ctx.sink
|
|
256
|
+
lines.push(` ${pushError(ctx.sink, msg, path, "const", JSON.stringify({ allowedValue: schema.const }))}`);
|
|
253
257
|
lines.push(` }`);
|
|
254
258
|
}
|
|
255
259
|
if (hasEnum(schema)) {
|
|
256
260
|
const label = schema.enum.map((v) => JSON.stringify(v)).join(", ");
|
|
257
261
|
lines.push(` if (${presence}!${enumMembershipExpr(schema.enum, raw)}) {`);
|
|
258
|
-
lines.push(` ${ctx.sink
|
|
262
|
+
lines.push(` ${pushError(ctx.sink, JSON.stringify(`must be one of: ${label}`), path, "enum", JSON.stringify({ allowedValues: schema.enum }))}`);
|
|
259
263
|
lines.push(` }`);
|
|
260
264
|
}
|
|
261
265
|
if (instanceOf === void 0 && primitive === void 0) {
|
|
@@ -264,7 +268,7 @@ const generateKeywordChecks = (key, raw, path, schema, suffix, ctx, presence) =>
|
|
|
264
268
|
const wrongType = wrongTypeCondition(raw, t);
|
|
265
269
|
if (wrongType) {
|
|
266
270
|
lines.push(` if (${presence === "" ? wrongType : `${presence}(${wrongType})`}) {`);
|
|
267
|
-
lines.push(` ${ctx.sink
|
|
271
|
+
lines.push(` ${pushError(ctx.sink, `'must be ${typeofString(t)}'`, path, "type", JSON.stringify({ type: t }))}`);
|
|
268
272
|
lines.push(` }`);
|
|
269
273
|
}
|
|
270
274
|
}
|
|
@@ -274,7 +278,7 @@ const generateKeywordChecks = (key, raw, path, schema, suffix, ctx, presence) =>
|
|
|
274
278
|
if (allWrong) {
|
|
275
279
|
const label = typeArray.map((t) => typeofString(t)).join(" or ");
|
|
276
280
|
lines.push(` if (${presence === "" ? allWrong : `${presence}(${allWrong})`}) {`);
|
|
277
|
-
lines.push(` ${ctx.sink
|
|
281
|
+
lines.push(` ${pushError(ctx.sink, JSON.stringify(`must be ${label}`), path, "type", JSON.stringify({ type: schema.type }))}`);
|
|
278
282
|
lines.push(` }`);
|
|
279
283
|
}
|
|
280
284
|
}
|
|
@@ -293,7 +297,7 @@ const generatePropertyCheckLines = (key, propSchema, isRequired, suffix, ctx) =>
|
|
|
293
297
|
const parentPath = ctx.depth === 0 ? "_path" : `\`${ctx.pathPrefix}\``;
|
|
294
298
|
const missing = [
|
|
295
299
|
` if (${missingCheck(ctx.objVar, key)}) {`,
|
|
296
|
-
` ${ctx.sink
|
|
300
|
+
` ${pushError(ctx.sink, JSON.stringify(`must have required property '${key}'`), parentPath, "required", JSON.stringify({ missingProperty: key }))}`
|
|
297
301
|
];
|
|
298
302
|
if (!isSchemaObject(propSchema)) {
|
|
299
303
|
if (isRequired && propSchema === true)
|
|
@@ -318,22 +322,31 @@ const generateConstraintChecks = (key, raw, path, propSchema, suffix, ctx) => {
|
|
|
318
322
|
return [];
|
|
319
323
|
const sp = propSchema;
|
|
320
324
|
const lines = [];
|
|
325
|
+
if (isSchemaObject(propSchema) && enforcesFormat(propSchema, ctx.formats)) {
|
|
326
|
+
const format = propSchema.format;
|
|
327
|
+
const family = formatFamily(format);
|
|
328
|
+
if (family !== void 0) {
|
|
329
|
+
lines.push(` if (typeof ${raw} === '${family}' && !${formatCheckName(format)}(${raw})) {`);
|
|
330
|
+
lines.push(` ${pushError(ctx.sink, JSON.stringify(`must match format "${format}"`), path, "format", JSON.stringify({ format }))}`);
|
|
331
|
+
lines.push(` }`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
321
334
|
if (hasPattern(propSchema) || hasMinLength(propSchema) || hasMaxLength(propSchema)) {
|
|
322
335
|
if (hasPattern(propSchema)) {
|
|
323
336
|
const re = regexLiteral(propSchema.pattern);
|
|
324
337
|
const msg = JSON.stringify(`must match pattern ${propSchema.pattern}`);
|
|
325
338
|
lines.push(` if (typeof ${raw} === 'string' && !${re}.test(${raw})) {`);
|
|
326
|
-
lines.push(` ${ctx.sink
|
|
339
|
+
lines.push(` ${pushError(ctx.sink, msg, path, "pattern", JSON.stringify({ pattern: propSchema.pattern }))}`);
|
|
327
340
|
lines.push(` }`);
|
|
328
341
|
}
|
|
329
342
|
if (hasMinLength(propSchema) && propSchema.minLength > 0) {
|
|
330
343
|
lines.push(` if (typeof ${raw} === 'string' && ${minLengthFailExpr(raw, propSchema.minLength)}) {`);
|
|
331
|
-
lines.push(` ${ctx.sink
|
|
344
|
+
lines.push(` ${pushError(ctx.sink, `'must have at least ${propSchema.minLength} characters'`, path, "minLength", JSON.stringify({ limit: propSchema.minLength }))}`);
|
|
332
345
|
lines.push(` }`);
|
|
333
346
|
}
|
|
334
347
|
if (hasMaxLength(propSchema)) {
|
|
335
348
|
lines.push(` if (typeof ${raw} === 'string' && ${maxLengthFailExpr(raw, propSchema.maxLength)}) {`);
|
|
336
|
-
lines.push(` ${ctx.sink
|
|
349
|
+
lines.push(` ${pushError(ctx.sink, `'must have at most ${propSchema.maxLength} characters'`, path, "maxLength", JSON.stringify({ limit: propSchema.maxLength }))}`);
|
|
337
350
|
lines.push(` }`);
|
|
338
351
|
}
|
|
339
352
|
}
|
|
@@ -341,28 +354,28 @@ const generateConstraintChecks = (key, raw, path, propSchema, suffix, ctx) => {
|
|
|
341
354
|
if (hasMinimum(propSchema)) {
|
|
342
355
|
const strict = hasStrictExclusiveMinimum(propSchema);
|
|
343
356
|
lines.push(` if (typeof ${raw} === 'number' && ${boundFailExpr(raw, "minimum", propSchema.minimum, strict)}) {`);
|
|
344
|
-
lines.push(` ${ctx.sink
|
|
357
|
+
lines.push(` ${pushError(ctx.sink, `'must be ${boundOperator("minimum", strict)} ${propSchema.minimum}'`, path, strict ? "exclusiveMinimum" : "minimum", JSON.stringify({ comparison: boundOperator("minimum", strict), limit: propSchema.minimum }))}`);
|
|
345
358
|
lines.push(` }`);
|
|
346
359
|
}
|
|
347
360
|
if (hasMaximum(propSchema)) {
|
|
348
361
|
const strict = hasStrictExclusiveMaximum(propSchema);
|
|
349
362
|
lines.push(` if (typeof ${raw} === 'number' && ${boundFailExpr(raw, "maximum", propSchema.maximum, strict)}) {`);
|
|
350
|
-
lines.push(` ${ctx.sink
|
|
363
|
+
lines.push(` ${pushError(ctx.sink, `'must be ${boundOperator("maximum", strict)} ${propSchema.maximum}'`, path, strict ? "exclusiveMaximum" : "maximum", JSON.stringify({ comparison: boundOperator("maximum", strict), limit: propSchema.maximum }))}`);
|
|
351
364
|
lines.push(` }`);
|
|
352
365
|
}
|
|
353
366
|
if (hasExclusiveMinimum(propSchema)) {
|
|
354
367
|
lines.push(` if (typeof ${raw} === 'number' && ${boundFailExpr(raw, "minimum", propSchema.exclusiveMinimum, true)}) {`);
|
|
355
|
-
lines.push(` ${ctx.sink
|
|
368
|
+
lines.push(` ${pushError(ctx.sink, `'must be > ${propSchema.exclusiveMinimum}'`, path, "exclusiveMinimum", JSON.stringify({ comparison: ">", limit: propSchema.exclusiveMinimum }))}`);
|
|
356
369
|
lines.push(` }`);
|
|
357
370
|
}
|
|
358
371
|
if (hasExclusiveMaximum(propSchema)) {
|
|
359
372
|
lines.push(` if (typeof ${raw} === 'number' && ${boundFailExpr(raw, "maximum", propSchema.exclusiveMaximum, true)}) {`);
|
|
360
|
-
lines.push(` ${ctx.sink
|
|
373
|
+
lines.push(` ${pushError(ctx.sink, `'must be < ${propSchema.exclusiveMaximum}'`, path, "exclusiveMaximum", JSON.stringify({ comparison: "<", limit: propSchema.exclusiveMaximum }))}`);
|
|
361
374
|
lines.push(` }`);
|
|
362
375
|
}
|
|
363
376
|
if (hasMultipleOf(propSchema)) {
|
|
364
377
|
lines.push(` if (typeof ${raw} === 'number' && ${multipleOfFailExpr(raw, propSchema.multipleOf)}) {`);
|
|
365
|
-
lines.push(` ${ctx.sink
|
|
378
|
+
lines.push(` ${pushError(ctx.sink, `'must be a multiple of ${propSchema.multipleOf}'`, path, "multipleOf", JSON.stringify({ multipleOf: propSchema.multipleOf }))}`);
|
|
366
379
|
lines.push(` }`);
|
|
367
380
|
}
|
|
368
381
|
}
|
|
@@ -397,23 +410,23 @@ const generateConstraintChecks = (key, raw, path, propSchema, suffix, ctx) => {
|
|
|
397
410
|
if (hasMinItems(propSchema) || hasMaxItems(propSchema) || hasUniqueItems(propSchema) && propSchema.uniqueItems === true || declaresKey(sp, "contains") || tuple !== void 0 || tail === false && tuple === void 0) {
|
|
398
411
|
if (tail === false && tuple === void 0) {
|
|
399
412
|
lines.push(` if (Array.isArray(${raw}) && ${raw}.length > 0) {`);
|
|
400
|
-
lines.push(` ${ctx.sink
|
|
413
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT have more than 0 items'`, path, "items", "{ limit: 0 }")}`);
|
|
401
414
|
lines.push(` }`);
|
|
402
415
|
}
|
|
403
416
|
if (hasMinItems(propSchema)) {
|
|
404
417
|
lines.push(` if (Array.isArray(${raw}) && ${raw}.length < ${propSchema.minItems}) {`);
|
|
405
|
-
lines.push(` ${ctx.sink
|
|
418
|
+
lines.push(` ${pushError(ctx.sink, `'must have at least ${propSchema.minItems} items'`, path, "minItems", JSON.stringify({ limit: propSchema.minItems }))}`);
|
|
406
419
|
lines.push(` }`);
|
|
407
420
|
}
|
|
408
421
|
if (hasMaxItems(propSchema)) {
|
|
409
422
|
lines.push(` if (Array.isArray(${raw}) && ${raw}.length > ${propSchema.maxItems}) {`);
|
|
410
|
-
lines.push(` ${ctx.sink
|
|
423
|
+
lines.push(` ${pushError(ctx.sink, `'must have at most ${propSchema.maxItems} items'`, path, "maxItems", JSON.stringify({ limit: propSchema.maxItems }))}`);
|
|
411
424
|
lines.push(` }`);
|
|
412
425
|
}
|
|
413
426
|
if (hasUniqueItems(propSchema) && propSchema.uniqueItems === true) {
|
|
414
427
|
const dupCond = arrayItemsAreScalarOnly(sp) ? `new Set(${raw} as unknown[]).size !== ${raw}.length` : `!allUnique(${raw} as unknown[])`;
|
|
415
428
|
lines.push(` if (Array.isArray(${raw}) && ${dupCond}) {`);
|
|
416
|
-
lines.push(` ${ctx.sink
|
|
429
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT have duplicate items'`, path, "uniqueItems")}`);
|
|
417
430
|
lines.push(` }`);
|
|
418
431
|
}
|
|
419
432
|
if (declaresKey(sp, "contains")) {
|
|
@@ -423,7 +436,7 @@ const generateConstraintChecks = (key, raw, path, propSchema, suffix, ctx) => {
|
|
|
423
436
|
const max = typeof declaredMax === "number" ? declaredMax : void 0;
|
|
424
437
|
if (min > 0 || max !== void 0) {
|
|
425
438
|
const matchExpr = generateMatchesExpr("_c", readKey(sp, "contains"), suffix, ctx, true);
|
|
426
|
-
const report =
|
|
439
|
+
const report = pushError(ctx.sink, `'array does not contain the required matching items'`, path, "contains");
|
|
427
440
|
if (matchExpr === "true") {
|
|
428
441
|
const bound = max !== void 0 ? `${raw}.length < ${min} || ${raw}.length > ${max}` : `${raw}.length < ${min}`;
|
|
429
442
|
lines.push(` if (Array.isArray(${raw}) && (${bound})) {`);
|
|
@@ -465,7 +478,7 @@ const generateConstraintChecks = (key, raw, path, propSchema, suffix, ctx) => {
|
|
|
465
478
|
}
|
|
466
479
|
if (tailIsClosed) {
|
|
467
480
|
lines.push(` if (${raw}.length > ${tuple.length}) {`);
|
|
468
|
-
lines.push(` ${ctx.sink
|
|
481
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT have more than ${tuple.length} items'`, path, "items", JSON.stringify({ limit: tuple.length }))}`);
|
|
469
482
|
lines.push(` }`);
|
|
470
483
|
}
|
|
471
484
|
lines.push(` }`);
|
|
@@ -485,7 +498,7 @@ const generateValueChecks = (key, raw, path, propSchema, suffix, ctx, required =
|
|
|
485
498
|
const generateValueCheckLines = (_key, raw, path, propSchema, suffix, ctx, required = false) => {
|
|
486
499
|
const lines = [];
|
|
487
500
|
if (propSchema === false) {
|
|
488
|
-
const report =
|
|
501
|
+
const report = pushError(ctx.sink, JSON.stringify(FALSE_SCHEMA_MESSAGE), path, "false schema");
|
|
489
502
|
if (required)
|
|
490
503
|
return [` {`, ` ${report}`, ` }`];
|
|
491
504
|
return [` if (${raw} !== undefined) {`, ` ${report}`, ` }`];
|
|
@@ -499,7 +512,8 @@ const generateValueCheckLines = (_key, raw, path, propSchema, suffix, ctx, requi
|
|
|
499
512
|
depth: ctx.depth + 1,
|
|
500
513
|
hoisted: ctx.hoisted,
|
|
501
514
|
rootSchema: ctx.rootSchema,
|
|
502
|
-
sink: ctx.sink
|
|
515
|
+
sink: ctx.sink,
|
|
516
|
+
formats: ctx.formats
|
|
503
517
|
};
|
|
504
518
|
lines.push(...generateKeywordChecks("", raw, path, propSchema, suffix, valueCtx, presence));
|
|
505
519
|
return lines;
|
|
@@ -548,7 +562,7 @@ const generateUnevaluatedChecks = (raw, path, schema, suffix, ctx) => {
|
|
|
548
562
|
for (const statement of properties.setup)
|
|
549
563
|
lines.push(` ${statement}`);
|
|
550
564
|
lines.push(` if (!(${properties.expr})) {`);
|
|
551
|
-
lines.push(` ${ctx.sink
|
|
565
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT have unevaluated properties'`, path, "unevaluatedProperties")}`);
|
|
552
566
|
lines.push(` }`);
|
|
553
567
|
lines.push(` }`);
|
|
554
568
|
}
|
|
@@ -560,7 +574,7 @@ const generateUnevaluatedChecks = (raw, path, schema, suffix, ctx) => {
|
|
|
560
574
|
for (const statement of items.setup)
|
|
561
575
|
lines.push(` ${statement}`);
|
|
562
576
|
lines.push(` if (!(${items.expr})) {`);
|
|
563
|
-
lines.push(` ${ctx.sink
|
|
577
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT have unevaluated items'`, path, "unevaluatedItems")}`);
|
|
564
578
|
lines.push(` }`);
|
|
565
579
|
lines.push(` }`);
|
|
566
580
|
}
|
|
@@ -578,14 +592,14 @@ const generateCombinatorChecks = (key, raw, path, schema, suffix, ctx) => {
|
|
|
578
592
|
const conds = schema.anyOf.map((b) => generateMatchesExpr(raw, b, suffix, ctx, true));
|
|
579
593
|
if (!conds.includes("true")) {
|
|
580
594
|
lines.push(` if (!(${conds.join(" || ")})) {`);
|
|
581
|
-
lines.push(` ${ctx.sink
|
|
595
|
+
lines.push(` ${pushError(ctx.sink, `'must match a schema in anyOf'`, path, "anyOf")}`);
|
|
582
596
|
lines.push(` }`);
|
|
583
597
|
}
|
|
584
598
|
}
|
|
585
599
|
if (hasOneOf(schema) && schema.oneOf.length > 0) {
|
|
586
600
|
const conds = schema.oneOf.map((b) => `(${generateMatchesExpr(raw, b, suffix, ctx, true)} ? 1 : 0)`);
|
|
587
601
|
lines.push(` if ((${conds.join(" + ")}) !== 1) {`);
|
|
588
|
-
lines.push(` ${ctx.sink
|
|
602
|
+
lines.push(` ${pushError(ctx.sink, `'must match exactly one schema in oneOf'`, path, "oneOf")}`);
|
|
589
603
|
lines.push(` }`);
|
|
590
604
|
}
|
|
591
605
|
const not = readKey(schema, "not");
|
|
@@ -593,7 +607,7 @@ const generateCombinatorChecks = (key, raw, path, schema, suffix, ctx) => {
|
|
|
593
607
|
const cond = generateMatchesExpr(raw, not, suffix, ctx, true);
|
|
594
608
|
if (cond !== "false") {
|
|
595
609
|
lines.push(` if (${cond}) {`);
|
|
596
|
-
lines.push(` ${ctx.sink
|
|
610
|
+
lines.push(` ${pushError(ctx.sink, `'must NOT match the schema in not'`, path, "not")}`);
|
|
597
611
|
lines.push(` }`);
|
|
598
612
|
}
|
|
599
613
|
}
|
|
@@ -680,7 +694,8 @@ const generateInlineObjectChecks = (key, propSchema, raw, suffix, ctx) => {
|
|
|
680
694
|
depth: ctx.depth + 1,
|
|
681
695
|
hoisted: ctx.hoisted,
|
|
682
696
|
rootSchema: ctx.rootSchema,
|
|
683
|
-
sink: ctx.sink
|
|
697
|
+
sink: ctx.sink,
|
|
698
|
+
formats: ctx.formats
|
|
684
699
|
};
|
|
685
700
|
const required = new Set(hasRequired(propSchema) ? propSchema.required : []);
|
|
686
701
|
const properties = hasProperties(propSchema) ? propSchema.properties : {};
|
|
@@ -715,7 +730,8 @@ const generatePropertyNameChecks = (nameSchema, suffix, ctx) => {
|
|
|
715
730
|
depth: ctx.depth + 1,
|
|
716
731
|
hoisted: ctx.hoisted,
|
|
717
732
|
rootSchema: ctx.rootSchema,
|
|
718
|
-
sink: ctx.sink
|
|
733
|
+
sink: ctx.sink,
|
|
734
|
+
formats: ctx.formats
|
|
719
735
|
};
|
|
720
736
|
const checks = generateValueChecks("", "_name", at, nameSchema, suffix, nameCtx, true);
|
|
721
737
|
if (checks.length === 0)
|
|
@@ -734,7 +750,7 @@ const generateDependentRequiredChecks = (schema, ctx) => {
|
|
|
734
750
|
for (const dep of deps) {
|
|
735
751
|
const msg = JSON.stringify(`must have property '${dep}' when '${trigger}' is present`);
|
|
736
752
|
lines.push(` if (${hasOwnCheck(obj, trigger)} && ${missingCheck(obj, dep)}) {`);
|
|
737
|
-
lines.push(` ${ctx.sink
|
|
753
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "dependentRequired", JSON.stringify({ missingProperty: dep, property: trigger, depsCount: 1 }))}`);
|
|
738
754
|
lines.push(` }`);
|
|
739
755
|
}
|
|
740
756
|
}
|
|
@@ -760,7 +776,7 @@ const generateDependentSchemasChecks = (schema, suffix, ctx) => {
|
|
|
760
776
|
if (sub === false) {
|
|
761
777
|
const msg = JSON.stringify(`must NOT have property '${trigger}'`);
|
|
762
778
|
lines.push(` if (${hasOwnCheck(obj, trigger)}) {`);
|
|
763
|
-
lines.push(` ${ctx.sink
|
|
779
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "dependentSchemas", JSON.stringify({ property: trigger }))}`);
|
|
764
780
|
lines.push(` }`);
|
|
765
781
|
continue;
|
|
766
782
|
}
|
|
@@ -794,7 +810,7 @@ const generateDependenciesChecks = (schema, suffix, ctx) => {
|
|
|
794
810
|
continue;
|
|
795
811
|
const msg = JSON.stringify(`must have property '${key}' when '${trigger}' is present`);
|
|
796
812
|
lines.push(` if (${hasOwnCheck(obj, trigger)} && ${missingCheck(obj, key)}) {`);
|
|
797
|
-
lines.push(` ${ctx.sink
|
|
813
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "dependencies", JSON.stringify({ missingProperty: key, property: trigger, depsCount: 1 }))}`);
|
|
798
814
|
lines.push(` }`);
|
|
799
815
|
}
|
|
800
816
|
continue;
|
|
@@ -804,7 +820,7 @@ const generateDependenciesChecks = (schema, suffix, ctx) => {
|
|
|
804
820
|
if (value === false) {
|
|
805
821
|
const msg = JSON.stringify(`must NOT have property '${trigger}'`);
|
|
806
822
|
lines.push(` if (${hasOwnCheck(obj, trigger)}) {`);
|
|
807
|
-
lines.push(` ${ctx.sink
|
|
823
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "dependencies", JSON.stringify({ property: trigger }))}`);
|
|
808
824
|
lines.push(` }`);
|
|
809
825
|
continue;
|
|
810
826
|
}
|
|
@@ -835,13 +851,13 @@ const generateMinMaxPropertiesChecks = (schema, ctx) => {
|
|
|
835
851
|
if (hasMin) {
|
|
836
852
|
const msg = JSON.stringify(`must have at least ${schema.minProperties} properties`);
|
|
837
853
|
lines.push(` if (${count} < ${schema.minProperties}) {`);
|
|
838
|
-
lines.push(` ${ctx.sink
|
|
854
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "minProperties", JSON.stringify({ limit: schema.minProperties }))}`);
|
|
839
855
|
lines.push(` }`);
|
|
840
856
|
}
|
|
841
857
|
if (hasMax) {
|
|
842
858
|
const msg = JSON.stringify(`must have at most ${schema.maxProperties} properties`);
|
|
843
859
|
lines.push(` if (${count} > ${schema.maxProperties}) {`);
|
|
844
|
-
lines.push(` ${ctx.sink
|
|
860
|
+
lines.push(` ${pushError(ctx.sink, msg, at, "maxProperties", JSON.stringify({ limit: schema.maxProperties }))}`);
|
|
845
861
|
lines.push(` }`);
|
|
846
862
|
}
|
|
847
863
|
return lines;
|
|
@@ -857,7 +873,13 @@ const carriesUnevaluated = (schema) => {
|
|
|
857
873
|
const s = schema;
|
|
858
874
|
return declaresKey(s, "unevaluatedProperties") && s["unevaluatedProperties"] !== true || declaresKey(s, "unevaluatedItems") && s["unevaluatedItems"] !== true;
|
|
859
875
|
};
|
|
860
|
-
const createGuardContext = (unknownKeys) => ({ unknownKeys, locals: 0, loops: 0 });
|
|
876
|
+
const createGuardContext = (unknownKeys, formats = NO_FORMATS) => ({ unknownKeys, formats, locals: 0, loops: 0 });
|
|
877
|
+
const guardFormatPass = (schema, acc, ctx) => {
|
|
878
|
+
if (!enforcesFormat(schema, ctx.formats))
|
|
879
|
+
return null;
|
|
880
|
+
const format = schema.format;
|
|
881
|
+
return formatFamily(format) === void 0 ? null : `${formatCheckName(format)}(${acc})`;
|
|
882
|
+
};
|
|
861
883
|
const emptyGuardBlock = () => ({ conditions: [], nested: [], keyChecks: [] });
|
|
862
884
|
const isFlatGuardBlock = (block) => block.nested.length === 0 && block.keyChecks.length === 0;
|
|
863
885
|
const keySetCheckLines = (check, bail, indent, unknownKeys) => {
|
|
@@ -996,11 +1018,11 @@ const guardObjectConditions = (schema, raw, objAcc, ctx) => {
|
|
|
996
1018
|
}
|
|
997
1019
|
return block;
|
|
998
1020
|
};
|
|
999
|
-
const generateObjectValidator = (schema, typeName, suffix, rootSchema, unknownKeys) => {
|
|
1021
|
+
const generateObjectValidator = (schema, typeName, suffix, rootSchema, unknownKeys, formats) => {
|
|
1000
1022
|
const vName = validatorName(typeName);
|
|
1001
1023
|
const required = new Set(hasRequired(schema) ? schema.required : []);
|
|
1002
1024
|
const properties = hasProperties(schema) ? schema.properties : {};
|
|
1003
|
-
const ctx = createRootContext(rootSchema);
|
|
1025
|
+
const ctx = createRootContext(rootSchema, formats);
|
|
1004
1026
|
const propertyLines = [];
|
|
1005
1027
|
for (const [key, propSchema] of Object.entries(properties)) {
|
|
1006
1028
|
const checks = generatePropertyChecks(key, propSchema, required.has(key), suffix, ctx);
|
|
@@ -1025,13 +1047,13 @@ const generateObjectValidator = (schema, typeName, suffix, rootSchema, unknownKe
|
|
|
1025
1047
|
propertyLines.push(...objectCombinators);
|
|
1026
1048
|
}
|
|
1027
1049
|
const body = propertyLines.length > 0 ? "\n" + propertyLines.join("\n") + "\n" : "";
|
|
1028
|
-
const guard = guardObjectConditions(schema, "input", "obj", createGuardContext(unknownKeys));
|
|
1050
|
+
const guard = guardObjectConditions(schema, "input", "obj", createGuardContext(unknownKeys, formats));
|
|
1029
1051
|
const objBinding = readsObjBinding(body) ? [` const obj = input as Record<string, unknown>`] : [];
|
|
1030
1052
|
const collectBody = (name, exported) => [
|
|
1031
1053
|
`${exported ? "export " : ""}const ${name} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1032
1054
|
...objBinding,
|
|
1033
1055
|
` if (typeof input !== 'object' || input === null || Array.isArray(input)) {`,
|
|
1034
|
-
`
|
|
1056
|
+
` ${returnError(`'must be object'`, "_path", "type", JSON.stringify({ type: "object" }))}`,
|
|
1035
1057
|
` }`,
|
|
1036
1058
|
``,
|
|
1037
1059
|
` let errors: ValidationError[] | undefined`,
|
|
@@ -1095,7 +1117,7 @@ const booleanLeafExpr = (schema, acc, ctx) => {
|
|
|
1095
1117
|
if (!hasType(schema)) {
|
|
1096
1118
|
if (!hasEnum(schema))
|
|
1097
1119
|
return null;
|
|
1098
|
-
if (declaresKeywordOutside(schema, ["enum"]))
|
|
1120
|
+
if (declaresKeywordOutside(schema, ["enum"], ctx.formats))
|
|
1099
1121
|
return null;
|
|
1100
1122
|
return enumMembershipExpr(schema.enum, acc);
|
|
1101
1123
|
}
|
|
@@ -1116,6 +1138,9 @@ const booleanLeafExpr = (schema, acc, ctx) => {
|
|
|
1116
1138
|
// spellings of `(obj.a as Record<string, unknown>).b`.
|
|
1117
1139
|
case "string": {
|
|
1118
1140
|
const parts = [`typeof ${acc} === 'string'`];
|
|
1141
|
+
const formatPass = guardFormatPass(schema, acc, ctx);
|
|
1142
|
+
if (formatPass !== null)
|
|
1143
|
+
parts.push(formatPass);
|
|
1119
1144
|
if (hasPattern(schema))
|
|
1120
1145
|
parts.push(`${regexLiteral(schema.pattern)}.test(${acc})`);
|
|
1121
1146
|
if (hasMinLength(schema))
|
|
@@ -1129,6 +1154,9 @@ const booleanLeafExpr = (schema, acc, ctx) => {
|
|
|
1129
1154
|
const parts = [`typeof ${acc} === 'number'`];
|
|
1130
1155
|
if (t === "integer")
|
|
1131
1156
|
parts.push(`Number.isInteger(${acc})`);
|
|
1157
|
+
const formatPass = guardFormatPass(schema, acc, ctx);
|
|
1158
|
+
if (formatPass !== null)
|
|
1159
|
+
parts.push(formatPass);
|
|
1132
1160
|
if (hasMinimum(schema))
|
|
1133
1161
|
parts.push(boundPassExpr(acc, "minimum", schema.minimum, hasStrictExclusiveMinimum(schema)));
|
|
1134
1162
|
if (hasMaximum(schema))
|
|
@@ -1266,12 +1294,12 @@ const typeDescribesEveryAcceptedValue = (schema) => {
|
|
|
1266
1294
|
}
|
|
1267
1295
|
return !IMPLICIT_OBJECT_KEYWORDS.some((keyword) => declaresKey(s, keyword));
|
|
1268
1296
|
};
|
|
1269
|
-
const generateBooleanGuard = (schema, typeName, _suffix = "", unknownKeys = DEFAULT_UNKNOWN_KEYS) => {
|
|
1297
|
+
const generateBooleanGuard = (schema, typeName, _suffix = "", unknownKeys = DEFAULT_UNKNOWN_KEYS, formats = NO_FORMATS) => {
|
|
1270
1298
|
const name = guardName(typeName);
|
|
1271
1299
|
const returns = typeDescribesEveryAcceptedValue(rewriteNullable(schema)) ? `input is ${typeName}` : "boolean";
|
|
1272
1300
|
const fallback = `export const ${name} = (input: unknown): ${returns} => ${validatorName(typeName)}(input) === true`;
|
|
1273
1301
|
const rewritten = rewriteNullable(schema);
|
|
1274
|
-
const ctx = createGuardContext(unknownKeys);
|
|
1302
|
+
const ctx = createGuardContext(unknownKeys, formats);
|
|
1275
1303
|
if (declaresObjectType(rewritten)) {
|
|
1276
1304
|
if (!objectRootIsSelfContained(rewritten))
|
|
1277
1305
|
return fallback;
|
|
@@ -1293,19 +1321,19 @@ const generateBooleanGuard = (schema, typeName, _suffix = "", unknownKeys = DEFA
|
|
|
1293
1321
|
return fallback;
|
|
1294
1322
|
return `export const ${name} = (input: unknown): ${returns} => ${expr}`;
|
|
1295
1323
|
};
|
|
1296
|
-
const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
1324
|
+
const generateScalarValidator = (schema, typeName, suffix, rootSchema, formats) => {
|
|
1297
1325
|
const vName = validatorName(typeName);
|
|
1298
1326
|
if (!isSchemaObject(schema)) {
|
|
1299
1327
|
if (schema === false) {
|
|
1300
1328
|
return [
|
|
1301
1329
|
`export const ${vName} = (_input: unknown, _path = ''): ValidationResult => {`,
|
|
1302
|
-
`
|
|
1330
|
+
` ${returnError(JSON.stringify(FALSE_SCHEMA_MESSAGE), "_path", "false schema")}`,
|
|
1303
1331
|
`}`
|
|
1304
1332
|
].join("\n");
|
|
1305
1333
|
}
|
|
1306
1334
|
return [`export const ${vName} = (_input: unknown, _path = ''): ValidationResult => {`, ` return true`, `}`].join("\n");
|
|
1307
1335
|
}
|
|
1308
|
-
const generalRoot = () => generateGeneralRootValidator(schema, typeName, suffix, rootSchema);
|
|
1336
|
+
const generalRoot = () => generateGeneralRootValidator(schema, typeName, suffix, rootSchema, formats);
|
|
1309
1337
|
if (hasRef(schema)) {
|
|
1310
1338
|
if (declaresKeywordOutside(schema, ["$ref"]))
|
|
1311
1339
|
return generalRoot();
|
|
@@ -1323,7 +1351,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1323
1351
|
return [
|
|
1324
1352
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1325
1353
|
` if (!(input instanceof ${instanceOf})) {`,
|
|
1326
|
-
`
|
|
1354
|
+
` ${returnError(`'must be ${instanceOf}'`, "_path", "type", JSON.stringify({ type: instanceOf }))}`,
|
|
1327
1355
|
` }`,
|
|
1328
1356
|
` return true`,
|
|
1329
1357
|
`}`
|
|
@@ -1336,7 +1364,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1336
1364
|
return [
|
|
1337
1365
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1338
1366
|
` if (typeof input !== "${primitive}") {`,
|
|
1339
|
-
`
|
|
1367
|
+
` ${returnError(`'must be ${primitive}'`, "_path", "type", JSON.stringify({ type: primitive }))}`,
|
|
1340
1368
|
` }`,
|
|
1341
1369
|
` return true`,
|
|
1342
1370
|
`}`
|
|
@@ -1350,7 +1378,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1350
1378
|
return [
|
|
1351
1379
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1352
1380
|
` if (${mismatch}) {`,
|
|
1353
|
-
`
|
|
1381
|
+
` ${returnError(msg, "_path", "const", JSON.stringify({ allowedValue: schema.const }))}`,
|
|
1354
1382
|
` }`,
|
|
1355
1383
|
` return true`,
|
|
1356
1384
|
`}`
|
|
@@ -1363,14 +1391,14 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1363
1391
|
return [
|
|
1364
1392
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1365
1393
|
` if (!${enumMembershipExpr(schema.enum, "input")}) {`,
|
|
1366
|
-
`
|
|
1394
|
+
` ${returnError(JSON.stringify(`must be one of: ${label}`), "_path", "enum", JSON.stringify({ allowedValues: schema.enum }))}`,
|
|
1367
1395
|
` }`,
|
|
1368
1396
|
` return true`,
|
|
1369
1397
|
`}`
|
|
1370
1398
|
].join("\n");
|
|
1371
1399
|
}
|
|
1372
1400
|
if (hasAllOf(schema) || hasAnyOf(schema) || hasOneOf(schema) || declaresKey(schema, "not") || declaresKey(schema, "if")) {
|
|
1373
|
-
const ctx = createRootContext(rootSchema);
|
|
1401
|
+
const ctx = createRootContext(rootSchema, formats);
|
|
1374
1402
|
const checks = [];
|
|
1375
1403
|
const rootPath = "`${_path}`";
|
|
1376
1404
|
const rootTypeArray2 = getTypeArray(schema);
|
|
@@ -1379,7 +1407,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1379
1407
|
if (allWrong) {
|
|
1380
1408
|
const label = rootTypeArray2.map((t) => typeofString(t)).join(" or ");
|
|
1381
1409
|
checks.push(` if (${allWrong}) {`);
|
|
1382
|
-
checks.push(` ${ctx.sink
|
|
1410
|
+
checks.push(` ${pushError(ctx.sink, JSON.stringify(`must be ${label}`), rootPath, "type", JSON.stringify({ type: schema.type }))}`);
|
|
1383
1411
|
checks.push(` }`);
|
|
1384
1412
|
}
|
|
1385
1413
|
} else if (hasType(schema)) {
|
|
@@ -1387,7 +1415,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1387
1415
|
const wrongType = wrongTypeCondition("input", t);
|
|
1388
1416
|
if (wrongType) {
|
|
1389
1417
|
checks.push(` if (${wrongType}) {`);
|
|
1390
|
-
checks.push(` ${ctx.sink
|
|
1418
|
+
checks.push(` ${pushError(ctx.sink, `'must be ${typeofString(t)}'`, rootPath, "type", JSON.stringify({ type: t }))}`);
|
|
1391
1419
|
checks.push(` }`);
|
|
1392
1420
|
}
|
|
1393
1421
|
}
|
|
@@ -1404,14 +1432,14 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1404
1432
|
}
|
|
1405
1433
|
const rootTypeArray = getTypeArray(schema);
|
|
1406
1434
|
if (rootTypeArray) {
|
|
1407
|
-
const ctx = createRootContext(rootSchema);
|
|
1435
|
+
const ctx = createRootContext(rootSchema, formats);
|
|
1408
1436
|
const rootPath = "`${_path}`";
|
|
1409
1437
|
const checks = [];
|
|
1410
1438
|
const allWrong = rootTypeArray.map((t) => wrongTypeCondition("input", t)).filter((c) => c !== "").map((c) => `(${c})`).join(" && ");
|
|
1411
1439
|
if (allWrong) {
|
|
1412
1440
|
const label = rootTypeArray.map((t) => typeofString(t)).join(" or ");
|
|
1413
1441
|
checks.push(` if (${allWrong}) {`);
|
|
1414
|
-
checks.push(` ${ctx.sink
|
|
1442
|
+
checks.push(` ${pushError(ctx.sink, JSON.stringify(`must be ${label}`), rootPath, "type", JSON.stringify({ type: schema.type }))}`);
|
|
1415
1443
|
checks.push(` }`);
|
|
1416
1444
|
}
|
|
1417
1445
|
checks.push(...generateConstraintChecks("", "input", rootPath, schema, suffix, ctx));
|
|
@@ -1435,7 +1463,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1435
1463
|
const t = schema.type;
|
|
1436
1464
|
const wrongType = wrongTypeCondition("input", t);
|
|
1437
1465
|
const typLabel = typeofString(t);
|
|
1438
|
-
const rootCtx = createRootContext(rootSchema);
|
|
1466
|
+
const rootCtx = createRootContext(rootSchema, formats);
|
|
1439
1467
|
const constraintLines = generateConstraintChecks("", "_root", "`${_path}`", schema, suffix, rootCtx);
|
|
1440
1468
|
if (!wrongType) {
|
|
1441
1469
|
return [
|
|
@@ -1448,7 +1476,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1448
1476
|
return [
|
|
1449
1477
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1450
1478
|
` if (${wrongType}) {`,
|
|
1451
|
-
`
|
|
1479
|
+
` ${returnError(`'must be ${typLabel}'`, "_path", "type", JSON.stringify({ type: schema.type }))}`,
|
|
1452
1480
|
` }`,
|
|
1453
1481
|
` return true`,
|
|
1454
1482
|
`}`
|
|
@@ -1457,7 +1485,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1457
1485
|
return withHoisted(rootCtx.hoisted, [
|
|
1458
1486
|
`export const ${vName} = (input: unknown, _path = ''): ValidationResult => {`,
|
|
1459
1487
|
` if (${wrongType}) {`,
|
|
1460
|
-
`
|
|
1488
|
+
` ${returnError(`'must be ${typLabel}'`, "_path", "type", JSON.stringify({ type: schema.type }))}`,
|
|
1461
1489
|
` }`,
|
|
1462
1490
|
...readsBinding("_root", constraintLines.join("\n")) ? [` const _root: unknown = input`] : [],
|
|
1463
1491
|
` let errors: ValidationError[] | undefined`,
|
|
@@ -1466,7 +1494,7 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1466
1494
|
`}`
|
|
1467
1495
|
].join("\n"));
|
|
1468
1496
|
}
|
|
1469
|
-
const typelessCtx = createRootContext(rootSchema);
|
|
1497
|
+
const typelessCtx = createRootContext(rootSchema, formats);
|
|
1470
1498
|
const typelessChecks = generateConstraintChecks("", "input", "`${_path}`", schema, suffix, typelessCtx);
|
|
1471
1499
|
if (typelessChecks.length === 0) {
|
|
1472
1500
|
return [`export const ${vName} = (_input: unknown, _path = ''): ValidationResult => {`, ` return true`, `}`].join("\n");
|
|
@@ -1479,8 +1507,8 @@ const generateScalarValidator = (schema, typeName, suffix, rootSchema) => {
|
|
|
1479
1507
|
`}`
|
|
1480
1508
|
].join("\n"));
|
|
1481
1509
|
};
|
|
1482
|
-
const generateGeneralRootValidator = (schema, typeName, suffix, rootSchema) => {
|
|
1483
|
-
const ctx = createRootContext(rootSchema);
|
|
1510
|
+
const generateGeneralRootValidator = (schema, typeName, suffix, rootSchema, formats) => {
|
|
1511
|
+
const ctx = createRootContext(rootSchema, formats);
|
|
1484
1512
|
const checks = generateValueChecks("", "input", "`${_path}`", schema, suffix, ctx, true);
|
|
1485
1513
|
const body = checks.join("\n");
|
|
1486
1514
|
return withHoisted(ctx.hoisted, [
|
|
@@ -1546,18 +1574,18 @@ const rewriteNullable = (node) => {
|
|
|
1546
1574
|
return { anyOf: [{ type: "null" }, out] };
|
|
1547
1575
|
return out;
|
|
1548
1576
|
};
|
|
1549
|
-
const generateValidatorFunction = (schema, typeName, suffix = "", rootSchema, unknownKeys = DEFAULT_UNKNOWN_KEYS) => {
|
|
1577
|
+
const generateValidatorFunction = (schema, typeName, suffix = "", rootSchema, unknownKeys = DEFAULT_UNKNOWN_KEYS, formats = NO_FORMATS) => {
|
|
1550
1578
|
assertGeneratableRefs(schema, typeName);
|
|
1551
1579
|
const rewritten = rewriteNullable(schema);
|
|
1552
1580
|
const document = rootSchema ?? schema;
|
|
1553
|
-
assertUnevaluatedGeneratable(rewritten, typeName, document, unevaluatedMatcher(suffix, createRootContext(document)));
|
|
1581
|
+
assertUnevaluatedGeneratable(rewritten, typeName, document, unevaluatedMatcher(suffix, createRootContext(document, formats)));
|
|
1554
1582
|
if (carriesUnevaluated(rewritten)) {
|
|
1555
|
-
return generateGeneralRootValidator(rewritten, typeName, suffix, document);
|
|
1583
|
+
return generateGeneralRootValidator(rewritten, typeName, suffix, document, formats);
|
|
1556
1584
|
}
|
|
1557
1585
|
if (declaresObjectType(rewritten) && objectRootIsSelfContained(rewritten)) {
|
|
1558
|
-
return generateObjectValidator(rewritten, typeName, suffix, document, unknownKeys);
|
|
1586
|
+
return generateObjectValidator(rewritten, typeName, suffix, document, unknownKeys, formats);
|
|
1559
1587
|
}
|
|
1560
|
-
return generateScalarValidator(rewritten, typeName, suffix, document);
|
|
1588
|
+
return generateScalarValidator(rewritten, typeName, suffix, document, formats);
|
|
1561
1589
|
};
|
|
1562
1590
|
export {
|
|
1563
1591
|
generateBooleanGuard,
|