/** * Represents the base (non-localized) currency information. * This data is locale-independent and comes from ISO 4217 standards. */ interface CurrencyBase { /** ISO 4217 alphabetic currency code (e.g., "USD", "EUR") */ code: string; /** ISO 4217 numeric currency code (e.g., "840" for USD) */ numeric_code: string; /** Common currency symbol (e.g., "$", "€") */ symbol: string; /** Native symbol as used locally (may differ by locale) */ symbol_native: string; /** Number of decimal digits typically used (e.g., 2 for USD) */ decimal_digits: number; /** Rounding increment for this currency */ rounding: number; /** Conversion factor of subunit to unit (e.g., 100 for cents to dollars) */ subunit_to_unit: number; /** ISO 3166-1 alpha-2 country codes that use this currency */ countries: string[]; /** Native language name of the currency */ name_native: string; /** Native name for the currency's subunit (e.g., "cent") */ subunit_name_native: string; } /** * Represents localized currency information (translated names and labels). * This data varies by locale and provides user-facing text. */ interface CurrencyLocalized { /** Localized name of the currency (e.g., "US Dollar") */ name: string; /** Localized plural form (e.g., "US Dollars") */ name_plural: string; /** Localized subunit name (e.g., "cent") */ subunit_name: string; /** Localized plural subunit name (e.g., "cents") */ subunit_name_plural: string; } /** Combined structure of base and localized currency info. */ type Currency = CurrencyBase & CurrencyLocalized; /** ISO 4217 alphabetic code, e.g., "USD". */ type CurrencyCode = string; /** Map of currency code to its base data. */ type CurrencyBaseMap = Record; /** Map of currency code to its localized data. */ type CurrencyLocalizedMap = Record; /** Map of currency code to fully localized data. */ type CurrencyMap = Record; /** BCP-47 locale code, e.g., "en", "fr-CA". */ type LocaleCode = string; /** Mapping of locale codes to localized currency maps. */ type LocaleCurrencyMap = Record; /** ISO 3166-1 alpha-2 country code, e.g., "US". */ type CountryCode = string; /** Mapping of countries to one or more associated currency codes. */ type CountryCurrencyMap = Record; /** * Logger interface: optional, allows consumers to control logging. * By default the library will use `console`. * * NOTE: Library intentionally avoids internal logging to prevent * hidden I/O operations that callers might not expect. */ interface Logger { warn(...args: unknown[]): void; info?: (...args: unknown[]) => void; } /** * Properties for initializing a CurrencyLibrary instance. */ interface CurrencyLibraryProps { /** Map of localized currency data by locale (BCP-47 tags or language roots). */ locales: LocaleCurrencyMap; /** Fallback locale if requested locale is not available. Defaults to "en". */ fallbackLocale?: LocaleCode; /** Optional logger; defaults to console. */ logger?: Logger; } /** * CurrencyLibrary - Locale-aware currency utility * * Key Design Principles: * - No internal caching of derived results (e.g., merged locale maps) * - All expensive operations are computed on-demand * - Memory efficiency through O(1) lookup indexes built once * - Callers responsible for any long-lived caching needs * - Immutable internal state to prevent accidental mutation */ /** * CurrencyLibrary - Locale-Aware Currency Utility * * A robust, memory-efficient library for currency data lookup and localization. * * DESIGN PHILOSOPHY: * - No internal caching of expensive derived results (caller manages caching) * - O(1) lookup performance via pre-built indexes * - Immutable internal state to prevent accidental mutation * - Memory safety through prototype-pollution-safe objects * - Locale normalization and best-match fallback resolution * * PERFORMANCE CHARACTERISTICS: * - Constructor: O(n) where n = number of base currencies * - getMap(): O(m) where m = number of currencies in base dataset * - getCurrency(): O(1) via hash lookup * - All other methods: O(1) or O(k) where k is typically small * * MEMORY USAGE: * - Fixed: base datasets (~few KB) * - Fixed: locale data (provided by caller) * - Fixed: lookup indexes (~2x base currency count) * - Transient: method return values (garbage collected) * * USAGE EXAMPLE: * ```typescript * const library = new CurrencyLibrary({ * locales: { 'en': { USD: { name: 'US Dollar', ... } } }, * fallbackLocale: 'en' * }); * * // Caller manages caching if needed * const currencyMap = library.getMap('en-US'); * ``` */ declare class CurrencyLibrary { private readonly locales; private readonly fallbackLocale; private readonly baseMap; private readonly countryCurrencyMap; private readonly supportedLocaleRoots; private readonly logger; private readonly alphaIndex; private readonly numericIndex; /** * Constructs a CurrencyLibrary instance. * * PERFORMANCE: O(n) where n is number of base currencies + locales * MEMORY: Builds immutable indexes and normalizes locale data * * @param props - Configuration properties * @param props.locales - Mapping of locale tags to localized currency data * @param props.fallbackLocale - Fallback locale (default: "en") * @param props.logger - Optional logger instance * * @throws {Error} If locales is missing or invalid * @throws {Error} If fallback locale cannot be resolved * * @example * ```typescript * const lib = new CurrencyLibrary({ * locales: { * 'en': { USD: { name: 'US Dollar', name_plural: 'US dollars' } }, * 'fr': { USD: { name: 'dollar américain', name_plural: 'dollars américains' } } * }, * fallbackLocale: 'en' * }); * ``` */ constructor({ locales, fallbackLocale, logger }: CurrencyLibraryProps); /** * Normalizes a locale string to canonical BCP-47 form. * * PERFORMANCE: O(1) for typical inputs * * @param input - Raw locale string (e.g., "en_US", "en-us") * @returns Canonical locale tag (e.g., "en-US") * @throws {Error} If input is not a string * * @example * ```typescript * normalizeLocale("en_US"); // "en-US" * normalizeLocale("fr_CA"); // "fr-CA" * ``` */ private static normalizeLocale; /** * Extracts the root language subtag from a locale string. * * PERFORMANCE: O(1) * * @param input - Locale string (e.g., "en-US", "fr_CA") * @returns Root language code in lowercase (e.g., "en", "fr") * @throws {Error} If input is not a string * * @example * ```typescript * normalizeLocaleRoot("en-US"); // "en" * normalizeLocaleRoot("zh-Hans-CN"); // "zh" * ``` */ private static normalizeLocaleRoot; /** * Finds the best matching locale from supported roots. * * PERFORMANCE: O(1) - Set.has() is O(1) * * @param locale - Input locale to match * @param supported - Set of supported locale roots * @param defaultFallback - Ultimate fallback if no match found * @returns Best matching locale root * * @example * ```typescript * const supported = new Set(['en', 'fr', 'es']); * bestMatch('fr-CA', supported, 'en'); // 'fr' * bestMatch('de-DE', supported, 'en'); // 'en' * ``` */ private static bestMatch; /** * Normalizes currency code to canonical form. * * Handles both alphabetic (USD) and numeric (840) ISO 4217 codes. * Numeric codes are zero-padded to 3 digits for consistency. * * PERFORMANCE: O(1) * * @param input - Raw currency code (e.g., "usd", "36", "840") * @returns Normalized code (e.g., "USD", "036", "840") * @throws {Error} If input is invalid or empty * * @example * ```typescript * normalizeCurrencyCode("usd"); // "USD" * normalizeCurrencyCode("36"); // "036" * normalizeCurrencyCode("840"); // "840" * ``` */ private static normalizeCurrencyCode; /** * Normalizes country code to ISO 3166-1 alpha-2 uppercase. * * PERFORMANCE: O(1) * * @param input - Raw country code (e.g., "us", "Fr") * @returns Normalized country code (e.g., "US", "FR") * @throws {Error} If input is invalid * * @example * ```typescript * normalizeCountryCode("us"); // "US" * normalizeCountryCode("fr"); // "FR" * ``` */ private static normalizeCountryCode; /** * Finds the best available locale match for the given input. * * Lookup order: * 1. Exact canonical match (e.g., "fr-CA") * 2. Language root match (e.g., "fr") * 3. Configured fallback locale * * PERFORMANCE: O(1) - normalized lookup * * @param locale - Requested locale string * @returns Best available locale from provided data * * @example * ```typescript * // If only 'fr' is provided, but 'fr-CA' requested: * getLocaleBestMatch('fr-CA'); // 'fr' * * // If no match found: * getLocaleBestMatch('de-DE'); // 'en' (fallback) * ``` */ getLocaleBestMatch(locale: string): LocaleCode; /** * Retrieves complete currency map for a locale. * * IMPORTANT: This method performs O(n) work each call and returns a new object. * Callers should cache the result if repeated access is needed. * * PERFORMANCE: O(n) where n = number of base currencies * MEMORY: Returns new object each call - caller manages caching * * @param locale - Target locale for localization * @returns Map of currency codes to merged Currency objects * * @example * ```typescript * // First call - builds complete map * const map1 = lib.getMap('en'); * * // Second call - builds again (caller should cache if needed) * const map2 = lib.getMap('en'); * * // map1 !== map2 (new object each time) * ``` */ getMap(locale: string): CurrencyMap; /** * Retrieves currency list for a locale. * * PERFORMANCE: O(n) - calls getMap() internally * MEMORY: Returns new array each call * * @param locale - Target locale * @returns Array of Currency objects * * @example * ```typescript * const currencies = lib.getList('en'); * currencies.forEach(currency => { * console.log(currency.name, currency.symbol); * }); * ``` */ getList(locale: string): Currency[]; /** * Retrieves a single currency by code for the given locale. * * Accepts both alphabetic ("USD") and numeric ("840") codes. * Uses O(1) lookup via pre-built indexes. * * PERFORMANCE: O(1) - hash lookup * MEMORY: Returns new object each call * * @param locale - Target locale for localization * @param code - Currency code (alpha or numeric) * @returns Merged Currency object or undefined if not found * * @example * ```typescript * // Alphabetic code * const usd = lib.getCurrency('en', 'USD'); * * // Numeric code * const usdNumeric = lib.getCurrency('en', '840'); * * // Both return the same currency object * ``` */ getCurrency(locale: string, code: string): Currency | undefined; /** * Checks if a currency exists in the base dataset. * * PERFORMANCE: O(1) - hash lookup * * @param code - Currency code (alpha or numeric) * @returns True if currency exists * * @example * ```typescript * hasCurrency('USD'); // true * hasCurrency('840'); // true (USD numeric) * hasCurrency('XYZ'); // false * ``` */ hasCurrency(code: string): boolean; /** * Gets all currency codes used by a country. * * Returns alphabetic codes where possible, falls back to numeric. * * PERFORMANCE: O(k) where k = number of currencies for country (typically small) * * @param countryCode - ISO 3166-1 alpha-2 country code * @returns Array of currency codes * * @example * ```typescript * getCurrenciesByCountry('US'); // ['USD'] * getCurrenciesByCountry('CA'); // ['CAD'] * getCurrenciesByCountry('XX'); // [] (with warning) * ``` */ getCurrenciesByCountry(countryCode: string): CurrencyCode[]; /** * Gets localized currency data for all currencies used by a country. * * PERFORMANCE: O(k) where k = number of country currencies * MEMORY: Returns new array each call * * @param locale - Target locale for localization * @param countryCode - ISO country code * @returns Array of Currency objects (missing localizations are filtered out) * * @example * ```typescript * const usCurrencies = lib.getCountryCurrencyData('en', 'US'); * // Returns [ { code: 'USD', name: 'US Dollar', ... } ] * ``` */ getCountryCurrencyData(locale: string, countryCode: string): Currency[]; /** * Gets the primary currency code for a country. * * Returns the first currency in the country's currency list. * * PERFORMANCE: O(k) where k = number of country currencies * * @param countryCode - ISO country code * @returns Primary currency code or undefined * * @example * ```typescript * getPrimaryCurrencyByCountry('US'); // 'USD' * getPrimaryCurrencyByCountry('XX'); // undefined * ``` */ getPrimaryCurrencyByCountry(countryCode: string): CurrencyCode | undefined; /** * Checks if a country uses multiple currencies. * * PERFORMANCE: O(k) where k = number of country currencies * * @param countryCode - ISO country code * @returns True if country has multiple currencies * * @example * ```typescript * hasMultipleCurrencies('US'); // false * hasMultipleCurrencies('CU'); // true (Cuba uses CUC and CUP) * ``` */ hasMultipleCurrencies(countryCode: string): boolean; /** * Gets all supported country codes. * * PERFORMANCE: O(1) - cached country map keys * * @returns Array of country codes in uppercase * * @example * ```typescript * const countries = lib.getSupportedCountryCodes(); * // Returns ['US', 'CA', 'GB', 'FR', ...] * ``` */ getSupportedCountryCodes(): CountryCode[]; /** * Gets all countries that use a specific currency. * * Accepts both alphabetic and numeric currency codes. * * PERFORMANCE: O(m) where m = number of countries (linear scan) * * @param currencyCode - Currency code (alpha or numeric) * @returns Array of country codes that use this currency * * @example * ```typescript * getCountriesByCurrency('USD'); // ['US', 'EC', 'SV', ...] * getCountriesByCurrency('840'); // same result * ``` */ getCountriesByCurrency(currencyCode: string): CountryCode[]; /** * Gets all available currency codes from base dataset. * * PERFORMANCE: O(n) where n = number of base currencies * * @returns Array of alphabetic currency codes in uppercase * * @example * ```typescript * const codes = lib.getCurrencyCodes(); * // Returns ['USD', 'EUR', 'GBP', 'JPY', ...] * ``` */ getCurrencyCodes(): CurrencyCode[]; /** * Gets all available locale keys provided to constructor. * * PERFORMANCE: O(1) - cached locale keys * * @returns Array of canonical locale codes * * @example * ```typescript * const locales = lib.getAvailableLocales(); * // Returns ['en', 'en-US', 'fr', 'fr-CA', ...] * ``` */ getAvailableLocales(): LocaleCode[]; /** * Checks if a locale is supported by the library. * * Checks against supported-locales.json roots, not provided locale data. * * PERFORMANCE: O(1) - Set lookup * * @param locale - Locale to check * @returns True if locale root is supported * * @example * ```typescript * isLocaleSupported('en-US'); // true * isLocaleSupported('en'); // true * isLocaleSupported('xx'); // false * ``` */ isLocaleSupported(locale: string): boolean; } export { type CountryCode, type CountryCurrencyMap, type Currency, type CurrencyBase, type CurrencyBaseMap, type CurrencyCode, CurrencyLibrary, type CurrencyLibraryProps, type CurrencyLocalized, type CurrencyLocalizedMap, type CurrencyMap, type LocaleCode, type LocaleCurrencyMap, type Logger };