SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
6 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
4.3 KB · 80 lines typescript
Raw Blame History
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