aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFridon <[email protected]>2022-06-23 00:01:12 +0400
committerFridon <[email protected]>2022-06-23 00:01:12 +0400
commit7d72153d68ea4c682266f0301aa45b4e3a9e45a9 (patch)
treeba2b4b8937d0c7785a468fae18880762a5e6b484 /src
parentbe829dad070205555c514ff497fcf2eae355a6e2 (diff)
downloadcountryfetch-7d72153d68ea4c682266f0301aa45b4e3a9e45a9.tar.xz
countryfetch-7d72153d68ea4c682266f0301aa45b4e3a9e45a9.zip
big refactor + raw option
Diffstat (limited to 'src')
-rw-r--r--src/app.ts67
-rw-r--r--src/countries.ts133
-rw-r--r--src/environment/environment.ts12
-rw-r--r--src/models/FetchedCountry.model.ts9
-rw-r--r--src/models/country.model.ts23
-rw-r--r--src/util/cache.ts9
-rw-r--r--src/util/help.ts28
-rw-r--r--src/util/logger.ts77
8 files changed, 220 insertions, 138 deletions
diff --git a/src/app.ts b/src/app.ts
index 10129e1..7064d74 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -1,36 +1,41 @@
-import { green, cyan } from "https://deno.land/x/[email protected]/mod.ts";
import { Countries } from "./countries.ts";
-import { Cache } from "./util/cache.ts";
-import { help } from "./util/help.ts";
+import { Logger } from "./util/logger.ts";
-export async function app() {
- const command = Deno.args[0];
- const countries = new Countries(new Cache());
+export class App {
+ constructor(
+ // private cache: Cache,
+ private logger: Logger,
+ private countries: Countries
+ ) {}
- await countries.sync();
- switch (command) {
- case undefined:
- help();
- break;
- case "help":
- help();
- break;
- case "sync":
- await countries.sync({ force: true });
- break;
- case "random":
- countries.print(countries.random());
- break;
- case "capital":
- const [, ...args] = Deno.args;
- const capital = args.join(" ");
- const country = countries.findByCapital(capital);
- console.log(
- green(capital) + " is the capital of " + cyan(country.name.common)
- );
- break;
- default:
- countries.print(Deno.args.join(" "));
- break;
+ async run() {
+ const command = Deno.args[0];
+
+ await this.countries.sync();
+ switch (command) {
+ case undefined:
+ this.logger.help();
+ break;
+ case "help":
+ this.logger.help();
+ break;
+ case "sync":
+ await this.countries.sync({ force: true });
+ break;
+ case "random":
+ this.countries.print(this.countries.random());
+ break;
+ case "capital":
+ const [, ...args] = Deno.args;
+ const capital = args.join(" ");
+ this.countries.capitalOf(capital);
+ break;
+ case "raw":
+ this.logger.log(this.countries.find(Deno.args[1]));
+ break;
+ default:
+ this.countries.print(Deno.args.join(" "));
+ break;
+ }
}
}
diff --git a/src/countries.ts b/src/countries.ts
index 05d6a17..bf8ae84 100644
--- a/src/countries.ts
+++ b/src/countries.ts
@@ -1,31 +1,24 @@
-import * as nano from "https://deno.land/x/[email protected]/mod.ts";
import { environment } from "./environment/environment.ts";
-import { Country } from "./models/country.model.ts";
+import {
+ Country,
+ Region,
+ Currencies,
+ Languages,
+} from "./models/country.model.ts";
import { Cache } from "./util/cache.ts";
+import { Logger } from "./util/logger.ts";
export class Countries {
list: Country[] = [];
names: string[] = [];
query = environment.queries;
- constructor(private cache: Cache) {}
+ constructor(private cache: Cache, private logger: Logger) {}
- async sync(config?: { force: boolean }): Promise<Country[]> {
- const lastSynced = this.cache.readTxt("last-synced");
- const savedCountries = this.cache.readJson("countries") as
- | Country[]
- | undefined;
- const week = environment.syncInterval * 23 * 60 * 60 * 1000;
-
- const shouldSync =
- !savedCountries ||
- !lastSynced ||
- config?.force ||
- Date.now() - Number(lastSynced) > week;
-
- if (shouldSync) {
- console.log(
- nano.cyan("Syncronizing countries database..."),
+ public async sync(config?: { force: boolean }): Promise<Country[]> {
+ if (this.shouldSync() || config?.force) {
+ this.logger.alert(
+ "Synchronizing countries database...",
config?.force
? ""
: `\nThis will only happen every ${environment.syncInterval} days`
@@ -39,15 +32,21 @@ export class Countries {
this.cache.saveJson("countries", countries);
this.cache.saveTxt("last-synced", JSON.stringify(Date.now()));
- console.log("Synced successfully");
+ this.logger.success(
+ `Synced successfully: cache saved at ${environment.cacheDir}`
+ );
} else {
- this.list = savedCountries;
+ this.list = this.cache.readJson("countries") as Country[];
}
this.names = this.list.map((c) => c.name.common);
return this.list;
}
- find(name: string) {
+ getAll() {
+ return this.list;
+ }
+
+ public find(name: string) {
name = name.toLowerCase();
// Find exact match first, then fall back to fuzzy match
const country = this.list.find((c) => {
@@ -56,13 +55,12 @@ export class Countries {
});
if (!country) {
- throw Error(`Cannot find country named ${name}`);
+ throw `Cannot find country named ${name}`;
}
-
return country;
}
- findByCapital(capital: string) {
+ public findByCapital(capital: string) {
const country = this.list.find((c) => {
const capitalsLowercase = c.capital.map((capital) =>
capital.toLowerCase()
@@ -71,52 +69,65 @@ export class Countries {
});
if (!country) {
- throw Error(`Could not find the country of capital: ${capital}`);
+ throw `Could not find the country of capital: ${capital}`;
}
return country;
}
- print(name: string) {
- const country = this.find(name);
- let currencies = [];
- let iteration = 0;
- for (const currencyAbbr in country.currencies) {
- iteration++;
- const currency = country.currencies[currencyAbbr];
- currencies.push(
- `${iteration > 1 ? "\t\t " : ""}${currency.name} [${
- currency.symbol
- }](${currencyAbbr})\n`
- );
- }
+ capitalOf(capital: string) {
+ const country = this.findByCapital(capital);
+ this.logger.capitalOf(capital, country.name.common);
+ }
- let languages = [];
- for (const langAbbr in country.languages) {
- languages.push(country.languages[langAbbr]);
- }
+ public filterByRegion(region: Region) {
+ return this.list.filter((country) => country.region === region);
+ }
- // above code needs refactoring
-
- console.log(
- nano.cyan("\nCountry:\t"),
- country.name.common,
- country.flag,
- nano.green("\nLanguages:\t"),
- languages.join(" | "),
- nano.green("\nCapital:\t"),
- country.capital[0],
- nano.green("\nRegion:\t\t"),
- country.region,
- nano.green("\nPopulation:\t"),
- country.population.toLocaleString(),
- nano.green("\nCurrencies:\t"),
- ...currencies
- );
+ public print(name: string) {
+ const country = this.find(name);
+ const currencies = this.extractCurrencies(country.currencies);
+ const languages = this.extractLanguages(country.languages);
+
+ this.logger.logCountry({
+ country: country.name.common,
+ capital: country.capital[0],
+ flag: country.flag,
+ population: country.population,
+ region: country.region,
+ currencies,
+ languages,
+ });
}
- random(): string {
+ public random(): string {
const randomNum = Math.floor(Math.random() * this.names.length);
return this.names[randomNum];
}
+
+ private shouldSync() {
+ const lastSynced = this.cache.readTxt("last-synced");
+ const cacheExists = this.cache.exists("countries", ".json");
+ const week = environment.syncInterval * 23 * 60 * 60 * 1000;
+ const updateDue = Date.now() - Number(lastSynced) > week;
+
+ return !cacheExists || !lastSynced || updateDue;
+ }
+
+ private extractCurrencies(currencies: Currencies) {
+ const result = [];
+ for (const currencyAbbr in currencies) {
+ const currency = currencies[currencyAbbr];
+ result.push(`${currency.name} [${currency.symbol}](${currencyAbbr})`);
+ }
+ return result.join("\n\t\t ");
+ }
+
+ private extractLanguages(languages: Languages) {
+ const result = [];
+ for (const langAbbr in languages) {
+ result.push(languages[langAbbr]);
+ }
+ return result.join(" | ");
+ }
}
diff --git a/src/environment/environment.ts b/src/environment/environment.ts
index b3897ec..bc82b40 100644
--- a/src/environment/environment.ts
+++ b/src/environment/environment.ts
@@ -5,15 +5,5 @@ export const environment = {
baseUrl: "https://restcountries.com/v3.1/",
syncInterval: 7,
cacheDir: join(home_dir() as string, ".cache", "countryfetch"),
- queries:
- "all?fields=" +
- "name," +
- "capital," +
- "currencies," +
- "population," +
- "flag," +
- "region," +
- "continent," +
- "languages," +
- "region",
+ queries: `all?fields=name,capital,currencies,population,flag,region,continent,languages,region`,
};
diff --git a/src/models/FetchedCountry.model.ts b/src/models/FetchedCountry.model.ts
new file mode 100644
index 0000000..be636ff
--- /dev/null
+++ b/src/models/FetchedCountry.model.ts
@@ -0,0 +1,9 @@
+export interface FetchedCountry {
+ country: string;
+ flag: string;
+ languages: string;
+ capital: string;
+ region: string;
+ population: number;
+ currencies: string;
+}
diff --git a/src/models/country.model.ts b/src/models/country.model.ts
index 4765d5e..1a6b3ae 100644
--- a/src/models/country.model.ts
+++ b/src/models/country.model.ts
@@ -1,9 +1,20 @@
// For better currency types, this can be used later:
// https://github.com/freeall/currency-codes
// Same can be done for language abbreviations
-export type CurrencyAbbr = string;
-export type CurrencyInfo = { name: string; symbol: string };
-export type LangAbbr = string;
+type CurrencyAbbr = string;
+type CurrencyInfo = { name: string; symbol: string };
+type LangAbbr = string;
+
+export type Currencies = Record<CurrencyAbbr, CurrencyInfo>;
+export type Languages = Record<LangAbbr, string>;
+export enum Region {
+ Asia = "Asia",
+ Europe = "Europe",
+ Americas = "Americas",
+ Africa = "Africa",
+ Oceania = "Oceania",
+ Antarctic = "Antarctic",
+}
export interface Country {
name: {
@@ -11,10 +22,10 @@ export interface Country {
official: string;
// Need type for nativeName later
};
- currencies: Record<CurrencyAbbr, CurrencyInfo>;
+ currencies: Currencies;
capital: string[];
flag: string;
population: number;
- languages: Record<LangAbbr, string>;
- region: string;
+ languages: Languages;
+ region: Region;
}
diff --git a/src/util/cache.ts b/src/util/cache.ts
index 3a0c5d4..df52f89 100644
--- a/src/util/cache.ts
+++ b/src/util/cache.ts
@@ -1,5 +1,8 @@
import { join } from "https://deno.land/[email protected]/path/mod.ts";
-import { ensureDirSync } from "https://deno.land/[email protected]/fs/mod.ts";
+import {
+ ensureDirSync,
+ existsSync,
+} from "https://deno.land/[email protected]/fs/mod.ts";
import { environment } from "../environment/environment.ts";
export class Cache {
@@ -36,4 +39,8 @@ export class Cache {
return undefined;
}
}
+
+ public exists(name: string, extension?: string) {
+ return existsSync(join(this.path, `${name}${extension}`));
+ }
}
diff --git a/src/util/help.ts b/src/util/help.ts
deleted file mode 100644
index 80b7e57..0000000
--- a/src/util/help.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-export function help(): void {
- console.log(
- "\ncountryfetch\n",
- "\tFetch information about countries",
- "\n",
- "\nUSAGE\n",
- "\tcountryfetch <ARGS>",
- "\n",
- "\nARGS:\n",
- "\tsync",
- "\n\t\tSynchronize database. Stores countries' data in ~/.cache/conntryfetch/countries.json.",
- "\n",
- "\n\trandom",
- "\n\t\tPrint information about a random country.",
- "\n",
- "\n\t<country_name>",
- "\n\t\tPrint information about the specified country.",
- "\n",
- "\n",
- "\n\tcapital <capital>",
- "\n\t\tPrint country to which the specified capital belongs.",
- "\n",
- "\nEXAMPLE:\n",
- "\tcountryfetch germany",
- "\n\t\tPrints information about Germany",
- "\n"
- );
-}
diff --git a/src/util/logger.ts b/src/util/logger.ts
new file mode 100644
index 0000000..52965c8
--- /dev/null
+++ b/src/util/logger.ts
@@ -0,0 +1,77 @@
+import * as nano from "https://deno.land/x/[email protected]/mod.ts";
+import { FetchedCountry } from "../models/FetchedCountry.model.ts";
+
+export class Logger {
+ public log(...data: any) {
+ console.log(data);
+ }
+
+ public alert(...data: any) {
+ console.log(nano.yellow(data));
+ }
+
+ public success(...data: any) {
+ console.log(nano.green(data));
+ }
+
+ public error(...data: any) {
+ console.error(data);
+ }
+
+ public logCountry(country: FetchedCountry) {
+ console.log(
+ nano.cyan("\nCountry:\t"),
+ country.country,
+ country.flag,
+ nano.green("\nLanguages:\t"),
+ country.languages,
+ nano.green("\nCapital:\t"),
+ country.capital,
+ nano.green("\nRegion:\t\t"),
+ country.region,
+ nano.green("\nPopulation:\t"),
+ country.population.toLocaleString(),
+ nano.green("\nCurrencies:\t"),
+ country.currencies
+ );
+ }
+
+ public capitalOf(capital: string, country: string) {
+ console.log(
+ nano.green(capital) + " is the capital of " + nano.cyan(country)
+ );
+ }
+
+ public help(): void {
+ console.log(
+ "\ncountryfetch\n",
+ "\tFetch information about countries",
+ "\n",
+ "\nUSAGE\n",
+ "\tcountryfetch <ARGS>",
+ "\n",
+ "\nARGS:\n",
+ "\tsync",
+ "\n\t\tSynchronize database. Stores countries' data in ~/.cache/conntryfetch/countries.json.",
+ "\n",
+ "\n\trandom",
+ "\n\t\tPrint information about a random country.",
+ "\n",
+ "\n\t<country_name>",
+ "\n\t\tPrint information about the specified country.",
+ "\n",
+ "\n",
+ "\n\tcapital <capital>",
+ "\n\t\tPrint country to which the specified capital belongs.",
+ "\n",
+ "\n",
+ "\n\traw <country_name>",
+ "\n\t\tPrint country information in raw format as JavaScript object.",
+ "\n",
+ "\nEXAMPLE:\n",
+ "\tcountryfetch germany",
+ "\n\t\tPrints information about Germany.",
+ "\n"
+ );
+ }
+}