@tldraw/validate 5.2.0-canary.49e2b474793c → 5.2.0-canary.4e00299c3e28

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/README.md CHANGED
@@ -32,6 +32,10 @@ queryValidator.validate(request.query)
32
32
 
33
33
  ## Documentation
34
34
 
35
+ Documentation for the most recent release can be found on [tldraw.dev/docs](https://tldraw.dev/docs), including [reference docs](https://tldraw.dev/reference/editor/Editor). Our release notes can be found [here](https://tldraw.dev/releases).
36
+
37
+ For more agent-friendly docs, see our [LLMs.txt](https://tldraw.dev/llms.txt).
38
+
35
39
  A `DOCS.md` file is included alongside this README in the published package, with detailed API documentation and usage examples.
36
40
 
37
41
  ## Contribution
@@ -712,7 +712,8 @@ export declare class UnionValidator<Key extends string, Config extends UnionVali
712
712
  */
713
713
  constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue, useNumberKeys: boolean);
714
714
  private expectObject;
715
- private getMatchingSchemaAndVariant;
715
+ private getVariant;
716
+ private getMatchingSchema;
716
717
  /**
717
718
  * Returns a new UnionValidator that can handle unknown variants using the provided function.
718
719
  *
@@ -781,14 +782,14 @@ declare const unitInterval: Validator<number>;
781
782
  declare const unknown: Validator<unknown>;
782
783
 
783
784
  /**
784
- * Validator that ensures a value is an object (non-null, non-array). Does not validate
785
- * the properties of the object.
785
+ * Validator that ensures a value is a non-null object. Does not validate the properties of
786
+ * the object. Note that arrays also pass this check.
786
787
  *
787
788
  * @example
788
789
  * ```ts
789
790
  * const obj = T.unknownObject.validate({ any: "properties" }) // Returns Record<string, unknown>
790
791
  * T.unknownObject.validate(null) // Throws ValidationError: "Expected object, got null"
791
- * T.unknownObject.validate([1, 2, 3]) // Throws ValidationError: "Expected object, got an array"
792
+ * T.unknownObject.validate([1, 2, 3]) // Returns the array (arrays pass the object check)
792
793
  * ```
793
794
  * @public
794
795
  */
package/dist-cjs/index.js CHANGED
@@ -41,7 +41,7 @@ var T = __toESM(require("./lib/validation"), 1);
41
41
  var import_validation = require("./lib/validation");
42
42
  (0, import_utils.registerTldrawLibraryVersion)(
43
43
  "@tldraw/validate",
44
- "5.2.0-canary.49e2b474793c",
44
+ "5.2.0-canary.4e00299c3e28",
45
45
  "cjs"
46
46
  );
47
47
  //# sourceMappingURL=index.js.map
@@ -95,7 +95,7 @@ class ValidationError extends Error {
95
95
  constructor(rawMessage, path = []) {
96
96
  const formattedPath = formatPath(path);
97
97
  const indentedMessage = rawMessage.split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
98
- super(path ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage);
98
+ super(formattedPath ? `At ${formattedPath}: ${indentedMessage}` : indentedMessage);
99
99
  this.rawMessage = rawMessage;
100
100
  this.path = path;
101
101
  }
@@ -103,15 +103,11 @@ class ValidationError extends Error {
103
103
  path;
104
104
  name = "ValidationError";
105
105
  }
106
- function prefixError(path, fn) {
107
- try {
108
- return fn();
109
- } catch (err) {
110
- if (err instanceof ValidationError) {
111
- throw new ValidationError(err.rawMessage, [path, ...err.path]);
112
- }
113
- throw new ValidationError(err.toString(), [path]);
106
+ function rethrowPrefixed(path, err) {
107
+ if (err instanceof ValidationError) {
108
+ throw new ValidationError(err.rawMessage, [path, ...err.path]);
114
109
  }
110
+ throw new ValidationError(err.toString(), [path]);
115
111
  }
116
112
  function typeToString(value) {
117
113
  if (value === null) return "null";
@@ -340,7 +336,11 @@ class Validator {
340
336
  check(nameOrCheckFn, checkFn) {
341
337
  if (typeof nameOrCheckFn === "string") {
342
338
  return this.refine((value) => {
343
- prefixError(`(check ${nameOrCheckFn})`, () => checkFn(value));
339
+ try {
340
+ checkFn(value);
341
+ } catch (err) {
342
+ rethrowPrefixed(`(check ${nameOrCheckFn})`, err);
343
+ }
344
344
  return value;
345
345
  });
346
346
  } else {
@@ -362,17 +362,10 @@ class ArrayOfValidator extends Validator {
362
362
  (value) => {
363
363
  const arr = array.validate(value);
364
364
  for (let i = 0; i < arr.length; i++) {
365
- if (IS_DEV) {
366
- prefixError(i, () => itemValidator.validate(arr[i]));
367
- } else {
368
- try {
369
- itemValidator.validate(arr[i]);
370
- } catch (err) {
371
- if (err instanceof ValidationError) {
372
- throw new ValidationError(err.rawMessage, [i, ...err.path]);
373
- }
374
- throw new ValidationError(err.toString(), [i]);
375
- }
365
+ try {
366
+ itemValidator.validate(arr[i]);
367
+ } catch (err) {
368
+ rethrowPrefixed(i, err);
376
369
  }
377
370
  }
378
371
  return arr;
@@ -388,46 +381,26 @@ class ArrayOfValidator extends Validator {
388
381
  const item = arr[i];
389
382
  if (i >= knownGoodValue.length) {
390
383
  isDifferent = true;
391
- if (IS_DEV) {
392
- prefixError(i, () => itemValidator.validate(item));
393
- } else {
394
- try {
395
- itemValidator.validate(item);
396
- } catch (err) {
397
- if (err instanceof ValidationError) {
398
- throw new ValidationError(err.rawMessage, [i, ...err.path]);
399
- }
400
- throw new ValidationError(err.toString(), [i]);
401
- }
384
+ try {
385
+ itemValidator.validate(item);
386
+ } catch (err) {
387
+ rethrowPrefixed(i, err);
402
388
  }
403
389
  continue;
404
390
  }
405
391
  if (Object.is(knownGoodValue[i], item)) {
406
392
  continue;
407
393
  }
408
- if (IS_DEV) {
409
- const checkedItem = prefixError(
410
- i,
411
- () => itemValidator.validateUsingKnownGoodVersion(knownGoodValue[i], item)
394
+ try {
395
+ const checkedItem = itemValidator.validateUsingKnownGoodVersion(
396
+ knownGoodValue[i],
397
+ item
412
398
  );
413
399
  if (!Object.is(checkedItem, knownGoodValue[i])) {
414
400
  isDifferent = true;
415
401
  }
416
- } else {
417
- try {
418
- const checkedItem = itemValidator.validateUsingKnownGoodVersion(
419
- knownGoodValue[i],
420
- item
421
- );
422
- if (!Object.is(checkedItem, knownGoodValue[i])) {
423
- isDifferent = true;
424
- }
425
- } catch (err) {
426
- if (err instanceof ValidationError) {
427
- throw new ValidationError(err.rawMessage, [i, ...err.path]);
428
- }
429
- throw new ValidationError(err.toString(), [i]);
430
- }
402
+ } catch (err) {
403
+ rethrowPrefixed(i, err);
431
404
  }
432
405
  }
433
406
  return isDifferent ? newValue : knownGoodValue;
@@ -483,33 +456,28 @@ class ObjectValidator extends Validator {
483
456
  * shouldAllowUnknownProperties - Whether to allow properties not defined in config
484
457
  */
485
458
  constructor(config, shouldAllowUnknownProperties = false) {
459
+ const configKeys = [];
460
+ const configValidators = [];
461
+ for (const [key, validator] of Object.entries(config)) {
462
+ configKeys.push(key);
463
+ configValidators.push(validator);
464
+ }
486
465
  super(
487
466
  (object2) => {
488
467
  if (typeof object2 !== "object" || object2 === null) {
489
468
  throw new ValidationError(`Expected object, got ${typeToString(object2)}`);
490
469
  }
491
- for (const key in config) {
492
- if (!(0, import_utils.hasOwnProperty)(config, key)) continue;
493
- const validator = config[key];
494
- if (IS_DEV) {
495
- prefixError(key, () => {
496
- ;
497
- validator.validate((0, import_utils.getOwnProperty)(object2, key));
498
- });
499
- } else {
500
- try {
501
- ;
502
- validator.validate((0, import_utils.getOwnProperty)(object2, key));
503
- } catch (err) {
504
- if (err instanceof ValidationError) {
505
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
506
- }
507
- throw new ValidationError(err.toString(), [key]);
508
- }
470
+ for (let i = 0; i < configKeys.length; i++) {
471
+ const key = configKeys[i];
472
+ try {
473
+ configValidators[i].validate((0, import_utils.getOwnProperty)(object2, key));
474
+ } catch (err) {
475
+ rethrowPrefixed(key, err);
509
476
  }
510
477
  }
511
478
  if (!shouldAllowUnknownProperties) {
512
- for (const key of Object.keys(object2)) {
479
+ for (const key in object2) {
480
+ if (!(0, import_utils.hasOwnProperty)(object2, key)) continue;
513
481
  if (!(0, import_utils.hasOwnProperty)(config, key)) {
514
482
  throw new ValidationError(`Unexpected property`, [key]);
515
483
  }
@@ -525,52 +493,45 @@ class ObjectValidator extends Validator {
525
493
  throw new ValidationError(`Expected object, got ${typeToString(newValue)}`);
526
494
  }
527
495
  let isDifferent = false;
528
- for (const key in config) {
529
- if (!(0, import_utils.hasOwnProperty)(config, key)) continue;
530
- const validator = config[key];
496
+ for (let i = 0; i < configKeys.length; i++) {
497
+ const key = configKeys[i];
531
498
  const prev = (0, import_utils.getOwnProperty)(knownGoodValue, key);
532
499
  const next = (0, import_utils.getOwnProperty)(newValue, key);
533
500
  if (Object.is(prev, next)) {
534
501
  continue;
535
502
  }
536
- if (IS_DEV) {
537
- const checked = prefixError(key, () => {
538
- const validatable = validator;
539
- if (validatable.validateUsingKnownGoodVersion) {
540
- return validatable.validateUsingKnownGoodVersion(prev, next);
541
- } else {
542
- return validatable.validate(next);
543
- }
544
- });
503
+ try {
504
+ const validator = configValidators[i];
505
+ const checked = validator.validateUsingKnownGoodVersion ? validator.validateUsingKnownGoodVersion(prev, next) : validator.validate(next);
545
506
  if (!Object.is(checked, prev)) {
546
507
  isDifferent = true;
547
508
  }
548
- } else {
549
- try {
550
- const validatable = validator;
551
- const checked = validatable.validateUsingKnownGoodVersion ? validatable.validateUsingKnownGoodVersion(prev, next) : validatable.validate(next);
552
- if (!Object.is(checked, prev)) {
553
- isDifferent = true;
554
- }
555
- } catch (err) {
556
- if (err instanceof ValidationError) {
557
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
558
- }
559
- throw new ValidationError(err.toString(), [key]);
560
- }
509
+ } catch (err) {
510
+ rethrowPrefixed(key, err);
561
511
  }
562
512
  }
563
513
  if (!shouldAllowUnknownProperties) {
564
- for (const key of Object.keys(newValue)) {
514
+ for (const key in newValue) {
515
+ if (!(0, import_utils.hasOwnProperty)(newValue, key)) continue;
565
516
  if (!(0, import_utils.hasOwnProperty)(config, key)) {
566
517
  throw new ValidationError(`Unexpected property`, [key]);
567
518
  }
568
519
  }
520
+ } else if (!isDifferent) {
521
+ for (const key of Object.keys(newValue)) {
522
+ if (!(0, import_utils.hasOwnProperty)(config, key) && !Object.is((0, import_utils.getOwnProperty)(knownGoodValue, key), (0, import_utils.getOwnProperty)(newValue, key))) {
523
+ isDifferent = true;
524
+ break;
525
+ }
526
+ }
569
527
  }
570
- for (const key of Object.keys(knownGoodValue)) {
571
- if (!(0, import_utils.hasOwnProperty)(newValue, key)) {
572
- isDifferent = true;
573
- break;
528
+ if (!isDifferent) {
529
+ for (const key in knownGoodValue) {
530
+ if (!(0, import_utils.hasOwnProperty)(knownGoodValue, key)) continue;
531
+ if (!(0, import_utils.hasOwnProperty)(newValue, key)) {
532
+ isDifferent = true;
533
+ break;
534
+ }
574
535
  }
575
536
  }
576
537
  return isDifferent ? newValue : knownGoodValue;
@@ -626,29 +587,35 @@ class UnionValidator extends Validator {
626
587
  super(
627
588
  (input) => {
628
589
  this.expectObject(input);
629
- const { matchingSchema, variant } = this.getMatchingSchemaAndVariant(input);
590
+ const matchingSchema = this.getMatchingSchema(input);
630
591
  if (matchingSchema === void 0) {
631
- return this.unknownValueValidation(input, variant);
592
+ return this.unknownValueValidation(input, this.getVariant(input));
593
+ }
594
+ try {
595
+ return matchingSchema.validate(input);
596
+ } catch (err) {
597
+ rethrowPrefixed(`(${key} = ${this.getVariant(input)})`, err);
632
598
  }
633
- return prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(input));
634
599
  },
635
600
  (prevValue, newValue) => {
636
601
  this.expectObject(newValue);
637
602
  this.expectObject(prevValue);
638
- const { matchingSchema, variant } = this.getMatchingSchemaAndVariant(newValue);
603
+ const matchingSchema = this.getMatchingSchema(newValue);
639
604
  if (matchingSchema === void 0) {
640
- return this.unknownValueValidation(newValue, variant);
641
- }
642
- if ((0, import_utils.getOwnProperty)(prevValue, key) !== (0, import_utils.getOwnProperty)(newValue, key)) {
643
- return prefixError(`(${key} = ${variant})`, () => matchingSchema.validate(newValue));
605
+ return this.unknownValueValidation(newValue, this.getVariant(newValue));
644
606
  }
645
- return prefixError(`(${key} = ${variant})`, () => {
607
+ try {
608
+ if ((0, import_utils.getOwnProperty)(prevValue, key) !== (0, import_utils.getOwnProperty)(newValue, key)) {
609
+ return matchingSchema.validate(newValue);
610
+ }
646
611
  if (matchingSchema.validateUsingKnownGoodVersion) {
647
612
  return matchingSchema.validateUsingKnownGoodVersion(prevValue, newValue);
648
613
  } else {
649
614
  return matchingSchema.validate(newValue);
650
615
  }
651
- });
616
+ } catch (err) {
617
+ rethrowPrefixed(`(${key} = ${this.getVariant(newValue)})`, err);
618
+ }
652
619
  }
653
620
  );
654
621
  this.key = key;
@@ -665,7 +632,13 @@ class UnionValidator extends Validator {
665
632
  throw new ValidationError(`Expected an object, got ${typeToString(value)}`, []);
666
633
  }
667
634
  }
668
- getMatchingSchemaAndVariant(object2) {
635
+ getVariant(object2) {
636
+ return (0, import_utils.getOwnProperty)(object2, this.key);
637
+ }
638
+ // Returns the matching schema for the object's variant, or undefined if the variant is
639
+ // unknown. The variant itself is only needed on cold paths (unknown variants and errors),
640
+ // so this avoids allocating a `{ matchingSchema, variant }` result per validation.
641
+ getMatchingSchema(object2) {
669
642
  const variant = (0, import_utils.getOwnProperty)(object2, this.key);
670
643
  if (!this.useNumberKeys && typeof variant !== "string") {
671
644
  throw new ValidationError(
@@ -679,8 +652,7 @@ class UnionValidator extends Validator {
679
652
  );
680
653
  }
681
654
  }
682
- const matchingSchema = (0, import_utils.hasOwnProperty)(this.config, variant) ? this.config[variant] : void 0;
683
- return { matchingSchema, variant };
655
+ return (0, import_utils.hasOwnProperty)(this.config, variant) ? this.config[variant] : void 0;
684
656
  }
685
657
  /**
686
658
  * Returns a new UnionValidator that can handle unknown variants using the provided function.
@@ -715,21 +687,11 @@ class DictValidator extends Validator {
715
687
  }
716
688
  for (const key in object2) {
717
689
  if (!(0, import_utils.hasOwnProperty)(object2, key)) continue;
718
- if (IS_DEV) {
719
- prefixError(key, () => {
720
- keyValidator.validate(key);
721
- valueValidator.validate(object2[key]);
722
- });
723
- } else {
724
- try {
725
- keyValidator.validate(key);
726
- valueValidator.validate(object2[key]);
727
- } catch (err) {
728
- if (err instanceof ValidationError) {
729
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
730
- }
731
- throw new ValidationError(err.toString(), [key]);
732
- }
690
+ try {
691
+ keyValidator.validate(key);
692
+ valueValidator.validate(object2[key]);
693
+ } catch (err) {
694
+ rethrowPrefixed(key, err);
733
695
  }
734
696
  }
735
697
  return object2;
@@ -747,21 +709,11 @@ class DictValidator extends Validator {
747
709
  const next = newObj[key];
748
710
  if (!(0, import_utils.hasOwnProperty)(knownGoodValue, key)) {
749
711
  isDifferent = true;
750
- if (IS_DEV) {
751
- prefixError(key, () => {
752
- keyValidator.validate(key);
753
- valueValidator.validate(next);
754
- });
755
- } else {
756
- try {
757
- keyValidator.validate(key);
758
- valueValidator.validate(next);
759
- } catch (err) {
760
- if (err instanceof ValidationError) {
761
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
762
- }
763
- throw new ValidationError(err.toString(), [key]);
764
- }
712
+ try {
713
+ keyValidator.validate(key);
714
+ valueValidator.validate(next);
715
+ } catch (err) {
716
+ rethrowPrefixed(key, err);
765
717
  }
766
718
  continue;
767
719
  }
@@ -769,29 +721,13 @@ class DictValidator extends Validator {
769
721
  if (Object.is(prev, next)) {
770
722
  continue;
771
723
  }
772
- if (IS_DEV) {
773
- const checked = prefixError(key, () => {
774
- if (valueValidator.validateUsingKnownGoodVersion) {
775
- return valueValidator.validateUsingKnownGoodVersion(prev, next);
776
- } else {
777
- return valueValidator.validate(next);
778
- }
779
- });
724
+ try {
725
+ const checked = valueValidator.validateUsingKnownGoodVersion ? valueValidator.validateUsingKnownGoodVersion(prev, next) : valueValidator.validate(next);
780
726
  if (!Object.is(checked, prev)) {
781
727
  isDifferent = true;
782
728
  }
783
- } else {
784
- try {
785
- const checked = valueValidator.validateUsingKnownGoodVersion ? valueValidator.validateUsingKnownGoodVersion(prev, next) : valueValidator.validate(next);
786
- if (!Object.is(checked, prev)) {
787
- isDifferent = true;
788
- }
789
- } catch (err) {
790
- if (err instanceof ValidationError) {
791
- throw new ValidationError(err.rawMessage, [key, ...err.path]);
792
- }
793
- throw new ValidationError(err.toString(), [key]);
794
- }
729
+ } catch (err) {
730
+ rethrowPrefixed(key, err);
795
731
  }
796
732
  }
797
733
  if (!isDifferent) {
@@ -981,10 +917,17 @@ function isValidJson(value) {
981
917
  return true;
982
918
  }
983
919
  if (Array.isArray(value)) {
984
- return value.every(isValidJson);
920
+ for (let i = 0; i < value.length; i++) {
921
+ if (!isValidJson(value[i])) return false;
922
+ }
923
+ return true;
985
924
  }
986
925
  if (isPlainObject(value)) {
987
- return Object.values(value).every(isValidJson);
926
+ for (const key in value) {
927
+ if (!(0, import_utils.hasOwnProperty)(value, key)) continue;
928
+ if (!isValidJson(value[key])) return false;
929
+ }
930
+ return true;
988
931
  }
989
932
  return false;
990
933
  }
@@ -1017,7 +960,8 @@ const jsonValue = new Validator(
1017
960
  return isDifferent ? newValue : knownGoodValue;
1018
961
  } else if (isPlainObject(knownGoodValue) && isPlainObject(newValue)) {
1019
962
  let isDifferent = false;
1020
- for (const key of Object.keys(newValue)) {
963
+ for (const key in newValue) {
964
+ if (!(0, import_utils.hasOwnProperty)(newValue, key)) continue;
1021
965
  if (!(0, import_utils.hasOwnProperty)(knownGoodValue, key)) {
1022
966
  isDifferent = true;
1023
967
  jsonValue.validate(newValue[key]);
@@ -1033,10 +977,13 @@ const jsonValue = new Validator(
1033
977
  isDifferent = true;
1034
978
  }
1035
979
  }
1036
- for (const key of Object.keys(knownGoodValue)) {
1037
- if (!(0, import_utils.hasOwnProperty)(newValue, key)) {
1038
- isDifferent = true;
1039
- break;
980
+ if (!isDifferent) {
981
+ for (const key in knownGoodValue) {
982
+ if (!(0, import_utils.hasOwnProperty)(knownGoodValue, key)) continue;
983
+ if (!(0, import_utils.hasOwnProperty)(newValue, key)) {
984
+ isDifferent = true;
985
+ break;
986
+ }
1040
987
  }
1041
988
  }
1042
989
  return isDifferent ? newValue : knownGoodValue;
@@ -1080,16 +1027,22 @@ function numberUnion(key, config) {
1080
1027
  function model(name, validator) {
1081
1028
  return new Validator(
1082
1029
  (value) => {
1083
- return prefixError(name, () => validator.validate(value));
1030
+ try {
1031
+ return validator.validate(value);
1032
+ } catch (err) {
1033
+ rethrowPrefixed(name, err);
1034
+ }
1084
1035
  },
1085
1036
  (prevValue, newValue) => {
1086
- return prefixError(name, () => {
1037
+ try {
1087
1038
  if (validator.validateUsingKnownGoodVersion) {
1088
1039
  return validator.validateUsingKnownGoodVersion(prevValue, newValue);
1089
1040
  } else {
1090
1041
  return validator.validate(newValue);
1091
1042
  }
1092
- });
1043
+ } catch (err) {
1044
+ rethrowPrefixed(name, err);
1045
+ }
1093
1046
  }
1094
1047
  );
1095
1048
  }