arabicfmt
Version:
Arabic-first formatting for numbers, currency, dates and bidirectional text across all 22 Arab League countries — with correct handling of the 2025–2026 Unicode currency-symbol transition (Saudi Riyal U+20C1, UAE Dirham U+20C3, Omani Rial U+20C4).
87 lines (84 loc) • 2.02 kB
JavaScript
// src/validate/iban.ts
var IBAN_LENGTHS = {
// Arab League
SA: 24,
AE: 23,
KW: 30,
BH: 22,
QA: 29,
JO: 30,
LB: 28,
EG: 29,
IQ: 23,
PS: 29,
TN: 24,
MR: 27,
LY: 25,
// Common partners
GB: 22,
DE: 22,
FR: 27,
NL: 18,
ES: 24,
IT: 27,
CH: 21,
BE: 16,
TR: 26,
PT: 25,
PK: 24
};
function toNumericString(rearranged) {
let out = "";
for (const ch of rearranged) {
const code = ch.charCodeAt(0);
out += code >= 65 && code <= 90 ? (code - 55).toString() : ch;
}
return out;
}
function mod97(numeric) {
let remainder = 0;
for (let i = 0; i < numeric.length; i++) {
remainder = (remainder * 10 + (numeric.charCodeAt(i) - 48)) % 97;
}
return remainder;
}
function normalizeIBAN(iban) {
return iban.replace(/\s+/g, "").toUpperCase();
}
function isValidIBAN(iban) {
const cleaned = normalizeIBAN(iban);
if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/.test(cleaned)) return false;
if (cleaned.length < 15 || cleaned.length > 34) return false;
const expected = IBAN_LENGTHS[cleaned.slice(0, 2)];
if (expected !== void 0 && cleaned.length !== expected) return false;
const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);
return mod97(toNumericString(rearranged)) === 1;
}
function formatIBAN(iban, options = {}) {
const cleaned = normalizeIBAN(iban);
const separator = options.separator ?? " ";
return (cleaned.match(/.{1,4}/g) ?? []).join(separator);
}
// src/validate/saudi-id.ts
function luhnOk(id) {
let sum = 0;
for (let i = 0; i < 10; i++) {
let d = id.charCodeAt(i) - 48;
if (i % 2 === 0) {
d *= 2;
if (d > 9) d -= 9;
}
sum += d;
}
return sum % 10 === 0;
}
function isValidSaudiId(id) {
const s = id.trim();
if (!/^[12][0-9]{9}$/.test(s)) return false;
return luhnOk(s);
}
function saudiIdType(id) {
if (!isValidSaudiId(id)) return null;
return id.trim()[0] === "1" ? "citizen" : "resident";
}
export { IBAN_LENGTHS, formatIBAN, isValidIBAN, isValidSaudiId, normalizeIBAN, saudiIdType };