@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
package/dist/cjs/mini.cjs CHANGED
@@ -3461,6 +3461,7 @@ const REGEX_PATTERNS = {
3461
3461
  ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/};
3462
3462
  /**
3463
3463
  * Immutable string validator with chainable methods
3464
+ * Features pre-compiled validation functions for maximum performance
3464
3465
  */
3465
3466
  class VldString extends VldBase {
3466
3467
  /**
@@ -3468,12 +3469,100 @@ class VldString extends VldBase {
3468
3469
  */
3469
3470
  constructor(config) {
3470
3471
  super();
3472
+ // Cache for pre-compiled validation function
3473
+ this._compiledValidator = null;
3471
3474
  this.config = {
3472
3475
  checks: config?.checks || [],
3473
3476
  transforms: config?.transforms || [],
3474
3477
  errorMessage: config?.errorMessage
3475
3478
  };
3476
3479
  }
3480
+ /**
3481
+ * Compile all transforms and checks into a single optimized function
3482
+ * This eliminates loop overhead and enables better JIT optimization
3483
+ */
3484
+ _compileValidator() {
3485
+ const transforms = this.config.transforms;
3486
+ const checks = this.config.checks;
3487
+ const errorMessage = this.config.errorMessage || getMessages().invalidString;
3488
+ // Fast path: no transforms or checks
3489
+ if (transforms.length === 0 && checks.length === 0) {
3490
+ return (value) => ({ success: true, value });
3491
+ }
3492
+ // Fast path: only transforms, no checks
3493
+ if (checks.length === 0) {
3494
+ switch (transforms.length) {
3495
+ case 1:
3496
+ return (value) => ({ success: true, value: transforms[0](value) });
3497
+ case 2:
3498
+ return (value) => ({ success: true, value: transforms[1](transforms[0](value)) });
3499
+ case 3:
3500
+ return (value) => ({ success: true, value: transforms[2](transforms[1](transforms[0](value))) });
3501
+ default:
3502
+ return (value) => {
3503
+ let result = value;
3504
+ for (let i = 0; i < transforms.length; i++) {
3505
+ result = transforms[i](result);
3506
+ }
3507
+ return { success: true, value: result };
3508
+ };
3509
+ }
3510
+ }
3511
+ // Fast path: only checks, no transforms
3512
+ if (transforms.length === 0) {
3513
+ switch (checks.length) {
3514
+ case 1:
3515
+ return (value) => {
3516
+ if (!checks[0](value))
3517
+ return { success: false, error: errorMessage };
3518
+ return { success: true, value };
3519
+ };
3520
+ case 2:
3521
+ return (value) => {
3522
+ if (!checks[0](value) || !checks[1](value))
3523
+ return { success: false, error: errorMessage };
3524
+ return { success: true, value };
3525
+ };
3526
+ case 3:
3527
+ return (value) => {
3528
+ if (!checks[0](value) || !checks[1](value) || !checks[2](value))
3529
+ return { success: false, error: errorMessage };
3530
+ return { success: true, value };
3531
+ };
3532
+ default:
3533
+ return (value) => {
3534
+ for (let i = 0; i < checks.length; i++) {
3535
+ if (!checks[i](value))
3536
+ return { success: false, error: errorMessage };
3537
+ }
3538
+ return { success: true, value };
3539
+ };
3540
+ }
3541
+ }
3542
+ // General case: both transforms and checks
3543
+ return (value) => {
3544
+ let result = value;
3545
+ // Apply transforms
3546
+ for (let i = 0; i < transforms.length; i++) {
3547
+ result = transforms[i](result);
3548
+ }
3549
+ // Apply checks
3550
+ for (let i = 0; i < checks.length; i++) {
3551
+ if (!checks[i](result))
3552
+ return { success: false, error: errorMessage };
3553
+ }
3554
+ return { success: true, value: result };
3555
+ };
3556
+ }
3557
+ /**
3558
+ * Get the cached compiled validator, creating it if necessary
3559
+ */
3560
+ _getCompiledValidator() {
3561
+ if (!this._compiledValidator) {
3562
+ this._compiledValidator = this._compileValidator();
3563
+ }
3564
+ return this._compiledValidator;
3565
+ }
3477
3566
  /**
3478
3567
  * Create a new string validator
3479
3568
  */
@@ -3481,26 +3570,18 @@ class VldString extends VldBase {
3481
3570
  return new VldString();
3482
3571
  }
3483
3572
  /**
3484
- * Parse and validate a string value - ultra-optimized
3573
+ * Parse and validate a string value - ultra-optimized with pre-compiled validator
3485
3574
  */
3486
3575
  parse(value) {
3487
3576
  if (typeof value !== 'string') {
3488
3577
  throw new Error(this.config.errorMessage || getMessages().invalidString);
3489
3578
  }
3490
- let result = value;
3491
- // Apply transformations with optimized loop
3492
- const transformsLength = this.config.transforms.length;
3493
- for (let i = 0; i < transformsLength; i++) {
3494
- result = this.config.transforms[i](result);
3495
- }
3496
- // Apply checks with optimized loop and early termination
3497
- const checksLength = this.config.checks.length;
3498
- for (let i = 0; i < checksLength; i++) {
3499
- if (!this.config.checks[i](result)) {
3500
- throw new Error(this.config.errorMessage || getMessages().invalidString);
3501
- }
3579
+ // Use pre-compiled validator for maximum performance
3580
+ const result = this._getCompiledValidator()(value);
3581
+ if (!result.success) {
3582
+ throw new Error(result.error);
3502
3583
  }
3503
- return result;
3584
+ return result.value;
3504
3585
  }
3505
3586
  /**
3506
3587
  * Safely parse and validate a string value
@@ -4602,16 +4683,9 @@ class VldArray extends VldBase {
4602
4683
  }
4603
4684
  result[i] = parseResult.data; // Direct assignment is faster than push
4604
4685
  }
4605
- // Check uniqueness if required
4686
+ // Check uniqueness if required - optimized with Map-based approach
4606
4687
  if (this.config.unique) {
4607
- const seen = new Set();
4608
- for (const item of result) {
4609
- const key = typeof item === 'object' ? this.stableStringify(item) : item;
4610
- if (seen.has(key)) {
4611
- throw new Error('Array must contain unique items');
4612
- }
4613
- seen.add(key);
4614
- }
4688
+ this.checkUnique(result);
4615
4689
  }
4616
4690
  return result;
4617
4691
  }
@@ -4626,6 +4700,38 @@ class VldArray extends VldBase {
4626
4700
  return { success: false, error: error };
4627
4701
  }
4628
4702
  }
4703
+ /**
4704
+ * Optimized uniqueness check using Map-based approach
4705
+ * Avoids repeated stableStringify calls by caching serialized values
4706
+ */
4707
+ checkUnique(items) {
4708
+ const seen = new Set(); // Set of seen keys
4709
+ const objectKeys = new WeakMap(); // Cache for object->string mappings
4710
+ for (const item of items) {
4711
+ let key;
4712
+ if (typeof item === 'object' && item !== null) {
4713
+ // Check if we've already serialized this object reference
4714
+ const cached = objectKeys.get(item);
4715
+ if (cached !== undefined) {
4716
+ key = cached;
4717
+ }
4718
+ else {
4719
+ // Serialize and cache
4720
+ const serialized = this.stableStringify(item);
4721
+ key = serialized;
4722
+ objectKeys.set(item, serialized);
4723
+ }
4724
+ }
4725
+ else {
4726
+ // Primitives can be used directly as keys
4727
+ key = item;
4728
+ }
4729
+ if (seen.has(key)) {
4730
+ throw new Error('Array must contain unique items');
4731
+ }
4732
+ seen.add(key);
4733
+ }
4734
+ }
4629
4735
  /**
4630
4736
  * Create a stable string representation of an object for hashing
4631
4737
  * Handles circular references and deep nesting gracefully
@@ -4753,11 +4859,17 @@ class VldEnum extends VldBase {
4753
4859
  /**
4754
4860
  * Private constructor to enforce immutability
4755
4861
  */
4756
- constructor(values, errorMessage) {
4862
+ constructor(_values, errorMessage) {
4757
4863
  super();
4758
- this.values = values;
4864
+ this._values = _values;
4759
4865
  this.errorMessage = errorMessage;
4760
4866
  }
4867
+ /**
4868
+ * Get the enum values
4869
+ */
4870
+ get values() {
4871
+ return this._values;
4872
+ }
4761
4873
  /**
4762
4874
  * Create a new enum validator
4763
4875
  */
@@ -4771,11 +4883,11 @@ class VldEnum extends VldBase {
4771
4883
  // BUG-002 FIX: Add type check before includes() to prevent type confusion
4772
4884
  if (typeof value !== 'string') {
4773
4885
  throw new Error(this.errorMessage ||
4774
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
4886
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
4775
4887
  }
4776
- if (!this.values.includes(value)) {
4888
+ if (!this._values.includes(value)) {
4777
4889
  throw new Error(this.errorMessage ||
4778
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
4890
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
4779
4891
  }
4780
4892
  return value;
4781
4893
  }
@@ -4788,16 +4900,16 @@ class VldEnum extends VldBase {
4788
4900
  return {
4789
4901
  success: false,
4790
4902
  error: new Error(this.errorMessage ||
4791
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
4903
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
4792
4904
  };
4793
4905
  }
4794
- if (this.values.includes(value)) {
4906
+ if (this._values.includes(value)) {
4795
4907
  return { success: true, data: value };
4796
4908
  }
4797
4909
  return {
4798
4910
  success: false,
4799
4911
  error: new Error(this.errorMessage ||
4800
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
4912
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
4801
4913
  };
4802
4914
  }
4803
4915
  /**
@@ -4805,7 +4917,7 @@ class VldEnum extends VldBase {
4805
4917
  * Creates a new enum validator without the specified values
4806
4918
  */
4807
4919
  exclude(...excludeValues) {
4808
- const filtered = this.values.filter(v => !excludeValues.includes(v));
4920
+ const filtered = this._values.filter(v => !excludeValues.includes(v));
4809
4921
  if (filtered.length === 0) {
4810
4922
  throw new Error('Cannot exclude all enum values');
4811
4923
  }
@@ -4817,7 +4929,7 @@ class VldEnum extends VldBase {
4817
4929
  * Creates a new enum validator with only the specified values
4818
4930
  */
4819
4931
  extract(...extractValues) {
4820
- const extracted = this.values.filter(v => extractValues.includes(v));
4932
+ const extracted = this._values.filter(v => extractValues.includes(v));
4821
4933
  if (extracted.length === 0) {
4822
4934
  throw new Error('Cannot extract non-existent enum values');
4823
4935
  }
@@ -5338,10 +5450,30 @@ class VldObject extends VldBase {
5338
5450
  */
5339
5451
  constructor(config) {
5340
5452
  super();
5341
- this.config = config;
5453
+ this._config = config;
5342
5454
  // Pre-compute shape keys for faster access
5343
- this.shapeKeys = Object.keys(config.shape);
5344
- this.shapeKeysSet = new Set(this.shapeKeys);
5455
+ this._shapeKeys = Object.keys(config.shape);
5456
+ this._shapeKeysSet = new Set(this._shapeKeys);
5457
+ }
5458
+ /**
5459
+ * Get the validator configuration
5460
+ * @internal Used by discriminated union validator
5461
+ */
5462
+ get config() {
5463
+ return this._config;
5464
+ }
5465
+ /**
5466
+ * Get the shape keys array
5467
+ */
5468
+ get shapeKeys() {
5469
+ return this._shapeKeys;
5470
+ }
5471
+ /**
5472
+ * Get the shape keys set for O(1) lookups
5473
+ * @internal Used by discriminated union validator
5474
+ */
5475
+ get shapeKeysSet() {
5476
+ return this._shapeKeysSet;
5345
5477
  }
5346
5478
  /**
5347
5479
  * Create a new object validator
@@ -5356,14 +5488,14 @@ class VldObject extends VldBase {
5356
5488
  parse(value) {
5357
5489
  // Fast type check
5358
5490
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
5359
- throw new Error(this.config.errorMessage || getMessages().invalidObject);
5491
+ throw new Error(this._config.errorMessage || getMessages().invalidObject);
5360
5492
  }
5361
5493
  const obj = value;
5362
5494
  const result = {};
5363
5495
  // Ultra-optimized field validation with inline fast paths
5364
- for (let i = 0; i < this.shapeKeys.length; i++) {
5365
- const key = this.shapeKeys[i];
5366
- const validator = this.config.shape[key];
5496
+ for (let i = 0; i < this._shapeKeys.length; i++) {
5497
+ const key = this._shapeKeys[i];
5498
+ const validator = this._config.shape[key];
5367
5499
  const fieldValue = obj[key];
5368
5500
  // BUG-NEW-002 FIX: Use instanceof instead of constructor.name
5369
5501
  // constructor.name breaks in minified builds where class names become 'a', 'b', etc.
@@ -5420,38 +5552,39 @@ class VldObject extends VldBase {
5420
5552
  result[key] = parseResult.data;
5421
5553
  }
5422
5554
  }
5423
- // Handle strict mode - optimized with Set
5424
- if (this.config.strict) {
5555
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
5556
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
5425
5557
  const objKeys = Object.keys(obj);
5426
- const extraKeys = [];
5427
- for (let i = 0; i < objKeys.length; i++) {
5428
- if (!this.shapeKeysSet.has(objKeys[i])) {
5429
- extraKeys.push(objKeys[i]);
5558
+ // Handle strict mode - optimized with Set
5559
+ if (this._config.strict) {
5560
+ const extraKeys = [];
5561
+ for (let i = 0; i < objKeys.length; i++) {
5562
+ if (!this._shapeKeysSet.has(objKeys[i])) {
5563
+ extraKeys.push(objKeys[i]);
5564
+ }
5565
+ }
5566
+ if (extraKeys.length > 0) {
5567
+ throw new Error(getMessages().unexpectedKeys(extraKeys));
5430
5568
  }
5431
5569
  }
5432
- if (extraKeys.length > 0) {
5433
- throw new Error(getMessages().unexpectedKeys(extraKeys));
5434
- }
5435
- }
5436
- // Handle passthrough mode - optimized with comprehensive prototype pollution protection
5437
- if (this.config.passthrough) {
5438
- const objKeys = Object.keys(obj);
5439
- for (let i = 0; i < objKeys.length; i++) {
5440
- const key = objKeys[i];
5441
- // Skip dangerous keys to prevent prototype pollution
5442
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5443
- result[key] = obj[key];
5570
+ // Handle passthrough mode - optimized with comprehensive prototype pollution protection
5571
+ if (this._config.passthrough) {
5572
+ for (let i = 0; i < objKeys.length; i++) {
5573
+ const key = objKeys[i];
5574
+ // Skip dangerous keys to prevent prototype pollution
5575
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5576
+ result[key] = obj[key];
5577
+ }
5444
5578
  }
5445
5579
  }
5446
- }
5447
- // Handle catchall - validate extra keys with catchall validator
5448
- if (this.config.catchall) {
5449
- const objKeys = Object.keys(obj);
5450
- for (let i = 0; i < objKeys.length; i++) {
5451
- const key = objKeys[i];
5452
- // Skip keys already in shape and dangerous keys
5453
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5454
- result[key] = this.config.catchall.parse(obj[key]);
5580
+ // Handle catchall - validate extra keys with catchall validator
5581
+ if (this._config.catchall) {
5582
+ for (let i = 0; i < objKeys.length; i++) {
5583
+ const key = objKeys[i];
5584
+ // Skip keys already in shape and dangerous keys
5585
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5586
+ result[key] = this._config.catchall.parse(obj[key]);
5587
+ }
5455
5588
  }
5456
5589
  }
5457
5590
  }
@@ -5466,15 +5599,15 @@ class VldObject extends VldBase {
5466
5599
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
5467
5600
  return {
5468
5601
  success: false,
5469
- error: new Error(this.config.errorMessage || getMessages().invalidObject)
5602
+ error: new Error(this._config.errorMessage || getMessages().invalidObject)
5470
5603
  };
5471
5604
  }
5472
5605
  const obj = value;
5473
5606
  const result = {};
5474
5607
  // Validate all fields
5475
- for (let i = 0; i < this.shapeKeys.length; i++) {
5476
- const key = this.shapeKeys[i];
5477
- const validator = this.config.shape[key];
5608
+ for (let i = 0; i < this._shapeKeys.length; i++) {
5609
+ const key = this._shapeKeys[i];
5610
+ const validator = this._config.shape[key];
5478
5611
  const fieldValue = obj[key];
5479
5612
  const parseResult = validator.safeParse(fieldValue);
5480
5613
  if (parseResult.success) {
@@ -5487,48 +5620,49 @@ class VldObject extends VldBase {
5487
5620
  };
5488
5621
  }
5489
5622
  }
5490
- // Handle strict mode
5491
- if (this.config.strict) {
5623
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
5624
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
5492
5625
  const objKeys = Object.keys(obj);
5493
- const extraKeys = [];
5494
- for (let i = 0; i < objKeys.length; i++) {
5495
- if (!this.shapeKeysSet.has(objKeys[i])) {
5496
- extraKeys.push(objKeys[i]);
5626
+ // Handle strict mode
5627
+ if (this._config.strict) {
5628
+ const extraKeys = [];
5629
+ for (let i = 0; i < objKeys.length; i++) {
5630
+ if (!this._shapeKeysSet.has(objKeys[i])) {
5631
+ extraKeys.push(objKeys[i]);
5632
+ }
5633
+ }
5634
+ if (extraKeys.length > 0) {
5635
+ return {
5636
+ success: false,
5637
+ error: new Error(getMessages().unexpectedKeys(extraKeys))
5638
+ };
5497
5639
  }
5498
5640
  }
5499
- if (extraKeys.length > 0) {
5500
- return {
5501
- success: false,
5502
- error: new Error(getMessages().unexpectedKeys(extraKeys))
5503
- };
5504
- }
5505
- }
5506
- // Handle passthrough mode with comprehensive prototype pollution protection
5507
- if (this.config.passthrough) {
5508
- const objKeys = Object.keys(obj);
5509
- for (let i = 0; i < objKeys.length; i++) {
5510
- const key = objKeys[i];
5511
- // Skip dangerous keys to prevent prototype pollution
5512
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5513
- result[key] = obj[key];
5641
+ // Handle passthrough mode with comprehensive prototype pollution protection
5642
+ if (this._config.passthrough) {
5643
+ for (let i = 0; i < objKeys.length; i++) {
5644
+ const key = objKeys[i];
5645
+ // Skip dangerous keys to prevent prototype pollution
5646
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5647
+ result[key] = obj[key];
5648
+ }
5514
5649
  }
5515
5650
  }
5516
- }
5517
- // Handle catchall - validate extra keys with catchall validator
5518
- if (this.config.catchall) {
5519
- const objKeys = Object.keys(obj);
5520
- for (let i = 0; i < objKeys.length; i++) {
5521
- const key = objKeys[i];
5522
- // Skip keys already in shape and dangerous keys
5523
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5524
- const catchallResult = this.config.catchall.safeParse(obj[key]);
5525
- if (!catchallResult.success) {
5526
- return {
5527
- success: false,
5528
- error: new Error(getMessages().objectField(key, catchallResult.error.message))
5529
- };
5651
+ // Handle catchall - validate extra keys with catchall validator
5652
+ if (this._config.catchall) {
5653
+ for (let i = 0; i < objKeys.length; i++) {
5654
+ const key = objKeys[i];
5655
+ // Skip keys already in shape and dangerous keys
5656
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5657
+ const catchallResult = this._config.catchall.safeParse(obj[key]);
5658
+ if (!catchallResult.success) {
5659
+ return {
5660
+ success: false,
5661
+ error: new Error(getMessages().objectField(key, catchallResult.error.message))
5662
+ };
5663
+ }
5664
+ result[key] = catchallResult.data;
5530
5665
  }
5531
- result[key] = catchallResult.data;
5532
5666
  }
5533
5667
  }
5534
5668
  }
@@ -5593,7 +5727,7 @@ class VldObject extends VldBase {
5593
5727
  */
5594
5728
  strict(message) {
5595
5729
  return new VldObject({
5596
- ...this.config,
5730
+ ...this._config,
5597
5731
  strict: true,
5598
5732
  passthrough: false,
5599
5733
  errorMessage: message
@@ -5604,7 +5738,7 @@ class VldObject extends VldBase {
5604
5738
  */
5605
5739
  passthrough() {
5606
5740
  return new VldObject({
5607
- ...this.config,
5741
+ ...this._config,
5608
5742
  strict: false,
5609
5743
  passthrough: true
5610
5744
  });
@@ -5614,11 +5748,11 @@ class VldObject extends VldBase {
5614
5748
  */
5615
5749
  partial() {
5616
5750
  const partialShape = {};
5617
- for (const key in this.config.shape) {
5618
- partialShape[key] = new VldOptional(this.config.shape[key]);
5751
+ for (const key in this._config.shape) {
5752
+ partialShape[key] = new VldOptional(this._config.shape[key]);
5619
5753
  }
5620
5754
  return new VldObject({
5621
- ...this.config,
5755
+ ...this._config,
5622
5756
  shape: partialShape
5623
5757
  });
5624
5758
  }
@@ -5627,8 +5761,8 @@ class VldObject extends VldBase {
5627
5761
  */
5628
5762
  deepPartial() {
5629
5763
  const deepPartialShape = {};
5630
- for (const key in this.config.shape) {
5631
- const validator = this.config.shape[key];
5764
+ for (const key in this._config.shape) {
5765
+ const validator = this._config.shape[key];
5632
5766
  if (validator instanceof VldObject) {
5633
5767
  deepPartialShape[key] = new VldOptional(validator.deepPartial());
5634
5768
  }
@@ -5637,7 +5771,7 @@ class VldObject extends VldBase {
5637
5771
  }
5638
5772
  }
5639
5773
  return new VldObject({
5640
- ...this.config,
5774
+ ...this._config,
5641
5775
  shape: deepPartialShape
5642
5776
  });
5643
5777
  }
@@ -5647,12 +5781,12 @@ class VldObject extends VldBase {
5647
5781
  pick(...keys) {
5648
5782
  const pickedShape = {};
5649
5783
  for (const key of keys) {
5650
- if (key in this.config.shape) {
5651
- pickedShape[key] = this.config.shape[key];
5784
+ if (key in this._config.shape) {
5785
+ pickedShape[key] = this._config.shape[key];
5652
5786
  }
5653
5787
  }
5654
5788
  return new VldObject({
5655
- ...this.config,
5789
+ ...this._config,
5656
5790
  shape: pickedShape
5657
5791
  });
5658
5792
  }
@@ -5662,13 +5796,13 @@ class VldObject extends VldBase {
5662
5796
  omit(...keys) {
5663
5797
  const omittedShape = {};
5664
5798
  const keysToOmit = new Set(keys);
5665
- for (const key in this.config.shape) {
5799
+ for (const key in this._config.shape) {
5666
5800
  if (!keysToOmit.has(key)) {
5667
- omittedShape[key] = this.config.shape[key];
5801
+ omittedShape[key] = this._config.shape[key];
5668
5802
  }
5669
5803
  }
5670
5804
  return new VldObject({
5671
- ...this.config,
5805
+ ...this._config,
5672
5806
  shape: omittedShape
5673
5807
  });
5674
5808
  }
@@ -5677,8 +5811,8 @@ class VldObject extends VldBase {
5677
5811
  */
5678
5812
  extend(extension) {
5679
5813
  return new VldObject({
5680
- ...this.config,
5681
- shape: { ...this.config.shape, ...extension }
5814
+ ...this._config,
5815
+ shape: { ...this._config.shape, ...extension }
5682
5816
  });
5683
5817
  }
5684
5818
  /**
@@ -5686,8 +5820,8 @@ class VldObject extends VldBase {
5686
5820
  */
5687
5821
  merge(other) {
5688
5822
  return new VldObject({
5689
- ...this.config,
5690
- shape: { ...this.config.shape, ...other.config.shape }
5823
+ ...this._config,
5824
+ shape: { ...this._config.shape, ...other.config.shape }
5691
5825
  });
5692
5826
  }
5693
5827
  /**
@@ -5695,8 +5829,8 @@ class VldObject extends VldBase {
5695
5829
  */
5696
5830
  required() {
5697
5831
  const requiredShape = {};
5698
- for (const key in this.config.shape) {
5699
- const validator = this.config.shape[key];
5832
+ for (const key in this._config.shape) {
5833
+ const validator = this._config.shape[key];
5700
5834
  // If it's optional, unwrap it
5701
5835
  if (validator instanceof VldOptional) {
5702
5836
  // BUG-001 FIX: Add defensive check for baseValidator property
@@ -5711,7 +5845,7 @@ class VldObject extends VldBase {
5711
5845
  }
5712
5846
  }
5713
5847
  return new VldObject({
5714
- ...this.config,
5848
+ ...this._config,
5715
5849
  shape: requiredShape
5716
5850
  });
5717
5851
  }
@@ -5721,7 +5855,7 @@ class VldObject extends VldBase {
5721
5855
  */
5722
5856
  catchall(schema) {
5723
5857
  return new VldObject({
5724
- ...this.config,
5858
+ ...this._config,
5725
5859
  catchall: schema,
5726
5860
  passthrough: false // catchall overrides passthrough
5727
5861
  });
@@ -5731,14 +5865,14 @@ class VldObject extends VldBase {
5731
5865
  * Zod 4 API parity - returns the shape object
5732
5866
  */
5733
5867
  get shape() {
5734
- return this.config.shape;
5868
+ return this._config.shape;
5735
5869
  }
5736
5870
  /**
5737
5871
  * Create an enum validator from object keys
5738
5872
  * Zod 4 API parity - creates literal union of keys
5739
5873
  */
5740
5874
  keyof() {
5741
- const keys = Object.keys(this.config.shape);
5875
+ const keys = Object.keys(this._config.shape);
5742
5876
  if (keys.length === 0) {
5743
5877
  throw new Error('Cannot create keyof enum from empty object');
5744
5878
  }
@@ -5757,7 +5891,7 @@ class VldObject extends VldBase {
5757
5891
  */
5758
5892
  safeExtend(extension) {
5759
5893
  // Check for overlapping keys
5760
- const existingKeys = new Set(Object.keys(this.config.shape));
5894
+ const existingKeys = new Set(Object.keys(this._config.shape));
5761
5895
  const extensionKeys = Object.keys(extension);
5762
5896
  const overlappingKeys = [];
5763
5897
  for (const key of extensionKeys) {
@@ -5769,8 +5903,8 @@ class VldObject extends VldBase {
5769
5903
  throw new Error(`safeExtend: ${getMessages().safeExtendOverlap(overlappingKeys)}`);
5770
5904
  }
5771
5905
  return new VldObject({
5772
- ...this.config,
5773
- shape: { ...this.config.shape, ...extension }
5906
+ ...this._config,
5907
+ shape: { ...this._config.shape, ...extension }
5774
5908
  });
5775
5909
  }
5776
5910
  }
@@ -6353,11 +6487,17 @@ class VldLiteral extends VldBase {
6353
6487
  /**
6354
6488
  * Private constructor to enforce immutability
6355
6489
  */
6356
- constructor(literal, errorMessage) {
6490
+ constructor(_literal, errorMessage) {
6357
6491
  super();
6358
- this.literal = literal;
6492
+ this._literal = _literal;
6359
6493
  this.errorMessage = errorMessage;
6360
6494
  }
6495
+ /**
6496
+ * Get the literal value
6497
+ */
6498
+ get literal() {
6499
+ return this._literal;
6500
+ }
6361
6501
  /**
6362
6502
  * Create a new literal validator
6363
6503
  */
@@ -6368,23 +6508,23 @@ class VldLiteral extends VldBase {
6368
6508
  * Parse and validate a literal value
6369
6509
  */
6370
6510
  parse(value) {
6371
- if (value !== this.literal) {
6511
+ if (value !== this._literal) {
6372
6512
  throw new Error(this.errorMessage ||
6373
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)));
6513
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)));
6374
6514
  }
6375
- return this.literal;
6515
+ return this._literal;
6376
6516
  }
6377
6517
  /**
6378
6518
  * Safely parse and validate a literal value
6379
6519
  */
6380
6520
  safeParse(value) {
6381
- if (value === this.literal) {
6382
- return { success: true, data: this.literal };
6521
+ if (value === this._literal) {
6522
+ return { success: true, data: this._literal };
6383
6523
  }
6384
6524
  return {
6385
6525
  success: false,
6386
6526
  error: new Error(this.errorMessage ||
6387
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)))
6527
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)))
6388
6528
  };
6389
6529
  }
6390
6530
  }
@@ -6596,27 +6736,56 @@ class VldNan extends VldBase {
6596
6736
  /**
6597
6737
  * Lazy validator - defers schema evaluation until runtime
6598
6738
  * Essential for recursive and self-referencing types
6739
+ *
6740
+ * MEMORY OPTIMIZATION: Uses WeakRef for the cached schema to allow garbage collection
6741
+ * when the validator is no longer in use. This prevents memory leaks in long-running
6742
+ * applications with dynamically created schemas.
6599
6743
  */
6600
6744
  class VldLazy extends VldBase {
6601
6745
  constructor(_schemaGetter) {
6602
6746
  super();
6603
6747
  this._schemaGetter = _schemaGetter;
6604
- this._cachedSchema = null;
6748
+ // Use WeakRef to allow garbage collection of the cached schema
6749
+ this._cachedSchemaRef = null;
6750
+ // Keep a strong reference flag to prevent GC during active use
6751
+ this._strongRef = null;
6605
6752
  }
6606
6753
  static create(schemaGetter) {
6607
6754
  return new VldLazy(schemaGetter);
6608
6755
  }
6609
6756
  /**
6610
6757
  * Get the actual schema, caching it after first retrieval
6758
+ * Uses WeakRef to allow garbage collection when validator is not in use
6611
6759
  */
6612
6760
  _getSchema() {
6613
- if (!this._cachedSchema) {
6614
- this._cachedSchema = this._schemaGetter();
6761
+ // Check if we have a strong reference first (active use)
6762
+ if (this._strongRef) {
6763
+ return this._strongRef;
6764
+ }
6765
+ // Try to get from WeakRef
6766
+ if (this._cachedSchemaRef) {
6767
+ const cached = this._cachedSchemaRef.deref();
6768
+ if (cached) {
6769
+ // Restore strong reference for active use
6770
+ this._strongRef = cached;
6771
+ return cached;
6772
+ }
6615
6773
  }
6616
- return this._cachedSchema;
6774
+ // Create new schema
6775
+ const schema = this._schemaGetter();
6776
+ this._cachedSchemaRef = new WeakRef(schema);
6777
+ this._strongRef = schema;
6778
+ // Clear strong reference after a tick to allow GC
6779
+ // This keeps the schema alive during synchronous operations
6780
+ // but allows it to be collected if the validator is discarded
6781
+ Promise.resolve().then(() => {
6782
+ this._strongRef = null;
6783
+ });
6784
+ return schema;
6617
6785
  }
6618
6786
  /**
6619
6787
  * Get the inner schema (unwrap)
6788
+ * Returns a strong reference that will keep the schema alive
6620
6789
  */
6621
6790
  unwrap() {
6622
6791
  return this._getSchema();
@@ -6639,11 +6808,10 @@ class VldLazy extends VldBase {
6639
6808
  */
6640
6809
  function extractLiteralValues(schema) {
6641
6810
  if (schema instanceof VldLiteral) {
6642
- const value = schema.literal;
6643
- return [value];
6811
+ return [schema.literal];
6644
6812
  }
6645
6813
  if (schema instanceof VldEnum) {
6646
- return schema.values;
6814
+ return [...schema.values];
6647
6815
  }
6648
6816
  throw new Error('Discriminator must be a literal or enum schema');
6649
6817
  }