@tldraw/validate 4.2.1 → 4.2.2
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-cjs/index.d.ts +37 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/validation.js +304 -68
- package/dist-cjs/lib/validation.js.map +3 -3
- package/dist-esm/index.d.mts +37 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/validation.mjs +304 -68
- package/dist-esm/lib/validation.mjs.map +3 -3
- package/package.json +2 -2
- package/src/lib/validation.ts +355 -68
- package/src/test/validation.test.ts +38 -5
package/dist-cjs/index.d.ts
CHANGED
|
@@ -322,6 +322,20 @@ declare function model<T extends {
|
|
|
322
322
|
readonly id: string;
|
|
323
323
|
}>(name: string, validator: Validatable<T>): Validator<T>;
|
|
324
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Validator that ensures a value is a finite, non-zero number. Allows negative numbers.
|
|
327
|
+
* Useful for scale factors that can be negative (for flipping) but not zero.
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* const scale = T.nonZeroFiniteNumber.validate(-1.5) // Returns -1.5 (valid, allows negative)
|
|
332
|
+
* T.nonZeroFiniteNumber.validate(0) // Throws ValidationError: "Expected a non-zero number, got 0"
|
|
333
|
+
* T.nonZeroFiniteNumber.validate(Infinity) // Throws ValidationError
|
|
334
|
+
* ```
|
|
335
|
+
* @public
|
|
336
|
+
*/
|
|
337
|
+
declare const nonZeroFiniteNumber: Validator<number>;
|
|
338
|
+
|
|
325
339
|
/**
|
|
326
340
|
* Validator that ensures a value is a positive integer (\> 0). Rejects zero and negative integers.
|
|
327
341
|
*
|
|
@@ -613,6 +627,8 @@ declare namespace T {
|
|
|
613
627
|
number,
|
|
614
628
|
positiveNumber,
|
|
615
629
|
nonZeroNumber,
|
|
630
|
+
nonZeroFiniteNumber,
|
|
631
|
+
unitInterval,
|
|
616
632
|
integer,
|
|
617
633
|
positiveInteger,
|
|
618
634
|
nonZeroInteger,
|
|
@@ -735,6 +751,22 @@ export declare type UnionValidatorConfig<Key extends string, Config> = {
|
|
|
735
751
|
};
|
|
736
752
|
};
|
|
737
753
|
|
|
754
|
+
/**
|
|
755
|
+
* Validator that ensures a value is a number in the unit interval [0, 1].
|
|
756
|
+
* Useful for opacity, percentages expressed as decimals, and other normalized values.
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* ```ts
|
|
760
|
+
* const opacity = T.unitInterval.validate(0.5) // Returns 0.5
|
|
761
|
+
* T.unitInterval.validate(0) // Returns 0 (valid)
|
|
762
|
+
* T.unitInterval.validate(1) // Returns 1 (valid)
|
|
763
|
+
* T.unitInterval.validate(1.5) // Throws ValidationError
|
|
764
|
+
* T.unitInterval.validate(-0.1) // Throws ValidationError
|
|
765
|
+
* ```
|
|
766
|
+
* @public
|
|
767
|
+
*/
|
|
768
|
+
declare const unitInterval: Validator<number>;
|
|
769
|
+
|
|
738
770
|
/**
|
|
739
771
|
* Validator that accepts any value without type checking. Useful as a starting point for
|
|
740
772
|
* building custom validations or when you need to accept truly unknown data.
|
|
@@ -854,13 +886,17 @@ declare class ValidationError extends Error {
|
|
|
854
886
|
export declare class Validator<T> implements Validatable<T> {
|
|
855
887
|
readonly validationFn: ValidatorFn<T>;
|
|
856
888
|
readonly validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T>;
|
|
889
|
+
/* Excluded from this release type: skipSameValueCheck */
|
|
857
890
|
/**
|
|
858
891
|
* Creates a new Validator instance.
|
|
859
892
|
*
|
|
860
893
|
* validationFn - Function that validates and returns a value of type T
|
|
861
894
|
* validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
|
|
895
|
+
* skipSameValueCheck - Internal flag to skip dev check for validators that transform values
|
|
862
896
|
*/
|
|
863
|
-
constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T
|
|
897
|
+
constructor(validationFn: ValidatorFn<T>, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn<T>,
|
|
898
|
+
/** @internal */
|
|
899
|
+
skipSameValueCheck?: boolean);
|
|
864
900
|
/**
|
|
865
901
|
* Validates an unknown value and returns it with the correct type. The returned value is
|
|
866
902
|
* guaranteed to be referentially equal to the passed value.
|
package/dist-cjs/index.js
CHANGED
|
@@ -39,6 +39,7 @@ __export(validation_exports, {
|
|
|
39
39
|
literal: () => literal,
|
|
40
40
|
literalEnum: () => literalEnum,
|
|
41
41
|
model: () => model,
|
|
42
|
+
nonZeroFiniteNumber: () => nonZeroFiniteNumber,
|
|
42
43
|
nonZeroInteger: () => nonZeroInteger,
|
|
43
44
|
nonZeroNumber: () => nonZeroNumber,
|
|
44
45
|
nullable: () => nullable,
|
|
@@ -53,11 +54,13 @@ __export(validation_exports, {
|
|
|
53
54
|
srcUrl: () => srcUrl,
|
|
54
55
|
string: () => string,
|
|
55
56
|
union: () => union,
|
|
57
|
+
unitInterval: () => unitInterval,
|
|
56
58
|
unknown: () => unknown,
|
|
57
59
|
unknownObject: () => unknownObject
|
|
58
60
|
});
|
|
59
61
|
module.exports = __toCommonJS(validation_exports);
|
|
60
62
|
var import_utils = require("@tldraw/utils");
|
|
63
|
+
const IS_DEV = process.env.NODE_ENV !== "production";
|
|
61
64
|
function formatPath(path) {
|
|
62
65
|
if (!path.length) {
|
|
63
66
|
return null;
|
|
@@ -134,10 +137,12 @@ class Validator {
|
|
|
134
137
|
*
|
|
135
138
|
* validationFn - Function that validates and returns a value of type T
|
|
136
139
|
* validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
|
|
140
|
+
* skipSameValueCheck - Internal flag to skip dev check for validators that transform values
|
|
137
141
|
*/
|
|
138
|
-
constructor(validationFn, validateUsingKnownGoodVersionFn) {
|
|
142
|
+
constructor(validationFn, validateUsingKnownGoodVersionFn, skipSameValueCheck = false) {
|
|
139
143
|
this.validationFn = validationFn;
|
|
140
144
|
this.validateUsingKnownGoodVersionFn = validateUsingKnownGoodVersionFn;
|
|
145
|
+
this.skipSameValueCheck = skipSameValueCheck;
|
|
141
146
|
}
|
|
142
147
|
/**
|
|
143
148
|
* Validates an unknown value and returns it with the correct type. The returned value is
|
|
@@ -161,7 +166,7 @@ class Validator {
|
|
|
161
166
|
*/
|
|
162
167
|
validate(value) {
|
|
163
168
|
const validated = this.validationFn(value);
|
|
164
|
-
if (
|
|
169
|
+
if (IS_DEV && !this.skipSameValueCheck && !Object.is(value, validated)) {
|
|
165
170
|
throw new ValidationError("Validator functions must return the same value they were passed");
|
|
166
171
|
}
|
|
167
172
|
return validated;
|
|
@@ -322,7 +327,9 @@ class Validator {
|
|
|
322
327
|
return knownGoodValue;
|
|
323
328
|
}
|
|
324
329
|
return otherValidationFn(validated);
|
|
325
|
-
}
|
|
330
|
+
},
|
|
331
|
+
true
|
|
332
|
+
// skipSameValueCheck: refine is designed to transform values
|
|
326
333
|
);
|
|
327
334
|
}
|
|
328
335
|
check(nameOrCheckFn, checkFn) {
|
|
@@ -350,11 +357,25 @@ class ArrayOfValidator extends Validator {
|
|
|
350
357
|
(value) => {
|
|
351
358
|
const arr = array.validate(value);
|
|
352
359
|
for (let i = 0; i < arr.length; i++) {
|
|
353
|
-
|
|
360
|
+
if (IS_DEV) {
|
|
361
|
+
prefixError(i, () => itemValidator.validate(arr[i]));
|
|
362
|
+
} else {
|
|
363
|
+
try {
|
|
364
|
+
itemValidator.validate(arr[i]);
|
|
365
|
+
} catch (err) {
|
|
366
|
+
if (err instanceof ValidationError) {
|
|
367
|
+
throw new ValidationError(err.rawMessage, [i, ...err.path]);
|
|
368
|
+
}
|
|
369
|
+
throw new ValidationError(err.toString(), [i]);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
354
372
|
}
|
|
355
373
|
return arr;
|
|
356
374
|
},
|
|
357
375
|
(knownGoodValue, newValue) => {
|
|
376
|
+
if (Object.is(knownGoodValue, newValue)) {
|
|
377
|
+
return knownGoodValue;
|
|
378
|
+
}
|
|
358
379
|
if (!itemValidator.validateUsingKnownGoodVersion) return this.validate(newValue);
|
|
359
380
|
const arr = array.validate(newValue);
|
|
360
381
|
let isDifferent = knownGoodValue.length !== arr.length;
|
|
@@ -362,18 +383,46 @@ class ArrayOfValidator extends Validator {
|
|
|
362
383
|
const item = arr[i];
|
|
363
384
|
if (i >= knownGoodValue.length) {
|
|
364
385
|
isDifferent = true;
|
|
365
|
-
|
|
386
|
+
if (IS_DEV) {
|
|
387
|
+
prefixError(i, () => itemValidator.validate(item));
|
|
388
|
+
} else {
|
|
389
|
+
try {
|
|
390
|
+
itemValidator.validate(item);
|
|
391
|
+
} catch (err) {
|
|
392
|
+
if (err instanceof ValidationError) {
|
|
393
|
+
throw new ValidationError(err.rawMessage, [i, ...err.path]);
|
|
394
|
+
}
|
|
395
|
+
throw new ValidationError(err.toString(), [i]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
366
398
|
continue;
|
|
367
399
|
}
|
|
368
400
|
if (Object.is(knownGoodValue[i], item)) {
|
|
369
401
|
continue;
|
|
370
402
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
403
|
+
if (IS_DEV) {
|
|
404
|
+
const checkedItem = prefixError(
|
|
405
|
+
i,
|
|
406
|
+
() => itemValidator.validateUsingKnownGoodVersion(knownGoodValue[i], item)
|
|
407
|
+
);
|
|
408
|
+
if (!Object.is(checkedItem, knownGoodValue[i])) {
|
|
409
|
+
isDifferent = true;
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
try {
|
|
413
|
+
const checkedItem = itemValidator.validateUsingKnownGoodVersion(
|
|
414
|
+
knownGoodValue[i],
|
|
415
|
+
item
|
|
416
|
+
);
|
|
417
|
+
if (!Object.is(checkedItem, knownGoodValue[i])) {
|
|
418
|
+
isDifferent = true;
|
|
419
|
+
}
|
|
420
|
+
} catch (err) {
|
|
421
|
+
if (err instanceof ValidationError) {
|
|
422
|
+
throw new ValidationError(err.rawMessage, [i, ...err.path]);
|
|
423
|
+
}
|
|
424
|
+
throw new ValidationError(err.toString(), [i]);
|
|
425
|
+
}
|
|
377
426
|
}
|
|
378
427
|
}
|
|
379
428
|
return isDifferent ? newValue : knownGoodValue;
|
|
@@ -433,11 +482,25 @@ class ObjectValidator extends Validator {
|
|
|
433
482
|
if (typeof object2 !== "object" || object2 === null) {
|
|
434
483
|
throw new ValidationError(`Expected object, got ${typeToString(object2)}`);
|
|
435
484
|
}
|
|
436
|
-
for (const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
485
|
+
for (const key in config) {
|
|
486
|
+
if (!(0, import_utils.hasOwnProperty)(config, key)) continue;
|
|
487
|
+
const validator = config[key];
|
|
488
|
+
if (IS_DEV) {
|
|
489
|
+
prefixError(key, () => {
|
|
490
|
+
;
|
|
491
|
+
validator.validate((0, import_utils.getOwnProperty)(object2, key));
|
|
492
|
+
});
|
|
493
|
+
} else {
|
|
494
|
+
try {
|
|
495
|
+
;
|
|
496
|
+
validator.validate((0, import_utils.getOwnProperty)(object2, key));
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (err instanceof ValidationError) {
|
|
499
|
+
throw new ValidationError(err.rawMessage, [key, ...err.path]);
|
|
500
|
+
}
|
|
501
|
+
throw new ValidationError(err.toString(), [key]);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
441
504
|
}
|
|
442
505
|
if (!shouldAllowUnknownProperties) {
|
|
443
506
|
for (const key of Object.keys(object2)) {
|
|
@@ -449,26 +512,46 @@ class ObjectValidator extends Validator {
|
|
|
449
512
|
return object2;
|
|
450
513
|
},
|
|
451
514
|
(knownGoodValue, newValue) => {
|
|
515
|
+
if (Object.is(knownGoodValue, newValue)) {
|
|
516
|
+
return knownGoodValue;
|
|
517
|
+
}
|
|
452
518
|
if (typeof newValue !== "object" || newValue === null) {
|
|
453
519
|
throw new ValidationError(`Expected object, got ${typeToString(newValue)}`);
|
|
454
520
|
}
|
|
455
521
|
let isDifferent = false;
|
|
456
|
-
for (const
|
|
522
|
+
for (const key in config) {
|
|
523
|
+
if (!(0, import_utils.hasOwnProperty)(config, key)) continue;
|
|
524
|
+
const validator = config[key];
|
|
457
525
|
const prev = (0, import_utils.getOwnProperty)(knownGoodValue, key);
|
|
458
526
|
const next = (0, import_utils.getOwnProperty)(newValue, key);
|
|
459
527
|
if (Object.is(prev, next)) {
|
|
460
528
|
continue;
|
|
461
529
|
}
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
530
|
+
if (IS_DEV) {
|
|
531
|
+
const checked = prefixError(key, () => {
|
|
532
|
+
const validatable = validator;
|
|
533
|
+
if (validatable.validateUsingKnownGoodVersion) {
|
|
534
|
+
return validatable.validateUsingKnownGoodVersion(prev, next);
|
|
535
|
+
} else {
|
|
536
|
+
return validatable.validate(next);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
if (!Object.is(checked, prev)) {
|
|
540
|
+
isDifferent = true;
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
try {
|
|
544
|
+
const validatable = validator;
|
|
545
|
+
const checked = validatable.validateUsingKnownGoodVersion ? validatable.validateUsingKnownGoodVersion(prev, next) : validatable.validate(next);
|
|
546
|
+
if (!Object.is(checked, prev)) {
|
|
547
|
+
isDifferent = true;
|
|
548
|
+
}
|
|
549
|
+
} catch (err) {
|
|
550
|
+
if (err instanceof ValidationError) {
|
|
551
|
+
throw new ValidationError(err.rawMessage, [key, ...err.path]);
|
|
552
|
+
}
|
|
553
|
+
throw new ValidationError(err.toString(), [key]);
|
|
468
554
|
}
|
|
469
|
-
});
|
|
470
|
-
if (!Object.is(checked, prev)) {
|
|
471
|
-
isDifferent = true;
|
|
472
555
|
}
|
|
473
556
|
}
|
|
474
557
|
if (!shouldAllowUnknownProperties) {
|
|
@@ -576,8 +659,13 @@ class UnionValidator extends Validator {
|
|
|
576
659
|
throw new ValidationError(
|
|
577
660
|
`Expected a string for key "${this.key}", got ${typeToString(variant)}`
|
|
578
661
|
);
|
|
579
|
-
} else if (this.useNumberKeys
|
|
580
|
-
|
|
662
|
+
} else if (this.useNumberKeys) {
|
|
663
|
+
const numVariant = Number(variant);
|
|
664
|
+
if (numVariant - numVariant !== 0) {
|
|
665
|
+
throw new ValidationError(
|
|
666
|
+
`Expected a number for key "${this.key}", got "${variant}"`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
581
669
|
}
|
|
582
670
|
const matchingSchema = (0, import_utils.hasOwnProperty)(this.config, variant) ? this.config[variant] : void 0;
|
|
583
671
|
return { matchingSchema, variant };
|
|
@@ -613,11 +701,24 @@ class DictValidator extends Validator {
|
|
|
613
701
|
if (typeof object2 !== "object" || object2 === null) {
|
|
614
702
|
throw new ValidationError(`Expected object, got ${typeToString(object2)}`);
|
|
615
703
|
}
|
|
616
|
-
for (const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
704
|
+
for (const key in object2) {
|
|
705
|
+
if (!(0, import_utils.hasOwnProperty)(object2, key)) continue;
|
|
706
|
+
if (IS_DEV) {
|
|
707
|
+
prefixError(key, () => {
|
|
708
|
+
keyValidator.validate(key);
|
|
709
|
+
valueValidator.validate(object2[key]);
|
|
710
|
+
});
|
|
711
|
+
} else {
|
|
712
|
+
try {
|
|
713
|
+
keyValidator.validate(key);
|
|
714
|
+
valueValidator.validate(object2[key]);
|
|
715
|
+
} catch (err) {
|
|
716
|
+
if (err instanceof ValidationError) {
|
|
717
|
+
throw new ValidationError(err.rawMessage, [key, ...err.path]);
|
|
718
|
+
}
|
|
719
|
+
throw new ValidationError(err.toString(), [key]);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
621
722
|
}
|
|
622
723
|
return object2;
|
|
623
724
|
},
|
|
@@ -625,36 +726,71 @@ class DictValidator extends Validator {
|
|
|
625
726
|
if (typeof newValue !== "object" || newValue === null) {
|
|
626
727
|
throw new ValidationError(`Expected object, got ${typeToString(newValue)}`);
|
|
627
728
|
}
|
|
729
|
+
const newObj = newValue;
|
|
628
730
|
let isDifferent = false;
|
|
629
|
-
|
|
731
|
+
let newKeyCount = 0;
|
|
732
|
+
for (const key in newObj) {
|
|
733
|
+
if (!(0, import_utils.hasOwnProperty)(newObj, key)) continue;
|
|
734
|
+
newKeyCount++;
|
|
735
|
+
const next = newObj[key];
|
|
630
736
|
if (!(0, import_utils.hasOwnProperty)(knownGoodValue, key)) {
|
|
631
737
|
isDifferent = true;
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
738
|
+
if (IS_DEV) {
|
|
739
|
+
prefixError(key, () => {
|
|
740
|
+
keyValidator.validate(key);
|
|
741
|
+
valueValidator.validate(next);
|
|
742
|
+
});
|
|
743
|
+
} else {
|
|
744
|
+
try {
|
|
745
|
+
keyValidator.validate(key);
|
|
746
|
+
valueValidator.validate(next);
|
|
747
|
+
} catch (err) {
|
|
748
|
+
if (err instanceof ValidationError) {
|
|
749
|
+
throw new ValidationError(err.rawMessage, [key, ...err.path]);
|
|
750
|
+
}
|
|
751
|
+
throw new ValidationError(err.toString(), [key]);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
636
754
|
continue;
|
|
637
755
|
}
|
|
638
|
-
const prev =
|
|
639
|
-
const next = value;
|
|
756
|
+
const prev = knownGoodValue[key];
|
|
640
757
|
if (Object.is(prev, next)) {
|
|
641
758
|
continue;
|
|
642
759
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
760
|
+
if (IS_DEV) {
|
|
761
|
+
const checked = prefixError(key, () => {
|
|
762
|
+
if (valueValidator.validateUsingKnownGoodVersion) {
|
|
763
|
+
return valueValidator.validateUsingKnownGoodVersion(prev, next);
|
|
764
|
+
} else {
|
|
765
|
+
return valueValidator.validate(next);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
if (!Object.is(checked, prev)) {
|
|
769
|
+
isDifferent = true;
|
|
770
|
+
}
|
|
771
|
+
} else {
|
|
772
|
+
try {
|
|
773
|
+
const checked = valueValidator.validateUsingKnownGoodVersion ? valueValidator.validateUsingKnownGoodVersion(prev, next) : valueValidator.validate(next);
|
|
774
|
+
if (!Object.is(checked, prev)) {
|
|
775
|
+
isDifferent = true;
|
|
776
|
+
}
|
|
777
|
+
} catch (err) {
|
|
778
|
+
if (err instanceof ValidationError) {
|
|
779
|
+
throw new ValidationError(err.rawMessage, [key, ...err.path]);
|
|
780
|
+
}
|
|
781
|
+
throw new ValidationError(err.toString(), [key]);
|
|
648
782
|
}
|
|
649
|
-
});
|
|
650
|
-
if (!Object.is(checked, prev)) {
|
|
651
|
-
isDifferent = true;
|
|
652
783
|
}
|
|
653
784
|
}
|
|
654
|
-
|
|
655
|
-
|
|
785
|
+
if (!isDifferent) {
|
|
786
|
+
let oldKeyCount = 0;
|
|
787
|
+
for (const key in knownGoodValue) {
|
|
788
|
+
if ((0, import_utils.hasOwnProperty)(knownGoodValue, key)) {
|
|
789
|
+
oldKeyCount++;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (oldKeyCount !== newKeyCount) {
|
|
656
793
|
isDifferent = true;
|
|
657
|
-
break;
|
|
658
794
|
}
|
|
659
795
|
}
|
|
660
796
|
return isDifferent ? newValue : knownGoodValue;
|
|
@@ -675,28 +811,125 @@ function typeofValidator(type) {
|
|
|
675
811
|
const unknown = new Validator((value) => value);
|
|
676
812
|
const any = new Validator((value) => value);
|
|
677
813
|
const string = typeofValidator("string");
|
|
678
|
-
const number =
|
|
679
|
-
if (Number.
|
|
814
|
+
const number = new Validator((value) => {
|
|
815
|
+
if (Number.isFinite(value)) {
|
|
816
|
+
return value;
|
|
817
|
+
}
|
|
818
|
+
if (typeof value !== "number") {
|
|
819
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
820
|
+
}
|
|
821
|
+
if (value !== value) {
|
|
680
822
|
throw new ValidationError("Expected a number, got NaN");
|
|
681
823
|
}
|
|
682
|
-
|
|
683
|
-
|
|
824
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
825
|
+
});
|
|
826
|
+
const positiveNumber = new Validator((value) => {
|
|
827
|
+
if (Number.isFinite(value) && value >= 0) {
|
|
828
|
+
return value;
|
|
829
|
+
}
|
|
830
|
+
if (typeof value !== "number") {
|
|
831
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
832
|
+
}
|
|
833
|
+
if (value !== value) {
|
|
834
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
684
835
|
}
|
|
836
|
+
if (value < 0) {
|
|
837
|
+
throw new ValidationError(`Expected a positive number, got ${value}`);
|
|
838
|
+
}
|
|
839
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
685
840
|
});
|
|
686
|
-
const
|
|
687
|
-
if (value
|
|
841
|
+
const nonZeroNumber = new Validator((value) => {
|
|
842
|
+
if (Number.isFinite(value) && value > 0) {
|
|
843
|
+
return value;
|
|
844
|
+
}
|
|
845
|
+
if (typeof value !== "number") {
|
|
846
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
847
|
+
}
|
|
848
|
+
if (value !== value) {
|
|
849
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
850
|
+
}
|
|
851
|
+
if (value <= 0) {
|
|
852
|
+
throw new ValidationError(`Expected a non-zero positive number, got ${value}`);
|
|
853
|
+
}
|
|
854
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
855
|
+
});
|
|
856
|
+
const nonZeroFiniteNumber = new Validator((value) => {
|
|
857
|
+
if (Number.isFinite(value) && value !== 0) {
|
|
858
|
+
return value;
|
|
859
|
+
}
|
|
860
|
+
if (typeof value !== "number") {
|
|
861
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
862
|
+
}
|
|
863
|
+
if (value !== value) {
|
|
864
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
865
|
+
}
|
|
866
|
+
if (value === 0) {
|
|
867
|
+
throw new ValidationError(`Expected a non-zero number, got 0`);
|
|
868
|
+
}
|
|
869
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
688
870
|
});
|
|
689
|
-
const
|
|
690
|
-
if (value
|
|
871
|
+
const unitInterval = new Validator((value) => {
|
|
872
|
+
if (Number.isFinite(value) && value >= 0 && value <= 1) {
|
|
873
|
+
return value;
|
|
874
|
+
}
|
|
875
|
+
if (typeof value !== "number") {
|
|
876
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
877
|
+
}
|
|
878
|
+
if (value !== value) {
|
|
879
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
880
|
+
}
|
|
881
|
+
throw new ValidationError(`Expected a number between 0 and 1, got ${value}`);
|
|
691
882
|
});
|
|
692
|
-
const integer =
|
|
693
|
-
if (
|
|
883
|
+
const integer = new Validator((value) => {
|
|
884
|
+
if (Number.isInteger(value)) {
|
|
885
|
+
return value;
|
|
886
|
+
}
|
|
887
|
+
if (typeof value !== "number") {
|
|
888
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
889
|
+
}
|
|
890
|
+
if (value !== value) {
|
|
891
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
892
|
+
}
|
|
893
|
+
if (value - value !== 0) {
|
|
894
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
895
|
+
}
|
|
896
|
+
throw new ValidationError(`Expected an integer, got ${value}`);
|
|
694
897
|
});
|
|
695
|
-
const positiveInteger =
|
|
696
|
-
if (value
|
|
898
|
+
const positiveInteger = new Validator((value) => {
|
|
899
|
+
if (Number.isInteger(value) && value >= 0) {
|
|
900
|
+
return value;
|
|
901
|
+
}
|
|
902
|
+
if (typeof value !== "number") {
|
|
903
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
904
|
+
}
|
|
905
|
+
if (value !== value) {
|
|
906
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
907
|
+
}
|
|
908
|
+
if (value - value !== 0) {
|
|
909
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
910
|
+
}
|
|
911
|
+
if (value < 0) {
|
|
912
|
+
throw new ValidationError(`Expected a positive integer, got ${value}`);
|
|
913
|
+
}
|
|
914
|
+
throw new ValidationError(`Expected an integer, got ${value}`);
|
|
697
915
|
});
|
|
698
|
-
const nonZeroInteger =
|
|
699
|
-
if (value
|
|
916
|
+
const nonZeroInteger = new Validator((value) => {
|
|
917
|
+
if (Number.isInteger(value) && value > 0) {
|
|
918
|
+
return value;
|
|
919
|
+
}
|
|
920
|
+
if (typeof value !== "number") {
|
|
921
|
+
throw new ValidationError(`Expected number, got ${typeToString(value)}`);
|
|
922
|
+
}
|
|
923
|
+
if (value !== value) {
|
|
924
|
+
throw new ValidationError("Expected a number, got NaN");
|
|
925
|
+
}
|
|
926
|
+
if (value - value !== 0) {
|
|
927
|
+
throw new ValidationError(`Expected a finite number, got ${value}`);
|
|
928
|
+
}
|
|
929
|
+
if (value <= 0) {
|
|
930
|
+
throw new ValidationError(`Expected a non-zero positive integer, got ${value}`);
|
|
931
|
+
}
|
|
932
|
+
throw new ValidationError(`Expected an integer, got ${value}`);
|
|
700
933
|
});
|
|
701
934
|
const boolean = typeofValidator("boolean");
|
|
702
935
|
const bigint = typeofValidator("bigint");
|
|
@@ -862,13 +1095,14 @@ function optional(validator) {
|
|
|
862
1095
|
return validator.validate(value);
|
|
863
1096
|
},
|
|
864
1097
|
(knownGoodValue, newValue) => {
|
|
865
|
-
if (knownGoodValue === void 0 && newValue === void 0) return void 0;
|
|
866
1098
|
if (newValue === void 0) return void 0;
|
|
867
1099
|
if (validator.validateUsingKnownGoodVersion && knownGoodValue !== void 0) {
|
|
868
1100
|
return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue);
|
|
869
1101
|
}
|
|
870
1102
|
return validator.validate(newValue);
|
|
871
|
-
}
|
|
1103
|
+
},
|
|
1104
|
+
// Propagate skipSameValueCheck from inner validator to allow refine wrappers
|
|
1105
|
+
validator instanceof Validator && validator.skipSameValueCheck
|
|
872
1106
|
);
|
|
873
1107
|
}
|
|
874
1108
|
function nullable(validator) {
|
|
@@ -883,7 +1117,9 @@ function nullable(validator) {
|
|
|
883
1117
|
return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue);
|
|
884
1118
|
}
|
|
885
1119
|
return validator.validate(newValue);
|
|
886
|
-
}
|
|
1120
|
+
},
|
|
1121
|
+
// Propagate skipSameValueCheck from inner validator to allow refine wrappers
|
|
1122
|
+
validator instanceof Validator && validator.skipSameValueCheck
|
|
887
1123
|
);
|
|
888
1124
|
}
|
|
889
1125
|
function literalEnum(...values) {
|