spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { Parser, ExtractedRecord, RawDocument, ConnectorContext } from "@dci/connectors";2import { countryFromText, cleanText } from "@dci/core";3import { loadHtml, tableRows, txt, parenthetical, resolvePlace, regionRecord, type Place } from "./shared.js";4import { normKey } from "./city-coords.js";56/**7 * Alibaba Cloud — https://www.alibabacloud.com/help/en/ecs/product-overview/regions-and-zones (static docs):8 * table Region name | Region ID | Number of zones | Zone name | Zone ID e.g. "Germany (Frankfurt)" | eu-central-1 | 39 * Launch years come from https://www.alibabacloud.com/global-locations (static <li>: "Japan (Tokyo) Availability Zone: 510 * Released in 2016"), joined on the region display name.11 */12const LOCATIONS_PAGE = "https://www.alibabacloud.com/global-locations";13const NAME_ISO: Array<[RegExp, string]> = [[/^China\b/i, "CN"], [/^SAU\b/i, "SA"], [/^UK\b/i, "GB"], [/^US\b/i, "US"], [/^UAE\b/i, "AE"], [/^Mexico\b/i, "MX"]];1415async function releaseYears(ctx: ConnectorContext): Promise<Map<string, string>> {16 const cached = await ctx.getState<Record<string, string>>("alibaba:releaseYears");17 if (cached) return new Map(Object.entries(cached));18 const map = new Map<string, string>();19 const doc = await ctx.fetch(LOCATIONS_PAGE, { group: "regions" });20 if (doc.error || doc.status !== 200) { ctx.log("warn", `alibaba global-locations unavailable (${doc.error?.code ?? doc.status}); launch years left null`); return map; }21 const $ = loadHtml(doc);22 $("li.item").each((_, li) => {23 const t = txt($(li));24 const m = t.match(/^(.*?)\s*Availability Zone:\s*(\d+)\s*Released in\s*(\d{4})/i);25 if (m) map.set(normKey(m[1]!), m[3]!);26 });27 await ctx.setState("alibaba:releaseYears", Object.fromEntries(map));28 return map;29}3031export const alibabaRegionsParser: Parser = {32 name: "cloud_alibaba_regions_v1",33 version: "1.0.0",34 pageTypes: ["cloud_region"],35 async parse(doc: RawDocument, ctx): Promise<ExtractedRecord[]> {36 const $ = loadHtml(doc);37 const years = await releaseYears(ctx);38 const out: ExtractedRecord[] = [];39 const seen = new Set<string>();40 for (const row of tableRows($, $("table"))) {41 if (row.length < 3) continue;42 const code = row[1]!.trim();43 if (!/^[a-z]{2}-[a-z0-9-]+$/.test(code) || seen.has(code)) continue;44 seen.add(code);45 const rawName = row[0]!;46 const closing = /closing down/i.test(rawName);47 const name = cleanText(rawName.replace(/closing down/i, "").replace(/\s*-\s*(Local|Partner) Region/i, "")) ?? rawName;48 const zones = Number.parseInt(row[2]!.replace(/[^\d]/g, ""), 10);49 const iso = NAME_ISO.find(([re]) => re.test(name))?.[1] ?? countryFromText(name.replace(/\(.*\)/, "")) ?? null;50 const label = parenthetical(rawName)?.replace(/\s*-\s*(Local|Partner) Region/i, "") ?? (iso === "SG" ? "Singapore" : null);51 const isoHint = label && /^hong kong$/i.test(label) ? "HK" : label && /^macau|macao$/i.test(label) ? "MO" : iso;52 const place: Place = resolvePlace(label, isoHint);53 if (!place.countryIso2) place.countryIso2 = isoHint ?? (label ? countryFromText(label) : null);54 const year = years.get(normKey(name)) ?? years.get(normKey(rawName.replace(/closing down/i, ""))) ?? null;55 const externalIds: Record<string, string | number> = { alibaba_region_id: code, kind: /local region/i.test(rawName) ? "local_region" : "region" };56 if (closing) externalIds.lifecycle = "closing_down";57 if (/partner region/i.test(rawName)) externalIds.operated_by = "partner";58 if (label) externalIds.published_location = label;59 out.push(60 regionRecord({61 connectorId: ctx.connectorId,62 keyPrefix: "alibaba:region",63 providerName: "Alibaba Cloud",64 code,65 name,66 place,67 availabilityZones: Number.isFinite(zones) && zones > 0 ? zones : null,68 launchedOn: year,69 status: "operational",70 externalIds,71 url: doc.finalUrl,72 methods: { code: "html:table.RegionID", name: "html:table.RegionName", availabilityZones: "html:table.NumberOfZones", launchedOn: year ? "html:global-locations.ReleasedIn" : "none", city: "curated-city-table" },73 }),74 );75 }76 ctx.log("info", `alibaba: ${out.length} regions (${[...years.keys()].length} launch years matched from global-locations)`);77 return out;78 },79};80