@oxog/vld 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/README.md +2 -2
- package/dist/chunks/{bigint-ZKkWLdmi.js → bigint-CRS0QVsy.js} +242 -16
- package/dist/chunks/bigint-CRS0QVsy.js.map +1 -0
- package/dist/chunks/{date-7Iz2BGsL.js → date-50JV_Mfj.js} +2 -2
- package/dist/chunks/{date-7Iz2BGsL.js.map → date-50JV_Mfj.js.map} +1 -1
- package/dist/chunks/{index-BoV-4S1F.js → index-DO8CFMxD.js} +4 -4
- package/dist/chunks/{index-BoV-4S1F.js.map → index-DO8CFMxD.js.map} +1 -1
- package/dist/chunks/{json-nIhyRPOU.js → json-Cp4WO0M9.js} +226 -139
- package/dist/chunks/json-Cp4WO0M9.js.map +1 -0
- package/dist/chunks/{unknown-CjSRcELI.js → unknown-Dhzri_T-.js} +2 -2
- package/dist/chunks/{unknown-CjSRcELI.js.map → unknown-Dhzri_T-.js.map} +1 -1
- package/dist/cjs/index.cjs +1095 -151
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/mini.cjs +462 -149
- package/dist/cjs/mini.cjs.map +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/codecs/index.js +3 -3
- package/dist/coercion/index.js +2 -2
- package/dist/index.d.ts +244 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +550 -11
- package/dist/index.js.map +1 -1
- package/dist/mini.js +5 -5
- package/dist/utils/json-schema.d.ts +67 -0
- package/dist/utils/json-schema.d.ts.map +1 -0
- package/dist/validators/array.d.ts +5 -0
- package/dist/validators/array.d.ts.map +1 -1
- package/dist/validators/base.d.ts +79 -0
- package/dist/validators/base.d.ts.map +1 -1
- package/dist/validators/discriminated-union.d.ts.map +1 -1
- package/dist/validators/enum.d.ts +5 -1
- package/dist/validators/enum.d.ts.map +1 -1
- package/dist/validators/index.d.ts +3 -2
- package/dist/validators/index.d.ts.map +1 -1
- package/dist/validators/index.js +514 -4
- package/dist/validators/index.js.map +1 -1
- package/dist/validators/lazy.d.ts +8 -1
- package/dist/validators/lazy.d.ts.map +1 -1
- package/dist/validators/literal.d.ts +5 -1
- package/dist/validators/literal.d.ts.map +1 -1
- package/dist/validators/number.d.ts +30 -0
- package/dist/validators/number.d.ts.map +1 -1
- package/dist/validators/object.d.ts +30 -3
- package/dist/validators/object.d.ts.map +1 -1
- package/dist/validators/promise.d.ts +53 -0
- package/dist/validators/promise.d.ts.map +1 -0
- package/dist/validators/string-formats.d.ts +6 -0
- package/dist/validators/string-formats.d.ts.map +1 -1
- package/dist/validators/string.d.ts +12 -1
- package/dist/validators/string.d.ts.map +1 -1
- package/package.json +6 -5
- package/dist/chunks/bigint-ZKkWLdmi.js.map +0 -1
- package/dist/chunks/index-eWXdjyyy.js +0 -426
- package/dist/chunks/index-eWXdjyyy.js.map +0 -1
- package/dist/chunks/json-nIhyRPOU.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as VldBase,
|
|
2
|
-
import { c as VldCoerceString, b as VldCoerceNumber, a as VldCoerceBoolean, V as VldCoerceDate } from './date-
|
|
1
|
+
import { i as VldBase, u as getMessages, h as VldString, c as VldNumber, a as VldBoolean, b as VldDate, f as VldOptional } from './bigint-CRS0QVsy.js';
|
|
2
|
+
import { c as VldCoerceString, b as VldCoerceNumber, a as VldCoerceBoolean, V as VldCoerceDate } from './date-50JV_Mfj.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
|
-
|
|
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(
|
|
349
|
+
constructor(_values, errorMessage) {
|
|
325
350
|
super();
|
|
326
|
-
this.
|
|
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.
|
|
373
|
+
getMessages().enumExpected([...this._values], JSON.stringify(value)));
|
|
343
374
|
}
|
|
344
|
-
if (!this.
|
|
375
|
+
if (!this._values.includes(value)) {
|
|
345
376
|
throw new Error(this.errorMessage ||
|
|
346
|
-
getMessages().enumExpected([...this.
|
|
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.
|
|
390
|
+
getMessages().enumExpected([...this._values], JSON.stringify(value)))
|
|
360
391
|
};
|
|
361
392
|
}
|
|
362
|
-
if (this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
438
|
+
this._config = config;
|
|
408
439
|
// Pre-compute shape keys for faster access
|
|
409
|
-
this.
|
|
410
|
-
this.
|
|
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.
|
|
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.
|
|
431
|
-
const key = this.
|
|
432
|
-
const validator = this.
|
|
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
|
|
490
|
-
if (this.
|
|
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
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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.
|
|
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.
|
|
542
|
-
const key = this.
|
|
543
|
-
const validator = this.
|
|
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
|
|
557
|
-
if (this.
|
|
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
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
684
|
-
partialShape[key] = new VldOptional(this.
|
|
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.
|
|
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.
|
|
697
|
-
const validator = this.
|
|
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.
|
|
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.
|
|
717
|
-
pickedShape[key] = this.
|
|
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.
|
|
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.
|
|
784
|
+
for (const key in this._config.shape) {
|
|
732
785
|
if (!keysToOmit.has(key)) {
|
|
733
|
-
omittedShape[key] = this.
|
|
786
|
+
omittedShape[key] = this._config.shape[key];
|
|
734
787
|
}
|
|
735
788
|
}
|
|
736
789
|
return new VldObject({
|
|
737
|
-
...this.
|
|
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.
|
|
747
|
-
shape: { ...this.
|
|
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.
|
|
756
|
-
shape: { ...this.
|
|
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.
|
|
765
|
-
const validator = this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
839
|
-
shape: { ...this.
|
|
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(
|
|
1028
|
+
constructor(_literal, errorMessage) {
|
|
976
1029
|
super();
|
|
977
|
-
this.
|
|
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.
|
|
1049
|
+
if (value !== this._literal) {
|
|
991
1050
|
throw new Error(this.errorMessage ||
|
|
992
|
-
getMessages().literalExpected(JSON.stringify(this.
|
|
1051
|
+
getMessages().literalExpected(JSON.stringify(this._literal), JSON.stringify(value)));
|
|
993
1052
|
}
|
|
994
|
-
return this.
|
|
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.
|
|
1001
|
-
return { success: true, data: this.
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
1696
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -1930,5 +2017,5 @@ class VldJson extends VldBase {
|
|
|
1930
2017
|
}
|
|
1931
2018
|
}
|
|
1932
2019
|
|
|
1933
|
-
export {
|
|
1934
|
-
//# sourceMappingURL=json-
|
|
2020
|
+
export { VldNever as V, VldAny as a, VldArray as b, VldDiscriminatedUnion as c, VldEnum as d, VldIntersection as e, VldJson as f, VldLazy as g, VldLiteral as h, VldObject as i, VldRecord as j, VldMap as k, VldNan as l, VldNull as m, VldSet as n, VldStringBool as o, VldSymbol as p, VldTuple as q, VldUndefined as r, VldUnion as s, VldVoid as t, VldXor as u };
|
|
2021
|
+
//# sourceMappingURL=json-Cp4WO0M9.js.map
|