n8n-nodes-redactor 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +42 -0
  2. package/README.dev.md +153 -0
  3. package/README.md +443 -0
  4. package/README.npm.md +443 -0
  5. package/dist/nodes/PiiRedactor/PiiRedactor.node.d.ts +5 -0
  6. package/dist/nodes/PiiRedactor/PiiRedactor.node.js +1093 -0
  7. package/dist/nodes/PiiRedactor/__tests__/encryption.test.d.ts +1 -0
  8. package/dist/nodes/PiiRedactor/__tests__/encryption.test.js +200 -0
  9. package/dist/nodes/PiiRedactor/__tests__/engine.test.d.ts +1 -0
  10. package/dist/nodes/PiiRedactor/__tests__/engine.test.js +524 -0
  11. package/dist/nodes/PiiRedactor/__tests__/operations.test.d.ts +1 -0
  12. package/dist/nodes/PiiRedactor/__tests__/operations.test.js +316 -0
  13. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.d.ts +1 -0
  14. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.js +427 -0
  15. package/dist/nodes/PiiRedactor/__tests__/patterns.test.d.ts +1 -0
  16. package/dist/nodes/PiiRedactor/__tests__/patterns.test.js +481 -0
  17. package/dist/nodes/PiiRedactor/__tests__/phase1.test.d.ts +1 -0
  18. package/dist/nodes/PiiRedactor/__tests__/phase1.test.js +343 -0
  19. package/dist/nodes/PiiRedactor/__tests__/phase3.test.d.ts +1 -0
  20. package/dist/nodes/PiiRedactor/__tests__/phase3.test.js +275 -0
  21. package/dist/nodes/PiiRedactor/__tests__/phase4.test.d.ts +1 -0
  22. package/dist/nodes/PiiRedactor/__tests__/phase4.test.js +184 -0
  23. package/dist/nodes/PiiRedactor/__tests__/presidio.test.d.ts +1 -0
  24. package/dist/nodes/PiiRedactor/__tests__/presidio.test.js +170 -0
  25. package/dist/nodes/PiiRedactor/__tests__/security.test.d.ts +1 -0
  26. package/dist/nodes/PiiRedactor/__tests__/security.test.js +178 -0
  27. package/dist/nodes/PiiRedactor/__tests__/semantic.test.d.ts +1 -0
  28. package/dist/nodes/PiiRedactor/__tests__/semantic.test.js +319 -0
  29. package/dist/nodes/PiiRedactor/__tests__/vault.test.d.ts +1 -0
  30. package/dist/nodes/PiiRedactor/__tests__/vault.test.js +247 -0
  31. package/dist/nodes/PiiRedactor/audit.d.ts +48 -0
  32. package/dist/nodes/PiiRedactor/audit.js +192 -0
  33. package/dist/nodes/PiiRedactor/classification.d.ts +33 -0
  34. package/dist/nodes/PiiRedactor/classification.js +118 -0
  35. package/dist/nodes/PiiRedactor/context.d.ts +57 -0
  36. package/dist/nodes/PiiRedactor/context.js +260 -0
  37. package/dist/nodes/PiiRedactor/encryption.d.ts +45 -0
  38. package/dist/nodes/PiiRedactor/encryption.js +158 -0
  39. package/dist/nodes/PiiRedactor/engine.d.ts +23 -0
  40. package/dist/nodes/PiiRedactor/engine.js +888 -0
  41. package/dist/nodes/PiiRedactor/injection.d.ts +46 -0
  42. package/dist/nodes/PiiRedactor/injection.js +425 -0
  43. package/dist/nodes/PiiRedactor/names.d.ts +25 -0
  44. package/dist/nodes/PiiRedactor/names.js +188 -0
  45. package/dist/nodes/PiiRedactor/patterns.d.ts +17 -0
  46. package/dist/nodes/PiiRedactor/patterns.js +1742 -0
  47. package/dist/nodes/PiiRedactor/presidio.d.ts +77 -0
  48. package/dist/nodes/PiiRedactor/presidio.js +264 -0
  49. package/dist/nodes/PiiRedactor/profiles.d.ts +47 -0
  50. package/dist/nodes/PiiRedactor/profiles.js +139 -0
  51. package/dist/nodes/PiiRedactor/pseudonymize.d.ts +20 -0
  52. package/dist/nodes/PiiRedactor/pseudonymize.js +203 -0
  53. package/dist/nodes/PiiRedactor/redact.png +0 -0
  54. package/dist/nodes/PiiRedactor/redact.svg +3 -0
  55. package/dist/nodes/PiiRedactor/ropa.d.ts +63 -0
  56. package/dist/nodes/PiiRedactor/ropa.js +70 -0
  57. package/dist/nodes/PiiRedactor/types.d.ts +82 -0
  58. package/dist/nodes/PiiRedactor/types.js +3 -0
  59. package/dist/nodes/PiiRedactor/vault.d.ts +61 -0
  60. package/dist/nodes/PiiRedactor/vault.js +352 -0
  61. package/package.json +87 -0
