euredact 0.5.0 → 0.6.0

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.
@@ -31,6 +31,41 @@ function p(entityType, pattern, validator = null, description = "", contextKeywo
31
31
  // ---------------------------------------------------------------------------
32
32
  // Secret context keywords (consolidated, reused across SECRET patterns)
33
33
  // ---------------------------------------------------------------------------
34
+ /**
35
+ * Words that name a travel document, in the official languages of the 31
36
+ * countries this engine covers, plus English.
37
+ *
38
+ * Shared by every passport pattern. Before this existed each country kept its
39
+ * own list, so a passport was only recognised when its shape and its label
40
+ * came from the same country: `Reisepass: CA1234567` was missed because the
41
+ * German pattern rejects that alphabet while the Dutch pattern, whose shape
42
+ * fits, had never heard of "Reisepass" (issue rules-engine#23).
43
+ *
44
+ * The bare Scandinavian "pass", Finnish "passi" and Latvian "pase" are
45
+ * omitted deliberately: context matching is substring, not word-boundary, so
46
+ * they fire inside "password", "passenger", "passive" and "phase". Only the
47
+ * compound forms are listed. Mirrors PASSPORT_CONTEXT in Python.
48
+ */
49
+ const PASSPORT_CONTEXT = [
50
+ "passport", "passport no", "passport number", "travel document",
51
+ "reisepass", "passnummer", "reisepassnummer", "reisepass-nr", "pass nr",
52
+ "reisedokument",
53
+ "paspoort", "paspoortnummer", "reisdocument", "identiteitsbewijs",
54
+ "passeport", "numéro de passeport", "document de voyage",
55
+ "passaporto", "numero di passaporto", "documento di viaggio",
56
+ "pasaporte", "número de pasaporte", "documento de viaje",
57
+ "passaporte", "número do passaporte",
58
+ "passnr", "passets nummer", "passin numero", "passinumero",
59
+ "passi number", "passinumber",
60
+ "vegabréf", "vegabréfsnúmer",
61
+ "paso numeris", "pases numurs",
62
+ "paszport", "numer paszportu", "cestovní pas", "číslo pasu",
63
+ "cestovný pas", "potni list", "številka potnega lista",
64
+ "putovnica", "broj putovnice",
65
+ "útlevél", "útlevélszám", "pașaport", "numărul pașaportului",
66
+ "паспорт", "номер на паспорт", "διαβατήριο",
67
+ "αριθμός διαβατηρίου", "passaport",
68
+ ];
34
69
  const SECRET_CONTEXT = [
35
70
  // English
36
71
  "key", "token", "secret", "password", "credential",
@@ -70,18 +105,50 @@ const SECRET_CONTEXT = [
70
105
  // ---------------------------------------------------------------------------
71
106
  // DOB context keywords (reused across SHARED patterns)
72
107
  // ---------------------------------------------------------------------------
108
+ // Every way the documents this engine sees introduce a date of birth.
109
+ //
110
+ // DOB recall was 62.8% -- 33,441 unmasked birth dates -- because this covered
111
+ // seven languages of thirty-one. Eleven countries scored exactly 100% (the
112
+ // listed languages) while twenty sat at 42-51%, which is what proved it was
113
+ // coverage rather than capability (rules-engine#38).
114
+ //
115
+ // Matching is substring, not word-boundary, so every entry was screened against
116
+ // the 29.2-million-character corpus for occurrences inside a longer word. Two
117
+ // were rejected: `fædd` lives inside `fæddur`, and `born` was found inside
118
+ // `gabornagy` and `gabornemeth` -- Hungarian names as e-mail local parts -- so
119
+ // `"born "` with the trailing space is listed instead.
120
+ //
121
+ // DOB_CONTEXT is gone: it was a second, shorter copy missing `nato il`,
122
+ // `nascido`, `geburtstag` and more, so ISO dates were gated on fewer keywords
123
+ // than DD/MM/YYYY ones for no stated reason.
73
124
  const DOB_CONTEXT = [
125
+ // Germanic / Romance -- the original set, kept verbatim.
74
126
  "geboren", "geboortedatum", "date de naissance", "né le", "née le",
75
127
  "né(e) le", "nee le", "nee(e) le", "date of birth", "DOB",
76
128
  "Geburtsdatum", "geboren am", "geboren op", "nascido", "nacido",
77
129
  "data di nascita", "nato il", "nata il", "geb.", "geb.datum", "geb ",
78
130
  "birth date", "birthday", "naissance", "geboorte", "geburtstag",
79
- ];
80
- const DOB_ISO_CONTEXT = [
81
- "geboren", "geboortedatum", "date de naissance", "né le", "née le",
82
- "né(e) le", "nee le", "date of birth", "DOB", "Geburtsdatum",
83
- "geboren am", "geboren op", "geb.", "birth date", "birthday",
84
- "naissance", "geboorte",
131
+ // English and Italian forms the list was missing.
132
+ "born ", "d.o.b", "nato/a il",
133
+ // Nordic.
134
+ "født", "fødselsdato", "född", "födelsedatum",
135
+ "syntynyt", "syntymäaika", "fæddur", "fæðingardagur",
136
+ // Greek -- Greece and Cyprus.
137
+ "γεννηθείς", "γεννήθηκε", "ημερομηνία γέννησης",
138
+ // West Slavic.
139
+ "urodzony", "urodzona", "data urodzenia",
140
+ "narozen", "datum narození", "narodený", "dátum narodenia",
141
+ // Hungarian, Romanian, Bulgarian.
142
+ "született", "születési", "născut", "născută", "data nașterii",
143
+ "роден", "родена", "дата на раждане",
144
+ // South Slavic.
145
+ "rođen", "rođena", "datum rođenja", "rojen", "rojena", "datum rojstva",
146
+ // Baltic.
147
+ "sündinud", "sünniaeg", "dzimis", "dzimusi", "dzimšanas datums",
148
+ "gimęs", "gimusi", "gimimo data",
149
+ // Maltese, Irish, Turkish (Cyprus).
150
+ "twieled", "twieldet", "data tat-twelid",
151
+ "rugadh", "dáta breithe", "doğum tarihi",
85
152
  ];
86
153
  const DATE_OF_DEATH_CONTEXT = [
87
154
  "overleden", "overlijdensdatum", "date de décès", "décédé le",
@@ -121,6 +188,17 @@ const SHARED = {
121
188
  // "Call (+32 475 12 34 56) today." also masked the ")" (issue
122
189
  // rules-engine#3). Mirrors the Python pattern character for character.
123
190
  p(types_js_1.EntityType.PHONE, String.raw `\+\d{1,3}(?:[\s\-/]?(?:\(\d{1,4}\)|\d{1,4})){2,7}`, "e164", "International phone number (E.164) — any country"),
191
+ // Passport (any country). The per-country patterns cover BE, DE, FR and NL
192
+ // only; the other 26 had none. Same argument as the E.164 phone rule: one
193
+ // country-independent shape, with the label carrying the precision.
194
+ // Shapes from the project canon (prompts/pii_definitions.md, PASSPORT):
195
+ // EU is 1-2 letters + 7 digits, UK is 9 digits optionally GBR-prefixed.
196
+ // The canon's position is that the EU converged on one shape, so national
197
+ // regexes would contradict it as well as being unverifiable. An earlier
198
+ // draft required a leading letter and missed all-numeric passports, the
199
+ // UK's own format among them; requiring exactly nine digits for the
200
+ // numeric form rejects eight-digit dates on shape (issue rules-engine#23).
201
+ p(types_js_1.EntityType.PASSPORT, String.raw `\b(?:GBR\d{9}|[A-Z]{1,2}\d{7}|\d{9})\b`, null, "Passport number — any country, label-gated", PASSPORT_CONTEXT, true),
124
202
  p(types_js_1.EntityType.BIC, String.raw `\b[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?\b`, "bic"),
125
203
  // Space-separated form: "RZBA AT WW", "NICA BE BB". Written as a separate
126
204
  // pattern requiring a space between *every* group, rather than making the
@@ -177,7 +255,12 @@ const SHARED = {
177
255
  // --- Secret / API Key (connection strings with embedded credentials) ---
178
256
  p(types_js_1.EntityType.SECRET, String.raw `(?:mongodb|mysql|postgres(?:ql)?|redis|amqp|rabbitmq):\/\/[^\s:]{1,256}:[^\s@]{1,256}@[^\s]+`, null, "Connection string with credentials"),
179
257
  // --- Secret / API Key (assignment-based: KEY=value or KEY: value) ---
180
- p(types_js_1.EntityType.SECRET, String.raw `(?<=[:=] )\S{8,}|(?<=[:=])\S{8,}`, "high_entropy", "Assigned secret value", SECRET_CONTEXT, true),
258
+ // The final character may not be sentence punctuation. `\S` does not stop
259
+ // at a full stop, so "Reisepass: CA1234567." was claimed as the
260
+ // ten-character span "CA1234567." -- a passport number plus the sentence's
261
+ // period, masked as a credential because a "credentials" word sat within
262
+ // the context window (rules-engine#35).
263
+ p(types_js_1.EntityType.SECRET, String.raw `(?<=[:=] )\S{7,}[^\s.,;:!?)'"]|(?<=[:=])\S{7,}[^\s.,;:!?)'"]`, "high_entropy", "Assigned secret value", SECRET_CONTEXT, true),
181
264
  // --- Secret / API Key (entropy-based fallback for longer tokens) ---
182
265
  // Only the *trailing* \b is replaced. It could not match when the token run
183
266
  // ended on "-", "+" or "/", so the engine backtracked across two
@@ -195,7 +278,7 @@ const SHARED = {
195
278
  p(types_js_1.EntityType.SECRET, String.raw `\b[A-Za-z0-9_\-+/]{24,}[A-Za-z0-9_\-+/=]*(?![A-Za-z0-9_\-+/=])`, "high_entropy", "High-entropy token", SECRET_CONTEXT, true),
196
279
  p(types_js_1.EntityType.DOB, String.raw `\b(?:0[1-9]|[12][0-9]|3[01])[/.\-](?:0[1-9]|1[0-2])[/.\-](?:19|20)\d{2}\b`, null, "DD/MM/YYYY", DOB_CONTEXT, true),
197
280
  p(types_js_1.EntityType.DATE_OF_DEATH, String.raw `\b(?:0[1-9]|[12][0-9]|3[01])[/.\-](?:0[1-9]|1[0-2])[/.\-](?:19|20)\d{2}\b`, null, "", DATE_OF_DEATH_CONTEXT, true),
198
- p(types_js_1.EntityType.DOB, String.raw `\b(?:19|20)\d{2}[/.\-](?:0[1-9]|1[0-2])[/.\-](?:0[1-9]|[12][0-9]|3[01])\b`, null, "ISO YYYY-MM-DD", DOB_ISO_CONTEXT, true),
281
+ p(types_js_1.EntityType.DOB, String.raw `\b(?:19|20)\d{2}[/.\-](?:0[1-9]|1[0-2])[/.\-](?:0[1-9]|[12][0-9]|3[01])\b`, null, "ISO YYYY-MM-DD", DOB_CONTEXT, true),
199
282
  ],
200
283
  };
201
284
  const NL = {
@@ -205,7 +288,7 @@ const NL = {
205
288
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[0-9]{9}\b`, "bsn"),
206
289
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[0-9]{2,4}\.[0-9]{2,4}\.[0-9]{2,4}\b`, "bsn"),
207
290
  p(types_js_1.EntityType.IBAN, String.raw `\bNL\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?\d{2}\b`, "iban"),
208
- p(types_js_1.EntityType.VAT, String.raw `\bNL\d{9}B\d{2}\b`, "vat_nl"),
291
+ p(types_js_1.EntityType.VAT, String.raw `\bNL[\s.]?\d{9}B\d{2}\b`, "vat_nl"),
209
292
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b\d{8}\b`, "kvk", "", ["KvK", "Kamer van Koophandel", "kvk-nummer", "KVK-nummer", "handelsregister", "chamber of commerce"], true),
210
293
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d[\s\-]?\d{3}[\s\-]?\d{4}\b`),
211
294
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d{2}[\s\-]?\d{6,7}\b`),
@@ -214,7 +297,7 @@ const NL = {
214
297
  p(types_js_1.EntityType.PHONE, String.raw `\b06[\s\-]?\d{2}[\s\-]?\d{2}[\s\-]?\d{2}[\s\-]?\d{2}\b`),
215
298
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d{1,2}[\s\-]?\d{2,3}[\s\-]?\d{2}[\s\-]?\d{2}\b`),
216
299
  p(types_js_1.EntityType.PHONE, String.raw `\+31\s?[1-9]\d{0,2}[\s\-]?\d{3,4}[\s\-]?\d{3,4}\b`),
217
- p(types_js_1.EntityType.PASSPORT, String.raw `\b[A-Z][A-Z0-9]{8}\b`, null, "", ["paspoort", "passport", "reisdocument", "travel document", "paspoortnummer", "identiteitsbewijs"], true),
300
+ p(types_js_1.EntityType.PASSPORT, String.raw `\b[A-Z][A-Z0-9]{8}\b`, null, "", PASSPORT_CONTEXT, true),
218
301
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b(?:[A-Z]{2}[\-\s]?\d{3}[\-\s]?[A-Z]|\d[\-\s]?[A-Z]{3}[\-\s]?\d{2}|\d{2}[\-\s]?[A-Z]{3}[\-\s]?\d|[A-Z]{2}[\-\s]?\d{2}[\-\s]?[A-Z]{2}|\d{2}[\-\s]?[A-Z]{2}[\-\s]?\d{2}|\d[\-\s]?[A-Z]{2}[\-\s]?\d{3})\b`),
219
302
  p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b[1-9]\d{3}\s?[A-Z]{2}\b`),
220
303
  ],
@@ -229,10 +312,10 @@ const BE = {
229
312
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b0\d{3}\.?\d{3}\.?\d{3}\b`, null, "", ["KBO", "BCE", "ondernemingsnummer", "numéro d'entreprise", "enterprise number", "bedrijfsnummer", "Kruispuntbank", "Banque-Carrefour", "Banque Carrefour", "Ondernemingen", "Entreprises", "onder nummer"], true),
230
313
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d{0,2}[/\s.\-]?\d{2,3}[.\s\-]?\d{2,3}[.\s\-]?\d{2,3}\b`),
231
314
  p(types_js_1.EntityType.PHONE, String.raw `\+32\s?\d{1,3}[\s.\-]?\d{2,3}[\s.\-]?\d{2}[\s.\-]?\d{2}`),
232
- p(types_js_1.EntityType.PASSPORT, String.raw `\b[A-Z]{2}\d{6}\b`, null, "", ["paspoort", "passport", "passeport", "reisdocument", "travel document", "document de voyage"], true),
315
+ p(types_js_1.EntityType.PASSPORT, String.raw `\b[A-Z]{2}\d{6}\b`, null, "", PASSPORT_CONTEXT, true),
233
316
  p(types_js_1.EntityType.DRIVERS_LICENSE, String.raw `\b\d{10}\b`, null, "", ["rijbewijs", "permis de conduire", "driving licence", "driving license", "rijbewijsnummer"], true),
234
317
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[12][\-\s]?[A-Z]{3}[\-\s]?\d{3}\b`),
235
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b[1-9]\d{3}\b`, null, "", ["postcode", "code postal", "postnummer", "postal code", "zip", "B-", "adres", "adresse", "wonende", "woonplaats", "rue", "straat", "laan", "avenue", "boulevard", "plein", "steenweg", "chaussée", "domicilié", "gedomicilieerd", "Levering:", "siège"], true),
318
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b[1-9]\d{3}\b`, null, "", ["postcode", "code postal", "postnummer", "postal code", "zip", "B-", "adres", "adresse", "wonende", "woonplaats", "domicile", "rue", "straat", "laan", "avenue", "boulevard", "plein", "steenweg", "chaussée", "domicilié", "gedomicilieerd", "Levering:", "siège"], true),
236
319
  p(types_js_1.EntityType.POSTAL_CODE, String.raw `(?<=, )[1-9]\d{3}(?= [A-Z])`),
237
320
  p(types_js_1.EntityType.HEALTHCARE_PROVIDER, String.raw `\b\d{1}[\-.]?\d{5}[\-.]?\d{2}[\-.]?\d{3}\b`, null, "", ["RIZIV", "INAMI", "arts", "médecin", "zorgverlener", "prestataire", "dokter", "doctor"], true),
238
321
  ],
@@ -248,7 +331,7 @@ const DE = {
248
331
  p(types_js_1.EntityType.VAT, String.raw `\bDE\s?\d{9}\b`, "vat_de"),
249
332
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d{1,4}[\s/\-]?\d{3,8}\b`),
250
333
  p(types_js_1.EntityType.PHONE, String.raw `\+49\s?\d{2,5}[\s/\-]?\d{3,8}\b`),
