@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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/phone.ts","../src/core/raw.ts","../src/core/format.ts","../src/core/formatter.ts","../src/core/regex.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { AsYouType, type CountryCode } from 'libphonenumber-js'\n\n/**\n * Format a phone number string using `libphonenumber-js`'s `AsYouType`.\n *\n * Non-digit characters are stripped before formatting (the leading `+` is\n * preserved so international numbers keep their country prefix). After\n * formatting, spaces produced by `AsYouType` are swapped for `delimiter` when\n * a custom delimiter is provided.\n *\n * @param value - The raw input (digits, `+`, spaces, dashes, parentheses, etc.).\n * @param country - ISO 3166-1 alpha-2 country code (e.g. `'MX'`, `'US'`).\n * @param delimiter - Character used to separate groups in the output.\n * @returns The formatted phone string, or `''` when `value` is empty.\n */\nexport const formatPhone = (\n value: string,\n country: string = 'MX',\n delimiter: string = ' '\n): string => {\n if (!value) return ''\n\n // Preserve '+' so international numbers keep their prefix.\n const digits = value.replace(/[^\\d+]/g, '')\n const formatter = new AsYouType(country as CountryCode)\n const formatted = formatter.input(digits)\n\n if (delimiter !== ' ') {\n return formatted.replace(/ /g, delimiter)\n }\n\n return formatted\n}","import {\n unformatCreditCard,\n unformatGeneral,\n unformatNumeral,\n type DatePatternType,\n type DateUnit,\n type FormatCreditCardOptions,\n type FormatDateOptions,\n type FormatGeneralOptions,\n type FormatNumeralOptions,\n type FormatTimeOptions,\n type TimePatternType,\n type TimeUnit\n} from 'cleave-zen'\n\nexport type FormatType =\n | 'general'\n | 'phone'\n | 'numeral'\n | 'date'\n | 'time'\n | 'creditCard'\n | 'creditCardType'\n\ntype ExtraFormatOptions = {\n country?: string\n dateRawPattern?: DatePatternType\n dateRawPatternDelimiter?: string\n timeRawPattern?: TimePatternType\n timeRawPatternDelimiter?: string\n tailPrefix?: boolean\n}\n\nexport type FormatOptions = Partial<\nFormatGeneralOptions &\nFormatNumeralOptions &\nFormatDateOptions &\nFormatTimeOptions &\nFormatCreditCardOptions\n> &\nExtraFormatOptions\n\ntype DateSegmentKey = 'day' | 'month' | 'year'\ntype TimeSegmentKey = 'hours' | 'minutes' | 'seconds'\n\nconst DEFAULT_DATE_PATTERN: DatePatternType = ['d', 'm', 'Y']\nconst DEFAULT_DATE_RAW_PATTERN: DatePatternType = ['Y', 'm', 'd']\nconst DEFAULT_DATE_RAW_PATTERN_DELIMITER = '-'\nconst DEFAULT_TIME_PATTERN: TimePatternType = ['h', 'm', 's']\nconst DEFAULT_TIME_RAW_PATTERN: TimePatternType = ['h', 'm']\nconst DEFAULT_TIME_RAW_PATTERN_DELIMITER = ':'\n\nconst getDateSegmentKey = (unit: DateUnit): DateSegmentKey => {\n switch (unit.toLowerCase()) {\n case 'd':\n return 'day'\n case 'm':\n return 'month'\n default:\n return 'year'\n }\n}\n\nconst getDateUnitLength = (unit: DateUnit): 2 | 4 =>\n unit === 'Y' ? 4 : 2\n\nconst normalizeDateSegment = (segment: string, unit: DateUnit): string => {\n if (!segment) return ''\n\n switch (unit) {\n case 'y':\n return segment.slice(-2)\n case 'Y':\n return segment.slice(0, 4)\n default:\n return segment.slice(0, 2)\n }\n}\n\nconst getDateSegments = (\n value: string,\n pattern: DatePatternType\n): Partial<Record<DateSegmentKey, string>> => {\n const digits = value.replace(/[^\\d]/g, '')\n const segments: Partial<Record<DateSegmentKey, string>> = {}\n let start = 0\n\n for (const unit of pattern) {\n const end = start + getDateUnitLength(unit)\n const segment = digits.slice(start, end)\n\n if (segment) {\n segments[getDateSegmentKey(unit)] = segment\n }\n\n start = end\n }\n\n return segments\n}\n\nconst formatDateSegments = (\n segments: Partial<Record<DateSegmentKey, string>>,\n pattern: DatePatternType,\n delimiter = ''\n): string =>\n pattern\n .map((unit) =>\n normalizeDateSegment(segments[getDateSegmentKey(unit)] ?? '', unit)\n )\n .filter(Boolean)\n .join(delimiter)\n\nconst getTimeSegmentKey = (unit: TimeUnit): TimeSegmentKey => {\n switch (unit) {\n case 'h':\n return 'hours'\n case 'm':\n return 'minutes'\n default:\n return 'seconds'\n }\n}\n\nconst getTimeSegments = (\n value: string,\n pattern: TimePatternType\n): Partial<Record<TimeSegmentKey, string>> => {\n const digits = value.replace(/[^\\d]/g, '')\n const segments: Partial<Record<TimeSegmentKey, string>> = {}\n let start = 0\n\n for (const unit of pattern) {\n const end = start + 2\n const segment = digits.slice(start, end)\n\n if (segment) {\n segments[getTimeSegmentKey(unit)] = segment\n }\n\n start = end\n }\n\n return segments\n}\n\nconst formatTimeSegments = (\n segments: Partial<Record<TimeSegmentKey, string>>,\n pattern: TimePatternType,\n delimiter = ''\n): string =>\n pattern\n .map((unit) => (segments[getTimeSegmentKey(unit)] ?? '').slice(0, 2))\n .filter(Boolean)\n .join(delimiter)\n\n/**\n * Convert a raw date string (e.g. `2026-05-12`) into the digit order of the\n * display pattern (e.g. `12/05/2026` → `12052026`).\n *\n * The output is intentionally digits-only and un-delimited — the caller is\n * expected to pass the result through `cleave-zen`'s `formatDate` (or an\n * equivalent) to add the configured delimiter. The source pattern is\n * `dateRawPattern`; the target pattern is `datePattern`.\n */\nexport const getDateValueFromRaw = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.dateRawPattern ?? DEFAULT_DATE_RAW_PATTERN\n const targetPattern = options.datePattern ?? DEFAULT_DATE_PATTERN\n\n return formatDateSegments(\n getDateSegments(value, sourcePattern),\n targetPattern\n )\n}\n\n/**\n * Convert a raw time string (e.g. `14:30`) into the digit order of the\n * display pattern (e.g. `14:30:00` → `1430`).\n *\n * The output is intentionally digits-only and un-delimited — the caller is\n * expected to pass the result through `cleave-zen`'s `formatTime` (or an\n * equivalent) to add the configured delimiter and pad missing segments.\n * The source pattern is `timeRawPattern`; the target pattern is\n * `timePattern`.\n */\nexport const getTimeValueFromRaw = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern =\n options.timeRawPattern ?? options.timePattern ?? DEFAULT_TIME_RAW_PATTERN\n const targetPattern = options.timePattern ?? DEFAULT_TIME_PATTERN\n\n return formatTimeSegments(\n getTimeSegments(value, sourcePattern),\n targetPattern\n )\n}\n\nconst getDateRawValue = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.datePattern ?? DEFAULT_DATE_PATTERN\n const targetPattern = options.dateRawPattern ?? DEFAULT_DATE_RAW_PATTERN\n const delimiter =\n options.dateRawPatternDelimiter ?? DEFAULT_DATE_RAW_PATTERN_DELIMITER\n\n return formatDateSegments(\n getDateSegments(value, sourcePattern),\n targetPattern,\n delimiter\n )\n}\n\nconst getTimeRawValue = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.timePattern ?? DEFAULT_TIME_PATTERN\n const targetPattern =\n options.timeRawPattern ?? options.timePattern ?? DEFAULT_TIME_RAW_PATTERN\n const delimiter =\n options.timeRawPatternDelimiter ?? DEFAULT_TIME_RAW_PATTERN_DELIMITER\n\n return formatTimeSegments(\n getTimeSegments(value, sourcePattern),\n targetPattern,\n delimiter\n )\n}\n\n/**\n * Strip a configured `prefix` from either the start or the end of `value`.\n * `tailPrefix: true` treats the prefix as a suffix.\n */\nexport const stripPrefixAndSuffix = (\n value: string,\n options: FormatOptions = {}\n): string => {\n if (!value || !options.prefix) return value\n\n const { prefix } = options\n const tailPrefix = options.tailPrefix ?? false\n\n if (tailPrefix && value.endsWith(prefix)) {\n return value.slice(0, -prefix.length)\n }\n\n if (!tailPrefix && value.startsWith(prefix)) {\n return value.slice(prefix.length)\n }\n\n return value\n}\n\n/**\n * Convert a formatted value back into its raw counterpart (digits only,\n * canonical structure ready to ship to a backend).\n */\nexport const getRawValue = (\n value: string,\n formatType: FormatType,\n options: FormatOptions = {}\n): string => {\n if (!value) return ''\n\n const cleanValue = stripPrefixAndSuffix(value, options)\n\n switch (formatType) {\n case 'numeral': {\n const numeralOpts: { numeralDecimalMark?: string } = {}\n if (options.numeralDecimalMark !== undefined) {\n numeralOpts.numeralDecimalMark = options.numeralDecimalMark\n }\n return unformatNumeral(cleanValue, numeralOpts)\n }\n\n case 'creditCard':\n case 'creditCardType':\n return unformatCreditCard(cleanValue)\n\n case 'general': {\n const generalOpts: {\n delimiter?: string\n delimiters?: string[]\n } = {}\n if (options.delimiter !== undefined) generalOpts.delimiter = options.delimiter\n if (options.delimiters !== undefined) generalOpts.delimiters = options.delimiters\n return unformatGeneral(cleanValue, generalOpts)\n }\n\n case 'date':\n return getDateRawValue(cleanValue, options)\n\n case 'time':\n return getTimeRawValue(cleanValue, options)\n\n case 'phone':\n return cleanValue.replace(/[^\\d+]/g, '')\n\n default:\n return cleanValue.replace(/\\s+/g, '')\n }\n}","import {\n formatCreditCard,\n formatDate,\n formatGeneral,\n formatNumeral,\n formatTime,\n getCreditCardType,\n type FormatGeneralOptions\n} from 'cleave-zen'\n\nimport { formatPhone } from './phone.js'\nimport {\n getDateValueFromRaw,\n getTimeValueFromRaw,\n type FormatOptions,\n type FormatType\n} from './raw.js'\n\nexport type { FormatOptions, FormatType }\n\nexport const FORMAT_TYPES = [\n 'general',\n 'phone',\n 'numeral',\n 'date',\n 'time',\n 'creditCard',\n 'creditCardType'\n] as const satisfies readonly FormatType[]\n\nexport const isFormatType = (value: unknown): value is FormatType =>\n typeof value === 'string' &&\n (FORMAT_TYPES as readonly string[]).includes(value)\n\ntype RuntimeOptions = FormatOptions & {\n country: string\n delimiter?: string\n}\n\n// Per-type defaults applied only when the caller does not pass their own.\n// `phone` overrides cleave-zen because libphonenumber emits spaces natively;\n// every other type lets cleave-zen pick its own idiomatic delimiter\n// (`/`, `:`, `,`, etc.) by leaving `delimiter` undefined on the runtime\n// options object passed downstream.\nconst PHONE_DEFAULT_DELIMITER = ' '\nconst PHONE_DEFAULT_COUNTRY = 'MX'\n\n/**\n * Internal: pick a country/delimiter-aware runtime options object with\n * phone-specific defaults applied. For non-phone formats the `delimiter`\n * is left as the user supplied it (or absent) so cleave-zen falls back to\n * its idiomatic defaults.\n */\nconst resolveRuntimeOptions = (\n formatType: FormatType,\n options: FormatOptions = {}\n): RuntimeOptions => {\n const isPhone = formatType === 'phone'\n const country = options.country ?? (isPhone ? PHONE_DEFAULT_COUNTRY : '')\n\n // Build the runtime options without ever assigning `undefined` to optional\n // fields (so `exactOptionalPropertyTypes` stays happy) and without ever\n // adding an explicit empty-string `delimiter` for non-phone types (so\n // cleave-zen falls back to its own idiomatic default).\n const runtime: RuntimeOptions = {\n ...options,\n country\n }\n\n if (options.delimiter !== undefined) {\n runtime.delimiter = options.delimiter\n } else if (isPhone) {\n runtime.delimiter = PHONE_DEFAULT_DELIMITER\n }\n\n return runtime\n}\n\n/**\n * Internal: format a pre-processed value into its display representation\n * by delegating to the matching `cleave-zen` (or `formatPhone`) helper.\n */\nconst formatValue = (\n value: string,\n formatType: FormatType,\n options: RuntimeOptions\n): string => {\n switch (formatType) {\n case 'phone':\n return formatPhone(value, options.country, options.delimiter)\n\n case 'numeral':\n return formatNumeral(value, options)\n\n case 'date':\n return formatDate(value, options)\n\n case 'time':\n return formatTime(value, options)\n\n case 'creditCard':\n return formatCreditCard(value, options)\n\n case 'creditCardType':\n return getCreditCardType(value, options.delimiter)\n\n case 'general':\n // cleave-zen's `formatGeneral` requires `blocks` in its options;\n // `FormatOptions` does not declare it (consumers pick blocks via\n // their own configuration). This cast is the documented seam.\n return formatGeneral(\n value,\n options as unknown as FormatGeneralOptions\n )\n }\n}\n\n/**\n * Internal: pre-process `value` before passing it to the per-type formatter.\n * Date and time inputs are first converted from raw to the display pattern\n * (so users can type either formatted or raw and still get sensible output).\n */\nconst getValueForFormatting = (\n value: string,\n formatType: FormatType,\n options: RuntimeOptions\n): string => {\n if (formatType === 'date') {\n return getDateValueFromRaw(value, options)\n }\n\n if (formatType === 'time') {\n return getTimeValueFromRaw(value, options)\n }\n\n return value\n}\n\nexport { formatValue, getValueForFormatting, resolveRuntimeOptions }","import {\n formatValue,\n getValueForFormatting,\n resolveRuntimeOptions,\n FORMAT_TYPES,\n isFormatType,\n type FormatType\n} from './format.js'\n\nimport { getRawValue, stripPrefixAndSuffix } from './raw.js'\n\nimport type { FormatterResult, FormatOptions } from './types.js'\n\nexport type { FormatOptions, FormatType, FormatterResult }\nexport { FORMAT_TYPES, isFormatType, stripPrefixAndSuffix }\n\n/**\n * Format `value` according to `formatType`, returning both a presentable\n * `formatted` string and a backend-ready `raw` string.\n *\n * The function is pure: it never touches the DOM and never reads from the\n * network. Pair it with your own input wiring (React, Vue, Svelte, vanilla)\n * to drive the visible field; mirror `result.raw` into a hidden input when\n * shipping to a server that expects clean digits.\n *\n * @param value - The raw value typed by the user (`null`/`undefined`/`''` return an empty result).\n * @param formatType - One of the supported `FormatType` values.\n * @param options - Per-type options (see `FormatOptions`).\n * @returns A `FormatterResult` with `formatted`, `raw`, and the echoed `type`.\n * @throws {TypeError} When `formatType` is not one of the supported types.\n */\nexport const format = (\n value: unknown,\n formatType: FormatType,\n options: FormatOptions = {}\n): FormatterResult => {\n if (!isFormatType(formatType)) {\n throw new TypeError(\n `Invalid formatType: ${String(formatType)}. Expected one of: ${FORMAT_TYPES.join(', ')}`\n )\n }\n\n if (value === null || value === undefined || value === '') {\n return { formatted: '', raw: '', type: formatType }\n }\n\n const runtime = resolveRuntimeOptions(formatType, options)\n const stringValue = typeof value === 'string' ? value : String(value)\n const cleanValue = stripPrefixAndSuffix(stringValue, runtime)\n const preValue = getValueForFormatting(cleanValue, formatType, runtime)\n const formatted = formatValue(preValue, formatType, runtime)\n // `getRawValue` normally consumes the *formatted* display string (mirrors\n // the original `syncRawInputValue` pipeline). The one exception is\n // `creditCardType`, where `formatted` is the card brand name (e.g. \"visa\")\n // rather than the card number — the raw needs to come from the cleaned\n // input directly.\n const raw =\n formatType === 'creditCardType'\n ? getRawValue(cleanValue, formatType, runtime)\n : getRawValue(formatted, formatType, runtime)\n\n return { formatted, raw, type: formatType }\n}","// Validation patterns exposed as public API for form consumers that pair\n// formatting with validation. Each entry bundles the regex with a ready-to-use\n// error message so consumers do not have to keep them in sync.\n\nexport const regex = {\n phone: {\n // 10 digit phone numbers, allowing for optional country code and delimiters\n pattern: /^(?:\\D*\\d){10}\\D*$/,\n errorMessage: 'Please enter a valid 10-digit phone number.'\n },\n email: {\n pattern: /^[^\\s@]+@[^\\s@]+\\.[a-zA-Z]{2,}$/,\n errorMessage: 'Please enter a valid email address.'\n },\n rfc: {\n // Mexican RFC format (simplified)\n pattern: /^([A-ZÑ&]{3,4})\\d{6}([A-Z0-9]{0,3})$/i,\n errorMessage: 'Please enter a valid RFC.'\n },\n numeral: {\n // Numbers with optional thousand separators and decimal points\n pattern: /\\d{1,3}(,\\d{3})*(\\.\\d+)?/,\n errorMessage: 'Please enter a valid number.'\n },\n onlyNumbers: {\n pattern: /^\\d+$/,\n errorMessage: 'Please enter only numbers.'\n },\n creditCard: {\n // 15 or 16 digits, allowing spaces or delimiters\n pattern: /^(?:\\D*\\d){15,16}\\D*$/,\n errorMessage: 'Please enter a valid card number.'\n },\n expirationDate: {\n // MM/YY format\n pattern: /^(0[1-9]|1[0-2])\\/\\d{2}$/,\n errorMessage: 'Please enter a valid expiration date.'\n },\n cardCvc: {\n // 3 or 4 digit card security codes\n pattern: /^\\d{3,4}$/,\n errorMessage: 'Please enter a valid CVC.'\n },\n onlyLetters: {\n // Letters only (including accented characters and spaces)\n pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ\\s]+$/,\n errorMessage: 'Please enter only letters.'\n },\n onlyAlphanumeric: {\n // Letters and numbers (including accented characters and spaces)\n pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ0-9\\s]+$/,\n errorMessage: 'Please enter only letters and numbers.'\n }\n} as const\n\nexport type RegexKey = keyof typeof regex"]}
1
+ {"version":3,"sources":["../src/core/phone.ts","../src/core/raw.ts","../src/core/format.ts","../src/core/formatter.ts","../src/core/regex.ts"],"names":["digits"],"mappings":"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","file":"index.js","sourcesContent":["import { AsYouType, type CountryCode } from 'libphonenumber-js'\n\n/**\n * Format a phone number string using `libphonenumber-js`'s `AsYouType`.\n *\n * Non-digit characters are stripped before formatting (the leading `+` is\n * preserved so international numbers keep their country prefix). After\n * formatting, spaces produced by `AsYouType` are swapped for `delimiter` when\n * a custom delimiter is provided.\n *\n * @param value - The raw input (digits, `+`, spaces, dashes, parentheses, etc.).\n * @param country - ISO 3166-1 alpha-2 country code (e.g. `'MX'`, `'US'`).\n * @param delimiter - Character used to separate groups in the output.\n * @returns The formatted phone string, or `''` when `value` is empty.\n */\nexport const formatPhone = (\n value: string,\n country: string = 'MX',\n delimiter: string = ' '\n): string => {\n if (!value) return ''\n\n // Preserve '+' so international numbers keep their prefix.\n const digits = value.replace(/[^\\d+]/g, '')\n const formatter = new AsYouType(country as CountryCode)\n const formatted = formatter.input(digits)\n\n if (delimiter !== ' ') {\n return formatted.replace(/ /g, delimiter)\n }\n\n return formatted\n}","import {\n unformatCreditCard,\n unformatGeneral,\n unformatNumeral,\n type DatePatternType,\n type DateUnit,\n type FormatCreditCardOptions,\n type FormatDateOptions,\n type FormatGeneralOptions,\n type FormatNumeralOptions,\n type FormatTimeOptions,\n type TimePatternType,\n type TimeUnit\n} from 'cleave-zen'\n\nexport type FormatType =\n | 'general'\n | 'phone'\n | 'numeral'\n | 'date'\n | 'time'\n | 'creditCard'\n | 'creditCardType'\n\ntype ExtraFormatOptions = {\n country?: string\n dateRawPattern?: DatePatternType\n dateRawPatternDelimiter?: string\n timeRawPattern?: TimePatternType\n timeRawPatternDelimiter?: string\n tailPrefix?: boolean\n}\n\nexport type FormatOptions = Partial<\nFormatGeneralOptions &\nFormatNumeralOptions &\nFormatDateOptions &\nFormatTimeOptions &\nFormatCreditCardOptions\n> &\nExtraFormatOptions\n\ntype DateSegmentKey = 'day' | 'month' | 'year'\ntype TimeSegmentKey = 'hours' | 'minutes' | 'seconds'\n\nconst DEFAULT_DATE_PATTERN: DatePatternType = ['d', 'm', 'Y']\nconst DEFAULT_DATE_RAW_PATTERN: DatePatternType = ['Y', 'm', 'd']\nconst DEFAULT_DATE_RAW_PATTERN_DELIMITER = '-'\nconst DEFAULT_TIME_PATTERN: TimePatternType = ['h', 'm', 's']\nconst DEFAULT_TIME_RAW_PATTERN: TimePatternType = ['h', 'm']\nconst DEFAULT_TIME_RAW_PATTERN_DELIMITER = ':'\n\nconst getDateSegmentKey = (unit: DateUnit): DateSegmentKey => {\n switch (unit.toLowerCase()) {\n case 'd':\n return 'day'\n case 'm':\n return 'month'\n default:\n return 'year'\n }\n}\n\nconst getDateUnitLength = (unit: DateUnit): 2 | 4 =>\n unit === 'Y' ? 4 : 2\n\nconst normalizeDateSegment = (segment: string, unit: DateUnit): string => {\n if (!segment) return ''\n\n switch (unit) {\n case 'y':\n return segment.slice(-2)\n case 'Y':\n return segment.slice(0, 4)\n default:\n return segment.slice(0, 2)\n }\n}\n\nconst getDateSegments = (\n value: string,\n pattern: DatePatternType\n): Partial<Record<DateSegmentKey, string>> => {\n const digits = value.replace(/[^\\d]/g, '')\n const segments: Partial<Record<DateSegmentKey, string>> = {}\n let start = 0\n\n for (const unit of pattern) {\n const end = start + getDateUnitLength(unit)\n const segment = digits.slice(start, end)\n\n if (segment) {\n segments[getDateSegmentKey(unit)] = segment\n }\n\n start = end\n }\n\n return segments\n}\n\nconst formatDateSegments = (\n segments: Partial<Record<DateSegmentKey, string>>,\n pattern: DatePatternType,\n delimiter = ''\n): string =>\n pattern\n .map((unit) =>\n normalizeDateSegment(segments[getDateSegmentKey(unit)] ?? '', unit)\n )\n .filter(Boolean)\n .join(delimiter)\n\nconst getTimeSegmentKey = (unit: TimeUnit): TimeSegmentKey => {\n switch (unit) {\n case 'h':\n return 'hours'\n case 'm':\n return 'minutes'\n default:\n return 'seconds'\n }\n}\n\nconst getTimeSegments = (\n value: string,\n pattern: TimePatternType\n): Partial<Record<TimeSegmentKey, string>> => {\n const digits = value.replace(/[^\\d]/g, '')\n const segments: Partial<Record<TimeSegmentKey, string>> = {}\n let start = 0\n\n for (const unit of pattern) {\n const end = start + 2\n const segment = digits.slice(start, end)\n\n if (segment) {\n segments[getTimeSegmentKey(unit)] = segment\n }\n\n start = end\n }\n\n return segments\n}\n\nconst formatTimeSegments = (\n segments: Partial<Record<TimeSegmentKey, string>>,\n pattern: TimePatternType,\n delimiter = ''\n): string =>\n pattern\n .map((unit) => (segments[getTimeSegmentKey(unit)] ?? '').slice(0, 2))\n .filter(Boolean)\n .join(delimiter)\n\n/**\n * Convert a raw date string (e.g. `2026-05-12`) into the digit order of the\n * display pattern (e.g. `12/05/2026` → `12052026`).\n *\n * The output is intentionally digits-only and un-delimited — the caller is\n * expected to pass the result through `cleave-zen`'s `formatDate` (or an\n * equivalent) to add the configured delimiter. The source pattern is\n * `dateRawPattern`; the target pattern is `datePattern`.\n */\nexport const getDateValueFromRaw = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.dateRawPattern ?? DEFAULT_DATE_RAW_PATTERN\n const targetPattern = options.datePattern ?? DEFAULT_DATE_PATTERN\n\n return formatDateSegments(\n getDateSegments(value, sourcePattern),\n targetPattern\n )\n}\n\n/**\n * Convert a raw time string (e.g. `14:30`) into the digit order of the\n * display pattern (e.g. `14:30:00` → `1430`).\n *\n * The output is intentionally digits-only and un-delimited — the caller is\n * expected to pass the result through `cleave-zen`'s `formatTime` (or an\n * equivalent) to add the configured delimiter and pad missing segments.\n * The source pattern is `timeRawPattern`; the target pattern is\n * `timePattern`.\n */\nexport const getTimeValueFromRaw = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern =\n options.timeRawPattern ?? options.timePattern ?? DEFAULT_TIME_RAW_PATTERN\n const targetPattern = options.timePattern ?? DEFAULT_TIME_PATTERN\n\n return formatTimeSegments(\n getTimeSegments(value, sourcePattern),\n targetPattern\n )\n}\n\nconst getDateRawValue = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.datePattern ?? DEFAULT_DATE_PATTERN\n const targetPattern = options.dateRawPattern ?? DEFAULT_DATE_RAW_PATTERN\n const delimiter =\n options.dateRawPatternDelimiter ?? DEFAULT_DATE_RAW_PATTERN_DELIMITER\n\n return formatDateSegments(\n getDateSegments(value, sourcePattern),\n targetPattern,\n delimiter\n )\n}\n\nconst getTimeRawValue = (\n value: string,\n options: FormatOptions = {}\n): string => {\n const sourcePattern = options.timePattern ?? DEFAULT_TIME_PATTERN\n const targetPattern =\n options.timeRawPattern ?? options.timePattern ?? DEFAULT_TIME_RAW_PATTERN\n const delimiter =\n options.timeRawPatternDelimiter ?? DEFAULT_TIME_RAW_PATTERN_DELIMITER\n\n return formatTimeSegments(\n getTimeSegments(value, sourcePattern),\n targetPattern,\n delimiter\n )\n}\n\n/**\n * Strip a configured `prefix` from either the start or the end of `value`.\n * `tailPrefix: true` treats the prefix as a suffix.\n */\nexport const stripPrefixAndSuffix = (\n value: string,\n options: FormatOptions = {}\n): string => {\n if (!value || !options.prefix) return value\n\n const { prefix } = options\n const tailPrefix = options.tailPrefix ?? false\n\n if (tailPrefix && value.endsWith(prefix)) {\n return value.slice(0, -prefix.length)\n }\n\n if (!tailPrefix && value.startsWith(prefix)) {\n return value.slice(prefix.length)\n }\n\n return value\n}\n\n/**\n * Convert a formatted value back into its raw counterpart (digits only,\n * canonical structure ready to ship to a backend).\n */\nexport const getRawValue = (\n value: string,\n formatType: FormatType,\n options: FormatOptions = {}\n): string => {\n if (!value) return ''\n\n const cleanValue = stripPrefixAndSuffix(value, options)\n\n switch (formatType) {\n case 'numeral': {\n const numeralOpts: { numeralDecimalMark?: string } = {}\n if (options.numeralDecimalMark !== undefined) {\n numeralOpts.numeralDecimalMark = options.numeralDecimalMark\n }\n return unformatNumeral(cleanValue, numeralOpts)\n }\n\n case 'creditCard':\n case 'creditCardType':\n return unformatCreditCard(cleanValue)\n\n case 'general': {\n const generalOpts: {\n delimiter?: string\n delimiters?: string[]\n } = {}\n if (options.delimiter !== undefined) generalOpts.delimiter = options.delimiter\n if (options.delimiters !== undefined) generalOpts.delimiters = options.delimiters\n return unformatGeneral(cleanValue, generalOpts)\n }\n\n case 'date':\n return getDateRawValue(cleanValue, options)\n\n case 'time':\n return getTimeRawValue(cleanValue, options)\n\n case 'phone':\n return cleanValue.replace(/[^\\d+]/g, '')\n\n default:\n return cleanValue.replace(/\\s+/g, '')\n }\n}","import {\n formatCreditCard,\n formatDate,\n formatGeneral,\n formatNumeral,\n formatTime,\n getCreditCardType,\n type FormatGeneralOptions\n} from 'cleave-zen'\n\nimport { formatPhone } from './phone.js'\nimport {\n getDateValueFromRaw,\n getTimeValueFromRaw,\n type FormatOptions,\n type FormatType\n} from './raw.js'\n\nexport type { FormatOptions, FormatType }\n\nexport const FORMAT_TYPES = [\n 'general',\n 'phone',\n 'numeral',\n 'date',\n 'time',\n 'creditCard',\n 'creditCardType'\n] as const satisfies readonly FormatType[]\n\nexport const isFormatType = (value: unknown): value is FormatType =>\n typeof value === 'string' &&\n (FORMAT_TYPES as readonly string[]).includes(value)\n\ntype RuntimeOptions = FormatOptions & {\n country: string\n delimiter?: string\n}\n\n// Per-type defaults applied only when the caller does not pass their own.\n// `phone` overrides cleave-zen because libphonenumber emits spaces natively;\n// every other type lets cleave-zen pick its own idiomatic delimiter\n// (`/`, `:`, `,`, etc.) by leaving `delimiter` undefined on the runtime\n// options object passed downstream.\nconst PHONE_DEFAULT_DELIMITER = ' '\nconst PHONE_DEFAULT_COUNTRY = 'MX'\n\n/**\n * Internal: pick a country/delimiter-aware runtime options object with\n * phone-specific defaults applied. For non-phone formats the `delimiter`\n * is left as the user supplied it (or absent) so cleave-zen falls back to\n * its idiomatic defaults.\n */\nconst resolveRuntimeOptions = (\n formatType: FormatType,\n options: FormatOptions = {}\n): RuntimeOptions => {\n const isPhone = formatType === 'phone'\n const country = options.country ?? (isPhone ? PHONE_DEFAULT_COUNTRY : '')\n\n // Build the runtime options without ever assigning `undefined` to optional\n // fields (so `exactOptionalPropertyTypes` stays happy) and without ever\n // adding an explicit empty-string `delimiter` for non-phone types (so\n // cleave-zen falls back to its own idiomatic default).\n const runtime: RuntimeOptions = {\n ...options,\n country\n }\n\n if (options.delimiter !== undefined) {\n runtime.delimiter = options.delimiter\n } else if (isPhone) {\n runtime.delimiter = PHONE_DEFAULT_DELIMITER\n }\n\n return runtime\n}\n\n/**\n * Internal: format a pre-processed value into its display representation\n * by delegating to the matching `cleave-zen` (or `formatPhone`) helper.\n */\nconst formatValue = (\n value: string,\n formatType: FormatType,\n options: RuntimeOptions\n): string => {\n switch (formatType) {\n case 'phone':\n return formatPhone(value, options.country, options.delimiter)\n\n case 'numeral':\n return formatNumeral(value, options)\n\n case 'date':\n return formatDate(value, options)\n\n case 'time':\n return formatTime(value, options)\n\n case 'creditCard':\n return formatCreditCard(value, options)\n\n case 'creditCardType':\n return getCreditCardType(value, options.delimiter)\n\n case 'general':\n // cleave-zen's `formatGeneral` requires `blocks` in its options;\n // `FormatOptions` does not declare it (consumers pick blocks via\n // their own configuration). This cast is the documented seam.\n return formatGeneral(\n value,\n options as unknown as FormatGeneralOptions\n )\n }\n}\n\n/**\n * Internal: pre-process `value` before passing it to the per-type formatter.\n * Date and time inputs are first converted from raw to the display pattern\n * (so users can type either formatted or raw and still get sensible output).\n */\nconst getValueForFormatting = (\n value: string,\n formatType: FormatType,\n options: RuntimeOptions\n): string => {\n if (formatType === 'date') {\n return getDateValueFromRaw(value, options)\n }\n\n if (formatType === 'time') {\n return getTimeValueFromRaw(value, options)\n }\n\n return value\n}\n\nexport { formatValue, getValueForFormatting, resolveRuntimeOptions }","import {\n formatValue,\n getValueForFormatting,\n resolveRuntimeOptions,\n FORMAT_TYPES,\n isFormatType,\n type FormatType\n} from './format.js'\n\nimport { getRawValue, stripPrefixAndSuffix } from './raw.js'\n\nimport type { FormatterResult, FormatOptions } from './types.js'\n\nexport type { FormatOptions, FormatType, FormatterResult }\nexport { FORMAT_TYPES, isFormatType, stripPrefixAndSuffix }\n\n/**\n * Format `value` according to `formatType`, returning both a presentable\n * `formatted` string and a backend-ready `raw` string.\n *\n * The function is pure: it never touches the DOM and never reads from the\n * network. Pair it with your own input wiring (React, Vue, Svelte, vanilla)\n * to drive the visible field; mirror `result.raw` into a hidden input when\n * shipping to a server that expects clean digits.\n *\n * @param value - The raw value typed by the user (`null`/`undefined`/`''` return an empty result).\n * @param formatType - One of the supported `FormatType` values.\n * @param options - Per-type options (see `FormatOptions`).\n * @returns A `FormatterResult` with `formatted`, `raw`, and the echoed `type`.\n * @throws {TypeError} When `formatType` is not one of the supported types.\n */\nexport const format = (\n value: unknown,\n formatType: FormatType,\n options: FormatOptions = {}\n): FormatterResult => {\n if (!isFormatType(formatType)) {\n throw new TypeError(\n `Invalid formatType: ${String(formatType)}. Expected one of: ${FORMAT_TYPES.join(', ')}`\n )\n }\n\n if (value === null || value === undefined || value === '') {\n return { formatted: '', raw: '', type: formatType }\n }\n\n const runtime = resolveRuntimeOptions(formatType, options)\n const stringValue = typeof value === 'string' ? value : String(value)\n const cleanValue = stripPrefixAndSuffix(stringValue, runtime)\n const preValue = getValueForFormatting(cleanValue, formatType, runtime)\n const formatted = formatValue(preValue, formatType, runtime)\n // `getRawValue` normally consumes the *formatted* display string (mirrors\n // the original `syncRawInputValue` pipeline). The one exception is\n // `creditCardType`, where `formatted` is the card brand name (e.g. \"visa\")\n // rather than the card number — the raw needs to come from the cleaned\n // input directly.\n const raw =\n formatType === 'creditCardType'\n ? getRawValue(cleanValue, formatType, runtime)\n : getRawValue(formatted, formatType, runtime)\n\n return { formatted, raw, type: formatType }\n}","/**\n * # Regex Module\n *\n * Validation patterns exposed as public API for form consumers that pair\n * formatting with validation. Each entry bundles the regex with a ready-to-use\n * error message so consumers do not have to keep them in sync.\n *\n * ## Usage\n *\n * **Static (backward compatible):**\n * ```ts\n * regex.phone.pattern.test('5512345678') // true\n * regex.email.errorMessage // 'Please enter a valid email address.'\n * ```\n *\n * **Parametric (dynamic):**\n * ```ts\n * regex.digits(10).pattern.test('1234567890') // true\n * regex.digits(7).pattern.test('1234567') // true\n * regex.phone({ length: 10 }).pattern.test('1234567890')\n * regex.phone({ length: 7 }).pattern.test('1234567')\n * ```\n *\n * **Custom regex:**\n * ```ts\n * regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO')\n * ```\n *\n * ## Available Patterns\n *\n * | Key | Static | Parametric | Description |\n * | --- | --- | --- | --- |\n * | `phone` | ✅ | ✅ `({ length })` | Phone numbers |\n * | `email` | ✅ | — | Email addresses |\n * | `rfc` | ✅ | — | Mexican RFC |\n * | `curp` | ✅ | — | Mexican CURP |\n * | `cp` | ✅ | — | Mexican postal code (5 digits) |\n * | `numeral` | ✅ | — | Numbers with separators |\n * | `onlyNumbers` | ✅ | ✅ `({ length })` | Digits only |\n * | `digits` | — | ✅ `({ length, min, max })` | Variable digit count |\n * | `creditCard` | ✅ | ✅ `({ min, max })` | Card numbers |\n * | `expirationDate` | ✅ | — | MM/YY format |\n * | `cardCvc` | ✅ | — | 3-4 digit CVC |\n * | `onlyLetters` | ✅ | — | Letters only |\n * | `onlyAlphanumeric` | ✅ | — | Letters and numbers |\n * | `url` | ✅ | ✅ `({ protocol })` | URLs |\n * | `ipv4` | ✅ | — | IPv4 addresses |\n * | `ipv6` | ✅ | — | IPv6 addresses |\n * | `uuid` | ✅ | — | UUID v4 |\n * | `hexColor` | ✅ | — | Hex color codes |\n * | `hashtag` | ✅ | — | Social media hashtags |\n * | `mention` | ✅ | — | Social media mentions |\n * | `password` | — | ✅ `({ min, max, rules })` | Password strength |\n * | `custom` | — | ✅ `({ pattern, errorMessage })` | User-defined regex |\n */\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport interface RegexEntry {\n pattern: RegExp\n errorMessage: string\n}\n\ninterface PhoneParams {\n length?: number\n}\n\ninterface DigitsParams {\n length?: number\n min?: number\n max?: number\n}\n\ninterface CreditCardParams {\n min?: number\n max?: number\n}\n\ninterface UrlParams {\n protocol?: 'http' | 'https' | 'ftp' | 'all'\n}\n\ninterface PasswordParams {\n min?: number\n max?: number\n uppercase?: boolean\n lowercase?: boolean\n numbers?: boolean\n special?: boolean\n}\n\ninterface CustomParams {\n pattern: RegExp\n errorMessage: string\n}\n\n\n// ─── Internal Factories ──────────────────────────────────────────────────────\n\nfunction createDigits(min: number, max: number, errorMsg: string): RegexEntry {\n return {\n pattern: new RegExp(`^\\\\d{${min},${max}}$`),\n errorMessage: errorMsg\n }\n}\n\nfunction createPhone(length: number): RegexEntry {\n return {\n pattern: new RegExp(`^(?:\\\\D*\\\\d){${length}}\\\\D*$`),\n errorMessage: `Please enter a valid ${length}-digit phone number.`\n }\n}\n\nfunction createCreditCard(min: number, max: number): RegexEntry {\n return {\n pattern: new RegExp(`^(?:\\\\D*\\\\d){${min},${max}}\\\\D*$`),\n errorMessage: `Please enter a valid card number (${min}-${max} digits).`\n }\n}\n\nfunction createUrl(requireProtocol: 'http' | 'https' | 'ftp' | 'all'): RegexEntry {\n const protocol = requireProtocol === 'all' ? 'https?' : requireProtocol\n return {\n pattern: new RegExp(`^${protocol}://[^\\\\s]+$`),\n errorMessage: `Please enter a valid URL${requireProtocol !== 'all' ? ` (${requireProtocol}://...)` : ''}.`\n }\n}\n\nfunction createPassword(params: PasswordParams): RegexEntry {\n const {\n min = 8,\n max = 128,\n uppercase = true,\n lowercase = true,\n numbers = true,\n special = false\n } = params\n\n // Build the character class with proper escaping (put - last to avoid range issues)\n let chars = ''\n if (uppercase) chars += 'A-Z'\n if (lowercase) chars += 'a-z'\n if (numbers) chars += '0-9'\n if (special) chars += '!@#$%^&*()_+\\\\-=\\\\[\\\\]{}|;:\\'\",.<>?/'\n\n const ruleParts: string[] = []\n if (uppercase) ruleParts.push('uppercase letter')\n if (lowercase) ruleParts.push('lowercase letter')\n if (numbers) ruleParts.push('number')\n if (special) ruleParts.push('special character')\n\n const rulesText = ruleParts.length > 2\n ? ruleParts.slice(0, -1).join(', ') + ' and ' + ruleParts.slice(-1)\n : ruleParts.join(' and ')\n\n return {\n pattern: new RegExp(`^[${chars}]{${min},${max}}$`),\n errorMessage: `Password must be ${min}-${max} characters with at least one ${rulesText}.`\n }\n}\n\n// ─── Static Patterns ─────────────────────────────────────────────────────────\n\nconst _regex = {\n phone: {\n pattern: /^(?:\\D*\\d){10}\\D*$/,\n errorMessage: 'Please enter a valid 10-digit phone number.'\n },\n email: {\n // Simple but effective email validation\n pattern: /^[^\\s@]+@[^\\s@]+\\.[a-zA-Z]{2,}$/,\n errorMessage: 'Please enter a valid email address.'\n },\n rfc: {\n // Mexican RFC ( Personas Morales y Físicas )\n pattern: /^([A-ZÑ&]{3,4})\\d{6}([A-Z0-9]{0,3})$/i,\n errorMessage: 'Please enter a valid RFC.'\n },\n curp: {\n // Mexican CURP (18 characters)\n pattern: /^[A-Z]{4}\\d{6}[A-Z]{6}[0-9A-Z]\\d$/i,\n errorMessage: 'Please enter a valid CURP.'\n },\n cp: {\n // Mexican postal code (5 digits)\n pattern: /^\\d{5}$/,\n errorMessage: 'Please enter a valid 5-digit postal code.'\n },\n numeral: {\n // Numbers with optional thousand separators and decimal points\n pattern: /\\d{1,3}(,\\d{3})*(\\.\\d+)?/,\n errorMessage: 'Please enter a valid number.'\n },\n onlyNumbers: {\n pattern: /^\\d+$/,\n errorMessage: 'Please enter only numbers.'\n },\n creditCard: {\n // 15 or 16 digits, allowing spaces or delimiters\n pattern: /^(?:\\D*\\d){15,16}\\D*$/,\n errorMessage: 'Please enter a valid card number (15-16 digits).'\n },\n expirationDate: {\n // MM/YY or MM/YYYY format\n pattern: /^(0[1-9]|1[0-2])\\/(\\d{2}|\\d{4})$/,\n errorMessage: 'Please enter a valid expiration date (MM/YY or MM/YYYY).'\n },\n cardCvc: {\n // 3 or 4 digit card security codes\n pattern: /^\\d{3,4}$/,\n errorMessage: 'Please enter a valid CVC (3-4 digits).'\n },\n onlyLetters: {\n // Letters only (including accented characters and spaces)\n pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ\\s]+$/,\n errorMessage: 'Please enter only letters.'\n },\n onlyAlphanumeric: {\n // Letters and numbers (including accented characters and spaces)\n pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ0-9\\s]+$/,\n errorMessage: 'Please enter only letters and numbers.'\n },\n url: {\n // Accepts http, https, ftp\n pattern: /^(?:https?|ftp):\\/\\/[^\\s]+$/,\n errorMessage: 'Please enter a valid URL.'\n },\n ipv4: {\n // IPv4 addresses (0-255 per octet)\n 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]?)$/,\n errorMessage: 'Please enter a valid IPv4 address.'\n },\n ipv6: {\n // IPv6 addresses (simplified)\n pattern: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/,\n errorMessage: 'Please enter a valid IPv6 address.'\n },\n uuid: {\n // UUID v4\n pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n errorMessage: 'Please enter a valid UUID.'\n },\n hexColor: {\n // Hex color codes (#RGB or #RRGGBB)\n pattern: /^#(?:[0-9a-fA-F]{3}){1,2}$/,\n errorMessage: 'Please enter a valid hex color code (e.g., #FFF or #FFFFFF).'\n },\n hashtag: {\n // Social media hashtags\n pattern: /^#[a-zA-Z_][a-zA-Z0-9_]*$/,\n errorMessage: 'Please enter a valid hashtag (e.g., #example).'\n },\n mention: {\n // Social media mentions\n pattern: /^@[a-zA-Z_][a-zA-Z0-9_]*$/,\n errorMessage: 'Please enter a valid mention (e.g., @username).'\n },\n postalCode: {\n // Generic 5-digit postal code (US-style ZIP / MX CP)\n pattern: /^\\d{5}(?:-\\d{4})?$/,\n errorMessage: 'Please enter a valid postal code (e.g., 90210 or 90210-1234).'\n },\n time24: {\n // 24-hour time HH:MM\n pattern: /^([01]\\d|2[0-3]):([0-5]\\d)$/,\n errorMessage: 'Please enter a valid 24-hour time (HH:MM).'\n },\n date: {\n // ISO-like date YYYY-MM-DD (loose)\n pattern: /^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$/,\n errorMessage: 'Please enter a valid date (YYYY-MM-DD).'\n },\n slug: {\n // URL slug (lowercase, hyphens, no spaces)\n pattern: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,\n errorMessage: 'Please enter a valid slug (lowercase, hyphens, no spaces).'\n },\n username: {\n // Username: 3-20 chars, alphanumeric, underscore, hyphen\n pattern: /^[a-zA-Z0-9_-]{3,20}$/,\n errorMessage: 'Please enter a valid username (3-20 chars, letters, numbers, _ or -).'\n },\n macAddress: {\n // MAC address (colon or hyphen separated)\n pattern: /^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/,\n errorMessage: 'Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7).'\n },\n semver: {\n // Semantic version (X.Y.Z with optional -prerelease)\n pattern: /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[a-zA-Z0-9.-]+)?$/,\n errorMessage: 'Please enter a valid semantic version (e.g., 1.2.3).'\n },\n base64: {\n // Base64 encoded string\n pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,\n errorMessage: 'Please enter a valid Base64 encoded string.'\n }\n} as const\n\n// ─── Parametric Extensions ───────────────────────────────────────────────────\n\n/**\n * Digits with configurable length.\n * @example\n * regex.digits(10).pattern.test('1234567890') // true\n * regex.digits({ length: 7 }).pattern.test('1234567') // true\n * regex.digits({ min: 3, max: 10 }).pattern.test('12345') // true\n */\nfunction digits(params?: number | DigitsParams): RegexEntry {\n if (typeof params === 'number') {\n return createDigits(params, params, `Please enter exactly ${params} digits.`)\n }\n const { length, min = 1, max = 20 } = params ?? {}\n const actualMin = length ?? min\n const actualMax = length ?? max\n if (actualMin === actualMax) {\n return createDigits(actualMin, actualMax, `Please enter exactly ${actualMin} digits.`)\n }\n return createDigits(actualMin, actualMax, `Please enter ${actualMin}-${actualMax} digits.`)\n}\n\n/**\n * Phone with configurable digit count.\n *\n * Also available as static entry: regex.phone.pattern (10 digits)\n * @example\n * regex.phone().pattern.test('5512345678') // true (10 digits)\n * regex.phone({ length: 7 }).pattern.test('1234567') // true (7 digits)\n */\nfunction _phoneFn(params?: PhoneParams): RegexEntry {\n const length = params?.length ?? 10\n return createPhone(length)\n}\n\n/**\n * Credit card with configurable digit range.\n *\n * Also available as static entry: regex.creditCard.pattern (15-16 digits)\n * @example\n * regex.creditCard().pattern.test('4111111111111111') // true (15-16)\n * regex.creditCard({ min: 13, max: 19 }).pattern.test('1234567890123') // true\n */\nfunction _creditCardFn(params?: CreditCardParams): RegexEntry {\n const min = params?.min ?? 15\n const max = params?.max ?? 16\n return createCreditCard(min, max)\n}\n\n/**\n * URL with configurable protocol.\n *\n * Also available as static entry: regex.url.pattern (any protocol)\n * @example\n * regex.url().pattern.test('https://example.com') // true\n * regex.url({ protocol: 'https' }).pattern.test('https://example.com') // true\n * regex.url({ protocol: 'https' }).pattern.test('ftp://example.com') // false\n */\nfunction _urlFn(params?: UrlParams): RegexEntry {\n const protocol = params?.protocol ?? 'all'\n return createUrl(protocol)\n}\n\n/**\n * Password with configurable strength rules.\n * @example\n * regex.password().pattern.test('Passw0rd!') // true (default: 8+ chars, upper, lower, number)\n * regex.password({ min: 12, special: true }).pattern.test('MyP@ssw0rd!') // true\n */\nfunction _passwordFn(params?: PasswordParams): RegexEntry {\n return createPassword(params ?? {})\n}\n\n/**\n * Custom regex provided by the user.\n * @example\n * regex.custom(/^[A-Z]{5}$/, 'Must be 5 uppercase letters').pattern.test('HELLO') // true\n * regex.custom({ pattern: /^\\d+$/, errorMessage: 'Numbers only' }).pattern.test('123') // true\n */\nfunction _customFn(pattern: RegExp, errorMessage?: string): RegexEntry\nfunction _customFn(params: CustomParams): RegexEntry\nfunction _customFn(\n arg1: RegExp | CustomParams,\n arg2?: string\n): RegexEntry {\n if (arg1 instanceof RegExp) {\n return { pattern: arg1, errorMessage: arg2 ?? 'Invalid value.' }\n }\n return { pattern: arg1.pattern, errorMessage: arg1.errorMessage }\n}\n\n// ─── Callable Objects with Attached Pattern ──────────────────────────────────\n\n// These are callable functions that also have .pattern and .errorMessage attached\n// This allows both: regex.phone({ length: 7 }) AND regex.phone.pattern\n\nconst phoneFn = _phoneFn as typeof _phoneFn & RegexEntry\nphoneFn.pattern = _regex.phone.pattern\nphoneFn.errorMessage = _regex.phone.errorMessage\n\nconst creditCardFn = _creditCardFn as typeof _creditCardFn & RegexEntry\ncreditCardFn.pattern = _regex.creditCard.pattern\ncreditCardFn.errorMessage = _regex.creditCard.errorMessage\n\nconst urlFn = _urlFn as typeof _urlFn & RegexEntry\nurlFn.pattern = _regex.url.pattern\nurlFn.errorMessage = _regex.url.errorMessage\n\n// Parametric-only functions need default error messages\nconst digitsFn = digits as typeof digits & RegexEntry\ndigitsFn.errorMessage = 'Please enter a valid number.'\n\nconst passwordFn = _passwordFn as typeof _passwordFn & RegexEntry\npasswordFn.errorMessage = 'Please enter a valid password.'\n\nconst customFn = _customFn as typeof _customFn & RegexEntry\ncustomFn.errorMessage = 'Please enter a valid value.'\n\n// ─── Final Export ─────────────────────────────────────────────────────────────\n\nexport const regex = {\n // Static entries (backward compatible - spread first)\n ..._regex,\n\n // Parametric functions\n digits: digitsFn,\n phone: phoneFn,\n creditCard: creditCardFn,\n url: urlFn,\n password: passwordFn,\n custom: customFn\n} as const\n\nexport type RegexKey = keyof typeof _regex\nexport type Regex = typeof regex"]}
@@ -6,9 +6,9 @@ var libphonenumberJs = require('libphonenumber-js');
6
6
  // src/core/format.ts
7
7
  var formatPhone = (value, country = "MX", delimiter = " ") => {
8
8
  if (!value) return "";
9
- const digits = value.replace(/[^\d+]/g, "");
9
+ const digits2 = value.replace(/[^\d+]/g, "");
10
10
  const formatter = new libphonenumberJs.AsYouType(country);
11
- const formatted = formatter.input(digits);
11
+ const formatted = formatter.input(digits2);
12
12
  if (delimiter !== " ") {
13
13
  return formatted.replace(/ /g, delimiter);
14
14
  }
@@ -43,12 +43,12 @@ var normalizeDateSegment = (segment, unit) => {
43
43
  }
44
44
  };
45
45
  var getDateSegments = (value, pattern) => {
46
- const digits = value.replace(/[^\d]/g, "");
46
+ const digits2 = value.replace(/[^\d]/g, "");
47
47
  const segments = {};
48
48
  let start = 0;
49
49
  for (const unit of pattern) {
50
50
  const end = start + getDateUnitLength(unit);
51
- const segment = digits.slice(start, end);
51
+ const segment = digits2.slice(start, end);
52
52
  if (segment) {
53
53
  segments[getDateSegmentKey(unit)] = segment;
54
54
  }
@@ -70,12 +70,12 @@ var getTimeSegmentKey = (unit) => {
70
70
  }
71
71
  };
72
72
  var getTimeSegments = (value, pattern) => {
73
- const digits = value.replace(/[^\d]/g, "");
73
+ const digits2 = value.replace(/[^\d]/g, "");
74
74
  const segments = {};
75
75
  let start = 0;
76
76
  for (const unit of pattern) {
77
77
  const end = start + 2;
78
- const segment = digits.slice(start, end);
78
+ const segment = digits2.slice(start, end);
79
79
  if (segment) {
80
80
  segments[getTimeSegmentKey(unit)] = segment;
81
81
  }
@@ -241,21 +241,81 @@ var format = (value, formatType, options = {}) => {
241
241
  };
242
242
 
243
243
  // src/core/regex.ts
244
- var regex = {
244
+ function createDigits(min, max, errorMsg) {
245
+ return {
246
+ pattern: new RegExp(`^\\d{${min},${max}}$`),
247
+ errorMessage: errorMsg
248
+ };
249
+ }
250
+ function createPhone(length) {
251
+ return {
252
+ pattern: new RegExp(`^(?:\\D*\\d){${length}}\\D*$`),
253
+ errorMessage: `Please enter a valid ${length}-digit phone number.`
254
+ };
255
+ }
256
+ function createCreditCard(min, max) {
257
+ return {
258
+ pattern: new RegExp(`^(?:\\D*\\d){${min},${max}}\\D*$`),
259
+ errorMessage: `Please enter a valid card number (${min}-${max} digits).`
260
+ };
261
+ }
262
+ function createUrl(requireProtocol) {
263
+ const protocol = requireProtocol === "all" ? "https?" : requireProtocol;
264
+ return {
265
+ pattern: new RegExp(`^${protocol}://[^\\s]+$`),
266
+ errorMessage: `Please enter a valid URL${requireProtocol !== "all" ? ` (${requireProtocol}://...)` : ""}.`
267
+ };
268
+ }
269
+ function createPassword(params) {
270
+ const {
271
+ min = 8,
272
+ max = 128,
273
+ uppercase = true,
274
+ lowercase = true,
275
+ numbers = true,
276
+ special = false
277
+ } = params;
278
+ let chars = "";
279
+ if (uppercase) chars += "A-Z";
280
+ if (lowercase) chars += "a-z";
281
+ if (numbers) chars += "0-9";
282
+ if (special) chars += `!@#$%^&*()_+\\-=\\[\\]{}|;:'",.<>?/`;
283
+ const ruleParts = [];
284
+ if (uppercase) ruleParts.push("uppercase letter");
285
+ if (lowercase) ruleParts.push("lowercase letter");
286
+ if (numbers) ruleParts.push("number");
287
+ if (special) ruleParts.push("special character");
288
+ const rulesText = ruleParts.length > 2 ? ruleParts.slice(0, -1).join(", ") + " and " + ruleParts.slice(-1) : ruleParts.join(" and ");
289
+ return {
290
+ pattern: new RegExp(`^[${chars}]{${min},${max}}$`),
291
+ errorMessage: `Password must be ${min}-${max} characters with at least one ${rulesText}.`
292
+ };
293
+ }
294
+ var _regex = {
245
295
  phone: {
246
- // 10 digit phone numbers, allowing for optional country code and delimiters
247
296
  pattern: /^(?:\D*\d){10}\D*$/,
248
297
  errorMessage: "Please enter a valid 10-digit phone number."
249
298
  },
250
299
  email: {
300
+ // Simple but effective email validation
251
301
  pattern: /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}$/,
252
302
  errorMessage: "Please enter a valid email address."
253
303
  },
254
304
  rfc: {
255
- // Mexican RFC format (simplified)
305
+ // Mexican RFC ( Personas Morales y Físicas )
256
306
  pattern: /^([A-ZÑ&]{3,4})\d{6}([A-Z0-9]{0,3})$/i,
257
307
  errorMessage: "Please enter a valid RFC."
258
308
  },
309
+ curp: {
310
+ // Mexican CURP (18 characters)
311
+ pattern: /^[A-Z]{4}\d{6}[A-Z]{6}[0-9A-Z]\d$/i,
312
+ errorMessage: "Please enter a valid CURP."
313
+ },
314
+ cp: {
315
+ // Mexican postal code (5 digits)
316
+ pattern: /^\d{5}$/,
317
+ errorMessage: "Please enter a valid 5-digit postal code."
318
+ },
259
319
  numeral: {
260
320
  // Numbers with optional thousand separators and decimal points
261
321
  pattern: /\d{1,3}(,\d{3})*(\.\d+)?/,
@@ -268,17 +328,17 @@ var regex = {
268
328
  creditCard: {
269
329
  // 15 or 16 digits, allowing spaces or delimiters
270
330
  pattern: /^(?:\D*\d){15,16}\D*$/,
271
- errorMessage: "Please enter a valid card number."
331
+ errorMessage: "Please enter a valid card number (15-16 digits)."
272
332
  },
273
333
  expirationDate: {
274
- // MM/YY format
275
- pattern: /^(0[1-9]|1[0-2])\/\d{2}$/,
276
- errorMessage: "Please enter a valid expiration date."
334
+ // MM/YY or MM/YYYY format
335
+ pattern: /^(0[1-9]|1[0-2])\/(\d{2}|\d{4})$/,
336
+ errorMessage: "Please enter a valid expiration date (MM/YY or MM/YYYY)."
277
337
  },
278
338
  cardCvc: {
279
339
  // 3 or 4 digit card security codes
280
340
  pattern: /^\d{3,4}$/,
281
- errorMessage: "Please enter a valid CVC."
341
+ errorMessage: "Please enter a valid CVC (3-4 digits)."
282
342
  },
283
343
  onlyLetters: {
284
344
  // Letters only (including accented characters and spaces)
@@ -289,7 +349,142 @@ var regex = {
289
349
  // Letters and numbers (including accented characters and spaces)
290
350
  pattern: /^[A-Za-zÁÉÍÓÚáéíóúÑñ0-9\s]+$/,
291
351
  errorMessage: "Please enter only letters and numbers."
352
+ },
353
+ url: {
354
+ // Accepts http, https, ftp
355
+ pattern: /^(?:https?|ftp):\/\/[^\s]+$/,
356
+ errorMessage: "Please enter a valid URL."
357
+ },
358
+ ipv4: {
359
+ // IPv4 addresses (0-255 per octet)
360
+ 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]?)$/,
361
+ errorMessage: "Please enter a valid IPv4 address."
362
+ },
363
+ ipv6: {
364
+ // IPv6 addresses (simplified)
365
+ pattern: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/,
366
+ errorMessage: "Please enter a valid IPv6 address."
367
+ },
368
+ uuid: {
369
+ // UUID v4
370
+ pattern: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
371
+ errorMessage: "Please enter a valid UUID."
372
+ },
373
+ hexColor: {
374
+ // Hex color codes (#RGB or #RRGGBB)
375
+ pattern: /^#(?:[0-9a-fA-F]{3}){1,2}$/,
376
+ errorMessage: "Please enter a valid hex color code (e.g., #FFF or #FFFFFF)."
377
+ },
378
+ hashtag: {
379
+ // Social media hashtags
380
+ pattern: /^#[a-zA-Z_][a-zA-Z0-9_]*$/,
381
+ errorMessage: "Please enter a valid hashtag (e.g., #example)."
382
+ },
383
+ mention: {
384
+ // Social media mentions
385
+ pattern: /^@[a-zA-Z_][a-zA-Z0-9_]*$/,
386
+ errorMessage: "Please enter a valid mention (e.g., @username)."
387
+ },
388
+ postalCode: {
389
+ // Generic 5-digit postal code (US-style ZIP / MX CP)
390
+ pattern: /^\d{5}(?:-\d{4})?$/,
391
+ errorMessage: "Please enter a valid postal code (e.g., 90210 or 90210-1234)."
392
+ },
393
+ time24: {
394
+ // 24-hour time HH:MM
395
+ pattern: /^([01]\d|2[0-3]):([0-5]\d)$/,
396
+ errorMessage: "Please enter a valid 24-hour time (HH:MM)."
397
+ },
398
+ date: {
399
+ // ISO-like date YYYY-MM-DD (loose)
400
+ pattern: /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/,
401
+ errorMessage: "Please enter a valid date (YYYY-MM-DD)."
402
+ },
403
+ slug: {
404
+ // URL slug (lowercase, hyphens, no spaces)
405
+ pattern: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
406
+ errorMessage: "Please enter a valid slug (lowercase, hyphens, no spaces)."
407
+ },
408
+ username: {
409
+ // Username: 3-20 chars, alphanumeric, underscore, hyphen
410
+ pattern: /^[a-zA-Z0-9_-]{3,20}$/,
411
+ errorMessage: "Please enter a valid username (3-20 chars, letters, numbers, _ or -)."
412
+ },
413
+ macAddress: {
414
+ // MAC address (colon or hyphen separated)
415
+ pattern: /^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/,
416
+ errorMessage: "Please enter a valid MAC address (e.g., 00:1B:44:11:3A:B7)."
417
+ },
418
+ semver: {
419
+ // Semantic version (X.Y.Z with optional -prerelease)
420
+ pattern: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[a-zA-Z0-9.-]+)?$/,
421
+ errorMessage: "Please enter a valid semantic version (e.g., 1.2.3)."
422
+ },
423
+ base64: {
424
+ // Base64 encoded string
425
+ pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,
426
+ errorMessage: "Please enter a valid Base64 encoded string."
427
+ }
428
+ };
429
+ function digits(params) {
430
+ if (typeof params === "number") {
431
+ return createDigits(params, params, `Please enter exactly ${params} digits.`);
292
432
  }
433
+ const { length, min = 1, max = 20 } = params ?? {};
434
+ const actualMin = length ?? min;
435
+ const actualMax = length ?? max;
436
+ if (actualMin === actualMax) {
437
+ return createDigits(actualMin, actualMax, `Please enter exactly ${actualMin} digits.`);
438
+ }
439
+ return createDigits(actualMin, actualMax, `Please enter ${actualMin}-${actualMax} digits.`);
440
+ }
441
+ function _phoneFn(params) {
442
+ const length = params?.length ?? 10;
443
+ return createPhone(length);
444
+ }
445
+ function _creditCardFn(params) {
446
+ const min = params?.min ?? 15;
447
+ const max = params?.max ?? 16;
448
+ return createCreditCard(min, max);
449
+ }
450
+ function _urlFn(params) {
451
+ const protocol = params?.protocol ?? "all";
452
+ return createUrl(protocol);
453
+ }
454
+ function _passwordFn(params) {
455
+ return createPassword(params ?? {});
456
+ }
457
+ function _customFn(arg1, arg2) {
458
+ if (arg1 instanceof RegExp) {
459
+ return { pattern: arg1, errorMessage: arg2 ?? "Invalid value." };
460
+ }
461
+ return { pattern: arg1.pattern, errorMessage: arg1.errorMessage };
462
+ }
463
+ var phoneFn = _phoneFn;
464
+ phoneFn.pattern = _regex.phone.pattern;
465
+ phoneFn.errorMessage = _regex.phone.errorMessage;
466
+ var creditCardFn = _creditCardFn;
467
+ creditCardFn.pattern = _regex.creditCard.pattern;
468
+ creditCardFn.errorMessage = _regex.creditCard.errorMessage;
469
+ var urlFn = _urlFn;
470
+ urlFn.pattern = _regex.url.pattern;
471
+ urlFn.errorMessage = _regex.url.errorMessage;
472
+ var digitsFn = digits;
473
+ digitsFn.errorMessage = "Please enter a valid number.";
474
+ var passwordFn = _passwordFn;
475
+ passwordFn.errorMessage = "Please enter a valid password.";
476
+ var customFn = _customFn;
477
+ customFn.errorMessage = "Please enter a valid value.";
478
+ var regex = {
479
+ // Static entries (backward compatible - spread first)
480
+ ..._regex,
481
+ // Parametric functions
482
+ digits: digitsFn,
483
+ phone: phoneFn,
484
+ creditCard: creditCardFn,
485
+ url: urlFn,
486
+ password: passwordFn,
487
+ custom: customFn
293
488
  };
294
489
 
295
490
  exports.FORMAT_TYPES = FORMAT_TYPES;