@@ -0,0 +1,481 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const patterns_1 = require("../patterns");
4
+ /**
5
+ * Helper: test a pattern against input, return all matches.
6
+ */
7
+ function matchAll(patternName, input) {
8
+ const pattern = patterns_1.PII_PATTERNS.find((p) => p.name === patternName);
9
+ if (!pattern)
10
+ throw new Error(`Pattern not found: ${patternName}`);
11
+ const re = new RegExp(pattern.regex.source, pattern.regex.flags);
12
+ const matches = [];
13
+ let m;
14
+ while ((m = re.exec(input)) !== null) {
15
+ // Run validator if present
16
+ if (pattern.validate && !pattern.validate(m[0]))
17
+ continue;
18
+ matches.push(m[0]);
19
+ }
20
+ return matches;
21
+ }
22
+ // ═══════════════════════════════════════════════════════
23
+ // EMAIL
24
+ // ═══════════════════════════════════════════════════════
25
+ describe('Email pattern', () => {
26
+ test('matches standard emails', () => {
27
+ expect(matchAll('email', 'contact me at john@example.com please')).toEqual(['john@example.com']);
28
+ });
29
+ test('matches emails with dots, plus, hyphens', () => {
30
+ expect(matchAll('email', 'john.doe+tag@sub-domain.example.co.uk')).toEqual([
31
+ 'john.doe+tag@sub-domain.example.co.uk',
32
+ ]);
33
+ });
34
+ test('matches multiple emails', () => {
35
+ const result = matchAll('email', 'From alice@foo.com to bob@bar.org cc charlie@baz.net');
36
+ expect(result).toEqual(['alice@foo.com', 'bob@bar.org', 'charlie@baz.net']);
37
+ });
38
+ test('does NOT match invalid emails', () => {
39
+ expect(matchAll('email', 'not-an-email')).toEqual([]);
40
+ expect(matchAll('email', '@nodomain.com')).toEqual([]);
41
+ expect(matchAll('email', 'user@')).toEqual([]);
42
+ });
43
+ test('matches emails with % in local part', () => {
44
+ expect(matchAll('email', 'user%name@example.com')).toEqual(['user%name@example.com']);
45
+ });
46
+ });
47
+ // ═══════════════════════════════════════════════════════
48
+ // PHONE
49
+ // ═══════════════════════════════════════════════════════
50
+ describe('Phone pattern', () => {
51
+ test('matches US phone numbers', () => {
52
+ expect(matchAll('phone', 'Call (555) 123-4567')).toEqual(['(555) 123-4567']);
53
+ });
54
+ test('matches international format with +', () => {
55
+ expect(matchAll('phone', '+49 30 1234-5678')).toEqual(['+49 30 1234-5678']);
56
+ });
57
+ test('matches phone with dots', () => {
58
+ expect(matchAll('phone', '555.123.4567')).toEqual(['555.123.4567']);
59
+ });
60
+ test('matches phone with dashes', () => {
61
+ expect(matchAll('phone', '555-123-4567')).toEqual(['555-123-4567']);
62
+ });
63
+ });
64
+ // ═══════════════════════════════════════════════════════
65
+ // PERSON NAME (heuristic — title prefix)
66
+ // ═══════════════════════════════════════════════════════
67
+ describe('Person name pattern', () => {
68
+ test('matches Mr. prefix', () => {
69
+ expect(matchAll('personName', 'Dear Mr. John Smith,')).toEqual(['Mr. John Smith']);
70
+ });
71
+ test('matches Mrs. prefix', () => {
72
+ expect(matchAll('personName', 'Contact Mrs. Jane Doe')).toEqual(['Mrs. Jane Doe']);
73
+ });
74
+ test('matches Dr. prefix', () => {
75
+ expect(matchAll('personName', 'Dr. Anna Marie Wilson attended')).toEqual(['Dr. Anna Marie Wilson']);
76
+ });
77
+ test('matches Prof. prefix', () => {
78
+ expect(matchAll('personName', 'Prof. Klaus Müller presented')).toEqual(['Prof. Klaus Müller']);
79
+ });
80
+ test('matches German titles', () => {
81
+ expect(matchAll('personName', 'Herr Schmidt called')).toEqual(['Herr Schmidt']);
82
+ expect(matchAll('personName', 'Frau Weber arrived')).toEqual(['Frau Weber']);
83
+ });
84
+ test('matches French titles', () => {
85
+ expect(matchAll('personName', 'Monsieur Dupont signed')).toEqual(['Monsieur Dupont']);
86
+ expect(matchAll('personName', 'Madame Lefèvre confirmed')).toEqual(['Madame Lefèvre']);
87
+ });
88
+ test('matches Spanish titles', () => {
89
+ expect(matchAll('personName', 'Señor García called')).toEqual(['Señor García']);
90
+ });
91
+ test('does NOT match without title prefix', () => {
92
+ // Without title, names won't match (by design — reduces false positives)
93
+ expect(matchAll('personName', 'John Smith called')).toEqual([]);
94
+ });
95
+ test('handles names with accented characters', () => {
96
+ expect(matchAll('personName', 'Mr. José María López')).toEqual(['Mr. José María López']);
97
+ });
98
+ });
99
+ // ═══════════════════════════════════════════════════════
100
+ // SSN
101
+ // ═══════════════════════════════════════════════════════
102
+ describe('SSN pattern', () => {
103
+ test('matches valid SSN', () => {
104
+ expect(matchAll('ssn', 'SSN: 123-45-6789')).toEqual(['123-45-6789']);
105
+ });
106
+ test('does NOT match partial SSN', () => {
107
+ expect(matchAll('ssn', '123-456789')).toEqual([]);
108
+ expect(matchAll('ssn', '12-34-5678')).toEqual([]);
109
+ });
110
+ });
111
+ // ═══════════════════════════════════════════════════════
112
+ // CREDIT CARD (with Luhn validation)
113
+ // ═══════════════════════════════════════════════════════
114
+ describe('Credit card pattern', () => {
115
+ test('matches valid Visa with Luhn check', () => {
116
+ // 4532015112830366 passes Luhn
117
+ expect(matchAll('creditCard', 'Card: 4532 0151 1283 0366')).toEqual(['4532 0151 1283 0366']);
118
+ });
119
+ test('matches with dashes', () => {
120
+ expect(matchAll('creditCard', '4532-0151-1283-0366')).toEqual(['4532-0151-1283-0366']);
121
+ });
122
+ test('rejects invalid Luhn', () => {
123
+ // 1234567890123456 fails Luhn
124
+ expect(matchAll('creditCard', '1234 5678 9012 3456')).toEqual([]);
125
+ });
126
+ test('matches valid Mastercard', () => {
127
+ // 5425233430109903 passes Luhn
128
+ expect(matchAll('creditCard', '5425233430109903')).toEqual(['5425233430109903']);
129
+ });
130
+ });
131
+ // ═══════════════════════════════════════════════════════
132
+ // IBAN (with ISO 13616 checksum)
133
+ // ═══════════════════════════════════════════════════════
134
+ describe('IBAN pattern', () => {
135
+ test('matches valid German IBAN', () => {
136
+ expect(matchAll('iban', 'IBAN: DE89370400440532013000')).toEqual(['DE89370400440532013000']);
137
+ });
138
+ test('matches valid UK IBAN', () => {
139
+ expect(matchAll('iban', 'GB29 NWBK 6016 1331 9268 19')).toEqual(['GB29 NWBK 6016 1331 9268 19']);
140
+ });
141
+ test('matches valid French IBAN', () => {
142
+ expect(matchAll('iban', 'FR7630006000011234567890189')).toEqual(['FR7630006000011234567890189']);
143
+ });
144
+ test('rejects invalid IBAN checksum', () => {
145
+ // DE00370400440532013000 — invalid check digits
146
+ expect(matchAll('iban', 'DE00370400440532013000')).toEqual([]);
147
+ });
148
+ });
149
+ // ═══════════════════════════════════════════════════════
150
+ // BIC / SWIFT
151
+ // ═══════════════════════════════════════════════════════
152
+ describe('BIC/SWIFT pattern', () => {
153
+ test('matches 8-char BIC', () => {
154
+ expect(matchAll('bic', 'BIC: DEUTDEFF')).toEqual(['DEUTDEFF']);
155
+ });
156
+ test('matches 11-char BIC', () => {
157
+ expect(matchAll('bic', 'SWIFT: DEUTDEFF500')).toEqual(['DEUTDEFF500']);
158
+ });
159
+ });
160
+ // ═══════════════════════════════════════════════════════
161
+ // EU VAT
162
+ // ═══════════════════════════════════════════════════════
163
+ describe('EU VAT pattern', () => {
164
+ test('matches German VAT', () => {
165
+ expect(matchAll('vatEU', 'VAT: DE123456789')).toEqual(['DE123456789']);
166
+ });
167
+ test('matches French VAT', () => {
168
+ expect(matchAll('vatEU', 'FR12345678901')).toEqual(['FR12345678901']);
169
+ });
170
+ test('matches Italian VAT', () => {
171
+ expect(matchAll('vatEU', 'IT12345678901')).toEqual(['IT12345678901']);
172
+ });
173
+ test('matches Dutch VAT', () => {
174
+ expect(matchAll('vatEU', 'NL123456789B01')).toEqual(['NL123456789B01']);
175
+ });
176
+ test('matches Austrian VAT', () => {
177
+ expect(matchAll('vatEU', 'ATU12345678')).toEqual(['ATU12345678']);
178
+ });
179
+ });
180
+ // ═══════════════════════════════════════════════════════
181
+ // IP ADDRESSES
182
+ // ═══════════════════════════════════════════════════════
183
+ describe('IPv4 pattern', () => {
184
+ test('matches valid IPv4', () => {
185
+ expect(matchAll('ipv4', 'Server at 192.168.1.1')).toEqual(['192.168.1.1']);
186
+ });
187
+ test('matches multiple IPs', () => {
188
+ expect(matchAll('ipv4', 'From 10.0.0.1 to 172.16.0.255')).toEqual(['10.0.0.1', '172.16.0.255']);
189
+ });
190
+ test('rejects out-of-range octets', () => {
191
+ expect(matchAll('ipv4', '999.999.999.999')).toEqual([]);
192
+ });
193
+ });
194
+ describe('IPv6 pattern', () => {
195
+ test('matches full IPv6', () => {
196
+ expect(matchAll('ipv6', '2001:0db8:85a3:0000:0000:8a2e:0370:7334')).toEqual([
197
+ '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
198
+ ]);
199
+ });
200
+ });
201
+ // ═══════════════════════════════════════════════════════
202
+ // MAC ADDRESS
203
+ // ═══════════════════════════════════════════════════════
204
+ describe('MAC address pattern', () => {
205
+ test('matches colon-separated MAC', () => {
206
+ expect(matchAll('macAddress', 'MAC: 00:1A:2B:3C:4D:5E')).toEqual(['00:1A:2B:3C:4D:5E']);
207
+ });
208
+ test('matches dash-separated MAC', () => {
209
+ expect(matchAll('macAddress', '00-1A-2B-3C-4D-5E')).toEqual(['00-1A-2B-3C-4D-5E']);
210
+ });
211
+ });
212
+ // ═══════════════════════════════════════════════════════
213
+ // URL
214
+ // ═══════════════════════════════════════════════════════
215
+ describe('URL pattern', () => {
216
+ test('matches http URLs', () => {
217
+ expect(matchAll('url', 'Visit http://example.com/path?q=1')).toEqual([
218
+ 'http://example.com/path?q=1',
219
+ ]);
220
+ });
221
+ test('matches https URLs', () => {
222
+ expect(matchAll('url', 'See https://secure.example.org/page')).toEqual([
223
+ 'https://secure.example.org/page',
224
+ ]);
225
+ });
226
+ });
227
+ // ═══════════════════════════════════════════════════════
228
+ // POSTAL CODES
229
+ // ═══════════════════════════════════════════════════════
230
+ describe('UK postcode pattern', () => {
231
+ test('matches standard UK postcode', () => {
232
+ expect(matchAll('postalCodeUK', 'Address: SW1A 1AA')).toEqual(['SW1A 1AA']);
233
+ });
234
+ test('matches without space', () => {
235
+ expect(matchAll('postalCodeUK', 'EC1A1BB')).toEqual(['EC1A1BB']);
236
+ });
237
+ });
238
+ // ═══════════════════════════════════════════════════════
239
+ // GPS COORDINATES
240
+ // ═══════════════════════════════════════════════════════
241
+ describe('GPS coordinates pattern', () => {
242
+ test('matches lat,lng pair', () => {
243
+ expect(matchAll('gpsCoordinates', 'Location: 51.5074, -0.1278')).toEqual(['51.5074, -0.1278']);
244
+ });
245
+ test('matches high-precision coords', () => {
246
+ expect(matchAll('gpsCoordinates', '40.748817,-73.985428')).toEqual(['40.748817,-73.985428']);
247
+ });
248
+ test('does NOT match low-precision numbers', () => {
249
+ expect(matchAll('gpsCoordinates', '12.34, 56.78')).toEqual([]);
250
+ });
251
+ });
252
+ // ═══════════════════════════════════════════════════════
253
+ // DATES
254
+ // ═══════════════════════════════════════════════════════
255
+ describe('Date patterns', () => {
256
+ test('matches slash dates', () => {
257
+ expect(matchAll('dateSlash', 'Born 15/03/1990')).toEqual(['15/03/1990']);
258
+ });
259
+ test('matches ISO dates', () => {
260
+ expect(matchAll('dateDash', 'Date: 2024-03-15')).toEqual(['2024-03-15']);
261
+ });
262
+ test('matches European dot dates', () => {
263
+ expect(matchAll('dateDot', 'Geboren: 15.03.1990')).toEqual(['15.03.1990']);
264
+ });
265
+ test('matches DOB with label', () => {
266
+ expect(matchAll('dateOfBirth', 'DOB: 15/03/1990')).toEqual(['DOB: 15/03/1990']);
267
+ });
268
+ });
269
+ // ═══════════════════════════════════════════════════════
270
+ // MEDICAL
271
+ // ═══════════════════════════════════════════════════════
272
+ describe('Medical record number pattern', () => {
273
+ test('matches MRN with colon', () => {
274
+ expect(matchAll('medicalRecordNumber', 'MRN: 12345678')).toEqual(['MRN: 12345678']);
275
+ });
276
+ test('matches MRN with hash', () => {
277
+ expect(matchAll('medicalRecordNumber', 'MRN#987654')).toEqual(['MRN#987654']);
278
+ });
279
+ });
280
+ // ═══════════════════════════════════════════════════════
281
+ // CRYPTO ADDRESSES
282
+ // ═══════════════════════════════════════════════════════
283
+ describe('Bitcoin address pattern', () => {
284
+ test('matches legacy address (1...)', () => {
285
+ expect(matchAll('bitcoinAddress', 'BTC: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa')).toEqual([
286
+ '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
287
+ ]);
288
+ });
289
+ test('matches bech32 address (bc1...)', () => {
290
+ expect(matchAll('bitcoinAddress', 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq')).toEqual(['bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq']);
291
+ });
292
+ });
293
+ describe('Ethereum address pattern', () => {
294
+ test('matches ETH address', () => {
295
+ expect(matchAll('ethereumAddress', 'ETH: 0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28')).toEqual(['0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28']);
296
+ });
297
+ });
298
+ // ═══════════════════════════════════════════════════════
299
+ // PASSPORT
300
+ // ═══════════════════════════════════════════════════════
301
+ describe('Passport patterns', () => {
302
+ test('matches US passport', () => {
303
+ expect(matchAll('passportUS', 'Passport: C12345678')).toEqual(['C12345678']);
304
+ });
305
+ test('matches EU passport', () => {
306
+ expect(matchAll('passportEU', 'Passport: AB1234567')).toEqual(['AB1234567']);
307
+ });
308
+ });
309
+ // ═══════════════════════════════════════════════════════
310
+ // NHS NUMBER (with checksum)
311
+ // ═══════════════════════════════════════════════════════
312
+ describe('NHS number pattern', () => {
313
+ test('matches valid NHS number with correct checksum', () => {
314
+ // 943 476 5919 — valid NHS number
315
+ const result = matchAll('nhsNumber', 'NHS: 943 476 5919');
316
+ // We test the regex match + validator
317
+ // The validator checks mod 11 — exact valid numbers are tricky to construct
318
+ // So we just verify the regex part matches the format
319
+ const pattern = patterns_1.PII_PATTERNS.find((p) => p.name === 'nhsNumber');
320
+ const re = new RegExp(pattern.regex.source, pattern.regex.flags);
321
+ const matches = '943 476 5919'.match(re);
322
+ expect(matches).not.toBeNull();
323
+ });
324
+ });
325
+ // ═══════════════════════════════════════════════════════
326
+ // EIN
327
+ // ═══════════════════════════════════════════════════════
328
+ describe('EIN pattern', () => {
329
+ test('matches EIN format', () => {
330
+ expect(matchAll('taxIdUS', 'EIN: 12-3456789')).toEqual(['12-3456789']);
331
+ });
332
+ });
333
+ // ═══════════════════════════════════════════════════════
334
+ // DACH PHONE NUMBERS
335
+ // ═══════════════════════════════════════════════════════
336
+ describe('German phone pattern', () => {
337
+ test('matches DE landline', () => {
338
+ expect(matchAll('phoneDE', '089 1234 5678')).toEqual(['089 1234 5678']);
339
+ });
340
+ test('matches DE with country code', () => {
341
+ expect(matchAll('phoneDE', '+49 30 12345678')).toEqual(['+49 30 12345678']);
342
+ });
343
+ });
344
+ describe('Austrian phone pattern', () => {
345
+ test('matches AT phone', () => {
346
+ expect(matchAll('phoneAT', '+43 1 1234567')).toEqual(['+43 1 1234567']);
347
+ });
348
+ });
349
+ describe('Swiss phone pattern', () => {
350
+ test('matches CH mobile', () => {
351
+ expect(matchAll('phoneCH', '079 123 45 67')).toEqual(['079 123 45 67']);
352
+ });
353
+ test('matches CH with country code', () => {
354
+ expect(matchAll('phoneCH', '+41 79 123 45 67')).toEqual(['+41 79 123 45 67']);
355
+ });
356
+ });
357
+ describe('French phone pattern', () => {
358
+ test('matches FR mobile', () => {
359
+ expect(matchAll('phoneFR', '06 12 34 56 78')).toEqual(['06 12 34 56 78']);
360
+ });
361
+ });
362
+ // ═══════════════════════════════════════════════════════
363
+ // EU IDENTITY DOCUMENTS
364
+ // ═══════════════════════════════════════════════════════
365
+ describe('German tax ID', () => {
366
+ test('matches labeled Steuer-ID', () => {
367
+ expect(matchAll('taxIdDE', 'Steuer-ID: 12345678901')).toEqual(['Steuer-ID: 12345678901']);
368
+ });
369
+ });
370
+ describe('German social insurance number', () => {
371
+ test('matches Sozialversicherungsnummer format', () => {
372
+ expect(matchAll('sozialversicherungDE', '12 060482 H 123')).toEqual(['12 060482 H 123']);
373
+ });
374
+ });
375
+ describe('Swiss AHV number', () => {
376
+ test('matches AHV format', () => {
377
+ expect(matchAll('ahvCH', 'AHV: 756.1234.5678.97')).toEqual(['756.1234.5678.97']);
378
+ });
379
+ });
380
+ describe('Italian Codice Fiscale', () => {
381
+ test('matches valid format', () => {
382
+ expect(matchAll('codiceFiscaleIT', 'CF: RSSMRA85M01H501Z')).toEqual(['RSSMRA85M01H501Z']);
383
+ });
384
+ });
385
+ describe('Spanish DNI', () => {
386
+ test('matches DNI format', () => {
387
+ expect(matchAll('dniES', 'DNI: 12345678Z')).toEqual(['12345678Z']);
388
+ });
389
+ });
390
+ describe('Spanish NIE', () => {
391
+ test('matches NIE format', () => {
392
+ expect(matchAll('nieES', 'NIE: X1234567L')).toEqual(['X1234567L']);
393
+ });
394
+ });
395
+ describe('German Handelsregister', () => {
396
+ test('matches HRB number', () => {
397
+ expect(matchAll('handelsregisterDE', 'HRB 12345')).toEqual(['HRB 12345']);
398
+ });
399
+ test('matches HRA number', () => {
400
+ expect(matchAll('handelsregisterDE', 'HRA 67890')).toEqual(['HRA 67890']);
401
+ });
402
+ });
403
+ // ═══════════════════════════════════════════════════════
404
+ // EU POSTAL CODES
405
+ // ═══════════════════════════════════════════════════════
406
+ describe('Dutch postal code', () => {
407
+ test('matches NL format', () => {
408
+ expect(matchAll('postalCodeNL', '1234 AB')).toEqual(['1234 AB']);
409
+ });
410
+ });
411
+ describe('Polish postal code', () => {
412
+ test('matches PL format', () => {
413
+ expect(matchAll('postalCodePL', '00-950')).toEqual(['00-950']);
414
+ });
415
+ });
416
+ // ═══════════════════════════════════════════════════════
417
+ // STREET ADDRESSES
418
+ // ═══════════════════════════════════════════════════════
419
+ describe('German address pattern', () => {
420
+ test('matches German street with number', () => {
421
+ const result = matchAll('addressDE', 'Musterstraße 12, 80331 München');
422
+ expect(result.length).toBeGreaterThanOrEqual(1);
423
+ expect(result[0]).toContain('Musterstraße 12');
424
+ });
425
+ test('matches Straße abbreviation', () => {
426
+ const result = matchAll('addressDE', 'Berlinerstr. 45');
427
+ expect(result.length).toBeGreaterThanOrEqual(1);
428
+ });
429
+ test('matches Weg suffix', () => {
430
+ const result = matchAll('addressDE', 'Feldweg 7');
431
+ expect(result.length).toBeGreaterThanOrEqual(1);
432
+ });
433
+ test('matches full address with PLZ and city', () => {
434
+ const result = matchAll('addressDE', 'Hauptstraße 23, 10115 Berlin');
435
+ expect(result.length).toBeGreaterThanOrEqual(1);
436
+ expect(result[0]).toContain('Hauptstraße 23');
437
+ expect(result[0]).toContain('10115 Berlin');
438
+ });
439
+ });
440
+ describe('Labeled address patterns', () => {
441
+ test('matches German labeled address', () => {
442
+ const result = matchAll('addressLabeledDE', 'Adresse: Musterstraße 12, 80331 München');
443
+ expect(result.length).toBeGreaterThanOrEqual(1);
444
+ });
445
+ test('matches English labeled address', () => {
446
+ const result = matchAll('addressLabeledEN', 'Address: 123 Main Street, Apt 4B, New York');
447
+ expect(result.length).toBeGreaterThanOrEqual(1);
448
+ });
449
+ test('matches shipping address label', () => {
450
+ const result = matchAll('addressLabeledEN', 'Shipping Address: 456 Oak Ave, Suite 100');
451
+ expect(result.length).toBeGreaterThanOrEqual(1);
452
+ });
453
+ });
454
+ // ═══════════════════════════════════════════════════════
455
+ // IP WITH PORT
456
+ // ═══════════════════════════════════════════════════════
457
+ describe('IPv4 with port', () => {
458
+ test('matches IP:port', () => {
459
+ expect(matchAll('ipv4Port', 'Server at 192.168.1.1:8080')).toEqual(['192.168.1.1:8080']);
460
+ });
461
+ });
462
+ // ═══════════════════════════════════════════════════════
463
+ // UTILITY FUNCTIONS
464
+ // ═══════════════════════════════════════════════════════
465
+ describe('getPatternOptions()', () => {
466
+ test('returns options for all patterns', () => {
467
+ const options = (0, patterns_1.getPatternOptions)();
468
+ expect(options.length).toBe(patterns_1.PII_PATTERNS.length);
469
+ expect(options.every((o) => o.name && o.value && o.description)).toBe(true);
470
+ });
471
+ });
472
+ describe('getPatternsByNames()', () => {
473
+ test('filters patterns by name', () => {
474
+ const result = (0, patterns_1.getPatternsByNames)(['email', 'phone']);
475
+ expect(result).toHaveLength(2);
476
+ expect(result.map((r) => r.name)).toEqual(['email', 'phone']);
477
+ });
478
+ test('returns empty for unknown names', () => {
479
+ expect((0, patterns_1.getPatternsByNames)(['nonexistent'])).toEqual([]);
480
+ });
481
+ });
@@ -0,0 +1 @@
1
+ export {};