251
- p(types_js_1.EntityType.PASSPORT, String.raw `\b[CFGHJK][0-9CFGHJKLMNPRTVWXYZ]{8}\d?\b`, null, "", ["Reisepass", "passport", "Passnummer", "Reisepassnummer", "Reisepass Nummer", "Reisepass-Nr", "Pass Nr"], true),
334
+ p(types_js_1.EntityType.PASSPORT, String.raw `\b[CFGHJK][0-9CFGHJKLMNPRTVWXYZ]{8}\d?\b`, null, "", PASSPORT_CONTEXT, true),
252
335
  // The separator after the city code is mandatory. When it was optional, a
253
336
  // contiguous letter run split across both groups and the hyphen was
254
337
  // consumed as the *second* separator, so any "LETTERS-DIGITS" token
@@ -257,7 +340,7 @@ const DE = {
257
340
  // separates the city code: "B-AB 1234", "M-XY 99".
258
341
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[A-ZÄÖÜ]{1,3}[\s\-][A-Z]{1,2}[\s\-]?\d{1,4}[EH]?\b`),
259
342
  p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{5}\b`, null, "", ["PLZ", "Postleitzahl", "postal code", "postcode", "Anschrift", "Adresse", "Wohnort", "Ort", "Stadt", "wohnt", "wohnhaft", "Straße", "Str.", "Weg", "Platz", "Allee", "Ring"], true),
