Files
itflow/libs/intl-tel-input/js/core/numerals.ts
2026-08-26 13:14:32 -04:00

65 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export class Numerals {
#userNumeralSet: "ascii" | "arabic-indic" | "persian" | undefined;
//* Stateless conversion of any Arabic-Indic / Persian digits to ASCII 0-9.
//* Use this when you need to normalise digits without affecting any instance's tracked numeral set (e.g. for the country-search query).
public static toAscii(str: string): string {
if (!str) {
return "";
}
// Note: yes it runs two replaces, but a replace call is really a test + manipulate, so for standard ascii input, it just runs 2x tests. Not worth splitting up and adding test guards.
return str
.replace(/[٠-٩]/g, (ch) =>
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x0660)),
)
.replace(/[۰-۹]/g, (ch) =>
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x06f0)),
);
}
constructor(initialValue: string) {
if (initialValue) {
this.#updateNumeralSet(initialValue);
}
}
// If any Arabic-Indic digits, then label it as that set. Same for Persian. Otherwise assume ASCII.
#updateNumeralSet(str: string): void {
if (/[٠-٩]/.test(str)) {
this.#userNumeralSet = "arabic-indic";
} else if (/[۰-۹]/.test(str)) {
this.#userNumeralSet = "persian";
} else {
this.#userNumeralSet = "ascii";
}
}
// Denormalise ASCII 0-9 to the user's numeral set. If not yet known, return as-is.
// NOTE: normalise is always called before this, so it should be impossible for the numeral set to be unknown at this point.
public denormalise(str: string): string {
if (!this.#userNumeralSet || this.#userNumeralSet === "ascii") {
return str;
}
const base = this.#userNumeralSet === "arabic-indic" ? 0x0660 : 0x06f0;
return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
}
// Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9.
// Tracks the user's numeral set as a side effect so denormalise can mirror it back.
public normalise(str: string): string {
if (!str) {
return "";
}
this.#updateNumeralSet(str);
//* Fast-path ASCII (the common case) so we skip both replaces on every keystroke.
if (this.#userNumeralSet === "ascii") {
return str;
}
return Numerals.toAscii(str);
}
public isAscii(): boolean {
return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
}
}