@naturalcycles/nodejs-lib 15.58.0 → 15.60.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/dist/validation/ajv/ajvSchema.d.ts +14 -4
- package/dist/validation/ajv/ajvSchema.js +3 -2
- package/dist/validation/ajv/jsonSchemaBuilder.d.ts +3 -1
- package/dist/validation/ajv/jsonSchemaBuilder.js +67 -89
- package/package.json +1 -1
- package/src/validation/ajv/ajvSchema.ts +17 -6
- package/src/validation/ajv/jsonSchemaBuilder.ts +77 -90
|
@@ -39,9 +39,9 @@ export declare class AjvSchema<IN = unknown, OUT = IN> {
|
|
|
39
39
|
*
|
|
40
40
|
* Returned object is always the same object (`===`) that was passed, so it is returned just for convenience.
|
|
41
41
|
*/
|
|
42
|
-
validate(input: IN, opt?: AjvValidationOptions): OUT;
|
|
43
|
-
isValid(input: IN, opt?: AjvValidationOptions): boolean;
|
|
44
|
-
getValidationResult(input: IN, opt?: AjvValidationOptions): ValidationFunctionResult<OUT, AjvValidationError>;
|
|
42
|
+
validate(input: IN, opt?: AjvValidationOptions<IN>): OUT;
|
|
43
|
+
isValid(input: IN, opt?: AjvValidationOptions<IN>): boolean;
|
|
44
|
+
getValidationResult(input: IN, opt?: AjvValidationOptions<IN>): ValidationFunctionResult<OUT, AjvValidationError>;
|
|
45
45
|
getValidationFunction(): ValidationFunction<IN, OUT, AjvValidationError>;
|
|
46
46
|
static isSchemaWithCachedAjvSchema<Base, IN, OUT>(schema: Base): schema is WithCachedAjvSchema<Base, IN, OUT>;
|
|
47
47
|
static cacheAjvSchema<Base extends AnyObject, IN, OUT>(schema: Base, ajvSchema: AjvSchema<IN, OUT>): WithCachedAjvSchema<Base, IN, OUT>;
|
|
@@ -54,7 +54,7 @@ export declare const HIDDEN_AJV_SCHEMA: unique symbol;
|
|
|
54
54
|
export type WithCachedAjvSchema<Base, IN, OUT> = Base & {
|
|
55
55
|
[HIDDEN_AJV_SCHEMA]: AjvSchema<IN, OUT>;
|
|
56
56
|
};
|
|
57
|
-
export interface AjvValidationOptions {
|
|
57
|
+
export interface AjvValidationOptions<IN> {
|
|
58
58
|
/**
|
|
59
59
|
* Defaults to true,
|
|
60
60
|
* because that's how AJV works by default,
|
|
@@ -73,6 +73,16 @@ export interface AjvValidationOptions {
|
|
|
73
73
|
mutateInput?: boolean;
|
|
74
74
|
inputName?: string;
|
|
75
75
|
inputId?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Function that returns "original input".
|
|
78
|
+
* What is original input?
|
|
79
|
+
* It's an input in its original non-mutated form.
|
|
80
|
+
* Why is it needed?
|
|
81
|
+
* Because we mutates the Input here. And after its been mutated - we no longer
|
|
82
|
+
* can include it "how it was" in an error message. So, for that reason we'll use
|
|
83
|
+
* `getOriginalInput()`, if it's provided.
|
|
84
|
+
*/
|
|
85
|
+
getOriginalInput?: () => IN;
|
|
76
86
|
}
|
|
77
87
|
export interface AjvSchemaCfg {
|
|
78
88
|
/**
|
|
@@ -108,7 +108,7 @@ export class AjvSchema {
|
|
|
108
108
|
const item = opt.mutateInput !== false || typeof input !== 'object'
|
|
109
109
|
? input // mutate
|
|
110
110
|
: _deepCopy(input); // not mutate
|
|
111
|
-
const valid = fn(item); // mutates item
|
|
111
|
+
const valid = fn(item); // mutates item, but not input
|
|
112
112
|
_typeCast(item);
|
|
113
113
|
if (valid)
|
|
114
114
|
return [null, item];
|
|
@@ -122,7 +122,8 @@ export class AjvSchema {
|
|
|
122
122
|
});
|
|
123
123
|
// Note: if we mutated the input already, e.g stripped unknown properties,
|
|
124
124
|
// the error message Input would contain already mutated object print, such as Input: {}
|
|
125
|
-
|
|
125
|
+
// Unless `getOriginalInput` function is provided - then it will be used to preserve the Input pureness.
|
|
126
|
+
const inputStringified = _inspect(opt.getOriginalInput?.() || input, { maxLen: 4000 });
|
|
126
127
|
message = [message, 'Input: ' + inputStringified].join(separator);
|
|
127
128
|
const err = new AjvValidationError(message, _filterNullishValues({
|
|
128
129
|
errors,
|
|
@@ -62,12 +62,14 @@ export declare class JsonSchemaTerminal<IN, OUT, Opt> {
|
|
|
62
62
|
* Same as if it would be JSON.stringified.
|
|
63
63
|
*/
|
|
64
64
|
build(): JsonSchema<IN, OUT>;
|
|
65
|
-
clone():
|
|
65
|
+
clone(): this;
|
|
66
|
+
cloneAndUpdateSchema(schema: Partial<JsonSchema>): this;
|
|
66
67
|
/**
|
|
67
68
|
* @experimental
|
|
68
69
|
*/
|
|
69
70
|
in: IN;
|
|
70
71
|
out: OUT;
|
|
72
|
+
opt: Opt;
|
|
71
73
|
}
|
|
72
74
|
export declare class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTerminal<IN, OUT, Opt> {
|
|
73
75
|
protected setErrorMessage(ruleName: string, errorMessage: string | undefined): void;
|
|
@@ -147,13 +147,21 @@ export class JsonSchemaTerminal {
|
|
|
147
147
|
return jsonSchema;
|
|
148
148
|
}
|
|
149
149
|
clone() {
|
|
150
|
-
|
|
150
|
+
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
151
|
+
cloned.schema = _deepCopy(this.schema);
|
|
152
|
+
return cloned;
|
|
153
|
+
}
|
|
154
|
+
cloneAndUpdateSchema(schema) {
|
|
155
|
+
const clone = this.clone();
|
|
156
|
+
_objectAssign(clone.schema, schema);
|
|
157
|
+
return clone;
|
|
151
158
|
}
|
|
152
159
|
/**
|
|
153
160
|
* @experimental
|
|
154
161
|
*/
|
|
155
162
|
in;
|
|
156
163
|
out;
|
|
164
|
+
opt;
|
|
157
165
|
}
|
|
158
166
|
export class JsonSchemaAnyBuilder extends JsonSchemaTerminal {
|
|
159
167
|
setErrorMessage(ruleName, errorMessage) {
|
|
@@ -178,48 +186,38 @@ export class JsonSchemaAnyBuilder extends JsonSchemaTerminal {
|
|
|
178
186
|
* ```
|
|
179
187
|
*/
|
|
180
188
|
isOfType() {
|
|
181
|
-
|
|
182
|
-
return this;
|
|
189
|
+
return this.cloneAndUpdateSchema({ hasIsOfTypeCheck: true });
|
|
183
190
|
}
|
|
184
191
|
$schema($schema) {
|
|
185
|
-
|
|
186
|
-
return this;
|
|
192
|
+
return this.cloneAndUpdateSchema({ $schema });
|
|
187
193
|
}
|
|
188
194
|
$schemaDraft7() {
|
|
189
|
-
this.$schema('http://json-schema.org/draft-07/schema#');
|
|
190
|
-
return this;
|
|
195
|
+
return this.$schema('http://json-schema.org/draft-07/schema#');
|
|
191
196
|
}
|
|
192
197
|
$id($id) {
|
|
193
|
-
|
|
194
|
-
return this;
|
|
198
|
+
return this.cloneAndUpdateSchema({ $id });
|
|
195
199
|
}
|
|
196
200
|
title(title) {
|
|
197
|
-
|
|
198
|
-
return this;
|
|
201
|
+
return this.cloneAndUpdateSchema({ title });
|
|
199
202
|
}
|
|
200
203
|
description(description) {
|
|
201
|
-
|
|
202
|
-
return this;
|
|
204
|
+
return this.cloneAndUpdateSchema({ description });
|
|
203
205
|
}
|
|
204
206
|
deprecated(deprecated = true) {
|
|
205
|
-
|
|
206
|
-
return this;
|
|
207
|
+
return this.cloneAndUpdateSchema({ deprecated });
|
|
207
208
|
}
|
|
208
209
|
type(type) {
|
|
209
|
-
|
|
210
|
-
return this;
|
|
210
|
+
return this.cloneAndUpdateSchema({ type });
|
|
211
211
|
}
|
|
212
212
|
default(v) {
|
|
213
|
-
|
|
214
|
-
return this;
|
|
213
|
+
return this.cloneAndUpdateSchema({ default: v });
|
|
215
214
|
}
|
|
216
215
|
instanceof(of) {
|
|
217
|
-
|
|
218
|
-
return this;
|
|
216
|
+
return this.cloneAndUpdateSchema({ type: 'object', instanceof: of });
|
|
219
217
|
}
|
|
220
218
|
optional() {
|
|
221
|
-
this.
|
|
222
|
-
return
|
|
219
|
+
const clone = this.cloneAndUpdateSchema({ optionalField: true });
|
|
220
|
+
return clone;
|
|
223
221
|
}
|
|
224
222
|
nullable() {
|
|
225
223
|
return new JsonSchemaAnyBuilder({
|
|
@@ -268,20 +266,18 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
268
266
|
return this.pattern(pattern.source, opt);
|
|
269
267
|
}
|
|
270
268
|
pattern(pattern, opt) {
|
|
269
|
+
const clone = this.cloneAndUpdateSchema({ pattern });
|
|
271
270
|
if (opt?.name)
|
|
272
|
-
|
|
271
|
+
clone.setErrorMessage('pattern', `is not a valid ${opt.name}`);
|
|
273
272
|
if (opt?.msg)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return this;
|
|
273
|
+
clone.setErrorMessage('pattern', opt.msg);
|
|
274
|
+
return clone;
|
|
277
275
|
}
|
|
278
276
|
minLength(minLength) {
|
|
279
|
-
|
|
280
|
-
return this;
|
|
277
|
+
return this.cloneAndUpdateSchema({ minLength });
|
|
281
278
|
}
|
|
282
279
|
maxLength(maxLength) {
|
|
283
|
-
|
|
284
|
-
return this;
|
|
280
|
+
return this.cloneAndUpdateSchema({ maxLength });
|
|
285
281
|
}
|
|
286
282
|
length(minLengthOrExactLength, maxLength) {
|
|
287
283
|
const maxLengthActual = maxLength ?? minLengthOrExactLength;
|
|
@@ -289,24 +285,27 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
289
285
|
}
|
|
290
286
|
email(opt) {
|
|
291
287
|
const defaultOptions = { checkTLD: true };
|
|
292
|
-
|
|
293
|
-
|
|
288
|
+
return this.cloneAndUpdateSchema({ email: { ...defaultOptions, ...opt } })
|
|
289
|
+
.trim()
|
|
290
|
+
.toLowerCase();
|
|
294
291
|
}
|
|
295
292
|
trim() {
|
|
296
|
-
|
|
297
|
-
return this;
|
|
293
|
+
return this.cloneAndUpdateSchema({ transform: { ...this.schema.transform, trim: true } });
|
|
298
294
|
}
|
|
299
295
|
toLowerCase() {
|
|
300
|
-
|
|
301
|
-
|
|
296
|
+
return this.cloneAndUpdateSchema({
|
|
297
|
+
transform: { ...this.schema.transform, toLowerCase: true },
|
|
298
|
+
});
|
|
302
299
|
}
|
|
303
300
|
toUpperCase() {
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
return this.cloneAndUpdateSchema({
|
|
302
|
+
transform: { ...this.schema.transform, toUpperCase: true },
|
|
303
|
+
});
|
|
306
304
|
}
|
|
307
305
|
truncate(toLength) {
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
return this.cloneAndUpdateSchema({
|
|
307
|
+
transform: { ...this.schema.transform, truncate: toLength },
|
|
308
|
+
});
|
|
310
309
|
}
|
|
311
310
|
branded() {
|
|
312
311
|
return this;
|
|
@@ -318,12 +317,10 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
318
317
|
* because this call effectively starts a new schema chain.
|
|
319
318
|
*/
|
|
320
319
|
isoDate() {
|
|
321
|
-
_objectAssign(this.schema, { IsoDate: {} });
|
|
322
320
|
return new JsonSchemaIsoDateBuilder();
|
|
323
321
|
}
|
|
324
322
|
isoDateTime() {
|
|
325
|
-
|
|
326
|
-
return this.branded();
|
|
323
|
+
return this.cloneAndUpdateSchema({ IsoDateTime: true }).branded();
|
|
327
324
|
}
|
|
328
325
|
/**
|
|
329
326
|
* Validates the string format to be JWT.
|
|
@@ -385,29 +382,26 @@ export class JsonSchemaIsoDateBuilder extends JsonSchemaAnyBuilder {
|
|
|
385
382
|
});
|
|
386
383
|
}
|
|
387
384
|
before(date) {
|
|
388
|
-
|
|
389
|
-
return this;
|
|
385
|
+
return this.cloneAndUpdateSchema({ IsoDate: { before: date } });
|
|
390
386
|
}
|
|
391
387
|
sameOrBefore(date) {
|
|
392
|
-
|
|
393
|
-
return this;
|
|
388
|
+
return this.cloneAndUpdateSchema({ IsoDate: { sameOrBefore: date } });
|
|
394
389
|
}
|
|
395
390
|
after(date) {
|
|
396
|
-
|
|
397
|
-
return this;
|
|
391
|
+
return this.cloneAndUpdateSchema({ IsoDate: { after: date } });
|
|
398
392
|
}
|
|
399
393
|
sameOrAfter(date) {
|
|
400
|
-
|
|
401
|
-
return this;
|
|
394
|
+
return this.cloneAndUpdateSchema({ IsoDate: { sameOrAfter: date } });
|
|
402
395
|
}
|
|
403
396
|
between(fromDate, toDate, incl) {
|
|
397
|
+
let schemaPatch = {};
|
|
404
398
|
if (incl === '[)') {
|
|
405
|
-
|
|
399
|
+
schemaPatch = { IsoDate: { sameOrAfter: fromDate, before: toDate } };
|
|
406
400
|
}
|
|
407
401
|
else if (incl === '[]') {
|
|
408
|
-
|
|
402
|
+
schemaPatch = { IsoDate: { sameOrAfter: fromDate, sameOrBefore: toDate } };
|
|
409
403
|
}
|
|
410
|
-
return this;
|
|
404
|
+
return this.cloneAndUpdateSchema(schemaPatch);
|
|
411
405
|
}
|
|
412
406
|
}
|
|
413
407
|
export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
|
|
@@ -435,31 +429,25 @@ export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
|
|
|
435
429
|
return newBuilder;
|
|
436
430
|
}
|
|
437
431
|
integer() {
|
|
438
|
-
|
|
439
|
-
return this;
|
|
432
|
+
return this.cloneAndUpdateSchema({ type: 'integer' });
|
|
440
433
|
}
|
|
441
434
|
branded() {
|
|
442
435
|
return this;
|
|
443
436
|
}
|
|
444
437
|
multipleOf(multipleOf) {
|
|
445
|
-
|
|
446
|
-
return this;
|
|
438
|
+
return this.cloneAndUpdateSchema({ multipleOf });
|
|
447
439
|
}
|
|
448
440
|
min(minimum) {
|
|
449
|
-
|
|
450
|
-
return this;
|
|
441
|
+
return this.cloneAndUpdateSchema({ minimum });
|
|
451
442
|
}
|
|
452
443
|
exclusiveMin(exclusiveMinimum) {
|
|
453
|
-
|
|
454
|
-
return this;
|
|
444
|
+
return this.cloneAndUpdateSchema({ exclusiveMinimum });
|
|
455
445
|
}
|
|
456
446
|
max(maximum) {
|
|
457
|
-
|
|
458
|
-
return this;
|
|
447
|
+
return this.cloneAndUpdateSchema({ maximum });
|
|
459
448
|
}
|
|
460
449
|
exclusiveMax(exclusiveMaximum) {
|
|
461
|
-
|
|
462
|
-
return this;
|
|
450
|
+
return this.cloneAndUpdateSchema({ exclusiveMaximum });
|
|
463
451
|
}
|
|
464
452
|
lessThan(value) {
|
|
465
453
|
return this.exclusiveMax(value);
|
|
@@ -584,15 +572,13 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
|
|
|
584
572
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
585
573
|
*/
|
|
586
574
|
allowAdditionalProperties() {
|
|
587
|
-
|
|
588
|
-
return this;
|
|
575
|
+
return this.cloneAndUpdateSchema({ additionalProperties: true });
|
|
589
576
|
}
|
|
590
577
|
extend(props) {
|
|
591
|
-
const
|
|
592
|
-
_objectAssign(newBuilder.schema, _deepCopy(this.schema));
|
|
578
|
+
const clone = this.cloneAndUpdateSchema(_deepCopy(this.schema));
|
|
593
579
|
const incomingSchemaBuilder = new JsonSchemaObjectBuilder(props);
|
|
594
|
-
mergeJsonSchemaObjects(
|
|
595
|
-
return
|
|
580
|
+
mergeJsonSchemaObjects(clone.schema, incomingSchemaBuilder.schema);
|
|
581
|
+
return clone;
|
|
596
582
|
}
|
|
597
583
|
/**
|
|
598
584
|
* Extends the current schema with `id`, `created` and `updated` according to NC DB conventions.
|
|
@@ -606,12 +592,10 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
|
|
|
606
592
|
});
|
|
607
593
|
}
|
|
608
594
|
minProperties(minProperties) {
|
|
609
|
-
|
|
610
|
-
return this;
|
|
595
|
+
return this.cloneAndUpdateSchema({ minProperties });
|
|
611
596
|
}
|
|
612
597
|
maxProperties(maxProperties) {
|
|
613
|
-
|
|
614
|
-
return this;
|
|
598
|
+
return this.cloneAndUpdateSchema({ maxProperties });
|
|
615
599
|
}
|
|
616
600
|
}
|
|
617
601
|
export class JsonSchemaObjectInferringBuilder extends JsonSchemaAnyBuilder {
|
|
@@ -644,8 +628,7 @@ export class JsonSchemaObjectInferringBuilder extends JsonSchemaAnyBuilder {
|
|
|
644
628
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
645
629
|
*/
|
|
646
630
|
allowAdditionalProperties() {
|
|
647
|
-
|
|
648
|
-
return this;
|
|
631
|
+
return this.cloneAndUpdateSchema({ additionalProperties: true });
|
|
649
632
|
}
|
|
650
633
|
extend(props) {
|
|
651
634
|
const newBuilder = new JsonSchemaObjectInferringBuilder();
|
|
@@ -674,12 +657,10 @@ export class JsonSchemaArrayBuilder extends JsonSchemaAnyBuilder {
|
|
|
674
657
|
});
|
|
675
658
|
}
|
|
676
659
|
minLength(minItems) {
|
|
677
|
-
|
|
678
|
-
return this;
|
|
660
|
+
return this.cloneAndUpdateSchema({ minItems });
|
|
679
661
|
}
|
|
680
662
|
maxLength(maxItems) {
|
|
681
|
-
|
|
682
|
-
return this;
|
|
663
|
+
return this.cloneAndUpdateSchema({ maxItems });
|
|
683
664
|
}
|
|
684
665
|
length(minItemsOrExact, maxItems) {
|
|
685
666
|
const maxItemsActual = maxItems ?? minItemsOrExact;
|
|
@@ -689,8 +670,7 @@ export class JsonSchemaArrayBuilder extends JsonSchemaAnyBuilder {
|
|
|
689
670
|
return this.minLength(length).maxLength(length);
|
|
690
671
|
}
|
|
691
672
|
unique() {
|
|
692
|
-
|
|
693
|
-
return this;
|
|
673
|
+
return this.cloneAndUpdateSchema({ uniqueItems: true });
|
|
694
674
|
}
|
|
695
675
|
}
|
|
696
676
|
export class JsonSchemaSet2Builder extends JsonSchemaAnyBuilder {
|
|
@@ -701,12 +681,10 @@ export class JsonSchemaSet2Builder extends JsonSchemaAnyBuilder {
|
|
|
701
681
|
});
|
|
702
682
|
}
|
|
703
683
|
min(minItems) {
|
|
704
|
-
|
|
705
|
-
return this;
|
|
684
|
+
return this.cloneAndUpdateSchema({ minItems });
|
|
706
685
|
}
|
|
707
686
|
max(maxItems) {
|
|
708
|
-
|
|
709
|
-
return this;
|
|
687
|
+
return this.cloneAndUpdateSchema({ maxItems });
|
|
710
688
|
}
|
|
711
689
|
}
|
|
712
690
|
export class JsonSchemaBufferBuilder extends JsonSchemaAnyBuilder {
|
package/package.json
CHANGED
|
@@ -120,13 +120,13 @@ export class AjvSchema<IN = unknown, OUT = IN> {
|
|
|
120
120
|
*
|
|
121
121
|
* Returned object is always the same object (`===`) that was passed, so it is returned just for convenience.
|
|
122
122
|
*/
|
|
123
|
-
validate(input: IN, opt: AjvValidationOptions = {}): OUT {
|
|
123
|
+
validate(input: IN, opt: AjvValidationOptions<IN> = {}): OUT {
|
|
124
124
|
const [err, output] = this.getValidationResult(input, opt)
|
|
125
125
|
if (err) throw err
|
|
126
126
|
return output
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
isValid(input: IN, opt?: AjvValidationOptions): boolean {
|
|
129
|
+
isValid(input: IN, opt?: AjvValidationOptions<IN>): boolean {
|
|
130
130
|
// todo: we can make it both fast and non-mutating by using Ajv
|
|
131
131
|
// with "removeAdditional" and "useDefaults" disabled.
|
|
132
132
|
const [err] = this.getValidationResult(input, opt)
|
|
@@ -135,7 +135,7 @@ export class AjvSchema<IN = unknown, OUT = IN> {
|
|
|
135
135
|
|
|
136
136
|
getValidationResult(
|
|
137
137
|
input: IN,
|
|
138
|
-
opt: AjvValidationOptions = {},
|
|
138
|
+
opt: AjvValidationOptions<IN> = {},
|
|
139
139
|
): ValidationFunctionResult<OUT, AjvValidationError> {
|
|
140
140
|
const fn = this.getAJVValidateFunction()
|
|
141
141
|
|
|
@@ -144,7 +144,7 @@ export class AjvSchema<IN = unknown, OUT = IN> {
|
|
|
144
144
|
? input // mutate
|
|
145
145
|
: _deepCopy(input) // not mutate
|
|
146
146
|
|
|
147
|
-
const valid = fn(item) // mutates item
|
|
147
|
+
const valid = fn(item) // mutates item, but not input
|
|
148
148
|
_typeCast<OUT>(item)
|
|
149
149
|
if (valid) return [null, item]
|
|
150
150
|
|
|
@@ -165,7 +165,8 @@ export class AjvSchema<IN = unknown, OUT = IN> {
|
|
|
165
165
|
|
|
166
166
|
// Note: if we mutated the input already, e.g stripped unknown properties,
|
|
167
167
|
// the error message Input would contain already mutated object print, such as Input: {}
|
|
168
|
-
|
|
168
|
+
// Unless `getOriginalInput` function is provided - then it will be used to preserve the Input pureness.
|
|
169
|
+
const inputStringified = _inspect(opt.getOriginalInput?.() || input, { maxLen: 4000 })
|
|
169
170
|
message = [message, 'Input: ' + inputStringified].join(separator)
|
|
170
171
|
|
|
171
172
|
const err = new AjvValidationError(
|
|
@@ -245,7 +246,7 @@ export type WithCachedAjvSchema<Base, IN, OUT> = Base & {
|
|
|
245
246
|
[HIDDEN_AJV_SCHEMA]: AjvSchema<IN, OUT>
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
export interface AjvValidationOptions {
|
|
249
|
+
export interface AjvValidationOptions<IN> {
|
|
249
250
|
/**
|
|
250
251
|
* Defaults to true,
|
|
251
252
|
* because that's how AJV works by default,
|
|
@@ -264,6 +265,16 @@ export interface AjvValidationOptions {
|
|
|
264
265
|
mutateInput?: boolean
|
|
265
266
|
inputName?: string
|
|
266
267
|
inputId?: string
|
|
268
|
+
/**
|
|
269
|
+
* Function that returns "original input".
|
|
270
|
+
* What is original input?
|
|
271
|
+
* It's an input in its original non-mutated form.
|
|
272
|
+
* Why is it needed?
|
|
273
|
+
* Because we mutates the Input here. And after its been mutated - we no longer
|
|
274
|
+
* can include it "how it was" in an error message. So, for that reason we'll use
|
|
275
|
+
* `getOriginalInput()`, if it's provided.
|
|
276
|
+
*/
|
|
277
|
+
getOriginalInput?: () => IN
|
|
267
278
|
}
|
|
268
279
|
|
|
269
280
|
export interface AjvSchemaCfg {
|
|
@@ -232,8 +232,16 @@ export class JsonSchemaTerminal<IN, OUT, Opt> {
|
|
|
232
232
|
return jsonSchema
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
clone():
|
|
236
|
-
|
|
235
|
+
clone(): this {
|
|
236
|
+
const cloned = Object.create(Object.getPrototypeOf(this))
|
|
237
|
+
cloned.schema = _deepCopy(this.schema)
|
|
238
|
+
return cloned
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
cloneAndUpdateSchema(schema: Partial<JsonSchema>): this {
|
|
242
|
+
const clone = this.clone()
|
|
243
|
+
_objectAssign(clone.schema, schema)
|
|
244
|
+
return clone
|
|
237
245
|
}
|
|
238
246
|
|
|
239
247
|
/**
|
|
@@ -241,6 +249,7 @@ export class JsonSchemaTerminal<IN, OUT, Opt> {
|
|
|
241
249
|
*/
|
|
242
250
|
in!: IN
|
|
243
251
|
out!: OUT
|
|
252
|
+
opt!: Opt
|
|
244
253
|
}
|
|
245
254
|
|
|
246
255
|
export class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTerminal<IN, OUT, Opt> {
|
|
@@ -267,58 +276,48 @@ export class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTerminal<IN, O
|
|
|
267
276
|
* ```
|
|
268
277
|
*/
|
|
269
278
|
isOfType<ExpectedType>(): ExactMatch<ExpectedType, OUT> extends true ? this : never {
|
|
270
|
-
|
|
271
|
-
return this as any
|
|
279
|
+
return this.cloneAndUpdateSchema({ hasIsOfTypeCheck: true }) as any
|
|
272
280
|
}
|
|
273
281
|
|
|
274
282
|
$schema($schema: string): this {
|
|
275
|
-
|
|
276
|
-
return this
|
|
283
|
+
return this.cloneAndUpdateSchema({ $schema })
|
|
277
284
|
}
|
|
278
285
|
|
|
279
286
|
$schemaDraft7(): this {
|
|
280
|
-
this.$schema('http://json-schema.org/draft-07/schema#')
|
|
281
|
-
return this
|
|
287
|
+
return this.$schema('http://json-schema.org/draft-07/schema#')
|
|
282
288
|
}
|
|
283
289
|
|
|
284
290
|
$id($id: string): this {
|
|
285
|
-
|
|
286
|
-
return this
|
|
291
|
+
return this.cloneAndUpdateSchema({ $id })
|
|
287
292
|
}
|
|
288
293
|
|
|
289
294
|
title(title: string): this {
|
|
290
|
-
|
|
291
|
-
return this
|
|
295
|
+
return this.cloneAndUpdateSchema({ title })
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
description(description: string): this {
|
|
295
|
-
|
|
296
|
-
return this
|
|
299
|
+
return this.cloneAndUpdateSchema({ description })
|
|
297
300
|
}
|
|
298
301
|
|
|
299
302
|
deprecated(deprecated = true): this {
|
|
300
|
-
|
|
301
|
-
return this
|
|
303
|
+
return this.cloneAndUpdateSchema({ deprecated })
|
|
302
304
|
}
|
|
303
305
|
|
|
304
306
|
type(type: string): this {
|
|
305
|
-
|
|
306
|
-
return this
|
|
307
|
+
return this.cloneAndUpdateSchema({ type })
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
default(v: any): this {
|
|
310
|
-
|
|
311
|
-
return this
|
|
311
|
+
return this.cloneAndUpdateSchema({ default: v })
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
instanceof(of: string): this {
|
|
315
|
-
|
|
316
|
-
return this
|
|
315
|
+
return this.cloneAndUpdateSchema({ type: 'object', instanceof: of })
|
|
317
316
|
}
|
|
318
317
|
|
|
319
318
|
optional(): JsonSchemaAnyBuilder<IN | undefined, OUT | undefined, true> {
|
|
320
|
-
this.
|
|
321
|
-
return
|
|
319
|
+
const clone = this.cloneAndUpdateSchema({ optionalField: true })
|
|
320
|
+
return clone as unknown as JsonSchemaAnyBuilder<IN | undefined, OUT | undefined, true>
|
|
322
321
|
}
|
|
323
322
|
|
|
324
323
|
nullable(): JsonSchemaAnyBuilder<IN | null, OUT | null, Opt> {
|
|
@@ -386,20 +385,18 @@ export class JsonSchemaStringBuilder<
|
|
|
386
385
|
}
|
|
387
386
|
|
|
388
387
|
pattern(pattern: string, opt?: JsonBuilderRuleOpt): this {
|
|
389
|
-
|
|
390
|
-
if (opt?.
|
|
391
|
-
|
|
392
|
-
return
|
|
388
|
+
const clone = this.cloneAndUpdateSchema({ pattern })
|
|
389
|
+
if (opt?.name) clone.setErrorMessage('pattern', `is not a valid ${opt.name}`)
|
|
390
|
+
if (opt?.msg) clone.setErrorMessage('pattern', opt.msg)
|
|
391
|
+
return clone
|
|
393
392
|
}
|
|
394
393
|
|
|
395
394
|
minLength(minLength: number): this {
|
|
396
|
-
|
|
397
|
-
return this
|
|
395
|
+
return this.cloneAndUpdateSchema({ minLength })
|
|
398
396
|
}
|
|
399
397
|
|
|
400
398
|
maxLength(maxLength: number): this {
|
|
401
|
-
|
|
402
|
-
return this
|
|
399
|
+
return this.cloneAndUpdateSchema({ maxLength })
|
|
403
400
|
}
|
|
404
401
|
|
|
405
402
|
length(exactLength: number): this
|
|
@@ -411,28 +408,31 @@ export class JsonSchemaStringBuilder<
|
|
|
411
408
|
|
|
412
409
|
email(opt?: Partial<JsonSchemaStringEmailOptions>): this {
|
|
413
410
|
const defaultOptions: JsonSchemaStringEmailOptions = { checkTLD: true }
|
|
414
|
-
|
|
415
|
-
|
|
411
|
+
return this.cloneAndUpdateSchema({ email: { ...defaultOptions, ...opt } })
|
|
412
|
+
.trim()
|
|
413
|
+
.toLowerCase()
|
|
416
414
|
}
|
|
417
415
|
|
|
418
416
|
trim(): this {
|
|
419
|
-
|
|
420
|
-
return this
|
|
417
|
+
return this.cloneAndUpdateSchema({ transform: { ...this.schema.transform, trim: true } })
|
|
421
418
|
}
|
|
422
419
|
|
|
423
420
|
toLowerCase(): this {
|
|
424
|
-
|
|
425
|
-
|
|
421
|
+
return this.cloneAndUpdateSchema({
|
|
422
|
+
transform: { ...this.schema.transform, toLowerCase: true },
|
|
423
|
+
})
|
|
426
424
|
}
|
|
427
425
|
|
|
428
426
|
toUpperCase(): this {
|
|
429
|
-
|
|
430
|
-
|
|
427
|
+
return this.cloneAndUpdateSchema({
|
|
428
|
+
transform: { ...this.schema.transform, toUpperCase: true },
|
|
429
|
+
})
|
|
431
430
|
}
|
|
432
431
|
|
|
433
432
|
truncate(toLength: number): this {
|
|
434
|
-
|
|
435
|
-
|
|
433
|
+
return this.cloneAndUpdateSchema({
|
|
434
|
+
transform: { ...this.schema.transform, truncate: toLength },
|
|
435
|
+
})
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
branded<B extends string>(): JsonSchemaStringBuilder<B, B, Opt> {
|
|
@@ -446,13 +446,11 @@ export class JsonSchemaStringBuilder<
|
|
|
446
446
|
* because this call effectively starts a new schema chain.
|
|
447
447
|
*/
|
|
448
448
|
isoDate(): JsonSchemaIsoDateBuilder {
|
|
449
|
-
_objectAssign(this.schema, { IsoDate: {} })
|
|
450
449
|
return new JsonSchemaIsoDateBuilder()
|
|
451
450
|
}
|
|
452
451
|
|
|
453
452
|
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime | IN, IsoDateTime, Opt> {
|
|
454
|
-
|
|
455
|
-
return this.branded<IsoDateTime>()
|
|
453
|
+
return this.cloneAndUpdateSchema({ IsoDateTime: true }).branded<IsoDateTime>()
|
|
456
454
|
}
|
|
457
455
|
|
|
458
456
|
/**
|
|
@@ -537,33 +535,31 @@ export class JsonSchemaIsoDateBuilder<Opt extends boolean = false> extends JsonS
|
|
|
537
535
|
}
|
|
538
536
|
|
|
539
537
|
before(date: string): this {
|
|
540
|
-
|
|
541
|
-
return this
|
|
538
|
+
return this.cloneAndUpdateSchema({ IsoDate: { before: date } })
|
|
542
539
|
}
|
|
543
540
|
|
|
544
541
|
sameOrBefore(date: string): this {
|
|
545
|
-
|
|
546
|
-
return this
|
|
542
|
+
return this.cloneAndUpdateSchema({ IsoDate: { sameOrBefore: date } })
|
|
547
543
|
}
|
|
548
544
|
|
|
549
545
|
after(date: string): this {
|
|
550
|
-
|
|
551
|
-
return this
|
|
546
|
+
return this.cloneAndUpdateSchema({ IsoDate: { after: date } })
|
|
552
547
|
}
|
|
553
548
|
|
|
554
549
|
sameOrAfter(date: string): this {
|
|
555
|
-
|
|
556
|
-
return this
|
|
550
|
+
return this.cloneAndUpdateSchema({ IsoDate: { sameOrAfter: date } })
|
|
557
551
|
}
|
|
558
552
|
|
|
559
553
|
between(fromDate: string, toDate: string, incl: Inclusiveness): this {
|
|
554
|
+
let schemaPatch: Partial<JsonSchema> = {}
|
|
555
|
+
|
|
560
556
|
if (incl === '[)') {
|
|
561
|
-
|
|
557
|
+
schemaPatch = { IsoDate: { sameOrAfter: fromDate, before: toDate } }
|
|
562
558
|
} else if (incl === '[]') {
|
|
563
|
-
|
|
559
|
+
schemaPatch = { IsoDate: { sameOrAfter: fromDate, sameOrBefore: toDate } }
|
|
564
560
|
}
|
|
565
561
|
|
|
566
|
-
return this
|
|
562
|
+
return this.cloneAndUpdateSchema(schemaPatch)
|
|
567
563
|
}
|
|
568
564
|
}
|
|
569
565
|
|
|
@@ -591,6 +587,7 @@ export class JsonSchemaNumberBuilder<
|
|
|
591
587
|
* This `optionalValues` feature only works when the current schema is nested in an object or array schema,
|
|
592
588
|
* due to how mutability works in Ajv.
|
|
593
589
|
*/
|
|
590
|
+
|
|
594
591
|
override optional(
|
|
595
592
|
optionalValues?: number[],
|
|
596
593
|
): JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true> {
|
|
@@ -613,8 +610,7 @@ export class JsonSchemaNumberBuilder<
|
|
|
613
610
|
}
|
|
614
611
|
|
|
615
612
|
integer(): this {
|
|
616
|
-
|
|
617
|
-
return this
|
|
613
|
+
return this.cloneAndUpdateSchema({ type: 'integer' })
|
|
618
614
|
}
|
|
619
615
|
|
|
620
616
|
branded<B extends number>(): JsonSchemaNumberBuilder<B, B, Opt> {
|
|
@@ -622,28 +618,23 @@ export class JsonSchemaNumberBuilder<
|
|
|
622
618
|
}
|
|
623
619
|
|
|
624
620
|
multipleOf(multipleOf: number): this {
|
|
625
|
-
|
|
626
|
-
return this
|
|
621
|
+
return this.cloneAndUpdateSchema({ multipleOf })
|
|
627
622
|
}
|
|
628
623
|
|
|
629
624
|
min(minimum: number): this {
|
|
630
|
-
|
|
631
|
-
return this
|
|
625
|
+
return this.cloneAndUpdateSchema({ minimum })
|
|
632
626
|
}
|
|
633
627
|
|
|
634
628
|
exclusiveMin(exclusiveMinimum: number): this {
|
|
635
|
-
|
|
636
|
-
return this
|
|
629
|
+
return this.cloneAndUpdateSchema({ exclusiveMinimum })
|
|
637
630
|
}
|
|
638
631
|
|
|
639
632
|
max(maximum: number): this {
|
|
640
|
-
|
|
641
|
-
return this
|
|
633
|
+
return this.cloneAndUpdateSchema({ maximum })
|
|
642
634
|
}
|
|
643
635
|
|
|
644
636
|
exclusiveMax(exclusiveMaximum: number): this {
|
|
645
|
-
|
|
646
|
-
return this
|
|
637
|
+
return this.cloneAndUpdateSchema({ exclusiveMaximum })
|
|
647
638
|
}
|
|
648
639
|
|
|
649
640
|
lessThan(value: number): this {
|
|
@@ -812,21 +803,24 @@ export class JsonSchemaObjectBuilder<
|
|
|
812
803
|
/**
|
|
813
804
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
814
805
|
*/
|
|
806
|
+
|
|
815
807
|
allowAdditionalProperties(): this {
|
|
816
|
-
|
|
817
|
-
return this
|
|
808
|
+
return this.cloneAndUpdateSchema({ additionalProperties: true })
|
|
818
809
|
}
|
|
819
810
|
|
|
820
811
|
extend<IN2 extends AnyObject>(
|
|
821
812
|
props: AnyObject,
|
|
822
813
|
): JsonSchemaObjectBuilder<IN & IN2, OUT & IN2, Opt> {
|
|
823
|
-
const
|
|
824
|
-
|
|
814
|
+
const clone = this.cloneAndUpdateSchema(_deepCopy(this.schema)) as JsonSchemaObjectBuilder<
|
|
815
|
+
IN & IN2,
|
|
816
|
+
OUT & IN2,
|
|
817
|
+
Opt
|
|
818
|
+
>
|
|
825
819
|
|
|
826
820
|
const incomingSchemaBuilder = new JsonSchemaObjectBuilder<IN2, IN2, false>(props)
|
|
827
|
-
mergeJsonSchemaObjects(
|
|
821
|
+
mergeJsonSchemaObjects(clone.schema as any, incomingSchemaBuilder.schema as any)
|
|
828
822
|
|
|
829
|
-
return
|
|
823
|
+
return clone
|
|
830
824
|
}
|
|
831
825
|
|
|
832
826
|
/**
|
|
@@ -842,13 +836,11 @@ export class JsonSchemaObjectBuilder<
|
|
|
842
836
|
}
|
|
843
837
|
|
|
844
838
|
minProperties(minProperties: number): this {
|
|
845
|
-
|
|
846
|
-
return this
|
|
839
|
+
return this.cloneAndUpdateSchema({ minProperties })
|
|
847
840
|
}
|
|
848
841
|
|
|
849
842
|
maxProperties(maxProperties: number): this {
|
|
850
|
-
|
|
851
|
-
return this
|
|
843
|
+
return this.cloneAndUpdateSchema({ maxProperties })
|
|
852
844
|
}
|
|
853
845
|
}
|
|
854
846
|
|
|
@@ -928,9 +920,9 @@ export class JsonSchemaObjectInferringBuilder<
|
|
|
928
920
|
/**
|
|
929
921
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
930
922
|
*/
|
|
923
|
+
|
|
931
924
|
allowAdditionalProperties(): this {
|
|
932
|
-
|
|
933
|
-
return this
|
|
925
|
+
return this.cloneAndUpdateSchema({ additionalProperties: true })
|
|
934
926
|
}
|
|
935
927
|
|
|
936
928
|
extend<NEW_PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(
|
|
@@ -985,13 +977,11 @@ export class JsonSchemaArrayBuilder<IN, OUT, Opt> extends JsonSchemaAnyBuilder<I
|
|
|
985
977
|
}
|
|
986
978
|
|
|
987
979
|
minLength(minItems: number): this {
|
|
988
|
-
|
|
989
|
-
return this
|
|
980
|
+
return this.cloneAndUpdateSchema({ minItems })
|
|
990
981
|
}
|
|
991
982
|
|
|
992
983
|
maxLength(maxItems: number): this {
|
|
993
|
-
|
|
994
|
-
return this
|
|
984
|
+
return this.cloneAndUpdateSchema({ maxItems })
|
|
995
985
|
}
|
|
996
986
|
|
|
997
987
|
length(exactLength: number): this
|
|
@@ -1006,8 +996,7 @@ export class JsonSchemaArrayBuilder<IN, OUT, Opt> extends JsonSchemaAnyBuilder<I
|
|
|
1006
996
|
}
|
|
1007
997
|
|
|
1008
998
|
unique(): this {
|
|
1009
|
-
|
|
1010
|
-
return this
|
|
999
|
+
return this.cloneAndUpdateSchema({ uniqueItems: true })
|
|
1011
1000
|
}
|
|
1012
1001
|
}
|
|
1013
1002
|
|
|
@@ -1024,13 +1013,11 @@ export class JsonSchemaSet2Builder<IN, OUT, Opt> extends JsonSchemaAnyBuilder<
|
|
|
1024
1013
|
}
|
|
1025
1014
|
|
|
1026
1015
|
min(minItems: number): this {
|
|
1027
|
-
|
|
1028
|
-
return this
|
|
1016
|
+
return this.cloneAndUpdateSchema({ minItems })
|
|
1029
1017
|
}
|
|
1030
1018
|
|
|
1031
1019
|
max(maxItems: number): this {
|
|
1032
|
-
|
|
1033
|
-
return this
|
|
1020
|
+
return this.cloneAndUpdateSchema({ maxItems })
|
|
1034
1021
|
}
|
|
1035
1022
|
}
|
|
1036
1023
|
|