@ledgerhq/coin-module-framework 1.1.0 → 2.0.1
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/.unimportedrc.json +0 -1
- package/CHANGELOG.md +12 -0
- package/lib/config.d.ts +3 -4
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +2 -2
- package/lib/config.js.map +1 -1
- package/lib/currencies/BigNumberToLocaleString.d.ts +7 -0
- package/lib/currencies/BigNumberToLocaleString.d.ts.map +1 -0
- package/lib/currencies/BigNumberToLocaleString.js +58 -0
- package/lib/currencies/BigNumberToLocaleString.js.map +1 -0
- package/lib/currencies/formatCurrencyUnit.d.ts +25 -1
- package/lib/currencies/formatCurrencyUnit.d.ts.map +1 -1
- package/lib/currencies/formatCurrencyUnit.js +130 -4
- package/lib/currencies/formatCurrencyUnit.js.map +1 -1
- package/lib/currencies/localeUtility.d.ts +8 -0
- package/lib/currencies/localeUtility.d.ts.map +1 -0
- package/lib/currencies/localeUtility.js +51 -0
- package/lib/currencies/localeUtility.js.map +1 -0
- package/lib/currencies/parseCurrencyUnit.d.ts +2 -1
- package/lib/currencies/parseCurrencyUnit.d.ts.map +1 -1
- package/lib/currencies/parseCurrencyUnit.js +9 -2
- package/lib/currencies/parseCurrencyUnit.js.map +1 -1
- package/lib-es/config.d.ts +3 -4
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js +2 -2
- package/lib-es/config.js.map +1 -1
- package/lib-es/currencies/BigNumberToLocaleString.d.ts +7 -0
- package/lib-es/currencies/BigNumberToLocaleString.d.ts.map +1 -0
- package/lib-es/currencies/BigNumberToLocaleString.js +54 -0
- package/lib-es/currencies/BigNumberToLocaleString.js.map +1 -0
- package/lib-es/currencies/formatCurrencyUnit.d.ts +25 -1
- package/lib-es/currencies/formatCurrencyUnit.d.ts.map +1 -1
- package/lib-es/currencies/formatCurrencyUnit.js +127 -1
- package/lib-es/currencies/formatCurrencyUnit.js.map +1 -1
- package/lib-es/currencies/localeUtility.d.ts +8 -0
- package/lib-es/currencies/localeUtility.d.ts.map +1 -0
- package/lib-es/currencies/localeUtility.js +48 -0
- package/lib-es/currencies/localeUtility.js.map +1 -0
- package/lib-es/currencies/parseCurrencyUnit.d.ts +2 -1
- package/lib-es/currencies/parseCurrencyUnit.d.ts.map +1 -1
- package/lib-es/currencies/parseCurrencyUnit.js +8 -1
- package/lib-es/currencies/parseCurrencyUnit.js.map +1 -1
- package/package.json +5 -5
- package/src/api/types.ts +1 -1
- package/src/config.ts +4 -5
- package/src/currencies/BigNumberToLocaleString.test.ts +164 -0
- package/src/currencies/BigNumberToLocaleString.ts +70 -0
- package/src/currencies/formatCurrencyUnit.test.ts +215 -0
- package/src/currencies/formatCurrencyUnit.ts +200 -6
- package/src/currencies/localeUtility.test.ts +22 -0
- package/src/currencies/localeUtility.ts +59 -0
- package/src/currencies/parseCurrencyUnit.test.ts +26 -0
- package/src/currencies/parseCurrencyUnit.ts +10 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/formatCurrencyUnit.test.ts
|
|
2
|
+
// Snapshot tests using @ledgerhq/cryptoassets removed (not available in this repo)
|
|
3
|
+
import { formatCurrencyUnit, formatCurrencyUnitFragment } from './formatCurrencyUnit'
|
|
4
|
+
import { BigNumber } from 'bignumber.js'
|
|
5
|
+
import type { Unit } from '../api/types'
|
|
6
|
+
|
|
7
|
+
describe('formatCurrencyUnit', () => {
|
|
8
|
+
describe('error handling', () => {
|
|
9
|
+
const unit: Unit = {
|
|
10
|
+
name: 'Test',
|
|
11
|
+
code: 'TST',
|
|
12
|
+
magnitude: 2,
|
|
13
|
+
showAllDigits: false,
|
|
14
|
+
prefixCode: false,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test('handles non-BigNumber', () => {
|
|
18
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
19
|
+
expect(formatCurrencyUnit(unit, null as unknown as BigNumber)).toBe('')
|
|
20
|
+
consoleSpy.mockRestore()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('handles NaN', () => {
|
|
24
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
25
|
+
expect(formatCurrencyUnit(unit, new BigNumber(NaN))).toBe('')
|
|
26
|
+
consoleSpy.mockRestore()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('handles Infinity', () => {
|
|
30
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
31
|
+
expect(formatCurrencyUnit(unit, new BigNumber(Infinity))).toBe('')
|
|
32
|
+
consoleSpy.mockRestore()
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('formatCurrencyUnit options', () => {
|
|
37
|
+
const unit: Unit = {
|
|
38
|
+
name: 'Test',
|
|
39
|
+
code: 'USD',
|
|
40
|
+
magnitude: 2,
|
|
41
|
+
showAllDigits: false,
|
|
42
|
+
prefixCode: false,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
test('prefixCode true', () => {
|
|
46
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
47
|
+
expect(formatCurrencyUnit(prefixUnit, new BigNumber('12345'), { showCode: true })).toBe(
|
|
48
|
+
'USD123.45'
|
|
49
|
+
)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('prefixCode false', () => {
|
|
53
|
+
expect(formatCurrencyUnit(unit, new BigNumber('12345'), { showCode: true })).toBe(
|
|
54
|
+
'123.45\u00A0USD'
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('negative with prefixCode', () => {
|
|
59
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
60
|
+
expect(formatCurrencyUnit(prefixUnit, new BigNumber('-12345'), { showCode: true })).toBe(
|
|
61
|
+
'-USD123.45'
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('negative with suffixCode', () => {
|
|
66
|
+
expect(formatCurrencyUnit(unit, new BigNumber('-12345'), { showCode: true })).toBe(
|
|
67
|
+
'-123.45\u00A0USD'
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('alwaysShowSign', () => {
|
|
72
|
+
expect(formatCurrencyUnit(unit, new BigNumber('12345'), { alwaysShowSign: true })).toBe(
|
|
73
|
+
'+123.45'
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('discreet mode', () => {
|
|
78
|
+
expect(formatCurrencyUnit(unit, new BigNumber('12345'), { discreet: true })).toBe('***')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('joinFragmentsSeparator', () => {
|
|
82
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
83
|
+
expect(
|
|
84
|
+
formatCurrencyUnit(prefixUnit, new BigNumber('12345'), {
|
|
85
|
+
showCode: true,
|
|
86
|
+
joinFragmentsSeparator: '-',
|
|
87
|
+
})
|
|
88
|
+
).toBe('USD-123.45')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('useGrouping false', () => {
|
|
92
|
+
expect(
|
|
93
|
+
formatCurrencyUnit(unit, new BigNumber('12345678'), { useGrouping: false })
|
|
94
|
+
).not.toContain(',')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('showAllDigits', () => {
|
|
98
|
+
const highMagUnit: Unit = { ...unit, magnitude: 4 }
|
|
99
|
+
expect(formatCurrencyUnit(highMagUnit, new BigNumber('12345'), { showAllDigits: true })).toBe(
|
|
100
|
+
'1.2345'
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test('filters undefined options', () => {
|
|
105
|
+
expect(
|
|
106
|
+
formatCurrencyUnit(unit, new BigNumber('12345'), { showCode: undefined, locale: 'en-US' })
|
|
107
|
+
).toBe('123.45')
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('formatCurrencyUnitFragment', () => {
|
|
112
|
+
const unit: Unit = {
|
|
113
|
+
name: 'Test',
|
|
114
|
+
code: 'USD',
|
|
115
|
+
magnitude: 2,
|
|
116
|
+
showAllDigits: false,
|
|
117
|
+
prefixCode: false,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
test('basic structure', () => {
|
|
121
|
+
const result = formatCurrencyUnitFragment(unit, new BigNumber('12345'))
|
|
122
|
+
expect(result.integerPart).toBe('123')
|
|
123
|
+
expect(result.decimalPart).toBe('45')
|
|
124
|
+
expect(result.decimalSeparator).toBe('.')
|
|
125
|
+
expect(result.currencyText).toBe('')
|
|
126
|
+
expect(result.currencyPosition).toBe('end')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('negative with prefixCode false', () => {
|
|
130
|
+
const result = formatCurrencyUnitFragment(unit, new BigNumber('-12345'), { showCode: true })
|
|
131
|
+
expect(result.integerPart).toBe('-123')
|
|
132
|
+
expect(result.currencyText).toBe('USD')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('negative with prefixCode true', () => {
|
|
136
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
137
|
+
const result = formatCurrencyUnitFragment(prefixUnit, new BigNumber('-12345'), {
|
|
138
|
+
showCode: true,
|
|
139
|
+
})
|
|
140
|
+
expect(result.integerPart).toBe('123')
|
|
141
|
+
expect(result.currencyText).toBe('-USD')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('negative with prefixCode true but no code', () => {
|
|
145
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
146
|
+
const result = formatCurrencyUnitFragment(prefixUnit, new BigNumber('-12345'), {
|
|
147
|
+
showCode: false,
|
|
148
|
+
})
|
|
149
|
+
expect(result.integerPart).toBe('-123')
|
|
150
|
+
expect(result.currencyText).toBe('')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('alwaysShowSign', () => {
|
|
154
|
+
const result = formatCurrencyUnitFragment(unit, new BigNumber('12345'), {
|
|
155
|
+
alwaysShowSign: true,
|
|
156
|
+
})
|
|
157
|
+
expect(result.integerPart).toBe('+123')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('no decimals', () => {
|
|
161
|
+
const result = formatCurrencyUnitFragment(unit, new BigNumber('10000'))
|
|
162
|
+
expect(result.integerPart).toBe('100')
|
|
163
|
+
expect(result.decimalPart).toBe('')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('french locale', () => {
|
|
167
|
+
const result = formatCurrencyUnitFragment(unit, new BigNumber('12345'), { locale: 'fr-FR' })
|
|
168
|
+
expect(result.decimalSeparator).toBe(',')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('error handling', () => {
|
|
172
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
173
|
+
const result = formatCurrencyUnitFragment(unit, null as unknown as BigNumber)
|
|
174
|
+
expect(result.integerPart).toBe('')
|
|
175
|
+
expect(result.decimalPart).toBe('')
|
|
176
|
+
consoleSpy.mockRestore()
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('error handling with prefixCode true', () => {
|
|
180
|
+
const prefixUnit: Unit = { ...unit, prefixCode: true }
|
|
181
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
|
|
182
|
+
const result = formatCurrencyUnitFragment(prefixUnit, new BigNumber(NaN))
|
|
183
|
+
expect(result.currencyPosition).toBe('start')
|
|
184
|
+
consoleSpy.mockRestore()
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
describe('coverage edge cases', () => {
|
|
189
|
+
test('disableRounding with subMagnitude', () => {
|
|
190
|
+
const unit: Unit = {
|
|
191
|
+
name: 'Test',
|
|
192
|
+
code: 'TST',
|
|
193
|
+
magnitude: 2,
|
|
194
|
+
showAllDigits: false,
|
|
195
|
+
prefixCode: false,
|
|
196
|
+
}
|
|
197
|
+
const value = new BigNumber('12345')
|
|
198
|
+
const result = formatCurrencyUnit(unit, value, { disableRounding: true, subMagnitude: 1 })
|
|
199
|
+
expect(result).toContain('123.45')
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
test('prefixCode true without code', () => {
|
|
203
|
+
const unit: Unit = {
|
|
204
|
+
name: 'Test',
|
|
205
|
+
code: 'USD',
|
|
206
|
+
magnitude: 2,
|
|
207
|
+
showAllDigits: false,
|
|
208
|
+
prefixCode: true,
|
|
209
|
+
}
|
|
210
|
+
const value = new BigNumber('12345')
|
|
211
|
+
const result = formatCurrencyUnit(unit, value, { showCode: false })
|
|
212
|
+
expect(result).toBe('123.45')
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
})
|
|
@@ -1,6 +1,200 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/formatCurrencyUnit.ts
|
|
2
|
+
import { BigNumber } from 'bignumber.js'
|
|
3
|
+
import { getSeparators } from './localeUtility'
|
|
4
|
+
import { toLocaleString } from './BigNumberToLocaleString'
|
|
5
|
+
import type { Unit } from '../api/types'
|
|
6
|
+
|
|
7
|
+
const nonBreakableSpace = '\u00A0'
|
|
8
|
+
const defaultFormatOptions = {
|
|
9
|
+
locale: 'en-EN',
|
|
10
|
+
showCode: false,
|
|
11
|
+
alwaysShowSign: false,
|
|
12
|
+
showAllDigits: false,
|
|
13
|
+
disableRounding: false,
|
|
14
|
+
useGrouping: true,
|
|
15
|
+
subMagnitude: 0,
|
|
16
|
+
discreet: false,
|
|
17
|
+
joinFragmentsSeparator: '',
|
|
18
|
+
dynamicSignificantDigits: 6,
|
|
19
|
+
staticSignificantDigits: 8,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type formatCurrencyUnitOptions = Partial<typeof defaultFormatOptions>
|
|
23
|
+
|
|
24
|
+
export type FormatterValue = {
|
|
25
|
+
integerPart: string
|
|
26
|
+
decimalPart: string
|
|
27
|
+
decimalSeparator: '.' | ','
|
|
28
|
+
currencyText: string
|
|
29
|
+
currencyPosition: 'start' | 'end'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type FormatState = {
|
|
33
|
+
value: string
|
|
34
|
+
sign: string | null
|
|
35
|
+
code: string | null
|
|
36
|
+
decimalSeparator: '.' | ','
|
|
37
|
+
currencyPosition: 'start' | 'end'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ResolvedFormatOptions = typeof defaultFormatOptions & Unit
|
|
41
|
+
|
|
42
|
+
const buildFormatState = (
|
|
43
|
+
unit: Unit,
|
|
44
|
+
value: BigNumber,
|
|
45
|
+
_options?: formatCurrencyUnitOptions
|
|
46
|
+
): FormatState => {
|
|
47
|
+
const emptyState = (): FormatState => ({
|
|
48
|
+
value: '',
|
|
49
|
+
sign: null,
|
|
50
|
+
code: null,
|
|
51
|
+
decimalSeparator: '.',
|
|
52
|
+
currencyPosition: unit.prefixCode ? 'start' : 'end',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (!BigNumber.isBigNumber(value)) {
|
|
56
|
+
console.warn('formatCurrencyUnit called with value=', value)
|
|
57
|
+
return emptyState()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (value.isNaN()) {
|
|
61
|
+
console.warn('formatCurrencyUnit called with NaN value!')
|
|
62
|
+
return emptyState()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!value.isFinite()) {
|
|
66
|
+
console.warn('formatCurrencyUnit called with infinite value=', value)
|
|
67
|
+
return emptyState()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const options: Record<string, unknown> = {}
|
|
71
|
+
|
|
72
|
+
if (_options) {
|
|
73
|
+
let k: keyof formatCurrencyUnitOptions
|
|
74
|
+
for (k in _options) {
|
|
75
|
+
const optionValue = _options[k]
|
|
76
|
+
if (optionValue !== undefined) {
|
|
77
|
+
options[k] = optionValue
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const resolvedOptions: ResolvedFormatOptions = {
|
|
83
|
+
...defaultFormatOptions,
|
|
84
|
+
...unit,
|
|
85
|
+
...options,
|
|
86
|
+
}
|
|
87
|
+
const {
|
|
88
|
+
showCode,
|
|
89
|
+
alwaysShowSign,
|
|
90
|
+
showAllDigits,
|
|
91
|
+
locale,
|
|
92
|
+
disableRounding,
|
|
93
|
+
useGrouping,
|
|
94
|
+
subMagnitude,
|
|
95
|
+
discreet,
|
|
96
|
+
dynamicSignificantDigits,
|
|
97
|
+
staticSignificantDigits,
|
|
98
|
+
} = resolvedOptions
|
|
99
|
+
const { magnitude, code } = unit
|
|
100
|
+
const floatValue = value.div(new BigNumber(10).pow(magnitude))
|
|
101
|
+
const floatValueAbs = floatValue.abs()
|
|
102
|
+
const minimumFractionDigits = showAllDigits ? magnitude : 0
|
|
103
|
+
const maximumFractionDigits = disableRounding
|
|
104
|
+
? magnitude + subMagnitude
|
|
105
|
+
: Math.max(
|
|
106
|
+
minimumFractionDigits,
|
|
107
|
+
Math.max(
|
|
108
|
+
0,
|
|
109
|
+
Math.min(
|
|
110
|
+
dynamicSignificantDigits - Math.ceil(Math.log(floatValueAbs.toNumber()) / Math.log(10)),
|
|
111
|
+
magnitude + subMagnitude,
|
|
112
|
+
staticSignificantDigits
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
const sign =
|
|
117
|
+
alwaysShowSign || floatValue.isNegative() ? (floatValue.isNegative() ? '-' : '+') : null
|
|
118
|
+
const formattedValue = discreet
|
|
119
|
+
? '***'
|
|
120
|
+
: toLocaleString(floatValueAbs, locale, {
|
|
121
|
+
maximumFractionDigits,
|
|
122
|
+
minimumFractionDigits,
|
|
123
|
+
useGrouping,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const separators = getSeparators(locale)
|
|
127
|
+
const decimalSeparator = separators.decimal === ',' ? ',' : '.'
|
|
128
|
+
const currencyPosition = unit.prefixCode ? 'start' : 'end'
|
|
129
|
+
return {
|
|
130
|
+
value: formattedValue,
|
|
131
|
+
sign,
|
|
132
|
+
code: showCode ? code : null,
|
|
133
|
+
decimalSeparator,
|
|
134
|
+
currencyPosition,
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const formatCurrencyUnitFragment = (
|
|
139
|
+
unit: Unit,
|
|
140
|
+
value: BigNumber,
|
|
141
|
+
options?: formatCurrencyUnitOptions
|
|
142
|
+
): FormatterValue => {
|
|
143
|
+
const {
|
|
144
|
+
value: formattedValue,
|
|
145
|
+
sign,
|
|
146
|
+
code,
|
|
147
|
+
decimalSeparator,
|
|
148
|
+
currencyPosition,
|
|
149
|
+
} = buildFormatState(unit, value, options)
|
|
150
|
+
const hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1
|
|
151
|
+
const [integerPartRaw, decimalPartRaw] = hasDecimals
|
|
152
|
+
? formattedValue.split(decimalSeparator)
|
|
153
|
+
: [formattedValue, '']
|
|
154
|
+
|
|
155
|
+
let integerPart = integerPartRaw
|
|
156
|
+
const decimalPart = decimalPartRaw || ''
|
|
157
|
+
let currencyText = code || ''
|
|
158
|
+
|
|
159
|
+
if (sign) {
|
|
160
|
+
if (currencyPosition === 'start' && currencyText) {
|
|
161
|
+
currencyText = `${sign}${currencyText}`
|
|
162
|
+
} else {
|
|
163
|
+
integerPart = `${sign}${integerPart}`
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
integerPart,
|
|
169
|
+
decimalPart,
|
|
170
|
+
decimalSeparator,
|
|
171
|
+
currencyText,
|
|
172
|
+
currencyPosition,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const formatCurrencyUnit = (
|
|
177
|
+
unit: Unit,
|
|
178
|
+
value: BigNumber,
|
|
179
|
+
options?: formatCurrencyUnitOptions
|
|
180
|
+
): string => {
|
|
181
|
+
const joinFragmentsSeparator =
|
|
182
|
+
(options && options.joinFragmentsSeparator) || defaultFormatOptions.joinFragmentsSeparator
|
|
183
|
+
const { value: formattedValue, sign, code } = buildFormatState(unit, value, options)
|
|
184
|
+
const parts: string[] = []
|
|
185
|
+
|
|
186
|
+
if (unit.prefixCode) {
|
|
187
|
+
if (sign) parts.push(sign)
|
|
188
|
+
if (code) parts.push(code)
|
|
189
|
+
parts.push(formattedValue)
|
|
190
|
+
} else {
|
|
191
|
+
if (sign) parts.push(sign)
|
|
192
|
+
parts.push(formattedValue)
|
|
193
|
+
if (code) {
|
|
194
|
+
parts.push(nonBreakableSpace)
|
|
195
|
+
parts.push(code)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return parts.join(joinFragmentsSeparator)
|
|
200
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/localeUtility.test.ts
|
|
2
|
+
import { getSeparators } from './localeUtility'
|
|
3
|
+
|
|
4
|
+
describe('localeUtility', () => {
|
|
5
|
+
test('getSeparators with known locale in staticFallback', () => {
|
|
6
|
+
const result = getSeparators('en')
|
|
7
|
+
expect(result.decimal).toBe('.')
|
|
8
|
+
expect(result.thousands).toBe(',')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('getSeparators with locale not in staticFallback', () => {
|
|
12
|
+
const result = getSeparators('it')
|
|
13
|
+
expect(result.decimal).toBeDefined()
|
|
14
|
+
expect(result.thousands).toBeDefined()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('getFallback uses en when locale not in staticFallback', () => {
|
|
18
|
+
const result = getSeparators('de')
|
|
19
|
+
expect(result.decimal).toBeDefined()
|
|
20
|
+
expect(result.thousands).toBeDefined()
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/localeUtility.ts
|
|
2
|
+
const memoize = <T extends (arg: string) => ReturnType<T>>(fn: T): T => {
|
|
3
|
+
const cache: Record<string, ReturnType<T>> = {}
|
|
4
|
+
return ((arg: string) => {
|
|
5
|
+
if (!(arg in cache)) {
|
|
6
|
+
cache[arg] = fn(arg)
|
|
7
|
+
}
|
|
8
|
+
return cache[arg]
|
|
9
|
+
}) as T
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const options = {
|
|
13
|
+
style: 'currency' as const,
|
|
14
|
+
currency: 'USD',
|
|
15
|
+
}
|
|
16
|
+
const localeNotAvailable = (1.2).toLocaleString('en', options) !== '$1.20'
|
|
17
|
+
|
|
18
|
+
const getFallback = (locale: string) =>
|
|
19
|
+
staticFallback[Object.prototype.hasOwnProperty.call(staticFallback, locale) ? locale : 'en']
|
|
20
|
+
|
|
21
|
+
const staticFallback: Record<string, string[]> = {
|
|
22
|
+
en: ['-$1.00', '10,000.2'],
|
|
23
|
+
es: ['-1,00 US$', '10.000,2'],
|
|
24
|
+
fr: ['-1,00 $US', '10 000,2'],
|
|
25
|
+
ja: ['-US$1.00', '10,000.2'],
|
|
26
|
+
ko: ['-US$1.00', '10,000.2'],
|
|
27
|
+
ru: ['-1,00 $', '10 000,2'],
|
|
28
|
+
zh: ['-US$1.00', '10,000.2'],
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const prefixFormat = ['sign', 'code', 'value'] as const
|
|
32
|
+
export const suffixFormat = ['sign', 'value', 'separator', 'code'] as const
|
|
33
|
+
|
|
34
|
+
export type GetSeparators = (locale: string) => {
|
|
35
|
+
decimal: string | null | undefined
|
|
36
|
+
thousands: string | null | undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const getSeparators: GetSeparators = memoize((locale) => {
|
|
40
|
+
const res = localeNotAvailable ? getFallback(locale)[1] : (10000.2).toLocaleString(locale)
|
|
41
|
+
let decimal
|
|
42
|
+
let thousands
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < res.length; i++) {
|
|
45
|
+
const c = res[i]
|
|
46
|
+
if (/[0-9]/.test(c)) continue
|
|
47
|
+
|
|
48
|
+
if (!thousands) {
|
|
49
|
+
thousands = c
|
|
50
|
+
} else {
|
|
51
|
+
decimal = c
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
decimal,
|
|
57
|
+
thousands,
|
|
58
|
+
}
|
|
59
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/parseCurrencyUnit.test.ts
|
|
2
|
+
import { BigNumber } from 'bignumber.js'
|
|
3
|
+
import type { Unit } from '../api/types'
|
|
4
|
+
import { parseCurrencyUnit } from './parseCurrencyUnit'
|
|
5
|
+
|
|
6
|
+
const unit: Unit = {
|
|
7
|
+
name: 'Test Unit',
|
|
8
|
+
code: 'TST',
|
|
9
|
+
magnitude: 2,
|
|
10
|
+
showAllDigits: false,
|
|
11
|
+
prefixCode: false,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('parseCurrencyUnit', () => {
|
|
15
|
+
test('parses dot decimals', () => {
|
|
16
|
+
expect(parseCurrencyUnit(unit, '1.23')).toEqual(new BigNumber(123))
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('parses comma decimals', () => {
|
|
20
|
+
expect(parseCurrencyUnit(unit, '1,23')).toEqual(new BigNumber(123))
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('returns zero on invalid input', () => {
|
|
24
|
+
expect(parseCurrencyUnit(unit, 'invalid')).toEqual(new BigNumber(0))
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
// Forked from @ledgerhq/live-currency-format/src/parseCurrencyUnit.ts
|
|
2
|
+
import type { Unit } from '../api/types'
|
|
3
|
+
import { BigNumber } from 'bignumber.js'
|
|
4
|
+
|
|
5
|
+
export const parseCurrencyUnit = (unit: Unit, valueString: string): BigNumber => {
|
|
6
|
+
const str = valueString.replace(/,/g, '.')
|
|
7
|
+
const value = new BigNumber(str)
|
|
8
|
+
if (value.isNaN()) return new BigNumber(0)
|
|
9
|
+
return value.times(new BigNumber(10).pow(unit.magnitude)).integerValue()
|
|
10
|
+
}
|