import BigNumber from 'bignumber.js'; const EXPONENT_SEPARATOR = 'e'; const SIGNIFICAND_DECIMAL_POINT = '.'; export const NEGATIVE_SIGN = '-'; export const BLANK_DIGIT = '0'; // must be a value where Number(BLANK_DIGIT) === 0 export type Numeric = number | bigint | string | BigNumber export type Group = [string, BigNumber] export const normalizeNumeric = (x: Numeric): string => { try { switch (typeof x) { case 'number': return new BigNumber(x).toString(10); case 'bigint': return x.toString(10); case 'string': // TODO assume not all strings follow a correct format return x.trim(); // return new BigNumber(x).toString(10) case 'object': return x.toString(10); default: break; } } catch { throw new RangeError('Not a valid numeric value in the current locale.'); } throw new TypeError('Not a valid numeric value in any locale.'); }; export const deconstructNumeric = (x: string) => { const absolute = x.replaceAll(NEGATIVE_SIGN, ''); if (!absolute.includes(EXPONENT_SEPARATOR)) { return { exponent: new BigNumber(absolute.length - 1), significandDigits: absolute, }; } const [significandStrExp, exponentStr] = absolute.split(EXPONENT_SEPARATOR); const [integral] = significandStrExp.split(SIGNIFICAND_DECIMAL_POINT); return { exponent: new BigNumber(exponentStr).plus(integral.length - 1), significandDigits: significandStrExp.replaceAll(SIGNIFICAND_DECIMAL_POINT, ''), }; }; export const createBlankDigits = (grouping: number) => new Array(grouping).fill(BLANK_DIGIT).join(''); export const groupDigits = (significandStr: string, exponent: BigNumber, grouping: number) => { const blankDigits = createBlankDigits(grouping); return significandStr .split('') .reduceRight( (theGroups, c, i): any => { const currentGroupIndex = exponent.minus(i).dividedToIntegerBy(grouping).minus(1); const [lastGroup = [blankDigits, currentGroupIndex.plus(1)] as Group] = theGroups; const [digits, groupIndex] = lastGroup; const currentPlaceValue = exponent.minus(i).mod(grouping); if (currentPlaceValue.eq(0)) { return [[`${blankDigits.slice(0, -c.length)}${c}`, currentGroupIndex.plus(1)], ...theGroups]; } const currentDigitStringIndex = new BigNumber(grouping).minus(1).minus(currentPlaceValue).toNumber(); const newDigits = digits.slice( 0, currentDigitStringIndex, ) + c + digits.slice(currentDigitStringIndex + c.length); return [[newDigits, groupIndex] as Group, ...theGroups.slice(1)]; }, [] as Group[], ); };