@samline/formatter 1.0.1 → 1.1.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/README.md +6 -4
- package/dist/browser/global.d.ts +209 -10
- package/dist/browser/global.global.js +239 -44
- package/dist/index.cjs +209 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +316 -6
- package/dist/index.d.ts +316 -6
- package/dist/index.js +209 -14
- package/dist/index.js.map +1 -1
- package/dist/vanilla/index.cjs +209 -14
- package/dist/vanilla/index.cjs.map +1 -1
- package/dist/vanilla/index.d.cts +316 -6
- package/dist/vanilla/index.d.ts +316 -6
- package/dist/vanilla/index.js +209 -14
- package/dist/vanilla/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -111,7 +111,93 @@ declare const format: (value: unknown, formatType: FormatType, options?: FormatO
|
|
|
111
111
|
*/
|
|
112
112
|
declare const formatPhone: (value: string, country?: string, delimiter?: string) => string;
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
/**
|
|
115
|
+
* # Regex Module
|
|
116
|
+
*
|
|
117
|
+
* Validation patterns exposed as public API for form consumers that pair
|
|
118
|
+
* formatting with validation. Each entry bundles the regex with a ready-to-use
|
|
119
|
+
* error message so consumers do not have to keep them in sync.
|
|
120
|
+
*
|
|
121
|
+
* ## Usage
|
|
122
|
+
*
|
|
123
|
+
* **Static (backward compatible):**
|
|
124
|
+
* ```ts
|
|
125
|
+
* regex.phone.pattern.test('5512345678') // true
|
|
126
|
+
* regex.email.errorMessage // 'Please enter a valid email address.'
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* **Parametric (dynamic):**
|
|
130
|
+
* ```ts
|
|
131
|
+
* regex.digits(10).pattern.test('1234567890') // true
|
|
132
|
+
* regex.digits(7).pattern.test('1234567') // true
|
|
133
|
+
* regex.phone({ length: 10 }).pattern.test('1234567890')
|
|
134
|
+
* regex.phone({ length: 7 }).pattern.test('1234567')
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* **Custom regex:**
|
|
138
|
+
* ```ts
|
|
139
|
+
* regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO')
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* ## Available Patterns
|
|
143
|
+
*
|
|
144
|
+
* | Key | Static | Parametric | Description |
|
|
145
|
+
* | --- | --- | --- | --- |
|
|
146
|
+
* | `phone` | ✅ | ✅ `({ length })` | Phone numbers |
|
|
147
|
+
* | `email` | ✅ | — | Email addresses |
|
|
148
|
+
* | `rfc` | ✅ | — | Mexican RFC |
|
|
149
|
+
* | `curp` | ✅ | — | Mexican CURP |
|
|
150
|
+
* | `cp` | ✅ | — | Mexican postal code (5 digits) |
|
|
151
|
+
* | `numeral` | ✅ | — | Numbers with separators |
|
|
152
|
+
* | `onlyNumbers` | ✅ | ✅ `({ length })` | Digits only |
|
|
153
|
+
* | `digits` | — | ✅ `({ length, min, max })` | Variable digit count |
|
|
154
|
+
* | `creditCard` | ✅ | ✅ `({ min, max })` | Card numbers |
|
|
155
|
+
* | `expirationDate` | ✅ | — | MM/YY format |
|
|
156
|
+
* | `cardCvc` | ✅ | — | 3-4 digit CVC |
|
|
157
|
+
* | `onlyLetters` | ✅ | — | Letters only |
|
|
158
|
+
* | `onlyAlphanumeric` | ✅ | — | Letters and numbers |
|
|
159
|
+
* | `url` | ✅ | ✅ `({ protocol })` | URLs |
|
|
160
|
+
* | `ipv4` | ✅ | — | IPv4 addresses |
|
|
161
|
+
* | `ipv6` | ✅ | — | IPv6 addresses |
|
|
162
|
+
* | `uuid` | ✅ | — | UUID v4 |
|
|
163
|
+
* | `hexColor` | ✅ | — | Hex color codes |
|
|
164
|
+
* | `hashtag` | ✅ | — | Social media hashtags |
|
|
165
|
+
* | `mention` | ✅ | — | Social media mentions |
|
|
166
|
+
* | `password` | — | ✅ `({ min, max, rules })` | Password strength |
|
|
167
|
+
* | `custom` | — | ✅ `({ pattern, errorMessage })` | User-defined regex |
|
|
168
|
+
*/
|
|
169
|
+
interface RegexEntry {
|
|
170
|
+
pattern: RegExp;
|
|
171
|
+
errorMessage: string;
|
|
172
|
+
}
|
|
173
|
+
interface PhoneParams {
|
|
174
|
+
length?: number;
|
|
175
|
+
}
|
|
176
|
+
interface DigitsParams {
|
|
177
|
+
length?: number;
|
|
178
|
+
min?: number;
|
|
179
|
+
max?: number;
|
|
180
|
+
}
|
|
181
|
+
interface CreditCardParams {
|
|
182
|
+
min?: number;
|
|
183
|
+
max?: number;
|
|
184
|
+
}
|
|
185
|
+
interface UrlParams {
|
|
186
|
+
protocol?: 'http' | 'https' | 'ftp' | 'all';
|
|
187
|
+
}
|
|
188
|
+
interface PasswordParams {
|
|
189
|
+
min?: number;
|
|
190
|
+
max?: number;
|
|
191
|
+
uppercase?: boolean;
|
|
192
|
+
lowercase?: boolean;
|
|
193
|
+
numbers?: boolean;
|
|
194
|
+
special?: boolean;
|
|
195
|
+
}
|
|
196
|
+
interface CustomParams {
|
|
197
|
+
pattern: RegExp;
|
|
198
|
+
errorMessage: string;
|
|
199
|
+
}
|
|
200
|
+
declare const _regex: {
|
|
115
201
|
readonly phone: {
|
|
116
202
|
readonly pattern: RegExp;
|
|
117
203
|
readonly errorMessage: "Please enter a valid 10-digit phone number.";
|
|
@@ -124,6 +210,14 @@ declare const regex: {
|
|
|
124
210
|
readonly pattern: RegExp;
|
|
125
211
|
readonly errorMessage: "Please enter a valid RFC.";
|
|
126
212
|
};
|
|
213
|
+
readonly curp: {
|
|
214
|
+
readonly pattern: RegExp;
|
|
215
|
+
readonly errorMessage: "Please enter a valid CURP.";
|
|
216
|
+
};
|
|
217
|
+
readonly cp: {
|
|
218
|
+
readonly pattern: RegExp;
|
|
219
|
+
readonly errorMessage: "Please enter a valid 5-digit postal code.";
|
|
220
|
+
};
|
|
127
221
|
readonly numeral: {
|
|
128
222
|
readonly pattern: RegExp;
|
|
129
223
|
readonly errorMessage: "Please enter a valid number.";
|
|
@@ -134,15 +228,174 @@ declare const regex: {
|
|
|
134
228
|
};
|
|
135
229
|
readonly creditCard: {
|
|
136
230
|
readonly pattern: RegExp;
|
|
137
|
-
readonly errorMessage: "Please enter a valid card number.";
|
|
231
|
+
readonly errorMessage: "Please enter a valid card number (15-16 digits).";
|
|
232
|
+
};
|
|
233
|
+
readonly expirationDate: {
|
|
234
|
+
readonly pattern: RegExp;
|
|
235
|
+
readonly errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY).";
|
|
236
|
+
};
|
|
237
|
+
readonly cardCvc: {
|
|
238
|
+
readonly pattern: RegExp;
|
|
239
|
+
readonly errorMessage: "Please enter a valid CVC (3-4 digits).";
|
|
240
|
+
};
|
|
241
|
+
readonly onlyLetters: {
|
|
242
|
+
readonly pattern: RegExp;
|
|
243
|
+
readonly errorMessage: "Please enter only letters.";
|
|
244
|
+
};
|
|
245
|
+
readonly onlyAlphanumeric: {
|
|
246
|
+
readonly pattern: RegExp;
|
|
247
|
+
readonly errorMessage: "Please enter only letters and numbers.";
|
|
248
|
+
};
|
|
249
|
+
readonly url: {
|
|
250
|
+
readonly pattern: RegExp;
|
|
251
|
+
readonly errorMessage: "Please enter a valid URL.";
|
|
252
|
+
};
|
|
253
|
+
readonly ipv4: {
|
|
254
|
+
readonly pattern: RegExp;
|
|
255
|
+
readonly errorMessage: "Please enter a valid IPv4 address.";
|
|
256
|
+
};
|
|
257
|
+
readonly ipv6: {
|
|
258
|
+
readonly pattern: RegExp;
|
|
259
|
+
readonly errorMessage: "Please enter a valid IPv6 address.";
|
|
260
|
+
};
|
|
261
|
+
readonly uuid: {
|
|
262
|
+
readonly pattern: RegExp;
|
|
263
|
+
readonly errorMessage: "Please enter a valid UUID.";
|
|
264
|
+
};
|
|
265
|
+
readonly hexColor: {
|
|
266
|
+
readonly pattern: RegExp;
|
|
267
|
+
readonly errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF).";
|
|
268
|
+
};
|
|
269
|
+
readonly hashtag: {
|
|
270
|
+
readonly pattern: RegExp;
|
|
271
|
+
readonly errorMessage: "Please enter a valid hashtag (e.g., #example).";
|
|
272
|
+
};
|
|
273
|
+
readonly mention: {
|
|
274
|
+
readonly pattern: RegExp;
|
|
275
|
+
readonly errorMessage: "Please enter a valid mention (e.g., @username).";
|
|
276
|
+
};
|
|
277
|
+
readonly postalCode: {
|
|
278
|
+
readonly pattern: RegExp;
|
|
279
|
+
readonly errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234).";
|
|
280
|
+
};
|
|
281
|
+
readonly time24: {
|
|
282
|
+
readonly pattern: RegExp;
|
|
283
|
+
readonly errorMessage: "Please enter a valid 24-hour time (HH:MM).";
|
|
284
|
+
};
|
|
285
|
+
readonly date: {
|
|
286
|
+
readonly pattern: RegExp;
|
|
287
|
+
readonly errorMessage: "Please enter a valid date (YYYY-MM-DD).";
|
|
288
|
+
};
|
|
289
|
+
readonly slug: {
|
|
290
|
+
readonly pattern: RegExp;
|
|
291
|
+
readonly errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces).";
|
|
292
|
+
};
|
|
293
|
+
readonly username: {
|
|
294
|
+
readonly pattern: RegExp;
|
|
295
|
+
readonly errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -).";
|
|
296
|
+
};
|
|
297
|
+
readonly macAddress: {
|
|
298
|
+
readonly pattern: RegExp;
|
|
299
|
+
readonly errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7).";
|
|
300
|
+
};
|
|
301
|
+
readonly semver: {
|
|
302
|
+
readonly pattern: RegExp;
|
|
303
|
+
readonly errorMessage: "Please enter a valid semantic version (e.g., 1.2.3).";
|
|
304
|
+
};
|
|
305
|
+
readonly base64: {
|
|
306
|
+
readonly pattern: RegExp;
|
|
307
|
+
readonly errorMessage: "Please enter a valid Base64 encoded string.";
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Digits with configurable length.
|
|
312
|
+
* @example
|
|
313
|
+
* regex.digits(10).pattern.test('1234567890') // true
|
|
314
|
+
* regex.digits({ length: 7 }).pattern.test('1234567') // true
|
|
315
|
+
* regex.digits({ min: 3, max: 10 }).pattern.test('12345') // true
|
|
316
|
+
*/
|
|
317
|
+
declare function digits(params?: number | DigitsParams): RegexEntry;
|
|
318
|
+
/**
|
|
319
|
+
* Phone with configurable digit count.
|
|
320
|
+
*
|
|
321
|
+
* Also available as static entry: regex.phone.pattern (10 digits)
|
|
322
|
+
* @example
|
|
323
|
+
* regex.phone().pattern.test('5512345678') // true (10 digits)
|
|
324
|
+
* regex.phone({ length: 7 }).pattern.test('1234567') // true (7 digits)
|
|
325
|
+
*/
|
|
326
|
+
declare function _phoneFn(params?: PhoneParams): RegexEntry;
|
|
327
|
+
/**
|
|
328
|
+
* Credit card with configurable digit range.
|
|
329
|
+
*
|
|
330
|
+
* Also available as static entry: regex.creditCard.pattern (15-16 digits)
|
|
331
|
+
* @example
|
|
332
|
+
* regex.creditCard().pattern.test('4111111111111111') // true (15-16)
|
|
333
|
+
* regex.creditCard({ min: 13, max: 19 }).pattern.test('1234567890123') // true
|
|
334
|
+
*/
|
|
335
|
+
declare function _creditCardFn(params?: CreditCardParams): RegexEntry;
|
|
336
|
+
/**
|
|
337
|
+
* URL with configurable protocol.
|
|
338
|
+
*
|
|
339
|
+
* Also available as static entry: regex.url.pattern (any protocol)
|
|
340
|
+
* @example
|
|
341
|
+
* regex.url().pattern.test('https://example.com') // true
|
|
342
|
+
* regex.url({ protocol: 'https' }).pattern.test('https://example.com') // true
|
|
343
|
+
* regex.url({ protocol: 'https' }).pattern.test('ftp://example.com') // false
|
|
344
|
+
*/
|
|
345
|
+
declare function _urlFn(params?: UrlParams): RegexEntry;
|
|
346
|
+
/**
|
|
347
|
+
* Password with configurable strength rules.
|
|
348
|
+
* @example
|
|
349
|
+
* regex.password().pattern.test('Passw0rd!') // true (default: 8+ chars, upper, lower, number)
|
|
350
|
+
* regex.password({ min: 12, special: true }).pattern.test('MyP@ssw0rd!') // true
|
|
351
|
+
*/
|
|
352
|
+
declare function _passwordFn(params?: PasswordParams): RegexEntry;
|
|
353
|
+
/**
|
|
354
|
+
* Custom regex provided by the user.
|
|
355
|
+
* @example
|
|
356
|
+
* regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO') // true
|
|
357
|
+
* regex.custom({ pattern: /^\d+$/, errorMessage: 'Numbers only' }).pattern.test('123') // true
|
|
358
|
+
*/
|
|
359
|
+
declare function _customFn(pattern: RegExp, errorMessage?: string): RegexEntry;
|
|
360
|
+
declare function _customFn(params: CustomParams): RegexEntry;
|
|
361
|
+
declare const regex: {
|
|
362
|
+
readonly digits: typeof digits & RegexEntry;
|
|
363
|
+
readonly phone: typeof _phoneFn & RegexEntry;
|
|
364
|
+
readonly creditCard: typeof _creditCardFn & RegexEntry;
|
|
365
|
+
readonly url: typeof _urlFn & RegexEntry;
|
|
366
|
+
readonly password: typeof _passwordFn & RegexEntry;
|
|
367
|
+
readonly custom: typeof _customFn & RegexEntry;
|
|
368
|
+
readonly email: {
|
|
369
|
+
readonly pattern: RegExp;
|
|
370
|
+
readonly errorMessage: "Please enter a valid email address.";
|
|
371
|
+
};
|
|
372
|
+
readonly rfc: {
|
|
373
|
+
readonly pattern: RegExp;
|
|
374
|
+
readonly errorMessage: "Please enter a valid RFC.";
|
|
375
|
+
};
|
|
376
|
+
readonly curp: {
|
|
377
|
+
readonly pattern: RegExp;
|
|
378
|
+
readonly errorMessage: "Please enter a valid CURP.";
|
|
379
|
+
};
|
|
380
|
+
readonly cp: {
|
|
381
|
+
readonly pattern: RegExp;
|
|
382
|
+
readonly errorMessage: "Please enter a valid 5-digit postal code.";
|
|
383
|
+
};
|
|
384
|
+
readonly numeral: {
|
|
385
|
+
readonly pattern: RegExp;
|
|
386
|
+
readonly errorMessage: "Please enter a valid number.";
|
|
387
|
+
};
|
|
388
|
+
readonly onlyNumbers: {
|
|
389
|
+
readonly pattern: RegExp;
|
|
390
|
+
readonly errorMessage: "Please enter only numbers.";
|
|
138
391
|
};
|
|
139
392
|
readonly expirationDate: {
|
|
140
393
|
readonly pattern: RegExp;
|
|
141
|
-
readonly errorMessage: "Please enter a valid expiration date.";
|
|
394
|
+
readonly errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY).";
|
|
142
395
|
};
|
|
143
396
|
readonly cardCvc: {
|
|
144
397
|
readonly pattern: RegExp;
|
|
145
|
-
readonly errorMessage: "Please enter a valid CVC.";
|
|
398
|
+
readonly errorMessage: "Please enter a valid CVC (3-4 digits).";
|
|
146
399
|
};
|
|
147
400
|
readonly onlyLetters: {
|
|
148
401
|
readonly pattern: RegExp;
|
|
@@ -152,7 +405,64 @@ declare const regex: {
|
|
|
152
405
|
readonly pattern: RegExp;
|
|
153
406
|
readonly errorMessage: "Please enter only letters and numbers.";
|
|
154
407
|
};
|
|
408
|
+
readonly ipv4: {
|
|
409
|
+
readonly pattern: RegExp;
|
|
410
|
+
readonly errorMessage: "Please enter a valid IPv4 address.";
|
|
411
|
+
};
|
|
412
|
+
readonly ipv6: {
|
|
413
|
+
readonly pattern: RegExp;
|
|
414
|
+
readonly errorMessage: "Please enter a valid IPv6 address.";
|
|
415
|
+
};
|
|
416
|
+
readonly uuid: {
|
|
417
|
+
readonly pattern: RegExp;
|
|
418
|
+
readonly errorMessage: "Please enter a valid UUID.";
|
|
419
|
+
};
|
|
420
|
+
readonly hexColor: {
|
|
421
|
+
readonly pattern: RegExp;
|
|
422
|
+
readonly errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF).";
|
|
423
|
+
};
|
|
424
|
+
readonly hashtag: {
|
|
425
|
+
readonly pattern: RegExp;
|
|
426
|
+
readonly errorMessage: "Please enter a valid hashtag (e.g., #example).";
|
|
427
|
+
};
|
|
428
|
+
readonly mention: {
|
|
429
|
+
readonly pattern: RegExp;
|
|
430
|
+
readonly errorMessage: "Please enter a valid mention (e.g., @username).";
|
|
431
|
+
};
|
|
432
|
+
readonly postalCode: {
|
|
433
|
+
readonly pattern: RegExp;
|
|
434
|
+
readonly errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234).";
|
|
435
|
+
};
|
|
436
|
+
readonly time24: {
|
|
437
|
+
readonly pattern: RegExp;
|
|
438
|
+
readonly errorMessage: "Please enter a valid 24-hour time (HH:MM).";
|
|
439
|
+
};
|
|
440
|
+
readonly date: {
|
|
441
|
+
readonly pattern: RegExp;
|
|
442
|
+
readonly errorMessage: "Please enter a valid date (YYYY-MM-DD).";
|
|
443
|
+
};
|
|
444
|
+
readonly slug: {
|
|
445
|
+
readonly pattern: RegExp;
|
|
446
|
+
readonly errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces).";
|
|
447
|
+
};
|
|
448
|
+
readonly username: {
|
|
449
|
+
readonly pattern: RegExp;
|
|
450
|
+
readonly errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -).";
|
|
451
|
+
};
|
|
452
|
+
readonly macAddress: {
|
|
453
|
+
readonly pattern: RegExp;
|
|
454
|
+
readonly errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7).";
|
|
455
|
+
};
|
|
456
|
+
readonly semver: {
|
|
457
|
+
readonly pattern: RegExp;
|
|
458
|
+
readonly errorMessage: "Please enter a valid semantic version (e.g., 1.2.3).";
|
|
459
|
+
};
|
|
460
|
+
readonly base64: {
|
|
461
|
+
readonly pattern: RegExp;
|
|
462
|
+
readonly errorMessage: "Please enter a valid Base64 encoded string.";
|
|
463
|
+
};
|
|
155
464
|
};
|
|
156
|
-
type RegexKey = keyof typeof
|
|
465
|
+
type RegexKey = keyof typeof _regex;
|
|
466
|
+
type Regex = typeof regex;
|
|
157
467
|
|
|
158
|
-
export { FORMAT_TYPES, type FormatOptions, type FormatType, type FormatterResult, type RegexKey, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };
|
|
468
|
+
export { FORMAT_TYPES, type FormatOptions, type FormatType, type FormatterResult, type Regex, type RegexEntry, type RegexKey, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { AsYouType } from 'libphonenumber-js';
|
|
|
4
4
|
// src/core/format.ts
|
|
5
5
|
var formatPhone = (value, country = "MX", delimiter = " ") => {
|
|
6
6
|
if (!value) return "";
|
|
7
|
-
const
|
|
7
|
+
const digits2 = value.replace(/[^\d+]/g, "");
|
|
8
8
|
const formatter = new AsYouType(country);
|
|
9
|
-
const formatted = formatter.input(
|
|
9
|
+
const formatted = formatter.input(digits2);
|
|
10
10
|
if (delimiter !== " ") {
|
|
11
11
|
return formatted.replace(/ /g, delimiter);
|
|
12
12
|
}
|
|
@@ -41,12 +41,12 @@ var normalizeDateSegment = (segment, unit) => {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
var getDateSegments = (value, pattern) => {
|
|
44
|
-
const
|
|
44
|
+
const digits2 = value.replace(/[^\d]/g, "");
|
|
45
45
|
const segments = {};
|
|
46
46
|
let start = 0;
|
|
47
47
|
for (const unit of pattern) {
|
|
48
48
|
const end = start + getDateUnitLength(unit);
|
|
49
|
-
const segment =
|
|
49
|
+
const segment = digits2.slice(start, end);
|
|
50
50
|
if (segment) {
|
|
51
51
|
segments[getDateSegmentKey(unit)] = segment;
|
|
52
52
|
}
|
|
@@ -68,12 +68,12 @@ var getTimeSegmentKey = (unit) => {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
var getTimeSegments = (value, pattern) => {
|
|
71
|
-
const
|
|
71
|
+
const digits2 = value.replace(/[^\d]/g, "");
|
|
72
72
|
const segments = {};
|
|
73
73
|
let start = 0;
|
|
74
74
|
for (const unit of pattern) {
|
|
75
75
|
const end = start + 2;
|
|
76
|
-
const segment =
|
|
76
|
+
const segment = digits2.slice(start, end);
|
|
77
77
|
if (segment) {
|
|
78
78
|
segments[getTimeSegmentKey(unit)] = segment;
|
|
79
79
|
}
|
|
@@ -239,21 +239,81 @@ var format = (value, formatType, options = {}) => {
|
|
|
239
239
|
};
|
|
240
240
|
|
|
241
241
|
// src/core/regex.ts
|
|
242
|
-
|
|
242
|
+
function createDigits(min, max, errorMsg) {
|
|
243
|
+
return {
|
|
244
|
+
pattern: new RegExp(`^\\d{${min},${max}}$`),
|
|
245
|
+
errorMessage: errorMsg
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function createPhone(length) {
|
|
249
|
+
return {
|
|
250
|
+
pattern: new RegExp(`^(?:\\D*\\d){${length}}\\D*$`),
|
|
251
|
+
errorMessage: `Please enter a valid ${length}-digit phone number.`
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function createCreditCard(min, max) {
|
|
255
|
+
return {
|
|
256
|
+
pattern: new RegExp(`^(?:\\D*\\d){${min},${max}}\\D*$`),
|
|
257
|
+
errorMessage: `Please enter a valid card number (${min}-${max} digits).`
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function createUrl(requireProtocol) {
|
|
261
|
+
const protocol = requireProtocol === "all" ? "https?" : requireProtocol;
|
|
262
|
+
return {
|
|
263
|
+
pattern: new RegExp(`^${protocol}://[^\\s]+$`),
|
|
264
|
+
errorMessage: `Please enter a valid URL${requireProtocol !== "all" ? ` (${requireProtocol}://...)` : ""}.`
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function createPassword(params) {
|
|
268
|
+
const {
|
|
269
|
+
min = 8,
|
|
270
|
+
max = 128,
|
|
271
|
+
uppercase = true,
|
|
272
|
+
lowercase = true,
|
|
273
|
+
numbers = true,
|
|
274
|
+
special = false
|
|
275
|
+
} = params;
|
|
276
|
+
let chars = "";
|
|
277
|
+
if (uppercase) chars += "A-Z";
|
|
278
|
+
if (lowercase) chars += "a-z";
|
|
279
|
+
if (numbers) chars += "0-9";
|
|
280
|
+
if (special) chars += `!@#$%^&*()_+\\-=\\[\\]{}|;:'",.<>?/`;
|
|
281
|
+
const ruleParts = [];
|
|
282
|
+
if (uppercase) ruleParts.push("uppercase letter");
|
|
283
|
+
if (lowercase) ruleParts.push("lowercase letter");
|
|
284
|
+
if (numbers) ruleParts.push("number");
|
|
285
|
+
if (special) ruleParts.push("special character");
|
|
286
|
+
const rulesText = ruleParts.length > 2 ? ruleParts.slice(0, -1).join(", ") + " and " + ruleParts.slice(-1) : ruleParts.join(" and ");
|
|
287
|
+
return {
|
|
288
|
+
pattern: new RegExp(`^[${chars}]{${min},${max}}$`),
|
|
289
|
+
errorMessage: `Password must be ${min}-${max} characters with at least one ${rulesText}.`
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
var _regex = {
|
|
243
293
|
phone: {
|
|
244
|
-
// 10 digit phone numbers, allowing for optional country code and delimiters
|
|
245
294
|
pattern: /^(?:\D*\d){10}\D*$/,
|
|
246
295
|
errorMessage: "Please enter a valid 10-digit phone number."
|
|
247
296
|
},
|
|
248
297
|
email: {
|
|
298
|
+
// Simple but effective email validation
|
|
249
299
|
pattern: /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/,
|
|
250
300
|
errorMessage: "Please enter a valid email address."
|
|
251
301
|
},
|
|
252
302
|
rfc: {
|
|
253
|
-
// Mexican RFC
|
|
303
|
+
// Mexican RFC ( Personas Morales y Físicas )
|
|
254
304
|
pattern: /^([A-ZÑ&]{3,4})\d{6}([A-Z0-9]{0,3})$/i,
|
|
255
305
|
errorMessage: "Please enter a valid RFC."
|
|
256
306
|
},
|
|
307
|
+
curp: {
|
|
308
|
+
// Mexican CURP (18 characters)
|
|
309
|
+
pattern: /^[A-Z]{4}\d{6}[A-Z]{6}[0-9A-Z]\d$/i,
|
|
310
|
+
errorMessage: "Please enter a valid CURP."
|
|
311
|
+
},
|
|
312
|
+
cp: {
|
|
313
|
+
// Mexican postal code (5 digits)
|
|
314
|
+
pattern: /^\d{5}$/,
|
|
315
|
+
errorMessage: "Please enter a valid 5-digit postal code."
|
|
316
|
+
},
|
|
257
317
|
numeral: {
|
|
258
318
|
// Numbers with optional thousand separators and decimal points
|
|
259
319
|
pattern: /\d{1,3}(,\d{3})*(\.\d+)?/,
|
|
@@ -266,17 +326,17 @@ var regex = {
|
|
|
266
326
|
creditCard: {
|
|
267
327
|
// 15 or 16 digits, allowing spaces or delimiters
|
|
268
328
|
pattern: /^(?:\D*\d){15,16}\D*$/,
|
|
269
|
-
errorMessage: "Please enter a valid card number."
|
|
329
|
+
errorMessage: "Please enter a valid card number (15-16 digits)."
|
|
270
330
|
},
|
|
271
331
|
expirationDate: {
|
|
272
|
-
// MM/YY format
|
|
273
|
-
pattern: /^(0[1-9]|1[0-2])
|
|
274
|
-
errorMessage: "Please enter a valid expiration date."
|
|
332
|
+
// MM/YY or MM/YYYY format
|
|
333
|
+
pattern: /^(0[1-9]|1[0-2])\/(\d{2}|\d{4})$/,
|
|
334
|
+
errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY)."
|
|
275
335
|
},
|
|
276
336
|
cardCvc: {
|
|
277
337
|
// 3 or 4 digit card security codes
|
|
278
338
|
pattern: /^\d{3,4}$/,
|
|
279
|
-
errorMessage: "Please enter a valid CVC."
|
|
339
|
+
errorMessage: "Please enter a valid CVC (3-4 digits)."
|
|
280
340
|
},
|
|
281
341
|
onlyLetters: {
|
|
282
342
|
// Letters only (including accented characters and spaces)
|
|
@@ -287,7 +347,142 @@ var regex = {
|
|
|
287
347
|
// Letters and numbers (including accented characters and spaces)
|
|
288
348
|
pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ0-9\s]+$/,
|
|
289
349
|
errorMessage: "Please enter only letters and numbers."
|
|
350
|
+
},
|
|
351
|
+
url: {
|
|
352
|
+
// Accepts http, https, ftp
|
|
353
|
+
pattern: /^(?:https?|ftp):\/\/[^\s]+$/,
|
|
354
|
+
errorMessage: "Please enter a valid URL."
|
|
355
|
+
},
|
|
356
|
+
ipv4: {
|
|
357
|
+
// IPv4 addresses (0-255 per octet)
|
|
358
|
+
pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
|
|
359
|
+
errorMessage: "Please enter a valid IPv4 address."
|
|
360
|
+
},
|
|
361
|
+
ipv6: {
|
|
362
|
+
// IPv6 addresses (simplified)
|
|
363
|
+
pattern: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/,
|
|
364
|
+
errorMessage: "Please enter a valid IPv6 address."
|
|
365
|
+
},
|
|
366
|
+
uuid: {
|
|
367
|
+
// UUID v4
|
|
368
|
+
pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
|
369
|
+
errorMessage: "Please enter a valid UUID."
|
|
370
|
+
},
|
|
371
|
+
hexColor: {
|
|
372
|
+
// Hex color codes (#RGB or #RRGGBB)
|
|
373
|
+
pattern: /^#(?:[0-9a-fA-F]{3}){1,2}$/,
|
|
374
|
+
errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF)."
|
|
375
|
+
},
|
|
376
|
+
hashtag: {
|
|
377
|
+
// Social media hashtags
|
|
378
|
+
pattern: /^#[a-zA-Z_][a-zA-Z0-9_]*$/,
|
|
379
|
+
errorMessage: "Please enter a valid hashtag (e.g., #example)."
|
|
380
|
+
},
|
|
381
|
+
mention: {
|
|
382
|
+
// Social media mentions
|
|
383
|
+
pattern: /^@[a-zA-Z_][a-zA-Z0-9_]*$/,
|
|
384
|
+
errorMessage: "Please enter a valid mention (e.g., @username)."
|
|
385
|
+
},
|
|
386
|
+
postalCode: {
|
|
387
|
+
// Generic 5-digit postal code (US-style ZIP / MX CP)
|
|
388
|
+
pattern: /^\d{5}(?:-\d{4})?$/,
|
|
389
|
+
errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234)."
|
|
390
|
+
},
|
|
391
|
+
time24: {
|
|
392
|
+
// 24-hour time HH:MM
|
|
393
|
+
pattern: /^([01]\d|2[0-3]):([0-5]\d)$/,
|
|
394
|
+
errorMessage: "Please enter a valid 24-hour time (HH:MM)."
|
|
395
|
+
},
|
|
396
|
+
date: {
|
|
397
|
+
// ISO-like date YYYY-MM-DD (loose)
|
|
398
|
+
pattern: /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,
|
|
399
|
+
errorMessage: "Please enter a valid date (YYYY-MM-DD)."
|
|
400
|
+
},
|
|
401
|
+
slug: {
|
|
402
|
+
// URL slug (lowercase, hyphens, no spaces)
|
|
403
|
+
pattern: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
|
|
404
|
+
errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces)."
|
|
405
|
+
},
|
|
406
|
+
username: {
|
|
407
|
+
// Username: 3-20 chars, alphanumeric, underscore, hyphen
|
|
408
|
+
pattern: /^[a-zA-Z0-9_-]{3,20}$/,
|
|
409
|
+
errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -)."
|
|
410
|
+
},
|
|
411
|
+
macAddress: {
|
|
412
|
+
// MAC address (colon or hyphen separated)
|
|
413
|
+
pattern: /^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/,
|
|
414
|
+
errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7)."
|
|
415
|
+
},
|
|
416
|
+
semver: {
|
|
417
|
+
// Semantic version (X.Y.Z with optional -prerelease)
|
|
418
|
+
pattern: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[a-zA-Z0-9.-]+)?$/,
|
|
419
|
+
errorMessage: "Please enter a valid semantic version (e.g., 1.2.3)."
|
|
420
|
+
},
|
|
421
|
+
base64: {
|
|
422
|
+
// Base64 encoded string
|
|
423
|
+
pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,
|
|
424
|
+
errorMessage: "Please enter a valid Base64 encoded string."
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
function digits(params) {
|
|
428
|
+
if (typeof params === "number") {
|
|
429
|
+
return createDigits(params, params, `Please enter exactly ${params} digits.`);
|
|
290
430
|
}
|
|
431
|
+
const { length, min = 1, max = 20 } = params ?? {};
|
|
432
|
+
const actualMin = length ?? min;
|
|
433
|
+
const actualMax = length ?? max;
|
|
434
|
+
if (actualMin === actualMax) {
|
|
435
|
+
return createDigits(actualMin, actualMax, `Please enter exactly ${actualMin} digits.`);
|
|
436
|
+
}
|
|
437
|
+
return createDigits(actualMin, actualMax, `Please enter ${actualMin}-${actualMax} digits.`);
|
|
438
|
+
}
|
|
439
|
+
function _phoneFn(params) {
|
|
440
|
+
const length = params?.length ?? 10;
|
|
441
|
+
return createPhone(length);
|
|
442
|
+
}
|
|
443
|
+
function _creditCardFn(params) {
|
|
444
|
+
const min = params?.min ?? 15;
|
|
445
|
+
const max = params?.max ?? 16;
|
|
446
|
+
return createCreditCard(min, max);
|
|
447
|
+
}
|
|
448
|
+
function _urlFn(params) {
|
|
449
|
+
const protocol = params?.protocol ?? "all";
|
|
450
|
+
return createUrl(protocol);
|
|
451
|
+
}
|
|
452
|
+
function _passwordFn(params) {
|
|
453
|
+
return createPassword(params ?? {});
|
|
454
|
+
}
|
|
455
|
+
function _customFn(arg1, arg2) {
|
|
456
|
+
if (arg1 instanceof RegExp) {
|
|
457
|
+
return { pattern: arg1, errorMessage: arg2 ?? "Invalid value." };
|
|
458
|
+
}
|
|
459
|
+
return { pattern: arg1.pattern, errorMessage: arg1.errorMessage };
|
|
460
|
+
}
|
|
461
|
+
var phoneFn = _phoneFn;
|
|
462
|
+
phoneFn.pattern = _regex.phone.pattern;
|
|
463
|
+
phoneFn.errorMessage = _regex.phone.errorMessage;
|
|
464
|
+
var creditCardFn = _creditCardFn;
|
|
465
|
+
creditCardFn.pattern = _regex.creditCard.pattern;
|
|
466
|
+
creditCardFn.errorMessage = _regex.creditCard.errorMessage;
|
|
467
|
+
var urlFn = _urlFn;
|
|
468
|
+
urlFn.pattern = _regex.url.pattern;
|
|
469
|
+
urlFn.errorMessage = _regex.url.errorMessage;
|
|
470
|
+
var digitsFn = digits;
|
|
471
|
+
digitsFn.errorMessage = "Please enter a valid number.";
|
|
472
|
+
var passwordFn = _passwordFn;
|
|
473
|
+
passwordFn.errorMessage = "Please enter a valid password.";
|
|
474
|
+
var customFn = _customFn;
|
|
475
|
+
customFn.errorMessage = "Please enter a valid value.";
|
|
476
|
+
var regex = {
|
|
477
|
+
// Static entries (backward compatible - spread first)
|
|
478
|
+
..._regex,
|
|
479
|
+
// Parametric functions
|
|
480
|
+
digits: digitsFn,
|
|
481
|
+
phone: phoneFn,
|
|
482
|
+
creditCard: creditCardFn,
|
|
483
|
+
url: urlFn,
|
|
484
|
+
password: passwordFn,
|
|
485
|
+
custom: customFn
|
|
291
486
|
};
|
|
292
487
|
|
|
293
488
|
export { FORMAT_TYPES, format, formatPhone, formatValue, getDateValueFromRaw, getRawValue, getTimeValueFromRaw, getValueForFormatting, isFormatType, regex, resolveRuntimeOptions, stripPrefixAndSuffix };
|