260
- p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\bHR[AB]\s?\d{4,6}\b`),
343
+ p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\bHR[AB]\s?\d{4,6}(?:\s[A-Z]\b)?`),
261
344
  p(types_js_1.EntityType.SSN, String.raw `\b\d{2}[\s]?\d{6}[\s]?[A-Z][\s]?\d{3}\b`, null, "", ["Rentenversicherung", "RV-Nummer", "Sozialversicherung", "SV-Nummer", "Versicherungsnummer", "Rentenversicherungsnummer", "Sozialversicherungsnummer", "SVNR", "SV-Nr", "RVNR"], true),
262
345
  p(types_js_1.EntityType.TAX_ID, String.raw `\b\d{2,3}/\d{3,4}/\d{4,5}\b`, null, "", ["Steuernummer", "St.-Nr", "StNr", "Finanzamt", "Steuer"], true),
263
346
  p(types_js_1.EntityType.TAX_ID, String.raw `\b\d{13}\b`, null, "", ["Steuernummer", "St.-Nr", "StNr", "Finanzamt", "Steuer"], true),
@@ -270,7 +353,7 @@ const AT = {
270
353
  patterns: [
271
354
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{4}\s?\d{6}\b`, "austrian_svnr"),
272
355
  p(types_js_1.EntityType.IBAN, String.raw `\bAT\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
273
- p(types_js_1.EntityType.VAT, String.raw `\bATU\d{8}\b`),
356
+ p(types_js_1.EntityType.VAT, String.raw `\bATU[\s.]?\d{8}\b`),
274
357
  p(types_js_1.EntityType.PHONE, String.raw `\b0\d{3,4}[\s\-]?\d{5,8}\b`),
275
358
  // Short area codes (Vienna is "01") split across three groups:
276
359
  // "01 53460 2215". The pattern above requires 3-4 digits after the trunk
@@ -309,9 +392,9 @@ const FR = {
309
392
  p(types_js_1.EntityType.VAT, String.raw `\bFR\s?[0-9A-HJ-NP-Z]{2}\s?\d{9}\b`, "vat_fr"),
310
393
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9][\s.\-]?\d{2}[\s.\-]?\d{2}[\s.\-]?\d{2}[\s.\-]?\d{2}\b`),
311
394
  p(types_js_1.EntityType.PHONE, String.raw `\+33\s?[1-9][\s.\-]?\d{2}[\s.\-]?\d{2}[\s.\-]?\d{2}[\s.\-]?\d{2}`),
312
- p(types_js_1.EntityType.PASSPORT, String.raw `\b\d{2}[A-Z]{2}\d{5}\b`, null, "", ["passeport", "passport", "numéro de passeport"], true),
395
+ p(types_js_1.EntityType.PASSPORT, String.raw `\b\d{2}[A-Z]{2}\d{5}\b`, null, "", PASSPORT_CONTEXT, true),
313
396
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[A-Z]{2}[\-\s]?\d{3}[\-\s]?[A-Z]{2}\b`),
314
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b(?:0[1-9]|[1-8]\d|9[0-5]|97[1-6])\d{3}\b`, null, "", ["code postal", "CP", "postal code", "postcode", "adresse", "domicilié", "résidant", "rue", "avenue", "boulevard", "place", "chemin", "allée", "impasse", "ville"], true),
397
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b(?:0[1-9]|[1-8]\d|9[0-5]|97[1-6])\d{3}\b`, null, "", ["code postal", "CP", "postal code", "postcode", "adresse", "domicile", "domicilié", "résidant", "rue", "avenue", "boulevard", "place", "chemin", "allée", "impasse", "ville"], true),
315
398
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b\d{3}\s?\d{3}\s?\d{3}\b`, null, "", ["SIREN", "siren", "RCS", "entreprise", "immatricul", "numéro d'entreprise", "registre du commerce"], true),
316
399
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b\d{3}\s?\d{3}\s?\d{3}\s?\d{5}\b`, null, "", ["SIRET", "siret", "établissement", "immatricul"], true),
317
400
  p(types_js_1.EntityType.TAX_ID, String.raw `\b\d{13}\b`, null, "", ["numéro fiscal", "SPI", "référence fiscale", "avis d'impôt", "impôt sur le revenu", "déclaration fiscale", "fiscal"], true),
