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, parenthetical, resolvePlace, regionRecord, type Place } from "./shared.js";45/**6 * Tencent Cloud — https://www.tencentcloud.com/document/product/213/6091 (docs table, server-rendered for the7 * SDK's direct fetcher; curl with a bot UA gets an anti-bot JS page, so `looksBlockedOrEmpty` escalation covers it):8 * Region | Region ID | Number of AZs | AZ — the first row of each region carries name/id/count, following rows only AZs.9 * Names look like "North China (Beijing)", "Asia Pacific and the Middle East (Singapore) Coverage: Southeast Asia",10 * "Beijing Finance Available only to finance institutions…", "Shanghai Self-driving Cloud".11 */12export const tencentRegionsParser: Parser = {13 name: "cloud_tencent_regions_v1",14 version: "1.0.0",15 pageTypes: ["cloud_region"],16 parse(doc: RawDocument, ctx): ExtractedRecord[] {17 const $ = loadHtml(doc);18 const out: ExtractedRecord[] = [];19 const seen = new Set<string>();20 for (const row of tableRows($, $("table"))) {21 if (row.length < 3) continue;22 const code = row[1]!.trim();23 if (!/^(ap|na|eu|sa|me|af)-[a-z]+(-[a-z]+)*$/.test(code) || seen.has(code)) continue;24 seen.add(code);25 const raw = row[0]!;26 const restricted = /available only|upon application/i.test(raw);27 const name = cleanText(raw.replace(/\s*Coverage:.*$/i, "").replace(/\s*Available only.*$/i, "")) ?? raw;28 const azs = Number.parseInt(row[2]!.replace(/[^\d]/g, ""), 10);29 // "Hong Kong (China), Macao (China), and Taiwan (China)" → drop the "(China)" qualifiers before reading the city30 const bare = name.replace(/\s*\(China\)/g, "");31 const label = parenthetical(bare)?.trim() ?? bare.replace(/\s+(Finance|Self-driving Cloud).*$/i, "").split(/,|\band\b/)[0]!.trim();32 const chinaRegion = /^(North|East|South|Southwest|Northwest|Central) China\b/i.test(name) || /Finance|Self-driving/i.test(name) || /^cn|^ap-(beijing|shanghai|nanjing|guangzhou|chengdu|chongqing|zhongwei|shenzhen|hongkong)/.test(code);33 const isoHint = /hong kong/i.test(label) ? "HK" : chinaRegion ? "CN" : null;34 let place: Place = resolvePlace(label, isoHint);35 if (!place.countryIso2) place.countryIso2 = isoHint ?? countryFromText(label) ?? countryFromText(name);36 const externalIds: Record<string, string | number> = { tencent_region_id: code, published_location: label };37 const coverage = raw.match(/Coverage:\s*(.+)$/i)?.[1];38 if (coverage) externalIds.coverage = cleanText(coverage) ?? coverage;39 if (/Finance/i.test(name)) externalIds.realm = "finance";40 if (/Self-driving/i.test(name)) externalIds.realm = "self_driving_cloud";41 out.push(42 regionRecord({43 connectorId: ctx.connectorId,44 keyPrefix: "tencent:region",45 providerName: "Tencent Cloud",46 code,47 name,48 place,49 availabilityZones: Number.isFinite(azs) && azs > 0 ? azs : null,50 status: restricted || /Self-driving/i.test(name) ? "restricted" : "operational",51 externalIds,52 url: doc.finalUrl,53 methods: { code: "html:table.RegionID", name: "html:table.Region", availabilityZones: "html:table.NumberOfAZs", city: "curated-city-table" },54 }),55 );56 }57 ctx.log("info", `tencent: ${out.length} regions`);58 return out;59 },60};61