@oxog/vld 2.0.1 → 2.0.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +20 -20
  3. package/README.md +2 -2
  4. package/dist/chunks/{bigint-ZKkWLdmi.js → bigint-DgsCr2dC.js} +96 -15
  5. package/dist/chunks/bigint-DgsCr2dC.js.map +1 -0
  6. package/dist/chunks/{date-7Iz2BGsL.js → date-ODue_rtq.js} +2 -2
  7. package/dist/chunks/{date-7Iz2BGsL.js.map → date-ODue_rtq.js.map} +1 -1
  8. package/dist/chunks/{index-eWXdjyyy.js → index-BZqWZvVe.js} +4 -4
  9. package/dist/chunks/{index-eWXdjyyy.js.map → index-BZqWZvVe.js.map} +1 -1
  10. package/dist/chunks/{index-BoV-4S1F.js → index-CETyGkrv.js} +3 -3
  11. package/dist/chunks/index-CETyGkrv.js.map +1 -0
  12. package/dist/chunks/{json-nIhyRPOU.js → json-o20GFhTh.js} +225 -138
  13. package/dist/chunks/json-o20GFhTh.js.map +1 -0
  14. package/dist/chunks/{unknown-CjSRcELI.js → unknown-SLIH1VCf.js} +2 -2
  15. package/dist/chunks/unknown-SLIH1VCf.js.map +1 -0
  16. package/dist/cjs/index.cjs +318 -150
  17. package/dist/cjs/index.cjs.map +1 -1
  18. package/dist/cjs/locales/index.cjs.map +1 -1
  19. package/dist/cjs/mini.cjs +317 -149
  20. package/dist/cjs/mini.cjs.map +1 -1
  21. package/dist/codecs/index.js +3 -3
  22. package/dist/coercion/index.js +2 -2
  23. package/dist/coercion/index.js.map +1 -1
  24. package/dist/index.js +8 -8
  25. package/dist/mini.js +5 -5
  26. package/dist/validators/array.d.ts +5 -0
  27. package/dist/validators/array.d.ts.map +1 -1
  28. package/dist/validators/discriminated-union.d.ts.map +1 -1
  29. package/dist/validators/enum.d.ts +5 -1
  30. package/dist/validators/enum.d.ts.map +1 -1
  31. package/dist/validators/index.js +4 -4
  32. package/dist/validators/lazy.d.ts +8 -1
  33. package/dist/validators/lazy.d.ts.map +1 -1
  34. package/dist/validators/literal.d.ts +5 -1
  35. package/dist/validators/literal.d.ts.map +1 -1
  36. package/dist/validators/object.d.ts +30 -3
  37. package/dist/validators/object.d.ts.map +1 -1
  38. package/dist/validators/string.d.ts +12 -1
  39. package/dist/validators/string.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/chunks/bigint-ZKkWLdmi.js.map +0 -1
  42. package/dist/chunks/index-BoV-4S1F.js.map +0 -1
  43. package/dist/chunks/json-nIhyRPOU.js.map +0 -1
  44. package/dist/chunks/unknown-CjSRcELI.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { i as VldBase, t as getMessages, V as VldString, a as VldNumber, b as VldBoolean, c as VldDate, e as VldOptional } from './bigint-ZKkWLdmi.js';
2
- import { c as VldCoerceString, b as VldCoerceNumber, a as VldCoerceBoolean, V as VldCoerceDate } from './date-7Iz2BGsL.js';
1
+ import { i as VldBase, t as getMessages, V as VldString, a as VldNumber, b as VldBoolean, c as VldDate, e as VldOptional } from './bigint-DgsCr2dC.js';
2
+ import { c as VldCoerceString, b as VldCoerceNumber, a as VldCoerceBoolean, V as VldCoerceDate } from './date-ODue_rtq.js';
3
3
 
