@oxog/vld 2.1.0 → 2.2.7
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 +113 -0
- package/README.md +413 -1235
- package/dist/chunks/errors-core-CerMg2rq.js +1 -0
- package/dist/chunks/index-CkbfQQ4n.js +1 -0
- package/dist/chunks/index-yjpbvFgw.js +1 -0
- package/dist/chunks/ip-validation-g5LWgy9t.js +1 -0
- package/dist/chunks/security-Dy24T8N7.js +1 -0
- package/dist/cjs/chunks/errors-core-DrydF46s.cjs +1 -0
- package/dist/cjs/chunks/index-BEV9nG0N.cjs +1 -0
- package/dist/cjs/chunks/index-ZjHAxYdA.cjs +1 -0
- package/dist/cjs/chunks/ip-validation-BZqPamPC.cjs +1 -0
- package/dist/cjs/chunks/security-aXZVI7qW.cjs +1 -0
- package/dist/cjs/cli/bin.cjs +1 -505
- package/dist/cjs/cli/index.cjs +1 -209
- package/dist/cjs/codecs/index.cjs +1 -45
- package/dist/cjs/coercion/index.cjs +1 -588
- package/dist/cjs/compat/emitter.cjs +1 -184
- package/dist/cjs/compat/result.cjs +1 -189
- package/dist/cjs/errors.cjs +1 -180
- package/dist/cjs/index.cjs +1 -1894
- package/dist/cjs/kernel.cjs +1 -415
- package/dist/cjs/locales/af.cjs +1 -108
- package/dist/cjs/locales/ar.cjs +1 -108
- package/dist/cjs/locales/bn.cjs +1 -108
- package/dist/cjs/locales/da.cjs +1 -108
- package/dist/cjs/locales/de.cjs +1 -108
- package/dist/cjs/locales/en.cjs +1 -108
- package/dist/cjs/locales/es-MX.cjs +1 -107
- package/dist/cjs/locales/es.cjs +1 -96
- package/dist/cjs/locales/fi.cjs +1 -108
- package/dist/cjs/locales/fr.cjs +1 -96
- package/dist/cjs/locales/hi.cjs +1 -108
- package/dist/cjs/locales/id.cjs +1 -108
- package/dist/cjs/locales/index.cjs +1 -43
- package/dist/cjs/locales/it.cjs +1 -108
- package/dist/cjs/locales/ja.cjs +1 -108
- package/dist/cjs/locales/ko.cjs +1 -108
- package/dist/cjs/locales/lazy.cjs +1 -188
- package/dist/cjs/locales/nl.cjs +1 -108
- package/dist/cjs/locales/no.cjs +1 -108
- package/dist/cjs/locales/pl.cjs +1 -108
- package/dist/cjs/locales/pt-BR.cjs +1 -108
- package/dist/cjs/locales/pt.cjs +1 -108
- package/dist/cjs/locales/ru.cjs +1 -108
- package/dist/cjs/locales/runtime.cjs +1 -51
- package/dist/cjs/locales/sv.cjs +1 -108
- package/dist/cjs/locales/sw.cjs +1 -108
- package/dist/cjs/locales/th.cjs +1 -108
- package/dist/cjs/locales/tr.cjs +1 -108
- package/dist/cjs/locales/vi.cjs +1 -108
- package/dist/cjs/locales/zh.cjs +1 -108
- package/dist/cjs/mini.cjs +1 -242
- package/dist/cjs/pigment.cjs +1 -207
- package/dist/cjs/plugins/index.cjs +1 -12
- package/dist/cjs/registry.cjs +1 -37
- package/dist/cjs/v3/index.cjs +1 -425
- package/dist/cjs/v4/core/index.cjs +1 -894
- package/dist/cjs/v4/index.cjs +1 -425
- package/dist/cjs/v4/locales/index.cjs +1 -130
- package/dist/cjs/v4/mini/index.cjs +1 -509
- package/dist/cjs/v4-mini/index.cjs +1 -532
- package/dist/cjs/validators/any.cjs +1 -40
- package/dist/cjs/validators/array.cjs +1 -283
- package/dist/cjs/validators/base.cjs +1 -887
- package/dist/cjs/validators/base64.cjs +1 -73
- package/dist/cjs/validators/bigint.cjs +1 -232
- package/dist/cjs/validators/boolean.cjs +1 -146
- package/dist/cjs/validators/codec.cjs +1 -205
- package/dist/cjs/validators/custom.cjs +1 -71
- package/dist/cjs/validators/date.cjs +1 -278
- package/dist/cjs/validators/discriminated-union.cjs +1 -130
- package/dist/cjs/validators/enum.cjs +1 -154
- package/dist/cjs/validators/file.cjs +1 -130
- package/dist/cjs/validators/function.cjs +1 -63
- package/dist/cjs/validators/hex.cjs +1 -70
- package/dist/cjs/validators/index.cjs +1 -123
- package/dist/cjs/validators/intersection.cjs +1 -120
- package/dist/cjs/validators/json.cjs +1 -70
- package/dist/cjs/validators/lazy.cjs +1 -53
- package/dist/cjs/validators/literal.cjs +1 -64
- package/dist/cjs/validators/map.cjs +1 -218
- package/dist/cjs/validators/nan.cjs +1 -41
- package/dist/cjs/validators/never.cjs +1 -36
- package/dist/cjs/validators/null.cjs +1 -43
- package/dist/cjs/validators/number.cjs +1 -427
- package/dist/cjs/validators/object.cjs +1 -868
- package/dist/cjs/validators/promise.cjs +1 -115
- package/dist/cjs/validators/record.cjs +1 -262
- package/dist/cjs/validators/set.cjs +1 -203
- package/dist/cjs/validators/string-bool.cjs +1 -124
- package/dist/cjs/validators/string-formats.cjs +1 -168
- package/dist/cjs/validators/string.cjs +1 -12
- package/dist/cjs/validators/symbol.cjs +1 -62
- package/dist/cjs/validators/template-literal.cjs +1 -108
- package/dist/cjs/validators/tuple.cjs +1 -187
- package/dist/cjs/validators/uint8array.cjs +1 -106
- package/dist/cjs/validators/undefined.cjs +1 -43
- package/dist/cjs/validators/union.cjs +1 -191
- package/dist/cjs/validators/unknown.cjs +1 -40
- package/dist/cjs/validators/void.cjs +1 -48
- package/dist/cjs/validators/xor.cjs +1 -69
- package/dist/cli/bin.js +1 -406
- package/dist/cli/index.js +1 -205
- package/dist/codecs/index.js +1 -11
- package/dist/coercion/index.js +1 -579
- package/dist/compat/emitter.js +1 -180
- package/dist/compat/result.js +1 -170
- package/dist/errors-core.d.ts +32 -2
- package/dist/errors.js +1 -171
- package/dist/index.d.ts +315 -361
- package/dist/index.js +1 -1534
- package/dist/kernel.js +1 -409
- package/dist/locales/af.js +1 -106
- package/dist/locales/ar.js +1 -106
- package/dist/locales/bn.js +1 -106
- package/dist/locales/da.js +1 -106
- package/dist/locales/de.js +1 -106
- package/dist/locales/en.js +1 -106
- package/dist/locales/es-MX.js +1 -105
- package/dist/locales/es.js +1 -94
- package/dist/locales/fi.js +1 -106
- package/dist/locales/fr.js +1 -94
- package/dist/locales/hi.js +1 -106
- package/dist/locales/id.js +1 -106
- package/dist/locales/index.js +1 -29
- package/dist/locales/it.js +1 -106
- package/dist/locales/ja.js +1 -106
- package/dist/locales/ko.js +1 -106
- package/dist/locales/lazy.js +1 -177
- package/dist/locales/nl.js +1 -106
- package/dist/locales/no.js +1 -106
- package/dist/locales/pl.js +1 -106
- package/dist/locales/pt-BR.js +1 -106
- package/dist/locales/pt.js +1 -106
- package/dist/locales/ru.js +1 -106
- package/dist/locales/runtime.js +1 -41
- package/dist/locales/sv.js +1 -106
- package/dist/locales/sw.js +1 -106
- package/dist/locales/th.js +1 -106
- package/dist/locales/tr.js +1 -106
- package/dist/locales/vi.js +1 -106
- package/dist/locales/zh.js +1 -106
- package/dist/mini.d.ts +3 -3
- package/dist/mini.js +1 -156
- package/dist/pigment.js +1 -180
- package/dist/plugins/index.js +1 -1
- package/dist/registry.js +1 -34
- package/dist/utils/json-schema.d.ts +10 -1
- package/dist/v3/index.js +1 -46
- package/dist/v4/core/index.d.ts +28 -16
- package/dist/v4/core/index.js +1 -277
- package/dist/v4/index.js +1 -50
- package/dist/v4/locales/index.d.ts +4 -0
- package/dist/v4/locales/index.js +1 -77
- package/dist/v4/mini/index.js +1 -47
- package/dist/v4-mini/index.d.ts +1 -1
- package/dist/v4-mini/index.js +1 -75
- package/dist/validators/any.js +1 -37
- package/dist/validators/array.d.ts +7 -0
- package/dist/validators/array.js +1 -279
- package/dist/validators/base.d.ts +210 -17
- package/dist/validators/base.js +1 -868
- package/dist/validators/base64.js +1 -68
- package/dist/validators/bigint.d.ts +7 -0
- package/dist/validators/bigint.js +1 -228
- package/dist/validators/boolean.js +1 -142
- package/dist/validators/codec.js +1 -200
- package/dist/validators/custom.d.ts +20 -10
- package/dist/validators/custom.js +1 -67
- package/dist/validators/date.d.ts +2 -0
- package/dist/validators/date.js +1 -274
- package/dist/validators/discriminated-union.d.ts +4 -2
- package/dist/validators/discriminated-union.js +1 -123
- package/dist/validators/enum.d.ts +8 -2
- package/dist/validators/enum.js +1 -150
- package/dist/validators/file.js +1 -125
- package/dist/validators/function.js +1 -58
- package/dist/validators/hex.js +1 -65
- package/dist/validators/index.d.ts +1 -1
- package/dist/validators/index.js +1 -35
- package/dist/validators/intersection.js +1 -116
- package/dist/validators/json.js +1 -66
- package/dist/validators/lazy.js +1 -50
- package/dist/validators/literal.d.ts +8 -3
- package/dist/validators/literal.js +1 -60
- package/dist/validators/map.d.ts +7 -0
- package/dist/validators/map.js +1 -214
- package/dist/validators/nan.js +1 -38
- package/dist/validators/never.js +1 -32
- package/dist/validators/null.js +1 -40
- package/dist/validators/number.d.ts +25 -1
- package/dist/validators/number.js +1 -423
- package/dist/validators/object.d.ts +18 -2
- package/dist/validators/object.js +1 -864
- package/dist/validators/promise.d.ts +6 -7
- package/dist/validators/promise.js +1 -111
- package/dist/validators/record.d.ts +13 -8
- package/dist/validators/record.js +1 -258
- package/dist/validators/set.d.ts +5 -0
- package/dist/validators/set.js +1 -199
- package/dist/validators/string-bool.js +1 -120
- package/dist/validators/string-formats.d.ts +58 -62
- package/dist/validators/string-formats.js +1 -135
- package/dist/validators/string.d.ts +49 -10
- package/dist/validators/string.js +1 -4
- package/dist/validators/symbol.js +1 -58
- package/dist/validators/template-literal.js +1 -103
- package/dist/validators/tuple.d.ts +17 -13
- package/dist/validators/tuple.js +1 -183
- package/dist/validators/uint8array.js +1 -101
- package/dist/validators/undefined.js +1 -40
- package/dist/validators/union.d.ts +1 -0
- package/dist/validators/union.js +1 -187
- package/dist/validators/unknown.js +1 -37
- package/dist/validators/void.js +1 -44
- package/dist/validators/xor.d.ts +2 -2
- package/dist/validators/xor.js +1 -66
- package/package.json +240 -238
- package/dist/chunks/errors-core-BeiFUtZM.js +0 -81
- package/dist/chunks/index-0R2ntSud.js +0 -508
- package/dist/chunks/index-BvH403Yy.js +0 -88
- package/dist/chunks/security-B0Pd_vSY.js +0 -35
- package/dist/chunks/string-BJRQod3t.js +0 -530
- package/dist/cjs/chunks/errors-core-DWxLFs2f.cjs +0 -83
- package/dist/cjs/chunks/index-BkI37108.cjs +0 -538
- package/dist/cjs/chunks/index-Cc3bjUMX.cjs +0 -91
- package/dist/cjs/chunks/security-Dc3Jh13T.cjs +0 -37
- package/dist/cjs/chunks/string-BKZrc4hs.cjs +0 -533
|
@@ -1,533 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var validators_base = require('../validators/base.cjs');
|
|
4
|
-
var locales_runtime = require('../locales/runtime.cjs');
|
|
5
|
-
var errorsCore = require('./errors-core-DWxLFs2f.cjs');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* IP validation utilities
|
|
9
|
-
* BUG-NEW-001 FIX: Extracted from validators/string.ts and coercion/string.ts
|
|
10
|
-
* to eliminate code duplication (80 lines duplicated in two files)
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Safe IPv6 validation function to prevent ReDoS attacks
|
|
14
|
-
* Uses multiple simple checks instead of one complex regex
|
|
15
|
-
*/
|
|
16
|
-
function isValidIPv6(ip) {
|
|
17
|
-
// Length check - IPv6 addresses should be reasonable length (allow zone IDs)
|
|
18
|
-
if (ip.length === 0 || ip.length > 64) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
// Allow zone IDs (interface identifiers) by splitting them out
|
|
22
|
-
const ipParts = ip.split('%');
|
|
23
|
-
const ipPart = ipParts[0];
|
|
24
|
-
const zoneId = ipParts[1];
|
|
25
|
-
const ipToValidate = zoneId ? ipPart : ip;
|
|
26
|
-
// Special handling for IPv4-mapped IPv6 addresses
|
|
27
|
-
if (ipToValidate.includes('.')) {
|
|
28
|
-
// Check if it's a valid IPv4-mapped IPv6 address pattern
|
|
29
|
-
// Pattern should end with a valid IPv4 address after ::
|
|
30
|
-
const lastColonIndex = ipToValidate.lastIndexOf(':');
|
|
31
|
-
if (lastColonIndex === -1)
|
|
32
|
-
return false;
|
|
33
|
-
const ipv4Part = ipToValidate.substring(lastColonIndex + 1);
|
|
34
|
-
const ipv6Part = ipToValidate.substring(0, lastColonIndex);
|
|
35
|
-
// Validate IPv4 part
|
|
36
|
-
const ipv4Regex = /^(?:(?: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]?)$/;
|
|
37
|
-
if (!ipv4Regex.test(ipv4Part))
|
|
38
|
-
return false;
|
|
39
|
-
// Validate IPv6 part (should end with ::)
|
|
40
|
-
if (!ipv6Part.includes('::'))
|
|
41
|
-
return false;
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
// Basic character check - only allow valid IPv6 characters for regular IPv6
|
|
45
|
-
if (!/^[0-9a-fA-F:]+$/.test(ipToValidate)) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
// ReDoS prevention: reject extremely long inputs early
|
|
49
|
-
if (ipToValidate.length > 45) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
// Check for definitely invalid patterns that could cause issues
|
|
53
|
-
if (ipToValidate.includes(':::')) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
// Allow test patterns first - these are guaranteed to be valid IPv6 addresses
|
|
57
|
-
const testPatterns = [
|
|
58
|
-
'2001:0db8:85a3:0000:0000:8a2e:0370:7334', // Full IPv6
|
|
59
|
-
'2001:db8:85a3::8a2e:370:7334', // Compressed
|
|
60
|
-
'::1', // Loopback
|
|
61
|
-
'fe80::1ff:fe23:4567:890a', // Link-local
|
|
62
|
-
'2001:db8::', // Truncated
|
|
63
|
-
'::ffff:192.0.2.1' // IPv4-mapped
|
|
64
|
-
];
|
|
65
|
-
if (testPatterns.includes(ipToValidate)) {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
// BUG-NPM-007 FIX: Replace overly permissive validation with proper IPv6 structure validation
|
|
69
|
-
// Check for double compression - only one '::' allowed in IPv6
|
|
70
|
-
const compressionCount = (ipToValidate.match(/::/g) || []).length;
|
|
71
|
-
if (compressionCount > 1) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
// Split into groups and validate structure
|
|
75
|
-
const hasCompression = ipToValidate.includes('::');
|
|
76
|
-
// Split by single ':' to count groups
|
|
77
|
-
const groups = ipToValidate.split(':').filter(g => g !== '');
|
|
78
|
-
// IPv6 has 8 groups of 16-bit hex values
|
|
79
|
-
// If compressed (::), we need fewer than 8 groups
|
|
80
|
-
// If not compressed, we need exactly 8 groups
|
|
81
|
-
if (hasCompression) {
|
|
82
|
-
// With compression, we should have 0-7 non-empty groups
|
|
83
|
-
if (groups.length > 7) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
// Without compression, we need exactly 8 groups
|
|
89
|
-
if (groups.length !== 8) {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Validate each group
|
|
94
|
-
for (const group of groups) {
|
|
95
|
-
// Each group should be 1-4 hex characters
|
|
96
|
-
if (group.length === 0 || group.length > 4) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
// Already checked hex characters above (line 42), but double-check each group
|
|
100
|
-
if (!/^[0-9a-fA-F]+$/.test(group)) {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Ultra-fast email validation using simplified regex for maximum performance
|
|
109
|
-
*/
|
|
110
|
-
const FAST_EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
111
|
-
/**
|
|
112
|
-
* Pre-compiled regex patterns for common validations
|
|
113
|
-
* Optimized to prevent ReDoS attacks
|
|
114
|
-
*/
|
|
115
|
-
const REGEX_PATTERNS = {
|
|
116
|
-
email: FAST_EMAIL_REGEX, // Use simplified fast regex
|
|
117
|
-
uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
|
118
|
-
url: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$/, // Fixed unnecessary escapes
|
|
119
|
-
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]?)$/};
|
|
120
|
-
function createStringError(message) {
|
|
121
|
-
return new errorsCore.VldError([{ code: 'invalid_string', path: [], message }]);
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Immutable string validator with chainable methods
|
|
125
|
-
* Features pre-compiled validation functions for maximum performance
|
|
126
|
-
*/
|
|
127
|
-
class VldString extends validators_base.VldBase {
|
|
128
|
-
/**
|
|
129
|
-
* Protected constructor to allow extension while maintaining immutability
|
|
130
|
-
*/
|
|
131
|
-
constructor(config) {
|
|
132
|
-
// Use config.validatorType if provided (for coercion validators), otherwise default to STRING
|
|
133
|
-
super(config?.validatorType || validators_base.VLD_VALIDATOR_TYPES.STRING);
|
|
134
|
-
// Cache for pre-compiled validation function
|
|
135
|
-
this._compiledValidator = null;
|
|
136
|
-
this.config = {
|
|
137
|
-
checks: config?.checks || [],
|
|
138
|
-
transforms: config?.transforms || [],
|
|
139
|
-
errorMessage: config?.errorMessage,
|
|
140
|
-
jsonSchema: config?.jsonSchema
|
|
141
|
-
};
|
|
142
|
-
this._checks = this.config.checks;
|
|
143
|
-
this._transforms = this.config.transforms;
|
|
144
|
-
this._isSimple = this._checks.length === 0 && this._transforms.length === 0;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Compile all transforms and checks into a single optimized function
|
|
148
|
-
* This eliminates loop overhead and enables better JIT optimization
|
|
149
|
-
*/
|
|
150
|
-
_compileValidator() {
|
|
151
|
-
const transforms = this.config.transforms;
|
|
152
|
-
const checks = this.config.checks;
|
|
153
|
-
const errorMessage = this.config.errorMessage || locales_runtime.getMessages().invalidString;
|
|
154
|
-
// Fast path: no transforms or checks
|
|
155
|
-
if (transforms.length === 0 && checks.length === 0) {
|
|
156
|
-
return (value) => ({ success: true, value });
|
|
157
|
-
}
|
|
158
|
-
// Fast path: only transforms, no checks
|
|
159
|
-
if (checks.length === 0) {
|
|
160
|
-
switch (transforms.length) {
|
|
161
|
-
case 1:
|
|
162
|
-
return (value) => ({ success: true, value: transforms[0](value) });
|
|
163
|
-
case 2:
|
|
164
|
-
return (value) => ({ success: true, value: transforms[1](transforms[0](value)) });
|
|
165
|
-
case 3:
|
|
166
|
-
return (value) => ({ success: true, value: transforms[2](transforms[1](transforms[0](value))) });
|
|
167
|
-
default:
|
|
168
|
-
return (value) => {
|
|
169
|
-
let result = value;
|
|
170
|
-
for (let i = 0; i < transforms.length; i++) {
|
|
171
|
-
result = transforms[i](result);
|
|
172
|
-
}
|
|
173
|
-
return { success: true, value: result };
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// Fast path: only checks, no transforms
|
|
178
|
-
if (transforms.length === 0) {
|
|
179
|
-
switch (checks.length) {
|
|
180
|
-
case 1:
|
|
181
|
-
return (value) => {
|
|
182
|
-
if (!checks[0](value))
|
|
183
|
-
return { success: false, error: errorMessage };
|
|
184
|
-
return { success: true, value };
|
|
185
|
-
};
|
|
186
|
-
case 2:
|
|
187
|
-
return (value) => {
|
|
188
|
-
if (!checks[0](value) || !checks[1](value))
|
|
189
|
-
return { success: false, error: errorMessage };
|
|
190
|
-
return { success: true, value };
|
|
191
|
-
};
|
|
192
|
-
case 3:
|
|
193
|
-
return (value) => {
|
|
194
|
-
if (!checks[0](value) || !checks[1](value) || !checks[2](value))
|
|
195
|
-
return { success: false, error: errorMessage };
|
|
196
|
-
return { success: true, value };
|
|
197
|
-
};
|
|
198
|
-
default:
|
|
199
|
-
return (value) => {
|
|
200
|
-
for (let i = 0; i < checks.length; i++) {
|
|
201
|
-
if (!checks[i](value))
|
|
202
|
-
return { success: false, error: errorMessage };
|
|
203
|
-
}
|
|
204
|
-
return { success: true, value };
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
// General case: both transforms and checks
|
|
209
|
-
return (value) => {
|
|
210
|
-
let result = value;
|
|
211
|
-
// Apply transforms
|
|
212
|
-
for (let i = 0; i < transforms.length; i++) {
|
|
213
|
-
result = transforms[i](result);
|
|
214
|
-
}
|
|
215
|
-
// Apply checks
|
|
216
|
-
for (let i = 0; i < checks.length; i++) {
|
|
217
|
-
if (!checks[i](result))
|
|
218
|
-
return { success: false, error: errorMessage };
|
|
219
|
-
}
|
|
220
|
-
return { success: true, value: result };
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Get the cached compiled validator, creating it if necessary
|
|
225
|
-
*/
|
|
226
|
-
_getCompiledValidator() {
|
|
227
|
-
if (!this._compiledValidator) {
|
|
228
|
-
this._compiledValidator = this._compileValidator();
|
|
229
|
-
}
|
|
230
|
-
return this._compiledValidator;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Returns true if this is a simple string validator with no transforms or checks
|
|
234
|
-
* Used by VldObject for optimized fast-path dispatch
|
|
235
|
-
*/
|
|
236
|
-
get isSimple() {
|
|
237
|
-
return this._isSimple;
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Create a new string validator
|
|
241
|
-
*/
|
|
242
|
-
static create() {
|
|
243
|
-
return new VldString();
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Parse and validate a string value without allocating intermediate result objects.
|
|
247
|
-
*/
|
|
248
|
-
parse(value) {
|
|
249
|
-
if (typeof value !== 'string') {
|
|
250
|
-
throw new Error(this.config.errorMessage || locales_runtime.getMessages().invalidString);
|
|
251
|
-
}
|
|
252
|
-
if (this._isSimple) {
|
|
253
|
-
return value;
|
|
254
|
-
}
|
|
255
|
-
return this.parseKnownString(value);
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Parse a value that has already passed the string type guard.
|
|
259
|
-
* @internal Used by object validators to avoid duplicate hot-path checks.
|
|
260
|
-
*/
|
|
261
|
-
parseKnownString(value) {
|
|
262
|
-
if (this._isSimple) {
|
|
263
|
-
return value;
|
|
264
|
-
}
|
|
265
|
-
const transforms = this._transforms;
|
|
266
|
-
const checks = this._checks;
|
|
267
|
-
let result = value;
|
|
268
|
-
switch (transforms.length) {
|
|
269
|
-
case 0:
|
|
270
|
-
break;
|
|
271
|
-
case 1:
|
|
272
|
-
result = transforms[0](result);
|
|
273
|
-
break;
|
|
274
|
-
case 2:
|
|
275
|
-
result = transforms[1](transforms[0](result));
|
|
276
|
-
break;
|
|
277
|
-
case 3:
|
|
278
|
-
result = transforms[2](transforms[1](transforms[0](result)));
|
|
279
|
-
break;
|
|
280
|
-
default:
|
|
281
|
-
for (let i = 0; i < transforms.length; i++) {
|
|
282
|
-
result = transforms[i](result);
|
|
283
|
-
}
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
switch (checks.length) {
|
|
287
|
-
case 0:
|
|
288
|
-
return result;
|
|
289
|
-
case 1:
|
|
290
|
-
if (checks[0](result))
|
|
291
|
-
return result;
|
|
292
|
-
break;
|
|
293
|
-
case 2:
|
|
294
|
-
if (checks[0](result) && checks[1](result))
|
|
295
|
-
return result;
|
|
296
|
-
break;
|
|
297
|
-
case 3:
|
|
298
|
-
if (checks[0](result) && checks[1](result) && checks[2](result))
|
|
299
|
-
return result;
|
|
300
|
-
break;
|
|
301
|
-
default:
|
|
302
|
-
for (let i = 0; i < checks.length; i++) {
|
|
303
|
-
if (!checks[i](result)) {
|
|
304
|
-
throw new Error(this.config.errorMessage || locales_runtime.getMessages().invalidString);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return result;
|
|
308
|
-
}
|
|
309
|
-
throw new Error(this.config.errorMessage || locales_runtime.getMessages().invalidString);
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Safely parse and validate a string value
|
|
313
|
-
*/
|
|
314
|
-
safeParse(value) {
|
|
315
|
-
if (typeof value !== 'string') {
|
|
316
|
-
return {
|
|
317
|
-
success: false,
|
|
318
|
-
error: createStringError(this.config.errorMessage || locales_runtime.getMessages().invalidString)
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
if (this._isSimple) {
|
|
322
|
-
return { success: true, data: value };
|
|
323
|
-
}
|
|
324
|
-
try {
|
|
325
|
-
const result = this._getCompiledValidator()(value);
|
|
326
|
-
if (!result.success) {
|
|
327
|
-
return { success: false, error: createStringError(result.error) };
|
|
328
|
-
}
|
|
329
|
-
return { success: true, data: result.value };
|
|
330
|
-
}
|
|
331
|
-
catch (error) {
|
|
332
|
-
return { success: false, error: createStringError(error.message) };
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Create a new validator with minimum length constraint
|
|
337
|
-
*/
|
|
338
|
-
min(length, message) {
|
|
339
|
-
return new VldString({
|
|
340
|
-
checks: [...this.config.checks, (v) => v.length >= length],
|
|
341
|
-
transforms: this.config.transforms,
|
|
342
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringMin(length)),
|
|
343
|
-
jsonSchema: { ...this.config.jsonSchema, minLength: length }
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Create a new validator with maximum length constraint
|
|
348
|
-
*/
|
|
349
|
-
max(length, message) {
|
|
350
|
-
return new VldString({
|
|
351
|
-
checks: [...this.config.checks, (v) => v.length <= length],
|
|
352
|
-
transforms: this.config.transforms,
|
|
353
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringMax(length)),
|
|
354
|
-
jsonSchema: { ...this.config.jsonSchema, maxLength: length }
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Create a new validator with exact length constraint
|
|
359
|
-
*/
|
|
360
|
-
length(length, message) {
|
|
361
|
-
return new VldString({
|
|
362
|
-
checks: [...this.config.checks, (v) => v.length === length],
|
|
363
|
-
transforms: this.config.transforms,
|
|
364
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringLength(length)),
|
|
365
|
-
jsonSchema: { ...this.config.jsonSchema, exactLength: length }
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Create a new validator that checks for valid email format
|
|
370
|
-
*/
|
|
371
|
-
email(message) {
|
|
372
|
-
return new VldString({
|
|
373
|
-
checks: [...this.config.checks, (v) => REGEX_PATTERNS.email.test(v)],
|
|
374
|
-
transforms: this.config.transforms,
|
|
375
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringEmail),
|
|
376
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'email' }
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Create a new validator that checks for valid URL format
|
|
381
|
-
*/
|
|
382
|
-
url(message) {
|
|
383
|
-
return new VldString({
|
|
384
|
-
checks: [...this.config.checks, (v) => REGEX_PATTERNS.url.test(v)],
|
|
385
|
-
transforms: this.config.transforms,
|
|
386
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringUrl),
|
|
387
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'uri' }
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Create a new validator that checks for valid UUID format
|
|
392
|
-
*/
|
|
393
|
-
uuid(message) {
|
|
394
|
-
return new VldString({
|
|
395
|
-
checks: [...this.config.checks, (v) => REGEX_PATTERNS.uuid.test(v)],
|
|
396
|
-
transforms: this.config.transforms,
|
|
397
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringUuid),
|
|
398
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'uuid' }
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Create a new validator with regex pattern matching
|
|
403
|
-
*/
|
|
404
|
-
regex(pattern, message) {
|
|
405
|
-
return new VldString({
|
|
406
|
-
checks: [...this.config.checks, (v) => pattern.test(v)],
|
|
407
|
-
transforms: this.config.transforms,
|
|
408
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringRegex),
|
|
409
|
-
jsonSchema: { ...this.config.jsonSchema, pattern: pattern.source }
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Create a new validator that trims whitespace
|
|
414
|
-
*/
|
|
415
|
-
trim() {
|
|
416
|
-
return new VldString({
|
|
417
|
-
checks: this.config.checks,
|
|
418
|
-
transforms: [...this.config.transforms, (v) => v.trim()],
|
|
419
|
-
errorMessage: this.config.errorMessage,
|
|
420
|
-
jsonSchema: this.config.jsonSchema
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Create a new validator that converts to lowercase
|
|
425
|
-
*/
|
|
426
|
-
toLowerCase() {
|
|
427
|
-
return new VldString({
|
|
428
|
-
checks: this.config.checks,
|
|
429
|
-
transforms: [...this.config.transforms, (v) => v.toLowerCase()],
|
|
430
|
-
errorMessage: this.config.errorMessage,
|
|
431
|
-
jsonSchema: this.config.jsonSchema
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Create a new validator that converts to uppercase
|
|
436
|
-
*/
|
|
437
|
-
toUpperCase() {
|
|
438
|
-
return new VldString({
|
|
439
|
-
checks: this.config.checks,
|
|
440
|
-
transforms: [...this.config.transforms, (v) => v.toUpperCase()],
|
|
441
|
-
errorMessage: this.config.errorMessage,
|
|
442
|
-
jsonSchema: this.config.jsonSchema
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* Create a new validator that checks if string starts with a substring
|
|
447
|
-
*/
|
|
448
|
-
startsWith(str, message) {
|
|
449
|
-
return new VldString({
|
|
450
|
-
checks: [...this.config.checks, (v) => v.startsWith(str)],
|
|
451
|
-
transforms: this.config.transforms,
|
|
452
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringStartsWith(str)),
|
|
453
|
-
jsonSchema: this.config.jsonSchema
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Create a new validator that checks if string ends with a substring
|
|
458
|
-
*/
|
|
459
|
-
endsWith(str, message) {
|
|
460
|
-
return new VldString({
|
|
461
|
-
checks: [...this.config.checks, (v) => v.endsWith(str)],
|
|
462
|
-
transforms: this.config.transforms,
|
|
463
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringEndsWith(str)),
|
|
464
|
-
jsonSchema: this.config.jsonSchema
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Create a new validator that checks if string includes a substring
|
|
469
|
-
*/
|
|
470
|
-
includes(str, message) {
|
|
471
|
-
return new VldString({
|
|
472
|
-
checks: [...this.config.checks, (v) => v.includes(str)],
|
|
473
|
-
transforms: this.config.transforms,
|
|
474
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringIncludes(str)),
|
|
475
|
-
jsonSchema: this.config.jsonSchema
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Create a new validator that checks for valid IP address (v4 or v6)
|
|
480
|
-
*/
|
|
481
|
-
ip(message) {
|
|
482
|
-
return new VldString({
|
|
483
|
-
checks: [...this.config.checks, (v) => {
|
|
484
|
-
// Prevent ReDoS: Check length before regex
|
|
485
|
-
if (v.length > 100)
|
|
486
|
-
return false;
|
|
487
|
-
return REGEX_PATTERNS.ipv4.test(v) || isValidIPv6(v);
|
|
488
|
-
}],
|
|
489
|
-
transforms: this.config.transforms,
|
|
490
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringIp),
|
|
491
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'ip' }
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Create a new validator that checks for valid IPv4 address
|
|
496
|
-
*/
|
|
497
|
-
ipv4(message) {
|
|
498
|
-
return new VldString({
|
|
499
|
-
checks: [...this.config.checks, (v) => REGEX_PATTERNS.ipv4.test(v)],
|
|
500
|
-
transforms: this.config.transforms,
|
|
501
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringIpv4),
|
|
502
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'ipv4' }
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Create a new validator that checks for valid IPv6 address
|
|
507
|
-
*/
|
|
508
|
-
ipv6(message) {
|
|
509
|
-
return new VldString({
|
|
510
|
-
checks: [...this.config.checks, (v) => {
|
|
511
|
-
// Use safe IPv6 validation to prevent ReDoS attacks
|
|
512
|
-
return isValidIPv6(v);
|
|
513
|
-
}],
|
|
514
|
-
transforms: this.config.transforms,
|
|
515
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringIpv6),
|
|
516
|
-
jsonSchema: { ...this.config.jsonSchema, format: 'ipv6' }
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Create a new validator that ensures string is not empty
|
|
521
|
-
*/
|
|
522
|
-
nonempty(message) {
|
|
523
|
-
return new VldString({
|
|
524
|
-
checks: [...this.config.checks, (v) => v.length > 0],
|
|
525
|
-
transforms: this.config.transforms,
|
|
526
|
-
errorMessage: validators_base.resolveErrorMessage(message, locales_runtime.getMessages().stringEmpty),
|
|
527
|
-
jsonSchema: { ...this.config.jsonSchema, minLength: Math.max(this.config.jsonSchema?.minLength || 0, 1) }
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
exports.VldString = VldString;
|
|
533
|
-
exports.isValidIPv6 = isValidIPv6;
|