UNPKG

@sroussey/parse-address

Version:

International street address parser for 220 jurisdictions (US, CA + 218 countries and territories), with SEC EDGAR country-code resolution

141 lines 6.09 kB
/** * Bahrain (BH) address configuration. * * Bahrain uses a Building / Road / Block numbering system instead of named * streets and house numbers. The BLOCK number (3-4 digits) is the routing code: * UPU/Bahrain Post treat it as the postal code, written after the city * ("Manama 319"). In the street body it is written "Block 319". Both forms are * supported; the block number is emitted as `postal_code`. * * Two dominant forms: * 1. PO Box: "P.O. Box 1234, Manama" -> sec_unit PO Box + city. * 2. Physical: "Building 50, Road 1901, Block 319, Manama" * -> sec_unit Building + street ("Road 1901") + postal_code (319, * from the Block) + city (Manama). The postal form * "Building 50, Road 1901, Manama 319" parses identically. * * Order: the labelled BUILDING leads ("Building 50"); then the numbered road * ("Road 1901"), then the Block, then the city/area. * Type: Bahraini roads are numbered ("Road 1901") and parse as a whole type-less * name; a few named roads carry a trailing type (Avenue, Highway, ...). * postal_code = the BLOCK number (3-4 digits). * city = the area / town (Manama, Muharraq, Riffa, Isa Town, Hamad Town, ...). * state = optional governorate -> Capital (CAP), Muharraq (MUH), Northern (NOR), * Southern (SOU). * * KNOWN GAPS (see research-bh.md): a building written as its own comma segment * after the block, and an area-first written order, are documented failure modes. */ const TYPES = [ "Avenue", "Highway", "Road", "Street", "Boulevard", "Ave", "Hwy", "Rd", "St", ]; const TYPE_SHORT = { avenue: "AVE", ave: "AVE", highway: "HWY", hwy: "HWY", road: "RD", rd: "RD", street: "ST", st: "ST", boulevard: "BLVD", }; // Four governorates (Bahrain Post abbreviations). const GOVERNORATES = ["Capital", "Muharraq", "Northern", "Southern"]; const GOV_ALT = "(?:" + GOVERNORATES.join("|") + ")(?:\\s+Governorate)?"; const REGION_MAP = { capital: "CAP", "capital governorate": "CAP", muharraq: "MUH", "muharraq governorate": "MUH", northern: "NOR", "northern governorate": "NOR", southern: "SOU", "southern governorate": "SOU", }; const BLOCK_RE = /^Block\s+(\d{3,4})$/i; export const bhConfig = { code: "bh", country: "BH", countryNames: ["Bahrain", "Kingdom of Bahrain", "BHR", "BH"], order: "number-street", typePlacement: "suffix", postalPlacement: "after-city", normalizeTypeCase: false, // Block number used as the postal code: 3-4 digits, after the city. postalPattern: "(?<postal_code>\\d{3,4})", // No independent leading house number (the building is labelled and handled as // a unit); keep a harmless digit run for parity. houseNumberPattern: "(?<number>\\d+)(?<civic_number_suffix>[A-Za-z](?![A-Za-z]))?", types: TYPES, typeDisplayMap: {}, typeShortCodeMap: TYPE_SHORT, // Keep the "Block NNN, Area[, Governorate]" chain together; in postNormalize // lift the Block number to postal_code (dropping the "Block" word) and keep the // area as the city. Only a real governorate lands in state. cityAllowsCommas: true, countyPattern: GOV_ALT, regionPattern: `(?<state>${GOV_ALT})`, regionMap: REGION_MAP, postNormalize: (parsed) => { var _a; const dropped = []; const lift = (part) => { const m = BLOCK_RE.exec(part.trim()); if (m) { if (!parsed.postal_code) parsed.postal_code = m[1]; // Drop the whole "Block NNN" and the bare word "Block" so the token guard // exempts the residue left before the postal-code cut. dropped.push(part.trim(), "Block"); return true; } return false; }; if (typeof parsed.city === "string") { if (parsed.city.includes(",")) { let parts = parsed.city.split(",").map((s) => s.trim()).filter(Boolean); const last = ((_a = parts[parts.length - 1]) !== null && _a !== void 0 ? _a : "").toLowerCase().replace(/\s+governorate$/, ""); // Only fold a trailing governorate here when the grammar has NOT already // captured one (otherwise this word is the AREA the city slot needs, e.g. // "..., Muharraq, Muharraq" -> area Muharraq + governorate Muharraq). if (!parsed.state && REGION_MAP[last]) { parsed.state = REGION_MAP[last]; parts.pop(); } parts = parts.filter((p) => !lift(p)); if (parts.length) { parsed.city = parts[parts.length - 1]; if (parts.length > 1) dropped.push(...parts.slice(0, -1)); } else { delete parsed.city; } } else if (lift(parsed.city)) { // "Block 319" as the sole locality: became the postal code, no city. delete parsed.city; } } if (dropped.length) parsed.__dropped = dropped; }, // Building / villa / flat / office lead-in ("Building 50", "Bldg No. 50"). secUnitPlacement: "before", secUnitPattern: "(?<sec_unit_type>Building|Bldg\\.?|Villa|Flat|Apartment|Apt\\.?|Office|Floor|Unit|Shop)\\.?\\s*(?:No\\.?\\s*)?(?<sec_unit_num>\\d+[A-Za-z0-9\\-/]*)", secUnitDisplayMap: { building: "Building", bldg: "Building", villa: "Villa", flat: "Flat", apartment: "Apartment", apt: "Apt", office: "Office", floor: "Floor", unit: "Unit", shop: "Shop", }, poBoxNames: ["PO Box", "P.O. Box", "P O Box", "POB", "Post Box"], poBoxDisplayMap: { "po box": "PO Box", "p.o. box": "PO Box", "p o box": "PO Box", pob: "PO Box", "post box": "PO Box", }, }; export default bhConfig; //# sourceMappingURL=config.js.map