@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
@@ -3478,6 +3478,7 @@ const REGEX_PATTERNS = {
3478
3478
  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]?)$/};
3479
3479
  /**
3480
3480
  * Immutable string validator with chainable methods
3481
+ * Features pre-compiled validation functions for maximum performance
3481
3482
  */
3482
3483
  class VldString extends VldBase {
3483
3484
  /**
@@ -3485,12 +3486,100 @@ class VldString extends VldBase {
3485
3486
  */
3486
3487
  constructor(config) {
3487
3488
  super();
3489
+ // Cache for pre-compiled validation function
3490
+ this._compiledValidator = null;
3488
3491
  this.config = {
3489
3492
  checks: config?.checks || [],
3490
3493
  transforms: config?.transforms || [],
3491
3494
  errorMessage: config?.errorMessage
3492
3495
  };
3493
3496
  }
3497
+ /**
3498
+ * Compile all transforms and checks into a single optimized function
3499
+ * This eliminates loop overhead and enables better JIT optimization
3500
+ */
3501
+ _compileValidator() {
3502
+ const transforms = this.config.transforms;
3503
+ const checks = this.config.checks;
3504
+ const errorMessage = this.config.errorMessage || getMessages().invalidString;
3505
+ // Fast path: no transforms or checks
3506
+ if (transforms.length === 0 && checks.length === 0) {
3507
+ return (value) => ({ success: true, value });
3508
+ }
3509
+ // Fast path: only transforms, no checks
3510
+ if (checks.length === 0) {
3511
+ switch (transforms.length) {
3512
+ case 1:
3513
+ return (value) => ({ success: true, value: transforms[0](value) });
3514
+ case 2:
3515
+ return (value) => ({ success: true, value: transforms[1](transforms[0](value)) });
3516
+ case 3:
3517
+ return (value) => ({ success: true, value: transforms[2](transforms[1](transforms[0](value))) });
3518
+ default:
3519
+ return (value) => {
3520
+ let result = value;
3521
+ for (let i = 0; i < transforms.length; i++) {
3522
+ result = transforms[i](result);
3523
+ }
3524
+ return { success: true, value: result };
3525
+ };
3526
+ }
3527
+ }
3528
+ // Fast path: only checks, no transforms
3529
+ if (transforms.length === 0) {
3530
+ switch (checks.length) {
3531
+ case 1:
3532
+ return (value) => {
3533
+ if (!checks[0](value))
3534
+ return { success: false, error: errorMessage };
3535
+ return { success: true, value };
3536
+ };
3537
+ case 2:
3538
+ return (value) => {
3539
+ if (!checks[0](value) || !checks[1](value))
3540
+ return { success: false, error: errorMessage };
3541
+ return { success: true, value };
3542
+ };
3543
+ case 3:
3544
+ return (value) => {
3545
+ if (!checks[0](value) || !checks[1](value) || !checks[2](value))
3546
+ return { success: false, error: errorMessage };
3547
+ return { success: true, value };
3548
+ };
3549
+ default:
3550
+ return (value) => {
3551
+ for (let i = 0; i < checks.length; i++) {
3552
+ if (!checks[i](value))
3553
+ return { success: false, error: errorMessage };
3554
+ }
3555
+ return { success: true, value };
3556
+ };
3557
+ }
3558
+ }
3559
+ // General case: both transforms and checks
3560
+ return (value) => {
3561
+ let result = value;
3562
+ // Apply transforms
3563
+ for (let i = 0; i < transforms.length; i++) {
3564
+ result = transforms[i](result);
3565
+ }
3566
+ // Apply checks
3567
+ for (let i = 0; i < checks.length; i++) {
3568
+ if (!checks[i](result))
3569
+ return { success: false, error: errorMessage };
3570
+ }
3571
+ return { success: true, value: result };
3572
+ };
3573
+ }
3574
+ /**
3575
+ * Get the cached compiled validator, creating it if necessary
3576
+ */
3577
+ _getCompiledValidator() {
3578
+ if (!this._compiledValidator) {
3579
+ this._compiledValidator = this._compileValidator();
3580
+ }
3581
+ return this._compiledValidator;
3582
+ }
3494
3583
  /**
3495
3584
  * Create a new string validator
3496
3585
  */
@@ -3498,26 +3587,18 @@ class VldString extends VldBase {
3498
3587
  return new VldString();
3499
3588
  }
3500
3589
  /**
3501
- * Parse and validate a string value - ultra-optimized
3590
+ * Parse and validate a string value - ultra-optimized with pre-compiled validator
3502
3591
  */
3503
3592
  parse(value) {
3504
3593
  if (typeof value !== 'string') {
3505
3594
  throw new Error(this.config.errorMessage || getMessages().invalidString);
3506
3595
  }
3507
- let result = value;
3508
- // Apply transformations with optimized loop
3509
- const transformsLength = this.config.transforms.length;
3510
- for (let i = 0; i < transformsLength; i++) {
3511
- result = this.config.transforms[i](result);
3512
- }
3513
- // Apply checks with optimized loop and early termination
3514
- const checksLength = this.config.checks.length;
3515
- for (let i = 0; i < checksLength; i++) {
3516
- if (!this.config.checks[i](result)) {
3517
- throw new Error(this.config.errorMessage || getMessages().invalidString);
3518
- }
3596
+ // Use pre-compiled validator for maximum performance
3597
+ const result = this._getCompiledValidator()(value);
3598
+ if (!result.success) {
3599
+ throw new Error(result.error);
3519
3600
  }
3520
- return result;
3601
+ return result.value;
3521
3602
  }
3522
3603
  /**
3523
3604
  * Safely parse and validate a string value
@@ -4439,16 +4520,9 @@ class VldArray extends VldBase {
4439
4520
  }
4440
4521
  result[i] = parseResult.data; // Direct assignment is faster than push
4441
4522
  }
4442
- // Check uniqueness if required
4523
+ // Check uniqueness if required - optimized with Map-based approach
4443
4524
  if (this.config.unique) {
4444
- const seen = new Set();
4445
- for (const item of result) {
4446
- const key = typeof item === 'object' ? this.stableStringify(item) : item;
4447
- if (seen.has(key)) {
4448
- throw new Error('Array must contain unique items');
4449
- }
4450
- seen.add(key);
4451
- }
4525
+ this.checkUnique(result);
4452
4526
  }
4453
4527
  return result;
4454
4528
  }
@@ -4463,6 +4537,38 @@ class VldArray extends VldBase {
4463
4537
  return { success: false, error: error };
4464
4538
  }
4465
4539
  }
4540
+ /**
4541
+ * Optimized uniqueness check using Map-based approach
4542
+ * Avoids repeated stableStringify calls by caching serialized values
4543
+ */
4544
+ checkUnique(items) {
4545
+ const seen = new Set(); // Set of seen keys
4546
+ const objectKeys = new WeakMap(); // Cache for object->string mappings
4547
+ for (const item of items) {
4548
+ let key;
4549
+ if (typeof item === 'object' && item !== null) {
4550
+ // Check if we've already serialized this object reference
4551
+ const cached = objectKeys.get(item);
4552
+ if (cached !== undefined) {
4553
+ key = cached;
4554
+ }
4555
+ else {
4556
+ // Serialize and cache
4557
+ const serialized = this.stableStringify(item);
4558
+ key = serialized;
4559
+ objectKeys.set(item, serialized);
4560
+ }
4561
+ }
4562
+ else {
4563
+ // Primitives can be used directly as keys
4564
+ key = item;
4565
+ }
4566
+ if (seen.has(key)) {
4567
+ throw new Error('Array must contain unique items');
4568
+ }
4569
+ seen.add(key);
4570
+ }
4571
+ }
4466
4572
  /**
4467
4573
  * Create a stable string representation of an object for hashing
4468
4574
  * Handles circular references and deep nesting gracefully
@@ -4590,11 +4696,17 @@ class VldEnum extends VldBase {
4590
4696
  /**
4591
4697
  * Private constructor to enforce immutability
4592
4698
  */
4593
- constructor(values, errorMessage) {
4699
+ constructor(_values, errorMessage) {
4594
4700
  super();
4595
- this.values = values;
4701
+ this._values = _values;
4596
4702
  this.errorMessage = errorMessage;
4597
4703
  }
4704
+ /**
4705
+ * Get the enum values
4706
+ */
4707
+ get values() {
4708
+ return this._values;
4709
+ }
4598
4710
  /**
4599
4711
  * Create a new enum validator
4600
4712
  */
@@ -4608,11 +4720,11 @@ class VldEnum extends VldBase {
4608
4720
  // BUG-002 FIX: Add type check before includes() to prevent type confusion
4609
4721
  if (typeof value !== 'string') {
4610
4722
  throw new Error(this.errorMessage ||
4611
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
4723
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
4612
4724
  }
4613
- if (!this.values.includes(value)) {
4725
+ if (!this._values.includes(value)) {
4614
4726
  throw new Error(this.errorMessage ||
4615
- getMessages().enumExpected([...this.values], JSON.stringify(value)));
4727
+ getMessages().enumExpected([...this._values], JSON.stringify(value)));
4616
4728
  }
4617
4729
  return value;
4618
4730
  }
@@ -4625,16 +4737,16 @@ class VldEnum extends VldBase {
4625
4737
  return {
4626
4738
  success: false,
4627
4739
  error: new Error(this.errorMessage ||
4628
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
4740
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
4629
4741
  };
4630
4742
  }
4631
- if (this.values.includes(value)) {
4743
+ if (this._values.includes(value)) {
4632
4744
  return { success: true, data: value };
4633
4745
  }
4634
4746
  return {
4635
4747
  success: false,
4636
4748
  error: new Error(this.errorMessage ||
4637
- getMessages().enumExpected([...this.values], JSON.stringify(value)))
4749
+ getMessages().enumExpected([...this._values], JSON.stringify(value)))
4638
4750
  };
4639
4751
  }
4640
4752
  /**
@@ -4642,7 +4754,7 @@ class VldEnum extends VldBase {
4642
4754
  * Creates a new enum validator without the specified values
4643
4755
  */
4644
4756
  exclude(...excludeValues) {
4645
- const filtered = this.values.filter(v => !excludeValues.includes(v));
4757
+ const filtered = this._values.filter(v => !excludeValues.includes(v));
4646
4758
  if (filtered.length === 0) {
4647
4759
  throw new Error('Cannot exclude all enum values');
4648
4760
  }
@@ -4654,7 +4766,7 @@ class VldEnum extends VldBase {
4654
4766
  * Creates a new enum validator with only the specified values
4655
4767
  */
4656
4768
  extract(...extractValues) {
4657
- const extracted = this.values.filter(v => extractValues.includes(v));
4769
+ const extracted = this._values.filter(v => extractValues.includes(v));
4658
4770
  if (extracted.length === 0) {
4659
4771
  throw new Error('Cannot extract non-existent enum values');
4660
4772
  }
@@ -5175,10 +5287,30 @@ class VldObject extends VldBase {
5175
5287
  */
5176
5288
  constructor(config) {
5177
5289
  super();
5178
- this.config = config;
5290
+ this._config = config;
5179
5291
  // Pre-compute shape keys for faster access
5180
- this.shapeKeys = Object.keys(config.shape);
5181
- this.shapeKeysSet = new Set(this.shapeKeys);
5292
+ this._shapeKeys = Object.keys(config.shape);
5293
+ this._shapeKeysSet = new Set(this._shapeKeys);
5294
+ }
5295
+ /**
5296
+ * Get the validator configuration
5297
+ * @internal Used by discriminated union validator
5298
+ */
5299
+ get config() {
5300
+ return this._config;
5301
+ }
5302
+ /**
5303
+ * Get the shape keys array
5304
+ */
5305
+ get shapeKeys() {
5306
+ return this._shapeKeys;
5307
+ }
5308
+ /**
5309
+ * Get the shape keys set for O(1) lookups
5310
+ * @internal Used by discriminated union validator
5311
+ */
5312
+ get shapeKeysSet() {
5313
+ return this._shapeKeysSet;
5182
5314
  }
5183
5315
  /**
5184
5316
  * Create a new object validator
@@ -5193,14 +5325,14 @@ class VldObject extends VldBase {
5193
5325
  parse(value) {
5194
5326
  // Fast type check
5195
5327
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
5196
- throw new Error(this.config.errorMessage || getMessages().invalidObject);
5328
+ throw new Error(this._config.errorMessage || getMessages().invalidObject);
5197
5329
  }
5198
5330
  const obj = value;
5199
5331
  const result = {};
5200
5332
  // Ultra-optimized field validation with inline fast paths
5201
- for (let i = 0; i < this.shapeKeys.length; i++) {
5202
- const key = this.shapeKeys[i];
5203
- const validator = this.config.shape[key];
5333
+ for (let i = 0; i < this._shapeKeys.length; i++) {
5334
+ const key = this._shapeKeys[i];
5335
+ const validator = this._config.shape[key];
5204
5336
  const fieldValue = obj[key];
5205
5337
  // BUG-NEW-002 FIX: Use instanceof instead of constructor.name
5206
5338
  // constructor.name breaks in minified builds where class names become 'a', 'b', etc.
@@ -5257,38 +5389,39 @@ class VldObject extends VldBase {
5257
5389
  result[key] = parseResult.data;
5258
5390
  }
5259
5391
  }
5260
- // Handle strict mode - optimized with Set
5261
- if (this.config.strict) {
5392
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
5393
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
5262
5394
  const objKeys = Object.keys(obj);
5263
- const extraKeys = [];
5264
- for (let i = 0; i < objKeys.length; i++) {
5265
- if (!this.shapeKeysSet.has(objKeys[i])) {
5266
- extraKeys.push(objKeys[i]);
5395
+ // Handle strict mode - optimized with Set
5396
+ if (this._config.strict) {
5397
+ const extraKeys = [];
5398
+ for (let i = 0; i < objKeys.length; i++) {
5399
+ if (!this._shapeKeysSet.has(objKeys[i])) {
5400
+ extraKeys.push(objKeys[i]);
5401
+ }
5402
+ }
5403
+ if (extraKeys.length > 0) {
5404
+ throw new Error(getMessages().unexpectedKeys(extraKeys));
5267
5405
  }
5268
5406
  }
5269
- if (extraKeys.length > 0) {
5270
- throw new Error(getMessages().unexpectedKeys(extraKeys));
5271
- }
5272
- }
5273
- // Handle passthrough mode - optimized with comprehensive prototype pollution protection
5274
- if (this.config.passthrough) {
5275
- const objKeys = Object.keys(obj);
5276
- for (let i = 0; i < objKeys.length; i++) {
5277
- const key = objKeys[i];
5278
- // Skip dangerous keys to prevent prototype pollution
5279
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5280
- result[key] = obj[key];
5407
+ // Handle passthrough mode - optimized with comprehensive prototype pollution protection
5408
+ if (this._config.passthrough) {
5409
+ for (let i = 0; i < objKeys.length; i++) {
5410
+ const key = objKeys[i];
5411
+ // Skip dangerous keys to prevent prototype pollution
5412
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5413
+ result[key] = obj[key];
5414
+ }
5281
5415
  }
5282
5416
  }
5283
- }
5284
- // Handle catchall - validate extra keys with catchall validator
5285
- if (this.config.catchall) {
5286
- const objKeys = Object.keys(obj);
5287
- for (let i = 0; i < objKeys.length; i++) {
5288
- const key = objKeys[i];
5289
- // Skip keys already in shape and dangerous keys
5290
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5291
- result[key] = this.config.catchall.parse(obj[key]);
5417
+ // Handle catchall - validate extra keys with catchall validator
5418
+ if (this._config.catchall) {
5419
+ for (let i = 0; i < objKeys.length; i++) {
5420
+ const key = objKeys[i];
5421
+ // Skip keys already in shape and dangerous keys
5422
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5423
+ result[key] = this._config.catchall.parse(obj[key]);
5424
+ }
5292
5425
  }
5293
5426
  }
5294
5427
  }
@@ -5303,15 +5436,15 @@ class VldObject extends VldBase {
5303
5436
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
5304
5437
  return {
5305
5438
  success: false,
5306
- error: new Error(this.config.errorMessage || getMessages().invalidObject)
5439
+ error: new Error(this._config.errorMessage || getMessages().invalidObject)
5307
5440
  };
5308
5441
  }
5309
5442
  const obj = value;
5310
5443
  const result = {};
5311
5444
  // Validate all fields
5312
- for (let i = 0; i < this.shapeKeys.length; i++) {
5313
- const key = this.shapeKeys[i];
5314
- const validator = this.config.shape[key];
5445
+ for (let i = 0; i < this._shapeKeys.length; i++) {
5446
+ const key = this._shapeKeys[i];
5447
+ const validator = this._config.shape[key];
5315
5448
  const fieldValue = obj[key];
5316
5449
  const parseResult = validator.safeParse(fieldValue);
5317
5450
  if (parseResult.success) {
@@ -5324,48 +5457,49 @@ class VldObject extends VldBase {
5324
5457
  };
5325
5458
  }
5326
5459
  }
5327
- // Handle strict mode
5328
- if (this.config.strict) {
5460
+ // Handle strict/passthrough/catchall modes - optimized single Object.keys() call
5461
+ if (this._config.strict || this._config.passthrough || this._config.catchall) {
5329
5462
  const objKeys = Object.keys(obj);
5330
- const extraKeys = [];
5331
- for (let i = 0; i < objKeys.length; i++) {
5332
- if (!this.shapeKeysSet.has(objKeys[i])) {
5333
- extraKeys.push(objKeys[i]);
5463
+ // Handle strict mode
5464
+ if (this._config.strict) {
5465
+ const extraKeys = [];
5466
+ for (let i = 0; i < objKeys.length; i++) {
5467
+ if (!this._shapeKeysSet.has(objKeys[i])) {
5468
+ extraKeys.push(objKeys[i]);
5469
+ }
5470
+ }
5471
+ if (extraKeys.length > 0) {
5472
+ return {
5473
+ success: false,
5474
+ error: new Error(getMessages().unexpectedKeys(extraKeys))
5475
+ };
5334
5476
  }
5335
5477
  }
5336
- if (extraKeys.length > 0) {
5337
- return {
5338
- success: false,
5339
- error: new Error(getMessages().unexpectedKeys(extraKeys))
5340
- };
5341
- }
5342
- }
5343
- // Handle passthrough mode with comprehensive prototype pollution protection
5344
- if (this.config.passthrough) {
5345
- const objKeys = Object.keys(obj);
5346
- for (let i = 0; i < objKeys.length; i++) {
5347
- const key = objKeys[i];
5348
- // Skip dangerous keys to prevent prototype pollution
5349
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5350
- result[key] = obj[key];
5478
+ // Handle passthrough mode with comprehensive prototype pollution protection
5479
+ if (this._config.passthrough) {
5480
+ for (let i = 0; i < objKeys.length; i++) {
5481
+ const key = objKeys[i];
5482
+ // Skip dangerous keys to prevent prototype pollution
5483
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5484
+ result[key] = obj[key];
5485
+ }
5351
5486
  }
5352
5487
  }
5353
- }
5354
- // Handle catchall - validate extra keys with catchall validator
5355
- if (this.config.catchall) {
5356
- const objKeys = Object.keys(obj);
5357
- for (let i = 0; i < objKeys.length; i++) {
5358
- const key = objKeys[i];
5359
- // Skip keys already in shape and dangerous keys
5360
- if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5361
- const catchallResult = this.config.catchall.safeParse(obj[key]);
5362
- if (!catchallResult.success) {
5363
- return {
5364
- success: false,
5365
- error: new Error(getMessages().objectField(key, catchallResult.error.message))
5366
- };
5488
+ // Handle catchall - validate extra keys with catchall validator
5489
+ if (this._config.catchall) {
5490
+ for (let i = 0; i < objKeys.length; i++) {
5491
+ const key = objKeys[i];
5492
+ // Skip keys already in shape and dangerous keys
5493
+ if (!this._shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
5494
+ const catchallResult = this._config.catchall.safeParse(obj[key]);
5495
+ if (!catchallResult.success) {
5496
+ return {
5497
+ success: false,
5498
+ error: new Error(getMessages().objectField(key, catchallResult.error.message))
5499
+ };
5500
+ }
5501
+ result[key] = catchallResult.data;
5367
5502
  }
5368
- result[key] = catchallResult.data;
5369
5503
  }
5370
5504
  }
5371
5505
  }
@@ -5430,7 +5564,7 @@ class VldObject extends VldBase {
5430
5564
  */
5431
5565
  strict(message) {
5432
5566
  return new VldObject({
5433
- ...this.config,
5567
+ ...this._config,
5434
5568
  strict: true,
5435
5569
  passthrough: false,
5436
5570
  errorMessage: message
@@ -5441,7 +5575,7 @@ class VldObject extends VldBase {
5441
5575
  */
5442
5576
  passthrough() {
5443
5577
  return new VldObject({
5444
- ...this.config,
5578
+ ...this._config,
5445
5579
  strict: false,
5446
5580
  passthrough: true
5447
5581
  });
@@ -5451,11 +5585,11 @@ class VldObject extends VldBase {
5451
5585
  */
5452
5586
  partial() {
5453
5587
  const partialShape = {};
5454
- for (const key in this.config.shape) {
5455
- partialShape[key] = new VldOptional(this.config.shape[key]);
5588
+ for (const key in this._config.shape) {
5589
+ partialShape[key] = new VldOptional(this._config.shape[key]);
5456
5590
  }
5457
5591
  return new VldObject({
5458
- ...this.config,
5592
+ ...this._config,
5459
5593
  shape: partialShape
5460
5594
  });
5461
5595
  }
@@ -5464,8 +5598,8 @@ class VldObject extends VldBase {
5464
5598
  */
5465
5599
  deepPartial() {
5466
5600
  const deepPartialShape = {};
5467
- for (const key in this.config.shape) {
5468
- const validator = this.config.shape[key];
5601
+ for (const key in this._config.shape) {
5602
+ const validator = this._config.shape[key];
5469
5603
  if (validator instanceof VldObject) {
5470
5604
  deepPartialShape[key] = new VldOptional(validator.deepPartial());
5471
5605
  }
@@ -5474,7 +5608,7 @@ class VldObject extends VldBase {
5474
5608
  }
5475
5609
  }
5476
5610
  return new VldObject({
5477
- ...this.config,
5611
+ ...this._config,
5478
5612
  shape: deepPartialShape
5479
5613
  });
5480
5614
  }
@@ -5484,12 +5618,12 @@ class VldObject extends VldBase {
5484
5618
  pick(...keys) {
5485
5619
  const pickedShape = {};
5486
5620
  for (const key of keys) {
5487
- if (key in this.config.shape) {
5488
- pickedShape[key] = this.config.shape[key];
5621
+ if (key in this._config.shape) {
5622
+ pickedShape[key] = this._config.shape[key];
5489
5623
  }
5490
5624
  }
5491
5625
  return new VldObject({
5492
- ...this.config,
5626
+ ...this._config,
5493
5627
  shape: pickedShape
5494
5628
  });
5495
5629
  }
@@ -5499,13 +5633,13 @@ class VldObject extends VldBase {
5499
5633
  omit(...keys) {
5500
5634
  const omittedShape = {};
5501
5635
  const keysToOmit = new Set(keys);
5502
- for (const key in this.config.shape) {
5636
+ for (const key in this._config.shape) {
5503
5637
  if (!keysToOmit.has(key)) {
5504
- omittedShape[key] = this.config.shape[key];
5638
+ omittedShape[key] = this._config.shape[key];
5505
5639
  }
5506
5640
  }
5507
5641
  return new VldObject({
5508
- ...this.config,
5642
+ ...this._config,
5509
5643
  shape: omittedShape
5510
5644
  });
5511
5645
  }
@@ -5514,8 +5648,8 @@ class VldObject extends VldBase {
5514
5648
  */
5515
5649
  extend(extension) {
5516
5650
  return new VldObject({
5517
- ...this.config,
5518
- shape: { ...this.config.shape, ...extension }
5651
+ ...this._config,
5652
+ shape: { ...this._config.shape, ...extension }
5519
5653
  });
5520
5654
  }
5521
5655
  /**
@@ -5523,8 +5657,8 @@ class VldObject extends VldBase {
5523
5657
  */
5524
5658
  merge(other) {
5525
5659
  return new VldObject({
5526
- ...this.config,
5527
- shape: { ...this.config.shape, ...other.config.shape }
5660
+ ...this._config,
5661
+ shape: { ...this._config.shape, ...other.config.shape }
5528
5662
  });
5529
5663
  }
5530
5664
  /**
@@ -5532,8 +5666,8 @@ class VldObject extends VldBase {
5532
5666
  */
5533
5667
  required() {
5534
5668
  const requiredShape = {};
5535
- for (const key in this.config.shape) {
5536
- const validator = this.config.shape[key];
5669
+ for (const key in this._config.shape) {
5670
+ const validator = this._config.shape[key];
5537
5671
  // If it's optional, unwrap it
5538
5672
  if (validator instanceof VldOptional) {
5539
5673
  // BUG-001 FIX: Add defensive check for baseValidator property
@@ -5548,7 +5682,7 @@ class VldObject extends VldBase {
5548
5682
  }
5549
5683
  }
5550
5684
  return new VldObject({
5551
- ...this.config,
5685
+ ...this._config,
5552
5686
  shape: requiredShape
5553
5687
  });
5554
5688
  }
@@ -5558,7 +5692,7 @@ class VldObject extends VldBase {
5558
5692
  */
5559
5693
  catchall(schema) {
5560
5694
  return new VldObject({
5561
- ...this.config,
5695
+ ...this._config,
5562
5696
  catchall: schema,
5563
5697
  passthrough: false // catchall overrides passthrough
5564
5698
  });
@@ -5568,14 +5702,14 @@ class VldObject extends VldBase {
5568
5702
  * Zod 4 API parity - returns the shape object
5569
5703
  */
5570
5704
  get shape() {
5571
- return this.config.shape;
5705
+ return this._config.shape;
5572
5706
  }
5573
5707
  /**
5574
5708
  * Create an enum validator from object keys
5575
5709
  * Zod 4 API parity - creates literal union of keys
5576
5710
  */
5577
5711
  keyof() {
5578
- const keys = Object.keys(this.config.shape);
5712
+ const keys = Object.keys(this._config.shape);
5579
5713
  if (keys.length === 0) {
5580
5714
  throw new Error('Cannot create keyof enum from empty object');
5581
5715
  }
@@ -5594,7 +5728,7 @@ class VldObject extends VldBase {
5594
5728
  */
5595
5729
  safeExtend(extension) {
5596
5730
  // Check for overlapping keys
5597
- const existingKeys = new Set(Object.keys(this.config.shape));
5731
+ const existingKeys = new Set(Object.keys(this._config.shape));
5598
5732
  const extensionKeys = Object.keys(extension);
5599
5733
  const overlappingKeys = [];
5600
5734
  for (const key of extensionKeys) {
@@ -5606,8 +5740,8 @@ class VldObject extends VldBase {
5606
5740
  throw new Error(`safeExtend: ${getMessages().safeExtendOverlap(overlappingKeys)}`);
5607
5741
  }
5608
5742
  return new VldObject({
5609
- ...this.config,
5610
- shape: { ...this.config.shape, ...extension }
5743
+ ...this._config,
5744
+ shape: { ...this._config.shape, ...extension }
5611
5745
  });
5612
5746
  }
5613
5747
  }
@@ -5743,11 +5877,17 @@ class VldLiteral extends VldBase {
5743
5877
  /**
5744
5878
  * Private constructor to enforce immutability
5745
5879
  */
5746
- constructor(literal, errorMessage) {
5880
+ constructor(_literal, errorMessage) {
5747
5881
  super();
5748
- this.literal = literal;
5882
+ this._literal = _literal;
5749
5883
  this.errorMessage = errorMessage;
5750
5884
  }
5885
+ /**
5886
+ * Get the literal value
5887
+ */
5888
+ get literal() {
5889
+ return this._literal;
5890
+ }
5751
5891
  /**
5752
5892
  * Create a new literal validator
5753
5893
  */
@@ -5758,23 +5898,23 @@ class VldLiteral extends VldBase {
5758
5898
  * Parse and validate a literal value
5759
5899
  */
5760
5900
  parse(value) {
5761
- if (value !== this.literal) {
5901
+ if (value !== this._literal) {
5762
5902
  throw new Error(this.errorMessage ||
5763
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)));
5903
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)));
5764
5904
  }
5765
- return this.literal;
5905
+ return this._literal;
5766
5906
  }
5767
5907
  /**
5768
5908
  * Safely parse and validate a literal value
5769
5909
  */
5770
5910
  safeParse(value) {
5771
- if (value === this.literal) {
5772
- return { success: true, data: this.literal };
5911
+ if (value === this._literal) {
5912
+ return { success: true, data: this._literal };
5773
5913
  }
5774
5914
  return {
5775
5915
  success: false,
5776
5916
  error: new Error(this.errorMessage ||
5777
- getMessages().literalExpected(JSON.stringify(this.literal), JSON.stringify(value)))
5917
+ getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)))
5778
5918
  };
5779
5919
  }
5780
5920
  }
@@ -6613,27 +6753,56 @@ class VldNan extends VldBase {
6613
6753
  /**
6614
6754
  * Lazy validator - defers schema evaluation until runtime
6615
6755
  * Essential for recursive and self-referencing types
6756
+ *
6757
+ * MEMORY OPTIMIZATION: Uses WeakRef for the cached schema to allow garbage collection
6758
+ * when the validator is no longer in use. This prevents memory leaks in long-running
6759
+ * applications with dynamically created schemas.
6616
6760
  */
6617
6761
  class VldLazy extends VldBase {
6618
6762
  constructor(_schemaGetter) {
6619
6763
  super();
6620
6764
  this._schemaGetter = _schemaGetter;
6621
- this._cachedSchema = null;
6765
+ // Use WeakRef to allow garbage collection of the cached schema
6766
+ this._cachedSchemaRef = null;
6767
+ // Keep a strong reference flag to prevent GC during active use
6768
+ this._strongRef = null;
6622
6769
  }
6623
6770
  static create(schemaGetter) {
6624
6771
  return new VldLazy(schemaGetter);
6625
6772
  }
6626
6773
  /**
6627
6774
  * Get the actual schema, caching it after first retrieval
6775
+ * Uses WeakRef to allow garbage collection when validator is not in use
6628
6776
  */
6629
6777
  _getSchema() {
6630
- if (!this._cachedSchema) {
6631
- this._cachedSchema = this._schemaGetter();
6632
- }
6633
- return this._cachedSchema;
6778
+ // Check if we have a strong reference first (active use)
6779
+ if (this._strongRef) {
6780
+ return this._strongRef;
6781
+ }
6782
+ // Try to get from WeakRef
6783
+ if (this._cachedSchemaRef) {
6784
+ const cached = this._cachedSchemaRef.deref();
6785
+ if (cached) {
6786
+ // Restore strong reference for active use
6787
+ this._strongRef = cached;
6788
+ return cached;
6789
+ }
6790
+ }
6791
+ // Create new schema
6792
+ const schema = this._schemaGetter();
6793
+ this._cachedSchemaRef = new WeakRef(schema);
6794
+ this._strongRef = schema;
6795
+ // Clear strong reference after a tick to allow GC
6796
+ // This keeps the schema alive during synchronous operations
6797
+ // but allows it to be collected if the validator is discarded
6798
+ Promise.resolve().then(() => {
6799
+ this._strongRef = null;
6800
+ });
6801
+ return schema;
6634
6802
  }
6635
6803
  /**
6636
6804
  * Get the inner schema (unwrap)
6805
+ * Returns a strong reference that will keep the schema alive
6637
6806
  */
6638
6807
  unwrap() {
6639
6808
  return this._getSchema();
@@ -6656,11 +6825,10 @@ class VldLazy extends VldBase {
6656
6825
  */
6657
6826
  function extractLiteralValues(schema) {
6658
6827
  if (schema instanceof VldLiteral) {
6659
- const value = schema.literal;
6660
- return [value];
6828
+ return [schema.literal];
6661
6829
  }
6662
6830
  if (schema instanceof VldEnum) {
6663
- return schema.values;
6831
+ return [...schema.values];
6664
6832
  }
6665
6833
  throw new Error('Discriminator must be a literal or enum schema');
6666
6834
  }