@page-speed/forms 0.1.4 → 0.1.6
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/README.md +1 -1
- package/dist/core.cjs +376 -21
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +356 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +376 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +356 -1
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +253 -0
- package/dist/inputs.cjs.map +1 -1
- package/dist/inputs.d.cts +77 -1
- package/dist/inputs.d.ts +77 -1
- package/dist/inputs.js +253 -1
- package/dist/inputs.js.map +1 -1
- package/dist/integration.cjs +243 -0
- package/dist/integration.cjs.map +1 -0
- package/dist/integration.d.cts +381 -0
- package/dist/integration.d.ts +381 -0
- package/dist/integration.js +217 -0
- package/dist/integration.js.map +1 -0
- package/dist/upload.cjs +348 -0
- package/dist/upload.cjs.map +1 -0
- package/dist/upload.d.cts +174 -0
- package/dist/upload.d.ts +174 -0
- package/dist/upload.js +326 -0
- package/dist/upload.js.map +1 -0
- package/dist/validation-rules.cjs +231 -75
- package/dist/validation-rules.cjs.map +1 -1
- package/dist/validation-rules.js +215 -1
- package/dist/validation-rules.js.map +1 -1
- package/dist/validation-utils.cjs +133 -43
- package/dist/validation-utils.cjs.map +1 -1
- package/dist/validation-utils.js +125 -1
- package/dist/validation-utils.js.map +1 -1
- package/dist/validation.cjs +364 -115
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.js +339 -2
- package/dist/validation.js.map +1 -1
- package/package.json +14 -4
- package/dist/chunk-2FXAQT7S.cjs +0 -236
- package/dist/chunk-2FXAQT7S.cjs.map +0 -1
- package/dist/chunk-A3UV7BIN.js +0 -357
- package/dist/chunk-A3UV7BIN.js.map +0 -1
- package/dist/chunk-P37YLBFA.cjs +0 -138
- package/dist/chunk-P37YLBFA.cjs.map +0 -1
- package/dist/chunk-WHQMBQNI.js +0 -127
- package/dist/chunk-WHQMBQNI.js.map +0 -1
- package/dist/chunk-YTTOWHBZ.js +0 -217
- package/dist/chunk-YTTOWHBZ.js.map +0 -1
- package/dist/chunk-ZQCPEOB6.cjs +0 -382
- package/dist/chunk-ZQCPEOB6.cjs.map +0 -1
|
@@ -1,80 +1,236 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// src/validation/rules.ts
|
|
4
|
+
function required(options = {}) {
|
|
5
|
+
const defaultMessage = "This field is required";
|
|
6
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
7
|
+
return (value) => {
|
|
8
|
+
if (value === void 0 || value === null || value === "") {
|
|
9
|
+
return message;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
12
|
+
return message;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
15
|
+
return message;
|
|
16
|
+
}
|
|
17
|
+
return void 0;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function email(options = {}) {
|
|
21
|
+
const defaultMessage = "Please enter a valid email address";
|
|
22
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
23
|
+
const emailRegex = /^[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])?)*$/;
|
|
24
|
+
return (value) => {
|
|
25
|
+
if (!value) return void 0;
|
|
26
|
+
if (typeof value !== "string") return message;
|
|
27
|
+
if (!emailRegex.test(value)) return message;
|
|
28
|
+
return void 0;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function url(options = {}) {
|
|
32
|
+
const defaultMessage = "Please enter a valid URL";
|
|
33
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
34
|
+
return (value) => {
|
|
35
|
+
if (!value) return void 0;
|
|
36
|
+
if (typeof value !== "string") return message;
|
|
37
|
+
try {
|
|
38
|
+
new URL(value);
|
|
39
|
+
return void 0;
|
|
40
|
+
} catch {
|
|
41
|
+
return message;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function phone(options = {}) {
|
|
46
|
+
const defaultMessage = "Please enter a valid phone number";
|
|
47
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
48
|
+
const phoneRegex = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
|
|
49
|
+
return (value) => {
|
|
50
|
+
if (!value) return void 0;
|
|
51
|
+
if (typeof value !== "string") return message;
|
|
52
|
+
const cleaned = value.replace(/[^\d+]/g, "");
|
|
53
|
+
if (!phoneRegex.test(cleaned)) return message;
|
|
54
|
+
return void 0;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function minLength(min2, options = {}) {
|
|
58
|
+
const defaultMessage = (p) => `Must be at least ${p.min} characters`;
|
|
59
|
+
const message = typeof options.message === "function" ? options.message({ min: min2 }) : options.message || defaultMessage({ min: min2 });
|
|
60
|
+
return (value) => {
|
|
61
|
+
if (!value) return void 0;
|
|
62
|
+
const length = Array.isArray(value) ? value.length : typeof value === "string" ? value.length : 0;
|
|
63
|
+
if (length < min2) return message;
|
|
64
|
+
return void 0;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function maxLength(max2, options = {}) {
|
|
68
|
+
const defaultMessage = (p) => `Must be no more than ${p.max} characters`;
|
|
69
|
+
const message = typeof options.message === "function" ? options.message({ max: max2 }) : options.message || defaultMessage({ max: max2 });
|
|
70
|
+
return (value) => {
|
|
71
|
+
if (!value) return void 0;
|
|
72
|
+
const length = Array.isArray(value) ? value.length : typeof value === "string" ? value.length : 0;
|
|
73
|
+
if (length > max2) return message;
|
|
74
|
+
return void 0;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function min(minValue, options = {}) {
|
|
78
|
+
const defaultMessage = (p) => `Must be at least ${p.min}`;
|
|
79
|
+
const message = typeof options.message === "function" ? options.message({ min: minValue }) : options.message || defaultMessage({ min: minValue });
|
|
80
|
+
return (value) => {
|
|
81
|
+
if (value === void 0 || value === null) return void 0;
|
|
82
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
83
|
+
if (isNaN(numValue) || numValue < minValue) return message;
|
|
84
|
+
return void 0;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function max(maxValue, options = {}) {
|
|
88
|
+
const defaultMessage = (p) => `Must be no more than ${p.max}`;
|
|
89
|
+
const message = typeof options.message === "function" ? options.message({ max: maxValue }) : options.message || defaultMessage({ max: maxValue });
|
|
90
|
+
return (value) => {
|
|
91
|
+
if (value === void 0 || value === null) return void 0;
|
|
92
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
93
|
+
if (isNaN(numValue) || numValue > maxValue) return message;
|
|
94
|
+
return void 0;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function pattern(regex, options = {}) {
|
|
98
|
+
const defaultMessage = "Invalid format";
|
|
99
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
100
|
+
return (value) => {
|
|
101
|
+
if (!value) return void 0;
|
|
102
|
+
if (typeof value !== "string") return message;
|
|
103
|
+
if (!regex.test(value)) return message;
|
|
104
|
+
return void 0;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function matches(fieldName, options = {}) {
|
|
108
|
+
const defaultMessage = (p) => `Must match ${p.field}`;
|
|
109
|
+
const message = typeof options.message === "function" ? options.message({ field: fieldName }) : options.message || defaultMessage({ field: fieldName });
|
|
110
|
+
return (value, allValues) => {
|
|
111
|
+
const otherValue = allValues[fieldName];
|
|
112
|
+
if (value !== otherValue) return message;
|
|
113
|
+
return void 0;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function oneOf(allowedValues, options = {}) {
|
|
117
|
+
const defaultMessage = "Invalid value";
|
|
118
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
119
|
+
return (value) => {
|
|
120
|
+
if (!value) return void 0;
|
|
121
|
+
if (!allowedValues.includes(value)) return message;
|
|
122
|
+
return void 0;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function creditCard(options = {}) {
|
|
126
|
+
const defaultMessage = "Please enter a valid credit card number";
|
|
127
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
128
|
+
const luhnCheck = (num) => {
|
|
129
|
+
let sum = 0;
|
|
130
|
+
let isEven = false;
|
|
131
|
+
for (let i = num.length - 1; i >= 0; i--) {
|
|
132
|
+
let digit = parseInt(num[i], 10);
|
|
133
|
+
if (isEven) {
|
|
134
|
+
digit *= 2;
|
|
135
|
+
if (digit > 9) {
|
|
136
|
+
digit -= 9;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
sum += digit;
|
|
140
|
+
isEven = !isEven;
|
|
141
|
+
}
|
|
142
|
+
return sum % 10 === 0;
|
|
143
|
+
};
|
|
144
|
+
return (value) => {
|
|
145
|
+
if (!value) return void 0;
|
|
146
|
+
if (typeof value !== "string") return message;
|
|
147
|
+
const cleaned = value.replace(/[\s-]/g, "");
|
|
148
|
+
if (!/^\d+$/.test(cleaned)) return message;
|
|
149
|
+
if (cleaned.length < 13 || cleaned.length > 19) return message;
|
|
150
|
+
if (!luhnCheck(cleaned)) return message;
|
|
151
|
+
return void 0;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function postalCode(options = {}) {
|
|
155
|
+
const defaultMessage = "Please enter a valid ZIP code";
|
|
156
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
157
|
+
const zipRegex = /^\d{5}(-\d{4})?$/;
|
|
158
|
+
return (value) => {
|
|
159
|
+
if (!value) return void 0;
|
|
160
|
+
if (typeof value !== "string") return message;
|
|
161
|
+
if (!zipRegex.test(value)) return message;
|
|
162
|
+
return void 0;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function alpha(options = {}) {
|
|
166
|
+
const defaultMessage = "Must contain only letters";
|
|
167
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
168
|
+
const alphaRegex = /^[a-zA-Z]+$/;
|
|
169
|
+
return (value) => {
|
|
170
|
+
if (!value) return void 0;
|
|
171
|
+
if (typeof value !== "string") return message;
|
|
172
|
+
if (!alphaRegex.test(value)) return message;
|
|
173
|
+
return void 0;
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function alphanumeric(options = {}) {
|
|
177
|
+
const defaultMessage = "Must contain only letters and numbers";
|
|
178
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
179
|
+
const alphanumericRegex = /^[a-zA-Z0-9]+$/;
|
|
180
|
+
return (value) => {
|
|
181
|
+
if (!value) return void 0;
|
|
182
|
+
if (typeof value !== "string") return message;
|
|
183
|
+
if (!alphanumericRegex.test(value)) return message;
|
|
184
|
+
return void 0;
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function numeric(options = {}) {
|
|
188
|
+
const defaultMessage = "Must be a valid number";
|
|
189
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
190
|
+
return (value) => {
|
|
191
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
192
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
193
|
+
if (isNaN(numValue)) return message;
|
|
194
|
+
return void 0;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function integer(options = {}) {
|
|
198
|
+
const defaultMessage = "Must be a whole number";
|
|
199
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
200
|
+
return (value) => {
|
|
201
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
202
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
203
|
+
if (isNaN(numValue) || !Number.isInteger(numValue)) return message;
|
|
204
|
+
return void 0;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function compose(...validators) {
|
|
208
|
+
return async (value, allValues) => {
|
|
209
|
+
for (const validator of validators) {
|
|
210
|
+
const error = await validator(value, allValues);
|
|
211
|
+
if (error) return error;
|
|
212
|
+
}
|
|
213
|
+
return void 0;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
4
216
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Object.defineProperty(exports, "email", {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
get: function () { return chunk2FXAQT7S_cjs.email; }
|
|
26
|
-
});
|
|
27
|
-
Object.defineProperty(exports, "integer", {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: function () { return chunk2FXAQT7S_cjs.integer; }
|
|
30
|
-
});
|
|
31
|
-
Object.defineProperty(exports, "matches", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
get: function () { return chunk2FXAQT7S_cjs.matches; }
|
|
34
|
-
});
|
|
35
|
-
Object.defineProperty(exports, "max", {
|
|
36
|
-
enumerable: true,
|
|
37
|
-
get: function () { return chunk2FXAQT7S_cjs.max; }
|
|
38
|
-
});
|
|
39
|
-
Object.defineProperty(exports, "maxLength", {
|
|
40
|
-
enumerable: true,
|
|
41
|
-
get: function () { return chunk2FXAQT7S_cjs.maxLength; }
|
|
42
|
-
});
|
|
43
|
-
Object.defineProperty(exports, "min", {
|
|
44
|
-
enumerable: true,
|
|
45
|
-
get: function () { return chunk2FXAQT7S_cjs.min; }
|
|
46
|
-
});
|
|
47
|
-
Object.defineProperty(exports, "minLength", {
|
|
48
|
-
enumerable: true,
|
|
49
|
-
get: function () { return chunk2FXAQT7S_cjs.minLength; }
|
|
50
|
-
});
|
|
51
|
-
Object.defineProperty(exports, "numeric", {
|
|
52
|
-
enumerable: true,
|
|
53
|
-
get: function () { return chunk2FXAQT7S_cjs.numeric; }
|
|
54
|
-
});
|
|
55
|
-
Object.defineProperty(exports, "oneOf", {
|
|
56
|
-
enumerable: true,
|
|
57
|
-
get: function () { return chunk2FXAQT7S_cjs.oneOf; }
|
|
58
|
-
});
|
|
59
|
-
Object.defineProperty(exports, "pattern", {
|
|
60
|
-
enumerable: true,
|
|
61
|
-
get: function () { return chunk2FXAQT7S_cjs.pattern; }
|
|
62
|
-
});
|
|
63
|
-
Object.defineProperty(exports, "phone", {
|
|
64
|
-
enumerable: true,
|
|
65
|
-
get: function () { return chunk2FXAQT7S_cjs.phone; }
|
|
66
|
-
});
|
|
67
|
-
Object.defineProperty(exports, "postalCode", {
|
|
68
|
-
enumerable: true,
|
|
69
|
-
get: function () { return chunk2FXAQT7S_cjs.postalCode; }
|
|
70
|
-
});
|
|
71
|
-
Object.defineProperty(exports, "required", {
|
|
72
|
-
enumerable: true,
|
|
73
|
-
get: function () { return chunk2FXAQT7S_cjs.required; }
|
|
74
|
-
});
|
|
75
|
-
Object.defineProperty(exports, "url", {
|
|
76
|
-
enumerable: true,
|
|
77
|
-
get: function () { return chunk2FXAQT7S_cjs.url; }
|
|
78
|
-
});
|
|
217
|
+
exports.alpha = alpha;
|
|
218
|
+
exports.alphanumeric = alphanumeric;
|
|
219
|
+
exports.compose = compose;
|
|
220
|
+
exports.creditCard = creditCard;
|
|
221
|
+
exports.email = email;
|
|
222
|
+
exports.integer = integer;
|
|
223
|
+
exports.matches = matches;
|
|
224
|
+
exports.max = max;
|
|
225
|
+
exports.maxLength = maxLength;
|
|
226
|
+
exports.min = min;
|
|
227
|
+
exports.minLength = minLength;
|
|
228
|
+
exports.numeric = numeric;
|
|
229
|
+
exports.oneOf = oneOf;
|
|
230
|
+
exports.pattern = pattern;
|
|
231
|
+
exports.phone = phone;
|
|
232
|
+
exports.postalCode = postalCode;
|
|
233
|
+
exports.required = required;
|
|
234
|
+
exports.url = url;
|
|
79
235
|
//# sourceMappingURL=validation-rules.cjs.map
|
|
80
236
|
//# sourceMappingURL=validation-rules.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"validation-rules.cjs"}
|
|
1
|
+
{"version":3,"sources":["../src/validation/rules.ts"],"names":["min","max"],"mappings":"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","file":"validation-rules.cjs","sourcesContent":["/**\n * @page-speed/forms - Validation Rules\n *\n * Common validation rules for form fields.\n * Tree-shakable - import only the rules you need.\n *\n * @example\n * ```tsx\n * import { required, email, minLength } from '@page-speed/forms/validation/rules';\n *\n * const form = useForm({\n * validationSchema: {\n * email: [required(), email()],\n * password: [required(), minLength(8)],\n * }\n * });\n * ```\n */\n\nimport type { FieldValidator } from \"../core/types\";\n\n/**\n * Error message template function\n * Allows customization of error messages\n */\nexport type ErrorMessageFn = (params?: Record<string, any>) => string;\n\n/**\n * Validation rule options\n */\nexport interface ValidationRuleOptions {\n /**\n * Custom error message\n */\n message?: string | ErrorMessageFn;\n}\n\n/**\n * Required field validator\n * Ensures field has a truthy value\n */\nexport function required(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"This field is required\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") {\n return message;\n }\n\n // Check for empty arrays\n if (Array.isArray(value) && value.length === 0) {\n return message;\n }\n\n // Check for empty objects\n if (\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.keys(value).length === 0\n ) {\n return message;\n }\n\n return undefined;\n };\n}\n\n/**\n * Email validator\n * Validates email format using RFC 5322 compatible regex\n */\nexport function email(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid email address\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // RFC 5322 simplified email regex\n const emailRegex =\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])?)*$/;\n\n return (value) => {\n if (!value) return undefined; // Use with required() if needed\n if (typeof value !== \"string\") return message;\n if (!emailRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * URL validator\n * Validates URL format\n */\nexport function url(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid URL\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined; // Use with required() if needed\n if (typeof value !== \"string\") return message;\n\n try {\n new URL(value);\n return undefined;\n } catch {\n return message;\n }\n };\n}\n\n/**\n * Phone number validator\n * Validates US phone numbers (flexible formats)\n */\nexport function phone(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid phone number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // Matches: (123) 456-7890, 123-456-7890, 1234567890, +1 123 456 7890\n const phoneRegex = /^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n\n // Remove all non-numeric characters except +\n const cleaned = value.replace(/[^\\d+]/g, \"\");\n\n if (!phoneRegex.test(cleaned)) return message;\n return undefined;\n };\n}\n\n/**\n * Minimum length validator\n */\nexport function minLength(\n min: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { min: number }) =>\n `Must be at least ${p.min} characters`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ min })\n : options.message || defaultMessage({ min });\n\n return (value) => {\n if (!value) return undefined;\n\n const length = Array.isArray(value)\n ? value.length\n : typeof value === \"string\"\n ? value.length\n : 0;\n\n if (length < min) return message;\n return undefined;\n };\n}\n\n/**\n * Maximum length validator\n */\nexport function maxLength(\n max: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { max: number }) =>\n `Must be no more than ${p.max} characters`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ max })\n : options.message || defaultMessage({ max });\n\n return (value) => {\n if (!value) return undefined;\n\n const length = Array.isArray(value)\n ? value.length\n : typeof value === \"string\"\n ? value.length\n : 0;\n\n if (length > max) return message;\n return undefined;\n };\n}\n\n/**\n * Minimum value validator (for numbers)\n */\nexport function min(\n minValue: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { min: number }) =>\n `Must be at least ${p.min}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ min: minValue })\n : options.message || defaultMessage({ min: minValue });\n\n return (value) => {\n if (value === undefined || value === null) return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || numValue < minValue) return message;\n return undefined;\n };\n}\n\n/**\n * Maximum value validator (for numbers)\n */\nexport function max(\n maxValue: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { max: number }) =>\n `Must be no more than ${p.max}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ max: maxValue })\n : options.message || defaultMessage({ max: maxValue });\n\n return (value) => {\n if (value === undefined || value === null) return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || numValue > maxValue) return message;\n return undefined;\n };\n}\n\n/**\n * Pattern validator\n * Validates against a regular expression\n */\nexport function pattern(\n regex: RegExp,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Invalid format\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!regex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Match validator\n * Ensures field matches another field (e.g., password confirmation)\n */\nexport function matches(\n fieldName: string,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { field: string }) =>\n `Must match ${p.field}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ field: fieldName })\n : options.message || defaultMessage({ field: fieldName });\n\n return (value, allValues) => {\n const otherValue = allValues[fieldName];\n if (value !== otherValue) return message;\n return undefined;\n };\n}\n\n/**\n * One of validator\n * Ensures value is one of the allowed values\n */\nexport function oneOf<T = any>(\n allowedValues: T[],\n options: ValidationRuleOptions = {}\n): FieldValidator<T> {\n const defaultMessage = \"Invalid value\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined;\n if (!allowedValues.includes(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Credit card validator\n * Validates credit card numbers using Luhn algorithm\n */\nexport function creditCard(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Please enter a valid credit card number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const luhnCheck = (num: string): boolean => {\n let sum = 0;\n let isEven = false;\n\n for (let i = num.length - 1; i >= 0; i--) {\n let digit = parseInt(num[i], 10);\n\n if (isEven) {\n digit *= 2;\n if (digit > 9) {\n digit -= 9;\n }\n }\n\n sum += digit;\n isEven = !isEven;\n }\n\n return sum % 10 === 0;\n };\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n\n // Remove spaces and dashes\n const cleaned = value.replace(/[\\s-]/g, \"\");\n\n // Check if only digits\n if (!/^\\d+$/.test(cleaned)) return message;\n\n // Check length (13-19 digits for most cards)\n if (cleaned.length < 13 || cleaned.length > 19) return message;\n\n // Luhn algorithm check\n if (!luhnCheck(cleaned)) return message;\n\n return undefined;\n };\n}\n\n/**\n * Postal code validator (US ZIP codes)\n */\nexport function postalCode(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Please enter a valid ZIP code\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // Matches: 12345 or 12345-6789\n const zipRegex = /^\\d{5}(-\\d{4})?$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!zipRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Alpha validator\n * Ensures value contains only alphabetic characters\n */\nexport function alpha(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must contain only letters\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const alphaRegex = /^[a-zA-Z]+$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!alphaRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Alphanumeric validator\n * Ensures value contains only letters and numbers\n */\nexport function alphanumeric(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Must contain only letters and numbers\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const alphanumericRegex = /^[a-zA-Z0-9]+$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!alphanumericRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Numeric validator\n * Ensures value is a valid number\n */\nexport function numeric(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must be a valid number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue)) return message;\n return undefined;\n };\n}\n\n/**\n * Integer validator\n * Ensures value is a valid integer\n */\nexport function integer(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must be a whole number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || !Number.isInteger(numValue)) return message;\n return undefined;\n };\n}\n\n/**\n * Compose multiple validators\n * Runs validators in sequence and returns first error\n */\nexport function compose(\n ...validators: FieldValidator[]\n): FieldValidator {\n return async (value, allValues) => {\n for (const validator of validators) {\n const error = await validator(value, allValues);\n if (error) return error;\n }\n return undefined;\n };\n}\n"]}
|
package/dist/validation-rules.js
CHANGED
|
@@ -1,3 +1,217 @@
|
|
|
1
|
-
|
|
1
|
+
// src/validation/rules.ts
|
|
2
|
+
function required(options = {}) {
|
|
3
|
+
const defaultMessage = "This field is required";
|
|
4
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
5
|
+
return (value) => {
|
|
6
|
+
if (value === void 0 || value === null || value === "") {
|
|
7
|
+
return message;
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
10
|
+
return message;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
13
|
+
return message;
|
|
14
|
+
}
|
|
15
|
+
return void 0;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function email(options = {}) {
|
|
19
|
+
const defaultMessage = "Please enter a valid email address";
|
|
20
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
21
|
+
const emailRegex = /^[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])?)*$/;
|
|
22
|
+
return (value) => {
|
|
23
|
+
if (!value) return void 0;
|
|
24
|
+
if (typeof value !== "string") return message;
|
|
25
|
+
if (!emailRegex.test(value)) return message;
|
|
26
|
+
return void 0;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function url(options = {}) {
|
|
30
|
+
const defaultMessage = "Please enter a valid URL";
|
|
31
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
32
|
+
return (value) => {
|
|
33
|
+
if (!value) return void 0;
|
|
34
|
+
if (typeof value !== "string") return message;
|
|
35
|
+
try {
|
|
36
|
+
new URL(value);
|
|
37
|
+
return void 0;
|
|
38
|
+
} catch {
|
|
39
|
+
return message;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function phone(options = {}) {
|
|
44
|
+
const defaultMessage = "Please enter a valid phone number";
|
|
45
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
46
|
+
const phoneRegex = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
|
|
47
|
+
return (value) => {
|
|
48
|
+
if (!value) return void 0;
|
|
49
|
+
if (typeof value !== "string") return message;
|
|
50
|
+
const cleaned = value.replace(/[^\d+]/g, "");
|
|
51
|
+
if (!phoneRegex.test(cleaned)) return message;
|
|
52
|
+
return void 0;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function minLength(min2, options = {}) {
|
|
56
|
+
const defaultMessage = (p) => `Must be at least ${p.min} characters`;
|
|
57
|
+
const message = typeof options.message === "function" ? options.message({ min: min2 }) : options.message || defaultMessage({ min: min2 });
|
|
58
|
+
return (value) => {
|
|
59
|
+
if (!value) return void 0;
|
|
60
|
+
const length = Array.isArray(value) ? value.length : typeof value === "string" ? value.length : 0;
|
|
61
|
+
if (length < min2) return message;
|
|
62
|
+
return void 0;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function maxLength(max2, options = {}) {
|
|
66
|
+
const defaultMessage = (p) => `Must be no more than ${p.max} characters`;
|
|
67
|
+
const message = typeof options.message === "function" ? options.message({ max: max2 }) : options.message || defaultMessage({ max: max2 });
|
|
68
|
+
return (value) => {
|
|
69
|
+
if (!value) return void 0;
|
|
70
|
+
const length = Array.isArray(value) ? value.length : typeof value === "string" ? value.length : 0;
|
|
71
|
+
if (length > max2) return message;
|
|
72
|
+
return void 0;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function min(minValue, options = {}) {
|
|
76
|
+
const defaultMessage = (p) => `Must be at least ${p.min}`;
|
|
77
|
+
const message = typeof options.message === "function" ? options.message({ min: minValue }) : options.message || defaultMessage({ min: minValue });
|
|
78
|
+
return (value) => {
|
|
79
|
+
if (value === void 0 || value === null) return void 0;
|
|
80
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
81
|
+
if (isNaN(numValue) || numValue < minValue) return message;
|
|
82
|
+
return void 0;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function max(maxValue, options = {}) {
|
|
86
|
+
const defaultMessage = (p) => `Must be no more than ${p.max}`;
|
|
87
|
+
const message = typeof options.message === "function" ? options.message({ max: maxValue }) : options.message || defaultMessage({ max: maxValue });
|
|
88
|
+
return (value) => {
|
|
89
|
+
if (value === void 0 || value === null) return void 0;
|
|
90
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
91
|
+
if (isNaN(numValue) || numValue > maxValue) return message;
|
|
92
|
+
return void 0;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function pattern(regex, options = {}) {
|
|
96
|
+
const defaultMessage = "Invalid format";
|
|
97
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
98
|
+
return (value) => {
|
|
99
|
+
if (!value) return void 0;
|
|
100
|
+
if (typeof value !== "string") return message;
|
|
101
|
+
if (!regex.test(value)) return message;
|
|
102
|
+
return void 0;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function matches(fieldName, options = {}) {
|
|
106
|
+
const defaultMessage = (p) => `Must match ${p.field}`;
|
|
107
|
+
const message = typeof options.message === "function" ? options.message({ field: fieldName }) : options.message || defaultMessage({ field: fieldName });
|
|
108
|
+
return (value, allValues) => {
|
|
109
|
+
const otherValue = allValues[fieldName];
|
|
110
|
+
if (value !== otherValue) return message;
|
|
111
|
+
return void 0;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function oneOf(allowedValues, options = {}) {
|
|
115
|
+
const defaultMessage = "Invalid value";
|
|
116
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
117
|
+
return (value) => {
|
|
118
|
+
if (!value) return void 0;
|
|
119
|
+
if (!allowedValues.includes(value)) return message;
|
|
120
|
+
return void 0;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function creditCard(options = {}) {
|
|
124
|
+
const defaultMessage = "Please enter a valid credit card number";
|
|
125
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
126
|
+
const luhnCheck = (num) => {
|
|
127
|
+
let sum = 0;
|
|
128
|
+
let isEven = false;
|
|
129
|
+
for (let i = num.length - 1; i >= 0; i--) {
|
|
130
|
+
let digit = parseInt(num[i], 10);
|
|
131
|
+
if (isEven) {
|
|
132
|
+
digit *= 2;
|
|
133
|
+
if (digit > 9) {
|
|
134
|
+
digit -= 9;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
sum += digit;
|
|
138
|
+
isEven = !isEven;
|
|
139
|
+
}
|
|
140
|
+
return sum % 10 === 0;
|
|
141
|
+
};
|
|
142
|
+
return (value) => {
|
|
143
|
+
if (!value) return void 0;
|
|
144
|
+
if (typeof value !== "string") return message;
|
|
145
|
+
const cleaned = value.replace(/[\s-]/g, "");
|
|
146
|
+
if (!/^\d+$/.test(cleaned)) return message;
|
|
147
|
+
if (cleaned.length < 13 || cleaned.length > 19) return message;
|
|
148
|
+
if (!luhnCheck(cleaned)) return message;
|
|
149
|
+
return void 0;
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function postalCode(options = {}) {
|
|
153
|
+
const defaultMessage = "Please enter a valid ZIP code";
|
|
154
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
155
|
+
const zipRegex = /^\d{5}(-\d{4})?$/;
|
|
156
|
+
return (value) => {
|
|
157
|
+
if (!value) return void 0;
|
|
158
|
+
if (typeof value !== "string") return message;
|
|
159
|
+
if (!zipRegex.test(value)) return message;
|
|
160
|
+
return void 0;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function alpha(options = {}) {
|
|
164
|
+
const defaultMessage = "Must contain only letters";
|
|
165
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
166
|
+
const alphaRegex = /^[a-zA-Z]+$/;
|
|
167
|
+
return (value) => {
|
|
168
|
+
if (!value) return void 0;
|
|
169
|
+
if (typeof value !== "string") return message;
|
|
170
|
+
if (!alphaRegex.test(value)) return message;
|
|
171
|
+
return void 0;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function alphanumeric(options = {}) {
|
|
175
|
+
const defaultMessage = "Must contain only letters and numbers";
|
|
176
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
177
|
+
const alphanumericRegex = /^[a-zA-Z0-9]+$/;
|
|
178
|
+
return (value) => {
|
|
179
|
+
if (!value) return void 0;
|
|
180
|
+
if (typeof value !== "string") return message;
|
|
181
|
+
if (!alphanumericRegex.test(value)) return message;
|
|
182
|
+
return void 0;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function numeric(options = {}) {
|
|
186
|
+
const defaultMessage = "Must be a valid number";
|
|
187
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
188
|
+
return (value) => {
|
|
189
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
190
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
191
|
+
if (isNaN(numValue)) return message;
|
|
192
|
+
return void 0;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function integer(options = {}) {
|
|
196
|
+
const defaultMessage = "Must be a whole number";
|
|
197
|
+
const message = typeof options.message === "function" ? options.message() : options.message || defaultMessage;
|
|
198
|
+
return (value) => {
|
|
199
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
200
|
+
const numValue = typeof value === "number" ? value : parseFloat(value);
|
|
201
|
+
if (isNaN(numValue) || !Number.isInteger(numValue)) return message;
|
|
202
|
+
return void 0;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function compose(...validators) {
|
|
206
|
+
return async (value, allValues) => {
|
|
207
|
+
for (const validator of validators) {
|
|
208
|
+
const error = await validator(value, allValues);
|
|
209
|
+
if (error) return error;
|
|
210
|
+
}
|
|
211
|
+
return void 0;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export { alpha, alphanumeric, compose, creditCard, email, integer, matches, max, maxLength, min, minLength, numeric, oneOf, pattern, phone, postalCode, required, url };
|
|
2
216
|
//# sourceMappingURL=validation-rules.js.map
|
|
3
217
|
//# sourceMappingURL=validation-rules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"validation-rules.js"}
|
|
1
|
+
{"version":3,"sources":["../src/validation/rules.ts"],"names":["min","max"],"mappings":";AAyCO,SAAS,QAAA,CACd,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,wBAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,UAAU,EAAA,EAAI;AACzD,MAAA,OAAO,OAAA;AAAA,IACT;AAGA,IAAA,IAAI,MAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AAC9C,MAAA,OAAO,OAAA;AAAA,IACT;AAGA,IAAA,IACE,OAAO,KAAA,KAAU,QAAA,IACjB,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IACpB,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,CAAE,WAAW,CAAA,EAC9B;AACA,MAAA,OAAO,OAAA;AAAA,IACT;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,KAAA,CAAM,OAAA,GAAiC,EAAC,EAAmB;AACzE,EAAA,MAAM,cAAA,GAAiB,oCAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAGzB,EAAA,MAAM,UAAA,GACJ,sIAAA;AAEF,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,KAAK,GAAG,OAAO,OAAA;AACpC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,GAAA,CAAI,OAAA,GAAiC,EAAC,EAAmB;AACvE,EAAA,MAAM,cAAA,GAAiB,0BAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AAEtC,IAAA,IAAI;AACF,MAAA,IAAI,IAAI,KAAK,CAAA;AACb,MAAA,OAAO,KAAA,CAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,EACF,CAAA;AACF;AAMO,SAAS,KAAA,CAAM,OAAA,GAAiC,EAAC,EAAmB;AACzE,EAAA,MAAM,cAAA,GAAiB,mCAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAGzB,EAAA,MAAM,UAAA,GAAa,2DAAA;AAEnB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AAGtC,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AAE3C,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,OAAO,GAAG,OAAO,OAAA;AACtC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAKO,SAAS,SAAA,CACdA,IAAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KACtB,CAAA,iBAAA,EAAoB,EAAE,GAAG,CAAA,WAAA,CAAA;AAC3B,EAAA,MAAM,UACJ,OAAO,OAAA,CAAQ,YAAY,UAAA,GACvB,OAAA,CAAQ,QAAQ,EAAE,GAAA,EAAAA,IAAAA,EAAK,IACvB,OAAA,CAAQ,OAAA,IAAW,eAAe,EAAE,GAAA,EAAAA,MAAK,CAAA;AAE/C,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAC9B,KAAA,CAAM,MAAA,GACN,OAAO,KAAA,KAAU,QAAA,GACf,KAAA,CAAM,MAAA,GACN,CAAA;AAEN,IAAA,IAAI,MAAA,GAASA,MAAK,OAAO,OAAA;AACzB,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAKO,SAAS,SAAA,CACdC,IAAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KACtB,CAAA,qBAAA,EAAwB,EAAE,GAAG,CAAA,WAAA,CAAA;AAC/B,EAAA,MAAM,UACJ,OAAO,OAAA,CAAQ,YAAY,UAAA,GACvB,OAAA,CAAQ,QAAQ,EAAE,GAAA,EAAAA,IAAAA,EAAK,IACvB,OAAA,CAAQ,OAAA,IAAW,eAAe,EAAE,GAAA,EAAAA,MAAK,CAAA;AAE/C,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAC9B,KAAA,CAAM,MAAA,GACN,OAAO,KAAA,KAAU,QAAA,GACf,KAAA,CAAM,MAAA,GACN,CAAA;AAEN,IAAA,IAAI,MAAA,GAASA,MAAK,OAAO,OAAA;AACzB,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAKO,SAAS,GAAA,CACd,QAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KACtB,CAAA,iBAAA,EAAoB,EAAE,GAAG,CAAA,CAAA;AAC3B,EAAA,MAAM,UACJ,OAAO,OAAA,CAAQ,YAAY,UAAA,GACvB,OAAA,CAAQ,QAAQ,EAAE,GAAA,EAAK,QAAA,EAAU,IACjC,OAAA,CAAQ,OAAA,IAAW,eAAe,EAAE,GAAA,EAAK,UAAU,CAAA;AAEzD,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,OAAO,MAAA;AAElD,IAAA,MAAM,WAAW,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,WAAW,KAAK,CAAA;AAErE,IAAA,IAAI,KAAA,CAAM,QAAQ,CAAA,IAAK,QAAA,GAAW,UAAU,OAAO,OAAA;AACnD,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAKO,SAAS,GAAA,CACd,QAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KACtB,CAAA,qBAAA,EAAwB,EAAE,GAAG,CAAA,CAAA;AAC/B,EAAA,MAAM,UACJ,OAAO,OAAA,CAAQ,YAAY,UAAA,GACvB,OAAA,CAAQ,QAAQ,EAAE,GAAA,EAAK,QAAA,EAAU,IACjC,OAAA,CAAQ,OAAA,IAAW,eAAe,EAAE,GAAA,EAAK,UAAU,CAAA;AAEzD,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,OAAO,MAAA;AAElD,IAAA,MAAM,WAAW,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,WAAW,KAAK,CAAA;AAErE,IAAA,IAAI,KAAA,CAAM,QAAQ,CAAA,IAAK,QAAA,GAAW,UAAU,OAAO,OAAA;AACnD,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,OAAA,CACd,KAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,gBAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AACtC,IAAA,IAAI,CAAC,KAAA,CAAM,IAAA,CAAK,KAAK,GAAG,OAAO,OAAA;AAC/B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,OAAA,CACd,SAAA,EACA,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KACtB,CAAA,WAAA,EAAc,EAAE,KAAK,CAAA,CAAA;AACvB,EAAA,MAAM,UACJ,OAAO,OAAA,CAAQ,YAAY,UAAA,GACvB,OAAA,CAAQ,QAAQ,EAAE,KAAA,EAAO,SAAA,EAAW,IACpC,OAAA,CAAQ,OAAA,IAAW,eAAe,EAAE,KAAA,EAAO,WAAW,CAAA;AAE5D,EAAA,OAAO,CAAC,OAAO,SAAA,KAAc;AAC3B,IAAA,MAAM,UAAA,GAAa,UAAU,SAAS,CAAA;AACtC,IAAA,IAAI,KAAA,KAAU,YAAY,OAAO,OAAA;AACjC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,KAAA,CACd,aAAA,EACA,OAAA,GAAiC,EAAC,EACf;AACnB,EAAA,MAAM,cAAA,GAAiB,eAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,CAAC,aAAA,CAAc,QAAA,CAAS,KAAK,GAAG,OAAO,OAAA;AAC3C,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,UAAA,CACd,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,yCAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,MAAM,SAAA,GAAY,CAAC,GAAA,KAAyB;AAC1C,IAAA,IAAI,GAAA,GAAM,CAAA;AACV,IAAA,IAAI,MAAA,GAAS,KAAA;AAEb,IAAA,KAAA,IAAS,IAAI,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACxC,MAAA,IAAI,KAAA,GAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,GAAG,EAAE,CAAA;AAE/B,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,KAAA,IAAS,CAAA;AACT,QAAA,IAAI,QAAQ,CAAA,EAAG;AACb,UAAA,KAAA,IAAS,CAAA;AAAA,QACX;AAAA,MACF;AAEA,MAAA,GAAA,IAAO,KAAA;AACP,MAAA,MAAA,GAAS,CAAC,MAAA;AAAA,IACZ;AAEA,IAAA,OAAO,MAAM,EAAA,KAAO,CAAA;AAAA,EACtB,CAAA;AAEA,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AAGtC,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AAG1C,IAAA,IAAI,CAAC,OAAA,CAAQ,IAAA,CAAK,OAAO,GAAG,OAAO,OAAA;AAGnC,IAAA,IAAI,QAAQ,MAAA,GAAS,EAAA,IAAM,OAAA,CAAQ,MAAA,GAAS,IAAI,OAAO,OAAA;AAGvD,IAAA,IAAI,CAAC,SAAA,CAAU,OAAO,CAAA,EAAG,OAAO,OAAA;AAEhC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAKO,SAAS,UAAA,CACd,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,+BAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAGzB,EAAA,MAAM,QAAA,GAAW,kBAAA;AAEjB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AACtC,IAAA,IAAI,CAAC,QAAA,CAAS,IAAA,CAAK,KAAK,GAAG,OAAO,OAAA;AAClC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,KAAA,CAAM,OAAA,GAAiC,EAAC,EAAmB;AACzE,EAAA,MAAM,cAAA,GAAiB,2BAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,MAAM,UAAA,GAAa,aAAA;AAEnB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,KAAK,GAAG,OAAO,OAAA;AACpC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,YAAA,CACd,OAAA,GAAiC,EAAC,EAClB;AAChB,EAAA,MAAM,cAAA,GAAiB,uCAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,MAAM,iBAAA,GAAoB,gBAAA;AAE1B,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,OAAA;AACtC,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,KAAK,GAAG,OAAO,OAAA;AAC3C,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,OAAA,CAAQ,OAAA,GAAiC,EAAC,EAAmB;AAC3E,EAAA,MAAM,cAAA,GAAiB,wBAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,IAAI,OAAO,MAAA;AAElE,IAAA,MAAM,WAAW,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,WAAW,KAAK,CAAA;AAErE,IAAA,IAAI,KAAA,CAAM,QAAQ,CAAA,EAAG,OAAO,OAAA;AAC5B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,OAAA,CAAQ,OAAA,GAAiC,EAAC,EAAmB;AAC3E,EAAA,MAAM,cAAA,GAAiB,wBAAA;AACvB,EAAA,MAAM,OAAA,GACJ,OAAO,OAAA,CAAQ,OAAA,KAAY,aACvB,OAAA,CAAQ,OAAA,EAAQ,GAChB,OAAA,CAAQ,OAAA,IAAW,cAAA;AAEzB,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,IAAI,OAAO,MAAA;AAElE,IAAA,MAAM,WAAW,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,WAAW,KAAK,CAAA;AAErE,IAAA,IAAI,KAAA,CAAM,QAAQ,CAAA,IAAK,CAAC,OAAO,SAAA,CAAU,QAAQ,GAAG,OAAO,OAAA;AAC3D,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;AAMO,SAAS,WACX,UAAA,EACa;AAChB,EAAA,OAAO,OAAO,OAAO,SAAA,KAAc;AACjC,IAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,MAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,KAAA,EAAO,SAAS,CAAA;AAC9C,MAAA,IAAI,OAAO,OAAO,KAAA;AAAA,IACpB;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF","file":"validation-rules.js","sourcesContent":["/**\n * @page-speed/forms - Validation Rules\n *\n * Common validation rules for form fields.\n * Tree-shakable - import only the rules you need.\n *\n * @example\n * ```tsx\n * import { required, email, minLength } from '@page-speed/forms/validation/rules';\n *\n * const form = useForm({\n * validationSchema: {\n * email: [required(), email()],\n * password: [required(), minLength(8)],\n * }\n * });\n * ```\n */\n\nimport type { FieldValidator } from \"../core/types\";\n\n/**\n * Error message template function\n * Allows customization of error messages\n */\nexport type ErrorMessageFn = (params?: Record<string, any>) => string;\n\n/**\n * Validation rule options\n */\nexport interface ValidationRuleOptions {\n /**\n * Custom error message\n */\n message?: string | ErrorMessageFn;\n}\n\n/**\n * Required field validator\n * Ensures field has a truthy value\n */\nexport function required(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"This field is required\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") {\n return message;\n }\n\n // Check for empty arrays\n if (Array.isArray(value) && value.length === 0) {\n return message;\n }\n\n // Check for empty objects\n if (\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.keys(value).length === 0\n ) {\n return message;\n }\n\n return undefined;\n };\n}\n\n/**\n * Email validator\n * Validates email format using RFC 5322 compatible regex\n */\nexport function email(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid email address\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // RFC 5322 simplified email regex\n const emailRegex =\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])?)*$/;\n\n return (value) => {\n if (!value) return undefined; // Use with required() if needed\n if (typeof value !== \"string\") return message;\n if (!emailRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * URL validator\n * Validates URL format\n */\nexport function url(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid URL\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined; // Use with required() if needed\n if (typeof value !== \"string\") return message;\n\n try {\n new URL(value);\n return undefined;\n } catch {\n return message;\n }\n };\n}\n\n/**\n * Phone number validator\n * Validates US phone numbers (flexible formats)\n */\nexport function phone(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Please enter a valid phone number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // Matches: (123) 456-7890, 123-456-7890, 1234567890, +1 123 456 7890\n const phoneRegex = /^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n\n // Remove all non-numeric characters except +\n const cleaned = value.replace(/[^\\d+]/g, \"\");\n\n if (!phoneRegex.test(cleaned)) return message;\n return undefined;\n };\n}\n\n/**\n * Minimum length validator\n */\nexport function minLength(\n min: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { min: number }) =>\n `Must be at least ${p.min} characters`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ min })\n : options.message || defaultMessage({ min });\n\n return (value) => {\n if (!value) return undefined;\n\n const length = Array.isArray(value)\n ? value.length\n : typeof value === \"string\"\n ? value.length\n : 0;\n\n if (length < min) return message;\n return undefined;\n };\n}\n\n/**\n * Maximum length validator\n */\nexport function maxLength(\n max: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { max: number }) =>\n `Must be no more than ${p.max} characters`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ max })\n : options.message || defaultMessage({ max });\n\n return (value) => {\n if (!value) return undefined;\n\n const length = Array.isArray(value)\n ? value.length\n : typeof value === \"string\"\n ? value.length\n : 0;\n\n if (length > max) return message;\n return undefined;\n };\n}\n\n/**\n * Minimum value validator (for numbers)\n */\nexport function min(\n minValue: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { min: number }) =>\n `Must be at least ${p.min}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ min: minValue })\n : options.message || defaultMessage({ min: minValue });\n\n return (value) => {\n if (value === undefined || value === null) return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || numValue < minValue) return message;\n return undefined;\n };\n}\n\n/**\n * Maximum value validator (for numbers)\n */\nexport function max(\n maxValue: number,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { max: number }) =>\n `Must be no more than ${p.max}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ max: maxValue })\n : options.message || defaultMessage({ max: maxValue });\n\n return (value) => {\n if (value === undefined || value === null) return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || numValue > maxValue) return message;\n return undefined;\n };\n}\n\n/**\n * Pattern validator\n * Validates against a regular expression\n */\nexport function pattern(\n regex: RegExp,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Invalid format\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!regex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Match validator\n * Ensures field matches another field (e.g., password confirmation)\n */\nexport function matches(\n fieldName: string,\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = (p: { field: string }) =>\n `Must match ${p.field}`;\n const message =\n typeof options.message === \"function\"\n ? options.message({ field: fieldName })\n : options.message || defaultMessage({ field: fieldName });\n\n return (value, allValues) => {\n const otherValue = allValues[fieldName];\n if (value !== otherValue) return message;\n return undefined;\n };\n}\n\n/**\n * One of validator\n * Ensures value is one of the allowed values\n */\nexport function oneOf<T = any>(\n allowedValues: T[],\n options: ValidationRuleOptions = {}\n): FieldValidator<T> {\n const defaultMessage = \"Invalid value\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (!value) return undefined;\n if (!allowedValues.includes(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Credit card validator\n * Validates credit card numbers using Luhn algorithm\n */\nexport function creditCard(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Please enter a valid credit card number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const luhnCheck = (num: string): boolean => {\n let sum = 0;\n let isEven = false;\n\n for (let i = num.length - 1; i >= 0; i--) {\n let digit = parseInt(num[i], 10);\n\n if (isEven) {\n digit *= 2;\n if (digit > 9) {\n digit -= 9;\n }\n }\n\n sum += digit;\n isEven = !isEven;\n }\n\n return sum % 10 === 0;\n };\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n\n // Remove spaces and dashes\n const cleaned = value.replace(/[\\s-]/g, \"\");\n\n // Check if only digits\n if (!/^\\d+$/.test(cleaned)) return message;\n\n // Check length (13-19 digits for most cards)\n if (cleaned.length < 13 || cleaned.length > 19) return message;\n\n // Luhn algorithm check\n if (!luhnCheck(cleaned)) return message;\n\n return undefined;\n };\n}\n\n/**\n * Postal code validator (US ZIP codes)\n */\nexport function postalCode(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Please enter a valid ZIP code\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n // Matches: 12345 or 12345-6789\n const zipRegex = /^\\d{5}(-\\d{4})?$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!zipRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Alpha validator\n * Ensures value contains only alphabetic characters\n */\nexport function alpha(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must contain only letters\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const alphaRegex = /^[a-zA-Z]+$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!alphaRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Alphanumeric validator\n * Ensures value contains only letters and numbers\n */\nexport function alphanumeric(\n options: ValidationRuleOptions = {}\n): FieldValidator {\n const defaultMessage = \"Must contain only letters and numbers\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n const alphanumericRegex = /^[a-zA-Z0-9]+$/;\n\n return (value) => {\n if (!value) return undefined;\n if (typeof value !== \"string\") return message;\n if (!alphanumericRegex.test(value)) return message;\n return undefined;\n };\n}\n\n/**\n * Numeric validator\n * Ensures value is a valid number\n */\nexport function numeric(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must be a valid number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue)) return message;\n return undefined;\n };\n}\n\n/**\n * Integer validator\n * Ensures value is a valid integer\n */\nexport function integer(options: ValidationRuleOptions = {}): FieldValidator {\n const defaultMessage = \"Must be a whole number\";\n const message =\n typeof options.message === \"function\"\n ? options.message()\n : options.message || defaultMessage;\n\n return (value) => {\n if (value === undefined || value === null || value === \"\") return undefined;\n\n const numValue = typeof value === \"number\" ? value : parseFloat(value);\n\n if (isNaN(numValue) || !Number.isInteger(numValue)) return message;\n return undefined;\n };\n}\n\n/**\n * Compose multiple validators\n * Runs validators in sequence and returns first error\n */\nexport function compose(\n ...validators: FieldValidator[]\n): FieldValidator {\n return async (value, allValues) => {\n for (const validator of validators) {\n const error = await validator(value, allValues);\n if (error) return error;\n }\n return undefined;\n };\n}\n"]}
|