/** * L3 — incremental regex matching for input masks. * * A regex such as `/^[A-Z]{2}[0-9]{4}$/` describes the *final* value, not the * intermediate states a user types through. Validating partial input against a * full-match regex is impossible with the native `RegExp` engine: `'A'` and `'1'` * both fail `^[A-Z]{2}[0-9]{4}$`, but only `'1'` should be rejected. * * This module compiles the pattern into a small Thompson NFA and simulates it one * character at a time, so it can tell whether the value so far is a complete * match ({@link DONE}), a valid prefix that could still grow ({@link MORE}), or * impossible ({@link FAILED}). * * Supported syntax: literals, `.`, escapes (`\d \D \w \W \s \S`, `\p{…}` / * `\P{…}`, `\n \t \r \f \v \0`, `\xNN`, `\uXXXX`, `\u{…}`, `\cX` and * punctuation escapes), character classes `[...]` / `[^...]` with ranges, groups * `(...)`, `(?:...)` and `(?...)`, alternation `|`, quantifiers `* + ? * {n} {n,} {n,m}`, and anchors `^ $`. Flags are honoured: `i` folds literals and * ranges, `s` widens `.`, `u` / `v` enable `\p{…}` and `\u{…}`. * * Lookarounds, back-references and word boundaries cannot be modelled by a * finite automaton. Patterns using them — and any pattern the native `RegExp` * rejects — compile to a failure carrying the reason, and the caller degrades to * pass-through rather than locking the user out of the field. An escape this * parser does not model fails the same way: reading it as the escaped letter * would build an automaton that silently rejects everything the pattern was * written to accept. * * Ported from `takeoff-ui/packages/core/src/utils/regex-mask-utils.ts`. The one * behavioural change: the original discarded the failure reason in * `catch { return null }`, leaving a consumer with a silently inert mask. Here the * reason survives so `useMask` can warn in development. */ /** The value is a complete match for the pattern. */ export declare const DONE = "DONE"; /** The value is a valid prefix; more characters could complete it. */ export declare const MORE = "MORE"; /** The value can never match the pattern, no matter what is appended. */ export declare const FAILED = "FAILED"; export type MatchState = typeof DONE | typeof MORE | typeof FAILED; /** Classifies a value against a compiled pattern. */ export type IncrementalMatcher = (value: string) => MatchState; /** * A left-to-right scan that keeps its own position in the automaton. * * {@link IncrementalMatcher} re-simulates the whole value on every call, so * building a value character by character costs O(n²). A scanner carries the * state set forward instead, which is what the masking loop needs: one step per * character, and a rejected character leaves the state untouched. */ export interface MatcherScanner { /** Feeds one character. On {@link FAILED} the scanner does not advance. */ push: (char: string) => MatchState; /** The verdict for everything pushed so far. */ state: () => MatchState; } /** Outcome of {@link createIncrementalMatcher}. */ export type MatcherCompileResult = { ok: true; matcher: IncrementalMatcher; scan: () => MatcherScanner; } | { ok: false; reason: string; }; /** * Builds a reusable matcher for a pattern. * * @param source - Regex source string. Anchors `^ $` are accepted and treated as * a single-line, fully-anchored match. * @param flags - The `RegExp` flags the pattern was written with. `i`, `s` and * `u` / `v` change what a character matches and are honoured; `g`, `y` and `m` * cannot change the verdict for a whole value and are ignored. * @returns Either the matcher, or a failure carrying the reason the pattern could * not be compiled. Callers degrade to pass-through on failure — a regex the * matcher cannot handle must never lock the user out of the field — but should * surface the reason in development rather than fail silently. */ export declare const createIncrementalMatcher: (source: string, flags?: string) => MatcherCompileResult; /** Strips a leading `^` and a trailing `$`, for use where anchors are implied. */ export declare const stripAnchors: (source: string) => string;