4
4
  /**
5
5
  * Default truthy and falsy value sets
@@ -170,16 +170,9 @@ class VldArray extends VldBase {
170
170
  }
171
171
  result[i] = parseResult.data; // Direct assignment is faster than push
172
172
  }
173
- // Check uniqueness if required
173
+ // Check uniqueness if required - optimized with Map-based approach
174
174
  if (this.config.unique) {
175
- const seen = new Set();
176
- for (const item of result) {
177
- const key = typeof item === 'object' ? this.stableStringify(item) : item;
178
- if (seen.has(key)) {
179
- throw new Error('Array must contain unique items');
180
- }
181
- seen.add(key);
182
- }
175
+ this.checkUnique(result);
183
176
  }
184
177
  return result;
185
178
  }
@@ -194,6 +187,38 @@ class VldArray extends VldBase {
194
187
  return { success: false, error: error };
195
188
  }
196
189
  }
190
+ /**
191
+ * Optimized uniqueness check using Map-based approach
192
+ * Avoids repeated stableStringify calls by caching serialized values
193
+ */
194
+ checkUnique(items) {
195
+ const seen = new Set(); // Set of seen keys
196
+ const objectKeys = new WeakMap(); // Cache for object->string mappings
197
+ for (const item of items) {
198
+ let key;
199
+ if (typeof item === 'object' && item !== null) {
200
+ // Check if we've already serialized this object reference
201
+ const cached = objectKeys.get(item);
202
+ if (cached !== undefined) {
203
+ key = cached;
204
+ }
205
+ else {
206
+ // Serialize and cache
207
+ const serialized = this.stableStringify(item);
208
+ key = serialized;
209
+ objectKeys.set(item, serialized);
210
+ }
211
+ }
212
+ else {
213
+ // Primitives can be used directly as keys
214
+ key = item;
215
+ }
216
+ if (seen.has(key)) {
217
+ throw new Error('Array must contain unique items');
218
+ }
219
+ seen.add(key);
220
+ }
221
+ }
197
222
  /**
198
223
  * Create a stable string representation of an object for hashing
199
224
  * Handles circular references and deep nesting gracefully
@@ -321,11 +346,17 @@ class VldEnum extends VldBase {
321
346
  /**
322
347
  * Private constructor to enforce immutability
323
348
  */
