# path-matcher _(no submodules)_ ## Purpose Implements a lightweight glob-style matcher for dot-notation object-path strings used by `@suaveplan/data-masking`'s rule engine. When a `MaskRule` declares `fields: ['user.*']` the path matcher is responsible for deciding whether a path like `'user.email'` satisfies that pattern during object traversal. Zero external dependencies are required — the entire implementation is a recursive backtracking segment comparator that handles the three modes callers need in practice. ## Features - Exact matching: `"user.email"` matches `"user.email"`. - Single-segment wildcard `*`: matches any one dot-separated segment. - Multi-segment wildcard `**`: matches zero or more consecutive dot-separated segments, enabling patterns like `"**.email"` or `"user.**"`. - Correct handling of leading, trailing, and adjacent wildcards through backtracking. - Pure function — no state, no side-effects, zero allocations beyond the initial `split`. ## Usage: Basic Example ```ts import { matchPath } from '@suaveplan/data-masking/utils/path-matcher'; matchPath('user.email', 'user.email'); // true — exact matchPath('user.name', 'user.email'); // false — no match matchPath('user.email', 'user.*'); // true — single wildcard ``` ## Usage: Advanced Example ```ts import { matchPath } from '@suaveplan/data-masking/utils/path-matcher'; // Match any path ending in .email regardless of depth matchPath('billing.contact.email', '**.email'); // true matchPath('email', '**.email'); // true (** matches zero segs) // Match everything under user.* matchPath('user.address.city', 'user.**'); // true matchPath('user.address.city', 'user.*'); // false — * is single-segment only matchPath('user.address', 'user.*'); // true // Combine wildcards matchPath('a.b.c.d', '*.b.**.d'); // true ``` ## API Reference ### `matchPath(fieldPath, pattern)` ```ts function matchPath(fieldPath: string, pattern: string): boolean; ``` | Parameter | Type | Description | |-------------|----------|--------------------------------------------------------| | `fieldPath` | `string` | Concrete dot-notation path, e.g. `"user.address.zip"`. | | `pattern` | `string` | Glob pattern with optional `*` / `**` wildcards. | **Returns** `true` when `fieldPath` satisfies `pattern`, `false` otherwise. **Does not throw.** Both empty strings are treated as single empty-segment paths and will only match each other or a lone `*` / `**` pattern. ## Implementation Notes - The implementation splits both inputs on `"."` and feeds the resulting arrays into a recursive `matchSegments` helper. The recursion depth is bounded by `Math.max(pathSegments, patternSegments)`, which in practice is small (typically < 10 for real object paths). - The `**` wildcard uses a greedy-with-backtrack strategy: it first attempts to match zero path segments (advance only the pattern pointer), then progressively tries consuming one more path segment per recursive call. This guarantees correct results for patterns like `"**.email"` where `**` must match zero leading segments. - No regular expressions are used, avoiding edge-case escaping issues with field names that contain regex metacharacters (dots, brackets, etc.). - The function is intentionally kept free of any optional parameters or configuration — the three modes (exact, `*`, `**`) cover every use case encountered in PII field-path matching.