import type { PatternDef } from './types.js'; /** * Swiss preset — the structured identifiers most relevant to the Swiss nLPD. * Order matters: specific patterns (AVS, IBAN) come before generic ones. */ const swiss: PatternDef[] = [ { tag: 'AVS', re: /\b756\.\d{4}\.\d{4}\.\d{2}\b/g }, // Swiss social security (AVS/AHV) { tag: 'IBAN', re: /\bCH\d{2}[0-9A-Z]{17}\b/gi }, // Swiss IBAN { tag: 'EMAIL', re: /\b[\w.+-]+@[\w-]+\.[\w.-]+\b/g }, { tag: 'TEL', re: /(?:\+41|0)(?:[\s.-]?\d){9}\b/g }, // Swiss phone number { tag: 'DATE', re: /\b\d{1,2}[./-]\d{1,2}[./-]\d{2,4}\b/g }, ]; /** Luhn check on a credit-card candidate (ignores spaces/dashes); 13–19 digits. */ function luhnValid(value: string): boolean { const digits = value.replace(/\D/g, ''); if (digits.length < 13 || digits.length > 19) return false; let sum = 0; let double = false; for (let i = digits.length - 1; i >= 0; i--) { let d = digits.charCodeAt(i) - 48; // '0' === 48 if (double) { d *= 2; if (d > 9) d -= 9; } sum += d; double = !double; } return sum % 10 === 0; } /** * Generic preset — locale-agnostic identifiers useful as a starting point * anywhere. Best-effort: extend or compose with your own {@link PatternDef}s. * * Order matters (patterns run in sequence on the already-anonymized text): * specific identifiers claim their matches before broader ones, and dates are * claimed before phone numbers so they don't get mis-tagged as `TEL`. */ const generic: PatternDef[] = [ { tag: 'EMAIL', re: /\b[\w.+-]+@[\w-]+\.[\w.-]+\b/g }, { tag: 'IBAN', re: /\b[A-Z]{2}\d{2}[0-9A-Z]{11,30}\b/g }, { tag: 'IPV4', re: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g }, // 13–19 digits in optional space/dash groups, gated by Luhn to avoid eating // arbitrary long digit runs (account numbers, ids). { tag: 'CREDIT_CARD', re: /\b\d(?:[ -]?\d){12,18}\b/g, validate: luhnValid }, { tag: 'DATE', re: /\b\d{1,2}[./-]\d{1,2}[./-]\d{2,4}\b/g }, // Requires grouped/separated digits (or a leading +country) so plain integers // aren't mistaken for phone numbers. { tag: 'TEL', re: /(?:\+\d{1,3}[\s.-]?)?(?:\(?\d{2,4}\)?[\s.-]){2,3}\d{2,4}/g }, ]; /** Built-in pattern sets for the regex fallback. */ export const presets = { swiss, generic };