@tldraw/validate 4.2.2 → 4.2.3

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.
@@ -5,7 +5,6 @@ import {
5
5
  hasOwnProperty,
6
6
  validateIndexKey
7
7
  } from "@tldraw/utils";
8
- const IS_DEV = process.env.NODE_ENV !== "production";
9
8
  function formatPath(path) {
10
9
  if (!path.length) {
11
10
  return null;
@@ -82,12 +81,10 @@ class Validator {
82
81
  *
83
82
  * validationFn - Function that validates and returns a value of type T
84
83
  * validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
85
- * skipSameValueCheck - Internal flag to skip dev check for validators that transform values
86
84
  */
87
- constructor(validationFn, validateUsingKnownGoodVersionFn, skipSameValueCheck = false) {
85
+ constructor(validationFn, validateUsingKnownGoodVersionFn) {
88
86
  this.validationFn = validationFn;
89
87
  this.validateUsingKnownGoodVersionFn = validateUsingKnownGoodVersionFn;
90
- this.skipSameValueCheck = skipSameValueCheck;
91
88
  }
92
89
  /**
93
90
  * Validates an unknown value and returns it with the correct type. The returned value is
@@ -111,7 +108,7 @@ class Validator {
111
108
  */
112
109
  validate(value) {
113
110
  const validated = this.validationFn(value);
114
- if (IS_DEV && !this.skipSameValueCheck && !Object.is(value, validated)) {
111
+ if (process.env.NODE_ENV !== "production" && !Object.is(value, validated)) {
115
112
  throw new ValidationError("Validator functions must return the same value they were passed");
116
113
  }
117
114
  return validated;
@@ -272,9 +269,7 @@ class Validator {
272
269
  return knownGoodValue;
273
270
  }
274
271
  return otherValidationFn(validated);
275
- },
276
- true
277
- // skipSameValueCheck: refine is designed to transform values
272
+ }
278
273
  );
279
274
  }
280
275
  check(nameOrCheckFn, checkFn) {
@@ -302,25 +297,11 @@ class ArrayOfValidator extends Validator {
302
297
  (value) => {
303
298
  const arr = array.validate(value);
304
299
  for (let i = 0; i < arr.length; i++) {
305
- if (IS_DEV) {
306
- prefixError(i, () => itemValidator.validate(arr[i]));
307
- } else {
308
- try {
309
- itemValidator.validate(arr[i]);
310
- } catch (err) {
311
- if (err instanceof ValidationError) {
312
- throw new ValidationError(err.rawMessage, [i, ...err.path]);
313
- }
314
- throw new ValidationError(err.toString(), [i]);
315
- }
316
- }
300
+ prefixError(i, () => itemValidator.validate(arr[i]));
317
301
  }
318
302
  return arr;
319
303
  },
320
304
  (knownGoodValue, newValue) => {
321
- if (Object.is(knownGoodValue, newValue)) {
322
- return knownGoodValue;
323
- }
324
305
  if (!itemValidator.validateUsingKnownGoodVersion) return this.validate(newValue);
325
306
  const arr = array.validate(newValue);
326
307
  let isDifferent = knownGoodValue.length !== arr.length;
@@ -328,46 +309,18 @@ class ArrayOfValidator extends Validator {
328
309
  const item = arr[i];
329
310
  if (i >= knownGoodValue.length) {
330
311
  isDifferent = true;
331
- if (IS_DEV) {
332
- prefixError(i, () => itemValidator.validate(item));
333
- } else {
334
- try {
335
- itemValidator.validate(item);
336
- } catch (err) {
337
- if (err instanceof ValidationError) {
338
- throw new ValidationError(err.rawMessage, [i, ...err.path]);
339
- }
340
- throw new ValidationError(err.toString(), [i]);
341
- }
342
- }
312
+ prefixError(i, () => itemValidator.validate(item));
343
313
  continue;
344
314
  }
345
315
  if (Object.is(knownGoodValue[i], item)) {
346
316
  continue;
347
317
  }
348
- if (IS_DEV) {
349
- const checkedItem = prefixError(
350
- i,
351
- () => itemValidator.validateUsingKnownGoodVersion(knownGoodValue[i], item)
352
- );
353
- if (!Object.is(checkedItem, knownGoodValue[i])) {
354
- isDifferent = true;
355
- }
356
- } else {
357
- try {
358
- const checkedItem = itemValidator.validateUsingKnownGoodVersion(
359
- knownGoodValue[i],
360
- item
361
- );
362
- if (!Object.is(checkedItem, knownGoodValue[i])) {
363
- isDifferent = true;
364
- }
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
- }
318
+ const checkedItem = prefixError(
319
+ i,
320
+ () => itemValidator.validateUsingKnownGoodVersion(knownGoodValue[i], item)
321
+ );
322
+ if (!Object.is(checkedItem, knownGoodValue[i])) {
323
+ isDifferent = true;
371
324
  }
372
325
  }
373
326
  return isDifferent ? newValue : knownGoodValue;
@@ -427,25 +380,11 @@ class ObjectValidator extends Validator {
427
380
  if (typeof object2 !== "object" || object2 === null) {
428
381
  throw new ValidationError(`Expected object, got ${typeToString(object2)}`);
429
382
  }
430
- for (const key in config) {
431
- if (!hasOwnProperty(config, key)) continue;
432
- const validator = config[key];
433
- if (IS_DEV) {
434
- prefixError(key, () => {
435
- ;
436
- validator.validate(getOwnProperty(object2, key));
437
- });
438
- } else {
439
- try {
440
- ;
441
- validator.validate(getOwnProperty(object2, key));
442
- } catch (err) {
443
- if (err instanceof ValidationError) {
444
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
445
- }
446
- throw new ValidationError(err.toString(), [key]);
447
- }
448
- }
383
+ for (const [key, validator] of Object.entries(config)) {
384
+ prefixError(key, () => {
385
+ ;
386
+ validator.validate(getOwnProperty(object2, key));
387
+ });
449
388
  }
450
389
  if (!shouldAllowUnknownProperties) {
451
390
  for (const key of Object.keys(object2)) {
@@ -457,46 +396,26 @@ class ObjectValidator extends Validator {
457
396
  return object2;
458
397
  },
459
398
  (knownGoodValue, newValue) => {
460
- if (Object.is(knownGoodValue, newValue)) {
461
- return knownGoodValue;
462
- }
463
399
  if (typeof newValue !== "object" || newValue === null) {
464
400
  throw new ValidationError(`Expected object, got ${typeToString(newValue)}`);
465
401
  }
466
402
  let isDifferent = false;
467
- for (const key in config) {
468
- if (!hasOwnProperty(config, key)) continue;
469
- const validator = config[key];
403
+ for (const [key, validator] of Object.entries(config)) {
470
404
  const prev = getOwnProperty(knownGoodValue, key);
471
405
  const next = getOwnProperty(newValue, key);
472
406
  if (Object.is(prev, next)) {
473
407
  continue;
474
408
  }
475
- if (IS_DEV) {
476
- const checked = prefixError(key, () => {
477
- const validatable = validator;
478
- if (validatable.validateUsingKnownGoodVersion) {
479
- return validatable.validateUsingKnownGoodVersion(prev, next);
480
- } else {
481
- return validatable.validate(next);
482
- }
483
- });
484
- if (!Object.is(checked, prev)) {
485
- isDifferent = true;
486
- }
487
- } else {
488
- try {
489
- const validatable = validator;
490
- const checked = validatable.validateUsingKnownGoodVersion ? validatable.validateUsingKnownGoodVersion(prev, next) : validatable.validate(next);
491
- if (!Object.is(checked, prev)) {
492
- isDifferent = true;
493
- }
494
- } catch (err) {
495
- if (err instanceof ValidationError) {
496
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
497
- }
498
- throw new ValidationError(err.toString(), [key]);
409
+ const checked = prefixError(key, () => {
410
+ const validatable = validator;
411
+ if (validatable.validateUsingKnownGoodVersion) {
412
+ return validatable.validateUsingKnownGoodVersion(prev, next);
413
+ } else {
414
+ return validatable.validate(next);
499
415
  }
416
+ });
417
+ if (!Object.is(checked, prev)) {
418
+ isDifferent = true;
500
419
  }
501
420
  }
502
421
  if (!shouldAllowUnknownProperties) {
@@ -604,13 +523,8 @@ class UnionValidator extends Validator {
604
523
  throw new ValidationError(
605
524
  `Expected a string for key "${this.key}", got ${typeToString(variant)}`
606
525
  );
607
- } else if (this.useNumberKeys) {
608
- const numVariant = Number(variant);
609
- if (numVariant - numVariant !== 0) {
610
- throw new ValidationError(
611
- `Expected a number for key "${this.key}", got "${variant}"`
612
- );
613
- }
526
+ } else if (this.useNumberKeys && !Number.isFinite(Number(variant))) {
527
+ throw new ValidationError(`Expected a number for key "${this.key}", got "${variant}"`);
614
528
  }
615
529
  const matchingSchema = hasOwnProperty(this.config, variant) ? this.config[variant] : void 0;
616
530
  return { matchingSchema, variant };
@@ -646,24 +560,11 @@ class DictValidator extends Validator {
646
560
  if (typeof object2 !== "object" || object2 === null) {
647
561
  throw new ValidationError(`Expected object, got ${typeToString(object2)}`);
648
562
  }
649
- for (const key in object2) {
650
- if (!hasOwnProperty(object2, key)) continue;
651
- if (IS_DEV) {
652
- prefixError(key, () => {
653
- keyValidator.validate(key);
654
- valueValidator.validate(object2[key]);
655
- });
656
- } else {
657
- try {
658
- keyValidator.validate(key);
659
- valueValidator.validate(object2[key]);
660
- } catch (err) {
661
- if (err instanceof ValidationError) {
662
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
663
- }
664
- throw new ValidationError(err.toString(), [key]);
665
- }
666
- }
563
+ for (const [key, value] of Object.entries(object2)) {
564
+ prefixError(key, () => {
565
+ keyValidator.validate(key);
566
+ valueValidator.validate(value);
567
+ });
667
568
  }
668
569
  return object2;
669
570
  },
@@ -671,71 +572,36 @@ class DictValidator extends Validator {
671
572
  if (typeof newValue !== "object" || newValue === null) {
672
573
  throw new ValidationError(`Expected object, got ${typeToString(newValue)}`);
673
574
  }
674
- const newObj = newValue;
675
575
  let isDifferent = false;
676
- let newKeyCount = 0;
677
- for (const key in newObj) {
678
- if (!hasOwnProperty(newObj, key)) continue;
679
- newKeyCount++;
680
- const next = newObj[key];
576
+ for (const [key, value] of Object.entries(newValue)) {
681
577
  if (!hasOwnProperty(knownGoodValue, key)) {
682
578
  isDifferent = true;
683
- if (IS_DEV) {
684
- prefixError(key, () => {
685
- keyValidator.validate(key);
686
- valueValidator.validate(next);
687
- });
688
- } else {
689
- try {
690
- keyValidator.validate(key);
691
- valueValidator.validate(next);
692
- } catch (err) {
693
- if (err instanceof ValidationError) {
694
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
695
- }
696
- throw new ValidationError(err.toString(), [key]);
697
- }
698
- }
579
+ prefixError(key, () => {
580
+ keyValidator.validate(key);
581
+ valueValidator.validate(value);
582
+ });
699
583
  continue;
700
584
  }
701
- const prev = knownGoodValue[key];
585
+ const prev = getOwnProperty(knownGoodValue, key);
586
+ const next = value;
702
587
  if (Object.is(prev, next)) {
703
588
  continue;
704
589
  }
705
- if (IS_DEV) {
706
- const checked = prefixError(key, () => {
707
- if (valueValidator.validateUsingKnownGoodVersion) {
708
- return valueValidator.validateUsingKnownGoodVersion(prev, next);
709
- } else {
710
- return valueValidator.validate(next);
711
- }
712
- });
713
- if (!Object.is(checked, prev)) {
714
- isDifferent = true;
715
- }
716
- } else {
717
- try {
718
- const checked = valueValidator.validateUsingKnownGoodVersion ? valueValidator.validateUsingKnownGoodVersion(prev, next) : valueValidator.validate(next);
719
- if (!Object.is(checked, prev)) {
720
- isDifferent = true;
721
- }
722
- } catch (err) {
723
- if (err instanceof ValidationError) {
724
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
725
- }
726
- throw new ValidationError(err.toString(), [key]);
590
+ const checked = prefixError(key, () => {
591
+ if (valueValidator.validateUsingKnownGoodVersion) {
592
+ return valueValidator.validateUsingKnownGoodVersion(prev, next);
593
+ } else {
594
+ return valueValidator.validate(next);
727
595
  }
596
+ });
597
+ if (!Object.is(checked, prev)) {
598
+ isDifferent = true;
728
599
  }
729
600
  }
730
- if (!isDifferent) {
731
- let oldKeyCount = 0;
732
- for (const key in knownGoodValue) {
733
- if (hasOwnProperty(knownGoodValue, key)) {
734
- oldKeyCount++;
735
- }
736
- }
737
- if (oldKeyCount !== newKeyCount) {
601
+ for (const key of Object.keys(knownGoodValue)) {
602
+ if (!hasOwnProperty(newValue, key)) {
738
603
  isDifferent = true;
604
+ break;
739
605
  }
740
606
  }
741
607
  return isDifferent ? newValue : knownGoodValue;
@@ -756,125 +622,28 @@ function typeofValidator(type) {
756
622
  const unknown = new Validator((value) => value);
757
623
  const any = new Validator((value) => value);
758
624
  const string = typeofValidator("string");
759
- const number = new Validator((value) => {
760
- if (Number.isFinite(value)) {
761
- return value;
762
- }
763
- if (typeof value !== "number") {
764
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
765
- }
766
- if (value !== value) {
625
+ const number = typeofValidator("number").check((number2) => {
626
+ if (Number.isNaN(number2)) {
767
627
  throw new ValidationError("Expected a number, got NaN");
768
628
  }
769
- throw new ValidationError(`Expected a finite number, got ${value}`);
770
- });
771
- const positiveNumber = new Validator((value) => {
772
- if (Number.isFinite(value) && value >= 0) {
773
- return value;
774
- }
775
- if (typeof value !== "number") {
776
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
777
- }
778
- if (value !== value) {
779
- throw new ValidationError("Expected a number, got NaN");
629
+ if (!Number.isFinite(number2)) {
630
+ throw new ValidationError(`Expected a finite number, got ${number2}`);
780
631
  }
781
- if (value < 0) {
782
- throw new ValidationError(`Expected a positive number, got ${value}`);
783
- }
784
- throw new ValidationError(`Expected a finite number, got ${value}`);
785
632
  });
786
- const nonZeroNumber = new Validator((value) => {
787
- if (Number.isFinite(value) && value > 0) {
788
- return value;
789
- }
790
- if (typeof value !== "number") {
791
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
792
- }
793
- if (value !== value) {
794
- throw new ValidationError("Expected a number, got NaN");
795
- }
796
- if (value <= 0) {
797
- throw new ValidationError(`Expected a non-zero positive number, got ${value}`);
798
- }
799
- throw new ValidationError(`Expected a finite number, got ${value}`);
800
- });
801
- const nonZeroFiniteNumber = new Validator((value) => {
802
- if (Number.isFinite(value) && value !== 0) {
803
- return value;
804
- }
805
- if (typeof value !== "number") {
806
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
807
- }
808
- if (value !== value) {
809
- throw new ValidationError("Expected a number, got NaN");
810
- }
811
- if (value === 0) {
812
- throw new ValidationError(`Expected a non-zero number, got 0`);
813
- }
814
- throw new ValidationError(`Expected a finite number, got ${value}`);
633
+ const positiveNumber = number.check((value) => {
634
+ if (value < 0) throw new ValidationError(`Expected a positive number, got ${value}`);
815
635
  });
816
- const unitInterval = new Validator((value) => {
817
- if (Number.isFinite(value) && value >= 0 && value <= 1) {
818
- return value;
819
- }
820
- if (typeof value !== "number") {
821
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
822
- }
823
- if (value !== value) {
824
- throw new ValidationError("Expected a number, got NaN");
825
- }
826
- throw new ValidationError(`Expected a number between 0 and 1, got ${value}`);
636
+ const nonZeroNumber = number.check((value) => {
637
+ if (value <= 0) throw new ValidationError(`Expected a non-zero positive number, got ${value}`);
827
638
  });
828
- const integer = new Validator((value) => {
829
- if (Number.isInteger(value)) {
830
- return value;
831
- }
832
- if (typeof value !== "number") {
833
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
834
- }
835
- if (value !== value) {
836
- throw new ValidationError("Expected a number, got NaN");
837
- }
838
- if (value - value !== 0) {
839
- throw new ValidationError(`Expected a finite number, got ${value}`);
840
- }
841
- throw new ValidationError(`Expected an integer, got ${value}`);
639
+ const integer = number.check((value) => {
640
+ if (!Number.isInteger(value)) throw new ValidationError(`Expected an integer, got ${value}`);
842
641
  });
843
- const positiveInteger = new Validator((value) => {
844
- if (Number.isInteger(value) && value >= 0) {
845
- return value;
846
- }
847
- if (typeof value !== "number") {
848
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
849
- }
850
- if (value !== value) {
851
- throw new ValidationError("Expected a number, got NaN");
852
- }
853
- if (value - value !== 0) {
854
- throw new ValidationError(`Expected a finite number, got ${value}`);
855
- }
856
- if (value < 0) {
857
- throw new ValidationError(`Expected a positive integer, got ${value}`);
858
- }
859
- throw new ValidationError(`Expected an integer, got ${value}`);
642
+ const positiveInteger = integer.check((value) => {
643
+ if (value < 0) throw new ValidationError(`Expected a positive integer, got ${value}`);
860
644
  });
861
- const nonZeroInteger = new Validator((value) => {
862
- if (Number.isInteger(value) && value > 0) {
863
- return value;
864
- }
865
- if (typeof value !== "number") {
866
- throw new ValidationError(`Expected number, got ${typeToString(value)}`);
867
- }
868
- if (value !== value) {
869
- throw new ValidationError("Expected a number, got NaN");
870
- }
871
- if (value - value !== 0) {
872
- throw new ValidationError(`Expected a finite number, got ${value}`);
873
- }
874
- if (value <= 0) {
875
- throw new ValidationError(`Expected a non-zero positive integer, got ${value}`);
876
- }
877
- throw new ValidationError(`Expected an integer, got ${value}`);
645
+ const nonZeroInteger = integer.check((value) => {
646
+ if (value <= 0) throw new ValidationError(`Expected a non-zero positive integer, got ${value}`);
878
647
  });
879
648
  const boolean = typeofValidator("boolean");
880
649
  const bigint = typeofValidator("bigint");
@@ -1040,14 +809,13 @@ function optional(validator) {
1040
809
  return validator.validate(value);
1041
810
  },
1042
811
  (knownGoodValue, newValue) => {
812
+ if (knownGoodValue === void 0 && newValue === void 0) return void 0;
1043
813
  if (newValue === void 0) return void 0;
1044
814
  if (validator.validateUsingKnownGoodVersion && knownGoodValue !== void 0) {
1045
815
  return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue);
1046
816
  }
1047
817
  return validator.validate(newValue);
1048
- },
1049
- // Propagate skipSameValueCheck from inner validator to allow refine wrappers
1050
- validator instanceof Validator && validator.skipSameValueCheck
818
+ }
1051
819
  );
1052
820
  }
1053
821
  function nullable(validator) {
@@ -1062,9 +830,7 @@ function nullable(validator) {
1062
830
  return validator.validateUsingKnownGoodVersion(knownGoodValue, newValue);
1063
831
  }
1064
832
  return validator.validate(newValue);
1065
- },
1066
- // Propagate skipSameValueCheck from inner validator to allow refine wrappers
1067
- validator instanceof Validator && validator.skipSameValueCheck
833
+ }
1068
834
  );
1069
835
  }
1070
836
  function literalEnum(...values) {
@@ -1152,7 +918,6 @@ export {
1152
918
  literal,
1153
919
  literalEnum,
1154
920
  model,
1155
- nonZeroFiniteNumber,
1156
921
  nonZeroInteger,
1157
922
  nonZeroNumber,
1158
923
  nullable,
@@ -1167,7 +932,6 @@ export {
1167
932
  srcUrl,
1168
933
  string,
1169
934
  union,
1170
- unitInterval,
1171
935
  unknown,
1172
936
  unknownObject
1173
937
  };