first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
# path-matcher
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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.