forked from LedgerHQ/ledger-live-common
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathformatCurrencyUnit.js
144 lines (138 loc) · 4.22 KB
/
formatCurrencyUnit.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// @flow
import { BigNumber } from "bignumber.js";
import type { Unit } from "../types";
import { prefixFormat, suffixFormat } from "./localeUtility";
import { toLocaleString } from "./BigNumberToLocaleString";
const nonBreakableSpace = " ";
const defaultFormatOptions = {
locale: "en-EN",
// show the currency code
showCode: false,
// always show the sign, even if it's a positive value
alwaysShowSign: false,
// override showAllDigits of the unit
showAllDigits: false,
// disable the feature that only show significant digits
// and removes the negligible extra digits.
// (rounding is dynamically applied based on the value. higher value means more rounding)
disableRounding: false,
// enable or not the thousands grouping (e.g; 1,234.00)
useGrouping: true,
// this allow to increase the number of digits displayed
// even if the currency don't allow more than this (sub-cent)
// a value of 1 can display USD 0.006 for instance. 2 can display USD 0.0065
// NB even if you set 3, USD 4.50 will be display as USD 4.50 , not 4.5000 (extra zeros are not displayed)
subMagnitude: 0,
// discrete mode will hide amounts
discreet: false,
joinFragmentsSeparator: "",
};
type FormatFragment =
| { kind: "value", value: string }
| { kind: "sign", value: string }
| { kind: "code", value: string }
| { kind: "separator", value: string };
export function formatCurrencyUnitFragment(
unit: Unit,
value: BigNumber,
_options?: $Shape<typeof defaultFormatOptions>
): FormatFragment[] {
if (!BigNumber.isBigNumber(value)) {
console.warn("formatCurrencyUnit called with value=", value);
return [];
}
if (value.isNaN()) {
console.warn("formatCurrencyUnit called with NaN value!");
return [];
}
if (!value.isFinite()) {
console.warn("formatCurrencyUnit called with infinite value=", value);
return [];
}
const options = {};
for (let k in _options) {
// sanitize the undefined value
if (_options[k] !== undefined) {
options[k] = _options[k];
}
}
const {
showCode,
alwaysShowSign,
showAllDigits,
locale,
disableRounding,
useGrouping,
subMagnitude,
discreet,
} =
// $FlowFixMe
{
...defaultFormatOptions,
...unit,
...options,
};
const { magnitude, code } = unit;
const floatValue = value.div(BigNumber(10).pow(magnitude));
const floatValueAbs = floatValue.abs();
const minimumFractionDigits = showAllDigits ? magnitude : 0;
const maximumFractionDigits = disableRounding
? magnitude + subMagnitude
: Math.max(
minimumFractionDigits,
Math.max(
0,
// dynamic max number of digits based on the value itself. to only show significant part
Math.min(
4 - Math.round(Math.log10(floatValueAbs.toNumber())),
magnitude + subMagnitude,
8
)
)
);
const fragValueByKind = {
sign:
alwaysShowSign || floatValue.isNegative()
? floatValue.isNegative()
? "-"
: "+"
: null,
code: showCode ? code : null,
value: discreet
? "***"
: toLocaleString(floatValueAbs, locale, {
maximumFractionDigits,
minimumFractionDigits,
useGrouping,
}),
separator: nonBreakableSpace,
};
const frags: FormatFragment[] = [];
let nonSepIndex = -1;
let sepConsumed = true;
(unit.prefixCode ? prefixFormat : suffixFormat).forEach((kind) => {
const v = fragValueByKind[kind];
if (!v) return;
const isSep = kind === "separator";
if (sepConsumed && isSep) return;
sepConsumed = isSep;
if (!isSep) nonSepIndex = frags.length;
// $FlowFixMe
frags.push({ kind, value: v });
});
frags.splice(nonSepIndex + 1); // remove extra space at the end
return frags;
}
// simplification of formatCurrencyUnitFragment if no fragmented styles is needed
export function formatCurrencyUnit(
unit: Unit,
value: BigNumber,
options?: $Shape<typeof defaultFormatOptions>
): string {
const joinFragmentsSeparator =
(options && options.joinFragmentsSeparator) ||
defaultFormatOptions.joinFragmentsSeparator;
return formatCurrencyUnitFragment(unit, value, options)
.map((f) => f.value)
.join(joinFragmentsSeparator);
}