@oxog/vld 1.5.0 → 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.
- package/CHANGELOG.md +168 -0
- package/LICENSE +20 -20
- package/README.md +558 -517
- package/dist/chunks/bigint-DgsCr2dC.js +1709 -0
- package/dist/chunks/bigint-DgsCr2dC.js.map +1 -0
- package/dist/{coercion/string.js → chunks/date-ODue_rtq.js} +271 -5
- package/dist/chunks/date-ODue_rtq.js.map +1 -0
- package/dist/chunks/index-BZqWZvVe.js +426 -0
- package/dist/chunks/index-BZqWZvVe.js.map +1 -0
- package/dist/chunks/index-CETyGkrv.js +894 -0
- package/dist/chunks/index-CETyGkrv.js.map +1 -0
- package/dist/chunks/json-o20GFhTh.js +2021 -0
- package/dist/chunks/json-o20GFhTh.js.map +1 -0
- package/dist/{validators/unknown.js → chunks/unknown-SLIH1VCf.js} +6 -3
- package/dist/chunks/unknown-SLIH1VCf.js.map +1 -0
- package/dist/cjs/errors.cjs +387 -0
- package/dist/cjs/errors.cjs.map +1 -0
- package/dist/cjs/index.cjs +9983 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/locales/index.cjs +2877 -0
- package/dist/cjs/locales/index.cjs.map +1 -0
- package/dist/cjs/locales/lazy.cjs +3169 -0
- package/dist/cjs/locales/lazy.cjs.map +1 -0
- package/dist/cjs/mini.cjs +7329 -0
- package/dist/cjs/mini.cjs.map +1 -0
- package/dist/codecs/index.js +4 -275
- package/dist/codecs/index.js.map +1 -1
- package/dist/coercion/index.d.ts +11 -0
- package/dist/coercion/index.d.ts.map +1 -0
- package/dist/coercion/{bigint.js → index.js} +7 -4
- package/dist/coercion/index.js.map +1 -0
- package/dist/compat/emitter.js +6 -4
- package/dist/compat/emitter.js.map +1 -1
- package/dist/compat/result.js +21 -19
- package/dist/compat/result.js.map +1 -1
- package/dist/errors.js +13 -10
- package/dist/errors.js.map +1 -1
- package/dist/index.js +225 -126
- package/dist/index.js.map +1 -1
- package/dist/kernel.js +10 -7
- package/dist/kernel.js.map +1 -1
- package/dist/locales/af.js +4 -2
- package/dist/locales/af.js.map +1 -1
- package/dist/locales/ar.js +4 -2
- package/dist/locales/ar.js.map +1 -1
- package/dist/locales/bn.js +4 -2
- package/dist/locales/bn.js.map +1 -1
- package/dist/locales/da.js +4 -2
- package/dist/locales/da.js.map +1 -1
- package/dist/locales/de.js +4 -2
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.js +4 -2
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es-MX.js +4 -2
- package/dist/locales/es-MX.js.map +1 -1
- package/dist/locales/es.js +4 -2
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fi.js +4 -2
- package/dist/locales/fi.js.map +1 -1
- package/dist/locales/fr.js +4 -2
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/hi.js +4 -2
- package/dist/locales/hi.js.map +1 -1
- package/dist/locales/id.js +4 -2
- package/dist/locales/id.js.map +1 -1
- package/dist/locales/index.js +3 -91
- package/dist/locales/index.js.map +1 -1
- package/dist/locales/it.js +4 -2
- package/dist/locales/it.js.map +1 -1
- package/dist/locales/ja.js +4 -2
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +4 -2
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/lazy.d.ts +111 -0
- package/dist/locales/lazy.d.ts.map +1 -0
- package/dist/locales/lazy.js +220 -0
- package/dist/locales/lazy.js.map +1 -0
- package/dist/locales/nl.js +4 -2
- package/dist/locales/nl.js.map +1 -1
- package/dist/locales/no.js +4 -2
- package/dist/locales/no.js.map +1 -1
- package/dist/locales/pl.js +4 -2
- package/dist/locales/pl.js.map +1 -1
- package/dist/locales/pt-BR.js +4 -2
- package/dist/locales/pt-BR.js.map +1 -1
- package/dist/locales/pt.js +4 -2
- package/dist/locales/pt.js.map +1 -1
- package/dist/locales/ru.js +4 -2
- package/dist/locales/ru.js.map +1 -1
- package/dist/locales/sv.js +4 -2
- package/dist/locales/sv.js.map +1 -1
- package/dist/locales/sw.js +4 -2
- package/dist/locales/sw.js.map +1 -1
- package/dist/locales/th.js +4 -2
- package/dist/locales/th.js.map +1 -1
- package/dist/locales/tr.js +4 -2
- package/dist/locales/tr.js.map +1 -1
- package/dist/locales/vi.js +4 -2
- package/dist/locales/vi.js.map +1 -1
- package/dist/locales/zh.js +4 -2
- package/dist/locales/zh.js.map +1 -1
- package/dist/mini.d.ts +182 -0
- package/dist/mini.d.ts.map +1 -0
- package/dist/mini.js +132 -0
- package/dist/mini.js.map +1 -0
- package/dist/pigment.js +8 -7
- package/dist/pigment.js.map +1 -1
- package/dist/validators/array.d.ts +5 -0
- package/dist/validators/array.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.js +5 -45
- 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/object.d.ts +30 -3
- package/dist/validators/object.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 +69 -11
- package/dist/cli/benchmark.d.ts +0 -15
- package/dist/cli/benchmark.d.ts.map +0 -1
- package/dist/cli/benchmark.js +0 -248
- package/dist/cli/benchmark.js.map +0 -1
- package/dist/cli/bin.js +0 -35
- package/dist/cli/bin.js.map +0 -1
- package/dist/cli/commands/benchmark.js +0 -204
- package/dist/cli/commands/benchmark.js.map +0 -1
- package/dist/cli/commands/validate.js +0 -157
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/generate.d.ts +0 -14
- package/dist/cli/generate.d.ts.map +0 -1
- package/dist/cli/generate.js +0 -233
- package/dist/cli/generate.js.map +0 -1
- package/dist/cli/index.js +0 -182
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/validate.d.ts +0 -15
- package/dist/cli/validate.d.ts.map +0 -1
- package/dist/cli/validate.js +0 -162
- package/dist/cli/validate.js.map +0 -1
- package/dist/coercion/bigint.js.map +0 -1
- package/dist/coercion/boolean.js +0 -59
- package/dist/coercion/boolean.js.map +0 -1
- package/dist/coercion/date.js +0 -52
- package/dist/coercion/date.js.map +0 -1
- package/dist/coercion/number.js +0 -160
- package/dist/coercion/number.js.map +0 -1
- package/dist/coercion/string.js.map +0 -1
- package/dist/compat/index.js +0 -14
- package/dist/compat/index.js.map +0 -1
- package/dist/events.js +0 -8
- package/dist/events.js.map +0 -1
- package/dist/guards.d.ts +0 -143
- package/dist/guards.d.ts.map +0 -1
- package/dist/guards.js +0 -238
- package/dist/guards.js.map +0 -1
- package/dist/index-new.d.ts.map +0 -1
- package/dist/locales/backup-en.js +0 -105
- package/dist/locales/backup-en.js.map +0 -1
- package/dist/locales/types.js +0 -2
- package/dist/locales/types.js.map +0 -1
- package/dist/locales.d.ts +0 -54
- package/dist/locales.d.ts.map +0 -1
- package/dist/locales.js +0 -732
- package/dist/locales.js.map +0 -1
- package/dist/logger.js +0 -184
- package/dist/logger.js.map +0 -1
- package/dist/plugins/codecs.d.ts +0 -17
- package/dist/plugins/codecs.d.ts.map +0 -1
- package/dist/plugins/codecs.js +0 -29
- package/dist/plugins/codecs.js.map +0 -1
- package/dist/plugins/coercion.d.ts +0 -13
- package/dist/plugins/coercion.d.ts.map +0 -1
- package/dist/plugins/coercion.js +0 -34
- package/dist/plugins/coercion.js.map +0 -1
- package/dist/plugins/core-validators.d.ts +0 -13
- package/dist/plugins/core-validators.d.ts.map +0 -1
- package/dist/plugins/core-validators.js +0 -96
- package/dist/plugins/core-validators.js.map +0 -1
- package/dist/plugins/index.js +0 -8
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/kernel.d.ts +0 -29
- package/dist/plugins/kernel.d.ts.map +0 -1
- package/dist/plugins/kernel.js +0 -486
- package/dist/plugins/kernel.js.map +0 -1
- package/dist/plugins/types.js +0 -8
- package/dist/plugins/types.js.map +0 -1
- package/dist/style.d.ts +0 -123
- package/dist/style.d.ts.map +0 -1
- package/dist/style.js +0 -369
- package/dist/style.js.map +0 -1
- package/dist/utils/codec-utils.js +0 -229
- package/dist/utils/codec-utils.js.map +0 -1
- package/dist/utils/deep-merge.js +0 -76
- package/dist/utils/deep-merge.js.map +0 -1
- package/dist/utils/ip-validation.js +0 -98
- package/dist/utils/ip-validation.js.map +0 -1
- package/dist/utils/security.js +0 -61
- package/dist/utils/security.js.map +0 -1
- package/dist/validators/any.js +0 -25
- package/dist/validators/any.js.map +0 -1
- package/dist/validators/array.js +0 -190
- package/dist/validators/array.js.map +0 -1
- package/dist/validators/base.js +0 -499
- package/dist/validators/base.js.map +0 -1
- package/dist/validators/base64.js +0 -65
- package/dist/validators/base64.js.map +0 -1
- package/dist/validators/bigint.js +0 -142
- package/dist/validators/bigint.js.map +0 -1
- package/dist/validators/boolean.js +0 -114
- package/dist/validators/boolean.js.map +0 -1
- package/dist/validators/codec.js +0 -182
- package/dist/validators/codec.js.map +0 -1
- package/dist/validators/custom.js +0 -50
- package/dist/validators/custom.js.map +0 -1
- package/dist/validators/date.js +0 -227
- package/dist/validators/date.js.map +0 -1
- package/dist/validators/discriminated-union.js +0 -98
- package/dist/validators/discriminated-union.js.map +0 -1
- package/dist/validators/enum.js +0 -82
- package/dist/validators/enum.js.map +0 -1
- package/dist/validators/file.js +0 -114
- package/dist/validators/file.js.map +0 -1
- package/dist/validators/function.js +0 -45
- package/dist/validators/function.js.map +0 -1
- package/dist/validators/hex.js +0 -62
- package/dist/validators/hex.js.map +0 -1
- package/dist/validators/intersection.js +0 -64
- package/dist/validators/intersection.js.map +0 -1
- package/dist/validators/json.js +0 -64
- package/dist/validators/json.js.map +0 -1
- package/dist/validators/lazy.js +0 -42
- package/dist/validators/lazy.js.map +0 -1
- package/dist/validators/literal.js +0 -45
- package/dist/validators/literal.js.map +0 -1
- package/dist/validators/map.js +0 -54
- package/dist/validators/map.js.map +0 -1
- package/dist/validators/nan.js +0 -32
- package/dist/validators/nan.js.map +0 -1
- package/dist/validators/never.js +0 -29
- package/dist/validators/never.js.map +0 -1
- package/dist/validators/null.js +0 -31
- package/dist/validators/null.js.map +0 -1
- package/dist/validators/number.js +0 -225
- package/dist/validators/number.js.map +0 -1
- package/dist/validators/object-optimized.d.ts +0 -23
- package/dist/validators/object-optimized.d.ts.map +0 -1
- package/dist/validators/object-optimized.js +0 -179
- package/dist/validators/object-optimized.js.map +0 -1
- package/dist/validators/object-ultra.d.ts +0 -34
- package/dist/validators/object-ultra.d.ts.map +0 -1
- package/dist/validators/object-ultra.js +0 -175
- package/dist/validators/object-ultra.js.map +0 -1
- package/dist/validators/object.js +0 -458
- package/dist/validators/object.js.map +0 -1
- package/dist/validators/record.js +0 -128
- package/dist/validators/record.js.map +0 -1
- package/dist/validators/set.js +0 -51
- package/dist/validators/set.js.map +0 -1
- package/dist/validators/string-bool.js +0 -127
- package/dist/validators/string-bool.js.map +0 -1
- package/dist/validators/string-formats.js +0 -120
- package/dist/validators/string-formats.js.map +0 -1
- package/dist/validators/string-ultra.d.ts +0 -49
- package/dist/validators/string-ultra.d.ts.map +0 -1
- package/dist/validators/string-ultra.js +0 -217
- package/dist/validators/string-ultra.js.map +0 -1
- package/dist/validators/string.js +0 -253
- package/dist/validators/string.js.map +0 -1
- package/dist/validators/symbol.js +0 -42
- package/dist/validators/symbol.js.map +0 -1
- package/dist/validators/template-literal.js +0 -102
- package/dist/validators/template-literal.js.map +0 -1
- package/dist/validators/tuple.js +0 -55
- package/dist/validators/tuple.js.map +0 -1
- package/dist/validators/uint8array.js +0 -98
- package/dist/validators/uint8array.js.map +0 -1
- package/dist/validators/undefined.js +0 -31
- package/dist/validators/undefined.js.map +0 -1
- package/dist/validators/union-optimized.d.ts +0 -15
- package/dist/validators/union-optimized.d.ts.map +0 -1
- package/dist/validators/union-optimized.js +0 -92
- package/dist/validators/union-optimized.js.map +0 -1
- package/dist/validators/union.js +0 -126
- package/dist/validators/union.js.map +0 -1
- package/dist/validators/unknown.js.map +0 -1
- package/dist/validators/void.js +0 -35
- package/dist/validators/void.js.map +0 -1
- package/dist/validators/xor.js +0 -64
- package/dist/validators/xor.js.map +0 -1
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { VldBase, VldOptional } from './base.js';
|
|
2
|
-
import { getMessages } from '../locales.js';
|
|
3
|
-
/**
|
|
4
|
-
* Ultra-optimized object validator for maximum performance
|
|
5
|
-
* Features aggressive optimizations for speed over flexibility
|
|
6
|
-
*/
|
|
7
|
-
export class VldObjectUltra extends VldBase {
|
|
8
|
-
constructor(config) {
|
|
9
|
-
super();
|
|
10
|
-
this.config = config;
|
|
11
|
-
this.shapeKeys = Object.keys(config.shape);
|
|
12
|
-
this.validators = this.shapeKeys.map(key => config.shape[key]);
|
|
13
|
-
this.keysLength = this.shapeKeys.length;
|
|
14
|
-
// Pre-compile optimized validation function
|
|
15
|
-
this.fastValidate = this.createFastValidator();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Create ultra-fast validator using direct property access
|
|
19
|
-
*/
|
|
20
|
-
createFastValidator() {
|
|
21
|
-
const keys = this.shapeKeys;
|
|
22
|
-
const validators = this.validators;
|
|
23
|
-
const length = this.keysLength;
|
|
24
|
-
// Return optimized function with direct property access
|
|
25
|
-
return (obj) => {
|
|
26
|
-
const result = {};
|
|
27
|
-
// Unrolled loop for small objects (most common case)
|
|
28
|
-
if (length <= 4) {
|
|
29
|
-
// Manual unrolling for 1-4 properties
|
|
30
|
-
for (let i = 0; i < length; i++) {
|
|
31
|
-
const key = keys[i];
|
|
32
|
-
const validator = validators[i];
|
|
33
|
-
const value = obj[key];
|
|
34
|
-
// Inline fast-path validation
|
|
35
|
-
if (validator.constructor.name === 'VldString') {
|
|
36
|
-
if (typeof value !== 'string') {
|
|
37
|
-
throw new Error(`Field ${key}: Expected string`);
|
|
38
|
-
}
|
|
39
|
-
result[key] = value;
|
|
40
|
-
}
|
|
41
|
-
else if (validator.constructor.name === 'VldNumber') {
|
|
42
|
-
if (typeof value !== 'number' || isNaN(value)) {
|
|
43
|
-
throw new Error(`Field ${key}: Expected number`);
|
|
44
|
-
}
|
|
45
|
-
result[key] = value;
|
|
46
|
-
}
|
|
47
|
-
else if (validator.constructor.name === 'VldBoolean') {
|
|
48
|
-
if (typeof value !== 'boolean') {
|
|
49
|
-
throw new Error(`Field ${key}: Expected boolean`);
|
|
50
|
-
}
|
|
51
|
-
result[key] = value;
|
|
52
|
-
}
|
|
53
|
-
else if (validator.constructor.name === 'VldDate') {
|
|
54
|
-
if (!(value instanceof Date)) {
|
|
55
|
-
throw new Error(`Field ${key}: Expected date`);
|
|
56
|
-
}
|
|
57
|
-
result[key] = value;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Fallback to safeParse for complex validators
|
|
61
|
-
const parseResult = validator.safeParse(value);
|
|
62
|
-
if (!parseResult.success) {
|
|
63
|
-
throw parseResult.error;
|
|
64
|
-
}
|
|
65
|
-
result[key] = parseResult.data;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// Standard loop for larger objects
|
|
71
|
-
for (let i = 0; i < length; i++) {
|
|
72
|
-
const key = keys[i];
|
|
73
|
-
const validator = validators[i];
|
|
74
|
-
const value = obj[key];
|
|
75
|
-
const parseResult = validator.safeParse(value);
|
|
76
|
-
if (!parseResult.success) {
|
|
77
|
-
throw new Error(getMessages().objectField(key, parseResult.error.message));
|
|
78
|
-
}
|
|
79
|
-
result[key] = parseResult.data;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return result;
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
static create(shape) {
|
|
86
|
-
return new VldObjectUltra({ shape });
|
|
87
|
-
}
|
|
88
|
-
parse(value) {
|
|
89
|
-
// Ultra-fast type check
|
|
90
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
91
|
-
throw new Error(this.config.errorMessage || getMessages().invalidObject);
|
|
92
|
-
}
|
|
93
|
-
return this.fastValidate(value);
|
|
94
|
-
}
|
|
95
|
-
safeParse(value) {
|
|
96
|
-
// Ultra-fast type check
|
|
97
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
98
|
-
return {
|
|
99
|
-
success: false,
|
|
100
|
-
error: new Error(this.config.errorMessage || getMessages().invalidObject)
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
const result = this.fastValidate(value);
|
|
105
|
-
return { success: true, data: result };
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
return { success: false, error: error };
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// Minimal set of chainable methods for performance
|
|
112
|
-
strict(message) {
|
|
113
|
-
return new VldObjectUltra({
|
|
114
|
-
...this.config,
|
|
115
|
-
strict: true,
|
|
116
|
-
passthrough: false,
|
|
117
|
-
errorMessage: message
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
passthrough() {
|
|
121
|
-
return new VldObjectUltra({
|
|
122
|
-
...this.config,
|
|
123
|
-
strict: false,
|
|
124
|
-
passthrough: true
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
partial() {
|
|
128
|
-
const partialShape = {};
|
|
129
|
-
for (const key in this.config.shape) {
|
|
130
|
-
partialShape[key] = new VldOptional(this.config.shape[key]);
|
|
131
|
-
}
|
|
132
|
-
return new VldObjectUltra({
|
|
133
|
-
...this.config,
|
|
134
|
-
shape: partialShape
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
pick(...keys) {
|
|
138
|
-
const pickedShape = {};
|
|
139
|
-
for (const key of keys) {
|
|
140
|
-
if (key in this.config.shape) {
|
|
141
|
-
pickedShape[key] = this.config.shape[key];
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return new VldObjectUltra({
|
|
145
|
-
...this.config,
|
|
146
|
-
shape: pickedShape
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
omit(...keys) {
|
|
150
|
-
const omittedShape = {};
|
|
151
|
-
const keysToOmit = new Set(keys);
|
|
152
|
-
for (const key in this.config.shape) {
|
|
153
|
-
if (!keysToOmit.has(key)) {
|
|
154
|
-
omittedShape[key] = this.config.shape[key];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return new VldObjectUltra({
|
|
158
|
-
...this.config,
|
|
159
|
-
shape: omittedShape
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
extend(extension) {
|
|
163
|
-
return new VldObjectUltra({
|
|
164
|
-
...this.config,
|
|
165
|
-
shape: { ...this.config.shape, ...extension }
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
merge(other) {
|
|
169
|
-
return new VldObjectUltra({
|
|
170
|
-
...this.config,
|
|
171
|
-
shape: { ...this.config.shape, ...other.config.shape }
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
//# sourceMappingURL=object-ultra.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"object-ultra.js","sourceRoot":"","sources":["../../src/validators/object-ultra.ts"],"names":[],"mappings":"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","sourcesContent":["import { VldBase, ParseResult, VldOptional } from './base';\nimport { getMessages } from '../locales';\n\n/**\n * Configuration for ultra-optimized object validator\n */\ninterface ObjectValidatorConfig<T extends Record<string, any>> {\n readonly shape: { readonly [K in keyof T]: VldBase<unknown, T[K]> };\n readonly strict?: boolean;\n readonly passthrough?: boolean;\n readonly errorMessage?: string;\n}\n\n/**\n * Ultra-optimized object validator for maximum performance\n * Features aggressive optimizations for speed over flexibility\n */\nexport class VldObjectUltra<T extends Record<string, any>> extends VldBase<unknown, T> {\n private readonly config: ObjectValidatorConfig<T>;\n private readonly shapeKeys: string[];\n private readonly validators: VldBase<unknown, any>[];\n private readonly keysLength: number;\n \n // Pre-computed validation function for hot path\n private readonly fastValidate: (obj: Record<string, unknown>) => T;\n \n private constructor(config: ObjectValidatorConfig<T>) {\n super();\n this.config = config;\n this.shapeKeys = Object.keys(config.shape);\n this.validators = this.shapeKeys.map(key => config.shape[key]);\n this.keysLength = this.shapeKeys.length;\n \n // Pre-compile optimized validation function\n this.fastValidate = this.createFastValidator();\n }\n \n /**\n * Create ultra-fast validator using direct property access\n */\n private createFastValidator(): (obj: Record<string, unknown>) => T {\n const keys = this.shapeKeys;\n const validators = this.validators;\n const length = this.keysLength;\n \n // Return optimized function with direct property access\n return (obj: Record<string, unknown>): T => {\n const result: any = {};\n \n // Unrolled loop for small objects (most common case)\n if (length <= 4) {\n // Manual unrolling for 1-4 properties\n for (let i = 0; i < length; i++) {\n const key = keys[i];\n const validator = validators[i];\n const value = obj[key];\n \n // Inline fast-path validation\n if (validator.constructor.name === 'VldString') {\n if (typeof value !== 'string') {\n throw new Error(`Field ${key}: Expected string`);\n }\n result[key] = value;\n } else if (validator.constructor.name === 'VldNumber') {\n if (typeof value !== 'number' || isNaN(value)) {\n throw new Error(`Field ${key}: Expected number`);\n }\n result[key] = value;\n } else if (validator.constructor.name === 'VldBoolean') {\n if (typeof value !== 'boolean') {\n throw new Error(`Field ${key}: Expected boolean`);\n }\n result[key] = value;\n } else if (validator.constructor.name === 'VldDate') {\n if (!(value instanceof Date)) {\n throw new Error(`Field ${key}: Expected date`);\n }\n result[key] = value;\n } else {\n // Fallback to safeParse for complex validators\n const parseResult = validator.safeParse(value);\n if (!parseResult.success) {\n throw parseResult.error;\n }\n result[key] = parseResult.data;\n }\n }\n } else {\n // Standard loop for larger objects\n for (let i = 0; i < length; i++) {\n const key = keys[i];\n const validator = validators[i];\n const value = obj[key];\n \n const parseResult = validator.safeParse(value);\n if (!parseResult.success) {\n throw new Error(getMessages().objectField(key, parseResult.error.message));\n }\n result[key] = parseResult.data;\n }\n }\n \n return result as T;\n };\n }\n \n static create<T extends Record<string, any>>(\n shape: { [K in keyof T]: VldBase<unknown, T[K]> }\n ): VldObjectUltra<T> {\n return new VldObjectUltra({ shape });\n }\n \n parse(value: unknown): T {\n // Ultra-fast type check\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(this.config.errorMessage || getMessages().invalidObject);\n }\n \n return this.fastValidate(value as Record<string, unknown>);\n }\n \n safeParse(value: unknown): ParseResult<T> {\n // Ultra-fast type check\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return {\n success: false,\n error: new Error(this.config.errorMessage || getMessages().invalidObject)\n };\n }\n \n try {\n const result = this.fastValidate(value as Record<string, unknown>);\n return { success: true, data: result };\n } catch (error) {\n return { success: false, error: error as Error };\n }\n }\n \n // Minimal set of chainable methods for performance\n strict(message?: string): VldObjectUltra<T> {\n return new VldObjectUltra({\n ...this.config,\n strict: true,\n passthrough: false,\n errorMessage: message\n });\n }\n \n passthrough(): VldObjectUltra<T> {\n return new VldObjectUltra({\n ...this.config,\n strict: false,\n passthrough: true\n });\n }\n \n partial(): VldObjectUltra<{ [K in keyof T]?: T[K] }> {\n const partialShape: any = {};\n for (const key in this.config.shape) {\n partialShape[key] = new VldOptional(this.config.shape[key]);\n }\n return new VldObjectUltra({ \n ...this.config, \n shape: partialShape \n }) as any;\n }\n \n pick<K extends keyof T>(...keys: K[]): VldObjectUltra<Pick<T, K>> {\n const pickedShape: any = {};\n for (const key of keys) {\n if (key in this.config.shape) {\n pickedShape[key] = this.config.shape[key];\n }\n }\n return new VldObjectUltra({ \n ...this.config, \n shape: pickedShape \n });\n }\n \n omit<K extends keyof T>(...keys: K[]): VldObjectUltra<Omit<T, K>> {\n const omittedShape: any = {};\n const keysToOmit = new Set(keys);\n for (const key in this.config.shape) {\n if (!keysToOmit.has(key as any)) {\n omittedShape[key] = this.config.shape[key];\n }\n }\n return new VldObjectUltra({ \n ...this.config, \n shape: omittedShape \n });\n }\n \n extend<U extends Record<string, any>>(\n extension: { [K in keyof U]: VldBase<unknown, U[K]> }\n ): VldObjectUltra<T & U> {\n return new VldObjectUltra({\n ...this.config,\n shape: { ...this.config.shape, ...extension } as any\n });\n }\n \n merge<U extends Record<string, any>>(\n other: VldObjectUltra<U>\n ): VldObjectUltra<T & U> {\n return new VldObjectUltra({\n ...this.config,\n shape: { ...this.config.shape, ...other.config.shape } as any\n });\n }\n}"]}
|
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
import { VldBase, VldOptional } from './base.js';
|
|
2
|
-
import { getMessages } from '../locales/index.js';
|
|
3
|
-
import { VldString } from './string.js';
|
|
4
|
-
import { VldNumber } from './number.js';
|
|
5
|
-
import { VldBoolean } from './boolean.js';
|
|
6
|
-
import { VldDate } from './date.js';
|
|
7
|
-
import { VldEnum } from './enum.js';
|
|
8
|
-
import { VldCoerceString } from '../coercion/string.js';
|
|
9
|
-
import { VldCoerceNumber } from '../coercion/number.js';
|
|
10
|
-
import { VldCoerceBoolean } from '../coercion/boolean.js';
|
|
11
|
-
import { VldCoerceDate } from '../coercion/date.js';
|
|
12
|
-
/**
|
|
13
|
-
* Optimized immutable object validator with chainable methods
|
|
14
|
-
* Features pre-computed keys and Set-based lookups for better performance
|
|
15
|
-
*/
|
|
16
|
-
export class VldObject extends VldBase {
|
|
17
|
-
/**
|
|
18
|
-
* Private constructor to enforce immutability
|
|
19
|
-
*/
|
|
20
|
-
constructor(config) {
|
|
21
|
-
super();
|
|
22
|
-
this.config = config;
|
|
23
|
-
// Pre-compute shape keys for faster access
|
|
24
|
-
this.shapeKeys = Object.keys(config.shape);
|
|
25
|
-
this.shapeKeysSet = new Set(this.shapeKeys);
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Create a new object validator
|
|
29
|
-
*/
|
|
30
|
-
static create(shape) {
|
|
31
|
-
return new VldObject({ shape });
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Parse and validate an object value
|
|
35
|
-
* Ultra-optimized with inline type checks and minimal overhead
|
|
36
|
-
*/
|
|
37
|
-
parse(value) {
|
|
38
|
-
// Fast type check
|
|
39
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
40
|
-
throw new Error(this.config.errorMessage || getMessages().invalidObject);
|
|
41
|
-
}
|
|
42
|
-
const obj = value;
|
|
43
|
-
const result = {};
|
|
44
|
-
// Ultra-optimized field validation with inline fast paths
|
|
45
|
-
for (let i = 0; i < this.shapeKeys.length; i++) {
|
|
46
|
-
const key = this.shapeKeys[i];
|
|
47
|
-
const validator = this.config.shape[key];
|
|
48
|
-
const fieldValue = obj[key];
|
|
49
|
-
// BUG-NEW-002 FIX: Use instanceof instead of constructor.name
|
|
50
|
-
// constructor.name breaks in minified builds where class names become 'a', 'b', etc.
|
|
51
|
-
// instanceof checks are reliable regardless of minification
|
|
52
|
-
//
|
|
53
|
-
// Note: Coercion validators extend their base validators, so we need to check for
|
|
54
|
-
// coercion types first (more specific) before checking base types
|
|
55
|
-
// Check for coercion validators first - they need full safeParse for type conversion
|
|
56
|
-
if (validator instanceof VldCoerceString ||
|
|
57
|
-
validator instanceof VldCoerceNumber ||
|
|
58
|
-
validator instanceof VldCoerceBoolean ||
|
|
59
|
-
validator instanceof VldCoerceDate) {
|
|
60
|
-
// Coercion validators need safeParse to handle type conversion
|
|
61
|
-
const parseResult = validator.safeParse(fieldValue);
|
|
62
|
-
if (!parseResult.success) {
|
|
63
|
-
throw new Error(getMessages().objectField(key, parseResult.error.message));
|
|
64
|
-
}
|
|
65
|
-
result[key] = parseResult.data;
|
|
66
|
-
}
|
|
67
|
-
else if (validator instanceof VldString) {
|
|
68
|
-
// For string with validations, use safeParse to handle email, regex etc.
|
|
69
|
-
const parseResult = validator.safeParse(fieldValue);
|
|
70
|
-
if (!parseResult.success) {
|
|
71
|
-
throw new Error(getMessages().objectField(key, parseResult.error.message));
|
|
72
|
-
}
|
|
73
|
-
result[key] = parseResult.data;
|
|
74
|
-
}
|
|
75
|
-
else if (validator instanceof VldNumber) {
|
|
76
|
-
if (typeof fieldValue !== 'number' || isNaN(fieldValue)) {
|
|
77
|
-
throw new Error(getMessages().objectField(key, getMessages().invalidNumber));
|
|
78
|
-
}
|
|
79
|
-
result[key] = fieldValue;
|
|
80
|
-
}
|
|
81
|
-
else if (validator instanceof VldBoolean) {
|
|
82
|
-
if (typeof fieldValue !== 'boolean') {
|
|
83
|
-
throw new Error(getMessages().objectField(key, getMessages().invalidBoolean));
|
|
84
|
-
}
|
|
85
|
-
result[key] = fieldValue;
|
|
86
|
-
}
|
|
87
|
-
else if (validator instanceof VldDate) {
|
|
88
|
-
// Use the actual validator for Date parsing (handles string conversion)
|
|
89
|
-
const parseResult = validator.safeParse(fieldValue);
|
|
90
|
-
if (!parseResult.success) {
|
|
91
|
-
throw new Error(getMessages().objectField(key, parseResult.error.message));
|
|
92
|
-
}
|
|
93
|
-
result[key] = parseResult.data;
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
// Fallback to safeParse for complex validators
|
|
97
|
-
const parseResult = validator.safeParse(fieldValue);
|
|
98
|
-
if (!parseResult.success) {
|
|
99
|
-
throw new Error(getMessages().objectField(key, parseResult.error.message));
|
|
100
|
-
}
|
|
101
|
-
result[key] = parseResult.data;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Handle strict mode - optimized with Set
|
|
105
|
-
if (this.config.strict) {
|
|
106
|
-
const objKeys = Object.keys(obj);
|
|
107
|
-
const extraKeys = [];
|
|
108
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
109
|
-
if (!this.shapeKeysSet.has(objKeys[i])) {
|
|
110
|
-
extraKeys.push(objKeys[i]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (extraKeys.length > 0) {
|
|
114
|
-
throw new Error(getMessages().unexpectedKeys(extraKeys));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
// Handle passthrough mode - optimized with comprehensive prototype pollution protection
|
|
118
|
-
if (this.config.passthrough) {
|
|
119
|
-
const objKeys = Object.keys(obj);
|
|
120
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
121
|
-
const key = objKeys[i];
|
|
122
|
-
// Skip dangerous keys to prevent prototype pollution
|
|
123
|
-
if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
|
|
124
|
-
result[key] = obj[key];
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// Handle catchall - validate extra keys with catchall validator
|
|
129
|
-
if (this.config.catchall) {
|
|
130
|
-
const objKeys = Object.keys(obj);
|
|
131
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
132
|
-
const key = objKeys[i];
|
|
133
|
-
// Skip keys already in shape and dangerous keys
|
|
134
|
-
if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
|
|
135
|
-
result[key] = this.config.catchall.parse(obj[key]);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Safely parse and validate an object value
|
|
143
|
-
* Optimized version using pre-computed keys
|
|
144
|
-
*/
|
|
145
|
-
safeParse(value) {
|
|
146
|
-
// Fast type check
|
|
147
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
148
|
-
return {
|
|
149
|
-
success: false,
|
|
150
|
-
error: new Error(this.config.errorMessage || getMessages().invalidObject)
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const obj = value;
|
|
154
|
-
const result = {};
|
|
155
|
-
// Validate all fields
|
|
156
|
-
for (let i = 0; i < this.shapeKeys.length; i++) {
|
|
157
|
-
const key = this.shapeKeys[i];
|
|
158
|
-
const validator = this.config.shape[key];
|
|
159
|
-
const fieldValue = obj[key];
|
|
160
|
-
const parseResult = validator.safeParse(fieldValue);
|
|
161
|
-
if (parseResult.success) {
|
|
162
|
-
result[key] = parseResult.data;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
return {
|
|
166
|
-
success: false,
|
|
167
|
-
error: new Error(getMessages().objectField(key, parseResult.error.message))
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
// Handle strict mode
|
|
172
|
-
if (this.config.strict) {
|
|
173
|
-
const objKeys = Object.keys(obj);
|
|
174
|
-
const extraKeys = [];
|
|
175
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
176
|
-
if (!this.shapeKeysSet.has(objKeys[i])) {
|
|
177
|
-
extraKeys.push(objKeys[i]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
if (extraKeys.length > 0) {
|
|
181
|
-
return {
|
|
182
|
-
success: false,
|
|
183
|
-
error: new Error(getMessages().unexpectedKeys(extraKeys))
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// Handle passthrough mode with comprehensive prototype pollution protection
|
|
188
|
-
if (this.config.passthrough) {
|
|
189
|
-
const objKeys = Object.keys(obj);
|
|
190
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
191
|
-
const key = objKeys[i];
|
|
192
|
-
// Skip dangerous keys to prevent prototype pollution
|
|
193
|
-
if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
|
|
194
|
-
result[key] = obj[key];
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Handle catchall - validate extra keys with catchall validator
|
|
199
|
-
if (this.config.catchall) {
|
|
200
|
-
const objKeys = Object.keys(obj);
|
|
201
|
-
for (let i = 0; i < objKeys.length; i++) {
|
|
202
|
-
const key = objKeys[i];
|
|
203
|
-
// Skip keys already in shape and dangerous keys
|
|
204
|
-
if (!this.shapeKeysSet.has(key) && !this.isDangerousKey(key)) {
|
|
205
|
-
const catchallResult = this.config.catchall.safeParse(obj[key]);
|
|
206
|
-
if (!catchallResult.success) {
|
|
207
|
-
return {
|
|
208
|
-
success: false,
|
|
209
|
-
error: new Error(getMessages().objectField(key, catchallResult.error.message))
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
result[key] = catchallResult.data;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return { success: true, data: result };
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Comprehensive prototype pollution protection
|
|
220
|
-
* Checks for dangerous keys that could modify Object.prototype
|
|
221
|
-
*/
|
|
222
|
-
isDangerousKey(key) {
|
|
223
|
-
// Direct dangerous keys
|
|
224
|
-
const directDangerousKeys = ['__proto__', 'constructor', 'prototype'];
|
|
225
|
-
if (directDangerousKeys.includes(key)) {
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
// Nested prototype manipulation vectors
|
|
229
|
-
// These patterns could allow prototype pollution through nested access
|
|
230
|
-
const nestedPatterns = [
|
|
231
|
-
'constructor.prototype',
|
|
232
|
-
'__proto__.toString',
|
|
233
|
-
'prototype.constructor',
|
|
234
|
-
'__defineGetter__',
|
|
235
|
-
'__defineSetter__',
|
|
236
|
-
'__lookupGetter__',
|
|
237
|
-
'__lookupSetter__'
|
|
238
|
-
];
|
|
239
|
-
// Check for nested patterns
|
|
240
|
-
for (const pattern of nestedPatterns) {
|
|
241
|
-
if (key.includes(pattern)) {
|
|
242
|
-
return true;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Check for property access chains that could lead to prototype pollution
|
|
246
|
-
// This covers patterns like "x.constructor.prototype.polluted"
|
|
247
|
-
const dangerousChains = [
|
|
248
|
-
'constructor.',
|
|
249
|
-
'__proto__.',
|
|
250
|
-
'prototype.'
|
|
251
|
-
];
|
|
252
|
-
for (const chain of dangerousChains) {
|
|
253
|
-
if (key.includes(chain)) {
|
|
254
|
-
return true;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// Additional protection: reject keys that could be used for property shadowing
|
|
258
|
-
const shadowingPatterns = [
|
|
259
|
-
'hasOwnProperty',
|
|
260
|
-
'toString',
|
|
261
|
-
'valueOf',
|
|
262
|
-
'isPrototypeOf',
|
|
263
|
-
'propertyIsEnumerable'
|
|
264
|
-
];
|
|
265
|
-
for (const pattern of shadowingPatterns) {
|
|
266
|
-
if (key === pattern || key.includes(`.${pattern}`)) {
|
|
267
|
-
return true;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Create a new validator in strict mode (no extra keys allowed)
|
|
274
|
-
*/
|
|
275
|
-
strict(message) {
|
|
276
|
-
return new VldObject({
|
|
277
|
-
...this.config,
|
|
278
|
-
strict: true,
|
|
279
|
-
passthrough: false,
|
|
280
|
-
errorMessage: message
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Create a new validator in passthrough mode (extra keys are preserved)
|
|
285
|
-
*/
|
|
286
|
-
passthrough() {
|
|
287
|
-
return new VldObject({
|
|
288
|
-
...this.config,
|
|
289
|
-
strict: false,
|
|
290
|
-
passthrough: true
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Create a new validator with all fields optional
|
|
295
|
-
*/
|
|
296
|
-
partial() {
|
|
297
|
-
const partialShape = {};
|
|
298
|
-
for (const key in this.config.shape) {
|
|
299
|
-
partialShape[key] = new VldOptional(this.config.shape[key]);
|
|
300
|
-
}
|
|
301
|
-
return new VldObject({
|
|
302
|
-
...this.config,
|
|
303
|
-
shape: partialShape
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Create a new validator with deep partial (nested objects also partial)
|
|
308
|
-
*/
|
|
309
|
-
deepPartial() {
|
|
310
|
-
const deepPartialShape = {};
|
|
311
|
-
for (const key in this.config.shape) {
|
|
312
|
-
const validator = this.config.shape[key];
|
|
313
|
-
if (validator instanceof VldObject) {
|
|
314
|
-
deepPartialShape[key] = new VldOptional(validator.deepPartial());
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
deepPartialShape[key] = new VldOptional(validator);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return new VldObject({
|
|
321
|
-
...this.config,
|
|
322
|
-
shape: deepPartialShape
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Create a new validator with only specified keys
|
|
327
|
-
*/
|
|
328
|
-
pick(...keys) {
|
|
329
|
-
const pickedShape = {};
|
|
330
|
-
for (const key of keys) {
|
|
331
|
-
if (key in this.config.shape) {
|
|
332
|
-
pickedShape[key] = this.config.shape[key];
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return new VldObject({
|
|
336
|
-
...this.config,
|
|
337
|
-
shape: pickedShape
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Create a new validator without specified keys
|
|
342
|
-
*/
|
|
343
|
-
omit(...keys) {
|
|
344
|
-
const omittedShape = {};
|
|
345
|
-
const keysToOmit = new Set(keys);
|
|
346
|
-
for (const key in this.config.shape) {
|
|
347
|
-
if (!keysToOmit.has(key)) {
|
|
348
|
-
omittedShape[key] = this.config.shape[key];
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
return new VldObject({
|
|
352
|
-
...this.config,
|
|
353
|
-
shape: omittedShape
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Create a new validator with additional fields
|
|
358
|
-
*/
|
|
359
|
-
extend(extension) {
|
|
360
|
-
return new VldObject({
|
|
361
|
-
...this.config,
|
|
362
|
-
shape: { ...this.config.shape, ...extension }
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Create a new validator by merging with another object validator
|
|
367
|
-
*/
|
|
368
|
-
merge(other) {
|
|
369
|
-
return new VldObject({
|
|
370
|
-
...this.config,
|
|
371
|
-
shape: { ...this.config.shape, ...other.config.shape }
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Create a new validator with all fields required (removes optional)
|
|
376
|
-
*/
|
|
377
|
-
required() {
|
|
378
|
-
const requiredShape = {};
|
|
379
|
-
for (const key in this.config.shape) {
|
|
380
|
-
const validator = this.config.shape[key];
|
|
381
|
-
// If it's optional, unwrap it
|
|
382
|
-
if (validator instanceof VldOptional) {
|
|
383
|
-
// BUG-001 FIX: Add defensive check for baseValidator property
|
|
384
|
-
const unwrapped = validator.baseValidator;
|
|
385
|
-
if (!unwrapped || typeof unwrapped.parse !== 'function') {
|
|
386
|
-
throw new Error(`Invalid VldOptional structure for field "${key}": missing or invalid baseValidator`);
|
|
387
|
-
}
|
|
388
|
-
requiredShape[key] = unwrapped;
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
requiredShape[key] = validator;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
return new VldObject({
|
|
395
|
-
...this.config,
|
|
396
|
-
shape: requiredShape
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Create a new validator with a catchall validator for extra keys
|
|
401
|
-
* Zod 4 API parity - validates unknown keys with provided schema
|
|
402
|
-
*/
|
|
403
|
-
catchall(schema) {
|
|
404
|
-
return new VldObject({
|
|
405
|
-
...this.config,
|
|
406
|
-
catchall: schema,
|
|
407
|
-
passthrough: false // catchall overrides passthrough
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Access the inner shape schemas
|
|
412
|
-
* Zod 4 API parity - returns the shape object
|
|
413
|
-
*/
|
|
414
|
-
get shape() {
|
|
415
|
-
return this.config.shape;
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Create an enum validator from object keys
|
|
419
|
-
* Zod 4 API parity - creates literal union of keys
|
|
420
|
-
*/
|
|
421
|
-
keyof() {
|
|
422
|
-
const keys = Object.keys(this.config.shape);
|
|
423
|
-
if (keys.length === 0) {
|
|
424
|
-
throw new Error('Cannot create keyof enum from empty object');
|
|
425
|
-
}
|
|
426
|
-
return VldEnum.create(keys);
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Type-safe extend that throws an error if any key already exists
|
|
430
|
-
* Zod 4 API parity - prevents accidental field override
|
|
431
|
-
* @param extension The extension shape to add
|
|
432
|
-
* @returns A new validator with extended shape
|
|
433
|
-
* @throws {Error} If any extension key already exists in the shape
|
|
434
|
-
* @example
|
|
435
|
-
* const base = v.object({ name: v.string() });
|
|
436
|
-
* const extended = base.safeExtend({ age: v.number() }); // OK
|
|
437
|
-
* const invalid = base.safeExtend({ name: v.number() }); // Throws error
|
|
438
|
-
*/
|
|
439
|
-
safeExtend(extension) {
|
|
440
|
-
// Check for overlapping keys
|
|
441
|
-
const existingKeys = new Set(Object.keys(this.config.shape));
|
|
442
|
-
const extensionKeys = Object.keys(extension);
|
|
443
|
-
const overlappingKeys = [];
|
|
444
|
-
for (const key of extensionKeys) {
|
|
445
|
-
if (existingKeys.has(key)) {
|
|
446
|
-
overlappingKeys.push(key);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
if (overlappingKeys.length > 0) {
|
|
450
|
-
throw new Error(`safeExtend: ${getMessages().safeExtendOverlap(overlappingKeys)}`);
|
|
451
|
-
}
|
|
452
|
-
return new VldObject({
|
|
453
|
-
...this.config,
|
|
454
|
-
shape: { ...this.config.shape, ...extension }
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
//# sourceMappingURL=object.js.map
|