TypeScript 97.5%
SQL 1.4%
Python 0.8%
1/** Fetcha's internal geography model. Providers translate from this. */2export interface GeoTarget {3 country: string | null; // ISO 3166-1 alpha-2, upper-case4 region: string | null; // free-form, normalized lower-case slug (e.g. "quebec", "california")5 city: string | null; // normalized lower-case slug6}78export const COUNTRIES: Record<string, string> = {9 US: "United States",10 CA: "Canada",11 GB: "United Kingdom",12 DE: "Germany",13 FR: "France",14 ES: "Spain",15 IT: "Italy",16 NL: "Netherlands",17 BE: "Belgium",18 CH: "Switzerland",19 AT: "Austria",20 SE: "Sweden",21 NO: "Norway",22 DK: "Denmark",23 FI: "Finland",24 IE: "Ireland",25 PT: "Portugal",26 PL: "Poland",27 CZ: "Czechia",28 AU: "Australia",29 NZ: "New Zealand",30 JP: "Japan",31 KR: "South Korea",32 SG: "Singapore",33 HK: "Hong Kong",34 IN: "India",35 BR: "Brazil",36 MX: "Mexico",37 AR: "Argentina",38 CL: "Chile",39 CO: "Colombia",40 ZA: "South Africa",41 AE: "United Arab Emirates",42 IL: "Israel",43 TR: "Türkiye",44 TW: "Taiwan",45 TH: "Thailand",46 VN: "Vietnam",47 ID: "Indonesia",48 PH: "Philippines",49 MY: "Malaysia",50 GR: "Greece",51 RO: "Romania",52 HU: "Hungary",53 UA: "Ukraine",54};5556const CA_REGIONS: Record<string, string> = {57 qc: "quebec",58 quebec: "quebec",59 québec: "quebec",60 on: "ontario",61 ontario: "ontario",62 bc: "british_columbia",63 "british columbia": "british_columbia",64 ab: "alberta",65 alberta: "alberta",66 mb: "manitoba",67 manitoba: "manitoba",68 sk: "saskatchewan",69 saskatchewan: "saskatchewan",70 ns: "nova_scotia",71 "nova scotia": "nova_scotia",72 nb: "new_brunswick",73 "new brunswick": "new_brunswick",74 nl: "newfoundland_and_labrador",75 pe: "prince_edward_island",76 pei: "prince_edward_island",77 yt: "yukon",78 nt: "northwest_territories",79 nu: "nunavut",80};8182const US_STATES: Record<string, string> = {83 al: "alabama", ak: "alaska", az: "arizona", ar: "arkansas", ca: "california", co: "colorado", ct: "connecticut",84 de: "delaware", fl: "florida", ga: "georgia", hi: "hawaii", id: "idaho", il: "illinois", in: "indiana", ia: "iowa",85 ks: "kansas", ky: "kentucky", la: "louisiana", me: "maine", md: "maryland", ma: "massachusetts", mi: "michigan",86 mn: "minnesota", ms: "mississippi", mo: "missouri", mt: "montana", ne: "nebraska", nv: "nevada", nh: "new_hampshire",87 nj: "new_jersey", nm: "new_mexico", ny: "new_york", nc: "north_carolina", nd: "north_dakota", oh: "ohio", ok: "oklahoma",88 or: "oregon", pa: "pennsylvania", ri: "rhode_island", sc: "south_carolina", sd: "south_dakota", tn: "tennessee",89 tx: "texas", ut: "utah", vt: "vermont", va: "virginia", wa: "washington", wv: "west_virginia", wi: "wisconsin", wy: "wyoming",90 dc: "district_of_columbia",91};9293export function slugifyGeo(s: string): string {94 return s95 .normalize("NFD")96 .replace(/[̀-ͯ]/g, "")97 .toLowerCase()98 .trim()99 .replace(/[^a-z0-9]+/g, "_")100 .replace(/^_+|_+$/g, "");101}102103export function normalizeGeo(input: { country?: string | null; region?: string | null; city?: string | null }): GeoTarget {104 const country = input.country ? input.country.toUpperCase() : null;105 let region: string | null = null;106 if (input.region) {107 const key = input.region.toLowerCase().trim();108 if (country === "CA" && CA_REGIONS[key]) region = CA_REGIONS[key]!;109 else if (country === "US" && US_STATES[key]) region = US_STATES[key]!;110 else region = slugifyGeo(input.region);111 }112 const city = input.city ? slugifyGeo(input.city) : null;113 return { country, region, city };114}115