@zipbul/baker 3.4.0 → 4.0.0
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 +46 -0
- package/README.md +236 -148
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -10
- package/dist/src/baker.d.ts +26 -0
- package/dist/src/baker.js +1 -0
- package/dist/src/collect.js +1 -26
- package/dist/src/configure.d.ts +7 -1
- package/dist/src/configure.js +1 -43
- package/dist/src/create-rule.d.ts +2 -1
- package/dist/src/create-rule.js +1 -41
- package/dist/src/decorators/field.d.ts +2 -1
- package/dist/src/decorators/field.js +1 -277
- package/dist/src/decorators/index.js +1 -2
- package/dist/src/decorators/recipe.js +1 -23
- package/dist/src/enums.d.ts +51 -0
- package/dist/src/enums.js +1 -0
- package/dist/src/errors.js +1 -52
- package/dist/src/functions/check-call-options.js +1 -51
- package/dist/src/functions/deserialize.js +1 -57
- package/dist/src/functions/serialize.js +1 -52
- package/dist/src/functions/validate.js +1 -49
- package/dist/src/interfaces.js +0 -4
- package/dist/src/meta-access.js +1 -75
- package/dist/src/registry.js +1 -8
- package/dist/src/rule-metadata.js +1 -17
- package/dist/src/rule-plan.d.ts +5 -3
- package/dist/src/rule-plan.js +1 -117
- package/dist/src/rules/array.js +1 -96
- package/dist/src/rules/binary.js +3 -51
- package/dist/src/rules/combinators.js +1 -111
- package/dist/src/rules/common.js +1 -77
- package/dist/src/rules/date.js +1 -35
- package/dist/src/rules/index.js +1 -10
- package/dist/src/rules/locales.js +1 -249
- package/dist/src/rules/number.js +1 -79
- package/dist/src/rules/object.js +1 -49
- package/dist/src/rules/string.js +10 -2033
- package/dist/src/rules/typechecker.js +5 -171
- package/dist/src/seal/circular-analyzer.js +1 -63
- package/dist/src/seal/codegen-utils.js +1 -18
- package/dist/src/seal/deserialize-builder.js +265 -1564
- package/dist/src/seal/enums.d.ts +8 -0
- package/dist/src/seal/enums.js +1 -0
- package/dist/src/seal/expose-validator.js +1 -65
- package/dist/src/seal/seal-state.js +1 -18
- package/dist/src/seal/seal.d.ts +15 -1
- package/dist/src/seal/seal.js +1 -431
- package/dist/src/seal/serialize-builder.js +66 -370
- package/dist/src/seal/validate-meta.js +1 -61
- package/dist/src/symbols.js +1 -13
- package/dist/src/transformers/collection.transformer.js +1 -25
- package/dist/src/transformers/date.transformer.js +1 -18
- package/dist/src/transformers/index.js +1 -6
- package/dist/src/transformers/luxon.transformer.js +1 -34
- package/dist/src/transformers/moment.transformer.js +1 -32
- package/dist/src/transformers/number.transformer.js +1 -8
- package/dist/src/transformers/string.transformer.js +1 -12
- package/dist/src/types.d.ts +11 -10
- package/dist/src/types.js +0 -1
- package/dist/src/utils.js +1 -10
- package/package.json +2 -2
package/dist/src/rules/string.js
CHANGED
|
@@ -1,2035 +1,12 @@
|
|
|
1
|
-
import { makePlannedRule, makeRule, planCompare, planLength, planOr } from '../rule-plan.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function makeStringRule(name, validate, buildEmit, requiresType = 'string', constraints = {}) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
constraints,
|
|
10
|
-
validate: value => typeof value === 'string' && validate(value),
|
|
11
|
-
emit: buildEmit,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
-
// Group A: Length / Range
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
function minLength(min) {
|
|
18
|
-
const plan = { cacheKey: 'length', failure: planCompare(planLength(), '<', min) };
|
|
19
|
-
return makePlannedRule({
|
|
20
|
-
name: 'minLength',
|
|
21
|
-
requiresType: 'string',
|
|
22
|
-
constraints: { min },
|
|
23
|
-
plan,
|
|
24
|
-
validate: value => typeof value === 'string' && value.length >= min,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
function maxLength(max) {
|
|
28
|
-
const plan = { cacheKey: 'length', failure: planCompare(planLength(), '>', max) };
|
|
29
|
-
return makePlannedRule({
|
|
30
|
-
name: 'maxLength',
|
|
31
|
-
requiresType: 'string',
|
|
32
|
-
constraints: { max },
|
|
33
|
-
plan,
|
|
34
|
-
validate: value => typeof value === 'string' && value.length <= max,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
function length(minLen, maxLen) {
|
|
38
|
-
const plan = {
|
|
39
|
-
cacheKey: 'length',
|
|
40
|
-
failure: planOr(planCompare(planLength(), '<', minLen), planCompare(planLength(), '>', maxLen)),
|
|
41
|
-
};
|
|
42
|
-
return makePlannedRule({
|
|
43
|
-
name: 'length',
|
|
44
|
-
requiresType: 'string',
|
|
45
|
-
constraints: { min: minLen, max: maxLen },
|
|
46
|
-
plan,
|
|
47
|
-
validate: value => typeof value === 'string' && value.length >= minLen && value.length <= maxLen,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
function contains(seed) {
|
|
51
|
-
return makeRule({
|
|
52
|
-
name: 'contains',
|
|
53
|
-
requiresType: 'string',
|
|
54
|
-
constraints: { seed },
|
|
55
|
-
validate: value => typeof value === 'string' && value.includes(seed),
|
|
56
|
-
emit: (varName, ctx) => {
|
|
57
|
-
const i = ctx.addRef(seed);
|
|
58
|
-
return `if (!${varName}.includes(refs[${i}])) ${ctx.fail('contains')};`;
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
function notContains(seed) {
|
|
63
|
-
return makeRule({
|
|
64
|
-
name: 'notContains',
|
|
65
|
-
requiresType: 'string',
|
|
66
|
-
constraints: { seed },
|
|
67
|
-
validate: value => typeof value === 'string' && !value.includes(seed),
|
|
68
|
-
emit: (varName, ctx) => {
|
|
69
|
-
const i = ctx.addRef(seed);
|
|
70
|
-
return `if (${varName}.includes(refs[${i}])) ${ctx.fail('notContains')};`;
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
function matches(pattern, modifiers) {
|
|
75
|
-
const re = pattern instanceof RegExp ? pattern : new RegExp(pattern, modifiers);
|
|
76
|
-
return makeRule({
|
|
77
|
-
name: 'matches',
|
|
78
|
-
requiresType: 'string',
|
|
79
|
-
constraints: { pattern: re.source },
|
|
80
|
-
validate: value => typeof value === 'string' && re.test(value),
|
|
81
|
-
emit: (varName, ctx) => {
|
|
82
|
-
const i = ctx.addRegex(re);
|
|
83
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('matches')};`;
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
88
|
-
// Group B: Simple Boolean Checks
|
|
89
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
-
const isLowercase = makeRule({
|
|
91
|
-
name: 'isLowercase',
|
|
92
|
-
requiresType: 'string',
|
|
93
|
-
constraints: {},
|
|
94
|
-
validate: value => typeof value === 'string' && value === value.toLowerCase(),
|
|
95
|
-
emit: (varName, ctx) => `if (${varName} !== ${varName}.toLowerCase()) ${ctx.fail('isLowercase')};`,
|
|
96
|
-
});
|
|
97
|
-
const isUppercase = makeRule({
|
|
98
|
-
name: 'isUppercase',
|
|
99
|
-
requiresType: 'string',
|
|
100
|
-
constraints: {},
|
|
101
|
-
validate: value => typeof value === 'string' && value === value.toUpperCase(),
|
|
102
|
-
emit: (varName, ctx) => `if (${varName} !== ${varName}.toUpperCase()) ${ctx.fail('isUppercase')};`,
|
|
103
|
-
});
|
|
104
|
-
// ASCII: all code points in [0x00, 0x7F]
|
|
105
|
-
const ASCII_RE = new RegExp(`^[${String.fromCharCode(0)}-${String.fromCharCode(0x7f)}]*$`);
|
|
106
|
-
const isAscii = makeStringRule('isAscii', v => ASCII_RE.test(v), (varName, ctx) => {
|
|
107
|
-
const i = ctx.addRegex(ASCII_RE);
|
|
108
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isAscii')};`;
|
|
109
|
-
});
|
|
110
|
-
// Alpha — [a-zA-Z]+ singleton
|
|
111
|
-
const ALPHA_DEFAULT_RE = /^[a-zA-Z]+$/;
|
|
112
|
-
// length > 0 guard is dead — `+` quantifier requires ≥1 char so the regex returns false on empty.
|
|
113
|
-
const isAlpha = makeStringRule('isAlpha', v => ALPHA_DEFAULT_RE.test(v), (varName, ctx) => {
|
|
114
|
-
const i = ctx.addRegex(ALPHA_DEFAULT_RE);
|
|
115
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isAlpha')};`;
|
|
116
|
-
});
|
|
117
|
-
// Alphanumeric — [a-zA-Z0-9]+ singleton (same empty-input rationale as isAlpha)
|
|
118
|
-
const ALNUM_DEFAULT_RE = /^[a-zA-Z0-9]+$/;
|
|
119
|
-
const isAlphanumeric = makeStringRule('isAlphanumeric', v => ALNUM_DEFAULT_RE.test(v), (varName, ctx) => {
|
|
120
|
-
const i = ctx.addRegex(ALNUM_DEFAULT_RE);
|
|
121
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isAlphanumeric')};`;
|
|
122
|
-
});
|
|
123
|
-
// HTTP token — RFC 9110 §5.6.2: token = 1*tchar.
|
|
124
|
-
// tchar = "!"/"#"/"$"/"%"/"&"/"'"/"*"/"+"/"-"/"."/"^"/"_"/"`"/"|"/"~" / DIGIT / ALPHA.
|
|
125
|
-
// Used for HTTP method names and header field-names (not field-values). The hyphen is
|
|
126
|
-
// escaped so it stays literal — an unescaped `+-.` would form a range that admits ",".
|
|
127
|
-
const HTTP_TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
128
|
-
const isHttpToken = makeStringRule('isHttpToken', v => HTTP_TOKEN_RE.test(v), (varName, ctx) => {
|
|
129
|
-
const i = ctx.addRegex(HTTP_TOKEN_RE);
|
|
130
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHttpToken')};`;
|
|
131
|
-
});
|
|
132
|
-
// RFC 6454 §6.2 serialized origin — a string equal to WHATWG URL `.origin`.
|
|
133
|
-
// The opaque-origin literal 'null' is matched explicitly because `new URL('null')` throws.
|
|
134
|
-
// '*' (CORS wildcard) is rejected here; use isCorsOrigin for the CORS superset.
|
|
135
|
-
const isOriginValue = (value) => {
|
|
136
|
-
if (value === 'null') {
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
return new URL(value).origin === value;
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
const isOrigin = makeRule({
|
|
147
|
-
name: 'isOrigin',
|
|
148
|
-
requiresType: 'string',
|
|
149
|
-
constraints: { format: 'origin' },
|
|
150
|
-
validate: value => typeof value === 'string' && isOriginValue(value),
|
|
151
|
-
emit: (varName, ctx) => {
|
|
152
|
-
const i = ctx.addRef(isOriginValue);
|
|
153
|
-
return `if (!(refs[${i}](${varName}))) ${ctx.fail('isOrigin')};`;
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
// CORS superset of isOrigin: additionally accepts the '*' wildcard literal
|
|
157
|
-
// (Access-Control-Allow-Origin). Keep '*' out of the general isOrigin.
|
|
158
|
-
const isCorsOriginValue = (value) => value === '*' || isOriginValue(value);
|
|
159
|
-
const isCorsOrigin = makeRule({
|
|
160
|
-
name: 'isCorsOrigin',
|
|
161
|
-
requiresType: 'string',
|
|
162
|
-
constraints: { format: 'origin', allowWildcard: true },
|
|
163
|
-
validate: value => typeof value === 'string' && isCorsOriginValue(value),
|
|
164
|
-
emit: (varName, ctx) => {
|
|
165
|
-
const i = ctx.addRef(isCorsOriginValue);
|
|
166
|
-
return `if (!(refs[${i}](${varName}))) ${ctx.fail('isCorsOrigin')};`;
|
|
167
|
-
},
|
|
168
|
-
});
|
|
169
|
-
// BooleanString: 'true' | 'false' | '1' | '0'
|
|
170
|
-
const isBooleanString = makeRule({
|
|
171
|
-
name: 'isBooleanString',
|
|
172
|
-
requiresType: 'string',
|
|
173
|
-
constraints: {},
|
|
174
|
-
validate: value => value === 'true' || value === 'false' || value === '1' || value === '0',
|
|
175
|
-
emit: (varName, ctx) => `if (${varName} !== 'true' && ${varName} !== 'false' && ${varName} !== '1' && ${varName} !== '0') ${ctx.fail('isBooleanString')};`,
|
|
176
|
-
});
|
|
177
|
-
const NO_SYMBOLS_RE = /^[0-9]+$/;
|
|
178
|
-
// A numeric string: optional sign, integer/decimal/leading-dot form. No whitespace, hex, or
|
|
179
|
-
// exponent — `Number()` coercion accepted all of those (e.g. " ", "0x1A", "1e5"), which is far
|
|
180
|
-
// looser than "is this string a number". Matches validator.js's default isNumeric behavior.
|
|
181
|
-
const NUMERIC_STRING_RE = /^[+-]?(?:[0-9]*\.)?[0-9]+$/;
|
|
182
|
-
function isNumberString(options) {
|
|
183
|
-
const noSymbols = options?.no_symbols ?? false;
|
|
184
|
-
const re = noSymbols ? NO_SYMBOLS_RE : NUMERIC_STRING_RE;
|
|
185
|
-
return makeStringRule('isNumberString', (s) => re.test(s), (varName, ctx) => {
|
|
186
|
-
const i = ctx.addRegex(re);
|
|
187
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isNumberString')};`;
|
|
188
|
-
}, 'string', { no_symbols: noSymbols });
|
|
189
|
-
}
|
|
190
|
-
function isDecimal() {
|
|
191
|
-
// Require a digit after the dot — `\d+(?:\.\d*)?` accepted a dangling "5.".
|
|
192
|
-
const decimalRe = /^[-+]?(?:\d+(?:\.\d+)?|\.\d+)$/;
|
|
193
|
-
return makeStringRule('isDecimal', v => decimalRe.test(v), (varName, ctx) => {
|
|
194
|
-
const i = ctx.addRegex(decimalRe);
|
|
195
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isDecimal')};`;
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
// Full-width characters (Unicode fullwidth forms)
|
|
199
|
-
const FULLWIDTH_RE = /[^\u0020-\u007E\uFF61-\uFF9F]/;
|
|
200
|
-
// Empty-string guard is redundant — non-anchored char-class regex returns false on empty input.
|
|
201
|
-
const isFullWidth = makeStringRule('isFullWidth', v => FULLWIDTH_RE.test(v), (varName, ctx) => {
|
|
202
|
-
const i = ctx.addRegex(FULLWIDTH_RE);
|
|
203
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isFullWidth')};`;
|
|
204
|
-
});
|
|
205
|
-
// Half-width characters
|
|
206
|
-
const HALFWIDTH_RE = /[\u0020-\u007E\uFF61-\uFF9F]/;
|
|
207
|
-
const isHalfWidth = makeStringRule('isHalfWidth', v => HALFWIDTH_RE.test(v), (varName, ctx) => {
|
|
208
|
-
const i = ctx.addRegex(HALFWIDTH_RE);
|
|
209
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHalfWidth')};`;
|
|
210
|
-
});
|
|
211
|
-
// Variable-width: must contain both full-width AND half-width
|
|
212
|
-
const isVariableWidth = makeStringRule('isVariableWidth', v => FULLWIDTH_RE.test(v) && HALFWIDTH_RE.test(v), (varName, ctx) => {
|
|
213
|
-
const i1 = ctx.addRegex(FULLWIDTH_RE);
|
|
214
|
-
const i2 = ctx.addRegex(HALFWIDTH_RE);
|
|
215
|
-
return `if (!re[${i1}].test(${varName}) || !re[${i2}].test(${varName})) ${ctx.fail('isVariableWidth')};`;
|
|
216
|
-
});
|
|
217
|
-
// Multibyte: any character outside Latin-1 / half-width range
|
|
218
|
-
const MULTIBYTE_RE = new RegExp(`[^${String.fromCharCode(0)}-${String.fromCharCode(0xff)}]`);
|
|
219
|
-
const isMultibyte = makeStringRule('isMultibyte', v => MULTIBYTE_RE.test(v), (varName, ctx) => {
|
|
220
|
-
const i = ctx.addRegex(MULTIBYTE_RE);
|
|
221
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMultibyte')};`;
|
|
222
|
-
});
|
|
223
|
-
// Surrogate pairs
|
|
224
|
-
const SURROGATE_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
|
|
225
|
-
const isSurrogatePair = makeStringRule('isSurrogatePair', v => SURROGATE_RE.test(v), (varName, ctx) => {
|
|
226
|
-
const i = ctx.addRegex(SURROGATE_RE);
|
|
227
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isSurrogatePair')};`;
|
|
228
|
-
});
|
|
229
|
-
// Hexadecimal
|
|
230
|
-
const HEX_RE = /^[0-9a-fA-F]+$/;
|
|
231
|
-
const isHexadecimal = makeStringRule('isHexadecimal', v => HEX_RE.test(v), (varName, ctx) => {
|
|
232
|
-
const i = ctx.addRegex(HEX_RE);
|
|
233
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHexadecimal')};`;
|
|
234
|
-
});
|
|
235
|
-
// Octal
|
|
236
|
-
const OCTAL_RE = /^(0[oO])?[0-7]+$/;
|
|
237
|
-
const isOctal = makeStringRule('isOctal', v => OCTAL_RE.test(v), (varName, ctx) => {
|
|
238
|
-
const i = ctx.addRegex(OCTAL_RE);
|
|
239
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isOctal')};`;
|
|
240
|
-
});
|
|
241
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
242
|
-
// Group C: Regex-based
|
|
243
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
244
|
-
// Email — RFC 5322 simplified
|
|
245
|
-
const EMAIL_RE = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/;
|
|
246
|
-
function isEmail() {
|
|
247
|
-
return makeStringRule('isEmail', v => EMAIL_RE.test(v), (varName, ctx) => {
|
|
248
|
-
const i = ctx.addRegex(EMAIL_RE);
|
|
249
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isEmail')};`;
|
|
250
|
-
}, 'string', { format: 'email' });
|
|
251
|
-
}
|
|
252
|
-
const URL_PROTOCOLS_DEFAULT = ['http', 'https', 'ftp'];
|
|
253
|
-
function isURL(options) {
|
|
254
|
-
const protocols = options?.protocols ?? URL_PROTOCOLS_DEFAULT;
|
|
255
|
-
const protocolPattern = protocols.map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
256
|
-
const re = new RegExp(`^(?:${protocolPattern}):\\/\\/(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?::(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{0,3}|0))?(?:\\/[^\\s]*)?$`);
|
|
257
|
-
return makeRule({
|
|
258
|
-
name: 'isURL',
|
|
259
|
-
requiresType: 'string',
|
|
260
|
-
constraints: { format: 'uri', protocols },
|
|
261
|
-
validate: value => typeof value === 'string' && re.test(value),
|
|
262
|
-
emit: (varName, ctx) => {
|
|
263
|
-
const i = ctx.addRegex(re);
|
|
264
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isURL')};`;
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
// UUID
|
|
269
|
-
const UUID_RE = {
|
|
270
|
-
all: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
|
|
271
|
-
1: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-1[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
|
|
272
|
-
2: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-2[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
|
|
273
|
-
3: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
|
|
274
|
-
4: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
|
|
275
|
-
5: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
|
|
276
|
-
};
|
|
277
|
-
function isUUID(version) {
|
|
278
|
-
const re = version != null ? UUID_RE[version] : UUID_RE.all;
|
|
279
|
-
return makeStringRule('isUUID', v => re.test(v), (varName, ctx) => {
|
|
280
|
-
const i = ctx.addRegex(re);
|
|
281
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isUUID')};`;
|
|
282
|
-
}, 'string', { format: 'uuid', version });
|
|
283
|
-
}
|
|
284
|
-
// IP
|
|
285
|
-
const IPV4_RE = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/;
|
|
286
|
-
const IPV6_RE = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,7}:$|^(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}$|^(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}$|^(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}$|^::$|^::1$|^::(?:ffff(?::0{1,4})?:)?(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$|^(?:[0-9a-fA-F]{1,4}:){1,4}:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
|
287
|
-
function isIP(version) {
|
|
288
|
-
return makeRule({
|
|
289
|
-
name: 'isIP',
|
|
290
|
-
requiresType: 'string',
|
|
291
|
-
constraints: { version },
|
|
292
|
-
validate: value => {
|
|
293
|
-
if (typeof value !== 'string') {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
if (version === 4) {
|
|
297
|
-
return IPV4_RE.test(value);
|
|
298
|
-
}
|
|
299
|
-
if (version === 6) {
|
|
300
|
-
return IPV6_RE.test(value);
|
|
301
|
-
}
|
|
302
|
-
return IPV4_RE.test(value) || IPV6_RE.test(value);
|
|
303
|
-
},
|
|
304
|
-
emit: (varName, ctx) => {
|
|
305
|
-
if (version === 4) {
|
|
306
|
-
const i = ctx.addRegex(IPV4_RE);
|
|
307
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isIP')};`;
|
|
308
|
-
}
|
|
309
|
-
if (version === 6) {
|
|
310
|
-
const i = ctx.addRegex(IPV6_RE);
|
|
311
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isIP')};`;
|
|
312
|
-
}
|
|
313
|
-
const i4 = ctx.addRegex(IPV4_RE);
|
|
314
|
-
const i6 = ctx.addRegex(IPV6_RE);
|
|
315
|
-
return `if (!re[${i4}].test(${varName}) && !re[${i6}].test(${varName})) ${ctx.fail('isIP')};`;
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
// HexColor: #RGB or #RRGGBB
|
|
320
|
-
const HEX_COLOR_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
321
|
-
const isHexColor = makeStringRule('isHexColor', v => HEX_COLOR_RE.test(v), (varName, ctx) => {
|
|
322
|
-
const i = ctx.addRegex(HEX_COLOR_RE);
|
|
323
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHexColor')};`;
|
|
324
|
-
});
|
|
325
|
-
// RgbColor
|
|
326
|
-
const RGB_RE = /^rgb\(\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*\)$/;
|
|
327
|
-
const RGBA_RE = /^rgba\(\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(0|0?\.\d+|1(\.0+)?)\s*\)$/;
|
|
328
|
-
// Percent forms: rgb(...) must NOT have alpha; rgba(...) MUST have alpha.
|
|
329
|
-
const RGB_PERCENT_NOALPHA_RE = /^rgb\(\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*\)$/;
|
|
330
|
-
const RGBA_PERCENT_RE = /^rgba\(\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(0|0?\.\d+|1(?:\.0+)?)\s*\)$/;
|
|
331
|
-
function isRgbColor(includePercentValues = false) {
|
|
332
|
-
return makeRule({
|
|
333
|
-
name: 'isRgbColor',
|
|
334
|
-
requiresType: 'string',
|
|
335
|
-
constraints: { includePercentValues },
|
|
336
|
-
validate: value => {
|
|
337
|
-
if (typeof value !== 'string') {
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
if (includePercentValues) {
|
|
341
|
-
return RGB_PERCENT_NOALPHA_RE.test(value) || RGBA_PERCENT_RE.test(value) || RGB_RE.test(value) || RGBA_RE.test(value);
|
|
342
|
-
}
|
|
343
|
-
return RGB_RE.test(value) || RGBA_RE.test(value);
|
|
344
|
-
},
|
|
345
|
-
emit: (varName, ctx) => {
|
|
346
|
-
if (includePercentValues) {
|
|
347
|
-
const ip1 = ctx.addRegex(RGB_PERCENT_NOALPHA_RE);
|
|
348
|
-
const ip2 = ctx.addRegex(RGBA_PERCENT_RE);
|
|
349
|
-
const ip3 = ctx.addRegex(RGB_RE);
|
|
350
|
-
const ip4 = ctx.addRegex(RGBA_RE);
|
|
351
|
-
return `if (!re[${ip1}].test(${varName}) && !re[${ip2}].test(${varName}) && !re[${ip3}].test(${varName}) && !re[${ip4}].test(${varName})) ${ctx.fail('isRgbColor')};`;
|
|
352
|
-
}
|
|
353
|
-
const i1 = ctx.addRegex(RGB_RE);
|
|
354
|
-
const i2 = ctx.addRegex(RGBA_RE);
|
|
355
|
-
return `if (!re[${i1}].test(${varName}) && !re[${i2}].test(${varName})) ${ctx.fail('isRgbColor')};`;
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
// HSL: hsl(H, S%, L%) or hsla(H, S%, L%, A)
|
|
360
|
-
// Alpha belongs to hsla() only — `hsla?(...)?` previously let hsl() carry alpha and hsla() omit it.
|
|
361
|
-
const HSL_RE = /^(?:hsl\(\s*(?:360|3[0-5]\d|[12]\d{2}|[1-9]\d|\d)\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:100|[1-9]\d|\d)%\s*\)|hsla\(\s*(?:360|3[0-5]\d|[12]\d{2}|[1-9]\d|\d)\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:0|0?\.\d+|1(?:\.0+)?)\s*\))$/;
|
|
362
|
-
const isHSL = makeStringRule('isHSL', v => HSL_RE.test(v), (varName, ctx) => {
|
|
363
|
-
const i = ctx.addRegex(HSL_RE);
|
|
364
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHSL')};`;
|
|
365
|
-
});
|
|
366
|
-
const MAC_COLON_RE = /^[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5}$/;
|
|
367
|
-
const MAC_HYPHEN_RE = /^[0-9a-fA-F]{2}(?:-[0-9a-fA-F]{2}){5}$/;
|
|
368
|
-
const MAC_NO_SEP_RE = /^[0-9a-fA-F]{12}$/;
|
|
369
|
-
function isMACAddress(options) {
|
|
370
|
-
return makeRule({
|
|
371
|
-
name: 'isMACAddress',
|
|
372
|
-
requiresType: 'string',
|
|
373
|
-
constraints: { no_separators: options?.no_separators },
|
|
374
|
-
validate: value => {
|
|
375
|
-
if (typeof value !== 'string') {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
if (options?.no_separators) {
|
|
379
|
-
return MAC_NO_SEP_RE.test(value);
|
|
380
|
-
}
|
|
381
|
-
return MAC_COLON_RE.test(value) || MAC_HYPHEN_RE.test(value);
|
|
382
|
-
},
|
|
383
|
-
emit: (varName, ctx) => {
|
|
384
|
-
if (options?.no_separators) {
|
|
385
|
-
const i = ctx.addRegex(MAC_NO_SEP_RE);
|
|
386
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMACAddress')};`;
|
|
387
|
-
}
|
|
388
|
-
const i1 = ctx.addRegex(MAC_COLON_RE);
|
|
389
|
-
const i2 = ctx.addRegex(MAC_HYPHEN_RE);
|
|
390
|
-
return `if (!re[${i1}].test(${varName}) && !re[${i2}].test(${varName})) ${ctx.fail('isMACAddress')};`;
|
|
391
|
-
},
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
// ISBN
|
|
395
|
-
function validateISBN10(str) {
|
|
396
|
-
const s = str.replace(/[-\s]/g, '');
|
|
397
|
-
if (!/^\d{9}[\dX]$/.test(s)) {
|
|
398
|
-
return false;
|
|
399
|
-
}
|
|
400
|
-
let sum = 0;
|
|
401
|
-
for (let i = 0; i < 9; i++) {
|
|
402
|
-
sum += (10 - i) * (s.charCodeAt(i) - 48);
|
|
403
|
-
}
|
|
404
|
-
const last = s[9] === 'X' ? 10 : s.charCodeAt(9) - 48;
|
|
405
|
-
sum += last;
|
|
406
|
-
return sum % 11 === 0;
|
|
407
|
-
}
|
|
408
|
-
function validateISBN13(str) {
|
|
409
|
-
const s = str.replace(/[-\s]/g, '');
|
|
410
|
-
if (!/^\d{13}$/.test(s)) {
|
|
411
|
-
return false;
|
|
412
|
-
}
|
|
413
|
-
let sum = 0;
|
|
414
|
-
for (let i = 0; i < 12; i++) {
|
|
415
|
-
sum += (s.charCodeAt(i) - 48) * (i % 2 === 0 ? 1 : 3);
|
|
416
|
-
}
|
|
417
|
-
const check = (10 - (sum % 10)) % 10;
|
|
418
|
-
return check === s.charCodeAt(12) - 48;
|
|
419
|
-
}
|
|
420
|
-
function isISBN(version) {
|
|
421
|
-
const validateFn = (value) => {
|
|
422
|
-
if (typeof value !== 'string') {
|
|
423
|
-
return false;
|
|
424
|
-
}
|
|
425
|
-
if (version === 10) {
|
|
426
|
-
return validateISBN10(value);
|
|
427
|
-
}
|
|
428
|
-
if (version === 13) {
|
|
429
|
-
return validateISBN13(value);
|
|
430
|
-
}
|
|
431
|
-
return validateISBN10(value) || validateISBN13(value);
|
|
432
|
-
};
|
|
433
|
-
const emitISBN10 = (v) => `{var s=${v}.replace(/[-\\s]/g,'');` +
|
|
434
|
-
`if(!/^\\d{9}[\\dX]$/.test(s)){%%FAIL%%}` +
|
|
435
|
-
`else{var sm=0;for(var i=0;i<9;i++)sm+=(10-i)*(s.charCodeAt(i)-48);` +
|
|
436
|
-
`var l=s[9]==='X'?10:(s.charCodeAt(9)-48);sm+=l;` +
|
|
437
|
-
`if(sm%11!==0){%%FAIL%%}}}`;
|
|
438
|
-
const emitISBN13 = (v) => `{var s=${v}.replace(/[-\\s]/g,'');` +
|
|
439
|
-
`if(!/^\\d{13}$/.test(s)){%%FAIL%%}` +
|
|
440
|
-
`else{var sm=0;for(var i=0;i<12;i++)sm+=(s.charCodeAt(i)-48)*(i%2===0?1:3);` +
|
|
441
|
-
`var ck=(10-(sm%10))%10;` +
|
|
442
|
-
`if(ck!==(s.charCodeAt(12)-48)){%%FAIL%%}}}`;
|
|
443
|
-
return makeRule({
|
|
444
|
-
name: 'isISBN',
|
|
445
|
-
requiresType: 'string',
|
|
446
|
-
constraints: { version },
|
|
447
|
-
validate: validateFn,
|
|
448
|
-
emit: (varName, ctx) => {
|
|
449
|
-
const fail = ctx.fail('isISBN');
|
|
450
|
-
if (version === 10) {
|
|
451
|
-
return emitISBN10(varName).replace(/%%FAIL%%/g, fail);
|
|
452
|
-
}
|
|
453
|
-
if (version === 13) {
|
|
454
|
-
return emitISBN13(varName).replace(/%%FAIL%%/g, fail);
|
|
455
|
-
}
|
|
456
|
-
const emit10 = emitISBN10(varName).replace(/%%FAIL%%/g, '__isbn_ok=false');
|
|
457
|
-
const emit13 = emitISBN13(varName).replace(/%%FAIL%%/g, '__isbn_ok=false');
|
|
458
|
-
return `{var __isbn_ok=true;${emit10} if(!__isbn_ok){__isbn_ok=true;${emit13}} if(!__isbn_ok)${fail};}`;
|
|
459
|
-
},
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
// ISIN — ISO 6166
|
|
463
|
-
const ISIN_RE = /^[A-Z]{2}[A-Z0-9]{9}[0-9]$/;
|
|
464
|
-
function validateISINStr(v) {
|
|
465
|
-
if (!ISIN_RE.test(v)) {
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
468
|
-
// Luhn mod10 on expanded digits — walk right-to-left, expanding letters as A=10..Z=35 on the fly.
|
|
469
|
-
// No intermediate string/array allocations.
|
|
470
|
-
let sum = 0;
|
|
471
|
-
let alternate = false;
|
|
472
|
-
for (let i = v.length - 1; i >= 0; i--) {
|
|
473
|
-
const code = v.charCodeAt(i);
|
|
474
|
-
if (code <= 57) {
|
|
475
|
-
// ASCII digit '0'..'9'
|
|
476
|
-
let n = code - 48;
|
|
477
|
-
if (alternate) {
|
|
478
|
-
n *= 2;
|
|
479
|
-
if (n > 9) {
|
|
480
|
-
n -= 9;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
sum += n;
|
|
484
|
-
alternate = !alternate;
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
// ASCII letter 'A'..'Z' → two-digit value, ones first when walking right-to-left
|
|
488
|
-
const value = code - 55;
|
|
489
|
-
const ones = value % 10;
|
|
490
|
-
let n = ones;
|
|
491
|
-
if (alternate) {
|
|
492
|
-
n *= 2;
|
|
493
|
-
if (n > 9) {
|
|
494
|
-
n -= 9;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
sum += n;
|
|
498
|
-
alternate = !alternate;
|
|
499
|
-
n = (value - ones) / 10;
|
|
500
|
-
if (alternate) {
|
|
501
|
-
n *= 2;
|
|
502
|
-
if (n > 9) {
|
|
503
|
-
n -= 9;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
sum += n;
|
|
507
|
-
alternate = !alternate;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
return sum % 10 === 0;
|
|
511
|
-
}
|
|
512
|
-
const isISIN = makeStringRule('isISIN', validateISINStr, (varName, ctx) => {
|
|
513
|
-
const i = ctx.addRegex(ISIN_RE);
|
|
514
|
-
return (`if (!re[${i}].test(${varName})) ${ctx.fail('isISIN')};\n` +
|
|
515
|
-
`else { var isSum=0,isAlt=false;\n` +
|
|
516
|
-
`for(var isI=${varName}.length-1;isI>=0;isI--){var isCd=${varName}.charCodeAt(isI);` +
|
|
517
|
-
`if(isCd<=57){var isN=isCd-48;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;}` +
|
|
518
|
-
`else{var isVal=isCd-55;var isO=isVal%10;var isN=isO;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;` +
|
|
519
|
-
`isN=(isVal-isO)/10;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;}}\n` +
|
|
520
|
-
`if(isSum%10!==0)${ctx.fail('isISIN')}; }`);
|
|
521
|
-
});
|
|
522
|
-
// ISO 8601
|
|
523
|
-
const ISO8601_RE = /^\d{4}(?:-\d{2}(?:-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)?)?)?$/;
|
|
524
|
-
// Strict ISO8601: requires month/day AND hour/minute/second to be valid values
|
|
525
|
-
function validateISO8601Strict(v) {
|
|
526
|
-
if (!ISO8601_RE.test(v)) {
|
|
527
|
-
return false;
|
|
528
|
-
}
|
|
529
|
-
const m = v.match(/^(\d{4})-(\d{2})(?:-(\d{2}))?/);
|
|
530
|
-
if (!m) {
|
|
531
|
-
return true;
|
|
532
|
-
} // year-only — no month/day to range-check
|
|
533
|
-
const month = Number(m[2]);
|
|
534
|
-
if (month < 1 || month > 12) {
|
|
535
|
-
return false;
|
|
536
|
-
}
|
|
537
|
-
if (m[3] !== undefined) {
|
|
538
|
-
const day = Number(m[3]);
|
|
539
|
-
const maxDay = new Date(Number(m[1]), month, 0).getDate();
|
|
540
|
-
if (day < 1 || day > maxDay) {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
// Time component check: hour 0-23, minute 0-59, second 0-60 (leap second).
|
|
545
|
-
const tm = v.match(/T(\d{2}):(\d{2}):(\d{2})/);
|
|
546
|
-
if (!tm) {
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
const hh = Number(tm[1]);
|
|
550
|
-
const mm = Number(tm[2]);
|
|
551
|
-
const ss = Number(tm[3]);
|
|
552
|
-
return hh >= 0 && hh <= 23 && mm >= 0 && mm <= 59 && ss >= 0 && ss <= 60;
|
|
553
|
-
}
|
|
554
|
-
function isISO8601(options) {
|
|
555
|
-
if (options?.strict) {
|
|
556
|
-
const validateStrict = (v) => typeof v === 'string' && validateISO8601Strict(v);
|
|
557
|
-
return makeRule({
|
|
558
|
-
name: 'isISO8601',
|
|
559
|
-
requiresType: 'string',
|
|
560
|
-
constraints: { format: 'date-time', strict: true },
|
|
561
|
-
validate: validateStrict,
|
|
562
|
-
emit: (varName, ctx) => {
|
|
563
|
-
const i = ctx.addRegex(ISO8601_RE);
|
|
564
|
-
return (`if (!re[${i}].test(${varName})) ${ctx.fail('isISO8601')};\n` +
|
|
565
|
-
`else { var dm=${varName}.match(/^(\\d{4})-(\\d{2})(?:-(\\d{2}))?/);` +
|
|
566
|
-
`if(dm){var mo=Number(dm[2]);` +
|
|
567
|
-
`if(mo<1||mo>12){${ctx.fail('isISO8601')}}` +
|
|
568
|
-
`else if(dm[3]!==undefined){var da=Number(dm[3]),md=new Date(Number(dm[1]),mo,0).getDate();` +
|
|
569
|
-
`if(da<1||da>md){${ctx.fail('isISO8601')}}}}` +
|
|
570
|
-
`var tm=${varName}.match(/T(\\d{2}):(\\d{2}):(\\d{2})/);` +
|
|
571
|
-
`if(tm){var hh=Number(tm[1]),mm=Number(tm[2]),ss=Number(tm[3]);` +
|
|
572
|
-
`if(hh<0||hh>23||mm<0||mm>59||ss<0||ss>60)${ctx.fail('isISO8601')};} }`);
|
|
573
|
-
},
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
// non-strict: both validate and emit use same ISO8601_RE
|
|
577
|
-
return makeStringRule('isISO8601', v => ISO8601_RE.test(v), (varName, ctx) => {
|
|
578
|
-
const i = ctx.addRegex(ISO8601_RE);
|
|
579
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isISO8601')};`;
|
|
580
|
-
}, 'string', { format: 'date-time', strict: false });
|
|
581
|
-
}
|
|
582
|
-
// ISRC — ISO 3901
|
|
583
|
-
const ISRC_RE = /^[A-Z]{2}-[A-Z0-9]{3}-\d{2}-\d{5}$|^[A-Z]{2}[A-Z0-9]{3}\d{7}$/;
|
|
584
|
-
const isISRC = makeStringRule('isISRC', v => ISRC_RE.test(v), (varName, ctx) => {
|
|
585
|
-
const i = ctx.addRegex(ISRC_RE);
|
|
586
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isISRC')};`;
|
|
587
|
-
});
|
|
588
|
-
function validateISSN(value, options) {
|
|
589
|
-
const requireHyphen = options?.requireHyphen !== false;
|
|
590
|
-
const s = requireHyphen ? value : value.replace(/-/g, '');
|
|
591
|
-
// Format with hyphen: NNNN-NNNX, without: NNNNNNXX
|
|
592
|
-
const re = requireHyphen ? /^\d{4}-\d{3}[\dX]$/ : /^\d{7}[\dX]$/;
|
|
593
|
-
if (!re.test(s)) {
|
|
594
|
-
return false;
|
|
595
|
-
}
|
|
596
|
-
const digits = s.replace(/-/g, '');
|
|
597
|
-
let sum = 0;
|
|
598
|
-
for (let i = 0; i < 7; i++) {
|
|
599
|
-
sum += (8 - i) * (digits.charCodeAt(i) - 48);
|
|
600
|
-
}
|
|
601
|
-
const last = digits[7] === 'X' ? 10 : digits.charCodeAt(7) - 48;
|
|
602
|
-
sum += last;
|
|
603
|
-
return sum % 11 === 0;
|
|
604
|
-
}
|
|
605
|
-
function isISSN(options) {
|
|
606
|
-
const requireHyphen = options?.requireHyphen !== false;
|
|
607
|
-
const validateIssn = (value) => typeof value === 'string' && validateISSN(value, options);
|
|
608
|
-
const formatRe = requireHyphen ? /^\d{4}-\d{3}[\dX]$/ : /^\d{7}[\dX]$/;
|
|
609
|
-
return makeRule({
|
|
610
|
-
name: 'isISSN',
|
|
611
|
-
requiresType: 'string',
|
|
612
|
-
constraints: { requireHyphen: options?.requireHyphen },
|
|
613
|
-
validate: validateIssn,
|
|
614
|
-
emit: (varName, ctx) => {
|
|
615
|
-
const ri = ctx.addRegex(formatRe);
|
|
616
|
-
const strip = requireHyphen ? varName : `${varName}.replace(/-/g,'')`;
|
|
617
|
-
return (`{var issn=${strip};` +
|
|
618
|
-
`if(!re[${ri}].test(issn)){${ctx.fail('isISSN')}}` +
|
|
619
|
-
`else{var id=issn.replace(/-/g,''),iss=0;` +
|
|
620
|
-
`for(var ii=0;ii<7;ii++)iss+=(8-ii)*(id.charCodeAt(ii)-48);` +
|
|
621
|
-
`var il=id[7]==='X'?10:(id.charCodeAt(7)-48);iss+=il;` +
|
|
622
|
-
`if(iss%11!==0)${ctx.fail('isISSN')};}}`);
|
|
623
|
-
},
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
// JWT — 3-part dot-separated base64url
|
|
627
|
-
const JWT_RE = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
|
|
628
|
-
const isJWT = makeStringRule('isJWT', v => JWT_RE.test(v), (varName, ctx) => {
|
|
629
|
-
const i = ctx.addRegex(JWT_RE);
|
|
630
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isJWT')};`;
|
|
631
|
-
});
|
|
632
|
-
// LatLong
|
|
633
|
-
const LAT_LONG_RE = /^[-+]?([1-8]?\d(?:\.\d+)?|90(?:\.0+)?),\s*[-+]?(180(?:\.0+)?|1[0-7]\d(?:\.\d+)?|\d{1,2}(?:\.\d+)?)$/;
|
|
634
|
-
function isLatLong() {
|
|
635
|
-
return makeStringRule('isLatLong', v => LAT_LONG_RE.test(v), (varName, ctx) => {
|
|
636
|
-
const i = ctx.addRegex(LAT_LONG_RE);
|
|
637
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isLatLong')};`;
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
// Locale — BCP 47 simplified
|
|
641
|
-
const LOCALE_RE = /^[a-zA-Z]{2,3}(?:-[a-zA-Z]{4})?(?:-(?:[a-zA-Z]{2}|\d{3}))?(?:-[a-zA-Z\d]{5,8})*$/;
|
|
642
|
-
const isLocale = makeStringRule('isLocale', v => LOCALE_RE.test(v), (varName, ctx) => {
|
|
643
|
-
const i = ctx.addRegex(LOCALE_RE);
|
|
644
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isLocale')};`;
|
|
645
|
-
});
|
|
646
|
-
// DataURI
|
|
647
|
-
const DATA_URI_RE = /^data:([a-zA-Z0-9!#$&\-^_]+\/[a-zA-Z0-9!#$&\-^_]+)(?:;[a-zA-Z0-9-]+=[a-zA-Z0-9-]+)*(?:;base64)?,[\s\S]*$/;
|
|
648
|
-
const isDataURI = makeStringRule('isDataURI', v => DATA_URI_RE.test(v), (varName, ctx) => {
|
|
649
|
-
const i = ctx.addRegex(DATA_URI_RE);
|
|
650
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isDataURI')};`;
|
|
651
|
-
});
|
|
652
|
-
function isFQDN(options) {
|
|
653
|
-
const requireTld = options?.require_tld !== false;
|
|
654
|
-
const allowUnderscores = options?.allow_underscores ?? false;
|
|
655
|
-
const allowTrailingDot = options?.allow_trailing_dot ?? false;
|
|
656
|
-
const partRe = allowUnderscores ? /^[a-zA-Z0-9_-]+$/ : /^[a-zA-Z0-9-]+$/;
|
|
657
|
-
const validateFqdn = (value) => {
|
|
658
|
-
if (typeof value !== 'string') {
|
|
659
|
-
return false;
|
|
660
|
-
}
|
|
661
|
-
let str = value;
|
|
662
|
-
if (allowTrailingDot && str.endsWith('.')) {
|
|
663
|
-
str = str.slice(0, -1);
|
|
664
|
-
}
|
|
665
|
-
if (str.length === 0) {
|
|
666
|
-
return false;
|
|
667
|
-
}
|
|
668
|
-
const parts = str.split('.');
|
|
669
|
-
if (requireTld && parts.length < 2) {
|
|
670
|
-
return false;
|
|
671
|
-
}
|
|
672
|
-
if (requireTld) {
|
|
673
|
-
const tld = parts[parts.length - 1];
|
|
674
|
-
if (!tld || tld.length < 2 || !/^[a-zA-Z]{2,}$/.test(tld)) {
|
|
675
|
-
return false;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
return parts.every(part => {
|
|
679
|
-
if (part.length === 0 || part.length > 63) {
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
if (!partRe.test(part)) {
|
|
683
|
-
return false;
|
|
684
|
-
}
|
|
685
|
-
if (!allowUnderscores && (part.startsWith('-') || part.endsWith('-'))) {
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
return true;
|
|
689
|
-
});
|
|
690
|
-
};
|
|
691
|
-
return makeRule({
|
|
692
|
-
name: 'isFQDN',
|
|
693
|
-
requiresType: 'string',
|
|
694
|
-
constraints: {
|
|
695
|
-
require_tld: options?.require_tld,
|
|
696
|
-
allow_underscores: options?.allow_underscores,
|
|
697
|
-
allow_trailing_dot: options?.allow_trailing_dot,
|
|
698
|
-
},
|
|
699
|
-
validate: validateFqdn,
|
|
700
|
-
emit: (varName, ctx) => {
|
|
701
|
-
const ri = ctx.addRegex(partRe);
|
|
702
|
-
const tldRi = requireTld ? ctx.addRegex(/^[a-zA-Z]{2,}$/) : -1;
|
|
703
|
-
// Inline for-loop instead of fp.every(function(p){...}) — avoids per-call closure
|
|
704
|
-
// allocation inside the JIT executor.
|
|
705
|
-
const partCheck = `if(p.length===0||p.length>63){fqOk=false;break;}` +
|
|
706
|
-
`if(!re[${ri}].test(p)){fqOk=false;break;}` +
|
|
707
|
-
(allowUnderscores ? '' : `if(p[0]==='-'||p[p.length-1]==='-'){fqOk=false;break;}`);
|
|
708
|
-
const loopBlock = `var fqOk=true;for(var fi=0;fi<fp.length;fi++){var p=fp[fi];${partCheck}}if(!fqOk)${ctx.fail('isFQDN')};`;
|
|
709
|
-
let code = `{var fq=${varName};`;
|
|
710
|
-
if (allowTrailingDot) {
|
|
711
|
-
code += `if(fq.endsWith('.'))fq=fq.slice(0,-1);`;
|
|
712
|
-
}
|
|
713
|
-
code += `if(fq.length===0)${ctx.fail('isFQDN')};`;
|
|
714
|
-
code += `else{var fp=fq.split('.');`;
|
|
715
|
-
if (requireTld) {
|
|
716
|
-
code += `if(fp.length<2)${ctx.fail('isFQDN')};`;
|
|
717
|
-
code += `else{var tld=fp[fp.length-1];`;
|
|
718
|
-
code += `if(!tld||tld.length<2||!re[${tldRi}].test(tld))${ctx.fail('isFQDN')};`;
|
|
719
|
-
code += `else{${loopBlock}}`; // close tld inner else block
|
|
720
|
-
code += '}'; // close tld outer else block
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
code += loopBlock;
|
|
724
|
-
}
|
|
725
|
-
code += '}'; // close split else{
|
|
726
|
-
code += '}'; // close outer {
|
|
727
|
-
return code;
|
|
728
|
-
},
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
// Port — 0 to 65535
|
|
732
|
-
const PORT_RE = /^(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{1,3}|\d)$/;
|
|
733
|
-
const isPort = makeStringRule('isPort', v => PORT_RE.test(v), (varName, ctx) => {
|
|
734
|
-
const i = ctx.addRegex(PORT_RE);
|
|
735
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isPort')};`;
|
|
736
|
-
});
|
|
737
|
-
// EAN (EAN-8 and EAN-13 with checksum)
|
|
738
|
-
function validateEAN(value) {
|
|
739
|
-
if (!/^\d{8}$/.test(value) && !/^\d{13}$/.test(value)) {
|
|
740
|
-
return false;
|
|
741
|
-
}
|
|
742
|
-
// Walk via charCodeAt — no split/map array allocations
|
|
743
|
-
const len = value.length;
|
|
744
|
-
let sum = 0;
|
|
745
|
-
for (let i = 0; i < len - 1; i++) {
|
|
746
|
-
const d = value.charCodeAt(i) - 48;
|
|
747
|
-
sum += d * (len === 8 ? (i % 2 === 0 ? 3 : 1) : i % 2 === 0 ? 1 : 3);
|
|
748
|
-
}
|
|
749
|
-
const check = (10 - (sum % 10)) % 10;
|
|
750
|
-
return check === value.charCodeAt(len - 1) - 48;
|
|
751
|
-
}
|
|
752
|
-
const isEAN = makeStringRule('isEAN', validateEAN, (varName, ctx) => {
|
|
753
|
-
const re8 = ctx.addRegex(/^\d{8}$/);
|
|
754
|
-
const re13 = ctx.addRegex(/^\d{13}$/);
|
|
755
|
-
return (`{var ev=${varName};` +
|
|
756
|
-
`if(!re[${re8}].test(ev)&&!re[${re13}].test(ev)){${ctx.fail('isEAN')}}` +
|
|
757
|
-
`else{var el=ev.length,es=0;` +
|
|
758
|
-
`for(var ei=0;ei<el-1;ei++){var ed=ev.charCodeAt(ei)-48;es+=ed*(el===8?(ei%2===0?3:1):(ei%2===0?1:3));}` +
|
|
759
|
-
`var ec=(10-(es%10))%10;` +
|
|
760
|
-
`if(ec!==(ev.charCodeAt(el-1)-48))${ctx.fail('isEAN')};}}`);
|
|
761
|
-
});
|
|
762
|
-
// ISO 3166-1 Alpha-2
|
|
763
|
-
const ISO31661A2_CODES = new Set([
|
|
764
|
-
'AD',
|
|
765
|
-
'AE',
|
|
766
|
-
'AF',
|
|
767
|
-
'AG',
|
|
768
|
-
'AI',
|
|
769
|
-
'AL',
|
|
770
|
-
'AM',
|
|
771
|
-
'AO',
|
|
772
|
-
'AQ',
|
|
773
|
-
'AR',
|
|
774
|
-
'AS',
|
|
775
|
-
'AT',
|
|
776
|
-
'AU',
|
|
777
|
-
'AW',
|
|
778
|
-
'AX',
|
|
779
|
-
'AZ',
|
|
780
|
-
'BA',
|
|
781
|
-
'BB',
|
|
782
|
-
'BD',
|
|
783
|
-
'BE',
|
|
784
|
-
'BF',
|
|
785
|
-
'BG',
|
|
786
|
-
'BH',
|
|
787
|
-
'BI',
|
|
788
|
-
'BJ',
|
|
789
|
-
'BL',
|
|
790
|
-
'BM',
|
|
791
|
-
'BN',
|
|
792
|
-
'BO',
|
|
793
|
-
'BQ',
|
|
794
|
-
'BR',
|
|
795
|
-
'BS',
|
|
796
|
-
'BT',
|
|
797
|
-
'BV',
|
|
798
|
-
'BW',
|
|
799
|
-
'BY',
|
|
800
|
-
'BZ',
|
|
801
|
-
'CA',
|
|
802
|
-
'CC',
|
|
803
|
-
'CD',
|
|
804
|
-
'CF',
|
|
805
|
-
'CG',
|
|
806
|
-
'CH',
|
|
807
|
-
'CI',
|
|
808
|
-
'CK',
|
|
809
|
-
'CL',
|
|
810
|
-
'CM',
|
|
811
|
-
'CN',
|
|
812
|
-
'CO',
|
|
813
|
-
'CR',
|
|
814
|
-
'CU',
|
|
815
|
-
'CV',
|
|
816
|
-
'CW',
|
|
817
|
-
'CX',
|
|
818
|
-
'CY',
|
|
819
|
-
'CZ',
|
|
820
|
-
'DE',
|
|
821
|
-
'DJ',
|
|
822
|
-
'DK',
|
|
823
|
-
'DM',
|
|
824
|
-
'DO',
|
|
825
|
-
'DZ',
|
|
826
|
-
'EC',
|
|
827
|
-
'EE',
|
|
828
|
-
'EG',
|
|
829
|
-
'EH',
|
|
830
|
-
'ER',
|
|
831
|
-
'ES',
|
|
832
|
-
'ET',
|
|
833
|
-
'FI',
|
|
834
|
-
'FJ',
|
|
835
|
-
'FK',
|
|
836
|
-
'FM',
|
|
837
|
-
'FO',
|
|
838
|
-
'FR',
|
|
839
|
-
'GA',
|
|
840
|
-
'GB',
|
|
841
|
-
'GD',
|
|
842
|
-
'GE',
|
|
843
|
-
'GF',
|
|
844
|
-
'GG',
|
|
845
|
-
'GH',
|
|
846
|
-
'GI',
|
|
847
|
-
'GL',
|
|
848
|
-
'GM',
|
|
849
|
-
'GN',
|
|
850
|
-
'GP',
|
|
851
|
-
'GQ',
|
|
852
|
-
'GR',
|
|
853
|
-
'GS',
|
|
854
|
-
'GT',
|
|
855
|
-
'GU',
|
|
856
|
-
'GW',
|
|
857
|
-
'GY',
|
|
858
|
-
'HK',
|
|
859
|
-
'HM',
|
|
860
|
-
'HN',
|
|
861
|
-
'HR',
|
|
862
|
-
'HT',
|
|
863
|
-
'HU',
|
|
864
|
-
'ID',
|
|
865
|
-
'IE',
|
|
866
|
-
'IL',
|
|
867
|
-
'IM',
|
|
868
|
-
'IN',
|
|
869
|
-
'IO',
|
|
870
|
-
'IQ',
|
|
871
|
-
'IR',
|
|
872
|
-
'IS',
|
|
873
|
-
'IT',
|
|
874
|
-
'JE',
|
|
875
|
-
'JM',
|
|
876
|
-
'JO',
|
|
877
|
-
'JP',
|
|
878
|
-
'KE',
|
|
879
|
-
'KG',
|
|
880
|
-
'KH',
|
|
881
|
-
'KI',
|
|
882
|
-
'KM',
|
|
883
|
-
'KN',
|
|
884
|
-
'KP',
|
|
885
|
-
'KR',
|
|
886
|
-
'KW',
|
|
887
|
-
'KY',
|
|
888
|
-
'KZ',
|
|
889
|
-
'LA',
|
|
890
|
-
'LB',
|
|
891
|
-
'LC',
|
|
892
|
-
'LI',
|
|
893
|
-
'LK',
|
|
894
|
-
'LR',
|
|
895
|
-
'LS',
|
|
896
|
-
'LT',
|
|
897
|
-
'LU',
|
|
898
|
-
'LV',
|
|
899
|
-
'LY',
|
|
900
|
-
'MA',
|
|
901
|
-
'MC',
|
|
902
|
-
'MD',
|
|
903
|
-
'ME',
|
|
904
|
-
'MF',
|
|
905
|
-
'MG',
|
|
906
|
-
'MH',
|
|
907
|
-
'MK',
|
|
908
|
-
'ML',
|
|
909
|
-
'MM',
|
|
910
|
-
'MN',
|
|
911
|
-
'MO',
|
|
912
|
-
'MP',
|
|
913
|
-
'MQ',
|
|
914
|
-
'MR',
|
|
915
|
-
'MS',
|
|
916
|
-
'MT',
|
|
917
|
-
'MU',
|
|
918
|
-
'MV',
|
|
919
|
-
'MW',
|
|
920
|
-
'MX',
|
|
921
|
-
'MY',
|
|
922
|
-
'MZ',
|
|
923
|
-
'NA',
|
|
924
|
-
'NC',
|
|
925
|
-
'NE',
|
|
926
|
-
'NF',
|
|
927
|
-
'NG',
|
|
928
|
-
'NI',
|
|
929
|
-
'NL',
|
|
930
|
-
'NO',
|
|
931
|
-
'NP',
|
|
932
|
-
'NR',
|
|
933
|
-
'NU',
|
|
934
|
-
'NZ',
|
|
935
|
-
'OM',
|
|
936
|
-
'PA',
|
|
937
|
-
'PE',
|
|
938
|
-
'PF',
|
|
939
|
-
'PG',
|
|
940
|
-
'PH',
|
|
941
|
-
'PK',
|
|
942
|
-
'PL',
|
|
943
|
-
'PM',
|
|
944
|
-
'PN',
|
|
945
|
-
'PR',
|
|
946
|
-
'PS',
|
|
947
|
-
'PT',
|
|
948
|
-
'PW',
|
|
949
|
-
'PY',
|
|
950
|
-
'QA',
|
|
951
|
-
'RE',
|
|
952
|
-
'RO',
|
|
953
|
-
'RS',
|
|
954
|
-
'RU',
|
|
955
|
-
'RW',
|
|
956
|
-
'SA',
|
|
957
|
-
'SB',
|
|
958
|
-
'SC',
|
|
959
|
-
'SD',
|
|
960
|
-
'SE',
|
|
961
|
-
'SG',
|
|
962
|
-
'SH',
|
|
963
|
-
'SI',
|
|
964
|
-
'SJ',
|
|
965
|
-
'SK',
|
|
966
|
-
'SL',
|
|
967
|
-
'SM',
|
|
968
|
-
'SN',
|
|
969
|
-
'SO',
|
|
970
|
-
'SR',
|
|
971
|
-
'SS',
|
|
972
|
-
'ST',
|
|
973
|
-
'SV',
|
|
974
|
-
'SX',
|
|
975
|
-
'SY',
|
|
976
|
-
'SZ',
|
|
977
|
-
'TC',
|
|
978
|
-
'TD',
|
|
979
|
-
'TF',
|
|
980
|
-
'TG',
|
|
981
|
-
'TH',
|
|
982
|
-
'TJ',
|
|
983
|
-
'TK',
|
|
984
|
-
'TL',
|
|
985
|
-
'TM',
|
|
986
|
-
'TN',
|
|
987
|
-
'TO',
|
|
988
|
-
'TR',
|
|
989
|
-
'TT',
|
|
990
|
-
'TV',
|
|
991
|
-
'TW',
|
|
992
|
-
'TZ',
|
|
993
|
-
'UA',
|
|
994
|
-
'UG',
|
|
995
|
-
'UM',
|
|
996
|
-
'US',
|
|
997
|
-
'UY',
|
|
998
|
-
'UZ',
|
|
999
|
-
'VA',
|
|
1000
|
-
'VC',
|
|
1001
|
-
'VE',
|
|
1002
|
-
'VG',
|
|
1003
|
-
'VI',
|
|
1004
|
-
'VN',
|
|
1005
|
-
'VU',
|
|
1006
|
-
'WF',
|
|
1007
|
-
'WS',
|
|
1008
|
-
'YE',
|
|
1009
|
-
'YT',
|
|
1010
|
-
'ZA',
|
|
1011
|
-
'ZM',
|
|
1012
|
-
'ZW',
|
|
1013
|
-
]);
|
|
1014
|
-
const isISO31661Alpha2 = makeRule({
|
|
1015
|
-
name: 'isISO31661Alpha2',
|
|
1016
|
-
requiresType: 'string',
|
|
1017
|
-
constraints: {},
|
|
1018
|
-
validate: value => typeof value === 'string' && ISO31661A2_CODES.has(value.toUpperCase()),
|
|
1019
|
-
emit: (varName, ctx) => {
|
|
1020
|
-
const i = ctx.addRef(ISO31661A2_CODES);
|
|
1021
|
-
return `if (!refs[${i}].has(${varName}.toUpperCase())) ${ctx.fail('isISO31661Alpha2')};`;
|
|
1022
|
-
},
|
|
1023
|
-
});
|
|
1024
|
-
// ISO 3166-1 Alpha-3
|
|
1025
|
-
const ISO31661A3_CODES = new Set([
|
|
1026
|
-
'ABW',
|
|
1027
|
-
'AFG',
|
|
1028
|
-
'AGO',
|
|
1029
|
-
'AIA',
|
|
1030
|
-
'ALA',
|
|
1031
|
-
'ALB',
|
|
1032
|
-
'AND',
|
|
1033
|
-
'ANT',
|
|
1034
|
-
'ARE',
|
|
1035
|
-
'ARG',
|
|
1036
|
-
'ARM',
|
|
1037
|
-
'ASM',
|
|
1038
|
-
'ATA',
|
|
1039
|
-
'ATF',
|
|
1040
|
-
'ATG',
|
|
1041
|
-
'AUS',
|
|
1042
|
-
'AUT',
|
|
1043
|
-
'AZE',
|
|
1044
|
-
'BDI',
|
|
1045
|
-
'BEL',
|
|
1046
|
-
'BEN',
|
|
1047
|
-
'BES',
|
|
1048
|
-
'BFA',
|
|
1049
|
-
'BGD',
|
|
1050
|
-
'BGR',
|
|
1051
|
-
'BHR',
|
|
1052
|
-
'BHS',
|
|
1053
|
-
'BIH',
|
|
1054
|
-
'BLM',
|
|
1055
|
-
'BLR',
|
|
1056
|
-
'BLZ',
|
|
1057
|
-
'BMU',
|
|
1058
|
-
'BOL',
|
|
1059
|
-
'BRA',
|
|
1060
|
-
'BRB',
|
|
1061
|
-
'BRN',
|
|
1062
|
-
'BTN',
|
|
1063
|
-
'BVT',
|
|
1064
|
-
'BWA',
|
|
1065
|
-
'CAF',
|
|
1066
|
-
'CAN',
|
|
1067
|
-
'CCK',
|
|
1068
|
-
'CHE',
|
|
1069
|
-
'CHL',
|
|
1070
|
-
'CHN',
|
|
1071
|
-
'CIV',
|
|
1072
|
-
'CMR',
|
|
1073
|
-
'COD',
|
|
1074
|
-
'COG',
|
|
1075
|
-
'COK',
|
|
1076
|
-
'COL',
|
|
1077
|
-
'COM',
|
|
1078
|
-
'CPV',
|
|
1079
|
-
'CRI',
|
|
1080
|
-
'CUB',
|
|
1081
|
-
'CUW',
|
|
1082
|
-
'CXR',
|
|
1083
|
-
'CYM',
|
|
1084
|
-
'CYP',
|
|
1085
|
-
'CZE',
|
|
1086
|
-
'DEU',
|
|
1087
|
-
'DJI',
|
|
1088
|
-
'DMA',
|
|
1089
|
-
'DNK',
|
|
1090
|
-
'DOM',
|
|
1091
|
-
'DZA',
|
|
1092
|
-
'ECU',
|
|
1093
|
-
'EGY',
|
|
1094
|
-
'ERI',
|
|
1095
|
-
'ESH',
|
|
1096
|
-
'ESP',
|
|
1097
|
-
'EST',
|
|
1098
|
-
'ETH',
|
|
1099
|
-
'FIN',
|
|
1100
|
-
'FJI',
|
|
1101
|
-
'FLK',
|
|
1102
|
-
'FRA',
|
|
1103
|
-
'FRO',
|
|
1104
|
-
'FSM',
|
|
1105
|
-
'GAB',
|
|
1106
|
-
'GBR',
|
|
1107
|
-
'GEO',
|
|
1108
|
-
'GGY',
|
|
1109
|
-
'GHA',
|
|
1110
|
-
'GIB',
|
|
1111
|
-
'GIN',
|
|
1112
|
-
'GLP',
|
|
1113
|
-
'GMB',
|
|
1114
|
-
'GNB',
|
|
1115
|
-
'GNQ',
|
|
1116
|
-
'GRC',
|
|
1117
|
-
'GRD',
|
|
1118
|
-
'GRL',
|
|
1119
|
-
'GTM',
|
|
1120
|
-
'GUF',
|
|
1121
|
-
'GUM',
|
|
1122
|
-
'GUY',
|
|
1123
|
-
'HKG',
|
|
1124
|
-
'HMD',
|
|
1125
|
-
'HND',
|
|
1126
|
-
'HRV',
|
|
1127
|
-
'HTI',
|
|
1128
|
-
'HUN',
|
|
1129
|
-
'IDN',
|
|
1130
|
-
'IMN',
|
|
1131
|
-
'IND',
|
|
1132
|
-
'IOT',
|
|
1133
|
-
'IRL',
|
|
1134
|
-
'IRN',
|
|
1135
|
-
'IRQ',
|
|
1136
|
-
'ISL',
|
|
1137
|
-
'ISR',
|
|
1138
|
-
'ITA',
|
|
1139
|
-
'JAM',
|
|
1140
|
-
'JEY',
|
|
1141
|
-
'JOR',
|
|
1142
|
-
'JPN',
|
|
1143
|
-
'KAZ',
|
|
1144
|
-
'KEN',
|
|
1145
|
-
'KGZ',
|
|
1146
|
-
'KHM',
|
|
1147
|
-
'KIR',
|
|
1148
|
-
'KNA',
|
|
1149
|
-
'KOR',
|
|
1150
|
-
'KWT',
|
|
1151
|
-
'LAO',
|
|
1152
|
-
'LBN',
|
|
1153
|
-
'LBR',
|
|
1154
|
-
'LBY',
|
|
1155
|
-
'LCA',
|
|
1156
|
-
'LIE',
|
|
1157
|
-
'LKA',
|
|
1158
|
-
'LSO',
|
|
1159
|
-
'LTU',
|
|
1160
|
-
'LUX',
|
|
1161
|
-
'LVA',
|
|
1162
|
-
'MAC',
|
|
1163
|
-
'MAF',
|
|
1164
|
-
'MAR',
|
|
1165
|
-
'MCO',
|
|
1166
|
-
'MDA',
|
|
1167
|
-
'MDG',
|
|
1168
|
-
'MDV',
|
|
1169
|
-
'MEX',
|
|
1170
|
-
'MHL',
|
|
1171
|
-
'MKD',
|
|
1172
|
-
'MLI',
|
|
1173
|
-
'MLT',
|
|
1174
|
-
'MMR',
|
|
1175
|
-
'MNE',
|
|
1176
|
-
'MNG',
|
|
1177
|
-
'MNP',
|
|
1178
|
-
'MOZ',
|
|
1179
|
-
'MRT',
|
|
1180
|
-
'MSR',
|
|
1181
|
-
'MTQ',
|
|
1182
|
-
'MUS',
|
|
1183
|
-
'MWI',
|
|
1184
|
-
'MYS',
|
|
1185
|
-
'MYT',
|
|
1186
|
-
'NAM',
|
|
1187
|
-
'NCL',
|
|
1188
|
-
'NER',
|
|
1189
|
-
'NFK',
|
|
1190
|
-
'NGA',
|
|
1191
|
-
'NIC',
|
|
1192
|
-
'NIU',
|
|
1193
|
-
'NLD',
|
|
1194
|
-
'NOR',
|
|
1195
|
-
'NPL',
|
|
1196
|
-
'NRU',
|
|
1197
|
-
'NZL',
|
|
1198
|
-
'OMN',
|
|
1199
|
-
'PAK',
|
|
1200
|
-
'PAN',
|
|
1201
|
-
'PCN',
|
|
1202
|
-
'PER',
|
|
1203
|
-
'PHL',
|
|
1204
|
-
'PLW',
|
|
1205
|
-
'PNG',
|
|
1206
|
-
'POL',
|
|
1207
|
-
'PRI',
|
|
1208
|
-
'PRK',
|
|
1209
|
-
'PRT',
|
|
1210
|
-
'PRY',
|
|
1211
|
-
'PSE',
|
|
1212
|
-
'PYF',
|
|
1213
|
-
'QAT',
|
|
1214
|
-
'REU',
|
|
1215
|
-
'ROU',
|
|
1216
|
-
'RUS',
|
|
1217
|
-
'RWA',
|
|
1218
|
-
'SAU',
|
|
1219
|
-
'SDN',
|
|
1220
|
-
'SEN',
|
|
1221
|
-
'SGP',
|
|
1222
|
-
'SGS',
|
|
1223
|
-
'SHN',
|
|
1224
|
-
'SJM',
|
|
1225
|
-
'SLB',
|
|
1226
|
-
'SLE',
|
|
1227
|
-
'SLV',
|
|
1228
|
-
'SMR',
|
|
1229
|
-
'SOM',
|
|
1230
|
-
'SPM',
|
|
1231
|
-
'SRB',
|
|
1232
|
-
'SSD',
|
|
1233
|
-
'STP',
|
|
1234
|
-
'SUR',
|
|
1235
|
-
'SVK',
|
|
1236
|
-
'SVN',
|
|
1237
|
-
'SWE',
|
|
1238
|
-
'SWZ',
|
|
1239
|
-
'SXM',
|
|
1240
|
-
'SYC',
|
|
1241
|
-
'SYR',
|
|
1242
|
-
'TCA',
|
|
1243
|
-
'TCD',
|
|
1244
|
-
'TGO',
|
|
1245
|
-
'THA',
|
|
1246
|
-
'TJK',
|
|
1247
|
-
'TKL',
|
|
1248
|
-
'TKM',
|
|
1249
|
-
'TLS',
|
|
1250
|
-
'TON',
|
|
1251
|
-
'TTO',
|
|
1252
|
-
'TUN',
|
|
1253
|
-
'TUR',
|
|
1254
|
-
'TUV',
|
|
1255
|
-
'TWN',
|
|
1256
|
-
'TZA',
|
|
1257
|
-
'UGA',
|
|
1258
|
-
'UKR',
|
|
1259
|
-
'UMI',
|
|
1260
|
-
'URY',
|
|
1261
|
-
'USA',
|
|
1262
|
-
'UZB',
|
|
1263
|
-
'VAT',
|
|
1264
|
-
'VCT',
|
|
1265
|
-
'VEN',
|
|
1266
|
-
'VGB',
|
|
1267
|
-
'VIR',
|
|
1268
|
-
'VNM',
|
|
1269
|
-
'VUT',
|
|
1270
|
-
'WLF',
|
|
1271
|
-
'WSM',
|
|
1272
|
-
'YEM',
|
|
1273
|
-
'ZAF',
|
|
1274
|
-
'ZMB',
|
|
1275
|
-
'ZWE',
|
|
1276
|
-
]);
|
|
1277
|
-
const isISO31661Alpha3 = makeRule({
|
|
1278
|
-
name: 'isISO31661Alpha3',
|
|
1279
|
-
requiresType: 'string',
|
|
1280
|
-
constraints: {},
|
|
1281
|
-
validate: value => typeof value === 'string' && ISO31661A3_CODES.has(value.toUpperCase()),
|
|
1282
|
-
emit: (varName, ctx) => {
|
|
1283
|
-
const i = ctx.addRef(ISO31661A3_CODES);
|
|
1284
|
-
return `if (!refs[${i}].has(${varName}.toUpperCase())) ${ctx.fail('isISO31661Alpha3')};`;
|
|
1285
|
-
},
|
|
1286
|
-
});
|
|
1287
|
-
// BIC / SWIFT code — case-insensitive via /i flag avoids per-call .toUpperCase() string allocation
|
|
1288
|
-
const BIC_RE = /^[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$/i;
|
|
1289
|
-
const isBIC = makeStringRule('isBIC', v => BIC_RE.test(v), (varName, ctx) => {
|
|
1290
|
-
const i = ctx.addRegex(BIC_RE);
|
|
1291
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isBIC')};`;
|
|
1292
|
-
});
|
|
1293
|
-
// Firebase Push ID — 20 chars, base64url charset (-0-9A-Za-z_)
|
|
1294
|
-
const FIREBASE_RE = /^[a-zA-Z0-9_-]{20}$/;
|
|
1295
|
-
const isFirebasePushId = makeStringRule('isFirebasePushId', v => FIREBASE_RE.test(v), (varName, ctx) => {
|
|
1296
|
-
const i = ctx.addRegex(FIREBASE_RE);
|
|
1297
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isFirebasePushId')};`;
|
|
1298
|
-
});
|
|
1299
|
-
// SemVer — Semantic Versioning 2.0
|
|
1300
|
-
const SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
1301
|
-
const isSemVer = makeStringRule('isSemVer', v => SEMVER_RE.test(v), (varName, ctx) => {
|
|
1302
|
-
const i = ctx.addRegex(SEMVER_RE);
|
|
1303
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isSemVer')};`;
|
|
1304
|
-
});
|
|
1305
|
-
// MongoDB ObjectId — 24-char hex
|
|
1306
|
-
const MONGO_ID_RE = /^[0-9a-fA-F]{24}$/;
|
|
1307
|
-
const isMongoId = makeStringRule('isMongoId', v => MONGO_ID_RE.test(v), (varName, ctx) => {
|
|
1308
|
-
const i = ctx.addRegex(MONGO_ID_RE);
|
|
1309
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMongoId')};`;
|
|
1310
|
-
});
|
|
1311
|
-
// JSON
|
|
1312
|
-
const validateJsonString = (value) => {
|
|
1313
|
-
if (typeof value !== 'string') {
|
|
1314
|
-
return false;
|
|
1315
|
-
}
|
|
1316
|
-
try {
|
|
1317
|
-
JSON.parse(value);
|
|
1318
|
-
return true;
|
|
1319
|
-
}
|
|
1320
|
-
catch {
|
|
1321
|
-
return false;
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
const isJSON = makeRule({
|
|
1325
|
-
name: 'isJSON',
|
|
1326
|
-
requiresType: 'string',
|
|
1327
|
-
constraints: {},
|
|
1328
|
-
validate: validateJsonString,
|
|
1329
|
-
emit: (varName, ctx) => `try { JSON.parse(${varName}); } catch { ${ctx.fail('isJSON')}; }`,
|
|
1330
|
-
});
|
|
1331
|
-
// Base32
|
|
1332
|
-
const BASE32_RE = /^[A-Z2-7]+=*$/i;
|
|
1333
|
-
// Empty-string fails the `+`-quantified regex anyway, so the explicit length===0 check is dead.
|
|
1334
|
-
function isBase32() {
|
|
1335
|
-
return makeStringRule('isBase32', v => v.length % 8 === 0 && BASE32_RE.test(v), (varName, ctx) => {
|
|
1336
|
-
const i = ctx.addRegex(BASE32_RE);
|
|
1337
|
-
return `if (${varName}.length % 8 !== 0 || !re[${i}].test(${varName})) ${ctx.fail('isBase32')};`;
|
|
1338
|
-
});
|
|
1339
|
-
}
|
|
1340
|
-
// Base58
|
|
1341
|
-
const BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]+$/;
|
|
1342
|
-
const isBase58 = makeStringRule('isBase58', v => BASE58_RE.test(v), (varName, ctx) => {
|
|
1343
|
-
const i = ctx.addRegex(BASE58_RE);
|
|
1344
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isBase58')};`;
|
|
1345
|
-
});
|
|
1346
|
-
// Base64
|
|
1347
|
-
const BASE64_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;
|
|
1348
|
-
const BASE64_URL_RE = /^[A-Za-z0-9_-]+={0,2}$/;
|
|
1349
|
-
function isBase64(options) {
|
|
1350
|
-
const re = options?.urlSafe ? BASE64_URL_RE : BASE64_RE;
|
|
1351
|
-
// Empty-string check is redundant — both base64 regexes require ≥1 char and fail on empty input.
|
|
1352
|
-
return makeStringRule('isBase64', v => re.test(v), (varName, ctx) => {
|
|
1353
|
-
const i = ctx.addRegex(re);
|
|
1354
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isBase64')};`;
|
|
1355
|
-
}, 'string', { urlSafe: options?.urlSafe });
|
|
1356
|
-
}
|
|
1357
|
-
// DateString — ISO 8601 date only (YYYY-MM-DD) with calendar validity (day must exist in month/year).
|
|
1358
|
-
const DATE_STRING_RE = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
|
|
1359
|
-
function isCalendarValidDate(v) {
|
|
1360
|
-
if (!DATE_STRING_RE.test(v)) {
|
|
1361
|
-
return false;
|
|
1362
|
-
}
|
|
1363
|
-
const y = Number(v.slice(0, 4));
|
|
1364
|
-
const m = Number(v.slice(5, 7));
|
|
1365
|
-
const d = Number(v.slice(8, 10));
|
|
1366
|
-
const maxDay = new Date(y, m, 0).getDate();
|
|
1367
|
-
return d >= 1 && d <= maxDay;
|
|
1368
|
-
}
|
|
1369
|
-
function isDateString() {
|
|
1370
|
-
return makeStringRule('isDateString', isCalendarValidDate, (varName, ctx) => {
|
|
1371
|
-
const i = ctx.addRegex(DATE_STRING_RE);
|
|
1372
|
-
return (`if (!re[${i}].test(${varName})) ${ctx.fail('isDateString')};\n` +
|
|
1373
|
-
`else { var y=Number(${varName}.slice(0,4)),m=Number(${varName}.slice(5,7)),d=Number(${varName}.slice(8,10));` +
|
|
1374
|
-
`var md=new Date(y,m,0).getDate(); if(d<1||d>md)${ctx.fail('isDateString')}; }`);
|
|
1375
|
-
});
|
|
1376
|
-
}
|
|
1377
|
-
// MimeType
|
|
1378
|
-
const MIME_TYPE_RE = /^(application|audio|font|image|message|model|multipart|text|video)\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-^_.+]*(?:;.+)?$/;
|
|
1379
|
-
const isMimeType = makeStringRule('isMimeType', v => MIME_TYPE_RE.test(v), (varName, ctx) => {
|
|
1380
|
-
const i = ctx.addRegex(MIME_TYPE_RE);
|
|
1381
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMimeType')};`;
|
|
1382
|
-
});
|
|
1383
|
-
// Currency
|
|
1384
|
-
// A single optional sign, either before the `$` (`-$5`, `+5`) or after it (`$-5`, `$+5`) — never
|
|
1385
|
-
// both. The previous `[-+]?\$?-?` allowed two signs (e.g. `+-5`, `-$-5`).
|
|
1386
|
-
const CURRENCY_RE = /^(?:[-+]?\$?|\$[-+]?)(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d{1,2})?$/;
|
|
1387
|
-
function isCurrency() {
|
|
1388
|
-
// Currency regex requires at least one digit; empty input fails the regex by itself.
|
|
1389
|
-
return makeStringRule('isCurrency', v => CURRENCY_RE.test(v), (varName, ctx) => {
|
|
1390
|
-
const i = ctx.addRegex(CURRENCY_RE);
|
|
1391
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isCurrency')};`;
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
1394
|
-
// Magnet URI
|
|
1395
|
-
const MAGNET_URI_RE = /^magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32,40}(?:&[a-z][a-z0-9.]*=[^&\s]*)*$/i;
|
|
1396
|
-
const isMagnetURI = makeStringRule('isMagnetURI', v => MAGNET_URI_RE.test(v), (varName, ctx) => {
|
|
1397
|
-
const i = ctx.addRegex(MAGNET_URI_RE);
|
|
1398
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMagnetURI')};`;
|
|
1399
|
-
});
|
|
1400
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1401
|
-
// Group D: Algorithm-based
|
|
1402
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1403
|
-
// Credit Card — Luhn algorithm (§4.8 C)
|
|
1404
|
-
function luhn(str) {
|
|
1405
|
-
const s = str.replace(/[\s-]/g, '');
|
|
1406
|
-
if (s.length === 0 || !/^\d+$/.test(s)) {
|
|
1407
|
-
return false;
|
|
1408
|
-
}
|
|
1409
|
-
let sum = 0;
|
|
1410
|
-
let alternate = false;
|
|
1411
|
-
for (let i = s.length - 1; i >= 0; i--) {
|
|
1412
|
-
let n = s.charCodeAt(i) - 48;
|
|
1413
|
-
if (alternate) {
|
|
1414
|
-
n *= 2;
|
|
1415
|
-
if (n > 9) {
|
|
1416
|
-
n -= 9;
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
sum += n;
|
|
1420
|
-
alternate = !alternate;
|
|
1421
|
-
}
|
|
1422
|
-
return sum % 10 === 0;
|
|
1423
|
-
}
|
|
1424
|
-
const isCreditCard = makeRule({
|
|
1425
|
-
name: 'isCreditCard',
|
|
1426
|
-
requiresType: 'string',
|
|
1427
|
-
constraints: {},
|
|
1428
|
-
validate: value => typeof value === 'string' && luhn(value),
|
|
1429
|
-
emit: (varName, ctx) => `{
|
|
1430
|
-
var cs=${varName}.replace(/[\\s-]/g,'');
|
|
1431
|
-
if(cs.length===0||!/^\\d+$/.test(cs)){${ctx.fail('isCreditCard')}}
|
|
1
|
+
import{CacheKey as k,RequiredType as f,RuleOp as h}from"../enums.js";import{makePlannedRule as g,makeRule as W,planCompare as B,planLength as y,planOr as Cj}from"../rule-plan.js";function X(j,Z,$,z=f.String,Q={}){return W({name:j,requiresType:z,constraints:Q,validate:(K)=>typeof K==="string"&&Z(K),emit:$})}function minLength(j){const Z={cacheKey:k.Length,failure:B(y(),h.Lt,j)};return g({name:"minLength",requiresType:f.String,constraints:{min:j},plan:Z,validate:($)=>typeof $==="string"&&$.length>=j})}function maxLength(j){const Z={cacheKey:k.Length,failure:B(y(),h.Gt,j)};return g({name:"maxLength",requiresType:f.String,constraints:{max:j},plan:Z,validate:($)=>typeof $==="string"&&$.length<=j})}function length(j,Z){const $={cacheKey:k.Length,failure:Cj(B(y(),h.Lt,j),B(y(),h.Gt,Z))};return g({name:"length",requiresType:f.String,constraints:{min:j,max:Z},plan:$,validate:(z)=>typeof z==="string"&&z.length>=j&&z.length<=Z})}function contains(j){return W({name:"contains",requiresType:f.String,constraints:{seed:j},validate:(Z)=>typeof Z==="string"&&Z.includes(j),emit:(Z,$)=>{const z=$.addRef(j);return`if (!${Z}.includes(refs[${z}])) ${$.fail("contains")};`}})}function notContains(j){return W({name:"notContains",requiresType:f.String,constraints:{seed:j},validate:(Z)=>typeof Z==="string"&&!Z.includes(j),emit:(Z,$)=>{const z=$.addRef(j);return`if (${Z}.includes(refs[${z}])) ${$.fail("notContains")};`}})}function matches(j,Z){const $=j instanceof RegExp?j:new RegExp(j,Z);return W({name:"matches",requiresType:f.String,constraints:{pattern:$.source},validate:(z)=>typeof z==="string"&&$.test(z),emit:(z,Q)=>{return`if (!re[${Q.addRegex($)}].test(${z})) ${Q.fail("matches")};`}})}const isLowercase=W({name:"isLowercase",requiresType:f.String,constraints:{},validate:(j)=>typeof j==="string"&&j===j.toLowerCase(),emit:(j,Z)=>`if (${j} !== ${j}.toLowerCase()) ${Z.fail("isLowercase")};`});const isUppercase=W({name:"isUppercase",requiresType:f.String,constraints:{},validate:(j)=>typeof j==="string"&&j===j.toUpperCase(),emit:(j,Z)=>`if (${j} !== ${j}.toUpperCase()) ${Z.fail("isUppercase")};`});const L=new RegExp(`^[${String.fromCharCode(0)}-${String.fromCharCode(127)}]*$`);const isAscii=X("isAscii",(j)=>L.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(L)}].test(${j})) ${Z.fail("isAscii")};`});const I=/^[a-zA-Z]+$/;const isAlpha=X("isAlpha",(j)=>I.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(I)}].test(${j})) ${Z.fail("isAlpha")};`});const T=/^[a-zA-Z0-9]+$/;const isAlphanumeric=X("isAlphanumeric",(j)=>T.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(T)}].test(${j})) ${Z.fail("isAlphanumeric")};`});const S=/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;const isHttpToken=X("isHttpToken",(j)=>S.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(S)}].test(${j})) ${Z.fail("isHttpToken")};`});const A=(j)=>{if(j==="null")return!0;try{return new URL(j).origin===j}catch{return!1}};const isOrigin=W({name:"isOrigin",requiresType:f.String,constraints:{format:"origin"},validate:(j)=>typeof j==="string"&&A(j),emit:(j,Z)=>{return`if (!(refs[${Z.addRef(A)}](${j}))) ${Z.fail("isOrigin")};`}});const d=(j)=>j==="*"||A(j);const isCorsOrigin=W({name:"isCorsOrigin",requiresType:f.String,constraints:{format:"origin",allowWildcard:!0},validate:(j)=>typeof j==="string"&&d(j),emit:(j,Z)=>{return`if (!(refs[${Z.addRef(d)}](${j}))) ${Z.fail("isCorsOrigin")};`}});const isBooleanString=W({name:"isBooleanString",requiresType:f.String,constraints:{},validate:(j)=>j==="true"||j==="false"||j==="1"||j==="0",emit:(j,Z)=>`if (${j} !== 'true' && ${j} !== 'false' && ${j} !== '1' && ${j} !== '0') ${Z.fail("isBooleanString")};`});const Aj=/^[0-9]+$/;const kj=/^[+-]?(?:[0-9]*\.)?[0-9]+$/;function isNumberString(j){const Z=j?.no_symbols??!1,$=Z?Aj:kj;return X("isNumberString",(z)=>$.test(z),(z,Q)=>{return`if (!re[${Q.addRegex($)}].test(${z})) ${Q.fail("isNumberString")};`},f.String,{no_symbols:Z})}function isDecimal(){const j=/^[-+]?(?:\d+(?:\.\d+)?|\.\d+)$/;return X("isDecimal",(Z)=>j.test(Z),(Z,$)=>{return`if (!re[${$.addRegex(j)}].test(${Z})) ${$.fail("isDecimal")};`})}const O=/[^\u0020-\u007E\uFF61-\uFF9F]/;const isFullWidth=X("isFullWidth",(j)=>O.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(O)}].test(${j})) ${Z.fail("isFullWidth")};`});const C=/[\u0020-\u007E\uFF61-\uFF9F]/;const isHalfWidth=X("isHalfWidth",(j)=>C.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(C)}].test(${j})) ${Z.fail("isHalfWidth")};`});const isVariableWidth=X("isVariableWidth",(j)=>O.test(j)&&C.test(j),(j,Z)=>{const $=Z.addRegex(O),z=Z.addRegex(C);return`if (!re[${$}].test(${j}) || !re[${z}].test(${j})) ${Z.fail("isVariableWidth")};`});const p=new RegExp(`[^${String.fromCharCode(0)}-${String.fromCharCode(255)}]`);const isMultibyte=X("isMultibyte",(j)=>p.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(p)}].test(${j})) ${Z.fail("isMultibyte")};`});const _=/[\uD800-\uDBFF][\uDC00-\uDFFF]/;const isSurrogatePair=X("isSurrogatePair",(j)=>_.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(_)}].test(${j})) ${Z.fail("isSurrogatePair")};`});const E=/^[0-9a-fA-F]+$/;const isHexadecimal=X("isHexadecimal",(j)=>E.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(E)}].test(${j})) ${Z.fail("isHexadecimal")};`});const o=/^(0[oO])?[0-7]+$/;const isOctal=X("isOctal",(j)=>o.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(o)}].test(${j})) ${Z.fail("isOctal")};`});const N=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/;function isEmail(){return X("isEmail",(j)=>N.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(N)}].test(${j})) ${Z.fail("isEmail")};`},f.String,{format:"email"})}const gj=["http","https","ftp"];function isURL(j){const Z=j?.protocols??gj,$=Z.map((Q)=>Q.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|"),z=new RegExp(`^(?:${$}):\\/\\/(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?::(6553[0-5]|655[0-2]\\d|65[0-4]\\d{2}|6[0-4]\\d{3}|[1-5]\\d{4}|[1-9]\\d{0,3}|0))?(?:\\/[^\\s]*)?$`);return W({name:"isURL",requiresType:f.String,constraints:{format:"uri",protocols:Z},validate:(Q)=>typeof Q==="string"&&z.test(Q),emit:(Q,K)=>{return`if (!re[${K.addRegex(z)}].test(${Q})) ${K.fail("isURL")};`}})}const R={all:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,1:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-1[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,2:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-2[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,3:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,4:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,5:/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/};function isUUID(j){const Z=j!=null?R[j]:R.all;return X("isUUID",($)=>Z.test($),($,z)=>{return`if (!re[${z.addRegex(Z)}].test(${$})) ${z.fail("isUUID")};`},f.String,{format:"uuid",version:j})}const q=/^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/;const D=/^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,7}:$|^(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}$|^(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}$|^(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}$|^::$|^::1$|^::(?:ffff(?::0{1,4})?:)?(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$|^(?:[0-9a-fA-F]{1,4}:){1,4}:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;function isIP(j){return W({name:"isIP",requiresType:f.String,constraints:{version:j},validate:(Z)=>{if(typeof Z!=="string")return!1;if(j===4)return q.test(Z);if(j===6)return D.test(Z);return q.test(Z)||D.test(Z)},emit:(Z,$)=>{if(j===4)return`if (!re[${$.addRegex(q)}].test(${Z})) ${$.fail("isIP")};`;if(j===6)return`if (!re[${$.addRegex(D)}].test(${Z})) ${$.fail("isIP")};`;const z=$.addRegex(q),Q=$.addRegex(D);return`if (!re[${z}].test(${Z}) && !re[${Q}].test(${Z})) ${$.fail("isIP")};`}})}const s=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;const isHexColor=X("isHexColor",(j)=>s.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(s)}].test(${j})) ${Z.fail("isHexColor")};`});const U=/^rgb\(\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*\)$/;const P=/^rgba\(\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\s*,\s*(0|0?\.\d+|1(\.0+)?)\s*\)$/;const n=/^rgb\(\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*\)$/;const x=/^rgba\(\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(\d{1,2}|100)%\s*,\s*(0|0?\.\d+|1(?:\.0+)?)\s*\)$/;function isRgbColor(j=!1){return W({name:"isRgbColor",requiresType:f.String,constraints:{includePercentValues:j},validate:(Z)=>{if(typeof Z!=="string")return!1;if(j)return n.test(Z)||x.test(Z)||U.test(Z)||P.test(Z);return U.test(Z)||P.test(Z)},emit:(Z,$)=>{if(j){const K=$.addRegex(n),Y=$.addRegex(x),J=$.addRegex(U),w=$.addRegex(P);return`if (!re[${K}].test(${Z}) && !re[${Y}].test(${Z}) && !re[${J}].test(${Z}) && !re[${w}].test(${Z})) ${$.fail("isRgbColor")};`}const z=$.addRegex(U),Q=$.addRegex(P);return`if (!re[${z}].test(${Z}) && !re[${Q}].test(${Z})) ${$.fail("isRgbColor")};`}})}const u=/^(?:hsl\(\s*(?:360|3[0-5]\d|[12]\d{2}|[1-9]\d|\d)\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:100|[1-9]\d|\d)%\s*\)|hsla\(\s*(?:360|3[0-5]\d|[12]\d{2}|[1-9]\d|\d)\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:100|[1-9]\d|\d)%\s*,\s*(?:0|0?\.\d+|1(?:\.0+)?)\s*\))$/;const isHSL=X("isHSL",(j)=>u.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(u)}].test(${j})) ${Z.fail("isHSL")};`});const l=/^[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5}$/;const i=/^[0-9a-fA-F]{2}(?:-[0-9a-fA-F]{2}){5}$/;const m=/^[0-9a-fA-F]{12}$/;function isMACAddress(j){return W({name:"isMACAddress",requiresType:f.String,constraints:{no_separators:j?.no_separators},validate:(Z)=>{if(typeof Z!=="string")return!1;if(j?.no_separators)return m.test(Z);return l.test(Z)||i.test(Z)},emit:(Z,$)=>{if(j?.no_separators)return`if (!re[${$.addRegex(m)}].test(${Z})) ${$.fail("isMACAddress")};`;const z=$.addRegex(l),Q=$.addRegex(i);return`if (!re[${z}].test(${Z}) && !re[${Q}].test(${Z})) ${$.fail("isMACAddress")};`}})}function c(j){const Z=j.replace(/[-\s]/g,"");if(!/^\d{9}[\dX]$/.test(Z))return!1;let $=0;for(let Q=0;Q<9;Q++)$+=(10-Q)*(Z.charCodeAt(Q)-48);const z=Z[9]==="X"?10:Z.charCodeAt(9)-48;$+=z;return $%11===0}function r(j){const Z=j.replace(/[-\s]/g,"");if(!/^\d{13}$/.test(Z))return!1;let $=0;for(let Q=0;Q<12;Q++)$+=(Z.charCodeAt(Q)-48)*(Q%2===0?1:3);return(10-$%10)%10===Z.charCodeAt(12)-48}function isISBN(j){const Z=(Q)=>{if(typeof Q!=="string")return!1;if(j===10)return c(Q);if(j===13)return r(Q);return c(Q)||r(Q)},$=(Q)=>`{var s=${Q}.replace(/[-\\s]/g,'');if(!/^\\d{9}[\\dX]$/.test(s)){%%FAIL%%}else{var sm=0;for(var i=0;i<9;i++)sm+=(10-i)*(s.charCodeAt(i)-48);var l=s[9]==='X'?10:(s.charCodeAt(9)-48);sm+=l;if(sm%11!==0){%%FAIL%%}}}`,z=(Q)=>`{var s=${Q}.replace(/[-\\s]/g,'');if(!/^\\d{13}$/.test(s)){%%FAIL%%}else{var sm=0;for(var i=0;i<12;i++)sm+=(s.charCodeAt(i)-48)*(i%2===0?1:3);var ck=(10-(sm%10))%10;if(ck!==(s.charCodeAt(12)-48)){%%FAIL%%}}}`;return W({name:"isISBN",requiresType:f.String,constraints:{version:j},validate:Z,emit:(Q,K)=>{const Y=K.fail("isISBN");if(j===10)return $(Q).replace(/%%FAIL%%/g,Y);if(j===13)return z(Q).replace(/%%FAIL%%/g,Y);const J=$(Q).replace(/%%FAIL%%/g,"__isbn_ok=false"),w=z(Q).replace(/%%FAIL%%/g,"__isbn_ok=false");return`{var __isbn_ok=true;${J} if(!__isbn_ok){__isbn_ok=true;${w}} if(!__isbn_ok)${Y};}`}})}const Bj=/^[A-Z]{2}[A-Z0-9]{9}[0-9]$/;function Lj(j){if(!Bj.test(j))return!1;let Z=0,$=!1;for(let z=j.length-1;z>=0;z--){const Q=j.charCodeAt(z);if(Q<=57){let K=Q-48;if($){K*=2;if(K>9)K-=9}Z+=K;$=!$}else{const K=Q-55,Y=K%10;let J=Y;if($){J*=2;if(J>9)J-=9}Z+=J;$=!$;J=(K-Y)/10;if($){J*=2;if(J>9)J-=9}Z+=J;$=!$}}return Z%10===0}const isISIN=X("isISIN",Lj,(j,Z)=>{return`if (!re[${Z.addRegex(Bj)}].test(${j})) ${Z.fail("isISIN")};
|
|
2
|
+
else { var isSum=0,isAlt=false;
|
|
3
|
+
for(var isI=${j}.length-1;isI>=0;isI--){var isCd=${j}.charCodeAt(isI);if(isCd<=57){var isN=isCd-48;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;}else{var isVal=isCd-55;var isO=isVal%10;var isN=isO;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;isN=(isVal-isO)/10;if(isAlt){isN*=2;if(isN>9)isN-=9;}isSum+=isN;isAlt=!isAlt;}}
|
|
4
|
+
if(isSum%10!==0)${Z.fail("isISIN")}; }`});const H=/^\d{4}(?:-\d{2}(?:-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)?)?)?$/;function Ij(j){if(!H.test(j))return!1;const Z=j.match(/^(\d{4})-(\d{2})(?:-(\d{2}))?/);if(!Z)return!0;const $=Number(Z[2]);if($<1||$>12)return!1;if(Z[3]!==void 0){const J=Number(Z[3]),w=new Date(Number(Z[1]),$,0).getDate();if(J<1||J>w)return!1}const z=j.match(/T(\d{2}):(\d{2}):(\d{2})/);if(!z)return!0;const Q=Number(z[1]),K=Number(z[2]),Y=Number(z[3]);return Q>=0&&Q<=23&&K>=0&&K<=59&&Y>=0&&Y<=60}function isISO8601(j){if(j?.strict){const Z=($)=>typeof $==="string"&&Ij($);return W({name:"isISO8601",requiresType:f.String,constraints:{format:"date-time",strict:!0},validate:Z,emit:($,z)=>{return`if (!re[${z.addRegex(H)}].test(${$})) ${z.fail("isISO8601")};
|
|
5
|
+
else { var dm=${$}.match(/^(\\d{4})-(\\d{2})(?:-(\\d{2}))?/);if(dm){var mo=Number(dm[2]);if(mo<1||mo>12){${z.fail("isISO8601")}}else if(dm[3]!==undefined){var da=Number(dm[3]),md=new Date(Number(dm[1]),mo,0).getDate();if(da<1||da>md){${z.fail("isISO8601")}}}}var tm=${$}.match(/T(\\d{2}):(\\d{2}):(\\d{2})/);if(tm){var hh=Number(tm[1]),mm=Number(tm[2]),ss=Number(tm[3]);if(hh<0||hh>23||mm<0||mm>59||ss<0||ss>60)${z.fail("isISO8601")};} }`}})}return X("isISO8601",(Z)=>H.test(Z),(Z,$)=>{return`if (!re[${$.addRegex(H)}].test(${Z})) ${$.fail("isISO8601")};`},f.String,{format:"date-time",strict:!1})}const v=/^[A-Z]{2}-[A-Z0-9]{3}-\d{2}-\d{5}$|^[A-Z]{2}[A-Z0-9]{3}\d{7}$/;const isISRC=X("isISRC",(j)=>v.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(v)}].test(${j})) ${Z.fail("isISRC")};`});function Tj(j,Z){const $=Z?.requireHyphen!==!1,z=$?j:j.replace(/-/g,"");if(!($?/^\d{4}-\d{3}[\dX]$/:/^\d{7}[\dX]$/).test(z))return!1;const K=z.replace(/-/g,"");let Y=0;for(let w=0;w<7;w++)Y+=(8-w)*(K.charCodeAt(w)-48);const J=K[7]==="X"?10:K.charCodeAt(7)-48;Y+=J;return Y%11===0}function isISSN(j){const Z=j?.requireHyphen!==!1,$=(Q)=>typeof Q==="string"&&Tj(Q,j),z=Z?/^\d{4}-\d{3}[\dX]$/:/^\d{7}[\dX]$/;return W({name:"isISSN",requiresType:f.String,constraints:{requireHyphen:j?.requireHyphen},validate:$,emit:(Q,K)=>{const Y=K.addRegex(z);return`{var issn=${Z?Q:`${Q}.replace(/-/g,'')`};if(!re[${Y}].test(issn)){${K.fail("isISSN")}}else{var id=issn.replace(/-/g,''),iss=0;for(var ii=0;ii<7;ii++)iss+=(8-ii)*(id.charCodeAt(ii)-48);var il=id[7]==='X'?10:(id.charCodeAt(7)-48);iss+=il;if(iss%11!==0)${K.fail("isISSN")};}}`}})}const t=/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;const isJWT=X("isJWT",(j)=>t.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(t)}].test(${j})) ${Z.fail("isJWT")};`});const a=/^[-+]?([1-8]?\d(?:\.\d+)?|90(?:\.0+)?),\s*[-+]?(180(?:\.0+)?|1[0-7]\d(?:\.\d+)?|\d{1,2}(?:\.\d+)?)$/;function isLatLong(){return X("isLatLong",(j)=>a.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(a)}].test(${j})) ${Z.fail("isLatLong")};`})}const e=/^[a-zA-Z]{2,3}(?:-[a-zA-Z]{4})?(?:-(?:[a-zA-Z]{2}|\d{3}))?(?:-[a-zA-Z\d]{5,8})*$/;const isLocale=X("isLocale",(j)=>e.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(e)}].test(${j})) ${Z.fail("isLocale")};`});const jj=/^data:([a-zA-Z0-9!#$&\-^_]+\/[a-zA-Z0-9!#$&\-^_]+)(?:;[a-zA-Z0-9-]+=[a-zA-Z0-9-]+)*(?:;base64)?,[\s\S]*$/;const isDataURI=X("isDataURI",(j)=>jj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(jj)}].test(${j})) ${Z.fail("isDataURI")};`});function isFQDN(j){const Z=j?.require_tld!==!1,$=j?.allow_underscores??!1,z=j?.allow_trailing_dot??!1,Q=$?/^[a-zA-Z0-9_-]+$/:/^[a-zA-Z0-9-]+$/,K=(Y)=>{if(typeof Y!=="string")return!1;let J=Y;if(z&&J.endsWith("."))J=J.slice(0,-1);if(J.length===0)return!1;const w=J.split(".");if(Z&&w.length<2)return!1;if(Z){const b=w[w.length-1];if(!b||b.length<2||!/^[a-zA-Z]{2,}$/.test(b))return!1}return w.every((b)=>{if(b.length===0||b.length>63)return!1;if(!Q.test(b))return!1;if(!$&&(b.startsWith("-")||b.endsWith("-")))return!1;return!0})};return W({name:"isFQDN",requiresType:f.String,constraints:{require_tld:j?.require_tld,allow_underscores:j?.allow_underscores,allow_trailing_dot:j?.allow_trailing_dot},validate:K,emit:(Y,J)=>{const w=J.addRegex(Q),b=Z?J.addRegex(/^[a-zA-Z]{2,}$/):-1,G=`var fqOk=true;for(var fi=0;fi<fp.length;fi++){var p=fp[fi];${`if(p.length===0||p.length>63){fqOk=false;break;}if(!re[${w}].test(p)){fqOk=false;break;}`+($?"":"if(p[0]==='-'||p[p.length-1]==='-'){fqOk=false;break;}")}}if(!fqOk)${J.fail("isFQDN")};`;let F=`{var fq=${Y};`;if(z)F+="if(fq.endsWith('.'))fq=fq.slice(0,-1);";F+=`if(fq.length===0)${J.fail("isFQDN")};`;F+="else{var fp=fq.split('.');";if(Z){F+=`if(fp.length<2)${J.fail("isFQDN")};`;F+="else{var tld=fp[fp.length-1];";F+=`if(!tld||tld.length<2||!re[${b}].test(tld))${J.fail("isFQDN")};`;F+=`else{${G}}`;F+="}"}else F+=G;F+="}";F+="}";return F}})}const Zj=/^(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{1,3}|\d)$/;const isPort=X("isPort",(j)=>Zj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Zj)}].test(${j})) ${Z.fail("isPort")};`});function Sj(j){if(!/^\d{8}$/.test(j)&&!/^\d{13}$/.test(j))return!1;const Z=j.length;let $=0;for(let Q=0;Q<Z-1;Q++){const K=j.charCodeAt(Q)-48;$+=K*(Z===8?Q%2===0?3:1:Q%2===0?1:3)}return(10-$%10)%10===j.charCodeAt(Z-1)-48}const isEAN=X("isEAN",Sj,(j,Z)=>{const $=Z.addRegex(/^\d{8}$/),z=Z.addRegex(/^\d{13}$/);return`{var ev=${j};if(!re[${$}].test(ev)&&!re[${z}].test(ev)){${Z.fail("isEAN")}}else{var el=ev.length,es=0;for(var ei=0;ei<el-1;ei++){var ed=ev.charCodeAt(ei)-48;es+=ed*(el===8?(ei%2===0?3:1):(ei%2===0?1:3));}var ec=(10-(es%10))%10;if(ec!==(ev.charCodeAt(el-1)-48))${Z.fail("isEAN")};}}`});const $j=new Set(["AD","AE","AF","AG","AI","AL","AM","AO","AQ","AR","AS","AT","AU","AW","AX","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BL","BM","BN","BO","BQ","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CW","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","GA","GB","GD","GE","GF","GG","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IM","IN","IO","IQ","IR","IS","IT","JE","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","ME","MF","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RS","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","SS","ST","SV","SX","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TL","TM","TN","TO","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","ZA","ZM","ZW"]);const isISO31661Alpha2=W({name:"isISO31661Alpha2",requiresType:f.String,constraints:{},validate:(j)=>typeof j==="string"&&$j.has(j.toUpperCase()),emit:(j,Z)=>{return`if (!refs[${Z.addRef($j)}].has(${j}.toUpperCase())) ${Z.fail("isISO31661Alpha2")};`}});const zj=new Set(["ABW","AFG","AGO","AIA","ALA","ALB","AND","ANT","ARE","ARG","ARM","ASM","ATA","ATF","ATG","AUS","AUT","AZE","BDI","BEL","BEN","BES","BFA","BGD","BGR","BHR","BHS","BIH","BLM","BLR","BLZ","BMU","BOL","BRA","BRB","BRN","BTN","BVT","BWA","CAF","CAN","CCK","CHE","CHL","CHN","CIV","CMR","COD","COG","COK","COL","COM","CPV","CRI","CUB","CUW","CXR","CYM","CYP","CZE","DEU","DJI","DMA","DNK","DOM","DZA","ECU","EGY","ERI","ESH","ESP","EST","ETH","FIN","FJI","FLK","FRA","FRO","FSM","GAB","GBR","GEO","GGY","GHA","GIB","GIN","GLP","GMB","GNB","GNQ","GRC","GRD","GRL","GTM","GUF","GUM","GUY","HKG","HMD","HND","HRV","HTI","HUN","IDN","IMN","IND","IOT","IRL","IRN","IRQ","ISL","ISR","ITA","JAM","JEY","JOR","JPN","KAZ","KEN","KGZ","KHM","KIR","KNA","KOR","KWT","LAO","LBN","LBR","LBY","LCA","LIE","LKA","LSO","LTU","LUX","LVA","MAC","MAF","MAR","MCO","MDA","MDG","MDV","MEX","MHL","MKD","MLI","MLT","MMR","MNE","MNG","MNP","MOZ","MRT","MSR","MTQ","MUS","MWI","MYS","MYT","NAM","NCL","NER","NFK","NGA","NIC","NIU","NLD","NOR","NPL","NRU","NZL","OMN","PAK","PAN","PCN","PER","PHL","PLW","PNG","POL","PRI","PRK","PRT","PRY","PSE","PYF","QAT","REU","ROU","RUS","RWA","SAU","SDN","SEN","SGP","SGS","SHN","SJM","SLB","SLE","SLV","SMR","SOM","SPM","SRB","SSD","STP","SUR","SVK","SVN","SWE","SWZ","SXM","SYC","SYR","TCA","TCD","TGO","THA","TJK","TKL","TKM","TLS","TON","TTO","TUN","TUR","TUV","TWN","TZA","UGA","UKR","UMI","URY","USA","UZB","VAT","VCT","VEN","VGB","VIR","VNM","VUT","WLF","WSM","YEM","ZAF","ZMB","ZWE"]);const isISO31661Alpha3=W({name:"isISO31661Alpha3",requiresType:f.String,constraints:{},validate:(j)=>typeof j==="string"&&zj.has(j.toUpperCase()),emit:(j,Z)=>{return`if (!refs[${Z.addRef(zj)}].has(${j}.toUpperCase())) ${Z.fail("isISO31661Alpha3")};`}});const Qj=/^[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$/i;const isBIC=X("isBIC",(j)=>Qj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Qj)}].test(${j})) ${Z.fail("isBIC")};`});const Jj=/^[a-zA-Z0-9_-]{20}$/;const isFirebasePushId=X("isFirebasePushId",(j)=>Jj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Jj)}].test(${j})) ${Z.fail("isFirebasePushId")};`});const Kj=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;const isSemVer=X("isSemVer",(j)=>Kj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Kj)}].test(${j})) ${Z.fail("isSemVer")};`});const Xj=/^[0-9a-fA-F]{24}$/;const isMongoId=X("isMongoId",(j)=>Xj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Xj)}].test(${j})) ${Z.fail("isMongoId")};`});const dj=(j)=>{if(typeof j!=="string")return!1;try{JSON.parse(j);return!0}catch{return!1}};const isJSON=W({name:"isJSON",requiresType:f.String,constraints:{},validate:dj,emit:(j,Z)=>`try { JSON.parse(${j}); } catch { ${Z.fail("isJSON")}; }`});const fj=/^[A-Z2-7]+=*$/i;function isBase32(){return X("isBase32",(j)=>j.length%8===0&&fj.test(j),(j,Z)=>{const $=Z.addRegex(fj);return`if (${j}.length % 8 !== 0 || !re[${$}].test(${j})) ${Z.fail("isBase32")};`})}const Yj=/^[1-9A-HJ-NP-Za-km-z]+$/;const isBase58=X("isBase58",(j)=>Yj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Yj)}].test(${j})) ${Z.fail("isBase58")};`});const pj=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;const _j=/^[A-Za-z0-9_-]+={0,2}$/;function isBase64(j){const Z=j?.urlSafe?_j:pj;return X("isBase64",($)=>Z.test($),($,z)=>{return`if (!re[${z.addRegex(Z)}].test(${$})) ${z.fail("isBase64")};`},f.String,{urlSafe:j?.urlSafe})}const yj=/^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;function Ej(j){if(!yj.test(j))return!1;const Z=Number(j.slice(0,4)),$=Number(j.slice(5,7)),z=Number(j.slice(8,10)),Q=new Date(Z,$,0).getDate();return z>=1&&z<=Q}function isDateString(){return X("isDateString",Ej,(j,Z)=>{return`if (!re[${Z.addRegex(yj)}].test(${j})) ${Z.fail("isDateString")};
|
|
6
|
+
else { var y=Number(${j}.slice(0,4)),m=Number(${j}.slice(5,7)),d=Number(${j}.slice(8,10));var md=new Date(y,m,0).getDate(); if(d<1||d>md)${Z.fail("isDateString")}; }`})}const Wj=/^(application|audio|font|image|message|model|multipart|text|video)\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-^_.+]*(?:;.+)?$/;const isMimeType=X("isMimeType",(j)=>Wj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Wj)}].test(${j})) ${Z.fail("isMimeType")};`});const wj=/^(?:[-+]?\$?|\$[-+]?)(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d{1,2})?$/;function isCurrency(){return X("isCurrency",(j)=>wj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(wj)}].test(${j})) ${Z.fail("isCurrency")};`})}const bj=/^magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32,40}(?:&[a-z][a-z0-9.]*=[^&\s]*)*$/i;const isMagnetURI=X("isMagnetURI",(j)=>bj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(bj)}].test(${j})) ${Z.fail("isMagnetURI")};`});function oj(j){const Z=j.replace(/[\s-]/g,"");if(Z.length===0||!/^\d+$/.test(Z))return!1;let $=0,z=!1;for(let Q=Z.length-1;Q>=0;Q--){let K=Z.charCodeAt(Q)-48;if(z){K*=2;if(K>9)K-=9}$+=K;z=!z}return $%10===0}const isCreditCard=W({name:"isCreditCard",requiresType:f.String,constraints:{},validate:(j)=>typeof j==="string"&&oj(j),emit:(j,Z)=>`{
|
|
7
|
+
var cs=${j}.replace(/[\\s-]/g,'');
|
|
8
|
+
if(cs.length===0||!/^\\d+$/.test(cs)){${Z.fail("isCreditCard")}}
|
|
1432
9
|
else{var sum=0,alt=false;
|
|
1433
10
|
for(var ci=cs.length-1;ci>=0;ci--){var cn=cs.charCodeAt(ci)-48;if(alt){cn*=2;if(cn>9)cn-=9;}sum+=cn;alt=!alt;}
|
|
1434
|
-
if(sum%10!==0)${
|
|
1435
|
-
}
|
|
1436
|
-
});
|
|
1437
|
-
const IBAN_COUNTRY_LENGTH = {
|
|
1438
|
-
AD: 24,
|
|
1439
|
-
AE: 23,
|
|
1440
|
-
AL: 28,
|
|
1441
|
-
AT: 20,
|
|
1442
|
-
AZ: 28,
|
|
1443
|
-
BA: 20,
|
|
1444
|
-
BE: 16,
|
|
1445
|
-
BG: 22,
|
|
1446
|
-
BH: 22,
|
|
1447
|
-
BR: 29,
|
|
1448
|
-
CH: 21,
|
|
1449
|
-
CR: 22,
|
|
1450
|
-
CY: 28,
|
|
1451
|
-
CZ: 24,
|
|
1452
|
-
DE: 22,
|
|
1453
|
-
DK: 18,
|
|
1454
|
-
DO: 28,
|
|
1455
|
-
EE: 20,
|
|
1456
|
-
ES: 24,
|
|
1457
|
-
FI: 18,
|
|
1458
|
-
FO: 18,
|
|
1459
|
-
FR: 27,
|
|
1460
|
-
GB: 22,
|
|
1461
|
-
GE: 22,
|
|
1462
|
-
GI: 23,
|
|
1463
|
-
GL: 18,
|
|
1464
|
-
GR: 27,
|
|
1465
|
-
GT: 28,
|
|
1466
|
-
HR: 21,
|
|
1467
|
-
HU: 28,
|
|
1468
|
-
IE: 22,
|
|
1469
|
-
IL: 23,
|
|
1470
|
-
IS: 26,
|
|
1471
|
-
IT: 27,
|
|
1472
|
-
JO: 30,
|
|
1473
|
-
KW: 30,
|
|
1474
|
-
KZ: 20,
|
|
1475
|
-
LB: 28,
|
|
1476
|
-
LC: 32,
|
|
1477
|
-
LI: 21,
|
|
1478
|
-
LT: 20,
|
|
1479
|
-
LU: 20,
|
|
1480
|
-
LV: 21,
|
|
1481
|
-
MC: 27,
|
|
1482
|
-
MD: 24,
|
|
1483
|
-
ME: 22,
|
|
1484
|
-
MK: 19,
|
|
1485
|
-
MR: 27,
|
|
1486
|
-
MT: 31,
|
|
1487
|
-
MU: 30,
|
|
1488
|
-
NL: 18,
|
|
1489
|
-
NO: 15,
|
|
1490
|
-
PK: 24,
|
|
1491
|
-
PL: 28,
|
|
1492
|
-
PS: 29,
|
|
1493
|
-
PT: 25,
|
|
1494
|
-
QA: 29,
|
|
1495
|
-
RO: 24,
|
|
1496
|
-
RS: 22,
|
|
1497
|
-
SA: 24,
|
|
1498
|
-
SC: 31,
|
|
1499
|
-
SE: 24,
|
|
1500
|
-
SI: 19,
|
|
1501
|
-
SK: 24,
|
|
1502
|
-
SM: 27,
|
|
1503
|
-
ST: 25,
|
|
1504
|
-
SV: 28,
|
|
1505
|
-
TL: 23,
|
|
1506
|
-
TN: 24,
|
|
1507
|
-
TR: 26,
|
|
1508
|
-
UA: 29,
|
|
1509
|
-
VA: 22,
|
|
1510
|
-
VG: 24,
|
|
1511
|
-
XK: 20,
|
|
1512
|
-
};
|
|
1513
|
-
function validateIBAN(value, options) {
|
|
1514
|
-
let s = options?.allowSpaces ? value.replace(/\s/g, '') : value;
|
|
1515
|
-
s = s.toUpperCase();
|
|
1516
|
-
if (!/^[A-Z]{2}\d{2}[A-Z0-9]+$/.test(s)) {
|
|
1517
|
-
return false;
|
|
1518
|
-
}
|
|
1519
|
-
const country = s.slice(0, 2);
|
|
1520
|
-
const expectedLength = IBAN_COUNTRY_LENGTH[country];
|
|
1521
|
-
if (expectedLength !== undefined && s.length !== expectedLength) {
|
|
1522
|
-
return false;
|
|
1523
|
-
}
|
|
1524
|
-
// Rearrange: move first 4 chars to end
|
|
1525
|
-
const rearranged = s.slice(4) + s.slice(0, 4);
|
|
1526
|
-
// Walk char-by-char accumulating mod 97 — no .replace/closure, no String() coercion,
|
|
1527
|
-
// no parseInt() allocations.
|
|
1528
|
-
let remainder = 0;
|
|
1529
|
-
for (let i = 0; i < rearranged.length; i++) {
|
|
1530
|
-
const code = rearranged.charCodeAt(i);
|
|
1531
|
-
if (code <= 57) {
|
|
1532
|
-
// digit
|
|
1533
|
-
remainder = (remainder * 10 + (code - 48)) % 97;
|
|
1534
|
-
}
|
|
1535
|
-
else {
|
|
1536
|
-
// letter A-Z → two digits (value = code - 55)
|
|
1537
|
-
const value = code - 55;
|
|
1538
|
-
remainder = (remainder * 100 + value) % 97;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
return remainder === 1;
|
|
1542
|
-
}
|
|
1543
|
-
function isIBAN(options) {
|
|
1544
|
-
const allowSpaces = options?.allowSpaces ?? false;
|
|
1545
|
-
const validateIban = (value) => typeof value === 'string' && validateIBAN(value, options);
|
|
1546
|
-
return makeRule({
|
|
1547
|
-
name: 'isIBAN',
|
|
1548
|
-
requiresType: 'string',
|
|
1549
|
-
constraints: { allowSpaces: options?.allowSpaces },
|
|
1550
|
-
validate: validateIban,
|
|
1551
|
-
emit: (varName, ctx) => {
|
|
1552
|
-
const baseRi = ctx.addRegex(/^[A-Z]{2}\d{2}[A-Z0-9]+$/);
|
|
1553
|
-
const tableIdx = ctx.addRef(IBAN_COUNTRY_LENGTH);
|
|
1554
|
-
let code = '{';
|
|
1555
|
-
code += `var ib=${allowSpaces ? `${varName}.replace(/\\s/g,'')` : varName}.toUpperCase();`;
|
|
1556
|
-
code += `if(!re[${baseRi}].test(ib)){${ctx.fail('isIBAN')}}`;
|
|
1557
|
-
code += `else{var ic=ib.slice(0,2),il=refs[${tableIdx}][ic];`;
|
|
1558
|
-
code += `if(il!==undefined&&ib.length!==il){${ctx.fail('isIBAN')}}`;
|
|
1559
|
-
code += `else{var ir=ib.slice(4)+ib.slice(0,4);`;
|
|
1560
|
-
// Walk char-by-char for mod 97 — no .replace closure, no parseInt allocation
|
|
1561
|
-
code += `var im=0;for(var ii=0;ii<ir.length;ii++){var cc=ir.charCodeAt(ii);`;
|
|
1562
|
-
code += `if(cc<=57){im=(im*10+(cc-48))%97;}else{im=(im*100+(cc-55))%97;}}`;
|
|
1563
|
-
code += `if(im!==1)${ctx.fail('isIBAN')};}}}`;
|
|
1564
|
-
return code;
|
|
1565
|
-
},
|
|
1566
|
-
});
|
|
1567
|
-
}
|
|
1568
|
-
// ByteLength — counts UTF-8 bytes via Buffer.byteLength
|
|
1569
|
-
function isByteLength(min, max) {
|
|
1570
|
-
const validateByteLength = (value) => {
|
|
1571
|
-
if (typeof value !== 'string') {
|
|
1572
|
-
return false;
|
|
1573
|
-
}
|
|
1574
|
-
const byteLen = Buffer.byteLength(value, 'utf8');
|
|
1575
|
-
if (byteLen < min) {
|
|
1576
|
-
return false;
|
|
1577
|
-
}
|
|
1578
|
-
if (max !== undefined && byteLen > max) {
|
|
1579
|
-
return false;
|
|
1580
|
-
}
|
|
1581
|
-
return true;
|
|
1582
|
-
};
|
|
1583
|
-
return makeRule({
|
|
1584
|
-
name: 'isByteLength',
|
|
1585
|
-
requiresType: 'string',
|
|
1586
|
-
constraints: { min, max },
|
|
1587
|
-
validate: validateByteLength,
|
|
1588
|
-
emit: (varName, ctx) => {
|
|
1589
|
-
let code = `{var bl=Buffer.byteLength(${varName},'utf8');`;
|
|
1590
|
-
code += `if(bl<${min})${ctx.fail('isByteLength')};`;
|
|
1591
|
-
if (max !== undefined) {
|
|
1592
|
-
code += `else if(bl>${max})${ctx.fail('isByteLength')};`;
|
|
1593
|
-
}
|
|
1594
|
-
code += '}';
|
|
1595
|
-
return code;
|
|
1596
|
-
},
|
|
1597
|
-
});
|
|
1598
|
-
}
|
|
1599
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1600
|
-
// Group E: New Validators
|
|
1601
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
1602
|
-
// isHash — per-algorithm hex regex (§4.8 B: regex inline)
|
|
1603
|
-
const HASH_REGEXES = {
|
|
1604
|
-
md5: /^[a-f0-9]{32}$/i,
|
|
1605
|
-
md4: /^[a-f0-9]{32}$/i,
|
|
1606
|
-
md2: /^[a-f0-9]{32}$/i,
|
|
1607
|
-
sha1: /^[a-f0-9]{40}$/i,
|
|
1608
|
-
sha256: /^[a-f0-9]{64}$/i,
|
|
1609
|
-
sha384: /^[a-f0-9]{96}$/i,
|
|
1610
|
-
sha512: /^[a-f0-9]{128}$/i,
|
|
1611
|
-
ripemd128: /^[a-f0-9]{32}$/i,
|
|
1612
|
-
ripemd160: /^[a-f0-9]{40}$/i,
|
|
1613
|
-
'tiger128,3': /^[a-f0-9]{32}$/i,
|
|
1614
|
-
'tiger128,4': /^[a-f0-9]{32}$/i,
|
|
1615
|
-
'tiger160,3': /^[a-f0-9]{40}$/i,
|
|
1616
|
-
'tiger160,4': /^[a-f0-9]{40}$/i,
|
|
1617
|
-
'tiger192,3': /^[a-f0-9]{48}$/i,
|
|
1618
|
-
'tiger192,4': /^[a-f0-9]{48}$/i,
|
|
1619
|
-
crc32: /^[a-f0-9]{8}$/i,
|
|
1620
|
-
crc32b: /^[a-f0-9]{8}$/i,
|
|
1621
|
-
};
|
|
1622
|
-
function isHash(algorithm) {
|
|
1623
|
-
const re = HASH_REGEXES[algorithm];
|
|
1624
|
-
return makeRule({
|
|
1625
|
-
name: 'isHash',
|
|
1626
|
-
requiresType: 'string',
|
|
1627
|
-
constraints: { algorithm },
|
|
1628
|
-
validate: value => typeof value === 'string' && !!re && re.test(value),
|
|
1629
|
-
emit: (varName, ctx) => {
|
|
1630
|
-
if (!re) {
|
|
1631
|
-
return ctx.fail('isHash') + ';';
|
|
1632
|
-
}
|
|
1633
|
-
const i = ctx.addRegex(re);
|
|
1634
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isHash')};`;
|
|
1635
|
-
},
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
// isRFC3339 — RFC 3339 datetime (§4.8 B)
|
|
1639
|
-
const RFC3339_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/i;
|
|
1640
|
-
const isRFC3339 = makeStringRule('isRFC3339', v => RFC3339_RE.test(v), (varName, ctx) => {
|
|
1641
|
-
const i = ctx.addRegex(RFC3339_RE);
|
|
1642
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isRFC3339')};`;
|
|
1643
|
-
});
|
|
1644
|
-
// isMilitaryTime — HH:MM 24-hour format (§4.8 B)
|
|
1645
|
-
const MILITARY_TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
1646
|
-
const isMilitaryTime = makeStringRule('isMilitaryTime', v => MILITARY_TIME_RE.test(v), (varName, ctx) => {
|
|
1647
|
-
const i = ctx.addRegex(MILITARY_TIME_RE);
|
|
1648
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isMilitaryTime')};`;
|
|
1649
|
-
});
|
|
1650
|
-
// isLatitude — string or number, -90 to 90 (requiresType none)
|
|
1651
|
-
function checkLatitude(value) {
|
|
1652
|
-
if (typeof value === 'number') {
|
|
1653
|
-
return value >= -90 && value <= 90;
|
|
1654
|
-
}
|
|
1655
|
-
if (typeof value === 'string') {
|
|
1656
|
-
const n = parseFloat(value);
|
|
1657
|
-
if (isNaN(n)) {
|
|
1658
|
-
return false;
|
|
1659
|
-
}
|
|
1660
|
-
// parseFloat('90abc') = 90 — strict regex check rejects trailing garbage
|
|
1661
|
-
if (!/^-?\d+(\.\d+)?$/.test(value)) {
|
|
1662
|
-
return false;
|
|
1663
|
-
}
|
|
1664
|
-
return n >= -90 && n <= 90;
|
|
1665
|
-
}
|
|
1666
|
-
return false;
|
|
1667
|
-
}
|
|
1668
|
-
const isLatitude = makeRule({
|
|
1669
|
-
name: 'isLatitude',
|
|
1670
|
-
constraints: {},
|
|
1671
|
-
validate: checkLatitude,
|
|
1672
|
-
emit: (varName, ctx) => {
|
|
1673
|
-
const ri = ctx.addRegex(/^-?\d+(\.\d+)?$/);
|
|
1674
|
-
return (`if(typeof ${varName}==='number'){if(${varName}<-90||${varName}>90)${ctx.fail('isLatitude')};}` +
|
|
1675
|
-
`else if(typeof ${varName}==='string'){` +
|
|
1676
|
-
// Regex catches non-numeric strings; if it matches, parseFloat is guaranteed valid (no isNaN check needed)
|
|
1677
|
-
`if(!re[${ri}].test(${varName})){${ctx.fail('isLatitude')}}` +
|
|
1678
|
-
`else{var lt=parseFloat(${varName});if(lt<-90||lt>90)${ctx.fail('isLatitude')};}}` +
|
|
1679
|
-
`else{${ctx.fail('isLatitude')};}`);
|
|
1680
|
-
},
|
|
1681
|
-
});
|
|
1682
|
-
// isLongitude — string or number, -180 to 180 (requiresType none)
|
|
1683
|
-
function checkLongitude(value) {
|
|
1684
|
-
if (typeof value === 'number') {
|
|
1685
|
-
return value >= -180 && value <= 180;
|
|
1686
|
-
}
|
|
1687
|
-
if (typeof value === 'string') {
|
|
1688
|
-
const n = parseFloat(value);
|
|
1689
|
-
if (isNaN(n)) {
|
|
1690
|
-
return false;
|
|
1691
|
-
}
|
|
1692
|
-
if (!/^-?\d+(\.\d+)?$/.test(value)) {
|
|
1693
|
-
return false;
|
|
1694
|
-
}
|
|
1695
|
-
return n >= -180 && n <= 180;
|
|
1696
|
-
}
|
|
1697
|
-
return false;
|
|
1698
|
-
}
|
|
1699
|
-
const isLongitude = makeRule({
|
|
1700
|
-
name: 'isLongitude',
|
|
1701
|
-
constraints: {},
|
|
1702
|
-
validate: checkLongitude,
|
|
1703
|
-
emit: (varName, ctx) => {
|
|
1704
|
-
const ri = ctx.addRegex(/^-?\d+(\.\d+)?$/);
|
|
1705
|
-
return (`if(typeof ${varName}==='number'){if(${varName}<-180||${varName}>180)${ctx.fail('isLongitude')};}` +
|
|
1706
|
-
`else if(typeof ${varName}==='string'){` +
|
|
1707
|
-
`if(!re[${ri}].test(${varName})){${ctx.fail('isLongitude')}}` +
|
|
1708
|
-
`else{var ln=parseFloat(${varName});if(ln<-180||ln>180)${ctx.fail('isLongitude')};}}` +
|
|
1709
|
-
`else{${ctx.fail('isLongitude')};}`);
|
|
1710
|
-
},
|
|
1711
|
-
});
|
|
1712
|
-
// isEthereumAddress — 0x + 40 hex chars (§4.8 B)
|
|
1713
|
-
const ETH_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
1714
|
-
const isEthereumAddress = makeStringRule('isEthereumAddress', v => ETH_ADDRESS_RE.test(v), (varName, ctx) => {
|
|
1715
|
-
const i = ctx.addRegex(ETH_ADDRESS_RE);
|
|
1716
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isEthereumAddress')};`;
|
|
1717
|
-
});
|
|
1718
|
-
// isBtcAddress — P2PKH (1...), P2SH (3...), bech32 (bc1...) (§4.8 B)
|
|
1719
|
-
const BTC_P2PKH_RE = /^1[a-km-zA-HJ-NP-Z1-9]{25,34}$/;
|
|
1720
|
-
const BTC_P2SH_RE = /^3[a-km-zA-HJ-NP-Z1-9]{25,34}$/;
|
|
1721
|
-
const BTC_BECH32_RE = /^(bc1)[a-z0-9]{6,87}$/;
|
|
1722
|
-
const isBtcAddress = makeStringRule('isBtcAddress', v => BTC_P2PKH_RE.test(v) || BTC_P2SH_RE.test(v) || BTC_BECH32_RE.test(v), (varName, ctx) => {
|
|
1723
|
-
const i1 = ctx.addRegex(BTC_P2PKH_RE);
|
|
1724
|
-
const i2 = ctx.addRegex(BTC_P2SH_RE);
|
|
1725
|
-
const i3 = ctx.addRegex(BTC_BECH32_RE);
|
|
1726
|
-
return `if (!re[${i1}].test(${varName}) && !re[${i2}].test(${varName}) && !re[${i3}].test(${varName})) ${ctx.fail('isBtcAddress')};`;
|
|
1727
|
-
});
|
|
1728
|
-
// isISO4217CurrencyCode — ISO 4217 currency code set (§4.8 C: ref-based)
|
|
1729
|
-
const ISO4217_CODES = new Set([
|
|
1730
|
-
'AED',
|
|
1731
|
-
'AFN',
|
|
1732
|
-
'ALL',
|
|
1733
|
-
'AMD',
|
|
1734
|
-
'ANG',
|
|
1735
|
-
'AOA',
|
|
1736
|
-
'ARS',
|
|
1737
|
-
'AUD',
|
|
1738
|
-
'AWG',
|
|
1739
|
-
'AZN',
|
|
1740
|
-
'BAM',
|
|
1741
|
-
'BBD',
|
|
1742
|
-
'BDT',
|
|
1743
|
-
'BGN',
|
|
1744
|
-
'BHD',
|
|
1745
|
-
'BIF',
|
|
1746
|
-
'BMD',
|
|
1747
|
-
'BND',
|
|
1748
|
-
'BOB',
|
|
1749
|
-
'BOV',
|
|
1750
|
-
'BRL',
|
|
1751
|
-
'BSD',
|
|
1752
|
-
'BTN',
|
|
1753
|
-
'BWP',
|
|
1754
|
-
'BYN',
|
|
1755
|
-
'BZD',
|
|
1756
|
-
'CAD',
|
|
1757
|
-
'CDF',
|
|
1758
|
-
'CHE',
|
|
1759
|
-
'CHF',
|
|
1760
|
-
'CHW',
|
|
1761
|
-
'CLF',
|
|
1762
|
-
'CLP',
|
|
1763
|
-
'CNY',
|
|
1764
|
-
'COP',
|
|
1765
|
-
'COU',
|
|
1766
|
-
'CRC',
|
|
1767
|
-
'CUC',
|
|
1768
|
-
'CUP',
|
|
1769
|
-
'CVE',
|
|
1770
|
-
'CZK',
|
|
1771
|
-
'DJF',
|
|
1772
|
-
'DKK',
|
|
1773
|
-
'DOP',
|
|
1774
|
-
'DZD',
|
|
1775
|
-
'EGP',
|
|
1776
|
-
'ERN',
|
|
1777
|
-
'ETB',
|
|
1778
|
-
'EUR',
|
|
1779
|
-
'FJD',
|
|
1780
|
-
'FKP',
|
|
1781
|
-
'GBP',
|
|
1782
|
-
'GEL',
|
|
1783
|
-
'GHS',
|
|
1784
|
-
'GIP',
|
|
1785
|
-
'GMD',
|
|
1786
|
-
'GNF',
|
|
1787
|
-
'GTQ',
|
|
1788
|
-
'GYD',
|
|
1789
|
-
'HKD',
|
|
1790
|
-
'HNL',
|
|
1791
|
-
'HRK',
|
|
1792
|
-
'HTG',
|
|
1793
|
-
'HUF',
|
|
1794
|
-
'IDR',
|
|
1795
|
-
'ILS',
|
|
1796
|
-
'INR',
|
|
1797
|
-
'IQD',
|
|
1798
|
-
'IRR',
|
|
1799
|
-
'ISK',
|
|
1800
|
-
'JMD',
|
|
1801
|
-
'JOD',
|
|
1802
|
-
'JPY',
|
|
1803
|
-
'KES',
|
|
1804
|
-
'KGS',
|
|
1805
|
-
'KHR',
|
|
1806
|
-
'KMF',
|
|
1807
|
-
'KPW',
|
|
1808
|
-
'KRW',
|
|
1809
|
-
'KWD',
|
|
1810
|
-
'KYD',
|
|
1811
|
-
'KZT',
|
|
1812
|
-
'LAK',
|
|
1813
|
-
'LBP',
|
|
1814
|
-
'LKR',
|
|
1815
|
-
'LRD',
|
|
1816
|
-
'LSL',
|
|
1817
|
-
'LYD',
|
|
1818
|
-
'MAD',
|
|
1819
|
-
'MDL',
|
|
1820
|
-
'MGA',
|
|
1821
|
-
'MKD',
|
|
1822
|
-
'MMK',
|
|
1823
|
-
'MNT',
|
|
1824
|
-
'MOP',
|
|
1825
|
-
'MRU',
|
|
1826
|
-
'MUR',
|
|
1827
|
-
'MVR',
|
|
1828
|
-
'MWK',
|
|
1829
|
-
'MXN',
|
|
1830
|
-
'MXV',
|
|
1831
|
-
'MYR',
|
|
1832
|
-
'MZN',
|
|
1833
|
-
'NAD',
|
|
1834
|
-
'NGN',
|
|
1835
|
-
'NIO',
|
|
1836
|
-
'NOK',
|
|
1837
|
-
'NPR',
|
|
1838
|
-
'NZD',
|
|
1839
|
-
'OMR',
|
|
1840
|
-
'PAB',
|
|
1841
|
-
'PEN',
|
|
1842
|
-
'PGK',
|
|
1843
|
-
'PHP',
|
|
1844
|
-
'PKR',
|
|
1845
|
-
'PLN',
|
|
1846
|
-
'PYG',
|
|
1847
|
-
'QAR',
|
|
1848
|
-
'RON',
|
|
1849
|
-
'RSD',
|
|
1850
|
-
'RUB',
|
|
1851
|
-
'RWF',
|
|
1852
|
-
'SAR',
|
|
1853
|
-
'SBD',
|
|
1854
|
-
'SCR',
|
|
1855
|
-
'SDG',
|
|
1856
|
-
'SEK',
|
|
1857
|
-
'SGD',
|
|
1858
|
-
'SHP',
|
|
1859
|
-
'SLE',
|
|
1860
|
-
'SLL',
|
|
1861
|
-
'SOS',
|
|
1862
|
-
'SRD',
|
|
1863
|
-
'SSP',
|
|
1864
|
-
'STN',
|
|
1865
|
-
'SVC',
|
|
1866
|
-
'SYP',
|
|
1867
|
-
'SZL',
|
|
1868
|
-
'THB',
|
|
1869
|
-
'TJS',
|
|
1870
|
-
'TMT',
|
|
1871
|
-
'TND',
|
|
1872
|
-
'TOP',
|
|
1873
|
-
'TRY',
|
|
1874
|
-
'TTD',
|
|
1875
|
-
'TWD',
|
|
1876
|
-
'TZS',
|
|
1877
|
-
'UAH',
|
|
1878
|
-
'UGX',
|
|
1879
|
-
'USD',
|
|
1880
|
-
'USN',
|
|
1881
|
-
'UYI',
|
|
1882
|
-
'UYU',
|
|
1883
|
-
'UYW',
|
|
1884
|
-
'UZS',
|
|
1885
|
-
'VED',
|
|
1886
|
-
'VES',
|
|
1887
|
-
'VND',
|
|
1888
|
-
'VUV',
|
|
1889
|
-
'WST',
|
|
1890
|
-
'XAF',
|
|
1891
|
-
'XAG',
|
|
1892
|
-
'XAU',
|
|
1893
|
-
'XBA',
|
|
1894
|
-
'XBB',
|
|
1895
|
-
'XBC',
|
|
1896
|
-
'XBD',
|
|
1897
|
-
'XCD',
|
|
1898
|
-
'XDR',
|
|
1899
|
-
'XOF',
|
|
1900
|
-
'XPD',
|
|
1901
|
-
'XPF',
|
|
1902
|
-
'XPT',
|
|
1903
|
-
'XSU',
|
|
1904
|
-
'XTS',
|
|
1905
|
-
'XUA',
|
|
1906
|
-
'YER',
|
|
1907
|
-
'ZAR',
|
|
1908
|
-
'ZMW',
|
|
1909
|
-
'ZWL',
|
|
1910
|
-
]);
|
|
1911
|
-
const isISO4217CurrencyCode = makeStringRule('isISO4217CurrencyCode', v => ISO4217_CODES.has(v), (varName, ctx) => {
|
|
1912
|
-
const i = ctx.addRef(ISO4217_CODES);
|
|
1913
|
-
return `if (!refs[${i}].has(${varName})) ${ctx.fail('isISO4217CurrencyCode')};`;
|
|
1914
|
-
});
|
|
1915
|
-
// isPhoneNumber — E.164 international phone number (§4.8 B)
|
|
1916
|
-
const PHONE_E164_RE = /^\+[1-9]\d{6,14}$/;
|
|
1917
|
-
const isPhoneNumber = makeStringRule('isPhoneNumber', v => PHONE_E164_RE.test(v), (varName, ctx) => {
|
|
1918
|
-
const i = ctx.addRegex(PHONE_E164_RE);
|
|
1919
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isPhoneNumber')};`;
|
|
1920
|
-
});
|
|
1921
|
-
function isStrongPassword(options) {
|
|
1922
|
-
const minLength = options?.minLength ?? 8;
|
|
1923
|
-
const minLower = options?.minLowercase ?? 1;
|
|
1924
|
-
const minUpper = options?.minUppercase ?? 1;
|
|
1925
|
-
const minNums = options?.minNumbers ?? 1;
|
|
1926
|
-
const minSymbols = options?.minSymbols ?? 1;
|
|
1927
|
-
// Single-pass character classification — counts all categories in one scan.
|
|
1928
|
-
// Replaces 4× v.match(/.../g) which allocates 4 result arrays per call.
|
|
1929
|
-
const validate = (v) => {
|
|
1930
|
-
if (v.length < minLength) {
|
|
1931
|
-
return false;
|
|
1932
|
-
}
|
|
1933
|
-
let lower = 0;
|
|
1934
|
-
let upper = 0;
|
|
1935
|
-
let nums = 0;
|
|
1936
|
-
let symbols = 0;
|
|
1937
|
-
for (let i = 0; i < v.length; i++) {
|
|
1938
|
-
const c = v.charCodeAt(i);
|
|
1939
|
-
if (c >= 97 && c <= 122) {
|
|
1940
|
-
lower++;
|
|
1941
|
-
}
|
|
1942
|
-
else if (c >= 65 && c <= 90) {
|
|
1943
|
-
upper++;
|
|
1944
|
-
}
|
|
1945
|
-
else if (c >= 48 && c <= 57) {
|
|
1946
|
-
nums++;
|
|
1947
|
-
}
|
|
1948
|
-
else {
|
|
1949
|
-
symbols++;
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
return lower >= minLower && upper >= minUpper && nums >= minNums && symbols >= minSymbols;
|
|
1953
|
-
};
|
|
1954
|
-
return makeRule({
|
|
1955
|
-
name: 'isStrongPassword',
|
|
1956
|
-
requiresType: 'string',
|
|
1957
|
-
constraints: {},
|
|
1958
|
-
validate: value => typeof value === 'string' && validate(value),
|
|
1959
|
-
emit: (varName, ctx) => {
|
|
1960
|
-
// Inline single-pass scan in the JIT executor — no regex match[] allocations
|
|
1961
|
-
const failExpr = ctx.fail('isStrongPassword');
|
|
1962
|
-
const checks = [];
|
|
1963
|
-
if (minLower > 0) {
|
|
1964
|
-
checks.push(`spLo<${minLower}`);
|
|
1965
|
-
}
|
|
1966
|
-
if (minUpper > 0) {
|
|
1967
|
-
checks.push(`spUp<${minUpper}`);
|
|
1968
|
-
}
|
|
1969
|
-
if (minNums > 0) {
|
|
1970
|
-
checks.push(`spNum<${minNums}`);
|
|
1971
|
-
}
|
|
1972
|
-
if (minSymbols > 0) {
|
|
1973
|
-
checks.push(`spSym<${minSymbols}`);
|
|
1974
|
-
}
|
|
1975
|
-
const guard = checks.length === 0 ? '' : `if(${checks.join('||')}){${failExpr}}`;
|
|
1976
|
-
return (`if(${varName}.length<${minLength}){${failExpr}}else{` +
|
|
1977
|
-
`var spLo=0,spUp=0,spNum=0,spSym=0;` +
|
|
1978
|
-
`for(var spI=0;spI<${varName}.length;spI++){var spC=${varName}.charCodeAt(spI);` +
|
|
1979
|
-
`if(spC>=97&&spC<=122)spLo++;else if(spC>=65&&spC<=90)spUp++;else if(spC>=48&&spC<=57)spNum++;else spSym++;}` +
|
|
1980
|
-
guard +
|
|
1981
|
-
`}`);
|
|
1982
|
-
},
|
|
1983
|
-
});
|
|
1984
|
-
}
|
|
1985
|
-
// isTaxId — locale-specific tax identifier (§4.8 C: factory)
|
|
1986
|
-
const TAX_ID_REGEXES = {
|
|
1987
|
-
US: /^\d{2}-\d{7}$/, // EIN format: XX-XXXXXXX
|
|
1988
|
-
KR: /^\d{3}-\d{2}-\d{5}$/, // Business Registration Number: XXX-XX-XXXXX
|
|
1989
|
-
DE: /^\d{11}$/, // Steuernummer: 11 digits
|
|
1990
|
-
FR: /^[0-9]{13}$/, // SIRET: 13 digits
|
|
1991
|
-
GB: /^\d{10}$/, // UTR: 10 digits
|
|
1992
|
-
IT: /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/i, // Codice Fiscale
|
|
1993
|
-
ES: /^[0-9A-Z]\d{7}[0-9A-Z]$/i, // NIF/NIE/CIF
|
|
1994
|
-
AU: /^\d{11}$/, // ABN: 11 digits
|
|
1995
|
-
CA: /^\d{9}$/, // BN: 9 digits
|
|
1996
|
-
IN: /^[A-Z]{5}\d{4}[A-Z]$/i, // PAN: XXXXX9999X
|
|
1997
|
-
};
|
|
1998
|
-
function isTaxId(locale) {
|
|
1999
|
-
const re = TAX_ID_REGEXES[locale];
|
|
2000
|
-
return makeRule({
|
|
2001
|
-
name: 'isTaxId',
|
|
2002
|
-
requiresType: 'string',
|
|
2003
|
-
constraints: { locale },
|
|
2004
|
-
validate: value => typeof value === 'string' && !!re && re.test(value),
|
|
2005
|
-
emit: (varName, ctx) => {
|
|
2006
|
-
if (!re) {
|
|
2007
|
-
return ctx.fail('isTaxId') + ';';
|
|
2008
|
-
}
|
|
2009
|
-
const i = ctx.addRegex(re);
|
|
2010
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isTaxId')};`;
|
|
2011
|
-
},
|
|
2012
|
-
});
|
|
2013
|
-
}
|
|
2014
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2015
|
-
// ULID
|
|
2016
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2017
|
-
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
2018
|
-
function isULID() {
|
|
2019
|
-
return makeStringRule('isULID', v => ULID_RE.test(v), (varName, ctx) => {
|
|
2020
|
-
const i = ctx.addRegex(ULID_RE);
|
|
2021
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isULID')};`;
|
|
2022
|
-
}, 'string', { format: 'ulid' });
|
|
2023
|
-
}
|
|
2024
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2025
|
-
// CUID2
|
|
2026
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2027
|
-
// CUID2 spec: length 24-32, lowercase alphanum, starts with a-z.
|
|
2028
|
-
const CUID2_RE = /^[a-z][0-9a-z]{23,31}$/;
|
|
2029
|
-
function isCUID2() {
|
|
2030
|
-
return makeStringRule('isCUID2', v => CUID2_RE.test(v), (varName, ctx) => {
|
|
2031
|
-
const i = ctx.addRegex(CUID2_RE);
|
|
2032
|
-
return `if (!re[${i}].test(${varName})) ${ctx.fail('isCUID2')};`;
|
|
2033
|
-
}, 'string', { format: 'cuid2' });
|
|
2034
|
-
}
|
|
2035
|
-
export { minLength, maxLength, length, contains, notContains, matches, isLowercase, isUppercase, isAscii, isAlpha, isAlphanumeric, isHttpToken, isOrigin, isCorsOrigin, isBooleanString, isNumberString, isDecimal, isFullWidth, isHalfWidth, isVariableWidth, isMultibyte, isSurrogatePair, isHexadecimal, isOctal, isEmail, isURL, isUUID, isIP, isHexColor, isRgbColor, isHSL, isMACAddress, isISBN, isISIN, isISO8601, isISRC, isISSN, isJWT, isLatLong, isLocale, isDataURI, isFQDN, isPort, isEAN, isISO31661Alpha2, isISO31661Alpha3, isBIC, isFirebasePushId, isSemVer, isMongoId, isJSON, isBase32, isBase58, isBase64, isDateString, isMimeType, isCurrency, isMagnetURI, isCreditCard, isIBAN, isByteLength, isHash, isRFC3339, isMilitaryTime, isLatitude, isLongitude, isEthereumAddress, isBtcAddress, isISO4217CurrencyCode, isPhoneNumber, isStrongPassword, isTaxId, isULID, isCUID2, };
|
|
11
|
+
if(sum%10!==0)${Z.fail("isCreditCard")};}
|
|
12
|
+
}`});const Oj={AD:24,AE:23,AL:28,AT:20,AZ:28,BA:20,BE:16,BG:22,BH:22,BR:29,CH:21,CR:22,CY:28,CZ:24,DE:22,DK:18,DO:28,EE:20,ES:24,FI:18,FO:18,FR:27,GB:22,GE:22,GI:23,GL:18,GR:27,GT:28,HR:21,HU:28,IE:22,IL:23,IS:26,IT:27,JO:30,KW:30,KZ:20,LB:28,LC:32,LI:21,LT:20,LU:20,LV:21,MC:27,MD:24,ME:22,MK:19,MR:27,MT:31,MU:30,NL:18,NO:15,PK:24,PL:28,PS:29,PT:25,QA:29,RO:24,RS:22,SA:24,SC:31,SE:24,SI:19,SK:24,SM:27,ST:25,SV:28,TL:23,TN:24,TR:26,UA:29,VA:22,VG:24,XK:20};function Nj(j,Z){let $=Z?.allowSpaces?j.replace(/\s/g,""):j;$=$.toUpperCase();if(!/^[A-Z]{2}\d{2}[A-Z0-9]+$/.test($))return!1;const z=$.slice(0,2),Q=Oj[z];if(Q!==void 0&&$.length!==Q)return!1;const K=$.slice(4)+$.slice(0,4);let Y=0;for(let J=0;J<K.length;J++){const w=K.charCodeAt(J);if(w<=57)Y=(Y*10+(w-48))%97;else{const b=w-55;Y=(Y*100+b)%97}}return Y===1}function isIBAN(j){const Z=j?.allowSpaces??!1,$=(z)=>typeof z==="string"&&Nj(z,j);return W({name:"isIBAN",requiresType:f.String,constraints:{allowSpaces:j?.allowSpaces},validate:$,emit:(z,Q)=>{const K=Q.addRegex(/^[A-Z]{2}\d{2}[A-Z0-9]+$/),Y=Q.addRef(Oj);let J="{";J+=`var ib=${Z?`${z}.replace(/\\s/g,'')`:z}.toUpperCase();`;J+=`if(!re[${K}].test(ib)){${Q.fail("isIBAN")}}`;J+=`else{var ic=ib.slice(0,2),il=refs[${Y}][ic];`;J+=`if(il!==undefined&&ib.length!==il){${Q.fail("isIBAN")}}`;J+="else{var ir=ib.slice(4)+ib.slice(0,4);";J+="var im=0;for(var ii=0;ii<ir.length;ii++){var cc=ir.charCodeAt(ii);";J+="if(cc<=57){im=(im*10+(cc-48))%97;}else{im=(im*100+(cc-55))%97;}}";J+=`if(im!==1)${Q.fail("isIBAN")};}}}`;return J}})}function isByteLength(j,Z){const $=(z)=>{if(typeof z!=="string")return!1;const Q=Buffer.byteLength(z,"utf8");if(Q<j)return!1;if(Z!==void 0&&Q>Z)return!1;return!0};return W({name:"isByteLength",requiresType:f.String,constraints:{min:j,max:Z},validate:$,emit:(z,Q)=>{let K=`{var bl=Buffer.byteLength(${z},'utf8');`;K+=`if(bl<${j})${Q.fail("isByteLength")};`;if(Z!==void 0)K+=`else if(bl>${Z})${Q.fail("isByteLength")};`;K+="}";return K}})}const Rj={md5:/^[a-f0-9]{32}$/i,md4:/^[a-f0-9]{32}$/i,md2:/^[a-f0-9]{32}$/i,sha1:/^[a-f0-9]{40}$/i,sha256:/^[a-f0-9]{64}$/i,sha384:/^[a-f0-9]{96}$/i,sha512:/^[a-f0-9]{128}$/i,ripemd128:/^[a-f0-9]{32}$/i,ripemd160:/^[a-f0-9]{40}$/i,"tiger128,3":/^[a-f0-9]{32}$/i,"tiger128,4":/^[a-f0-9]{32}$/i,"tiger160,3":/^[a-f0-9]{40}$/i,"tiger160,4":/^[a-f0-9]{40}$/i,"tiger192,3":/^[a-f0-9]{48}$/i,"tiger192,4":/^[a-f0-9]{48}$/i,crc32:/^[a-f0-9]{8}$/i,crc32b:/^[a-f0-9]{8}$/i};function isHash(j){const Z=Rj[j];return W({name:"isHash",requiresType:f.String,constraints:{algorithm:j},validate:($)=>typeof $==="string"&&!!Z&&Z.test($),emit:($,z)=>{if(!Z)return z.fail("isHash")+";";return`if (!re[${z.addRegex(Z)}].test(${$})) ${z.fail("isHash")};`}})}const Fj=/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/i;const isRFC3339=X("isRFC3339",(j)=>Fj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Fj)}].test(${j})) ${Z.fail("isRFC3339")};`});const Vj=/^([01]\d|2[0-3]):[0-5]\d$/;const isMilitaryTime=X("isMilitaryTime",(j)=>Vj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Vj)}].test(${j})) ${Z.fail("isMilitaryTime")};`});function sj(j){if(typeof j==="number")return j>=-90&&j<=90;if(typeof j==="string"){const Z=parseFloat(j);if(isNaN(Z))return!1;if(!/^-?\d+(\.\d+)?$/.test(j))return!1;return Z>=-90&&Z<=90}return!1}const isLatitude=W({name:"isLatitude",constraints:{},validate:sj,emit:(j,Z)=>{const $=Z.addRegex(/^-?\d+(\.\d+)?$/);return`if(typeof ${j}==='number'){if(${j}<-90||${j}>90)${Z.fail("isLatitude")};}else if(typeof ${j}==='string'){if(!re[${$}].test(${j})){${Z.fail("isLatitude")}}else{var lt=parseFloat(${j});if(lt<-90||lt>90)${Z.fail("isLatitude")};}}else{${Z.fail("isLatitude")};}`}});function nj(j){if(typeof j==="number")return j>=-180&&j<=180;if(typeof j==="string"){const Z=parseFloat(j);if(isNaN(Z))return!1;if(!/^-?\d+(\.\d+)?$/.test(j))return!1;return Z>=-180&&Z<=180}return!1}const isLongitude=W({name:"isLongitude",constraints:{},validate:nj,emit:(j,Z)=>{const $=Z.addRegex(/^-?\d+(\.\d+)?$/);return`if(typeof ${j}==='number'){if(${j}<-180||${j}>180)${Z.fail("isLongitude")};}else if(typeof ${j}==='string'){if(!re[${$}].test(${j})){${Z.fail("isLongitude")}}else{var ln=parseFloat(${j});if(ln<-180||ln>180)${Z.fail("isLongitude")};}}else{${Z.fail("isLongitude")};}`}});const Gj=/^0x[0-9a-fA-F]{40}$/;const isEthereumAddress=X("isEthereumAddress",(j)=>Gj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Gj)}].test(${j})) ${Z.fail("isEthereumAddress")};`});const Mj=/^1[a-km-zA-HJ-NP-Z1-9]{25,34}$/;const qj=/^3[a-km-zA-HJ-NP-Z1-9]{25,34}$/;const Dj=/^(bc1)[a-z0-9]{6,87}$/;const isBtcAddress=X("isBtcAddress",(j)=>Mj.test(j)||qj.test(j)||Dj.test(j),(j,Z)=>{const $=Z.addRegex(Mj),z=Z.addRegex(qj),Q=Z.addRegex(Dj);return`if (!re[${$}].test(${j}) && !re[${z}].test(${j}) && !re[${Q}].test(${j})) ${Z.fail("isBtcAddress")};`});const Uj=new Set(["AED","AFN","ALL","AMD","ANG","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BHD","BIF","BMD","BND","BOB","BOV","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHE","CHF","CHW","CLF","CLP","CNY","COP","COU","CRC","CUC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HRK","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MXV","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SLL","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","USN","UYI","UYU","UYW","UZS","VED","VES","VND","VUV","WST","XAF","XAG","XAU","XBA","XBB","XBC","XBD","XCD","XDR","XOF","XPD","XPF","XPT","XSU","XTS","XUA","YER","ZAR","ZMW","ZWL"]);const isISO4217CurrencyCode=X("isISO4217CurrencyCode",(j)=>Uj.has(j),(j,Z)=>{return`if (!refs[${Z.addRef(Uj)}].has(${j})) ${Z.fail("isISO4217CurrencyCode")};`});const Pj=/^\+[1-9]\d{6,14}$/;const isPhoneNumber=X("isPhoneNumber",(j)=>Pj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Pj)}].test(${j})) ${Z.fail("isPhoneNumber")};`});function isStrongPassword(j){const Z=j?.minLength??8,$=j?.minLowercase??1,z=j?.minUppercase??1,Q=j?.minNumbers??1,K=j?.minSymbols??1,Y=(J)=>{if(J.length<Z)return!1;let w=0,b=0,V=0,G=0;for(let F=0;F<J.length;F++){const M=J.charCodeAt(F);if(M>=97&&M<=122)w++;else if(M>=65&&M<=90)b++;else if(M>=48&&M<=57)V++;else G++}return w>=$&&b>=z&&V>=Q&&G>=K};return W({name:"isStrongPassword",requiresType:f.String,constraints:{},validate:(J)=>typeof J==="string"&&Y(J),emit:(J,w)=>{const b=w.fail("isStrongPassword"),V=[];if($>0)V.push(`spLo<${$}`);if(z>0)V.push(`spUp<${z}`);if(Q>0)V.push(`spNum<${Q}`);if(K>0)V.push(`spSym<${K}`);const G=V.length===0?"":`if(${V.join("||")}){${b}}`;return`if(${J}.length<${Z}){${b}}else{var spLo=0,spUp=0,spNum=0,spSym=0;for(var spI=0;spI<${J}.length;spI++){var spC=${J}.charCodeAt(spI);if(spC>=97&&spC<=122)spLo++;else if(spC>=65&&spC<=90)spUp++;else if(spC>=48&&spC<=57)spNum++;else spSym++;}`+G+"}"}})}const xj={US:/^\d{2}-\d{7}$/,KR:/^\d{3}-\d{2}-\d{5}$/,DE:/^\d{11}$/,FR:/^[0-9]{13}$/,GB:/^\d{10}$/,IT:/^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/i,ES:/^[0-9A-Z]\d{7}[0-9A-Z]$/i,AU:/^\d{11}$/,CA:/^\d{9}$/,IN:/^[A-Z]{5}\d{4}[A-Z]$/i};function isTaxId(j){const Z=xj[j];return W({name:"isTaxId",requiresType:f.String,constraints:{locale:j},validate:($)=>typeof $==="string"&&!!Z&&Z.test($),emit:($,z)=>{if(!Z)return z.fail("isTaxId")+";";return`if (!re[${z.addRegex(Z)}].test(${$})) ${z.fail("isTaxId")};`}})}const Hj=/^[0-9A-HJKMNP-TV-Z]{26}$/;function isULID(){return X("isULID",(j)=>Hj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(Hj)}].test(${j})) ${Z.fail("isULID")};`},f.String,{format:"ulid"})}const hj=/^[a-z][0-9a-z]{23,31}$/;function isCUID2(){return X("isCUID2",(j)=>hj.test(j),(j,Z)=>{return`if (!re[${Z.addRegex(hj)}].test(${j})) ${Z.fail("isCUID2")};`},f.String,{format:"cuid2"})}export{minLength,maxLength,length,contains,notContains,matches,isLowercase,isUppercase,isAscii,isAlpha,isAlphanumeric,isHttpToken,isOrigin,isCorsOrigin,isBooleanString,isNumberString,isDecimal,isFullWidth,isHalfWidth,isVariableWidth,isMultibyte,isSurrogatePair,isHexadecimal,isOctal,isEmail,isURL,isUUID,isIP,isHexColor,isRgbColor,isHSL,isMACAddress,isISBN,isISIN,isISO8601,isISRC,isISSN,isJWT,isLatLong,isLocale,isDataURI,isFQDN,isPort,isEAN,isISO31661Alpha2,isISO31661Alpha3,isBIC,isFirebasePushId,isSemVer,isMongoId,isJSON,isBase32,isBase58,isBase64,isDateString,isMimeType,isCurrency,isMagnetURI,isCreditCard,isIBAN,isByteLength,isHash,isRFC3339,isMilitaryTime,isLatitude,isLongitude,isEthereumAddress,isBtcAddress,isISO4217CurrencyCode,isPhoneNumber,isStrongPassword,isTaxId,isULID,isCUID2};
|