{"version":3,"names":["unnecessaryDecimal","RegExp","trailingZeros","BigDecimal","constructor","input","integers","decimals","expandExponentialNumberString","split","concat","this","value","BigInt","padEnd","DECIMALS","slice","ROUNDED","isNegative","charAt","getIntegersAndDecimals","s","toString","replace","padStart","length","formatToParts","formatter","parts","numberFormatter","unshift","type","minusSign","push","decimal","forEach","char","format","integersFormatted","decimalsFormatted","map","Number","join","add","n","fromBigInt","subtract","multiply","_divRound","SHIFT","divide","repeat","dividend","divisor","bigint","Object","assign","create","prototype","isValidNumber","numberString","isNaN","parseNumberString","stringContainsNumbers","sanitizeExponentialNumberString","nonExpoNumString","containsDecimal","result","filter","i","match","numberKeys","includes","allLeadingZerosOptionallyNegative","decimalOnlyAtEndOfString","allHyphensExceptTheStart","isNegativeDecimalOnlyZeros","hasTrailingDecimalZeros","sanitizeNumberString","sanitizedValue","test","getBigDecimalAsString","sanitizedValueDecimals","bigDecimalValueInteger","bigDecimalValueDecimals","func","firstE","toLowerCase","indexOf","substring","section","exponentialParts","number","isSafeInteger","magnitude","decimalParts","shiftDecimalLeft","magnitudeDelta","Math","abs","leftPaddedZeros","shiftedDecimal","shiftDecimalRight","rightPaddedZeros","expandedNumberString","string","some","addLocalizedTrailingDecimalZeros","localizedValue","trailingDecimalZeros","delocalize","decimalSeparator","localize","defaultLocale","t9nLocales","locales","numberingSystems","isNumberingSystemSupported","numberingSystem","browserNumberingSystem","Intl","NumberFormat","resolvedOptions","defaultNumberingSystem","getSupportedNumberingSystem","getSupportedLocale","locale","context","contextualLocales","_match","language","region","toUpperCase","console","warn","getDateFormatSupportedLocale","connectedComponents","Set","connectLocalized","component","updateEffectiveLocale","size","mutationObserver","observe","document","documentElement","attributes","attributeFilter","subtree","effectiveLocale","getLocale","disconnectLocalized","delete","disconnect","createObserver","records","record","el","target","inUnrelatedSubtree","containsCrossShadowBoundary","closestLangEl","closestElementCrossShadowBoundary","closestLang","lang","hasAttribute","NumberStringFormat","_numberFormatOptions","_minusSign","_group","_decimal","_digits","_getDigitIndex","trim","_actualGroup","group","digits","_numberFormatter","numberFormatOptions","options","keys","JSON","stringify","useGrouping","reverse","index","Map","d","find","get","numberStringFormatter","dateTimeFormatCache","previousLocaleUsedForCaching","buildDateTimeFormatCacheKey","entries","sort","key1","key2","localeCompare","keyValue","flat","getDateTimeFormat","clear","key","cached","DateTimeFormat","set"],"sources":["src/utils/number.ts","src/utils/locale.ts"],"sourcesContent":["import { numberKeys } from \"./key\";\nimport { NumberStringFormat } from \"./locale\";\n\nconst unnecessaryDecimal = new RegExp(`\\\\${\".\"}(0+)?$`);\nconst trailingZeros = new RegExp(\"0+$\");\n\n// adopted from https://stackoverflow.com/a/66939244\nexport class BigDecimal {\n value: bigint;\n\n // BigInt(\"-0\").toString() === \"0\" which removes the minus sign when typing numbers like -0.1\n isNegative: boolean;\n\n // Configuration: constants\n static DECIMALS = 100; // number of decimals on all instances\n\n static ROUNDED = true; // numbers are truncated (false) or rounded (true)\n\n static SHIFT = BigInt(\"1\" + \"0\".repeat(BigDecimal.DECIMALS)); // derived constant\n\n constructor(input: string | BigDecimal) {\n if (input instanceof BigDecimal) {\n return input;\n }\n const [integers, decimals] = expandExponentialNumberString(input).split(\".\").concat(\"\");\n this.value =\n BigInt(integers + decimals.padEnd(BigDecimal.DECIMALS, \"0\").slice(0, BigDecimal.DECIMALS)) +\n BigInt(BigDecimal.ROUNDED && decimals[BigDecimal.DECIMALS] >= \"5\");\n\n this.isNegative = input.charAt(0) === \"-\";\n }\n\n static _divRound = (dividend: bigint, divisor: bigint): BigDecimal =>\n BigDecimal.fromBigInt(\n dividend / divisor + (BigDecimal.ROUNDED ? ((dividend * BigInt(2)) / divisor) % BigInt(2) : BigInt(0)),\n );\n\n static fromBigInt = (bigint: bigint): BigDecimal =>\n Object.assign(Object.create(BigDecimal.prototype), { value: bigint, isNegative: bigint < BigInt(0) });\n\n getIntegersAndDecimals(): { integers: string; decimals: string } {\n const s = this.value\n .toString()\n .replace(\"-\", \"\")\n .padStart(BigDecimal.DECIMALS + 1, \"0\");\n const integers = s.slice(0, -BigDecimal.DECIMALS);\n const decimals = s.slice(-BigDecimal.DECIMALS).replace(trailingZeros, \"\");\n return { integers, decimals };\n }\n\n toString(): string {\n const { integers, decimals } = this.getIntegersAndDecimals();\n return `${this.isNegative ? \"-\" : \"\"}${integers}${decimals.length ? \".\" + decimals : \"\"}`;\n }\n\n formatToParts(formatter: NumberStringFormat): Intl.NumberFormatPart[] {\n const { integers, decimals } = this.getIntegersAndDecimals();\n const parts = formatter.numberFormatter.formatToParts(BigInt(integers));\n this.isNegative && parts.unshift({ type: \"minusSign\", value: formatter.minusSign });\n\n if (decimals.length) {\n parts.push({ type: \"decimal\", value: formatter.decimal });\n decimals.split(\"\").forEach((char: string) => parts.push({ type: \"fraction\", value: char }));\n }\n\n return parts;\n }\n\n format(formatter: NumberStringFormat): string {\n const { integers, decimals } = this.getIntegersAndDecimals();\n const integersFormatted = `${this.isNegative ? formatter.minusSign : \"\"}${formatter.numberFormatter.format(\n BigInt(integers),\n )}`;\n const decimalsFormatted = decimals.length\n ? `${formatter.decimal}${decimals\n .split(\"\")\n .map((char: string) => formatter.numberFormatter.format(Number(char)))\n .join(\"\")}`\n : \"\";\n return `${integersFormatted}${decimalsFormatted}`;\n }\n\n add(n: string): BigDecimal {\n return BigDecimal.fromBigInt(this.value + new BigDecimal(n).value);\n }\n\n subtract(n: string): BigDecimal {\n return BigDecimal.fromBigInt(this.value - new BigDecimal(n).value);\n }\n\n multiply(n: string): BigDecimal {\n return BigDecimal._divRound(this.value * new BigDecimal(n).value, BigDecimal.SHIFT);\n }\n\n divide(n: string): BigDecimal {\n return BigDecimal._divRound(this.value * BigDecimal.SHIFT, new BigDecimal(n).value);\n }\n}\n\nexport function isValidNumber(numberString: string): boolean {\n return !(!numberString || isNaN(Number(numberString)));\n}\n\nexport function parseNumberString(numberString?: string): string {\n if (!numberString || !stringContainsNumbers(numberString)) {\n return \"\";\n }\n\n return sanitizeExponentialNumberString(numberString, (nonExpoNumString: string): string => {\n let containsDecimal = false;\n const result = nonExpoNumString\n .split(\"\")\n .filter((value, i) => {\n if (value.match(/\\./g) && !containsDecimal) {\n containsDecimal = true;\n return true;\n }\n if (value.match(/-/g) && i === 0) {\n return true;\n }\n return numberKeys.includes(value);\n })\n .join(\"\");\n return isValidNumber(result) ? new BigDecimal(result).toString() : \"\";\n });\n}\n\n// regex for number sanitization\nconst allLeadingZerosOptionallyNegative = /^([-0])0+(?=\\d)/;\nconst decimalOnlyAtEndOfString = /(?!^\\.)\\.$/;\nconst allHyphensExceptTheStart = /(?!^-)-/g;\nconst isNegativeDecimalOnlyZeros = /^-\\b0\\b\\.?0*$/;\nconst hasTrailingDecimalZeros = /0*$/;\n\nexport const sanitizeNumberString = (numberString: string): string =>\n sanitizeExponentialNumberString(numberString, (nonExpoNumString) => {\n const sanitizedValue = nonExpoNumString\n .replace(allHyphensExceptTheStart, \"\")\n .replace(decimalOnlyAtEndOfString, \"\")\n .replace(allLeadingZerosOptionallyNegative, \"$1\");\n return isValidNumber(sanitizedValue)\n ? isNegativeDecimalOnlyZeros.test(sanitizedValue)\n ? sanitizedValue\n : getBigDecimalAsString(sanitizedValue)\n : nonExpoNumString;\n });\n\nexport function getBigDecimalAsString(sanitizedValue: string): string {\n const sanitizedValueDecimals = sanitizedValue.split(\".\")[1];\n const value = new BigDecimal(sanitizedValue).toString();\n const [bigDecimalValueInteger, bigDecimalValueDecimals] = value.split(\".\");\n\n return sanitizedValueDecimals && bigDecimalValueDecimals !== sanitizedValueDecimals\n ? `${bigDecimalValueInteger}.${sanitizedValueDecimals}`\n : value;\n}\n\nexport function sanitizeExponentialNumberString(numberString: string, func: (s: string) => string): string {\n if (!numberString) {\n return numberString;\n }\n\n const firstE = numberString.toLowerCase().indexOf(\"e\") + 1;\n\n if (!firstE) {\n return func(numberString);\n }\n\n return numberString\n .replace(/[eE]*$/g, \"\")\n .substring(0, firstE)\n .concat(numberString.slice(firstE).replace(/[eE]/g, \"\"))\n .split(/[eE]/)\n .map((section, i) => (i === 1 ? func(section.replace(/\\./g, \"\")) : func(section)))\n .join(\"e\")\n .replace(/^e/, \"1e\");\n}\n\n/**\n * Converts an exponential notation numberString into decimal notation.\n * BigInt doesn't support exponential notation, so this is required to maintain precision\n *\n * @param {string} numberString - pre-validated exponential or decimal number\n * @returns {string} numberString in decimal notation\n */\nexport function expandExponentialNumberString(numberString: string): string {\n const exponentialParts = numberString.split(/[eE]/);\n if (exponentialParts.length === 1) {\n return numberString;\n }\n\n const number = +numberString;\n if (Number.isSafeInteger(number)) {\n return `${number}`;\n }\n\n const isNegative = numberString.charAt(0) === \"-\";\n const magnitude = +exponentialParts[1];\n const decimalParts = exponentialParts[0].split(\".\");\n const integers = (isNegative ? decimalParts[0].substring(1) : decimalParts[0]) || \"\";\n const decimals = decimalParts[1] || \"\";\n\n const shiftDecimalLeft = (integers: string, magnitude: number): string => {\n const magnitudeDelta = Math.abs(magnitude) - integers.length;\n const leftPaddedZeros = magnitudeDelta > 0 ? `${\"0\".repeat(magnitudeDelta)}${integers}` : integers;\n const shiftedDecimal = `${leftPaddedZeros.slice(0, magnitude)}${\".\"}${leftPaddedZeros.slice(magnitude)}`;\n return shiftedDecimal;\n };\n\n const shiftDecimalRight = (decimals: string, magnitude: number): string => {\n const rightPaddedZeros =\n magnitude > decimals.length ? `${decimals}${\"0\".repeat(magnitude - decimals.length)}` : decimals;\n const shiftedDecimal = `${rightPaddedZeros.slice(0, magnitude)}${\".\"}${rightPaddedZeros.slice(magnitude)}`;\n return shiftedDecimal;\n };\n\n const expandedNumberString =\n magnitude > 0\n ? `${integers}${shiftDecimalRight(decimals, magnitude)}`\n : `${shiftDecimalLeft(integers, magnitude)}${decimals}`;\n\n return `${isNegative ? \"-\" : \"\"}${expandedNumberString.charAt(0) === \".\" ? \"0\" : \"\"}${expandedNumberString\n .replace(unnecessaryDecimal, \"\")\n .replace(allLeadingZerosOptionallyNegative, \"\")}`;\n}\n\nfunction stringContainsNumbers(string: string): boolean {\n return numberKeys.some((number) => string.includes(number));\n}\n\n/**\n * Adds localized trailing decimals zero values to the number string.\n * BigInt conversion to string removes the trailing decimal zero values (Ex: 1.000 is returned as 1). This method helps adding them back.\n *\n * @param {string} localizedValue - localized number string value\n * @param {string} value - current value in the input field\n * @param {NumberStringFormat} formatter - numberStringFormatter instance to localize the number value\n * @returns {string} localized number string value\n */\nexport function addLocalizedTrailingDecimalZeros(\n localizedValue: string,\n value: string,\n formatter: NumberStringFormat,\n): string {\n const decimals = value.split(\".\")[1];\n if (decimals) {\n const trailingDecimalZeros = decimals.match(hasTrailingDecimalZeros)[0];\n if (\n trailingDecimalZeros &&\n formatter.delocalize(localizedValue).length !== value.length &&\n decimals.indexOf(\"e\") === -1\n ) {\n const decimalSeparator = formatter.decimal;\n localizedValue = !localizedValue.includes(decimalSeparator)\n ? `${localizedValue}${decimalSeparator}`\n : localizedValue;\n return localizedValue.padEnd(localizedValue.length + trailingDecimalZeros.length, formatter.localize(\"0\"));\n }\n }\n return localizedValue;\n}\n","import { closestElementCrossShadowBoundary, containsCrossShadowBoundary } from \"./dom\";\nimport { BigDecimal, isValidNumber, sanitizeExponentialNumberString } from \"./number\";\nimport { createObserver } from \"./observers\";\n\nexport const defaultLocale = \"en\";\n\nexport const t9nLocales = [\n \"ar\",\n \"bg\",\n \"bs\",\n \"ca\",\n \"cs\",\n \"da\",\n \"de\",\n \"el\",\n defaultLocale,\n \"es\",\n \"et\",\n \"fi\",\n \"fr\",\n \"he\",\n \"hr\",\n \"hu\",\n \"id\",\n \"it\",\n \"ja\",\n \"ko\",\n \"lt\",\n \"lv\",\n \"no\",\n \"nl\",\n \"pl\",\n \"pt-BR\",\n \"pt-PT\",\n \"ro\",\n \"ru\",\n \"sk\",\n \"sl\",\n \"sr\",\n \"sv\",\n \"th\",\n \"tr\",\n \"uk\",\n \"vi\",\n \"zh-CN\",\n \"zh-HK\",\n \"zh-TW\",\n];\n\nexport const locales = [\n \"ar\",\n \"bg\",\n \"bs\",\n \"ca\",\n \"cs\",\n \"da\",\n \"de\",\n \"de-AT\",\n \"de-CH\",\n \"el\",\n defaultLocale,\n \"en-AU\",\n \"en-CA\",\n \"en-GB\",\n \"es\",\n \"es-MX\",\n \"et\",\n \"fi\",\n \"fr\",\n \"fr-CH\",\n \"he\",\n \"hi\",\n \"hr\",\n \"hu\",\n \"id\",\n \"it\",\n \"it-CH\",\n \"ja\",\n \"ko\",\n \"lt\",\n \"lv\",\n \"mk\",\n \"no\",\n \"nl\",\n \"pl\",\n \"pt\",\n \"pt-PT\",\n \"ro\",\n \"ru\",\n \"sk\",\n \"sl\",\n \"sr\",\n \"sv\",\n \"th\",\n \"tr\",\n \"uk\",\n \"vi\",\n \"zh-CN\",\n \"zh-HK\",\n \"zh-TW\",\n];\n\nexport const numberingSystems = [\"arab\", \"arabext\", \"latn\"] as const;\n\nexport const supportedLocales = [...new Set([...t9nLocales, ...locales])] as const;\n\nexport type NumberingSystem = (typeof numberingSystems)[number];\n\nexport type SupportedLocale = (typeof supportedLocales)[number];\n\nconst isNumberingSystemSupported = (numberingSystem: string): numberingSystem is NumberingSystem =>\n numberingSystems.includes(numberingSystem as NumberingSystem);\n\nconst browserNumberingSystem = new Intl.NumberFormat().resolvedOptions().numberingSystem;\n\n// for consistent browser behavior, we normalize numberingSystem to prevent the browser-inferred value\n// see https://github.com/Esri/calcite-design-system/issues/3079#issuecomment-1168964195 for more info\nexport const defaultNumberingSystem =\n browserNumberingSystem === \"arab\" || !isNumberingSystemSupported(browserNumberingSystem)\n ? \"latn\"\n : browserNumberingSystem;\n\nexport const getSupportedNumberingSystem = (numberingSystem: string): NumberingSystem =>\n isNumberingSystemSupported(numberingSystem) ? numberingSystem : defaultNumberingSystem;\n\n/**\n * Gets the locale that best matches the context.\n *\n * @param locale – the BCP 47 locale code\n * @param context - specifies whether the locale code should match in the context of CLDR or T9N (translation)\n */\nexport function getSupportedLocale(locale: string, context: \"cldr\" | \"t9n\" = \"cldr\"): SupportedLocale {\n const contextualLocales = context === \"cldr\" ? locales : t9nLocales;\n\n if (!locale) {\n return defaultLocale;\n }\n\n if (contextualLocales.includes(locale)) {\n return locale;\n }\n\n locale = locale.toLowerCase();\n\n // we support both 'nb' and 'no' (BCP 47) for Norwegian but only `no` has corresponding bundle\n if (locale === \"nb\") {\n return \"no\";\n }\n\n // we use `pt-BR` as it will have the same translations as `pt`, which has no corresponding bundle\n if (context === \"t9n\" && locale === \"pt\") {\n return \"pt-BR\";\n }\n\n if (locale.includes(\"-\")) {\n locale = locale.replace(/(\\w+)-(\\w+)/, (_match, language, region) => `${language}-${region.toUpperCase()}`);\n\n if (!contextualLocales.includes(locale)) {\n locale = locale.split(\"-\")[0];\n }\n }\n\n // we can `zh-CN` as base translation for chinese locales which has no corresponding bundle.\n if (locale === \"zh\") {\n return \"zh-CN\";\n }\n\n if (!contextualLocales.includes(locale)) {\n console.warn(\n `Translations for the \"${locale}\" locale are not available and will fall back to the default, English (en).`,\n );\n return defaultLocale;\n }\n\n return locale;\n}\n\n/**\n * Gets the locale that best matches the context for date formatting.\n *\n * Intl date formatting has some quirks with certain locales. This handles those quirks by mapping a locale to another for date formatting.\n *\n * See https://github.com/Esri/calcite-design-system/issues/9387\n *\n * @param locale – the BCP 47 locale code\n * @returns {string} a BCP 47 locale code\n */\nexport function getDateFormatSupportedLocale(locale: string): string {\n switch (locale) {\n case \"it-CH\":\n return \"de-CH\";\n case \"bs\":\n return \"bs-Cyrl\";\n default:\n return locale;\n }\n}\n\n/**\n * This interface is for components that need to determine locale from the lang attribute.\n */\nexport interface LocalizedComponent {\n el: HTMLElement;\n\n /**\n * Used to store the effective locale to avoid multiple lookups.\n *\n * This is an internal property and should:\n *\n * - use the `@State` decorator\n * - be initialized to \"\"\n *\n * Components should watch this prop to ensure messages are updated.\n *\n * @Watch(\"effectiveLocale\")\n * effectiveLocaleChange(): void {\n * updateMessages(this, this.effectiveLocale);\n * }\n */\n effectiveLocale: string;\n}\n\nconst connectedComponents = new Set();\n\n/**\n * This utility sets up internals for messages support.\n *\n * It needs to be called in `connectedCallback` before any logic that depends on locale\n *\n * @param component\n */\nexport function connectLocalized(component: LocalizedComponent): void {\n updateEffectiveLocale(component);\n\n if (connectedComponents.size === 0) {\n mutationObserver?.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"lang\"],\n subtree: true,\n });\n }\n\n connectedComponents.add(component);\n}\n\n/**\n * This is only exported for components that implemented the now deprecated `locale` prop.\n *\n * Do not use this utils for new components.\n *\n * @param component\n */\nexport function updateEffectiveLocale(component: LocalizedComponent): void {\n component.effectiveLocale = getLocale(component);\n}\n\n/**\n * This utility tears down internals for messages support.\n *\n * It needs to be called in `disconnectedCallback`\n *\n * @param component\n */\nexport function disconnectLocalized(component: LocalizedComponent): void {\n connectedComponents.delete(component);\n\n if (connectedComponents.size === 0) {\n mutationObserver.disconnect();\n }\n}\n\nconst mutationObserver = createObserver(\"mutation\", (records) => {\n records.forEach((record) => {\n const el = record.target as HTMLElement;\n\n connectedComponents.forEach((component) => {\n const inUnrelatedSubtree = !containsCrossShadowBoundary(el, component.el);\n\n if (inUnrelatedSubtree) {\n return;\n }\n\n const closestLangEl = closestElementCrossShadowBoundary(component.el, \"[lang]\");\n\n if (!closestLangEl) {\n component.effectiveLocale = defaultLocale;\n return;\n }\n\n const closestLang = closestLangEl.lang;\n\n component.effectiveLocale =\n // user set lang=\"\" means unknown language, so we use default\n closestLangEl.hasAttribute(\"lang\") && closestLang === \"\" ? defaultLocale : closestLang;\n });\n });\n});\n\n/**\n * This util helps resolve a component's locale.\n * It will also fall back on the deprecated `locale` if a component implemented this previously.\n *\n * @param component\n */\nfunction getLocale(component: LocalizedComponent): string {\n return (\n component.el.lang ||\n closestElementCrossShadowBoundary(component.el, \"[lang]\")?.lang ||\n document.documentElement.lang ||\n defaultLocale\n );\n}\n\nexport interface NumberStringFormatOptions extends Intl.NumberFormatOptions {\n numberingSystem: NumberingSystem;\n locale: string;\n}\n\n/**\n * This util formats and parses numbers for localization\n */\nexport class NumberStringFormat {\n /**\n * The actual group separator for the specified locale.\n * White-space group separators are changed to the non-breaking space (nbsp) unicode character.\n * so we replace them with a normal .\n */\n private _actualGroup: string;\n\n /** the corrected group separator */\n private _group: string;\n\n get group(): string {\n return this._group;\n }\n\n private _decimal: string;\n\n get decimal(): string {\n return this._decimal;\n }\n\n private _minusSign: string;\n\n get minusSign(): string {\n return this._minusSign;\n }\n\n private _digits: Array;\n\n get digits(): Array {\n return this._digits;\n }\n\n private _getDigitIndex;\n\n private _numberFormatter: Intl.NumberFormat;\n\n get numberFormatter(): Intl.NumberFormat {\n return this._numberFormatter;\n }\n\n private _numberFormatOptions: NumberStringFormatOptions;\n\n get numberFormatOptions(): NumberStringFormatOptions {\n return this._numberFormatOptions;\n }\n\n /**\n * numberFormatOptions needs to be set before localize/delocalize is called to ensure the options are up to date\n */\n set numberFormatOptions(options: NumberStringFormatOptions) {\n options.locale = getSupportedLocale(options?.locale);\n options.numberingSystem = getSupportedNumberingSystem(options?.numberingSystem);\n\n if (\n // No need to create the formatter if `locale` and `numberingSystem`\n // are the default values and `numberFormatOptions` has not been set\n (!this._numberFormatOptions &&\n options.locale === defaultLocale &&\n options.numberingSystem === defaultNumberingSystem &&\n // don't skip initialization if any options besides locale/numberingSystem are set\n Object.keys(options).length === 2) ||\n // cache formatter by only recreating when options change\n JSON.stringify(this._numberFormatOptions) === JSON.stringify(options)\n ) {\n return;\n }\n\n this._numberFormatOptions = options;\n\n this._numberFormatter = new Intl.NumberFormat(\n this._numberFormatOptions.locale,\n this._numberFormatOptions as Intl.NumberFormatOptions,\n );\n\n this._digits = [\n ...new Intl.NumberFormat(this._numberFormatOptions.locale, {\n useGrouping: false,\n numberingSystem: this._numberFormatOptions.numberingSystem,\n } as Intl.NumberFormatOptions).format(9876543210),\n ].reverse();\n\n const index = new Map(this._digits.map((d, i) => [d, i]));\n\n // numberingSystem is parsed to return consistent decimal separator across browsers.\n const parts = new Intl.NumberFormat(this._numberFormatOptions.locale, {\n numberingSystem: this._numberFormatOptions.numberingSystem,\n } as Intl.NumberFormatOptions).formatToParts(-12345678.9);\n\n this._actualGroup = parts.find((d) => d.type === \"group\").value;\n // change whitespace group separators to the unicode non-breaking space (nbsp)\n this._group = this._actualGroup.trim().length === 0 || this._actualGroup == \" \" ? \"\\u00A0\" : this._actualGroup;\n this._decimal = parts.find((d) => d.type === \"decimal\").value;\n this._minusSign = parts.find((d) => d.type === \"minusSign\").value;\n this._getDigitIndex = (d: string) => index.get(d);\n }\n\n delocalize = (numberString: string): string =>\n // For performance, (de)localization is skipped if the formatter isn't initialized.\n // In order to localize/delocalize, e.g. when lang/numberingSystem props are not default values,\n // `numberFormatOptions` must be set in a component to create and cache the formatter.\n this._numberFormatOptions\n ? sanitizeExponentialNumberString(numberString, (nonExpoNumString: string): string =>\n nonExpoNumString\n .replace(new RegExp(`[${this._minusSign}]`, \"g\"), \"-\")\n .replace(new RegExp(`[${this._group}]`, \"g\"), \"\")\n .replace(new RegExp(`[${this._decimal}]`, \"g\"), \".\")\n .replace(new RegExp(`[${this._digits.join(\"\")}]`, \"g\"), this._getDigitIndex),\n )\n : numberString;\n\n localize = (numberString: string): string =>\n this._numberFormatOptions\n ? sanitizeExponentialNumberString(numberString, (nonExpoNumString: string): string =>\n isValidNumber(nonExpoNumString.trim())\n ? new BigDecimal(nonExpoNumString.trim())\n .format(this)\n .replace(new RegExp(`[${this._actualGroup}]`, \"g\"), this._group)\n : nonExpoNumString,\n )\n : numberString;\n}\n\nexport const numberStringFormatter = new NumberStringFormat();\n\nexport type LocaleDateTimeOptionKey = string;\n\n/**\n * Exported for testing purposes only.\n *\n * @internal\n */\nexport let dateTimeFormatCache: Map;\n\n/**\n * Used to ensure all cached formats are for the same locale.\n *\n * @internal\n */\nlet previousLocaleUsedForCaching: string;\n\n/**\n * Generates a cache key for date time format lookups.\n *\n * @internal\n */\nfunction buildDateTimeFormatCacheKey(options: Intl.DateTimeFormatOptions = {}): string {\n return Object.entries(options)\n .sort(([key1], [key2]) => key1.localeCompare(key2))\n .map((keyValue) => `${keyValue[0]}-${keyValue[1]}`)\n .flat()\n .join(\":\");\n}\n\n/**\n * Returns an instance of Intl.DateTimeFormat and reuses it if requested with the same locale and options.\n *\n * **Note**: the cache will be cleared if a different locale is provided\n *\n * @internal\n */\nexport function getDateTimeFormat(locale: string, options?: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n locale = getSupportedLocale(locale);\n\n if (!dateTimeFormatCache) {\n dateTimeFormatCache = new Map();\n }\n\n if (previousLocaleUsedForCaching !== locale) {\n dateTimeFormatCache.clear();\n previousLocaleUsedForCaching = locale;\n }\n\n const key = buildDateTimeFormatCacheKey(options);\n const cached = dateTimeFormatCache.get(key);\n\n if (cached) {\n return cached;\n }\n\n const format = new Intl.DateTimeFormat(locale, options);\n dateTimeFormatCache.set(key, format);\n\n return format;\n}\n"],"mappings":"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","ignoreList":[]}