diff --git a/README.md b/README.md index 9517f8b..160ff57 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 @@ -67,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/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()) {