@@ -344,9 +427,9 @@ const SE = {
344
427
  p(types_js_1.EntityType.PHONE, String.raw `\b0\d{1,3}[\-\s]?\d{2,3}[\s]?\d{2,3}[\s]?\d{2}\b`),
345
428
  p(types_js_1.EntityType.PHONE, String.raw `\+46\s?\d{1,3}[\s\-]?\d{2,3}[\s\-]?\d{2,3}[\s\-]?\d{2}`),
346
429
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[A-Z]{3}\s?\d{2}[A-Z0-9]\b`),
347
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{3}\s?\d{2}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé", "plats", "torg", "stigen", "Bostadsadress"], true),
348
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{4}\s\d{2}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé"], true),
349
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{6}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé"], true),
430
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{3}\s?\d{2}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "Postal:", "Address:", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé", "plats", "torg", "stigen", "Bostadsadress"], true),
431
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{4}\s\d{2}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "Postal:", "Address:", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé"], true),
432
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{6}\b`, null, "", ["postnummer", "postort", "postkod", "adress", "Postal:", "Address:", "bostadsadress", "gatuadress", "boende", "gatan", "vägen", "gata", "väg", "allé"], true),
350
433
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b\d{6}-?\d{4}\b`, null, "", ["organisationsnummer", "org.nr", "org nr", "Bolagsverket", "registreringsnummer"], true),
351
434
  ],
352
435
  };
@@ -362,7 +445,7 @@ const NO = {
362
445
  p(types_js_1.EntityType.PHONE, String.raw `\b[2-9]\d\s?\d{2}\s?\d{2}\s?\d{2}\b`),
363
446
  p(types_js_1.EntityType.PHONE, String.raw `\+47\s?\d{2}\s?\d{2}\s?\d{2}\s?\d{2}`),
364
447
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[A-Z]{2}\s?\d{5}\b`),
365
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{4}\b`, null, "", ["postnummer", "poststed", "postnr", "adresse", "bostedsadresse", "gate", "vei", "veien", "gata", "plass", "stien", "allé"], true),
448
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{4}\b`, null, "", ["postnummer", "poststed", "postnr", "adresse", "bostedsadresse", "gate", "vei", "veien", "gata", "plass", "stien", "allé", "Postal:", "Address:"], true),
366
449
  ],
367
450
  };
