From 519668edf244919e17beb519927ab3c56c09e715 Mon Sep 17 00:00:00 2001 From: Vyacheslav Date: Mon, 10 Jul 2023 19:54:02 +0600 Subject: [PATCH 1/4] Added support for "unsafe" numbers & update bin & readme --- README.md | 1 + bin/millify | 6 ++++++ lib/millify.ts | 2 +- lib/options.ts | 9 +++++++++ lib/utils.ts | 18 ++++++++++++++++-- test.js | 29 +++++++++++++++++++++++++++++ 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9517f8b..e8b44ab 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Before :unamused: | After :tada: `42500` | `'42.5 kg'` `1250000` | `'1.25 MB'` `2700000000` | `'2.7 bil'` +`1500000000000000000000000000000` | `'1.5 Q'` ## Install diff --git a/bin/millify b/bin/millify index bf0ffc0..516e3a0 100755 --- a/bin/millify +++ b/bin/millify @@ -35,6 +35,12 @@ require("yargs").command( type: "boolean", default: false, }) + .option("unsafeInteger", { + describe: "Use unsafe integer", + alias: "U", + type: "boolean", + default: false, + }) .option("units", { describe: "Unit abbreviatons", alias: "u", diff --git a/lib/millify.ts b/lib/millify.ts index 203e2bf..54151d2 100644 --- a/lib/millify.ts +++ b/lib/millify.ts @@ -48,7 +48,7 @@ function millify(value: number, options?: Partial): string { // Originally this threw an error, but was changed to return a graceful fallback. let val: number; try { - val = parseValue(value); + val = parseValue(value, opts); } catch (e) { if (e instanceof Error) { console.warn(`WARN: ${e.message} (millify)`); diff --git a/lib/options.ts b/lib/options.ts index a71dbb5..62d0088 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -23,6 +23,10 @@ export interface MillifyOptions { * A list of units to use. */ units: string[]; + /** + * Use unsafe integer + * */ + unsafeInteger: boolean; } /** @@ -32,6 +36,7 @@ export const defaultOptions: MillifyOptions = { lowercase: false, precision: 1, space: false, + unsafeInteger: false, units: [ "", "K", // Thousand @@ -40,5 +45,9 @@ export const defaultOptions: MillifyOptions = { "T", // Trillion "P", // Quadrillion "E", // Quintillion + "Z", // Sextillion + "Y", // Septillion + "R", // Octillion + "Q", // Nonillion ], }; diff --git a/lib/utils.ts b/lib/utils.ts index 9cbf138..e9be750 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,13 +1,27 @@ +import { MillifyOptions } from "./options"; + /** * parseValue ensures the value is a number and within accepted range. */ -export function parseValue(value: number): number { +export function parseValue( + value: number, + options?: Partial, +): number { const val: number = parseFloat(value?.toString()); if (isNaN(val)) { throw new Error(`Input value is not a number`); } - if (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER) { + if ( + options?.unsafeInteger && + (val > Number.MAX_VALUE || val < Number.MIN_VALUE) + ) { + throw new RangeError("Input value is outside of unsafe integer range"); + } + if ( + !options?.unsafeInteger && + (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER) + ) { throw new RangeError("Input value is outside of safe integer range"); } return val; diff --git a/test.js b/test.js index d2b4613..fd1a573 100644 --- a/test.js +++ b/test.js @@ -12,6 +12,35 @@ test("uses correct suffixes with default options", (t) => { [1000000, "1M"], [1000000000, "1B"], [1000000000000, "1T"], + [1000000000000000, "1P"], + ]); + + for (const [value, expected] of tests.entries()) { + t.is(millify(value), expected); + } +}); + +test("uses correct suffixes with 'unsafeInteger' option", (t) => { + const tests = new Map([ + [1000000000000000000, "1E"], + [1000000000000000000000, "1Z"], + [1000000000000000000000000, "1Y"], + [1000000000000000000000000000, "1R"], + [1700000000000000000000000000000, "1.7Q"], + ]); + + for (const [value, expected] of tests.entries()) { + t.is(millify(value, { unsafeInteger: true }), expected); + } +}); + +test("uses correct suffixes without 'unsafeInteger' option", (t) => { + const tests = new Map([ + ["1000000000000000000", "1000000000000000000"], + ["1000000000000000000000", "1000000000000000000000"], + ["1000000000000000000000000", "1000000000000000000000000"], + ["1000000000000000000000000000", "1000000000000000000000000000"], + ["1000000000000000000000000000000", "1000000000000000000000000000000"], ]); for (const [value, expected] of tests.entries()) { From 15a4f5f169f60b6fe05e37334fa9d1789edd6ce4 Mon Sep 17 00:00:00 2001 From: Vyacheslav Date: Mon, 10 Jul 2023 20:11:54 +0600 Subject: [PATCH 2/4] add dist --- dist/index.d.ts | 3 ++ dist/index.js | 9 +++++ dist/millify.d.ts | 7 ++++ dist/millify.js | 96 +++++++++++++++++++++++++++++++++++++++++++++++ dist/options.d.ts | 34 +++++++++++++++++ dist/utils.d.ts | 17 +++++++++ dist/utils.js | 61 ++++++++++++++++++++++++++++++ 7 files changed, 227 insertions(+) create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/millify.d.ts create mode 100644 dist/millify.js create mode 100644 dist/options.d.ts create mode 100644 dist/utils.d.ts create mode 100644 dist/utils.js diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..a963531 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,3 @@ +import millify from "./millify"; +export { millify }; +export default millify; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..cdd0b76 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,9 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.millify = void 0; +const millify_1 = __importDefault(require("./millify")); +exports.millify = millify_1.default; +exports.default = millify_1.default; diff --git a/dist/millify.d.ts b/dist/millify.d.ts new file mode 100644 index 0000000..e325b7d --- /dev/null +++ b/dist/millify.d.ts @@ -0,0 +1,7 @@ +import { MillifyOptions } from "./options"; +/** + * millify converts long numbers to human-readable strings. + */ +declare function millify(value: number, options?: Partial): string; +export { millify }; +export default millify; diff --git a/dist/millify.js b/dist/millify.js new file mode 100644 index 0000000..5e316e4 --- /dev/null +++ b/dist/millify.js @@ -0,0 +1,96 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.millify = void 0; +const options_1 = require("./options"); +const utils_1 = require("./utils"); +// Most commonly used digit grouping base. +const DIGIT_GROUPING_BASE = 1000; +/** + * Generator that divides a number until a decimal value is found. + * + * The denominator is defined by the numerical digit grouping base, + * or interval. The most commonly-used digit group interval is 1000. + * + * e.g. 1,000,000 is grouped in multiples of 1000. + */ +function* divider(value) { + // Create a mutable copy of the base. + let denominator = DIGIT_GROUPING_BASE; + while (true) { + const result = value / denominator; + if (result < 1) { + // End of operation. We can't divide the value any further. + return; + } + yield result; + // The denominator is increased every iteration by multiplying + // the base by itself, until a decimal value remains. + denominator *= DIGIT_GROUPING_BASE; + } +} +/** + * millify converts long numbers to human-readable strings. + */ +function millify(value, options) { + var _a, _b; + // Override default options with options supplied by user. + const opts = options + ? { ...options_1.defaultOptions, ...options } + : options_1.defaultOptions; + if (!Array.isArray(opts.units) || !opts.units.length) { + throw new Error("Option `units` must be a non-empty array"); + } + // If the input value is invalid, then return the value in string form. + // Originally this threw an error, but was changed to return a graceful fallback. + let val; + try { + val = utils_1.parseValue(value, opts); + } + catch (e) { + if (e instanceof Error) { + console.warn(`WARN: ${e.message} (millify)`); + } + // Invalid values will be converted to string as per `String()`. + return String(value); + } + // Add a minus sign (-) prefix if it's a negative number. + const prefix = val < 0 ? "-" : ""; + // Work only with positive values for simplicity's sake. + val = Math.abs(val); + // Keep dividing the input value by the digit grouping base + // until the decimal and the unit index is deciphered. + let unitIndex = 0; + for (const result of divider(val)) { + val = result; + unitIndex += 1; + } + // Return the original number if the number is too large to have + // a corresponding unit. Returning anything else is ambiguous. + const unitIndexOutOfRange = unitIndex >= opts.units.length; + if (unitIndexOutOfRange) { + // At this point we don't know what to do with the input value, + // so we return it as is, without localizing the string. + return value.toString(); + } + // Round decimal up to desired precision. + let rounded = utils_1.roundTo(val, opts.precision); + // Fixes an edge case bug that outputs certain numbers as 1000K instead of 1M. + // The rounded value needs another iteration in the divider cycle. + for (const result of divider(rounded)) { + rounded = result; + unitIndex += 1; + } + // Calculate the unit suffix and make it lowercase (if needed). + const unit = (_a = opts.units[unitIndex]) !== null && _a !== void 0 ? _a : ""; + const suffix = opts.lowercase ? unit.toLowerCase() : unit; + // Add a space between number and abbreviation. + const space = opts.space ? " " : ""; + // Format the number according to the desired locale. + const formatted = rounded.toLocaleString((_b = opts.locales) !== null && _b !== void 0 ? _b : utils_1.getLocales(), { + // toLocaleString needs the explicit fraction digits. + minimumFractionDigits: utils_1.getFractionDigits(rounded), + }); + return `${prefix}${formatted}${space}${suffix}`; +} +exports.millify = millify; +exports.default = millify; diff --git a/dist/options.d.ts b/dist/options.d.ts new file mode 100644 index 0000000..00f03f9 --- /dev/null +++ b/dist/options.d.ts @@ -0,0 +1,34 @@ +/** + * Options used to configure Millify. + */ +export interface MillifyOptions { + /** + * The number of significant figures. + */ + precision: number; + /** + * The active browser or server location. A string with a BCP 47 language + * tag, or an array of such strings, e.g. "en-US". + */ + locales?: string | string[]; + /** + * Convert units to lower case. + */ + lowercase: boolean; + /** + * Add a space between the number and the unit. + */ + space: boolean; + /** + * A list of units to use. + */ + units: string[]; + /** + * Use unsafe integer + * */ + unsafeInteger: boolean; +} +/** + * Default options for Millify. + */ +export declare const defaultOptions: MillifyOptions; diff --git a/dist/utils.d.ts b/dist/utils.d.ts new file mode 100644 index 0000000..291df18 --- /dev/null +++ b/dist/utils.d.ts @@ -0,0 +1,17 @@ +import { MillifyOptions } from "./options"; +/** + * parseValue ensures the value is a number and within accepted range. + */ +export declare function parseValue(value: number, options?: Partial): number; +/** + * Rounds a number [value] up to a specified [precision]. + */ +export declare function roundTo(value: number, precision: number): number; +/** + * Returns the number of digits after the decimal. + */ +export declare function getFractionDigits(num: number): number; +/** + * Returns the default browser locales. + */ +export declare function getLocales(): string[]; diff --git a/dist/utils.js b/dist/utils.js new file mode 100644 index 0000000..bda5bd3 --- /dev/null +++ b/dist/utils.js @@ -0,0 +1,61 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getLocales = exports.getFractionDigits = exports.roundTo = exports.parseValue = void 0; +/** + * parseValue ensures the value is a number and within accepted range. + */ +function parseValue(value, options) { + const val = parseFloat(value === null || value === void 0 ? void 0 : value.toString()); + if (isNaN(val)) { + throw new Error(`Input value is not a number`); + } + if ((options === null || options === void 0 ? void 0 : options.unsafeInteger) && + (val > Number.MAX_VALUE || val < Number.MIN_VALUE)) { + throw new RangeError("Input value is outside of unsafe integer range"); + } + if (!(options === null || options === void 0 ? void 0 : options.unsafeInteger) && + (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER)) { + throw new RangeError("Input value is outside of safe integer range"); + } + return val; +} +exports.parseValue = parseValue; +/** + * Rounds a number [value] up to a specified [precision]. + */ +function roundTo(value, precision) { + if (!Number.isFinite(value)) { + throw new Error("Input value is not a finite number"); + } + if (!Number.isInteger(precision) || precision < 0) { + throw new Error("Precision is not a positive integer"); + } + if (Number.isInteger(value)) { + return value; + } + return parseFloat(value.toFixed(precision)); +} +exports.roundTo = roundTo; +/** + * Returns the number of digits after the decimal. + */ +function getFractionDigits(num) { + var _a; + if (Number.isInteger(num)) { + return 0; + } + const decimalPart = num.toString().split(".")[1]; + return (_a = decimalPart === null || decimalPart === void 0 ? void 0 : decimalPart.length) !== null && _a !== void 0 ? _a : 0; +} +exports.getFractionDigits = getFractionDigits; +/** + * Returns the default browser locales. + */ +function getLocales() { + var _a; + if (typeof navigator === "undefined") { + return []; + } + return Array.from((_a = navigator.languages) !== null && _a !== void 0 ? _a : []); +} +exports.getLocales = getLocales; From 686fa0cd8d087c795778f67cdb55f84bc5e8e188 Mon Sep 17 00:00:00 2001 From: Vyacheslav Date: Mon, 10 Jul 2023 20:17:07 +0600 Subject: [PATCH 3/4] add options file --- dist/options.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 dist/options.js diff --git a/dist/options.js b/dist/options.js new file mode 100644 index 0000000..4e4f42c --- /dev/null +++ b/dist/options.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.defaultOptions = void 0; +/** + * Default options for Millify. + */ +exports.defaultOptions = { + lowercase: false, + precision: 1, + space: false, + unsafeInteger: false, + units: [ + "", + "K", + "M", + "B", + "T", + "P", + "E", + "Z", + "Y", + "R", + "Q", // Nonillion + ], +}; From 465f6954985eeb4c13a1c5baebdcefae9f242dbd Mon Sep 17 00:00:00 2001 From: Vyacheslav Date: Mon, 10 Jul 2023 22:00:18 +0600 Subject: [PATCH 4/4] upd readme & delete dist --- README.md | 1 + dist/index.d.ts | 3 -- dist/index.js | 9 ----- dist/millify.d.ts | 7 ---- dist/millify.js | 96 ----------------------------------------------- dist/options.d.ts | 34 ----------------- dist/options.js | 25 ------------ dist/utils.d.ts | 17 --------- dist/utils.js | 61 ------------------------------ 9 files changed, 1 insertion(+), 252 deletions(-) delete mode 100644 dist/index.d.ts delete mode 100644 dist/index.js delete mode 100644 dist/millify.d.ts delete mode 100644 dist/millify.js delete mode 100644 dist/options.d.ts delete mode 100644 dist/options.js delete mode 100644 dist/utils.d.ts delete mode 100644 dist/utils.js diff --git a/README.md b/README.md index e8b44ab..160ff57 100644 --- a/README.md +++ b/README.md @@ -68,4 +68,5 @@ Name | Type | Default | Description `locales` | `string \| Array` | browser language | Formats the number in different languages `lowercase` | `boolean` | `false` | Use lowercase abbreviations `space` | `boolean` | `false` | Add a space between number and abbreviation +`unsafeInteger` | `boolean` | `false` | Use unsafe numbers `units` | `Array` | `['', 'K', 'M', 'B', 'T', 'P', 'E']` | Unit abbreviations diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index a963531..0000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import millify from "./millify"; -export { millify }; -export default millify; diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index cdd0b76..0000000 --- a/dist/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.millify = void 0; -const millify_1 = __importDefault(require("./millify")); -exports.millify = millify_1.default; -exports.default = millify_1.default; diff --git a/dist/millify.d.ts b/dist/millify.d.ts deleted file mode 100644 index e325b7d..0000000 --- a/dist/millify.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MillifyOptions } from "./options"; -/** - * millify converts long numbers to human-readable strings. - */ -declare function millify(value: number, options?: Partial): string; -export { millify }; -export default millify; diff --git a/dist/millify.js b/dist/millify.js deleted file mode 100644 index 5e316e4..0000000 --- a/dist/millify.js +++ /dev/null @@ -1,96 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.millify = void 0; -const options_1 = require("./options"); -const utils_1 = require("./utils"); -// Most commonly used digit grouping base. -const DIGIT_GROUPING_BASE = 1000; -/** - * Generator that divides a number until a decimal value is found. - * - * The denominator is defined by the numerical digit grouping base, - * or interval. The most commonly-used digit group interval is 1000. - * - * e.g. 1,000,000 is grouped in multiples of 1000. - */ -function* divider(value) { - // Create a mutable copy of the base. - let denominator = DIGIT_GROUPING_BASE; - while (true) { - const result = value / denominator; - if (result < 1) { - // End of operation. We can't divide the value any further. - return; - } - yield result; - // The denominator is increased every iteration by multiplying - // the base by itself, until a decimal value remains. - denominator *= DIGIT_GROUPING_BASE; - } -} -/** - * millify converts long numbers to human-readable strings. - */ -function millify(value, options) { - var _a, _b; - // Override default options with options supplied by user. - const opts = options - ? { ...options_1.defaultOptions, ...options } - : options_1.defaultOptions; - if (!Array.isArray(opts.units) || !opts.units.length) { - throw new Error("Option `units` must be a non-empty array"); - } - // If the input value is invalid, then return the value in string form. - // Originally this threw an error, but was changed to return a graceful fallback. - let val; - try { - val = utils_1.parseValue(value, opts); - } - catch (e) { - if (e instanceof Error) { - console.warn(`WARN: ${e.message} (millify)`); - } - // Invalid values will be converted to string as per `String()`. - return String(value); - } - // Add a minus sign (-) prefix if it's a negative number. - const prefix = val < 0 ? "-" : ""; - // Work only with positive values for simplicity's sake. - val = Math.abs(val); - // Keep dividing the input value by the digit grouping base - // until the decimal and the unit index is deciphered. - let unitIndex = 0; - for (const result of divider(val)) { - val = result; - unitIndex += 1; - } - // Return the original number if the number is too large to have - // a corresponding unit. Returning anything else is ambiguous. - const unitIndexOutOfRange = unitIndex >= opts.units.length; - if (unitIndexOutOfRange) { - // At this point we don't know what to do with the input value, - // so we return it as is, without localizing the string. - return value.toString(); - } - // Round decimal up to desired precision. - let rounded = utils_1.roundTo(val, opts.precision); - // Fixes an edge case bug that outputs certain numbers as 1000K instead of 1M. - // The rounded value needs another iteration in the divider cycle. - for (const result of divider(rounded)) { - rounded = result; - unitIndex += 1; - } - // Calculate the unit suffix and make it lowercase (if needed). - const unit = (_a = opts.units[unitIndex]) !== null && _a !== void 0 ? _a : ""; - const suffix = opts.lowercase ? unit.toLowerCase() : unit; - // Add a space between number and abbreviation. - const space = opts.space ? " " : ""; - // Format the number according to the desired locale. - const formatted = rounded.toLocaleString((_b = opts.locales) !== null && _b !== void 0 ? _b : utils_1.getLocales(), { - // toLocaleString needs the explicit fraction digits. - minimumFractionDigits: utils_1.getFractionDigits(rounded), - }); - return `${prefix}${formatted}${space}${suffix}`; -} -exports.millify = millify; -exports.default = millify; diff --git a/dist/options.d.ts b/dist/options.d.ts deleted file mode 100644 index 00f03f9..0000000 --- a/dist/options.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Options used to configure Millify. - */ -export interface MillifyOptions { - /** - * The number of significant figures. - */ - precision: number; - /** - * The active browser or server location. A string with a BCP 47 language - * tag, or an array of such strings, e.g. "en-US". - */ - locales?: string | string[]; - /** - * Convert units to lower case. - */ - lowercase: boolean; - /** - * Add a space between the number and the unit. - */ - space: boolean; - /** - * A list of units to use. - */ - units: string[]; - /** - * Use unsafe integer - * */ - unsafeInteger: boolean; -} -/** - * Default options for Millify. - */ -export declare const defaultOptions: MillifyOptions; diff --git a/dist/options.js b/dist/options.js deleted file mode 100644 index 4e4f42c..0000000 --- a/dist/options.js +++ /dev/null @@ -1,25 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.defaultOptions = void 0; -/** - * Default options for Millify. - */ -exports.defaultOptions = { - lowercase: false, - precision: 1, - space: false, - unsafeInteger: false, - units: [ - "", - "K", - "M", - "B", - "T", - "P", - "E", - "Z", - "Y", - "R", - "Q", // Nonillion - ], -}; diff --git a/dist/utils.d.ts b/dist/utils.d.ts deleted file mode 100644 index 291df18..0000000 --- a/dist/utils.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MillifyOptions } from "./options"; -/** - * parseValue ensures the value is a number and within accepted range. - */ -export declare function parseValue(value: number, options?: Partial): number; -/** - * Rounds a number [value] up to a specified [precision]. - */ -export declare function roundTo(value: number, precision: number): number; -/** - * Returns the number of digits after the decimal. - */ -export declare function getFractionDigits(num: number): number; -/** - * Returns the default browser locales. - */ -export declare function getLocales(): string[]; diff --git a/dist/utils.js b/dist/utils.js deleted file mode 100644 index bda5bd3..0000000 --- a/dist/utils.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getLocales = exports.getFractionDigits = exports.roundTo = exports.parseValue = void 0; -/** - * parseValue ensures the value is a number and within accepted range. - */ -function parseValue(value, options) { - const val = parseFloat(value === null || value === void 0 ? void 0 : value.toString()); - if (isNaN(val)) { - throw new Error(`Input value is not a number`); - } - if ((options === null || options === void 0 ? void 0 : options.unsafeInteger) && - (val > Number.MAX_VALUE || val < Number.MIN_VALUE)) { - throw new RangeError("Input value is outside of unsafe integer range"); - } - if (!(options === null || options === void 0 ? void 0 : options.unsafeInteger) && - (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER)) { - throw new RangeError("Input value is outside of safe integer range"); - } - return val; -} -exports.parseValue = parseValue; -/** - * Rounds a number [value] up to a specified [precision]. - */ -function roundTo(value, precision) { - if (!Number.isFinite(value)) { - throw new Error("Input value is not a finite number"); - } - if (!Number.isInteger(precision) || precision < 0) { - throw new Error("Precision is not a positive integer"); - } - if (Number.isInteger(value)) { - return value; - } - return parseFloat(value.toFixed(precision)); -} -exports.roundTo = roundTo; -/** - * Returns the number of digits after the decimal. - */ -function getFractionDigits(num) { - var _a; - if (Number.isInteger(num)) { - return 0; - } - const decimalPart = num.toString().split(".")[1]; - return (_a = decimalPart === null || decimalPart === void 0 ? void 0 : decimalPart.length) !== null && _a !== void 0 ? _a : 0; -} -exports.getFractionDigits = getFractionDigits; -/** - * Returns the default browser locales. - */ -function getLocales() { - var _a; - if (typeof navigator === "undefined") { - return []; - } - return Array.from((_a = navigator.languages) !== null && _a !== void 0 ? _a : []); -} -exports.getLocales = getLocales;