smart-id-validator
Version:
A package to validate official document numbers and other IDs format for various countries.
112 lines (96 loc) • 3.71 kB
text/typescript
import { PhoneValidationResult, CNICValidationResult, PasspostValidateResult } from './common';
const networkPrefixes: { [key: string]: string } = {
// Jazz
"300": "Jazz", "301": "Jazz", "302": "Jazz", "303": "Jazz", "304": "Jazz",
"305": "Jazz", "306": "Jazz", "307": "Jazz", "308": "Jazz", "309": "Jazz",
// Zong
"310": "Zong", "311": "Zong", "312": "Zong", "313": "Zong", "314": "Zong",
"315": "Zong", "316": "Zong", "317": "Zong", "318": "Zong", "319": "Zong",
"370": "Zong",
// Warid
"320": "Warid", "321": "Warid", "322": "Warid", "323": "Warid", "324": "Warid",
"325": "Warid", "326": "Warid", "327": "Warid", "328": "Warid", "329": "Warid",
// Ufone
"330": "Ufone", "331": "Ufone", "332": "Ufone", "333": "Ufone", "334": "Ufone",
"335": "Ufone", "336": "Ufone", "337": "Ufone", "338": "Ufone", "339": "Ufone",
// Telenor
"340": "Telenor", "341": "Telenor", "342": "Telenor", "343": "Telenor",
"344": "Telenor", "345": "Telenor", "346": "Telenor", "347": "Telenor",
"348": "Telenor", "349": "Telenor",
// SCO (Special Communications Organization)
"355": "SCO"
};
export function validatePhoneNumberPK(phoneNumber: string): PhoneValidationResult {
// Remove spaces, dashes, and brackets
const cleanedNumber = phoneNumber.replace(/[\s\-\(\)]/g, "");
// Define regex patterns
const patterns = {
mobile: /^(?:\+92|0)?(3\d{2})\d{7}$/,
tollFree: /^(?:\+92|0)?(800)\d{5,6}$/,
landline: /^(?:\+92|0)?([2-9]\d{1,2})\d{6,7}$/,
emergency: /^(?:\+92|0)?(15|16|1122|115)$/,
shortcode: /^\d{3,5}$/
};
// Match mobile number
let match = patterns.mobile.exec(cleanedNumber);
if (match) {
const networkCode = match[1];
const numberWithoutPrefix = cleanedNumber.replace(/^(\+92|0)/, '');
return {
isValid: true,
type: "mobile",
formatted: `0${networkCode}${numberWithoutPrefix.slice(-7)}`,
network: networkPrefixes[networkCode] || "Unknown",
country: "PK",
};
}
// Match other types
for (const [type, regex] of Object.entries(patterns)) {
if (type !== "mobile" && regex.test(cleanedNumber)) {
let formattedNumber = cleanedNumber.replace(/^(\+92|0)/, '');
if (type === "tollFree") {
formattedNumber = `0800${formattedNumber.slice(-5)}`;
} else if (type === "emergency" || type === "shortcode") {
formattedNumber = cleanedNumber.replace(/^(\+92|0)/, '');
} else if (type === "landline") {
formattedNumber = `0${formattedNumber}`;
}
return {
isValid: true,
type: type as PhoneValidationResult["type"],
formatted: formattedNumber,
country: "PK",
};
}
}
// If none matched, return invalid
return { isValid: false };
}
export function validateCNICPK(cnic: string): CNICValidationResult {
// Remove any non-numeric characters
const cleanedCNIC = cnic.replace(/\D/g, "");
// Ensure CNIC is exactly 13 digits and starts with 1-7
if (!/^[1-7]\d{12}$/.test(cleanedCNIC)) {
return { isValid: false };
}
// Format as #####-#######-#
return {
isValid: true,
formatted: `${cleanedCNIC.slice(0, 5)}-${cleanedCNIC.slice(5, 12)}-${cleanedCNIC.slice(12)}`,
country: "PK",
};
}
export function validatePassportPK(passport: string): PasspostValidateResult {
// Remove any non-alphanumeric characters
const cleanedPassport = passport.replace(/[^a-zA-Z0-9]/g, "");
// Ensure passport number is exactly 9 characters: 2 letters followed by 7 digits
if (!/^[A-Z]{2}\d{7}$/.test(cleanedPassport)) {
return { isValid: false };
}
// Format as XX#######
return {
isValid: true,
formatted: cleanedPassport,
country: "PK",
};
}