{"version":3,"sources":["../../src/validators/cin.ts","../../src/validators/phone.ts","../../src/validators/rib.ts","../../src/validators/matricule.ts","../../src/validators/passport.ts","../../src/validators/iban.ts","../../src/validators/landline.ts","../../src/validators/license-plate.ts","../../src/validators/postal-code.ts"],"names":["mod97"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Validates a Tunisian National ID (CIN).\n * - Must be exactly 8 digits\n * - Must contain only numbers\n * - Must not be the all-zero placeholder\n *\n * NOTE: This validator performs format-only validation (8 digits, not all\n * zeros). It does NOT validate the official CIN checksum algorithm. Full\n * checksum validation can be added once the canonical algorithm is confirmed\n * against an authoritative source (e.g., Ministry of Interior specifications).\n */\nexport function isValidCIN(cin: string): boolean {\n  if (typeof cin !== 'string') return false;\n  if (!/^\\d{8}$/.test(cin)) return false;\n\n  // An all-zero value is a placeholder, not a valid issued identifier.\n  if (cin === '00000000') return false;\n\n  return true;\n}\n","/**\n * Valid Tunisian mobile phone prefixes by provider:\n * - Tunisie Telecom: 9x, 4x\n * - Ooredoo: 2x\n * - Orange: 5x\n * - Lycamobile: 6x\n */\nconst VALID_PREFIXES = ['2', '4', '5', '6', '9'];\n\n/**\n * Validates a Tunisian mobile phone number.\n * Supports formats:\n * - 22555111 (8 digits)\n * - +21622555111 (with country code)\n * - 0021622555111 (with 00 prefix)\n */\nexport function isValidPhone(phone: string): boolean {\n  if (typeof phone !== 'string') return false;\n\n  // Remove spaces and dashes\n  const cleaned = phone.replace(/[\\s-]/g, '');\n\n  // Extract the 8-digit local number\n  let localNumber: string;\n\n  if (cleaned.startsWith('+216')) {\n    localNumber = cleaned.slice(4);\n  } else if (cleaned.startsWith('00216')) {\n    localNumber = cleaned.slice(5);\n  } else {\n    localNumber = cleaned;\n  }\n\n  // Must be exactly 8 digits\n  if (!/^\\d{8}$/.test(localNumber)) return false;\n\n  // Check valid provider prefix\n  const prefix = localNumber.charAt(0);\n  return VALID_PREFIXES.includes(prefix);\n}\n\nexport type PhoneProvider = 'Tunisie Telecom' | 'Ooredoo' | 'Orange' | 'Lycamobile';\n\n/**\n * Returns the *original* operator assigned to a Tunisian mobile number, derived\n * from its first digit.\n *\n * **⚠️ MNP caveat:** Tunisia fully implements Mobile Number Portability, so a\n * number's *current* network operator can differ from the prefix it was\n * originally assigned. This helper reports only the prefix-derived operator\n * and MUST NOT be used to determine the number's active carrier.\n *\n * - Tunisie Telecom: `9x`, `4x`\n * - Ooredoo: `2x`\n * - Orange: `5x`\n * - Lycamobile: `6x`\n *\n * @param phone - The mobile number (with or without `+216` / `00216` prefix)\n * @returns The prefix-derived provider, or `null` if the number is invalid\n */\nexport function getPhoneProvider(phone: string): PhoneProvider | null {\n  if (typeof phone !== 'string') return null;\n\n  // Remove spaces and dashes\n  const cleaned = phone.replace(/[\\s-]/g, '');\n\n  // Extract the 8-digit local number\n  let localNumber: string;\n  if (cleaned.startsWith('+216')) {\n    localNumber = cleaned.slice(4);\n  } else if (cleaned.startsWith('00216')) {\n    localNumber = cleaned.slice(5);\n  } else {\n    localNumber = cleaned;\n  }\n\n  // Must be exactly 8 digits\n  if (!/^\\d{8}$/.test(localNumber)) return null;\n\n  const prefix = localNumber.charAt(0);\n  if (prefix === '2') return 'Ooredoo';\n  if (prefix === '5') return 'Orange';\n  if (prefix === '6') return 'Lycamobile';\n  if (prefix === '4' || prefix === '9') return 'Tunisie Telecom';\n  return null;\n}\n","/**\n * Validates a Tunisian RIB (Relevé d'Identité Bancaire).\n * - Must be exactly 20 digits\n * - Uses Modulo 97 algorithm for check digit validation\n *\n * RIB Format: BB BBB CCCCC CCCCCCC KK\n * - BB: Bank code (2 digits)\n * - BBB: Branch code (3 digits)\n * - CCCCC CCCCCCC: Account number (12 digits)\n * - KK: Check digits (2 digits)\n */\nexport function isValidRIB(rib: string): boolean {\n  if (typeof rib !== 'string') return false;\n\n  // Remove spaces\n  const cleaned = rib.replace(/\\s/g, '');\n\n  // Must be exactly 20 digits\n  if (!/^\\d{20}$/.test(cleaned)) return false;\n\n  // Modulo 97 validation\n  // The entire RIB number modulo 97 should equal 97\n  // We process in chunks to avoid BigInt issues\n  const remainder = mod97(cleaned);\n\n  return remainder === 0;\n}\n\n/**\n * Calculate modulo 97 for a large number string\n */\nfunction mod97(numStr: string): number {\n  let remainder = 0;\n  for (const char of numStr) {\n    remainder = (remainder * 10 + parseInt(char, 10)) % 97;\n  }\n  return remainder;\n}\n","/**\n * Validates a Tunisian Company Tax ID (Matricule Fiscale).\n * Format: 1234567/X/A/M/000\n * - 7 digits\n * - 1 letter: control letter (any Latin letter except I, O, U, which are\n *   excluded to avoid confusion with digits 1, 0)\n * - 1 letter: type (A, B, P, D, N)\n * - 1 letter: category (M, C, P, E, N)\n * - 3 digits (establishment number)\n *\n * Accepts formats with or without separators (/, spaces)\n */\nexport function isValidMatricule(mat: string): boolean {\n  if (typeof mat !== 'string') return false;\n\n  // Remove common separators\n  const cleaned = mat.replace(/[\\s/\\\\-]/g, '').toUpperCase();\n\n  // Pattern: 7 digits + 1 control letter (not I/O/U) + 1 letter (A,B,P,D,N)\n  // + 1 category letter (M,C,P,E,N) + 3 digits.\n  const pattern = /^\\d{7}[^IOU][ABPDN][MCPEN]\\d{3}$/;\n\n  return pattern.test(cleaned);\n}\n","/**\n * Validates a Tunisian passport number.\n *\n * Two formats are accepted:\n * - 1 letter followed by 7 digits (legacy / machine-readable format)\n *   e.g. `A1234567`\n * - 2 letters followed by 6 digits (newer biometric format)\n *   e.g. `AB123456`\n */\nexport function isValidPassport(pass: string): boolean {\n  if (typeof pass !== 'string') return false;\n\n  const cleaned = pass.replace(/\\s/g, '').toUpperCase();\n\n  // 1 letter + 7 digits  OR  2 letters + 6 digits\n  return /^[A-Z]\\d{7}$/.test(cleaned) || /^[A-Z]{2}\\d{6}$/.test(cleaned);\n}\n","/**\n * Validates a Tunisian IBAN (International Bank Account Number).\n *\n * Format: TN59 1234 5678 9012 3456 7890 (24 characters)\n * - TN: Country code\n * - 59: Check digits (calculated using ISO 7064 Modulo 97-10)\n * - Remaining 20 digits: RIB (bank account number)\n *\n * @param iban - The IBAN string to validate\n * @returns true if the IBAN is valid, false otherwise\n */\nexport function isValidIBAN(iban: string): boolean {\n  if (typeof iban !== 'string') return false;\n\n  // Remove spaces and convert to uppercase\n  const cleaned = iban.replace(/\\s/g, '').toUpperCase();\n\n  // Must be exactly 24 characters\n  if (cleaned.length !== 24) return false;\n\n  // Must start with TN\n  if (!cleaned.startsWith('TN')) return false;\n\n  // Remaining characters after TN must be digits\n  if (!/^TN\\d{22}$/.test(cleaned)) return false;\n\n  // ISO 7064 Modulo 97-10 validation\n  // Move first 4 characters to end and convert letters to numbers (A=10, B=11, ..., Z=35)\n  const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);\n  const numericString = rearranged.replace(/[A-Z]/g, (char) =>\n    (char.charCodeAt(0) - 55).toString()\n  );\n\n  // Calculate modulo 97\n  const remainder = mod97(numericString);\n\n  return remainder === 1;\n}\n\n/**\n * Converts a Tunisian RIB (20 digits) to a full IBAN (24 characters).\n *\n * @param rib - The 20-digit RIB to convert\n * @returns The full IBAN string, or null if the RIB is invalid\n */\nexport function ribToIBAN(rib: string): string | null {\n  if (typeof rib !== 'string') return null;\n\n  // Remove spaces\n  const cleaned = rib.replace(/\\s/g, '');\n\n  // Must be exactly 20 digits\n  if (!/^\\d{20}$/.test(cleaned)) return null;\n\n  // Calculate check digits\n  // Formula: 98 - ((RIB * 100 + TN_numeric) mod 97)\n  // TN = 29 14 (T=29, N=23) → \"2923\"\n  const checkBase = cleaned + '292300';\n  const checkDigits = 98 - mod97(checkBase);\n\n  // Format check digits with leading zero if needed\n  const formattedCheck = checkDigits.toString().padStart(2, '0');\n\n  return `TN${formattedCheck}${cleaned}`;\n}\n\n/**\n * Calculate modulo 97 for a large number string.\n * Processes in chunks to avoid BigInt issues.\n */\nfunction mod97(numStr: string): number {\n  let remainder = 0;\n  for (const char of numStr) {\n    remainder = (remainder * 10 + parseInt(char, 10)) % 97;\n  }\n  return remainder;\n}\n","/**\n * Validates a Tunisian landline phone number.\n *\n * Landlines in Tunisia are 8 digits starting with 7.\n * The second digit indicates the region:\n * - 70: Grand Tunis (Tunis, Ariana, Ben Arous, Manouba)\n * - 71: Greater Tunis\n * - 72: Northeast (Cap Bon, Bizerte)\n * - 73: Sahel (Sousse, Monastir, Mahdia)\n * - 74: Sfax region\n * - 75: Gafsa, Tozeur, Kebili\n * - 76: Gabès, Médenine, Tataouine\n * - 77: Kasserine, Sidi Bouzid\n * - 78: Béja, Jendouba, Le Kef, Siliana\n * - 79: Grand Tunis (Tunis, Ariana, Ben Arous, Manouba)\n *\n * Supports formats:\n * - 71234567 (8 digits)\n * - +21671234567 (with country code)\n * - 0021671234567 (with 00 prefix)\n */\nexport function isValidLandline(phone: string): boolean {\n  if (typeof phone !== 'string') return false;\n\n  // Remove spaces and dashes\n  const cleaned = phone.replace(/[\\s-]/g, '');\n\n  // Extract the 8-digit local number\n  let localNumber: string;\n\n  if (cleaned.startsWith('+216')) {\n    localNumber = cleaned.slice(4);\n  } else if (cleaned.startsWith('00216')) {\n    localNumber = cleaned.slice(5);\n  } else {\n    localNumber = cleaned;\n  }\n\n  // Must be exactly 8 digits\n  if (!/^\\d{8}$/.test(localNumber)) return false;\n\n  // Must start with 7 and have valid region prefix (70-79)\n  const prefix = localNumber.substring(0, 2);\n  const validPrefixes = ['70', '71', '72', '73', '74', '75', '76', '77', '78', '79'];\n\n  return validPrefixes.includes(prefix);\n}\n","/**\n * Validates a Tunisian license plate (Matricule).\n *\n * Standard formats:\n * - \"123 تونس 4567\" (Arabic, with or without spaces)\n * - \"123 TU 4567\"  (Latin representation, case-insensitive)\n *\n * Special series (per ATT.TN documentation):\n * - Diplomatic corps: \"12 CD 34\" (CD = Corps Diplomatique)\n * - Résident Secondaire / rental: \"RS 12345 AB\"\n * - Motorcycle: \"01 MN 1234\"\n * - Tractor: \"01 TRAC 1234\"\n * - PAT — Personnel Administratif et Technique: \"01 MF 01\"\n * - CMD — Chef de Mission Diplomatique: \"01 RB 01\"\n * - MD — Mission Diplomatique: \"01 SD 01\"\n * - MC — Mission Consulaire: \"01 TQ 01\"\n *\n * @see https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Tunisia\n */\nexport function isValidLicensePlate(plate: string): boolean {\n  if (typeof plate !== 'string') return false;\n\n  // Remove all spaces\n  const cleaned = plate.replace(/\\s/g, '');\n\n  // Pattern 1: Arabic format (تونس)\n  const arabicPattern = /^\\d{3}تونس\\d{4}$/;\n\n  // Pattern 2: Latin standard format (TU or Tunisia)\n  const latinPattern = /^\\d{3}TU\\d{4}$/i;\n\n  // Pattern 3: Diplomatic corps (CD = Corps Diplomatique)\n  const diplomaticPattern = /^\\d{2}CD\\d{2}$/i;\n\n  // Pattern 4: Résident Secondaire / rental (RS)\n  const rentalPattern = /^RS\\d{5}[A-Z]{2}$/i;\n\n  // Pattern 5: Motorcycle (MN)\n  const motoPattern = /^\\d{2}MN\\d{4}$/i;\n\n  // Pattern 6: Tractor (TRAC)\n  const tracteurPattern = /^\\d{2}TRAC\\d{4}$/i;\n\n  // Pattern 7: PAT — Personnel Administratif et Technique (MF)\n  const patPattern = /^\\d{2}MF\\d{2}$/i;\n\n  // Pattern 8: CMD — Chef de Mission Diplomatique (RB)\n  const cmdPattern = /^\\d{2}RB\\d{2}$/i;\n\n  // Pattern 9: MD — Mission Diplomatique (SD)\n  const mdPattern = /^\\d{2}SD\\d{2}$/i;\n\n  // Pattern 10: MC — Mission Consulaire (TQ)\n  const mcPattern = /^\\d{2}TQ\\d{2}$/i;\n\n  return (\n    arabicPattern.test(cleaned) ||\n    latinPattern.test(cleaned) ||\n    diplomaticPattern.test(cleaned) ||\n    rentalPattern.test(cleaned) ||\n    motoPattern.test(cleaned) ||\n    tracteurPattern.test(cleaned) ||\n    patPattern.test(cleaned) ||\n    cmdPattern.test(cleaned) ||\n    mdPattern.test(cleaned) ||\n    mcPattern.test(cleaned)\n  );\n}\n","/**\n * Validates a Tunisian postal code.\n *\n * Postal codes are exactly 4 digits in the range `1000`–`9299`.\n * The all-zero code `0000` is rejected.\n *\n * @param code - The postal code as a string (or number)\n * @returns `true` if the code is a well-formed Tunisian postal code\n */\nexport function isValidPostalCode(code: string | number): boolean {\n  const normalized = typeof code === 'number' ? String(code) : String(code).replace(/\\s/g, '');\n  if (!/^\\d{4}$/.test(normalized)) return false;\n\n  const value = parseInt(normalized, 10);\n  if (value < 1000 || value > 9299) return false;\n\n  return true;\n}\n"]}