368
451
  const FI = {
@@ -371,7 +454,7 @@ const FI = {
371
454
  patterns: [
372
455
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{6}[-+ABCDEFYXWVU]\d{3}[0-9A-FHJK-NPR-Y]\b`, "finnish_hetu"),
373
456
  p(types_js_1.EntityType.IBAN, String.raw `\bFI\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{2}\b`, "iban"),
374
- p(types_js_1.EntityType.VAT, String.raw `\bFI\d{8}\b`),
457
+ p(types_js_1.EntityType.VAT, String.raw `\bFI[\s.]?\d{8}\b`),
375
458
  p(types_js_1.EntityType.CHAMBER_OF_COMMERCE, String.raw `\b\d{7}-\d\b`, "finnish_business_id"),
376
459
  p(types_js_1.EntityType.PHONE, String.raw `\b0\d{1,2}\s?\d{3,4}\s?\d{3,4}\b`),
377
460
  p(types_js_1.EntityType.PHONE, String.raw `\+358\s?\d{1,3}[\s\-]?\d{3,4}[\s\-]?\d{3,4}`),
@@ -389,7 +472,7 @@ const IS = {
389
472
  p(types_js_1.EntityType.PHONE, String.raw `\b[3-9]\d{6}\b`, null, "", ["sími", "símanúmer", "farsími", "gsm", "phone", "tel", "hringja", "hringdu", "ná í", "nás á", "nás", "SMS", "sent to"], true),
390
473
  p(types_js_1.EntityType.PHONE, String.raw `\+354\s?\d{3}\s?\d{4}`),
391
474
  p(types_js_1.EntityType.LICENSE_PLATE, String.raw `\b[A-Z]{2}\s?\d{3}\b`, null, "", ["skráningarnúmer", "bílnúmer", "ökutæki", "bifreið", "plata"], true),
392
- p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b[1-9]\d{2}\b`, null, "", ["póstnúmer", "póstfang", "staður", "heimilisfang"], true),
475
+ p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b[1-9]\d{2}\b`, null, "", ["póstnúmer", "póstfang", "staður", "heimilisfang", "Postal:", "Address:"], true),
393
476
  ],
394
477
  };
395
478
  const IT = {
@@ -399,7 +482,7 @@ const IT = {
399
482
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[A-Z]{6}\d{2}[ABCDEHLMPRST]\d{2}[A-Z]\d{3}[A-Z]\b`, "italian_cf"),
400
483
  p(types_js_1.EntityType.IBAN, String.raw `\bIT\d{2}\s?[A-Z]\d{3}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{3}\b`, "iban"),
401
484
  p(types_js_1.EntityType.IBAN, String.raw `\bIT\d{2}[A-Z]\d{22}\b`, "iban"),
402
- p(types_js_1.EntityType.VAT, String.raw `\bIT\d{11}\b`),
485
+ p(types_js_1.EntityType.VAT, String.raw `\bIT[\s.]?\d{11}\b`),
403
486
  p(types_js_1.EntityType.PHONE, String.raw `\b3\d{2}[\s\-]?\d{3}[\s\-]?\d{4}\b`),
404
487
  p(types_js_1.EntityType.PHONE, String.raw `\b0\d{1,3}[\s\-]?\d{6,8}\b`),
405
488
  p(types_js_1.EntityType.PHONE, String.raw `\b0\d{1,2}[\s\-]\d{3}[\s\-]\d{4}\b`),
@@ -415,7 +498,7 @@ const ES = {
415
498
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{8}[A-Z]\b`, "spanish_dni"),
416
499
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[XYZ]\d{7}[A-Z]\b`, "spanish_nie"),
417
500
  p(types_js_1.EntityType.IBAN, String.raw `\bES\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
418
- p(types_js_1.EntityType.VAT, String.raw `\bES[A-Z0-9]\d{7}[A-Z0-9]\b`),
501
+ p(types_js_1.EntityType.VAT, String.raw `\bES[\s.]?[A-Z0-9]\d{7}[A-Z0-9]\b`),
419
502
  p(types_js_1.EntityType.PHONE, String.raw `\b[679]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
420
503
  p(types_js_1.EntityType.PHONE, String.raw `\b[679]\d{8}\b`),
421
504
  p(types_js_1.EntityType.PHONE, String.raw `\b[679]\d[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}\b`),
@@ -438,7 +521,7 @@ const PT = {
438
521
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[1-35-9]\d{8}\b`, "portuguese_nif"),
439
522
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[1-35-9]\d{2}[\s.]\d{3}[\s.]\d{3}\b`, "portuguese_nif"),
440
523
  p(types_js_1.EntityType.IBAN, String.raw `\bPT\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{5}\b`, "iban"),
441
- p(types_js_1.EntityType.VAT, String.raw `\bPT\d{9}\b`),
524
+ p(types_js_1.EntityType.VAT, String.raw `\bPT[\s.]?\d{9}\b`),
442
525
  p(types_js_1.EntityType.PHONE, String.raw `\b[29]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
443
526
  p(types_js_1.EntityType.PHONE, String.raw `\b[29]\d{8}\b`),
444
527
  p(types_js_1.EntityType.PHONE, String.raw `\+351\s?[29]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}`),
@@ -471,7 +554,7 @@ const PL = {
471
554
  p(types_js_1.EntityType.TAX_ID, String.raw `\b\d{3}-?\d{3}-?\d{2}-?\d{2}\b`, "polish_nip"),
472
555
  p(types_js_1.EntityType.IBAN, String.raw `\bPL\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
473
556
  p(types_js_1.EntityType.IBAN, String.raw `\bPL\d{26}\b`, "iban"),
474
- p(types_js_1.EntityType.VAT, String.raw `\bPL\d{10}\b`),
557
+ p(types_js_1.EntityType.VAT, String.raw `\bPL[\s.]?\d{10}\b`),
475
558
  p(types_js_1.EntityType.PHONE, String.raw `\b[5-8]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
476
559
  p(types_js_1.EntityType.PHONE, String.raw `\b[5-8]\d{8}\b`),
477
560
  p(types_js_1.EntityType.PHONE, String.raw `\+48\s?[5-8]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}`),
@@ -485,7 +568,7 @@ const IE = {
485
568
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{7}[A-W][ABWTXZ]?\b`, "irish_pps"),
486
569
  p(types_js_1.EntityType.IBAN, String.raw `\bIE\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{2}\b`, "iban"),
487
570
  p(types_js_1.EntityType.IBAN, String.raw `\bIE\d{2}[A-Z]{4}\d{14}\b`, "iban"),
488
- p(types_js_1.EntityType.VAT, String.raw `\bIE\d{7}[A-Z]\b`),
571
+ p(types_js_1.EntityType.VAT, String.raw `\bIE[\s.]?\d{7}[A-Z]\b`),
489
572
  p(types_js_1.EntityType.PHONE, String.raw `\b0[89]\d[\s\-]?\d{3}[\s\-]?\d{4}\b`),
490
573
  p(types_js_1.EntityType.PHONE, String.raw `\b0[89]\d{8}\b`),
491
574
  p(types_js_1.EntityType.PHONE, String.raw `\b0[1-9]\d{0,2}[\s\-]?\d{5,8}\b`),
@@ -501,7 +584,7 @@ const UK = {
501
584
  p(types_js_1.EntityType.HEALTH_INSURANCE, String.raw `\b\d{3}\s?\d{3}\s?\d{4}\b`, "uk_nhs", "", ["NHS", "NHS number", "health number", "NHS no"], true),
502
585
  p(types_js_1.EntityType.IBAN, String.raw `\bGB\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{2}\b`, "iban"),
503
586
  p(types_js_1.EntityType.IBAN, String.raw `\bGB\d{2}[A-Z]{4}\d{14}\b`, "iban"),
504
- p(types_js_1.EntityType.VAT, String.raw `\bGB\d{9}\b`),
587
+ p(types_js_1.EntityType.VAT, String.raw `\bGB[\s.]?\d{3}[\s.]?\d{4}[\s.]?\d{2}\b`),
505
588
  p(types_js_1.EntityType.PHONE, String.raw `\b07[4-9]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
506
589
  p(types_js_1.EntityType.PHONE, String.raw `\b07[4-9]\d{8}\b`),
507
590
  p(types_js_1.EntityType.PHONE, String.raw `\b0[12]\d{2}[\s\-]?\d{3}[\s\-]?\d{4}\b`),
@@ -517,7 +600,7 @@ const BG = {
517
600
  patterns: [
518
601
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{10}\b`, "bulgarian_egn"),
519
602
  p(types_js_1.EntityType.IBAN, String.raw `\bBG\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{2}\b`, "iban"),
520
- p(types_js_1.EntityType.VAT, String.raw `\bBG\d{9,10}\b`),
603
+ p(types_js_1.EntityType.VAT, String.raw `\bBG[\s.]?\d{9,10}\b`),
521
604
  p(types_js_1.EntityType.PHONE, String.raw `\b0?[89][789][\s\-]?\d{3}[\s\-]?\d{3,4}\b`),
522
605
  p(types_js_1.EntityType.PHONE, String.raw `\b0?[89][789]\d{7,8}\b`),
523
606
  p(types_js_1.EntityType.PHONE, String.raw `\+359\s?[89][789][\s\-]?\d{3}[\s\-]?\d{3,4}`),
@@ -532,7 +615,7 @@ const CY = {
532
615
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{8}[A-Z]\b`),
533
616
  p(types_js_1.EntityType.IBAN, String.raw `\bCY\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
534
617
  p(types_js_1.EntityType.IBAN, String.raw `\bCY\d{26}\b`, "iban"),
535
- p(types_js_1.EntityType.VAT, String.raw `\bCY\d{8}[A-Z]\b`),
618
+ p(types_js_1.EntityType.VAT, String.raw `\bCY[\s.]?\d{8}[A-Z]\b`),
536
619
  p(types_js_1.EntityType.PHONE, String.raw `\b[29]\d{3}[\s\-]?\d{4}\b`),
537
620
  p(types_js_1.EntityType.PHONE, String.raw `\b[29]\d[\s\-]?\d{3}[\s\-]?\d{3}\b`),
538
621
  p(types_js_1.EntityType.PHONE, String.raw `\b[29]\d{7}\b`),
@@ -548,7 +631,7 @@ const CZ = {
548
631
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{6}/?\d{3,4}\b`, "czech_birth_number"),
549
632
  p(types_js_1.EntityType.IBAN, String.raw `\bCZ\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
550
633
  p(types_js_1.EntityType.IBAN, String.raw `\bCZ\d{22}\b`, "iban"),
551
- p(types_js_1.EntityType.VAT, String.raw `\bCZ\d{8,10}\b`),
634
+ p(types_js_1.EntityType.VAT, String.raw `\bCZ[\s.]?\d{8,10}\b`),
552
635
  p(types_js_1.EntityType.PHONE, String.raw `\b[67]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
553
636
  p(types_js_1.EntityType.PHONE, String.raw `\b[67]\d{8}\b`),
554
637
  p(types_js_1.EntityType.PHONE, String.raw `\+420\s?[67]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}`),
@@ -562,7 +645,7 @@ const SK = {
562
645
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{6}/?\d{3,4}\b`, "czech_birth_number"),
563
646
  p(types_js_1.EntityType.IBAN, String.raw `\bSK\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
564
647
  p(types_js_1.EntityType.IBAN, String.raw `\bSK\d{22}\b`, "iban"),
565
- p(types_js_1.EntityType.VAT, String.raw `\bSK\d{10}\b`),
648
+ p(types_js_1.EntityType.VAT, String.raw `\bSK[\s.]?\d{10}\b`),
566
649
  p(types_js_1.EntityType.PHONE, String.raw `\b0?9\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
567
650
  p(types_js_1.EntityType.PHONE, String.raw `\+421\s?9\d{2}[\s\-]?\d{3}[\s\-]?\d{3}`),
568
651
  p(types_js_1.EntityType.POSTAL_CODE, String.raw `\b\d{3}\s?\d{2}\b`, null, "", ["PSČ", "poštové", "adresa", "ulica", "Postal:", "Address:"], true),
@@ -575,7 +658,7 @@ const EE = {
575
658
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[1-6]\d{10}\b`, "estonian_id"),
576
659
  p(types_js_1.EntityType.IBAN, String.raw `\bEE\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
577
660
  p(types_js_1.EntityType.IBAN, String.raw `\bEE\d{18}\b`, "iban"),
578
- p(types_js_1.EntityType.VAT, String.raw `\bEE\d{9}\b`),
661
+ p(types_js_1.EntityType.VAT, String.raw `\bEE[\s.]?\d{9}\b`),
579
662
  p(types_js_1.EntityType.PHONE, String.raw `\b5\d{3}[\s\-]?\d{4}\b`),
580
663
  p(types_js_1.EntityType.PHONE, String.raw `\b5\d{7}\b`),
581
664
  p(types_js_1.EntityType.PHONE, String.raw `\+372\s?5\d{3}[\s\-]?\d{3,4}`),
@@ -589,7 +672,7 @@ const LT = {
589
672
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[1-6]\d{10}\b`, "estonian_id"),
590
673
  p(types_js_1.EntityType.IBAN, String.raw `\bLT\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
591
674
  p(types_js_1.EntityType.IBAN, String.raw `\bLT\d{18}\b`, "iban"),
592
- p(types_js_1.EntityType.VAT, String.raw `\bLT\d{9,12}\b`),
675
+ p(types_js_1.EntityType.VAT, String.raw `\bLT[\s.]?\d{9,12}\b`),
593
676
  p(types_js_1.EntityType.PHONE, String.raw `\b6\d{2}[\s\-]?\d{2}[\s\-]?\d{3}\b`),
594
677
  p(types_js_1.EntityType.PHONE, String.raw `\b6\d{7}\b`),
595
678
  p(types_js_1.EntityType.PHONE, String.raw `\b8[\s\-]?6\d{2}[\s\-]?\d{2}[\s\-]?\d{3}\b`),
@@ -605,7 +688,7 @@ const LV = {
605
688
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b(?:0[1-9]|[12]\d|3[01])(?:0[1-9]|1[0-2])\d{7}\b`, null, "", ["personas kods", "PK", "identifikācijas"], true),
606
689
  p(types_js_1.EntityType.IBAN, String.raw `\bLV\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d\b`, "iban"),
607
690
  p(types_js_1.EntityType.IBAN, String.raw `\bLV\d{2}[A-Z]{4}\d{13}\b`, "iban"),
608
- p(types_js_1.EntityType.VAT, String.raw `\bLV\d{11}\b`),
691
+ p(types_js_1.EntityType.VAT, String.raw `\bLV[\s.]?\d{11}\b`),
609
692
  p(types_js_1.EntityType.PHONE, String.raw `\b[2]\d{3}[\s\-]?\d{4}\b`),
610
693
  p(types_js_1.EntityType.PHONE, String.raw `\b[2]\d{7}\b`),
611
694
  p(types_js_1.EntityType.PHONE, String.raw `\+371\s?[2]\d{3}[\s\-]?\d{3,4}`),
@@ -620,7 +703,7 @@ const HR = {
620
703
  p(types_js_1.EntityType.IBAN, String.raw `\bHR\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{3}\b`, "iban"),
621
704
  p(types_js_1.EntityType.IBAN, String.raw `\bHR\d{2}\s\d{4}\s\d{4}\s\d{4}\s\d{5}\b`, "iban"),
622
705
  p(types_js_1.EntityType.IBAN, String.raw `\bHR\d{19}\b`, "iban"),
623
- p(types_js_1.EntityType.VAT, String.raw `\bHR\d{11}\b`),
706
+ p(types_js_1.EntityType.VAT, String.raw `\bHR[\s.]?\d{11}\b`),
624
707
  p(types_js_1.EntityType.PHONE, String.raw `\b0?9[12579][\s\-]?\d{3}[\s\-]?\d{3,4}\b`),
625
708
  p(types_js_1.EntityType.PHONE, String.raw `\b0?9[12579]\d{7,8}\b`),
626
709
  p(types_js_1.EntityType.PHONE, String.raw `\+385\s?9[12579][\s\-]?\d{3}[\s\-]?\d{3,4}`),
@@ -634,7 +717,7 @@ const HU = {
634
717
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{9}\b`, "hungarian_taj"),
635
718
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{3}\s\d{3}\s\d{3}\b`, "hungarian_taj"),
636
719
  p(types_js_1.EntityType.TAX_ID, String.raw `\b8\d{9}\b`, null, "", ["adóazonosító", "adószám", "adóazonosító jel"], true),
637
- p(types_js_1.EntityType.VAT, String.raw `\bHU\d{8,11}\b`, null, "", ["adószám", "ÁFA"]),
720
+ p(types_js_1.EntityType.VAT, String.raw `\bHU[\s.]?\d{8,11}\b`, null, "", ["adószám", "ÁFA"]),
638
721
  p(types_js_1.EntityType.IBAN, String.raw `\bHU\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\b`, "iban"),
639
722
  p(types_js_1.EntityType.IBAN, String.raw `\bHU\d{26}\b`, "iban"),
640
723
  p(types_js_1.EntityType.PHONE, String.raw `\b06\s?\d{1,2}[\s\-]?\d{3}[\s\-]?\d{3,4}\b`),
@@ -649,7 +732,7 @@ const RO = {
649
732
  patterns: [
650
733
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b[1-8]\d{12}\b`, "romanian_cnp"),
651
734
  p(types_js_1.EntityType.IBAN, String.raw `\bRO\d{2}[A-Z]{4}\d{16}\b`, "iban"),
652
- p(types_js_1.EntityType.VAT, String.raw `\bRO\d{2,10}\b`),
735
+ p(types_js_1.EntityType.VAT, String.raw `\bRO[\s.]?\d{2,10}\b`),
653
736
  p(types_js_1.EntityType.PHONE, String.raw `\b0?7[2-9]\d{1}[\s\-]?\d{3}[\s\-]?\d{3,4}\b`),
654
737
  p(types_js_1.EntityType.PHONE, String.raw `\b0?7[2-9]\d{7,8}\b`),
655
738
  p(types_js_1.EntityType.PHONE, String.raw `\+40\s?7[2-9]\d{1}[\s\-]?\d{3}[\s\-]?\d{3,4}`),
@@ -664,7 +747,7 @@ const EL = {
664
747
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{11}\b`, "greek_amka"),
665
748
  p(types_js_1.EntityType.IBAN, String.raw `\bGR\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{3}\b`, "iban"),
666
749
  p(types_js_1.EntityType.IBAN, String.raw `\bGR\d{25}\b`, "iban"),
667
- p(types_js_1.EntityType.VAT, String.raw `\bEL\d{9}\b`),
750
+ p(types_js_1.EntityType.VAT, String.raw `\bEL[\s.]?\d{9}\b`),
668
751
  p(types_js_1.EntityType.PHONE, String.raw `\b69\d[\s\-]?\d{3,4}[\s\-]?\d{4}\b`),
669
752
  p(types_js_1.EntityType.PHONE, String.raw `\b69\d{8}\b`),
670
753
  p(types_js_1.EntityType.PHONE, String.raw `\b2\d{1,3}[\s\-]?\d{3,4}[\s\-]?\d{3,4}\b`),
@@ -679,7 +762,7 @@ const SI = {
679
762
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{13}\b`, "slovenian_emso"),
680
763
  p(types_js_1.EntityType.IBAN, String.raw `\bSI\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{3}\b`, "iban"),
681
764
  p(types_js_1.EntityType.IBAN, String.raw `\bSI\d{17}\b`, "iban"),
682
- p(types_js_1.EntityType.VAT, String.raw `\bSI\d{8}\b`),
765
+ p(types_js_1.EntityType.VAT, String.raw `\bSI[\s.]?\d{8}\b`),
683
766
  p(types_js_1.EntityType.PHONE, String.raw `\b0?[34567]\d{1}[\s\-]?\d{3}[\s\-]?\d{3}\b`),
684
767
  p(types_js_1.EntityType.PHONE, String.raw `\b0?[34567]\d{7}\b`),
685
768
  p(types_js_1.EntityType.PHONE, String.raw `\+386\s?[34567]\d{1}[\s\-]?\d{3}[\s\-]?\d{3}`),
@@ -694,7 +777,7 @@ const MT = {
694
777
  p(types_js_1.EntityType.NATIONAL_ID, String.raw `\b\d{5,7}[MGAPLHBZ]\b`),
695
778
  p(types_js_1.EntityType.IBAN, String.raw `\bMT\d{2}\s?[A-Z]{4}\s?\d{4}\s?\d{4}\s?[A-Z0-9]{4}\s?[A-Z0-9]{4}\s?[A-Z0-9]{4}\s?[A-Z0-9]{3}\b`, "iban"),
696
779
  p(types_js_1.EntityType.IBAN, String.raw `\bMT\d{2}[A-Z]{4}\d{5}[A-Z0-9]{18}\b`, "iban"),
697
- p(types_js_1.EntityType.VAT, String.raw `\bMT\d{8}\b`),
780
+ p(types_js_1.EntityType.VAT, String.raw `\bMT[\s.]?\d{8}\b`),
698
781
  p(types_js_1.EntityType.PHONE, String.raw `\b[79]\d{3}[\s\-]?\d{4}\b`),
699
782
  p(types_js_1.EntityType.PHONE, String.raw `\b[79]\d{7}\b`),
700
783
  p(types_js_1.EntityType.PHONE, String.raw `\+356\s?[79]\d{3}[\s\-]?\d{3,4}`),
@@ -69,8 +69,20 @@ const types_js_1 = require("../types.js");
69
69
  * How far back a cue may sit. Short on purpose: a cue is only evidence about
70
70
  * the value it introduces, which is the lesson of the postal-code year defect,
71
71
  * where a cue 150 characters away licensed every number in the window.
72
+ *
73
+ * This bounds how long a *label* may be, not how far it may sit from the
74
+ * value: every pattern is anchored with `$`, so the label still has to reach
75
+ * the span through a run-on or one qualifier word.
76
+ *
77
+ * 32 was too short for German tax labels, the longest the engine carries.
78
+ * "Steuerliche Identifikationsnummer " is 34 characters and
79
+ * "Steueridentifikationsnummer lautet: " is 36, so the label's own start sat
80
+ * outside the window and `(?<![A-Za-z0-9_])` had nothing to anchor against,
81
+ * leaving a critical-tier identifier in the clear (rules-engine#26). 44
82
+ * admits the longest with a qualifier: "Steuerliche Identifikationsnummer
83
+ * lautet: " is 42.
72
84
  */
73
- exports.CUE_WINDOW = 32;
85
+ exports.CUE_WINDOW = 44;
74
86
  /**
75
87
  * (entity type, label pattern). Ordered: the first match wins, so the narrower
76
88
  * label comes first where two could read the same text.
@@ -93,8 +105,15 @@ exports.CUES = [
93
105
  /(?<![A-Za-z0-9_])(?:ssn|social\s*security|sozialversicherungsnummer|svnr|sofi)(?:(?:[A-Za-z0-9_]|[^\x00-\x7F])*|\s+[^\s:.\-\d,;()\/]{2,20})\s*\)?\s*[:.\-]*\s*$/i],
94
106
  // Tax number. Greece's ΑΦΜ is issued by the tax authority; the identity-card
95
107
  // number is the ΑΔΤ, above.
108
+ //
109
+ // The German long forms are spelled out rather than left to the run-on after
110
+ // `steuer-?id`. A cue may use its run-on *or* one qualifier word, never both,
111
+ // and "Steuer-IdNr lautet:" needs both: the run-on for "Nr" and the qualifier
112
+ // for "lautet". Naming the whole label leaves the qualifier free.
113
+ // "Steuerliche Identifikationsnummer" matched nothing at all — it is two
114
+ // words, and `steuer-?id` cannot reach across "liche " (rules-engine#26).
96
115
  [types_js_1.EntityType.TAX_ID,
97
- /(?<![A-Za-z0-9_])(?:αφμ|α\.φ\.μ\.|steuer-?id|steuernummer|st\.?-?nr|stnr|tin|finanzamt\s+ist|tax\s*(?:id|no|number)|daňové\s*číslo|numer\s*podatkowy)(?:(?:[A-Za-z0-9_]|[^\x00-\x7F])*|\s+[^\s:.\-\d,;()\/]{2,20})\s*\)?\s*[:.\-]*\s*$/i],
116
+ /(?<![A-Za-z0-9_])(?:αφμ|α\.φ\.μ\.|steuerliche\s*identifikations-?nummer|steuer-?identifikations-?nummer|steuer-?id-?nr\.?|steuer-?id|steuernummer|st\.?-?nr|stnr|tin|finanzamt\s+ist|tax\s*(?:id|no|number)|daňové\s*číslo|numer\s*podatkowy)(?:(?:[A-Za-z0-9_]|[^\x00-\x7F])*|\s+[^\s:.\-\d,;()\/]{2,20})\s*\)?\s*[:.\-]*\s*$/i],
98
117
  // Health insurance: the insured person.
99
118
  [types_js_1.EntityType.HEALTH_INSURANCE,
100
119
  /(?<![A-Za-z0-9_])(?:versichertennummer|krankenversicherung|kvnr|kv-?nr|mutualité|ziekenfonds|aansluitingsnummer|medical\s*card(?:\s*(?:no|number))?)(?:(?:[A-Za-z0-9_]|[^\x00-\x7F])*|\s+[^\s:.\-\d,;()\/]{2,20})\s*\)?\s*[:.\-]*\s*$/i],