first commit
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# preserve-format strategy
|
||||
|
||||
## Purpose
|
||||
|
||||
The `preserve-format` masking strategy replaces every alphanumeric character
|
||||
with a placeholder of the same character class — digits become `0`, letters
|
||||
become `X` — while leaving all punctuation, spaces, and special characters
|
||||
unchanged. The result has the same total length and the same structural
|
||||
"skeleton" as the original, which allows downstream systems (parsers, validators,
|
||||
format checkers) to continue operating on the masked data without seeing any
|
||||
real content. This is particularly useful in schema-validation pipelines that
|
||||
process PII-bearing fields and must remain functional during testing against
|
||||
production-shaped data.
|
||||
|
||||
## Features
|
||||
|
||||
- Length-preserving: output has exactly the same character count as input.
|
||||
- Character-class-preserving: digits → `0`, letters → `X`, other → verbatim.
|
||||
- No regex — single character-by-character pass, safe on all Unicode inputs
|
||||
(only ASCII alphanumerics are substituted; non-ASCII passes through).
|
||||
- Zero external dependencies.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { maskPreserveFormat } from '@suaveplan/data-masking/strategies/preserve-format';
|
||||
|
||||
const masked = maskPreserveFormat('Hello123', { fields: ['code'], strategy: 'preserve-format' });
|
||||
// masked → 'XXXXX000'
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { maskPreserveFormat } from '@suaveplan/data-masking/strategies/preserve-format';
|
||||
|
||||
// Phone with separators
|
||||
maskPreserveFormat('+1-555-123-4567', { fields: ['phone'], strategy: 'preserve-format' });
|
||||
// → '+0-000-000-0000'
|
||||
|
||||
// Mixed alphanumeric code
|
||||
maskPreserveFormat('AB12-CD34-EF56', { fields: ['serial'], strategy: 'preserve-format' });
|
||||
// → 'XX00-XX00-XX00'
|
||||
|
||||
// Non-ASCII pass-through (accented chars preserved)
|
||||
maskPreserveFormat('café 42', { fields: ['label'], strategy: 'preserve-format' });
|
||||
// → 'XXXX 00' (é is non-ASCII and passes through as-is)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `maskPreserveFormat(value, rule)`
|
||||
|
||||
```ts
|
||||
function maskPreserveFormat(value: string, rule: MaskRule): string;
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------------|----------------------------------------------------------------|
|
||||
| `value` | `string` | The original string to format-preserve. |
|
||||
| `rule` | `MaskRule` | Driving rule (no fields consumed by preserve-format strategy). |
|
||||
|
||||
**Returns** a same-length string with alphanumeric chars replaced by `0` / `X`
|
||||
and all other chars preserved.
|
||||
|
||||
**Does not throw.**
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Only ASCII alphanumerics (`a-z`, `A-Z`, `0-9`) are replaced. Non-ASCII
|
||||
characters (including accented letters, CJK, emoji) pass through unchanged.
|
||||
This is intentional: the strategy targets structured English-language data
|
||||
formats (phone numbers, reference codes, account identifiers) where only
|
||||
ASCII alphanumerics carry sensitive content.
|
||||
- The `for...of` iteration correctly handles multi-code-unit Unicode characters
|
||||
(surrogate pairs) because JavaScript iterates by codepoint in `for...of`.
|
||||
The ASCII range check ensures non-ASCII characters are passed through intact.
|
||||
- The `rule` parameter is silently voided to satisfy the uniform strategy
|
||||
interface.
|
||||
Reference in New Issue
Block a user