diff options
| author | Fridon <[email protected]> | 2022-06-23 00:01:12 +0400 |
|---|---|---|
| committer | Fridon <[email protected]> | 2022-06-23 00:01:12 +0400 |
| commit | 7d72153d68ea4c682266f0301aa45b4e3a9e45a9 (patch) | |
| tree | ba2b4b8937d0c7785a468fae18880762a5e6b484 /src | |
| parent | be829dad070205555c514ff497fcf2eae355a6e2 (diff) | |
| download | countryfetch-7d72153d68ea4c682266f0301aa45b4e3a9e45a9.tar.xz countryfetch-7d72153d68ea4c682266f0301aa45b4e3a9e45a9.zip | |
big refactor + raw option
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.ts | 67 | ||||
| -rw-r--r-- | src/countries.ts | 133 | ||||
| -rw-r--r-- | src/environment/environment.ts | 12 | ||||
| -rw-r--r-- | src/models/FetchedCountry.model.ts | 9 | ||||
| -rw-r--r-- | src/models/country.model.ts | 23 | ||||
| -rw-r--r-- | src/util/cache.ts | 9 | ||||
| -rw-r--r-- | src/util/help.ts | 28 | ||||
| -rw-r--r-- | src/util/logger.ts | 77 |
8 files changed, 220 insertions, 138 deletions
@@ -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" + ); + } +} |
