diff --git a/data/countries-gr.json b/data/countries-el.json similarity index 99% rename from data/countries-gr.json rename to data/countries-el.json index 924dbf2..03e7a4f 100644 --- a/data/countries-gr.json +++ b/data/countries-el.json @@ -2,7 +2,7 @@ { "id": "004", "name": "Αφγανιστάν", - "complete name": "Αφγανιστάν", + "completeName": "Αφγανιστάν", "officialName": "Η Ισλαμική Δημοκρατία του Αφγανιστάν", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -14,7 +14,7 @@ { "id": "008", "name": "Αλβανία", - "complete name": "Αλβανία", + "completeName": "Αλβανία", "officialName": "Η Δημοκρατία της Αλβανίας", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -26,7 +26,7 @@ { "id": "010", "name": "Ανταρκτική", - "complete name": "Ανταρκτική", + "completeName": "Ανταρκτική", "officialName": "Ανταρκτική", "sovereignty": "Συνθήκη της Ανταρκτικής", "iso31661": { @@ -38,7 +38,7 @@ { "id": "012", "name": "Αλγερία", - "complete name": "Αλγερία", + "completeName": "Αλγερία", "officialName": "Η Λαϊκή Δημοκρατία της Αλγερίας", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -50,7 +50,7 @@ { "id": "016", "name": "Αμερικανική Σαμόα", - "complete name": "Αμερικανική Σαμόα", + "completeName": "Αμερικανική Σαμόα", "officialName": "Η Επικράτεια της Αμερικανικής Σαμόα", "sovereignty": "Ηνωμένες Πολιτείες", "iso31661": { @@ -62,7 +62,7 @@ { "id": "020", "name": "Ανδόρα", - "complete name": "Ανδόρα", + "completeName": "Ανδόρα", "officialName": "Το Πριγκιπάτο της Ανδόρας", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -74,7 +74,7 @@ { "id": "024", "name": "Ανγκόλα", - "complete name": "Ανγκόλα", + "completeName": "Ανγκόλα", "officialName": "Η Δημοκρατία της Ανγκόλα", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -86,7 +86,7 @@ { "id": "028", "name": "Αντίγκουα και Μπαρμπούντα", - "complete name": "Αντίγκουα και Μπαρμπούντα", + "completeName": "Αντίγκουα και Μπαρμπούντα", "officialName": "Αντίγκουα και Μπαρμπούντα", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -98,7 +98,7 @@ { "id": "031", "name": "Αζερμπαϊτζάν", - "complete name": "Αζερμπαϊτζάν", + "completeName": "Αζερμπαϊτζάν", "officialName": "Η Δημοκρατία του Αζερμπαϊτζάν", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -110,7 +110,7 @@ { "id": "032", "name": "Αργεντινή", - "complete name": "Αργεντινή", + "completeName": "Αργεντινή", "officialName": "Η Αργεντινή Δημοκρατία", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -122,7 +122,7 @@ { "id": "036", "name": "Αυστραλία", - "complete name": "Αυστραλία", + "completeName": "Αυστραλία", "officialName": "Η Κοινοπολιτεία της Αυστραλίας", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { @@ -134,7 +134,7 @@ { "id": "040", "name": "Αυστρία", - "complete name": "Αυστρία", + "completeName": "Αυστρία", "officialName": "Η Δημοκρατία της Αυστρίας", "sovereignty": "Μέλος του ΟΗΕ", "iso31661": { diff --git a/data/countries-en.json b/data/countries-en.json index c1868d7..e6565df 100644 --- a/data/countries-en.json +++ b/data/countries-en.json @@ -2,7 +2,7 @@ { "id": "004", "name": "Afghanistan", - "complete name": "Afghanistan", + "completeName": "Afghanistan", "officialName": "The Islamic Republic of Afghanistan", "sovereignty": "UN member", "iso31661": { @@ -14,7 +14,7 @@ { "id": "008", "name": "Albania", - "complete name": "Albania", + "completeName": "Albania", "officialName": "The Republic of Albania", "sovereignty": "UN member", "iso31661": { @@ -26,7 +26,7 @@ { "id": "010", "name": "Antarctica", - "complete name": "Antarctica", + "completeName": "Antarctica", "officialName": "Antarctica", "sovereignty": "Antarctic Treaty", "iso31661": { @@ -38,7 +38,7 @@ { "id": "012", "name": "Algeria", - "complete name": "Algeria", + "completeName": "Algeria", "officialName": "The People's Democratic Republic of Algeria", "sovereignty": "UN member", "iso31661": { @@ -50,7 +50,7 @@ { "id": "016", "name": "American Samoa", - "complete name": "American Samoa", + "completeName": "American Samoa", "officialName": "American Samoa", "sovereignty": "United States", "iso31661": { @@ -62,7 +62,7 @@ { "id": "020", "name": "Andorra", - "complete name": "Andorra", + "completeName": "Andorra", "officialName": "The Principality of Andorra", "sovereignty": "UN member", "iso31661": { @@ -74,7 +74,7 @@ { "id": "024", "name": "Angola", - "complete name": "Angola", + "completeName": "Angola", "officialName": "The Republic of Angola", "sovereignty": "UN member", "iso31661": { @@ -86,7 +86,7 @@ { "id": "028", "name": "Antigua and Barbuda", - "complete name": "Antigua and Barbuda", + "completeName": "Antigua and Barbuda", "officialName": "Antigua and Barbuda", "sovereignty": "UN member", "iso31661": { @@ -98,7 +98,7 @@ { "id": "031", "name": "Azerbaijan", - "complete name": "Azerbaijan", + "completeName": "Azerbaijan", "officialName": "The Republic of Azerbaijan", "sovereignty": "UN member", "iso31661": { @@ -110,7 +110,7 @@ { "id": "032", "name": "Argentina", - "complete name": "Argentina", + "completeName": "Argentina", "officialName": "The Argentine Republic", "sovereignty": "UN member", "iso31661": { @@ -122,7 +122,7 @@ { "id": "036", "name": "Australia", - "complete name": "Australia", + "completeName": "Australia", "officialName": "The Commonwealth of Australia", "sovereignty": "UN member", "iso31661": { @@ -134,7 +134,7 @@ { "id": "040", "name": "Austria", - "complete name": "Austria", + "completeName": "Austria", "officialName": "The Republic of Austria", "sovereignty": "UN member", "iso31661": { diff --git a/package-lock.json b/package-lock.json index 72c6f5a..92dcd2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tsevdos/el-utils", - "version": "0.6.0", + "version": "0.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tsevdos/el-utils", - "version": "0.6.0", + "version": "0.7.0", "license": "MIT", "devDependencies": { "@changesets/changelog-github": "^0.5.0", diff --git a/src/__tests__/geoUtils.test.ts b/src/__tests__/geoUtils.test.ts index a3f9796..2791350 100644 --- a/src/__tests__/geoUtils.test.ts +++ b/src/__tests__/geoUtils.test.ts @@ -9,6 +9,8 @@ import prefecturesEl from "../../data/prefectures-el.json"; import prefecturesEn from "../../data/prefectures-en.json"; import taxOfficesEl from "../../data/taxOffices-el.json"; import taxOfficesEn from "../../data/taxOffices-en.json"; +import countriesEl from "../../data/countries-el.json"; +import countriesEn from "../../data/countries-en.json"; import { MOUNT_ATHOS_PREFECTURE_ID, MOUNT_ATHOS_REGION_ID, @@ -35,6 +37,9 @@ import { getTaxOfficesByUnitId, searchCityByName, searchTaxOffice, + getCountries, + searchCountryByName, + getCountry, } from "../geoUtils"; const administrativeRegions = { el: administrativeRegionsEl, en: administrativeRegionsEn }; @@ -45,11 +50,13 @@ const administrativeRegionsWithoutMountAthos = { const cities = { el: citiesEl, en: citiesEn }; const geographicRegions = { el: geographicRegionsEl, en: geographicRegionsEn }; const prefectures = { el: prefecturesEl, en: prefecturesEn }; -export const prefecturesWithoutMountAthos = { +const prefecturesWithoutMountAthos = { el: prefectures.el.filter(({ id }) => id !== MOUNT_ATHOS_PREFECTURE_ID), en: prefectures.en.filter(({ id }) => id !== MOUNT_ATHOS_PREFECTURE_ID), }; +const allCountries = { el: countriesEl, en: countriesEn } as const; + describe("getAdministrativeRegions", () => { it("correctly returns data with default values (in greek language)", () => { const expectedData = administrativeRegionsWithoutMountAthos.el; @@ -1481,3 +1488,158 @@ describe("searchTaxOffice", () => { ]); }); }); + +describe("getCountries", () => { + it("correctly returns data with default values (in greek language)", () => { + const expectedData = allCountries.el; + + expect(getCountries()).toEqual(expectedData); + expect(getCountries({ locale: "el" })).toEqual(expectedData); + expect(getCountries().length).toEqual(249); + }); + + it("correctly returns data (in english language)", () => { + const expectedData = allCountries.en; + + expect(getCountries({ locale: "en" })).toEqual(expectedData); + expect(getCountries({ locale: "en" }).length).toEqual(249); + }); +}); + +describe("searchCountryByName", () => { + it("given the search term 'Ελλάδα', returns Greece (in greek language)", () => { + const greeceIndex = allCountries.el.findIndex(({ name }) => name === "Ελλάδα"); + + expect(searchCountryByName({ searchTerm: "Ελλάδα" })).toEqual([allCountries.el[greeceIndex]]); + expect(searchCountryByName({ searchTerm: "Ελλάδα" })?.length).toBe(1); + }); + + it("given the search term 'ελλα', returns Greece (in greek language)", () => { + const greeceIndex = allCountries.el.findIndex(({ name }) => name === "Ελλάδα"); + + expect(searchCountryByName({ searchTerm: "ελλα", locale: "el" })).toEqual([allCountries.el[greeceIndex]]); + expect(searchCountryByName({ searchTerm: "ελλα", locale: "el" })?.length).toBe(1); + }); + + it("given the search term 'ηνωμε', returns all (7) the correct countries (in greek language)", () => { + const expectedCountries = [ + { + id: "484", + name: "Μεξικό", + completeName: "Μεξικό", + officialName: "Οι Ηνωμένες Μεξικανικές Πολιτείες", + sovereignty: "Μέλος του ΟΗΕ", + iso31661: { A2: "MX", A3: "MEX" }, + tld: ".mx", + }, + { + id: "581", + name: "Απομακρυσμένες Νησίδες των Ηνωμένων Πολιτειών", + completeName: "Απομακρυσμένες Νησίδες των Ηνωμένων Πολιτειών", + officialName: + "Νήσος Μπέικερ, Νήσος Χάουλαντ, Νήσος Τζάρβις, Ατόλη Τζόνστον, Ύφαλος Κίνγκμαν, Ατόλη Μίντγουεϊ, Νήσος Ναβάσσα, Ατόλη Παλμίρα, και Νήσος Γουέικ", + sovereignty: "Ηνωμένες Πολιτείες", + iso31661: { A2: "UM", A3: "UMI" }, + tld: "[af]", + }, + { + id: "784", + name: "Ηνωμένα Αραβικά Εμιράτα", + completeName: "Τα Ηνωμένα Αραβικά Εμιράτα", + officialName: "Τα Ηνωμένα Αραβικά Εμιράτα", + sovereignty: "Μέλος του ΟΗΕ", + iso31661: { A2: "AE", A3: "ARE" }, + tld: ".ae", + }, + { + id: "826", + name: "Ηνωμένο Βασίλειο", + completeName: "Το Ηνωμένο Βασίλειο της Μεγάλης Βρετανίας και Βόρειας Ιρλανδίας", + officialName: "Το Ηνωμένο Βασίλειο της Μεγάλης Βρετανίας και Βόρειας Ιρλανδίας", + sovereignty: "Μέλος του ΟΗΕ", + iso31661: { A2: "GB", A3: "GBR" }, + tld: ".gb", + }, + { + id: "834", + name: "Τανζανία", + completeName: "Η Ηνωμένη Δημοκρατία της Τανζανίας", + officialName: "Η Ηνωμένη Δημοκρατία της Τανζανίας", + sovereignty: "Μέλος του ΟΗΕ", + iso31661: { A2: "TZ", A3: "TZA" }, + tld: ".tz", + }, + { + id: "840", + name: "Ηνωμένες Πολιτείες της Αμερικής", + completeName: "Οι Ηνωμένες Πολιτείες της Αμερικής", + officialName: "Οι Ηνωμένες Πολιτείες της Αμερικής", + sovereignty: "Μέλος του ΟΗΕ", + iso31661: { A2: "US", A3: "USA" }, + tld: ".us", + }, + { + id: "850", + name: "Παρθένοι Νήσοι", + completeName: "Παρθένοι Νήσοι (ΗΠΑ)", + officialName: "Οι Παρθένοι Νήσοι των Ηνωμένων Πολιτειών", + sovereignty: "Ηνωμένες Πολιτείες", + iso31661: { A2: "VI", A3: "VIR" }, + tld: ".vi", + }, + ]; + + expect(searchCountryByName({ searchTerm: "ηνωμε" })).toEqual(expectedCountries); + expect(searchCountryByName({ searchTerm: "ηνωμε" })?.length).toBe(7); + }); +}); + +describe("getCountry", () => { + it("correctly returns a country with specific id (in greek language)", () => { + expect(getCountry({ locale: "el", type: "id", value: "300" })).toEqual(allCountries.el[87]); + expect(getCountry({ locale: "el", type: "id", value: "840" })).toEqual(allCountries.el[239]); + expect(getCountry({ locale: "el", type: "id", value: "826" })).toEqual(allCountries.el[234]); + }); + + it("correctly returns a country with specific iso31661 A2 (in greek language)", () => { + expect(getCountry({ locale: "el", type: "iso31661-a2", value: "GR" })).toEqual(allCountries.el[87]); + expect(getCountry({ locale: "el", type: "iso31661-a2", value: "US" })).toEqual(allCountries.el[239]); + expect(getCountry({ locale: "el", type: "iso31661-a2", value: "GB" })).toEqual(allCountries.el[234]); + }); + + it("correctly returns a country with specific iso31661 A2 (in greek language)", () => { + expect(getCountry({ locale: "el", type: "iso31661-a3", value: "GRC" })).toEqual(allCountries.el[87]); + expect(getCountry({ locale: "el", type: "iso31661-a3", value: "USA" })).toEqual(allCountries.el[239]); + expect(getCountry({ locale: "el", type: "iso31661-a3", value: "GBR" })).toEqual(allCountries.el[234]); + }); + + it("correctly returns a country with top level domain (in greek language)", () => { + expect(getCountry({ locale: "el", type: "tld", value: ".gr" })).toEqual(allCountries.el[87]); + expect(getCountry({ locale: "el", type: "tld", value: ".us" })).toEqual(allCountries.el[239]); + expect(getCountry({ locale: "el", type: "tld", value: ".gb" })).toEqual(allCountries.el[234]); + }); + + it("correctly returns a country with specific id (in english language)", () => { + expect(getCountry({ locale: "en", type: "id", value: "300" })).toEqual(allCountries.en[87]); + expect(getCountry({ locale: "en", type: "id", value: "840" })).toEqual(allCountries.en[239]); + expect(getCountry({ locale: "en", type: "id", value: "826" })).toEqual(allCountries.en[234]); + }); + + it("correctly returns a country with specific iso31661 A2 (in english language)", () => { + expect(getCountry({ locale: "en", type: "iso31661-a2", value: "GR" })).toEqual(allCountries.en[87]); + expect(getCountry({ locale: "en", type: "iso31661-a2", value: "US" })).toEqual(allCountries.en[239]); + expect(getCountry({ locale: "en", type: "iso31661-a2", value: "GB" })).toEqual(allCountries.en[234]); + }); + + it("correctly returns a country with specific iso31661 A3 (in english language)", () => { + expect(getCountry({ locale: "en", type: "iso31661-a3", value: "GRC" })).toEqual(allCountries.en[87]); + expect(getCountry({ locale: "en", type: "iso31661-a3", value: "USA" })).toEqual(allCountries.en[239]); + expect(getCountry({ locale: "en", type: "iso31661-a3", value: "GBR" })).toEqual(allCountries.en[234]); + }); + + it("correctly returns a country with top level domain (in english language)", () => { + expect(getCountry({ locale: "en", type: "tld", value: ".gr" })).toEqual(allCountries.en[87]); + expect(getCountry({ locale: "en", type: "tld", value: ".us" })).toEqual(allCountries.en[239]); + expect(getCountry({ locale: "en", type: "tld", value: ".gb" })).toEqual(allCountries.en[234]); + }); +}); diff --git a/src/geoUtils.ts b/src/geoUtils.ts index 34a7265..f831941 100644 --- a/src/geoUtils.ts +++ b/src/geoUtils.ts @@ -10,8 +10,11 @@ import prefecturesEn from "../data/prefectures-en.json"; import taxOfficesEl from "../data/taxOffices-el.json"; import taxOfficesEn from "../data/taxOffices-en.json"; import { convertsGreekTextToComparableUpperCase } from "./languageUtils"; +import countriesEl from "../data/countries-el.json"; +import countriesEn from "../data/countries-en.json"; import { City, + Country, GeographicRegion, Municipality, Prefecture, @@ -54,6 +57,8 @@ const prefecturesWithoutMountAthos = { const allTaxOffices = { el: taxOfficesEl, en: taxOfficesEn } as const; +const allCountries = { el: countriesEl, en: countriesEn } as const; + type Locale = "el" | "en"; type AdministrativeRegionsOptions = { @@ -256,7 +261,7 @@ export function getCityById(options: CityByIdOptions): City | undefined { return citiesData.find((city) => city.id === id); } -export type FindByCityRelationsOptions = { +type CityAdministrativeDivisionOptions = { cityId: number; locale: Locale; entity: "region" | "unit" | "prefecture"; @@ -265,7 +270,7 @@ export type FindByCityRelationsOptions = { /** * Retrieves related administrative entities for a given city based on the provided options. * - * @param {FindByCityRelationsOptions} options - The options for finding city relations. + * @param {CityAdministrativeDivisionOptions} options - The options for finding city relations. * @param {number} options.id - The ID of the city to retrieve relations for. * @param {string} [options.locale="el"] - The locale to use when retrieving related entities. Defaults to "el". * @param {("region"|"unit"|"municipality"|"prefecture")} options.entity - The type of related entity to retrieve. @@ -273,7 +278,7 @@ export type FindByCityRelationsOptions = { * @returns {Region|Unit|RegionWithoutUnits|Prefecture|undefined} - The related entity based on the specified type, or `undefined` if not found. */ export function getCityAdministrativeDivision( - options: FindByCityRelationsOptions, + options: CityAdministrativeDivisionOptions, ): Region | RegionWithoutUnits | Unit | UnitWithoutMunicipalities | Prefecture | undefined { const { cityId, locale = "el", entity } = options; const city = getCityById({ id: cityId, locale }); @@ -528,10 +533,96 @@ type TaxOfficeOptionsByTerm = { searchTerm: string } & TaxOfficeOptions; */ export function searchTaxOffice(options: TaxOfficeOptionsByTerm): TaxOffice[] { const { searchTerm, locale = "el" } = options; + if (searchTerm.trim() === "") return []; + const normalizedTerm = convertsGreekTextToComparableUpperCase(searchTerm); return allTaxOffices[locale].filter(({ name }) => convertsGreekTextToComparableUpperCase(name).includes(normalizedTerm), ); } + +type CountriesOptions = { + locale?: Locale; +}; + +/** + * This function returns all the countries based on the provided options. + * + * @param {CountriesOptions} [options={}] - The options for the countries. + * @param {string} [options.locale="el"] - The locale to use. Default is "el". + * + * @returns {Country[]} The countries that match the given options, or all countries if no options are provided. + */ +export function getCountries({ locale = "el" }: CountriesOptions = {}): Country[] { + return allCountries[locale]; +} + +type SearchCountryByNameOptions = { + locale?: Locale; + searchTerm: string; +}; + +/** + * This function searches for countries by name based on the provided options. + * + * @param {SearchCountryByNameOptions} options - The options for searching countries by name. + * @param {string} [options.locale="el"] - The locale to use. Default is "el". + * @param {string} options.searchTerm - The term to search for in country names. + * + * @returns {Country[] | null} The countries that match the search term, or null if no matches are found. + */ +export function searchCountryByName({ locale = "el", searchTerm }: SearchCountryByNameOptions): Country[] | null { + const countries = getCountries({ locale }); + let countriesByName: Country[] = []; + + if (locale === "el") { + countriesByName = countries.filter(({ name, completeName, officialName }) => { + return ( + convertsGreekTextToComparableUpperCase(name).includes(convertsGreekTextToComparableUpperCase(searchTerm)) || + convertsGreekTextToComparableUpperCase(completeName).includes( + convertsGreekTextToComparableUpperCase(searchTerm), + ) || + convertsGreekTextToComparableUpperCase(officialName).includes( + convertsGreekTextToComparableUpperCase(searchTerm), + ) + ); + }); + } + + if (locale === "en") { + countriesByName = countries.filter(({ name, completeName, officialName }) => { + return ( + name.toUpperCase().includes(searchTerm.toUpperCase()) || + completeName.toUpperCase().includes(searchTerm.toUpperCase()) || + officialName.toUpperCase().includes(searchTerm.toUpperCase()) + ); + }); + } + + return countriesByName?.length ? countriesByName : null; +} + +type GetCountryOptions = { + locale?: Locale; + type: "id" | "iso31661-a2" | "iso31661-a3" | "tld"; + value: string; +}; + +export function getCountry({ locale = "el", type = "id", value = "" }: GetCountryOptions): Country | null { + const countries = getCountries({ locale }); + + switch (type) { + case "id": + return countries.find((country) => country.id === value) ?? null; + case "iso31661-a2": + return countries.find((country) => country.iso31661.A2 === value) ?? null; + case "iso31661-a3": + return countries.find((country) => country.iso31661.A3 === value) ?? null; + case "tld": + return countries.find((country) => country.tld === value) ?? null; + default: + return null; + } +} diff --git a/src/types.ts b/src/types.ts index 19b3404..dcf82a3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -80,3 +80,16 @@ export type City = { prefectureId: number; }; }; + +export type Country = { + id: string; + name: string; + completeName: string; + officialName: string; + sovereignty: string; + iso31661: { + A2: string; + A3: string; + }; + tld: string; +};