{"version":3,"sources":["../src/core/constants.ts","../src/core/format.ts","../src/core/clipboard.ts","../src/core/copyAmount.ts","../src/core/vat.ts","../src/core/conversion.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * UAE Dirham currency symbol constants.\n *\n * This package maps the Dirham glyph to the official Unicode codepoint U+20C3\n * (UAE DIRHAM SIGN) via a custom web font. The codepoint was accepted by the\n * Unicode Technical Committee for Unicode 18.0 (expected September 2026).\n *\n * Until system fonts ship native U+20C3 glyphs, the bundled web font provides\n * the rendering. When OS/font support lands, the web font becomes optional;\n * zero migration required.\n *\n * @module dirham\n * @see https://www.unicode.org/alloc/Pipeline.html\n */\n\n/** Unicode character for the Dirham symbol (U+20C3, requires Dirham web font until system fonts support it) */\nexport const DIRHAM_UNICODE = \"\\u20C3\";\n\n/** HTML entity for the Dirham symbol */\nexport const DIRHAM_HTML_ENTITY = \"&#x20C3;\";\n\n/** CSS content value for use in `::before` / `::after` pseudo-elements */\nexport const DIRHAM_CSS_CONTENT = \"\\\\20C3\";\n\n/** ISO 4217 currency code for UAE Dirham */\nexport const DIRHAM_CURRENCY_CODE = \"AED\";\n\n/** Arabic text representation of the Dirham symbol (د.إ) */\nexport const DIRHAM_SYMBOL_TEXT = \"د.إ\";\n\n/** The font family name used for the Dirham web font */\nexport const DIRHAM_FONT_FAMILY = \"Dirham\";\n\n/** CSS class name for the Dirham icon */\nexport const DIRHAM_CSS_CLASS = \"dirham-symbol\";\n\n/** Unicode codepoint as a number (0x20C3) */\nexport const DIRHAM_CODEPOINT = 0x20c3;\n\n// ── Font weight mapping ─────────────────────────────────────────────────\n\n/**\n * Supported visual weights for the Dirham symbol SVG component.\n *\n * Because the Dirham symbol is not yet in standard fonts (until Unicode 18.0),\n * weight simulation is applied via SVG stroke to match surrounding text weight,\n * similar to how $, €, £ adapt to their font's weight.\n */\nexport type DirhamWeight =\n\t| \"thin\"\n\t| \"extralight\"\n\t| \"light\"\n\t| \"regular\"\n\t| \"medium\"\n\t| \"semibold\"\n\t| \"bold\"\n\t| \"extrabold\"\n\t| \"black\";\n\n/**\n * Map from weight name to CSS `font-weight` numeric value.\n * Used for matching the symbol weight to surrounding text.\n */\nexport const DIRHAM_WEIGHT_MAP: Record<DirhamWeight, number> = {\n\tthin: 100,\n\textralight: 200,\n\tlight: 300,\n\tregular: 400,\n\tmedium: 500,\n\tsemibold: 600,\n\tbold: 700,\n\textrabold: 800,\n\tblack: 900,\n};\n\n/**\n * SVG stroke-width values that simulate font weight.\n * Applied with `paint-order: stroke` so stroke renders behind fill.\n */\nexport const DIRHAM_STROKE_MAP: Record<DirhamWeight, number> = {\n\tthin: 0,\n\textralight: 0,\n\tlight: 0,\n\tregular: 0,\n\tmedium: 8,\n\tsemibold: 16,\n\tbold: 24,\n\textrabold: 36,\n\tblack: 48,\n};\n","import {\n\tDIRHAM_CURRENCY_CODE,\n\tDIRHAM_SYMBOL_TEXT,\n\tDIRHAM_UNICODE,\n} from \"./constants\";\n\n// ─── Intl.NumberFormat cache ─────────────────────────────────────────────────\n// Constructing Intl.NumberFormat is expensive (~µs). Cache instances keyed on\n// \"locale:decimals\" so repeated calls (e.g., rendering a price list) reuse\n// the same formatter instead of allocating a new object each time.\nconst _fmtCache = new Map<string, Intl.NumberFormat>();\n\nfunction getFormatter(\n\tlocale: string,\n\tdecimals: number,\n\tnotation: \"standard\" | \"compact\" = \"standard\",\n): Intl.NumberFormat {\n\tconst key = `${locale}:${decimals}:${notation}`;\n\tlet fmt = _fmtCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(locale, {\n\t\t\tminimumFractionDigits: notation === \"compact\" ? 0 : decimals,\n\t\t\tmaximumFractionDigits: decimals,\n\t\t\t...(notation === \"compact\" && {\n\t\t\t\tnotation: \"compact\",\n\t\t\t\tcompactDisplay: \"short\",\n\t\t\t}),\n\t\t});\n\t\t_fmtCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\n/**\n * Options for formatting a Dirham amount.\n */\nexport interface FormatDirhamOptions {\n\t/**\n\t * Locale string for number formatting.\n\t * @default \"en-AE\"\n\t */\n\tlocale?: string;\n\n\t/**\n\t * Number of decimal places.\n\t * @default 2\n\t */\n\tdecimals?: number;\n\n\t/**\n\t * Whether to place the symbol before the amount.\n\t * When `undefined`, determined by locale:\n\t * - Arabic locales (ar-*): symbol after amount\n\t * - Other locales: symbol before amount\n\t */\n\tsymbolFirst?: boolean;\n\n\t/**\n\t * Use ISO currency code (AED) instead of the symbol.\n\t * @default false\n\t */\n\tuseCode?: boolean;\n\n\t/**\n\t * Separator between symbol and amount.\n\t * @default \" \" (non-breaking space)\n\t */\n\tseparator?: string;\n\n\t/**\n\t * Number notation style.\n\t * - `\"standard\"` — full digits (e.g. 1,500,000.00)\n\t * - `\"compact\"` — abbreviated (e.g. 1.5M)\n\t * @default \"standard\"\n\t */\n\tnotation?: \"standard\" | \"compact\";\n}\n\n/**\n * Format a number as a Dirham currency string.\n *\n * @example\n * ```ts\n * formatDirham(100);          // \"\\u20C3 100.00\"\n * formatDirham(1234.5);       // \"\\u20C3 1,234.50\"\n * formatDirham(100, { locale: \"ar-AE\" }); // \"100.00 \\u20C3\"\n * formatDirham(100, { useCode: true });   // \"AED 100.00\"\n * formatDirham(1500000, { notation: \"compact\" }); // \"\\u20C3 1.5M\"\n * ```\n */\nexport function formatDirham(\n\tamount: number,\n\toptions: FormatDirhamOptions = {},\n): string {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`formatDirham: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\n\tconst {\n\t\tlocale = \"en-AE\",\n\t\tdecimals = 2,\n\t\tuseCode = false,\n\t\tseparator = \"\\u00A0\", // non-breaking space\n\t\tnotation = \"standard\",\n\t} = options;\n\n\tconst symbol = useCode ? DIRHAM_CURRENCY_CODE : DIRHAM_UNICODE;\n\n\t// Determine symbol placement\n\tlet symbolFirst: boolean;\n\tif (options.symbolFirst !== undefined) {\n\t\tsymbolFirst = options.symbolFirst;\n\t} else {\n\t\t// Arabic locales place symbol after amount\n\t\tsymbolFirst = !locale.startsWith(\"ar\");\n\t}\n\n\t// Format the number (use cached formatter)\n\tconst formatted = getFormatter(locale, decimals, notation).format(amount);\n\n\treturn symbolFirst\n\t\t? `${symbol}${separator}${formatted}`\n\t\t: `${formatted}${separator}${symbol}`;\n}\n\n/**\n * Options for parsing a Dirham-formatted string.\n */\nexport interface ParseDirhamOptions {\n\t/**\n\t * Normalize Arabic-Indic digits (٠١٢٣٤٥٦٧٨٩ / U+0660–U+0669) to ASCII\n\t * digits before parsing. Enables round-tripping strings produced by\n\t * `formatDirham` with Arabic locales (e.g. `\"ar-AE\"`).\n\t * @default true\n\t */\n\tnormalizeArabicNumerals?: boolean;\n}\n\n/**\n * Parse a Dirham-formatted string back to a number.\n * Strips currency symbols, codes, and formatting characters.\n * By default also normalizes Arabic-Indic digits so strings produced by\n * `formatDirham({ locale: \"ar-AE\" })` round-trip correctly.\n *\n * @example\n * ```ts\n * parseDirham(\"\\u20C3 1,234.50\");                  // 1234.5\n * parseDirham(\"AED 100.00\");                        // 100\n * parseDirham(\"١٬٢٣٤٫٥٠ \\u20C3\");                  // 1234.5\n * parseDirham(\"١٠٠٫٠٠ \\u20C3\", { normalizeArabicNumerals: false }); // throws\n * ```\n */\nexport function parseDirham(\n\tvalue: string,\n\toptions: ParseDirhamOptions = {},\n): number {\n\tconst { normalizeArabicNumerals = true } = options;\n\n\tlet cleaned = value\n\t\t.replaceAll(DIRHAM_UNICODE, \"\")\n\t\t.replaceAll(DIRHAM_SYMBOL_TEXT, \"\")\n\t\t.replaceAll(DIRHAM_CURRENCY_CODE, \"\")\n\t\t.replace(/[,\\s\\u00A0\\u066C]/g, \"\") // ASCII comma, whitespace, NBSP, Arabic thousands sep\n\t\t.trim();\n\n\tif (normalizeArabicNumerals) {\n\t\t// Arabic-Indic digits U+0660–U+0669 → ASCII 0–9\n\t\tcleaned = cleaned.replace(/[\\u0660-\\u0669]/g, (d) =>\n\t\t\tString(d.charCodeAt(0) - 0x0660),\n\t\t);\n\t\t// Arabic decimal separator (U+066B) → '.'\n\t\tcleaned = cleaned.replace(/\\u066B/g, \".\");\n\t}\n\n\tconst result = Number.parseFloat(cleaned);\n\tif (Number.isNaN(result)) {\n\t\tthrow new Error(`Cannot parse \"${value}\" as a Dirham amount`);\n\t}\n\treturn result;\n}\n","import {\n\tDIRHAM_CSS_CONTENT,\n\tDIRHAM_HTML_ENTITY,\n\tDIRHAM_SYMBOL_TEXT,\n\tDIRHAM_UNICODE,\n} from \"./constants\";\n\n/**\n * Format of the Dirham symbol to copy.\n *\n * - `\"unicode\"` — the character itself (`\\u20C3`)\n * - `\"html\"` — HTML entity (`&#x20C3;`)\n * - `\"css\"` — CSS content value (`\\\\20C3`)\n * - `\"arabic\"` — Arabic text (د.إ)\n */\nexport type DirhamCopyFormat = \"unicode\" | \"html\" | \"css\" | \"arabic\";\n\nconst FORMAT_MAP: Record<DirhamCopyFormat, string> = {\n\tunicode: DIRHAM_UNICODE,\n\thtml: DIRHAM_HTML_ENTITY,\n\tcss: DIRHAM_CSS_CONTENT,\n\tarabic: DIRHAM_SYMBOL_TEXT,\n};\n\n/**\n * Copy the Dirham symbol to the clipboard in the specified format.\n *\n * @returns A promise that resolves when the text is on the clipboard.\n * @throws If the Clipboard API is unavailable (e.g. non-browser environment).\n *\n * @example\n * ```ts\n * import { copyDirhamSymbol } from \"dirham\";\n *\n * await copyDirhamSymbol();          // copies \"\\u20C3\"\n * await copyDirhamSymbol(\"html\");    // copies \"&#x20C3;\"\n * await copyDirhamSymbol(\"css\");     // copies \"\\\\20C3\"\n * ```\n */\nexport async function copyDirhamSymbol(\n\tformat: DirhamCopyFormat = \"unicode\",\n): Promise<void> {\n\tconst text = FORMAT_MAP[format];\n\tif (typeof navigator === \"undefined\" || !navigator.clipboard) {\n\t\tthrow new Error(\n\t\t\t\"copyDirhamSymbol: Clipboard API is not available in this environment\",\n\t\t);\n\t}\n\tawait navigator.clipboard.writeText(text);\n}\n","import { type FormatDirhamOptions, formatDirham } from \"./format\";\n\n/**\n * Copy a formatted Dirham amount to the clipboard.\n *\n * Combines `formatDirham()` with the Clipboard API so users can\n * paste a fully formatted price (e.g. \"ৃ 1,234.50\") into documents.\n *\n * @example\n * ```ts\n * import { copyDirhamAmount } from \"dirham\";\n *\n * await copyDirhamAmount(1234.5);                      // copies \"ৃ 1,234.50\"\n * await copyDirhamAmount(1234.5, { useCode: true });   // copies \"AED 1,234.50\"\n * await copyDirhamAmount(500, { locale: \"ar-AE\" });    // copies \"500.00 ৃ\"\n * ```\n *\n * @returns A promise that resolves when the text is on the clipboard.\n * @throws If the Clipboard API is unavailable or the amount is not finite.\n */\nexport async function copyDirhamAmount(\n\tamount: number,\n\toptions: FormatDirhamOptions = {},\n): Promise<void> {\n\tif (typeof navigator === \"undefined\" || !navigator.clipboard) {\n\t\tthrow new Error(\n\t\t\t\"copyDirhamAmount: Clipboard API is not available in this environment\",\n\t\t);\n\t}\n\tconst text = formatDirham(amount, options);\n\tawait navigator.clipboard.writeText(text);\n}\n","/**\n * UAE VAT rate (5%).\n * @see https://tax.gov.ae/en/taxes/vat.aspx\n */\nexport const UAE_VAT_RATE = 0.05;\n\n/**\n * Options for VAT calculation.\n */\nexport interface VATOptions {\n\t/**\n\t * VAT rate as a decimal (e.g. 0.05 for 5%).\n\t * @default 0.05 (UAE standard rate)\n\t */\n\trate?: number;\n\n\t/**\n\t * Number of decimal places to round the result to.\n\t * @default 2\n\t */\n\tdecimals?: number;\n}\n\n/**\n * Add VAT to an amount.\n *\n * @example\n * ```ts\n * addVAT(100);           // 105\n * addVAT(100, { rate: 0.1 }); // 110\n * addVAT(99.99);         // 104.99\n * ```\n */\nexport function addVAT(amount: number, options: VATOptions = {}): number {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`addVAT: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\tconst { rate = UAE_VAT_RATE, decimals = 2 } = options;\n\tconst factor = 10 ** decimals;\n\treturn Math.round(amount * (1 + rate) * factor) / factor;\n}\n\n/**\n * Remove VAT from a VAT-inclusive amount.\n * Returns the original pre-VAT amount.\n *\n * @example\n * ```ts\n * removeVAT(105);         // 100\n * removeVAT(110, { rate: 0.1 }); // 100\n * ```\n */\nexport function removeVAT(amount: number, options: VATOptions = {}): number {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`removeVAT: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\tconst { rate = UAE_VAT_RATE, decimals = 2 } = options;\n\tconst factor = 10 ** decimals;\n\treturn Math.round((amount / (1 + rate)) * factor) / factor;\n}\n\n/**\n * Get the VAT amount from a pre-VAT price.\n *\n * @example\n * ```ts\n * getVAT(100);  // 5\n * getVAT(200);  // 10\n * ```\n */\nexport function getVAT(amount: number, options: VATOptions = {}): number {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`getVAT: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\tconst { rate = UAE_VAT_RATE, decimals = 2 } = options;\n\tconst factor = 10 ** decimals;\n\treturn Math.round(amount * rate * factor) / factor;\n}\n","/**\n * Common exchange rates cache entry.\n */\ninterface CachedRates {\n\ttimestamp: number;\n\trates: Record<string, number>;\n}\n\nlet _cache: CachedRates | null = null;\n\n/** Default TTL for cached rates: 1 hour */\nconst CACHE_TTL = 60 * 60 * 1000;\n\n/**\n * Options for currency conversion.\n */\nexport interface ConvertOptions {\n\t/**\n\t * Number of decimal places for the result.\n\t * @default 2\n\t */\n\tdecimals?: number;\n\n\t/**\n\t * Custom exchange rate (AED per 1 unit of target currency).\n\t * When provided, skips network fetch.\n\t */\n\trate?: number;\n}\n\n/**\n * Fetch exchange rates from the Central Bank of UAE open API.\n * Results are cached in memory for 1 hour.\n *\n * Uses the free, no-auth-required exchangerate.host API as a fallback-safe source.\n *\n * @returns Map of currency codes to their AED exchange rates.\n */\nexport async function fetchExchangeRates(): Promise<Record<string, number>> {\n\tif (_cache && Date.now() - _cache.timestamp < CACHE_TTL) {\n\t\treturn _cache.rates;\n\t}\n\n\tconst res = await fetch(\"https://open.er-api.com/v6/latest/AED\");\n\n\tif (!res.ok) {\n\t\tthrow new Error(\n\t\t\t`Failed to fetch exchange rates: ${res.status} ${res.statusText}`,\n\t\t);\n\t}\n\n\tconst data = (await res.json()) as { rates?: Record<string, number> };\n\n\tif (!data.rates) {\n\t\tthrow new Error(\"Invalid exchange rate response: missing rates\");\n\t}\n\n\t_cache = { timestamp: Date.now(), rates: data.rates };\n\treturn data.rates;\n}\n\n/**\n * Clear the in-memory exchange rate cache.\n * Useful for testing or forcing a refresh.\n */\nexport function clearRateCache(): void {\n\t_cache = null;\n}\n\n/**\n * Convert an AED amount to another currency.\n *\n * @example\n * ```ts\n * const usd = await convertFromAED(100, \"USD\");\n * const eur = await convertFromAED(100, \"EUR\", { decimals: 4 });\n * const manual = await convertFromAED(100, \"USD\", { rate: 0.2723 });\n * ```\n */\nexport async function convertFromAED(\n\tamount: number,\n\tcurrency: string,\n\toptions: ConvertOptions = {},\n): Promise<number> {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`convertFromAED: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\tconst { decimals = 2 } = options;\n\tconst code = currency.toUpperCase();\n\n\tlet rate: number;\n\tif (options.rate !== undefined) {\n\t\trate = options.rate;\n\t} else {\n\t\tconst rates = await fetchExchangeRates();\n\t\tconst r = rates[code];\n\t\tif (r === undefined) {\n\t\t\tthrow new Error(`Unknown currency code: ${code}`);\n\t\t}\n\t\trate = r;\n\t}\n\n\tconst factor = 10 ** decimals;\n\treturn Math.round(amount * rate * factor) / factor;\n}\n\n/**\n * Convert a foreign currency amount to AED.\n *\n * @example\n * ```ts\n * const aed = await convertToAED(27.23, \"USD\");\n * ```\n */\nexport async function convertToAED(\n\tamount: number,\n\tcurrency: string,\n\toptions: ConvertOptions = {},\n): Promise<number> {\n\tif (!Number.isFinite(amount)) {\n\t\tthrow new RangeError(\n\t\t\t`convertToAED: amount must be a finite number, got ${amount}`,\n\t\t);\n\t}\n\tconst { decimals = 2 } = options;\n\tconst code = currency.toUpperCase();\n\n\tlet rate: number;\n\tif (options.rate !== undefined) {\n\t\trate = options.rate;\n\t} else {\n\t\tconst rates = await fetchExchangeRates();\n\t\tconst r = rates[code];\n\t\tif (r === undefined) {\n\t\t\tthrow new Error(`Unknown currency code: ${code}`);\n\t\t}\n\t\trate = r;\n\t}\n\n\tif (rate === 0) {\n\t\tthrow new Error(`Exchange rate for ${code} is zero`);\n\t}\n\n\tconst factor = 10 ** decimals;\n\treturn Math.round((amount / rate) * factor) / factor;\n}\n"]}