324
- constructor(values, errorMessage) {
349
+ constructor(_values, errorMessage) {
325
350
  super();
326
- this.values = values;
351
+ this._values = _values;
327
352
  this.errorMessage = errorMessage;
328
353
  }
354
+ /**
355
+ * Get the enum values
356
+ */
357
+ get values() {
358
+ return this._values;
359
+ }
329
360
  /**
330
361
  * Create a new enum validator
331
362
  */
@@ -339,11 +370,11 @@ class VldEnum extends VldBase {
339
370
  // BUG-002 FIX: Add type check before includes() to prevent type confusion
340
371
  if (typeof value !== 'string') {
341
372
  throw new Error(this.errorMessage ||
342
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
373
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
343
374
  }
344
- if (!this.values.includes(value)) {
375
+ if (!this._values.includes(value)) {
345
376
  throw new Error(this.errorMessage ||
346
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
377
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
347
378
  }
348
379
  return value;
349
380
  }
@@ -356,16 +387,16 @@ class VldEnum extends VldBase {
356
387
  return {
357
388
  success: false,
358
389
  error: new Error(this.errorMessage ||
359
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
390
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
360
391
  };
361
392
  }
362
- if (this.values.includes(value)) {
393
+ if (this._values.includes(value)) {
363
394
  return { success: true, data: value };
364
395
  }
365
396
  return {
366
397
  success: false,
367
398
  error: new Error(this.errorMessage ||
368
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
399
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
369
400
  };
370
401
  }
371
402
  /**
@@ -373,7 +404,7 @@ class VldEnum extends VldBase {
373
404
  * Creates a new enum validator without the specified values
374
405
  */
375
406
  exclude(...excludeValues) {
376
- const filtered = this.values.filter(v => !excludeValues.includes(v));
407
+ const filtered = this._values.filter(v => !excludeValues.includes(v));
377
408
  if (filtered.length === 0) {
378
409
  throw new Error('Cannot exclude all enum values');
379
410
  }
@@ -385,7 +416,7 @@ class VldEnum extends VldBase {
385
416
  * Creates a new enum validator with only the specified values
386
417
  */
387
418
  extract(...extractValues) {
388
- const extracted = this.values.filter(v => extractValues.includes(v));
419
+ const extracted = this._values.filter(v => extractValues.includes(v));
389
420
  if (extracted.length === 0) {
390
421
  throw new Error('Cannot extract non-existent enum values');
391
422
  }
@@ -404,10 +435,30 @@ class VldObject extends VldBase {
404
435
  */
405
436
  constructor(config) {
406
437
  super();
407
- this.config = config;
438
+ this._config = config;
408
439
  // Pre-compute shape keys for faster access
409
- this.shapeKeys = Object.keys(config.shape);
410
- this.shapeKeysSet = new Set(this.shapeKeys);
440
+ this._shapeKeys = Object.keys(config.shape);
441
+ this._shapeKeysSet = new Set(this._shapeKeys);
442
+ }
443
+ /**
444
+ * Get the validator configuration
445
+ * @internal Used by discriminated union validator
446
+ */
447
+ get config() {
448
+ return this._config;
449
+ }
450
+ /**
451
+ * Get the shape keys array
452
+ */
453
+ get shapeKeys() {
454
+ return this._shapeKeys;
455
+ }
456
+ /**
457
+ * Get the shape keys set for O(1) lookups
458
+ * @internal Used by discriminated union validator
459
+ */
460
+ get shapeKeysSet() {
461
+ return this._shapeKeysSet;
411
462
  }
412
463
  /**
413
464
  * Create a new object validator
@@ -422,14 +473,14 @@ class VldObject extends VldBase {
422
473
  parse(value) {
423
474
  // Fast type check
424
475
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
425
- throw new Error(this.config.errorMessage || getMessages().invalidObject);
476
+ throw new Error(this._config.errorMessage || getMessages().invalidObject);
426
477
  }
427
478
  const obj = value;
428
479
  const result = {};
429
480
  // Ultra-optimized field validation with inline fast paths
430
- for (let i = 0; i < this.shapeKeys.length; i++) {
431
- const key = this.shapeKeys[i];
432
- const validator = this.config.shape[key];
481
+ for (let i = 0; i < this._shapeKeys.length; i++) {
482
+ const key = this._shapeKeys[i];
483
+ const validator = this._config.shape[key];
433
484
  const fieldValue = obj[key];
434
485
  // BUG-NEW-002 FIX: Use instanceof instead of constructor.name
435
486
  // constructor.name breaks in minified builds where class names become 'a', 'b', etc.
@@ -486,38 +537,39 @@ class VldObject extends VldBase {
486
537
  result[key] = parseResult.data;
487
538
  }
488
539
  }
489
- // Handle strict mode - optimized with Set
490
- if (this.config.strict) {
540
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
541
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
491
542
  const objKeys = Object.keys(obj);
492
- const extraKeys = [];
493
- for (let i = 0; i < objKeys.length; i++) {
494
- if (!this.shapeKeysSet.has(objKeys[i])) {
495
- extraKeys.push(objKeys[i]);
543
+ // Handle strict mode - optimized with Set
544
+ if (this._config.strict) {
545
+ const extraKeys = [];
546
+ for (let i = 0; i < objKeys.length; i++) {
547
+ if (!this._shapeKeysSet.has(objKeys[i])) {
548
+ extraKeys.push(objKeys[i]);
549
+ }
550
+ }
551
+ if (extraKeys.length > 0) {
552
+ throw new Error(getMessages().unexpectedKeys(extraKeys));
496
553
  }
497
554
  }
498
- if (extraKeys.length > 0) {
499
- throw new Error(getMessages().unexpectedKeys(extraKeys));
500
- }
501
- }
502
- // Handle passthrough mode - optimized with comprehensive prototype pollution protection
503
- if (this.config.passthrough) {
504
- const objKeys = Object.keys(obj);
505
- for (let i = 0; i < objKeys.length; i++) {
506
- const key = objKeys[i];
507
- // Skip dangerous keys to prevent prototype pollution
508
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
509
- result[key] = obj[key];
555
+ // Handle passthrough mode - optimized with comprehensive prototype pollution protection
556
+ if (this._config.passthrough) {
557
+ for (let i = 0; i < objKeys.length; i++) {
558
+ const key = objKeys[i];
559
+ // Skip dangerous keys to prevent prototype pollution
560
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
561
+ result[key] = obj[key];
562
+ }
510
563
  }
511
564
  }
512
- }
513
- // Handle catchall - validate extra keys with catchall validator
514
- if (this.config.catchall) {
515
- const objKeys = Object.keys(obj);
516
- for (let i = 0; i < objKeys.length; i++) {
517
- const key = objKeys[i];
518
- // Skip keys already in shape and dangerous keys
519
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
520
- result[key] = this.config.catchall.parse(obj[key]);
565
+ // Handle catchall - validate extra keys with catchall validator
566
+ if (this._config.catchall) {
567
+ for (let i = 0; i < objKeys.length; i++) {
568
+ const key = objKeys[i];
569
+ // Skip keys already in shape and dangerous keys
570
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
571
+ result[key] = this._config.catchall.parse(obj[key]);
572
+ }
521
573
  }
522
574
  }
523
575
  }
@@ -532,15 +584,15 @@ class VldObject extends VldBase {
532
584
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
533
585
  return {
534
586
  success: false,
535
- error: new Error(this.config.errorMessage || getMessages().invalidObject)
587
+ error: new Error(this._config.errorMessage || getMessages().invalidObject)
536
588
  };
537
589
  }
538
590
  const obj = value;
539
591
  const result = {};
540
592
  // Validate all fields
541
- for (let i = 0; i < this.shapeKeys.length; i++) {
542
- const key = this.shapeKeys[i];
543
- const validator = this.config.shape[key];
593
+ for (let i = 0; i < this._shapeKeys.length; i++) {
594
+ const key = this._shapeKeys[i];
595
+ const validator = this._config.shape[key];
544
596
  const fieldValue = obj[key];
545
597
  const parseResult = validator.safeParse(fieldValue);
546
598
  if (parseResult.success) {
@@ -553,48 +605,49 @@ class VldObject extends VldBase {
553
605
  };
554
606
  }
555
607
  }
556
- // Handle strict mode
557
- if (this.config.strict) {
608
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
609
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
558
610
  const objKeys = Object.keys(obj);
559
- const extraKeys = [];
560
- for (let i = 0; i < objKeys.length; i++) {
561
- if (!this.shapeKeysSet.has(objKeys[i])) {
562
- extraKeys.push(objKeys[i]);
611
+ // Handle strict mode
612
+ if (this._config.strict) {
613
+ const extraKeys = [];
614
+ for (let i = 0; i < objKeys.length; i++) {
615
+ if (!this._shapeKeysSet.has(objKeys[i])) {
616
+ extraKeys.push(objKeys[i]);
617
+ }
618
+ }
619
+ if (extraKeys.length > 0) {
620
+ return {
621
+ success: false,
622
+ error: new Error(getMessages().unexpectedKeys(extraKeys))
623
+ };
563
624
  }
564
625
  }
565
- if (extraKeys.length > 0) {
566
- return {
567
- success: false,
568
- error: new Error(getMessages().unexpectedKeys(extraKeys))
569
- };
570
- }
571
- }
572
- // Handle passthrough mode with comprehensive prototype pollution protection
573
- if (this.config.passthrough) {
574
- const objKeys = Object.keys(obj);
575
- for (let i = 0; i < objKeys.length; i++) {
576
- const key = objKeys[i];
577
- // Skip dangerous keys to prevent prototype pollution
578
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
579
- result[key] = obj[key];
626
+ // Handle passthrough mode with comprehensive prototype pollution protection
627
+ if (this._config.passthrough) {
628
+ for (let i = 0; i < objKeys.length; i++) {
629
+ const key = objKeys[i];
630
+ // Skip dangerous keys to prevent prototype pollution
631
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
632
+ result[key] = obj[key];
633
+ }
580
634
  }
581
635
  }
582
- }
583
- // Handle catchall - validate extra keys with catchall validator
584
- if (this.config.catchall) {
585
- const objKeys = Object.keys(obj);
586
- for (let i = 0; i < objKeys.length; i++) {
587
- const key = objKeys[i];
588
- // Skip keys already in shape and dangerous keys
589
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
590
- const catchallResult = this.config.catchall.safeParse(obj[key]);
591
- if (!catchallResult.success) {
592
- return {
593
- success: false,
594
- error: new Error(getMessages().objectField(key, catchallResult.error.message))
595
- };
636
+ // Handle catchall - validate extra keys with catchall validator
637
+ if (this._config.catchall) {
638
+ for (let i = 0; i < objKeys.length; i++) {
639
+ const key = objKeys[i];
640
+ // Skip keys already in shape and dangerous keys
641
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
642
+ const catchallResult = this._config.catchall.safeParse(obj[key]);
643
+ if (!catchallResult.success) {
644
+ return {
645
+ success: false,
646
+ error: new Error(getMessages().objectField(key, catchallResult.error.message))
647
+ };
648
+ }
649
+ result[key] = catchallResult.data;
596
650
  }
597
- result[key] = catchallResult.data;
598
651
  }
599
652
  }
600
653
  }
@@ -659,7 +712,7 @@ class VldObject extends VldBase {
659
712
  */
660
713
  strict(message) {
661
714
  return new VldObject({
662
- ...this.config,
715
+ ...this._config,
663
716
  strict: true,
664
717
  passthrough: false,
665
718
  errorMessage: message
@@ -670,7 +723,7 @@ class VldObject extends VldBase {
670
723
  */
671
724
  passthrough() {
672
725
  return new VldObject({
673
- ...this.config,
726
+ ...this._config,
674
727
  strict: false,
675
728
  passthrough: true
676
729
  });
@@ -680,11 +733,11 @@ class VldObject extends VldBase {
680
733
  */
681
734
  partial() {
682
735
  const partialShape = {};
683
- for (const key in this.config.shape) {
684
- partialShape[key] = new VldOptional(this.config.shape[key]);
736
+ for (const key in this._config.shape) {
737
+ partialShape[key] = new VldOptional(this._config.shape[key]);
685
738
  }
686
739
  return new VldObject({
687
- ...this.config,
740
+ ...this._config,
688
741
  shape: partialShape
689
742
  });
690
743
  }
@@ -693,8 +746,8 @@ class VldObject extends VldBase {
693
746
  */
694
747
  deepPartial() {
695
748
  const deepPartialShape = {};
696
- for (const key in this.config.shape) {
697
- const validator = this.config.shape[key];
749
+ for (const key in this._config.shape) {
750
+ const validator = this._config.shape[key];
698
751
  if (validator instanceof VldObject) {
699
752
  deepPartialShape[key] = new VldOptional(validator.deepPartial());
700
753
  }
@@ -703,7 +756,7 @@ class VldObject extends VldBase {
703
756
  }
704
757
  }
705
758
  return new VldObject({
706
- ...this.config,
759
+ ...this._config,
707
760
  shape: deepPartialShape
708
761
  });
709
762
  }
@@ -713,12 +766,12 @@ class VldObject extends VldBase {
713
766
  pick(...keys) {
714
767
  const pickedShape = {};
715
768
  for (const key of keys) {
716
- if (key in this.config.shape) {
717
- pickedShape[key] = this.config.shape[key];
769
+ if (key in this._config.shape) {
770
+ pickedShape[key] = this._config.shape[key];
718
771
  }
719
772
  }
720
773
  return new VldObject({
721
- ...this.config,
774
+ ...this._config,
722
775
  shape: pickedShape
723
776
  });
724
777
  }
@@ -728,13 +781,13 @@ class VldObject extends VldBase {
728
781
  omit(...keys) {
729
782
  const omittedShape = {};
730
783
  const keysToOmit = new Set(keys);
731
- for (const key in this.config.shape) {
784
+ for (const key in this._config.shape) {
732
785
  if (!keysToOmit.has(key)) {
733
- omittedShape[key] = this.config.shape[key];
786
+ omittedShape[key] = this._config.shape[key];
734
787
  }
735
788
  }
736
789
  return new VldObject({
737
- ...this.config,
790
+ ...this._config,
738
791
  shape: omittedShape
739
792
  });
740
793
  }
@@ -743,8 +796,8 @@ class VldObject extends VldBase {
743
796
  */
744
797
  extend(extension) {
745
798
  return new VldObject({
746
- ...this.config,
747
- shape: { ...this.config.shape, ...extension }
799
+ ...this._config,
800
+ shape: { ...this._config.shape, ...extension }
748
801
  });
749
802
  }
750
803
  /**
@@ -752,8 +805,8 @@ class VldObject extends VldBase {
752
805
  */
753
806
  merge(other) {
754
807
  return new VldObject({
755
- ...this.config,
756
- shape: { ...this.config.shape, ...other.config.shape }
808
+ ...this._config,
809
+ shape: { ...this._config.shape, ...other.config.shape }
757
810
  });
758
811
  }
759
812
  /**
@@ -761,8 +814,8 @@ class VldObject extends VldBase {
761
814
  */
762
815
  required() {
763
816
  const requiredShape = {};
764
- for (const key in this.config.shape) {
765
- const validator = this.config.shape[key];
817
+ for (const key in this._config.shape) {
818
+ const validator = this._config.shape[key];
766
819
  // If it's optional, unwrap it
767
820
  if (validator instanceof VldOptional) {
768
821
  // BUG-001 FIX: Add defensive check for baseValidator property
@@ -777,7 +830,7 @@ class VldObject extends VldBase {
777
830
  }
778
831
  }
779
832
  return new VldObject({
780
- ...this.config,
833
+ ...this._config,
781
834
  shape: requiredShape
782
835
  });
783
836
  }
@@ -787,7 +840,7 @@ class VldObject extends VldBase {
787
840
  */
788
841
  catchall(schema) {
789
842
  return new VldObject({
790
- ...this.config,
843
+ ...this._config,
791
844
  catchall: schema,
792
845
  passthrough: false // catchall overrides passthrough
793
846
  });
@@ -797,14 +850,14 @@ class VldObject extends VldBase {
797
850
  * Zod 4 API parity - returns the shape object
798
851
  */
799
852
  get shape() {
800
- return this.config.shape;
853
+ return this._config.shape;
801
854
  }
802
855
  /**
803
856
  * Create an enum validator from object keys
804
857
  * Zod 4 API parity - creates literal union of keys
805
858
  */
806
859
  keyof() {
807
- const keys = Object.keys(this.config.shape);
860
+ const keys = Object.keys(this._config.shape);
808
861
  if (keys.length === 0) {
809
862
  throw new Error('Cannot create keyof enum from empty object');
810
863
  }
@@ -823,7 +876,7 @@ class VldObject extends VldBase {
823
876
  */
824
877
  safeExtend(extension) {
825
878
  // Check for overlapping keys
826
- const existingKeys = new Set(Object.keys(this.config.shape));
879
+ const existingKeys = new Set(Object.keys(this._config.shape));
827
880
  const extensionKeys = Object.keys(extension);
828
881
  const overlappingKeys = [];
829
882
  for (const key of extensionKeys) {
@@ -835,8 +888,8 @@ class VldObject extends VldBase {
835
888
  throw new Error(`safeExtend: ${getMessages().safeExtendOverlap(overlappingKeys)}`);
836
889
  }
837
890
  return new VldObject({
838
- ...this.config,
839
- shape: { ...this.config.shape, ...extension }
891
+ ...this._config,
892
+ shape: { ...this._config.shape, ...extension }
840
893
  });
841
894
  }
842
895
  }
@@ -972,11 +1025,17 @@ class VldLiteral extends VldBase {
972
1025
  /**
973
1026
  * Private constructor to enforce immutability
974
1027
  */
975
- constructor(literal, errorMessage) {
1028
+ constructor(_literal, errorMessage) {
976
1029
  super();
977
- this.literal = literal;
1030
+ this._literal = _literal;
978
1031
  this.errorMessage = errorMessage;
979
1032
  }
1033
+ /**
1034
+ * Get the literal value
1035
+ */
1036
+ get literal() {
1037
+ return this._literal;
1038
+ }
980
1039
  /**
981
1040
  * Create a new literal validator
982
1041
  */
@@ -987,23 +1046,23 @@ class VldLiteral extends VldBase {
987
1046
  * Parse and validate a literal value
988
1047
  */
989
1048
  parse(value) {
990
- if (value !== this.literal) {
1049
+ if (value !== this._literal) {
991
1050
  throw new Error(this.errorMessage ||
992
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)));
1051
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)));
993
1052
  }
994
- return this.literal;
1053
+ return this._literal;
995
1054
  }
996
1055
  /**
997
1056
  * Safely parse and validate a literal value
998
1057
  */
999
1058
  safeParse(value) {
1000
- if (value === this.literal) {
1001
- return { success: true, data: this.literal };
1059
+ if (value === this._literal) {
1060
+ return { success: true, data: this._literal };
1002
1061
  }
1003
1062
  return {
1004
1063
  success: false,
1005
1064
  error: new Error(this.errorMessage ||
1006
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)))
1065
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)))
1007
1066
  };
1008
1067
  }
1009
1068
  }
@@ -1678,27 +1737,56 @@ class VldNan extends VldBase {
1678
1737
  /**
1679
1738
  * Lazy validator - defers schema evaluation until runtime
1680
1739
  * Essential for recursive and self-referencing types
1740
+ *
1741
+ * MEMORY OPTIMIZATION: Uses WeakRef for the cached schema to allow garbage collection
1742
+ * when the validator is no longer in use. This prevents memory leaks in long-running
1743
+ * applications with dynamically created schemas.
1681
1744
  */
1682
1745
  class VldLazy extends VldBase {
1683
1746
  constructor(_schemaGetter) {
1684
1747
  super();
1685
1748
  this._schemaGetter = _schemaGetter;
1686
- this._cachedSchema = null;
1749
+ // Use WeakRef to allow garbage collection of the cached schema
1750
+ this._cachedSchemaRef = null;
1751
+ // Keep a strong reference flag to prevent GC during active use
1752
+ this._strongRef = null;
1687
1753
  }
1688
1754
  static create(schemaGetter) {
1689
1755
  return new VldLazy(schemaGetter);
1690
1756
  }
1691
1757
  /**
1692
1758
  * Get the actual schema, caching it after first retrieval
1759
+ * Uses WeakRef to allow garbage collection when validator is not in use
1693
1760
  */
1694
1761
  _getSchema() {
1695
- if (!this._cachedSchema) {
1696
- this._cachedSchema = this._schemaGetter();
1762
+ // Check if we have a strong reference first (active use)
1763
+ if (this._strongRef) {
1764
+ return this._strongRef;
1765
+ }
1766
+ // Try to get from WeakRef
1767
+ if (this._cachedSchemaRef) {
1768
+ const cached = this._cachedSchemaRef.deref();
1769
+ if (cached) {
1770
+ // Restore strong reference for active use
1771
+ this._strongRef = cached;
1772
+ return cached;
1773
+ }
1697
1774
  }
1698
- return this._cachedSchema;
1775
+ // Create new schema
1776
+ const schema = this._schemaGetter();
1777
+ this._cachedSchemaRef = new WeakRef(schema);
1778
+ this._strongRef = schema;
1779
+ // Clear strong reference after a tick to allow GC
1780
+ // This keeps the schema alive during synchronous operations
1781
+ // but allows it to be collected if the validator is discarded
1782
+ Promise.resolve().then(() => {
1783
+ this._strongRef = null;
1784
+ });
1785
+ return schema;
1699
1786
  }
1700
1787
  /**
1701
1788
  * Get the inner schema (unwrap)
1789
+ * Returns a strong reference that will keep the schema alive
1702
1790
  */
1703
1791
  unwrap() {
1704
1792
  return this._getSchema();
@@ -1721,11 +1809,10 @@ class VldLazy extends VldBase {
1721
1809
  */
1722
1810
  function extractLiteralValues(schema) {
1723
1811
  if (schema instanceof VldLiteral) {
1724
- const value = schema.literal;
1725
- return [value];
1812
+ return [schema.literal];
1726
1813
  }
1727
1814
  if (schema instanceof VldEnum) {
1728
- return schema.values;
1815
+ return [...schema.values];
1729
1816
  }
1730
1817
  throw new Error('Discriminator must be a literal or enum schema');
1731
1818
  }
@@ -1931,4 +2018,4 @@ class VldJson extends VldBase {
1931
2018
  }
1932
2019
 
1933
2020
  export { VldSymbol as V, VldStringBool as a, VldArray as b, VldObject as c, VldTuple as d, VldRecord as e, VldSet as f, VldMap as g, VldUnion as h, VldIntersection as i, VldDiscriminatedUnion as j, VldXor as k, VldLiteral as l, VldEnum as m, VldAny as n, VldVoid as o, VldNever as p, VldNull as q, VldUndefined as r, VldNan as s, VldLazy as t, VldJson as u };
1934
- //# sourceMappingURL=json-nIhyRPOU.js.map
2021
+ //# sourceMappingURL=json-o20GFhTh.js.map