formatBalance withAll/withZero (#1703)

This commit is contained in:
Jaco
2023-01-11 15:45:19 +02:00
committed by GitHub
parent 955605b2b0
commit 39403fcfe7
3 changed files with 81 additions and 37 deletions
+8
View File
@@ -1,5 +1,13 @@
# CHANGELOG
## master
Changes:
- Add the `withAll` (default false) flag to `formatBalance` to format to max decimals
- Add the `withZero` (default true) flags to `formatBalance` to retain trailing zeros
## 10.2.3 Jan 7, 2023
Changes:
@@ -37,6 +37,24 @@ describe('formatBalance', (): void => {
).toEqual('123.4567 µUnit');
});
it('formats 123,456,789,000 (decimals=10, withAll=true)', (): void => {
expect(
formatBalance(TESTVAL, { decimals: 10, forceUnit: '-', withAll: true, withSi: true })
).toEqual('12.3456789000 Unit');
});
it('formats 123,456,789,000 (decimals=10, withAll=true, withZero=false)', (): void => {
expect(
formatBalance(TESTVAL, { decimals: 10, forceUnit: '-', withAll: true, withSi: true, withZero: false })
).toEqual('12.3456789 Unit');
});
it('formats 123,000,000,000 (decimals=9, withAll=true, withZero=false)', (): void => {
expect(
formatBalance('123000000000', { decimals: 9, forceUnit: '-', withAll: true, withSi: true, withZero: false })
).toEqual('123 Unit');
});
it('formats 123,456,789,000 (decimals=15, Compact)', (): void => {
const compact = {
something: 'else',
+55 -37
View File
@@ -29,7 +29,11 @@ interface Options {
*/
forceUnit?: string;
/**
* @description Format with SI, i.e. m/M/etc.
* @description Returns value using all available decimals
*/
withAll?: boolean;
/**
* @description Format with SI, i.e. m/M/etc. (default = true)
*/
withSi?: boolean;
/**
@@ -40,6 +44,10 @@ interface Options {
* @description Add the unit (useful in Balance formats)
*/
withUnit?: boolean | string;
/**
* @description Returns all trailing zeros, otherwise removes (default = true)
*/
withZero?: boolean;
}
interface BalanceFormatter {
@@ -57,35 +65,10 @@ const DEFAULT_UNIT = SI[SI_MID].text;
let defaultDecimals = DEFAULT_DECIMALS;
let defaultUnit = DEFAULT_UNIT;
function getUnits (si: SiDef, withSi: boolean, withSiFull: boolean, withUnit: boolean | string): string {
const unit = isBoolean(withUnit)
? SI[SI_MID].text
: withUnit;
return withSi || withSiFull
? si.value === '-'
? withUnit
? ` ${unit}`
: ''
: ` ${withSiFull ? `${si.text}${withUnit ? ' ' : ''}` : si.value}${withUnit ? unit : ''}`
: '';
}
function getPrePost (text: string, decimals: number, forceUnit?: string): [SiDef, string, string] {
// NOTE We start at midpoint (8) minus 1 - this means that values display as
// 123.456 instead of 0.123k (so always 6 relevant). Additionally we use ceil
// so there are at most 3 decimal before the decimal separator
const si = calcSi(text, decimals, forceUnit);
const mid = text.length - (decimals + si.power);
const prefix = text.substring(0, mid);
const padding = mid < 0 ? 0 - mid : 0;
const postfix = `${`${new Array(padding + 1).join('0')}${text}`.substring(mid < 0 ? 0 : mid)}0000`.substring(0, 4);
return [si, prefix || '0', postfix];
}
// Formats a string/number with <prefix>.<postfix><type> notation
function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | bigint | ExtToBn, { decimals = defaultDecimals, forceUnit, withSi = true, withSiFull = false, withUnit = true }: Options = {}): string {
function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | bigint | ExtToBn, { decimals = defaultDecimals, forceUnit, withAll = false, withSi = true, withSiFull = false, withUnit = true, withZero = true }: Options = {}): string {
// we only work with string inputs here - convert anything
// into the string-only value
let text = bnToBn(input).toString();
if (text.length === 0 || text === '0') {
@@ -101,22 +84,59 @@ function _formatBalance <ExtToBn extends ToBn> (input?: number | string | BN | b
text = text.substring(1);
}
const [si, prefix, postfix] = getPrePost(text, decimals, forceUnit);
const units = getUnits(si, withSi, withSiFull, withUnit);
// We start at midpoint (8) minus 1 - this means that values display as
// 123.4567 instead of 0.1234 k (so we always have the most relevant).
const si = calcSi(text, decimals, forceUnit);
const mid = text.length - (decimals + si.power);
const pre = mid <= 0 ? '0' : text.substring(0, mid);
return `${sign}${formatDecimal(prefix)}.${postfix}${units}`;
// get the post from the midpoint onward and then first add max decimals
// before trimming to the correct (calculated) amount of decimals again
let post = text
.padStart((mid < 0 ? 0 - mid : 0) + 1, '0')
.substring(mid < 0 ? 0 : mid)
.padEnd(withAll ? Math.max(decimals, 4) : 4, '0')
.substring(0, withAll ? Math.max(4, decimals + si.power) : 4);
// remove all trailing 0's (if required via flag)
if (!withZero) {
let end = post.length - 1;
// This looks inefficient, however it is better to do the checks and
// only make one final slice than it is to do it in multiples
do {
if (post[end] === '0') {
end--;
}
} while (post[end] === '0');
post = post.substring(0, end + 1);
}
// the display unit
const unit = isBoolean(withUnit)
? SI[SI_MID].text
: withUnit;
// format the units for display based on the flags
const units = withSi || withSiFull
? si.value === '-'
? withUnit
? ` ${unit}`
: ''
: ` ${withSiFull ? `${si.text}${withUnit ? ' ' : ''}` : si.value}${withUnit ? unit : ''}`
: '';
return `${sign}${formatDecimal(pre)}${post && `.${post}`}${units}`;
}
export const formatBalance = _formatBalance as BalanceFormatter;
// eslint-disable-next-line @typescript-eslint/unbound-method
formatBalance.calcSi = (text: string, decimals: number = defaultDecimals): SiDef =>
calcSi(text, decimals);
// eslint-disable-next-line @typescript-eslint/unbound-method
formatBalance.findSi = findSi;
// eslint-disable-next-line @typescript-eslint/unbound-method
formatBalance.getDefaults = (): Defaults => {
return {
decimals: defaultDecimals,
@@ -125,7 +145,6 @@ formatBalance.getDefaults = (): Defaults => {
};
// get allowable options to display in a dropdown
// eslint-disable-next-line @typescript-eslint/unbound-method
formatBalance.getOptions = (decimals: number = defaultDecimals): SiDef[] => {
return SI.filter(({ power }): boolean =>
power < 0
@@ -135,7 +154,6 @@ formatBalance.getOptions = (decimals: number = defaultDecimals): SiDef[] => {
};
// Sets the default decimals to use for formatting (ui-wide)
// eslint-disable-next-line @typescript-eslint/unbound-method
formatBalance.setDefaults = ({ decimals, unit }: SetDefaults): void => {
defaultDecimals = decimals === undefined
? defaultDecimals