formatBalance withAll/withZero (#1703)
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user