first commit
This commit is contained in:
80
docs/foundation/data/data-masking/src/strategies/phone.md
Normal file
80
docs/foundation/data/data-masking/src/strategies/phone.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# phone strategy
|
||||
|
||||
## Purpose
|
||||
|
||||
The `phone` masking strategy anonymises phone numbers while preserving their
|
||||
formatting separators, making masked values easy to read in logs and audit
|
||||
trails. Only the last 4 digits are kept; all other digit positions are
|
||||
replaced with `*`. Non-digit characters (hyphens, spaces, parentheses, dots,
|
||||
`+`) pass through unchanged, so the output retains the same visual structure
|
||||
as the input regardless of locale or formatting convention.
|
||||
|
||||
## Features
|
||||
|
||||
- Last-4-digit preservation regardless of phone format.
|
||||
- Separator characters (`-`, ` `, `(`, `)`, `.`, `+`) are preserved verbatim.
|
||||
- Handles international formats (`+1-…`), US formats (`(555) 123-4567`), and
|
||||
unformatted digit strings (`5551234567`).
|
||||
- No regex-based capture groups or lookaheads — single linear pass.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { maskPhone } from '@suaveplan/data-masking/strategies/phone';
|
||||
|
||||
const masked = maskPhone('+1-555-123-4567', { fields: ['phone'], strategy: 'phone' });
|
||||
// masked → '*-***-***-4567'
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { maskPhone } from '@suaveplan/data-masking/strategies/phone';
|
||||
|
||||
// US format with parentheses
|
||||
maskPhone('(555) 123-4567', { fields: ['phone'], strategy: 'phone' });
|
||||
// → '(***) ***-4567'
|
||||
|
||||
// E.164 international
|
||||
maskPhone('+447911123456', { fields: ['phone'], strategy: 'phone' });
|
||||
// → '+*********3456'
|
||||
|
||||
// Unformatted
|
||||
maskPhone('5551234567', { fields: ['phone'], strategy: 'phone' });
|
||||
// → '******4567'
|
||||
|
||||
// No digits at all → passthrough
|
||||
maskPhone('N/A', { fields: ['phone'], strategy: 'phone' });
|
||||
// → 'N/A'
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `maskPhone(value, rule)`
|
||||
|
||||
```ts
|
||||
function maskPhone(value: string, rule: MaskRule): string;
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------------|----------------------------------------------------------|
|
||||
| `value` | `string` | The original phone number in any format. |
|
||||
| `rule` | `MaskRule` | Driving rule (no fields are consumed by phone strategy). |
|
||||
|
||||
**Returns** the masked phone string with last 4 digits preserved and all other
|
||||
digit positions replaced by `*`.
|
||||
|
||||
**Does not throw.** Returns the original value unchanged when no digit
|
||||
characters are found.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The strategy extracts all digits first to determine the `keepFrom` boundary
|
||||
(total digits minus 4), then makes a single linear pass over the original
|
||||
string to rebuild the result. This avoids multi-pass scanning and keeps
|
||||
the logic O(n).
|
||||
- `Math.max(0, digits.length - 4)` ensures that strings with 4 or fewer digits
|
||||
are returned with all digits preserved (no masking applied), matching the
|
||||
principle of least surprise.
|
||||
- The `rule` parameter is accepted to satisfy the uniform strategy interface
|
||||
but none of its fields are consumed.
|
||||
Reference in New Issue
Block a user