UNPKG

zellige.js

Version:

A Moroccan utility library for working with CIN, phone numbers, currency, addresses, dates, and more.

172 lines (171 loc) 5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.sanitizeCIN = sanitizeCIN; exports.validateCIN = validateCIN; exports.isValidCIN = isValidCIN; exports.getCINRegion = getCINRegion; exports.generateTestCIN = generateTestCIN; const regions_1 = require("../constants/regions"); const cin_1 = require("../types/cin"); /** * Regular expression for Moroccan CIN validation * Format: 1-3 letters followed by 6 digits */ const CIN_REGEX = /^[A-Z]{1,3}\d{6}$/; /** * Sanitizes a CIN (Carte d'Identité Nationale) input string by removing whitespace and special characters * * @param input - Raw CIN input that needs to be sanitized * @returns Sanitized uppercase string or null if input is invalid * * @example * ```typescript * sanitizeCIN('A 123456'); // Returns 'A123456' * sanitizeCIN('BE-789.012'); // Returns 'BE789012' * sanitizeCIN(null); // Returns null * ``` */ function sanitizeCIN(input) { if (typeof input !== 'string') { return null; } return input.replace(/[^A-Za-z0-9]/g, '').toUpperCase(); } /** * Performs comprehensive validation of a Moroccan CIN (Carte d'Identité Nationale) * * @param cin - The CIN string to validate * @returns Validation result containing status, errors, and metadata if valid * * @example * ```typescript * validateCIN('A123456'); * // Returns { * // isValid: true, * // errors: [], * // metadata: { * // region: 'Rabat', * // sequence: '123456', * // issuingOffice: 'A' * // } * // } * * validateCIN('XX999999'); * // Returns { * // isValid: false, * // errors: [{ * // code: CINErrorCode.INVALID_REGION, * // message: 'Invalid region prefix: XX' * // }] * // } * ``` */ function validateCIN(cin) { const result = { isValid: false, errors: [], }; // Input validation if (!cin || typeof cin !== 'string') { result.errors.push({ code: cin_1.CINErrorCode.INVALID_INPUT, message: 'CIN must be a non-empty string', }); return result; } // Sanitize input const sanitized = sanitizeCIN(cin); if (!sanitized) { result.errors.push({ code: cin_1.CINErrorCode.INVALID_INPUT, message: 'CIN contains invalid characters', }); return result; } // Check format if (!CIN_REGEX.test(sanitized)) { result.errors.push({ code: cin_1.CINErrorCode.INVALID_FORMAT, message: 'Invalid CIN format. Must be 1-3 letters followed by 6 digits', }); return result; } // Extract and validate parts const prefix = sanitized.match(/^[A-Z]+/)[0]; const sequence = sanitized.match(/\d+$/)[0]; // Validate region if (!regions_1.REGION_PREFIXES[prefix]) { result.errors.push({ code: cin_1.CINErrorCode.INVALID_REGION, message: `Invalid region prefix: ${prefix}`, }); return result; } // Validate sequence if (!/^[1-9]\d{5}$/.test(sequence)) { result.errors.push({ code: cin_1.CINErrorCode.INVALID_SEQUENCE, message: 'Sequence must be 6 digits and cannot start with 0', }); return result; } // Valid CIN result.isValid = true; result.metadata = { region: regions_1.REGION_PREFIXES[prefix], sequence: sequence, issuingOffice: prefix, }; return result; } /** * Quick check to determine if a string is a valid Moroccan CIN * * @param cin - The CIN string to check * @returns True if the CIN is valid, false otherwise * * @example * ```typescript * isValidCIN('A123456'); // Returns true * isValidCIN('XX999999'); // Returns false * isValidCIN('12345'); // Returns false * ``` */ function isValidCIN(cin) { return validateCIN(cin).isValid; } /** * Retrieves the region name associated with a CIN prefix * * @param prefix - The CIN prefix (1-3 letters) to look up * @returns The full region name or null if the prefix is invalid * * @example * ```typescript * getCINRegion('A'); // Returns 'Rabat' * getCINRegion('BK'); // Returns 'Casablanca' * getCINRegion('XX'); // Returns null * ``` */ function getCINRegion(prefix) { const sanitized = prefix.trim().toUpperCase(); return regions_1.REGION_PREFIXES[sanitized] || null; } /** * Generates a random valid CIN for testing purposes * * @param prefix - Optional specific region prefix to use * @returns A valid CIN string * * @example * ```typescript * generateTestCIN(); // Returns random CIN like 'A123456' * generateTestCIN('BK'); // Returns random CIN starting with 'BK' * ``` */ function generateTestCIN(prefix) { const randomPrefix = prefix || Object.keys(regions_1.REGION_PREFIXES)[Math.floor(Math.random() * Object.keys(regions_1.REGION_PREFIXES).length)]; const sequence = String(Math.floor(Math.random() * 899999) + 100000); return `${randomPrefix}${sequence}`; }