@augment-vir/common 6.4.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/augments/common-number.d.ts +4 -22
- package/dist/cjs/augments/common-number.js +16 -82
- package/dist/cjs/augments/error.d.ts +4 -0
- package/dist/cjs/augments/error.js +28 -1
- package/dist/cjs/augments/function.d.ts +2 -1
- package/dist/cjs/augments/nested-keys.js +8 -15
- package/dist/cjs/augments/promise.js +6 -5
- package/dist/cjs/augments/truncate-number.d.ts +20 -0
- package/dist/cjs/augments/truncate-number.js +154 -0
- package/dist/cjs/augments/tuple.d.ts +2 -2
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/esm/augments/common-number.d.ts +4 -22
- package/dist/esm/augments/common-number.js +14 -81
- package/dist/esm/augments/error.d.ts +4 -0
- package/dist/esm/augments/error.js +26 -0
- package/dist/esm/augments/function.d.ts +2 -1
- package/dist/esm/augments/nested-keys.js +8 -15
- package/dist/esm/augments/promise.js +6 -5
- package/dist/esm/augments/truncate-number.d.ts +20 -0
- package/dist/esm/augments/truncate-number.js +150 -0
- package/dist/esm/augments/tuple.d.ts +2 -2
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/types/augments/common-number.d.ts +4 -22
- package/dist/types/augments/error.d.ts +4 -0
- package/dist/types/augments/function.d.ts +2 -1
- package/dist/types/augments/truncate-number.d.ts +20 -0
- package/dist/types/augments/tuple.d.ts +2 -2
- package/dist/types/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const NaNString: string;
|
|
2
|
+
export declare function addCommasToNumber(input: number | string): string;
|
|
2
3
|
export declare function clamp(
|
|
3
4
|
/**
|
|
4
5
|
* This uses a destructured object so that consumers cannot get confused as to which input is
|
|
@@ -9,25 +10,6 @@ export declare function clamp(
|
|
|
9
10
|
min: number;
|
|
10
11
|
max: number;
|
|
11
12
|
}): number;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* point, or comma.
|
|
15
|
-
*
|
|
16
|
-
* Default suffixes are:
|
|
17
|
-
*
|
|
18
|
-
* '', // no suffix, numbers below 1000
|
|
19
|
-
* 'k', // thousand
|
|
20
|
-
* 'M', // million
|
|
21
|
-
* 'B', // billion
|
|
22
|
-
* 'T', // trillion
|
|
23
|
-
* 'P', // peta-, quadrillion
|
|
24
|
-
* 'E', // exa- quintillion
|
|
25
|
-
* 'Z', // zetta- sextillion
|
|
26
|
-
* 'Y', // yotta- septillion
|
|
27
|
-
*/
|
|
28
|
-
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
|
|
29
|
-
customSuffixes?: ReadonlyArray<string>;
|
|
30
|
-
suppressErrorLogging?: boolean;
|
|
31
|
-
customErrorLogCallback?: (...args: any) => void;
|
|
32
|
-
}): string;
|
|
13
|
+
export declare function convertIntoNumber(input: unknown): number;
|
|
14
|
+
export declare function doesRequireScientificNotation(input: number): boolean;
|
|
33
15
|
//# sourceMappingURL=common-number.d.ts.map
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.doesRequireScientificNotation = exports.convertIntoNumber = exports.clamp = exports.addCommasToNumber = exports.NaNString = void 0;
|
|
4
4
|
const common_string_1 = require("./common-string");
|
|
5
5
|
const regexp_1 = require("./regexp");
|
|
6
|
+
exports.NaNString = String(NaN);
|
|
6
7
|
function addCommasToNumber(input) {
|
|
8
|
+
if (typeof input === 'string' && isNaN(Number(input))) {
|
|
9
|
+
return exports.NaNString;
|
|
10
|
+
}
|
|
7
11
|
const stringValue = String(input);
|
|
8
12
|
const [digits, decimalValues,] = stringValue.split('.');
|
|
9
13
|
const decimalString = decimalValues ? `.${decimalValues}` : '';
|
|
@@ -23,89 +27,19 @@ function clamp(
|
|
|
23
27
|
return Math.max(Math.min(value, max), min);
|
|
24
28
|
}
|
|
25
29
|
exports.clamp = clamp;
|
|
26
|
-
|
|
27
|
-
''
|
|
28
|
-
|
|
29
|
-
'M',
|
|
30
|
-
'B',
|
|
31
|
-
'T',
|
|
32
|
-
'P',
|
|
33
|
-
'E',
|
|
34
|
-
'Z',
|
|
35
|
-
'Y', // yotta- septillion
|
|
36
|
-
];
|
|
37
|
-
function recursiveTruncation(value, recursionDepth = 0, decimalValues = '') {
|
|
38
|
-
var _a;
|
|
39
|
-
if (value.includes('e+')) {
|
|
40
|
-
throw new Error(`Number is too large, it cannot be truncated: ${value}`);
|
|
30
|
+
function convertIntoNumber(input) {
|
|
31
|
+
if (typeof input === 'number') {
|
|
32
|
+
return input;
|
|
41
33
|
}
|
|
42
|
-
else if (
|
|
43
|
-
|
|
34
|
+
else if (typeof input === 'string') {
|
|
35
|
+
return Number((0, common_string_1.removeCommasFromNumberString)(input));
|
|
44
36
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const amount = split[0];
|
|
48
|
-
if (amount.length > 3) {
|
|
49
|
-
decimalValues = amount.slice(-3);
|
|
50
|
-
return recursiveTruncation(amount.slice(0, -3), recursionDepth + 1, decimalValues);
|
|
37
|
+
else {
|
|
38
|
+
return Number(input);
|
|
51
39
|
}
|
|
52
|
-
return {
|
|
53
|
-
value: amount,
|
|
54
|
-
decimalValues,
|
|
55
|
-
recursionDepth,
|
|
56
|
-
};
|
|
57
40
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* point, or comma.
|
|
62
|
-
*
|
|
63
|
-
* Default suffixes are:
|
|
64
|
-
*
|
|
65
|
-
* '', // no suffix, numbers below 1000
|
|
66
|
-
* 'k', // thousand
|
|
67
|
-
* 'M', // million
|
|
68
|
-
* 'B', // billion
|
|
69
|
-
* 'T', // trillion
|
|
70
|
-
* 'P', // peta-, quadrillion
|
|
71
|
-
* 'E', // exa- quintillion
|
|
72
|
-
* 'Z', // zetta- sextillion
|
|
73
|
-
* 'Y', // yotta- septillion
|
|
74
|
-
*/
|
|
75
|
-
function truncateNumber(originalValue, { customSuffixes, suppressErrorLogging, customErrorLogCallback, } = {}) {
|
|
76
|
-
try {
|
|
77
|
-
const value = typeof originalValue === 'number'
|
|
78
|
-
? originalValue
|
|
79
|
-
: typeof originalValue === 'string'
|
|
80
|
-
? Number((0, common_string_1.removeCommasFromNumberString)(originalValue))
|
|
81
|
-
: Number(originalValue);
|
|
82
|
-
if (isNaN(value)) {
|
|
83
|
-
throw new Error(`${originalValue} could not be converted into a number.`);
|
|
84
|
-
}
|
|
85
|
-
const stringValue = String(value);
|
|
86
|
-
const results = recursiveTruncation(stringValue);
|
|
87
|
-
const suffixes = customSuffixes !== null && customSuffixes !== void 0 ? customSuffixes : defaultTruncationSuffixes;
|
|
88
|
-
const suffix = suffixes[results.recursionDepth];
|
|
89
|
-
if (suffix === undefined) {
|
|
90
|
-
throw new Error(`Number is too large, could not truncate: ${value}`);
|
|
91
|
-
}
|
|
92
|
-
const decimalPlaces = maxDecimals - (results.value.length - 1) - suffix.length;
|
|
93
|
-
const decimalValues = results.decimalValues.replace(/0+$/, '').slice(0, decimalPlaces);
|
|
94
|
-
const withDecimal = decimalValues.length ? `.${decimalValues}` : '';
|
|
95
|
-
const combined = `${results.value}${withDecimal}${suffix}`;
|
|
96
|
-
if (combined.length > stringValue.length + 1) {
|
|
97
|
-
return addCommasToNumber(value);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
return combined;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
const errorCallback = customErrorLogCallback ? customErrorLogCallback : console.error;
|
|
105
|
-
if (!suppressErrorLogging) {
|
|
106
|
-
errorCallback(error);
|
|
107
|
-
}
|
|
108
|
-
return String(originalValue);
|
|
109
|
-
}
|
|
41
|
+
exports.convertIntoNumber = convertIntoNumber;
|
|
42
|
+
function doesRequireScientificNotation(input) {
|
|
43
|
+
return String(input).includes('e');
|
|
110
44
|
}
|
|
111
|
-
exports.
|
|
45
|
+
exports.doesRequireScientificNotation = doesRequireScientificNotation;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { NoInputsFunction } from './function';
|
|
1
2
|
import { AtLeastTuple } from './tuple';
|
|
3
|
+
import { UnPromise } from './type';
|
|
2
4
|
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;
|
|
3
5
|
export declare function combineErrors(errors: ReadonlyArray<never>): undefined;
|
|
4
6
|
export declare function combineErrors(errors: ReadonlyArray<Error>): Error | undefined;
|
|
@@ -6,4 +8,6 @@ export declare function combineErrors(errors?: undefined): undefined;
|
|
|
6
8
|
export declare function combineErrorMessages(errors?: ReadonlyArray<Error | string | undefined> | undefined): string;
|
|
7
9
|
export declare function extractErrorMessage(error: unknown): string;
|
|
8
10
|
export declare function ensureError(input: unknown): Error;
|
|
11
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
|
|
12
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
|
|
9
13
|
//# sourceMappingURL=error.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensureError = exports.extractErrorMessage = exports.combineErrorMessages = exports.combineErrors = void 0;
|
|
3
|
+
exports.executeAndReturnError = exports.ensureError = exports.extractErrorMessage = exports.combineErrorMessages = exports.combineErrors = void 0;
|
|
4
4
|
const function_1 = require("./function");
|
|
5
|
+
const promise_1 = require("./promise");
|
|
5
6
|
function combineErrors(errors) {
|
|
6
7
|
if (!errors || errors.length === 0) {
|
|
7
8
|
return undefined;
|
|
@@ -41,3 +42,29 @@ function ensureError(input) {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
exports.ensureError = ensureError;
|
|
45
|
+
function executeAndReturnError(callback) {
|
|
46
|
+
let caughtError;
|
|
47
|
+
try {
|
|
48
|
+
const result = callback();
|
|
49
|
+
if ((0, promise_1.isPromiseLike)(result)) {
|
|
50
|
+
return new Promise(async (resolve) => {
|
|
51
|
+
try {
|
|
52
|
+
const output = await result;
|
|
53
|
+
return resolve(output);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
caughtError = ensureError(error);
|
|
57
|
+
}
|
|
58
|
+
return resolve(caughtError);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
caughtError = ensureError(error);
|
|
67
|
+
}
|
|
68
|
+
return caughtError;
|
|
69
|
+
}
|
|
70
|
+
exports.executeAndReturnError = executeAndReturnError;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export type AnyFunction = (...args: any[]) =>
|
|
1
|
+
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
|
|
2
|
+
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
|
|
2
3
|
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
|
|
3
4
|
//# sourceMappingURL=function.d.ts.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getValueFromNestedKeys = void 0;
|
|
4
|
-
const error_1 = require("./error");
|
|
5
4
|
const object_1 = require("./object");
|
|
6
5
|
function getValueFromNestedKeys(inputObject, nestedKeys) {
|
|
7
6
|
/**
|
|
@@ -10,21 +9,15 @@ function getValueFromNestedKeys(inputObject, nestedKeys) {
|
|
|
10
9
|
* affect the external API of this function.
|
|
11
10
|
*/
|
|
12
11
|
const keyToAccess = nestedKeys[0];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
const currentValue = inputObject[keyToAccess];
|
|
18
|
-
if (nestedKeys.length > 1) {
|
|
19
|
-
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return currentValue;
|
|
23
|
-
}
|
|
12
|
+
if (!(0, object_1.typedHasProperty)(inputObject, keyToAccess)) {
|
|
13
|
+
return undefined;
|
|
24
14
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
const currentValue = inputObject[keyToAccess];
|
|
16
|
+
if (nestedKeys.length > 1) {
|
|
17
|
+
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return currentValue;
|
|
28
21
|
}
|
|
29
22
|
}
|
|
30
23
|
exports.getValueFromNestedKeys = getValueFromNestedKeys;
|
|
@@ -5,12 +5,11 @@ const error_1 = require("./error");
|
|
|
5
5
|
const object_1 = require("./object");
|
|
6
6
|
function wait(delayMs) {
|
|
7
7
|
const deferredPromiseWrapper = createDeferredPromiseWrapper();
|
|
8
|
-
if (delayMs
|
|
9
|
-
|
|
8
|
+
if (delayMs !== Infinity) {
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
deferredPromiseWrapper.resolve();
|
|
11
|
+
}, delayMs <= 0 ? 0 : delayMs);
|
|
10
12
|
}
|
|
11
|
-
setTimeout(() => {
|
|
12
|
-
deferredPromiseWrapper.resolve();
|
|
13
|
-
}, delayMs);
|
|
14
13
|
return deferredPromiseWrapper.promise;
|
|
15
14
|
}
|
|
16
15
|
exports.wait = wait;
|
|
@@ -57,6 +56,8 @@ function createDeferredPromiseWrapper() {
|
|
|
57
56
|
resolve = resolveCallback;
|
|
58
57
|
reject = rejectCallback;
|
|
59
58
|
});
|
|
59
|
+
// no way to test this edge case
|
|
60
|
+
// istanbul ignore next
|
|
60
61
|
if (!resolve || !reject) {
|
|
61
62
|
throw new Error(`Reject and resolve callbacks were not set by the promise constructor for ${createDeferredPromiseWrapper.name}.`);
|
|
62
63
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
3
|
+
* point, or comma.
|
|
4
|
+
*
|
|
5
|
+
* Default suffixes are:
|
|
6
|
+
*
|
|
7
|
+
* 'k', // thousand
|
|
8
|
+
* 'M', // million
|
|
9
|
+
* 'B', // billion
|
|
10
|
+
* 'T', // trillion
|
|
11
|
+
* 'P', // peta-, quadrillion
|
|
12
|
+
* 'E', // exa- quintillion
|
|
13
|
+
* 'Z', // zetta- sextillion
|
|
14
|
+
* 'Y', // yotta- septillion
|
|
15
|
+
*/
|
|
16
|
+
export declare function truncateNumber(originalValue: Readonly<unknown>, { customSuffixes, maxLength, }?: Partial<{
|
|
17
|
+
customSuffixes: ReadonlyArray<string> | undefined;
|
|
18
|
+
maxLength: number | undefined;
|
|
19
|
+
}>): string;
|
|
20
|
+
//# sourceMappingURL=truncate-number.d.ts.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.truncateNumber = void 0;
|
|
4
|
+
const common_number_1 = require("./common-number");
|
|
5
|
+
const common_string_1 = require("./common-string");
|
|
6
|
+
const regexp_1 = require("./regexp");
|
|
7
|
+
const defaultTruncationSuffixes = [
|
|
8
|
+
'k',
|
|
9
|
+
'M',
|
|
10
|
+
'B',
|
|
11
|
+
'T',
|
|
12
|
+
'P',
|
|
13
|
+
'E',
|
|
14
|
+
'Z',
|
|
15
|
+
'Y', // yotta- septillion
|
|
16
|
+
];
|
|
17
|
+
function combineBeforeAndAfterDot({ beforeDot, afterDot = '', maxLength, }) {
|
|
18
|
+
if (afterDot.length) {
|
|
19
|
+
const allowedAfterDotLength = maxLength -
|
|
20
|
+
beforeDot.length -
|
|
21
|
+
// 1 for the period
|
|
22
|
+
1;
|
|
23
|
+
if (allowedAfterDotLength > 0) {
|
|
24
|
+
const slicedAfterDot = afterDot.slice(0, allowedAfterDotLength);
|
|
25
|
+
// if slicedAfterDot is just a bunch of 0
|
|
26
|
+
if (!Number(slicedAfterDot)) {
|
|
27
|
+
return beforeDot;
|
|
28
|
+
}
|
|
29
|
+
return [
|
|
30
|
+
beforeDot,
|
|
31
|
+
slicedAfterDot,
|
|
32
|
+
].join('.');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return beforeDot;
|
|
36
|
+
}
|
|
37
|
+
function truncateBigNumber(numberAsString, suffixes, maxLength) {
|
|
38
|
+
const [beforeDot, afterDot,] = (0, common_string_1.typedSplit)(numberAsString, '.');
|
|
39
|
+
const withCommas = (0, common_number_1.addCommasToNumber)(beforeDot);
|
|
40
|
+
const truncationDepth = (0, regexp_1.safeMatch)(withCommas, /,/g).length;
|
|
41
|
+
const suffix = suffixes[truncationDepth - 1];
|
|
42
|
+
const [beforeComma, afterComma,] = (0, common_string_1.typedSplit)(withCommas, ',');
|
|
43
|
+
const trailing = [
|
|
44
|
+
afterComma,
|
|
45
|
+
afterDot,
|
|
46
|
+
].join('');
|
|
47
|
+
if (beforeComma.length + 1 > maxLength) {
|
|
48
|
+
// will look like 0.9M
|
|
49
|
+
const minimumString = [
|
|
50
|
+
'0.',
|
|
51
|
+
beforeComma[0],
|
|
52
|
+
suffixes[truncationDepth],
|
|
53
|
+
].join('');
|
|
54
|
+
return minimumString;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const combined = combineBeforeAndAfterDot({
|
|
58
|
+
beforeDot: beforeComma,
|
|
59
|
+
afterDot: trailing,
|
|
60
|
+
maxLength: maxLength - 1 /* -1 to account for the suffix*/,
|
|
61
|
+
});
|
|
62
|
+
return [
|
|
63
|
+
combined,
|
|
64
|
+
suffix,
|
|
65
|
+
].join('');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const minScientificNotationLength = '1e+'.length;
|
|
69
|
+
function truncateScientificNotation({ input, maxLength, }) {
|
|
70
|
+
const valueString = String(input);
|
|
71
|
+
const [beforeExponent, rawExponent,] = (0, common_string_1.typedSplit)(valueString, 'e');
|
|
72
|
+
const exponent = rawExponent.replace(/^[\-\+]/, '');
|
|
73
|
+
const plusOrMinus = rawExponent[0];
|
|
74
|
+
const eSuffix = [
|
|
75
|
+
'e',
|
|
76
|
+
plusOrMinus,
|
|
77
|
+
exponent,
|
|
78
|
+
].join('');
|
|
79
|
+
const [beforeDot, afterDot,] = (0, common_string_1.typedSplit)(beforeExponent, '.');
|
|
80
|
+
const minLength = exponent.length + minScientificNotationLength;
|
|
81
|
+
if (minLength === maxLength) {
|
|
82
|
+
// this will look like "4e+4" or "5e-234"
|
|
83
|
+
return [
|
|
84
|
+
beforeDot,
|
|
85
|
+
eSuffix,
|
|
86
|
+
].join('');
|
|
87
|
+
}
|
|
88
|
+
else if (minLength > maxLength) {
|
|
89
|
+
// in this case the number is either way too big or way to small for its exponent to fit within the max length so we just jump to 0 or Infinity
|
|
90
|
+
if (plusOrMinus === '-') {
|
|
91
|
+
return '0';
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return String(Infinity);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// in this case we have room to add some decimal values to the number
|
|
99
|
+
const beforeE = combineBeforeAndAfterDot({
|
|
100
|
+
afterDot,
|
|
101
|
+
beforeDot,
|
|
102
|
+
maxLength: maxLength - exponent.length + minScientificNotationLength,
|
|
103
|
+
});
|
|
104
|
+
return [
|
|
105
|
+
beforeE,
|
|
106
|
+
eSuffix,
|
|
107
|
+
].join('');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function handleSmallNumbers(numberAsString, maxLength) {
|
|
111
|
+
const [beforeDot, afterDot,] = (0, common_string_1.typedSplit)((0, common_number_1.addCommasToNumber)(numberAsString), '.');
|
|
112
|
+
if (beforeDot.length <= maxLength) {
|
|
113
|
+
return combineBeforeAndAfterDot({
|
|
114
|
+
beforeDot,
|
|
115
|
+
afterDot,
|
|
116
|
+
maxLength,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// in this case, the number is not small enough to be handled by this function
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
124
|
+
* point, or comma.
|
|
125
|
+
*
|
|
126
|
+
* Default suffixes are:
|
|
127
|
+
*
|
|
128
|
+
* 'k', // thousand
|
|
129
|
+
* 'M', // million
|
|
130
|
+
* 'B', // billion
|
|
131
|
+
* 'T', // trillion
|
|
132
|
+
* 'P', // peta-, quadrillion
|
|
133
|
+
* 'E', // exa- quintillion
|
|
134
|
+
* 'Z', // zetta- sextillion
|
|
135
|
+
* 'Y', // yotta- septillion
|
|
136
|
+
*/
|
|
137
|
+
function truncateNumber(originalValue, { customSuffixes = defaultTruncationSuffixes, maxLength = 6, } = {}) {
|
|
138
|
+
const inputNumber = (0, common_number_1.convertIntoNumber)(originalValue);
|
|
139
|
+
// handle edge cases
|
|
140
|
+
if (isNaN(inputNumber) || inputNumber === Infinity) {
|
|
141
|
+
return String(inputNumber);
|
|
142
|
+
}
|
|
143
|
+
// handle too big or too small edge cases
|
|
144
|
+
if ((0, common_number_1.doesRequireScientificNotation)(inputNumber)) {
|
|
145
|
+
return truncateScientificNotation({ input: inputNumber, maxLength });
|
|
146
|
+
}
|
|
147
|
+
const numberAsString = String(inputNumber);
|
|
148
|
+
const smallResult = handleSmallNumbers(numberAsString, maxLength);
|
|
149
|
+
if (smallResult != undefined) {
|
|
150
|
+
return smallResult;
|
|
151
|
+
}
|
|
152
|
+
return truncateBigNumber(numberAsString, customSuffixes, maxLength);
|
|
153
|
+
}
|
|
154
|
+
exports.truncateNumber = truncateNumber;
|
|
@@ -2,8 +2,8 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGen
|
|
|
2
2
|
type _TupleOf<ArrayElementGeneric, LengthGeneric extends number, FullArrayGeneric extends unknown[]> = FullArrayGeneric['length'] extends LengthGeneric ? FullArrayGeneric : _TupleOf<ArrayElementGeneric, LengthGeneric, [ArrayElementGeneric, ...FullArrayGeneric]>;
|
|
3
3
|
export type AtLeastTuple<ArrayElementGeneric, LengthGeneric extends number> = readonly [
|
|
4
4
|
...Tuple<ArrayElementGeneric, LengthGeneric>,
|
|
5
|
-
...ArrayElementGeneric[]
|
|
5
|
+
...(ArrayElementGeneric | undefined)[]
|
|
6
6
|
];
|
|
7
|
-
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
7
|
+
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=tuple.d.ts.map
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './augments/object';
|
|
|
12
12
|
export * from './augments/pick-deep';
|
|
13
13
|
export * from './augments/promise';
|
|
14
14
|
export * from './augments/regexp';
|
|
15
|
+
export * from './augments/truncate-number';
|
|
15
16
|
export * from './augments/tuple';
|
|
16
17
|
export * from './augments/type';
|
|
17
18
|
export * from './augments/type-of';
|
package/dist/cjs/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __exportStar(require("./augments/object"), exports);
|
|
|
28
28
|
__exportStar(require("./augments/pick-deep"), exports);
|
|
29
29
|
__exportStar(require("./augments/promise"), exports);
|
|
30
30
|
__exportStar(require("./augments/regexp"), exports);
|
|
31
|
+
__exportStar(require("./augments/truncate-number"), exports);
|
|
31
32
|
__exportStar(require("./augments/tuple"), exports);
|
|
32
33
|
__exportStar(require("./augments/type"), exports);
|
|
33
34
|
__exportStar(require("./augments/type-of"), exports);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const NaNString: string;
|
|
2
|
+
export declare function addCommasToNumber(input: number | string): string;
|
|
2
3
|
export declare function clamp(
|
|
3
4
|
/**
|
|
4
5
|
* This uses a destructured object so that consumers cannot get confused as to which input is
|
|
@@ -9,25 +10,6 @@ export declare function clamp(
|
|
|
9
10
|
min: number;
|
|
10
11
|
max: number;
|
|
11
12
|
}): number;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* point, or comma.
|
|
15
|
-
*
|
|
16
|
-
* Default suffixes are:
|
|
17
|
-
*
|
|
18
|
-
* '', // no suffix, numbers below 1000
|
|
19
|
-
* 'k', // thousand
|
|
20
|
-
* 'M', // million
|
|
21
|
-
* 'B', // billion
|
|
22
|
-
* 'T', // trillion
|
|
23
|
-
* 'P', // peta-, quadrillion
|
|
24
|
-
* 'E', // exa- quintillion
|
|
25
|
-
* 'Z', // zetta- sextillion
|
|
26
|
-
* 'Y', // yotta- septillion
|
|
27
|
-
*/
|
|
28
|
-
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
|
|
29
|
-
customSuffixes?: ReadonlyArray<string>;
|
|
30
|
-
suppressErrorLogging?: boolean;
|
|
31
|
-
customErrorLogCallback?: (...args: any) => void;
|
|
32
|
-
}): string;
|
|
13
|
+
export declare function convertIntoNumber(input: unknown): number;
|
|
14
|
+
export declare function doesRequireScientificNotation(input: number): boolean;
|
|
33
15
|
//# sourceMappingURL=common-number.d.ts.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { removeCommasFromNumberString
|
|
1
|
+
import { removeCommasFromNumberString } from './common-string';
|
|
2
2
|
import { safeMatch } from './regexp';
|
|
3
|
+
export const NaNString = String(NaN);
|
|
3
4
|
export function addCommasToNumber(input) {
|
|
5
|
+
if (typeof input === 'string' && isNaN(Number(input))) {
|
|
6
|
+
return NaNString;
|
|
7
|
+
}
|
|
4
8
|
const stringValue = String(input);
|
|
5
9
|
const [digits, decimalValues,] = stringValue.split('.');
|
|
6
10
|
const decimalString = decimalValues ? `.${decimalValues}` : '';
|
|
@@ -18,88 +22,17 @@ export function clamp(
|
|
|
18
22
|
{ value, min, max, }) {
|
|
19
23
|
return Math.max(Math.min(value, max), min);
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
''
|
|
23
|
-
|
|
24
|
-
'M',
|
|
25
|
-
'B',
|
|
26
|
-
'T',
|
|
27
|
-
'P',
|
|
28
|
-
'E',
|
|
29
|
-
'Z',
|
|
30
|
-
'Y', // yotta- septillion
|
|
31
|
-
];
|
|
32
|
-
function recursiveTruncation(value, recursionDepth = 0, decimalValues = '') {
|
|
33
|
-
var _a;
|
|
34
|
-
if (value.includes('e+')) {
|
|
35
|
-
throw new Error(`Number is too large, it cannot be truncated: ${value}`);
|
|
25
|
+
export function convertIntoNumber(input) {
|
|
26
|
+
if (typeof input === 'number') {
|
|
27
|
+
return input;
|
|
36
28
|
}
|
|
37
|
-
else if (
|
|
38
|
-
|
|
29
|
+
else if (typeof input === 'string') {
|
|
30
|
+
return Number(removeCommasFromNumberString(input));
|
|
39
31
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const amount = split[0];
|
|
43
|
-
if (amount.length > 3) {
|
|
44
|
-
decimalValues = amount.slice(-3);
|
|
45
|
-
return recursiveTruncation(amount.slice(0, -3), recursionDepth + 1, decimalValues);
|
|
32
|
+
else {
|
|
33
|
+
return Number(input);
|
|
46
34
|
}
|
|
47
|
-
return {
|
|
48
|
-
value: amount,
|
|
49
|
-
decimalValues,
|
|
50
|
-
recursionDepth,
|
|
51
|
-
};
|
|
52
35
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
56
|
-
* point, or comma.
|
|
57
|
-
*
|
|
58
|
-
* Default suffixes are:
|
|
59
|
-
*
|
|
60
|
-
* '', // no suffix, numbers below 1000
|
|
61
|
-
* 'k', // thousand
|
|
62
|
-
* 'M', // million
|
|
63
|
-
* 'B', // billion
|
|
64
|
-
* 'T', // trillion
|
|
65
|
-
* 'P', // peta-, quadrillion
|
|
66
|
-
* 'E', // exa- quintillion
|
|
67
|
-
* 'Z', // zetta- sextillion
|
|
68
|
-
* 'Y', // yotta- septillion
|
|
69
|
-
*/
|
|
70
|
-
export function truncateNumber(originalValue, { customSuffixes, suppressErrorLogging, customErrorLogCallback, } = {}) {
|
|
71
|
-
try {
|
|
72
|
-
const value = typeof originalValue === 'number'
|
|
73
|
-
? originalValue
|
|
74
|
-
: typeof originalValue === 'string'
|
|
75
|
-
? Number(removeCommasFromNumberString(originalValue))
|
|
76
|
-
: Number(originalValue);
|
|
77
|
-
if (isNaN(value)) {
|
|
78
|
-
throw new Error(`${originalValue} could not be converted into a number.`);
|
|
79
|
-
}
|
|
80
|
-
const stringValue = String(value);
|
|
81
|
-
const results = recursiveTruncation(stringValue);
|
|
82
|
-
const suffixes = customSuffixes !== null && customSuffixes !== void 0 ? customSuffixes : defaultTruncationSuffixes;
|
|
83
|
-
const suffix = suffixes[results.recursionDepth];
|
|
84
|
-
if (suffix === undefined) {
|
|
85
|
-
throw new Error(`Number is too large, could not truncate: ${value}`);
|
|
86
|
-
}
|
|
87
|
-
const decimalPlaces = maxDecimals - (results.value.length - 1) - suffix.length;
|
|
88
|
-
const decimalValues = results.decimalValues.replace(/0+$/, '').slice(0, decimalPlaces);
|
|
89
|
-
const withDecimal = decimalValues.length ? `.${decimalValues}` : '';
|
|
90
|
-
const combined = `${results.value}${withDecimal}${suffix}`;
|
|
91
|
-
if (combined.length > stringValue.length + 1) {
|
|
92
|
-
return addCommasToNumber(value);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
return combined;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
const errorCallback = customErrorLogCallback ? customErrorLogCallback : console.error;
|
|
100
|
-
if (!suppressErrorLogging) {
|
|
101
|
-
errorCallback(error);
|
|
102
|
-
}
|
|
103
|
-
return String(originalValue);
|
|
104
|
-
}
|
|
36
|
+
export function doesRequireScientificNotation(input) {
|
|
37
|
+
return String(input).includes('e');
|
|
105
38
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { NoInputsFunction } from './function';
|
|
1
2
|
import { AtLeastTuple } from './tuple';
|
|
3
|
+
import { UnPromise } from './type';
|
|
2
4
|
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;
|
|
3
5
|
export declare function combineErrors(errors: ReadonlyArray<never>): undefined;
|
|
4
6
|
export declare function combineErrors(errors: ReadonlyArray<Error>): Error | undefined;
|
|
@@ -6,4 +8,6 @@ export declare function combineErrors(errors?: undefined): undefined;
|
|
|
6
8
|
export declare function combineErrorMessages(errors?: ReadonlyArray<Error | string | undefined> | undefined): string;
|
|
7
9
|
export declare function extractErrorMessage(error: unknown): string;
|
|
8
10
|
export declare function ensureError(input: unknown): Error;
|
|
11
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
|
|
12
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
|
|
9
13
|
//# sourceMappingURL=error.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isTruthy } from './function';
|
|
2
|
+
import { isPromiseLike } from './promise';
|
|
2
3
|
export function combineErrors(errors) {
|
|
3
4
|
if (!errors || errors.length === 0) {
|
|
4
5
|
return undefined;
|
|
@@ -34,3 +35,28 @@ export function ensureError(input) {
|
|
|
34
35
|
return new Error(extractErrorMessage(input));
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
export function executeAndReturnError(callback) {
|
|
39
|
+
let caughtError;
|
|
40
|
+
try {
|
|
41
|
+
const result = callback();
|
|
42
|
+
if (isPromiseLike(result)) {
|
|
43
|
+
return new Promise(async (resolve) => {
|
|
44
|
+
try {
|
|
45
|
+
const output = await result;
|
|
46
|
+
return resolve(output);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
caughtError = ensureError(error);
|
|
50
|
+
}
|
|
51
|
+
return resolve(caughtError);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
caughtError = ensureError(error);
|
|
60
|
+
}
|
|
61
|
+
return caughtError;
|
|
62
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export type AnyFunction = (...args: any[]) =>
|
|
1
|
+
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
|
|
2
|
+
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
|
|
2
3
|
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
|
|
3
4
|
//# sourceMappingURL=function.d.ts.map
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { extractErrorMessage } from './error';
|
|
2
1
|
import { typedHasProperty } from './object';
|
|
3
2
|
export function getValueFromNestedKeys(inputObject, nestedKeys) {
|
|
4
3
|
/**
|
|
@@ -7,20 +6,14 @@ export function getValueFromNestedKeys(inputObject, nestedKeys) {
|
|
|
7
6
|
* affect the external API of this function.
|
|
8
7
|
*/
|
|
9
8
|
const keyToAccess = nestedKeys[0];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
|
-
const currentValue = inputObject[keyToAccess];
|
|
15
|
-
if (nestedKeys.length > 1) {
|
|
16
|
-
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
return currentValue;
|
|
20
|
-
}
|
|
9
|
+
if (!typedHasProperty(inputObject, keyToAccess)) {
|
|
10
|
+
return undefined;
|
|
21
11
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
const currentValue = inputObject[keyToAccess];
|
|
13
|
+
if (nestedKeys.length > 1) {
|
|
14
|
+
return getValueFromNestedKeys(currentValue, nestedKeys.slice(1));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return currentValue;
|
|
25
18
|
}
|
|
26
19
|
}
|
|
@@ -2,12 +2,11 @@ import { extractErrorMessage } from './error';
|
|
|
2
2
|
import { typedHasProperty } from './object';
|
|
3
3
|
export function wait(delayMs) {
|
|
4
4
|
const deferredPromiseWrapper = createDeferredPromiseWrapper();
|
|
5
|
-
if (delayMs
|
|
6
|
-
|
|
5
|
+
if (delayMs !== Infinity) {
|
|
6
|
+
setTimeout(() => {
|
|
7
|
+
deferredPromiseWrapper.resolve();
|
|
8
|
+
}, delayMs <= 0 ? 0 : delayMs);
|
|
7
9
|
}
|
|
8
|
-
setTimeout(() => {
|
|
9
|
-
deferredPromiseWrapper.resolve();
|
|
10
|
-
}, delayMs);
|
|
11
10
|
return deferredPromiseWrapper.promise;
|
|
12
11
|
}
|
|
13
12
|
export function isPromiseLike(input) {
|
|
@@ -50,6 +49,8 @@ export function createDeferredPromiseWrapper() {
|
|
|
50
49
|
resolve = resolveCallback;
|
|
51
50
|
reject = rejectCallback;
|
|
52
51
|
});
|
|
52
|
+
// no way to test this edge case
|
|
53
|
+
// istanbul ignore next
|
|
53
54
|
if (!resolve || !reject) {
|
|
54
55
|
throw new Error(`Reject and resolve callbacks were not set by the promise constructor for ${createDeferredPromiseWrapper.name}.`);
|
|
55
56
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
3
|
+
* point, or comma.
|
|
4
|
+
*
|
|
5
|
+
* Default suffixes are:
|
|
6
|
+
*
|
|
7
|
+
* 'k', // thousand
|
|
8
|
+
* 'M', // million
|
|
9
|
+
* 'B', // billion
|
|
10
|
+
* 'T', // trillion
|
|
11
|
+
* 'P', // peta-, quadrillion
|
|
12
|
+
* 'E', // exa- quintillion
|
|
13
|
+
* 'Z', // zetta- sextillion
|
|
14
|
+
* 'Y', // yotta- septillion
|
|
15
|
+
*/
|
|
16
|
+
export declare function truncateNumber(originalValue: Readonly<unknown>, { customSuffixes, maxLength, }?: Partial<{
|
|
17
|
+
customSuffixes: ReadonlyArray<string> | undefined;
|
|
18
|
+
maxLength: number | undefined;
|
|
19
|
+
}>): string;
|
|
20
|
+
//# sourceMappingURL=truncate-number.d.ts.map
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { addCommasToNumber, convertIntoNumber, doesRequireScientificNotation } from './common-number';
|
|
2
|
+
import { typedSplit } from './common-string';
|
|
3
|
+
import { safeMatch } from './regexp';
|
|
4
|
+
const defaultTruncationSuffixes = [
|
|
5
|
+
'k',
|
|
6
|
+
'M',
|
|
7
|
+
'B',
|
|
8
|
+
'T',
|
|
9
|
+
'P',
|
|
10
|
+
'E',
|
|
11
|
+
'Z',
|
|
12
|
+
'Y', // yotta- septillion
|
|
13
|
+
];
|
|
14
|
+
function combineBeforeAndAfterDot({ beforeDot, afterDot = '', maxLength, }) {
|
|
15
|
+
if (afterDot.length) {
|
|
16
|
+
const allowedAfterDotLength = maxLength -
|
|
17
|
+
beforeDot.length -
|
|
18
|
+
// 1 for the period
|
|
19
|
+
1;
|
|
20
|
+
if (allowedAfterDotLength > 0) {
|
|
21
|
+
const slicedAfterDot = afterDot.slice(0, allowedAfterDotLength);
|
|
22
|
+
// if slicedAfterDot is just a bunch of 0
|
|
23
|
+
if (!Number(slicedAfterDot)) {
|
|
24
|
+
return beforeDot;
|
|
25
|
+
}
|
|
26
|
+
return [
|
|
27
|
+
beforeDot,
|
|
28
|
+
slicedAfterDot,
|
|
29
|
+
].join('.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return beforeDot;
|
|
33
|
+
}
|
|
34
|
+
function truncateBigNumber(numberAsString, suffixes, maxLength) {
|
|
35
|
+
const [beforeDot, afterDot,] = typedSplit(numberAsString, '.');
|
|
36
|
+
const withCommas = addCommasToNumber(beforeDot);
|
|
37
|
+
const truncationDepth = safeMatch(withCommas, /,/g).length;
|
|
38
|
+
const suffix = suffixes[truncationDepth - 1];
|
|
39
|
+
const [beforeComma, afterComma,] = typedSplit(withCommas, ',');
|
|
40
|
+
const trailing = [
|
|
41
|
+
afterComma,
|
|
42
|
+
afterDot,
|
|
43
|
+
].join('');
|
|
44
|
+
if (beforeComma.length + 1 > maxLength) {
|
|
45
|
+
// will look like 0.9M
|
|
46
|
+
const minimumString = [
|
|
47
|
+
'0.',
|
|
48
|
+
beforeComma[0],
|
|
49
|
+
suffixes[truncationDepth],
|
|
50
|
+
].join('');
|
|
51
|
+
return minimumString;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const combined = combineBeforeAndAfterDot({
|
|
55
|
+
beforeDot: beforeComma,
|
|
56
|
+
afterDot: trailing,
|
|
57
|
+
maxLength: maxLength - 1 /* -1 to account for the suffix*/,
|
|
58
|
+
});
|
|
59
|
+
return [
|
|
60
|
+
combined,
|
|
61
|
+
suffix,
|
|
62
|
+
].join('');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const minScientificNotationLength = '1e+'.length;
|
|
66
|
+
function truncateScientificNotation({ input, maxLength, }) {
|
|
67
|
+
const valueString = String(input);
|
|
68
|
+
const [beforeExponent, rawExponent,] = typedSplit(valueString, 'e');
|
|
69
|
+
const exponent = rawExponent.replace(/^[\-\+]/, '');
|
|
70
|
+
const plusOrMinus = rawExponent[0];
|
|
71
|
+
const eSuffix = [
|
|
72
|
+
'e',
|
|
73
|
+
plusOrMinus,
|
|
74
|
+
exponent,
|
|
75
|
+
].join('');
|
|
76
|
+
const [beforeDot, afterDot,] = typedSplit(beforeExponent, '.');
|
|
77
|
+
const minLength = exponent.length + minScientificNotationLength;
|
|
78
|
+
if (minLength === maxLength) {
|
|
79
|
+
// this will look like "4e+4" or "5e-234"
|
|
80
|
+
return [
|
|
81
|
+
beforeDot,
|
|
82
|
+
eSuffix,
|
|
83
|
+
].join('');
|
|
84
|
+
}
|
|
85
|
+
else if (minLength > maxLength) {
|
|
86
|
+
// in this case the number is either way too big or way to small for its exponent to fit within the max length so we just jump to 0 or Infinity
|
|
87
|
+
if (plusOrMinus === '-') {
|
|
88
|
+
return '0';
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return String(Infinity);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// in this case we have room to add some decimal values to the number
|
|
96
|
+
const beforeE = combineBeforeAndAfterDot({
|
|
97
|
+
afterDot,
|
|
98
|
+
beforeDot,
|
|
99
|
+
maxLength: maxLength - exponent.length + minScientificNotationLength,
|
|
100
|
+
});
|
|
101
|
+
return [
|
|
102
|
+
beforeE,
|
|
103
|
+
eSuffix,
|
|
104
|
+
].join('');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function handleSmallNumbers(numberAsString, maxLength) {
|
|
108
|
+
const [beforeDot, afterDot,] = typedSplit(addCommasToNumber(numberAsString), '.');
|
|
109
|
+
if (beforeDot.length <= maxLength) {
|
|
110
|
+
return combineBeforeAndAfterDot({
|
|
111
|
+
beforeDot,
|
|
112
|
+
afterDot,
|
|
113
|
+
maxLength,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// in this case, the number is not small enough to be handled by this function
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
121
|
+
* point, or comma.
|
|
122
|
+
*
|
|
123
|
+
* Default suffixes are:
|
|
124
|
+
*
|
|
125
|
+
* 'k', // thousand
|
|
126
|
+
* 'M', // million
|
|
127
|
+
* 'B', // billion
|
|
128
|
+
* 'T', // trillion
|
|
129
|
+
* 'P', // peta-, quadrillion
|
|
130
|
+
* 'E', // exa- quintillion
|
|
131
|
+
* 'Z', // zetta- sextillion
|
|
132
|
+
* 'Y', // yotta- septillion
|
|
133
|
+
*/
|
|
134
|
+
export function truncateNumber(originalValue, { customSuffixes = defaultTruncationSuffixes, maxLength = 6, } = {}) {
|
|
135
|
+
const inputNumber = convertIntoNumber(originalValue);
|
|
136
|
+
// handle edge cases
|
|
137
|
+
if (isNaN(inputNumber) || inputNumber === Infinity) {
|
|
138
|
+
return String(inputNumber);
|
|
139
|
+
}
|
|
140
|
+
// handle too big or too small edge cases
|
|
141
|
+
if (doesRequireScientificNotation(inputNumber)) {
|
|
142
|
+
return truncateScientificNotation({ input: inputNumber, maxLength });
|
|
143
|
+
}
|
|
144
|
+
const numberAsString = String(inputNumber);
|
|
145
|
+
const smallResult = handleSmallNumbers(numberAsString, maxLength);
|
|
146
|
+
if (smallResult != undefined) {
|
|
147
|
+
return smallResult;
|
|
148
|
+
}
|
|
149
|
+
return truncateBigNumber(numberAsString, customSuffixes, maxLength);
|
|
150
|
+
}
|
|
@@ -2,8 +2,8 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGen
|
|
|
2
2
|
type _TupleOf<ArrayElementGeneric, LengthGeneric extends number, FullArrayGeneric extends unknown[]> = FullArrayGeneric['length'] extends LengthGeneric ? FullArrayGeneric : _TupleOf<ArrayElementGeneric, LengthGeneric, [ArrayElementGeneric, ...FullArrayGeneric]>;
|
|
3
3
|
export type AtLeastTuple<ArrayElementGeneric, LengthGeneric extends number> = readonly [
|
|
4
4
|
...Tuple<ArrayElementGeneric, LengthGeneric>,
|
|
5
|
-
...ArrayElementGeneric[]
|
|
5
|
+
...(ArrayElementGeneric | undefined)[]
|
|
6
6
|
];
|
|
7
|
-
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
7
|
+
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=tuple.d.ts.map
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './augments/object';
|
|
|
12
12
|
export * from './augments/pick-deep';
|
|
13
13
|
export * from './augments/promise';
|
|
14
14
|
export * from './augments/regexp';
|
|
15
|
+
export * from './augments/truncate-number';
|
|
15
16
|
export * from './augments/tuple';
|
|
16
17
|
export * from './augments/type';
|
|
17
18
|
export * from './augments/type-of';
|
package/dist/esm/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export * from './augments/object';
|
|
|
12
12
|
export * from './augments/pick-deep';
|
|
13
13
|
export * from './augments/promise';
|
|
14
14
|
export * from './augments/regexp';
|
|
15
|
+
export * from './augments/truncate-number';
|
|
15
16
|
export * from './augments/tuple';
|
|
16
17
|
export * from './augments/type';
|
|
17
18
|
export * from './augments/type-of';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const NaNString: string;
|
|
2
|
+
export declare function addCommasToNumber(input: number | string): string;
|
|
2
3
|
export declare function clamp(
|
|
3
4
|
/**
|
|
4
5
|
* This uses a destructured object so that consumers cannot get confused as to which input is
|
|
@@ -9,25 +10,6 @@ export declare function clamp(
|
|
|
9
10
|
min: number;
|
|
10
11
|
max: number;
|
|
11
12
|
}): number;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* point, or comma.
|
|
15
|
-
*
|
|
16
|
-
* Default suffixes are:
|
|
17
|
-
*
|
|
18
|
-
* '', // no suffix, numbers below 1000
|
|
19
|
-
* 'k', // thousand
|
|
20
|
-
* 'M', // million
|
|
21
|
-
* 'B', // billion
|
|
22
|
-
* 'T', // trillion
|
|
23
|
-
* 'P', // peta-, quadrillion
|
|
24
|
-
* 'E', // exa- quintillion
|
|
25
|
-
* 'Z', // zetta- sextillion
|
|
26
|
-
* 'Y', // yotta- septillion
|
|
27
|
-
*/
|
|
28
|
-
export declare function truncateNumber(originalValue: unknown, { customSuffixes, suppressErrorLogging, customErrorLogCallback, }?: {
|
|
29
|
-
customSuffixes?: ReadonlyArray<string>;
|
|
30
|
-
suppressErrorLogging?: boolean;
|
|
31
|
-
customErrorLogCallback?: (...args: any) => void;
|
|
32
|
-
}): string;
|
|
13
|
+
export declare function convertIntoNumber(input: unknown): number;
|
|
14
|
+
export declare function doesRequireScientificNotation(input: number): boolean;
|
|
33
15
|
//# sourceMappingURL=common-number.d.ts.map
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { NoInputsFunction } from './function';
|
|
1
2
|
import { AtLeastTuple } from './tuple';
|
|
3
|
+
import { UnPromise } from './type';
|
|
2
4
|
export declare function combineErrors(errors: AtLeastTuple<Error, 1>): Error;
|
|
3
5
|
export declare function combineErrors(errors: ReadonlyArray<never>): undefined;
|
|
4
6
|
export declare function combineErrors(errors: ReadonlyArray<Error>): Error | undefined;
|
|
@@ -6,4 +8,6 @@ export declare function combineErrors(errors?: undefined): undefined;
|
|
|
6
8
|
export declare function combineErrorMessages(errors?: ReadonlyArray<Error | string | undefined> | undefined): string;
|
|
7
9
|
export declare function extractErrorMessage(error: unknown): string;
|
|
8
10
|
export declare function ensureError(input: unknown): Error;
|
|
11
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction<PromiseLike<any>>>(callback: CallbackGeneric): Promise<Error | UnPromise<ReturnType<CallbackGeneric>>>;
|
|
12
|
+
export declare function executeAndReturnError<CallbackGeneric extends NoInputsFunction>(callback: CallbackGeneric): Error | ReturnType<CallbackGeneric>;
|
|
9
13
|
//# sourceMappingURL=error.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export type AnyFunction = (...args: any[]) =>
|
|
1
|
+
export type AnyFunction<ReturnGeneric = any> = (...args: any[]) => ReturnGeneric;
|
|
2
|
+
export type NoInputsFunction<ReturnGeneric = any> = () => ReturnGeneric;
|
|
2
3
|
export declare function isTruthy<T>(input: T): input is NonNullable<T>;
|
|
3
4
|
//# sourceMappingURL=function.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This truncates a number such that is will at a max have 6 characters including suffix, decimal
|
|
3
|
+
* point, or comma.
|
|
4
|
+
*
|
|
5
|
+
* Default suffixes are:
|
|
6
|
+
*
|
|
7
|
+
* 'k', // thousand
|
|
8
|
+
* 'M', // million
|
|
9
|
+
* 'B', // billion
|
|
10
|
+
* 'T', // trillion
|
|
11
|
+
* 'P', // peta-, quadrillion
|
|
12
|
+
* 'E', // exa- quintillion
|
|
13
|
+
* 'Z', // zetta- sextillion
|
|
14
|
+
* 'Y', // yotta- septillion
|
|
15
|
+
*/
|
|
16
|
+
export declare function truncateNumber(originalValue: Readonly<unknown>, { customSuffixes, maxLength, }?: Partial<{
|
|
17
|
+
customSuffixes: ReadonlyArray<string> | undefined;
|
|
18
|
+
maxLength: number | undefined;
|
|
19
|
+
}>): string;
|
|
20
|
+
//# sourceMappingURL=truncate-number.d.ts.map
|
|
@@ -2,8 +2,8 @@ export type Tuple<ArrayElementGeneric, LengthGeneric extends number> = LengthGen
|
|
|
2
2
|
type _TupleOf<ArrayElementGeneric, LengthGeneric extends number, FullArrayGeneric extends unknown[]> = FullArrayGeneric['length'] extends LengthGeneric ? FullArrayGeneric : _TupleOf<ArrayElementGeneric, LengthGeneric, [ArrayElementGeneric, ...FullArrayGeneric]>;
|
|
3
3
|
export type AtLeastTuple<ArrayElementGeneric, LengthGeneric extends number> = readonly [
|
|
4
4
|
...Tuple<ArrayElementGeneric, LengthGeneric>,
|
|
5
|
-
...ArrayElementGeneric[]
|
|
5
|
+
...(ArrayElementGeneric | undefined)[]
|
|
6
6
|
];
|
|
7
|
-
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
7
|
+
export declare function isLengthAtLeast<ArrayElementGeneric, LengthGeneric extends number>(array: ReadonlyArray<ArrayElementGeneric | undefined>, length: LengthGeneric): array is AtLeastTuple<ArrayElementGeneric, LengthGeneric>;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=tuple.d.ts.map
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './augments/object';
|
|
|
12
12
|
export * from './augments/pick-deep';
|
|
13
13
|
export * from './augments/promise';
|
|
14
14
|
export * from './augments/regexp';
|
|
15
|
+
export * from './augments/truncate-number';
|
|
15
16
|
export * from './augments/tuple';
|
|
16
17
|
export * from './augments/type';
|
|
17
18
|
export * from './augments/type-of';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augment-vir/common",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"homepage": "https://github.com/electrovir/augment-vir/tree/main/packages/common",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/electrovir/augment-vir/issues"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"test:coverage": "npm test"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"type-fest": "^3.5.
|
|
26
|
+
"type-fest": "^3.5.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"typescript": "^4.9.4"
|