country-to-iso
Version:
Convert inconsistent country names and codes into ISO 3166-1 alpha-2.
146 lines (121 loc) • 4.33 kB
text/typescript
import * as fs from "fs";
import * as path from "path";
import * as countryJs from "countryjs";
import * as countryList from "country-list";
import * as isoCountries from "i18n-iso-countries";
interface CountryData {
alpha2: string;
alpha3: string;
names: Array<string>
}
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const dataDir = path.join(__dirname, "..", "..", "..", "data");
const countryDir = path.join(dataDir, "country");
const alpha2File = path.join(dataDir, "iso-alpha-2.json");
const alpha3File = path.join(dataDir, "iso-alpha-3.json");
const alpha23File = path.join(dataDir, "iso-alpha-2-to-3.json");
const namesSeen : { [key: string]: string } = {};
const alpha2s: Array<string> = []
const alpha3s: {[key: string]: string} = {}
const alpha23s: {[key: string]: string} = {}
const loadCountryFile = function(file: string, alpha2: string, alpha3: string): CountryData {
let data : CountryData = {
alpha2,
alpha3,
names: []
};
try {
const stat = fs.lstatSync(file);
if (stat.isFile()) {
data = JSON.parse(fs.readFileSync(file).toString());
}
} catch (err: any) {
// Ignore file doesn't exist error as we'll create it
if (err.code !== "ENOENT") {
console.log(file);
throw err;
}
}
return data;
}
const getCountryInfo = function(code: string) {
let alpha2 = null;
let alpha3 = null;
const names = [];
// Source from "countryjs"
const info = countryJs.info(code);
if (info) {
alpha2 = info.ISO.alpha2;
alpha3 = info.ISO.alpha3;
names.push(info.name);
names.push(info.nativeName);
for (const alt of info.altSpellings) {
names.push(alt);
}
}
// Source from "country-list"
const countryListName = countryList.getName(code);
if (countryListName) {
alpha2 = code;
names.push(countryListName);
}
// Source from "i18n-iso-countries"
const isoNames = isoCountries.getName(code, "en", { select: "all" });
if (Array.isArray(isoNames)) {
isoNames.forEach(name => names.push(name));
}
// Populate alpha 3 if not found yet
if (alpha2 && !alpha3) {
alpha3 = isoCountries.alpha2ToAlpha3(code);
}
return { alpha2, alpha3, names };
}
const processCountryCode = function(code: string) {
const countryFile = path.join(countryDir, `${code}.json`);
let data : CountryData = getCountryInfo(code);
// Attempt to load country data from this library
if (!data.alpha2) {
data = loadCountryFile(countryFile, data.alpha2, data.alpha3);
}
if (data.alpha2) {
// ISO 3166
alpha2s.push(data.alpha2);
alpha3s[data.alpha3] = data.alpha2;
alpha23s[data.alpha2] = data.alpha3;
// Load existing data
data = loadCountryFile(countryFile, data.alpha2, data.alpha3);
// Populate a set so we don't duplicate
const namesSet = new Set(data.names);
namesSet.add(data.alpha2);
namesSet.add(data.alpha3);
data.names.forEach((name) => namesSet.add(name));
// Empty names array so we don't duplicate
data.names = [];
// Put names back into names array
for (const name of namesSet) {
if (typeof name === 'string' && name.length > 1) {
if (namesSeen[name]) {
console.log(`CLASH! "${name}" [${data.alpha2}] has been seen for ${namesSeen[name]}`);
} else {
data.names.push(name);
namesSeen[name] = data.alpha2;
}
}
}
fs.writeFileSync(countryFile, JSON.stringify(data, null, 2));
}
}
const seed = function() {
for (const letter1 of alphabet) {
for (const letter2 of alphabet) {
processCountryCode(`${letter1}${letter2}`);
}
}
fs.writeFileSync(alpha2File, JSON.stringify(alpha2s, null, 2));
fs.writeFileSync(alpha3File, JSON.stringify(alpha3s, null, 2));
fs.writeFileSync(alpha23File, JSON.stringify(alpha23s, null, 2));
console.log("Seed complete...");
console.log(`* Countries: ${alpha2s.length};`);
console.log(`* Names: ${Object.keys(namesSeen).length}`);
}
seed();