spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { Parser, ExtractedRecord, RawDocument } from "@dci/connectors";2import { countryFromText, cleanText } from "@dci/core";3import { loadHtml, tableRows, txt, resolvePlace, regionRecord, type Place } from "./shared.js";45/**6 * IBM Cloud — https://cloud.ibm.com/docs/overview?topic=overview-locations (server-rendered docs):7 * "Multizone regions" / "Single-campus MZRs" tables: Region ("Dallas (us-south)") | Zone ("us-south-1 us-south-2 us-south-3").8 * Later tables (fault domains, zone mapping, classic data centers) are ignored for regions.9 */10export const ibmRegionsParser: Parser = {11 name: "cloud_ibm_regions_v1",12 version: "1.0.0",13 pageTypes: ["cloud_region"],14 parse(doc: RawDocument, ctx): ExtractedRecord[] {15 const $ = loadHtml(doc);16 const out: ExtractedRecord[] = [];17 const seen = new Set<string>();18 $("table").each((_, table) => {19 const rows = tableRows($, $(table));20 const header = rows[0] ?? [];21 if (header.length !== 2 || !/^Region$/i.test(header[0] ?? "") || !/^Zone/i.test(header[1] ?? "")) return;22 // find the nearest preceding h2/h3 for the MZR type23 const heading = txt($(table).prevAll("h2,h3").first()) || txt($(table).parent().prevAll("h2,h3").first());24 const kind = /single-campus/i.test(heading) ? "single_campus_mzr" : "mzr";25 for (const row of rows.slice(1)) {26 const m = row[0]!.match(/^(.*?)\s*\(\s*([a-z]{2}-[a-z]{2,4})\s*\)/);27 if (!m) continue;28 const code = m[2]!;29 if (seen.has(code)) continue;30 seen.add(code);31 const rawCity = cleanText(m[1]!) ?? m[1]!;32 const partner = rawCity.match(/-\s*(.+)$/)?.[1]?.trim() ?? null; // "Chennai - Airtel"33 const cityLabel = rawCity.replace(/\s*-\s*.+$/, "").trim();34 const zones = (row[1] ?? "").split(/\s+/).filter((z) => /^[a-z]{2}-[a-z]{2,4}-\d$/.test(z));35 let place: Place = resolvePlace(cityLabel);36 if (!place.countryIso2) place.countryIso2 = countryFromText(cityLabel);37 if (!place.city) place.city = cityLabel;38 const externalIds: Record<string, string | number> = { ibm_region: code, kind, ibm_zones: zones.join(","), published_location: rawCity };39 if (partner) externalIds.partner = partner;40 out.push(41 regionRecord({42 connectorId: ctx.connectorId,43 keyPrefix: "ibm:region",44 providerName: "IBM Cloud",45 code,46 name: `${cityLabel} (${code})`,47 place,48 availabilityZones: zones.length || null,49 status: "operational",50 externalIds,51 url: doc.finalUrl,52 methods: { code: "html:table.Region", availabilityZones: "count:zones", city: "curated-city-table" },53 }),54 );55 }56 });57 ctx.log("info", `ibm: ${out.length} regions`);58 return out;59 },60};61