@coingecko/cryptoformat 0.8.2 → 0.8.3

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.
@@ -1,524 +0,0 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = global || self, factory(global.cryptoformat = {}));
5
- }(this, function (exports) { 'use strict';
6
-
7
- // A map of supported currency codes to currency symbols.
8
- const supportedCurrencySymbols = {
9
- BTC: "₿",
10
- ETH: "Ξ",
11
- USD: "$",
12
- CAD: "C$",
13
- GBP: "£",
14
- EUR: "€",
15
- CHF: "Fr.",
16
- SEK: "kr",
17
- JPY: "¥",
18
- CNY: "¥",
19
- INR: "₹",
20
- RUB: "₽",
21
- AUD: "A$",
22
- HKD: "HK$",
23
- SGD: "S$",
24
- TWD: "NT$",
25
- BRL: "R$",
26
- KRW: "₩",
27
- ZAR: "R",
28
- MYR: "RM",
29
- IDR: "Rp",
30
- NZD: "NZ$",
31
- MXN: "MX$",
32
- PHP: "₱",
33
- DKK: "kr.",
34
- PLN: "zł",
35
- AED: "DH",
36
- ARS: "$",
37
- CLP: "CLP",
38
- CZK: "Kč",
39
- HUF: "Ft",
40
- ILS: "₪",
41
- KWD: "KD",
42
- LKR: "Rs",
43
- NOK: "kr",
44
- PKR: "₨",
45
- SAR: "SR",
46
- THB: "฿",
47
- TRY: "₺",
48
- XAU: "XAU",
49
- XAG: "XAG",
50
- XDR: "XDR",
51
- };
52
-
53
- // A map of override objects to apply.
54
- // Format:
55
- // { location: { start: Boolean, end: Boolean }, forLocales: { <locale>: Boolean } }
56
- const symbolOverrides = {
57
- MYR: { location: { start: true }, forLocales: { en: true } },
58
- SGD: { location: { start: true }, forLocales: { en: true } },
59
- PHP: { location: { start: true }, forLocales: { en: true } },
60
- BTC: { location: { start: true }, forLocales: { en: true } },
61
- ETH: { location: { start: true }, forLocales: { en: true } },
62
- };
63
-
64
- // Feature detection for Intl.NumberFormat
65
- function IntlNumberFormatSupported() {
66
- return !!(
67
- typeof Intl == "object" &&
68
- Intl &&
69
- typeof Intl.NumberFormat == "function"
70
- );
71
- }
72
-
73
- function isBTCETH(isoCode) {
74
- return isoCode === "BTC" || isoCode === "ETH";
75
- }
76
-
77
- function isCrypto(isoCode) {
78
- return isBTCETH(isoCode) || supportedCurrencySymbols[isoCode] == null;
79
- }
80
-
81
- // Function to transform decimal trailing zeroes to exponent
82
- function decimalTrailingZeroesToExponent(formattedCurrency, maximumDecimalTrailingZeroes) {
83
- const decimalTrailingZeroesPattern = new RegExp(`(\\.|,)(0{${maximumDecimalTrailingZeroes + 1},})(?=[1-9]?)`);
84
-
85
- return formattedCurrency.replace(
86
- decimalTrailingZeroesPattern,
87
- (_match, separator, decimalTrailingZeroes) => `${separator}0<sub title=\"${formattedCurrency}\">${decimalTrailingZeroes.length}</sub>`,
88
- )
89
- }
90
-
91
- // Function to transform the output from Intl.NumberFormat#format
92
- function formatCurrencyOverride(formattedCurrency, locale = "en", maximumDecimalTrailingZeroes) {
93
- if (typeof maximumDecimalTrailingZeroes !== "undefined") {
94
- formattedCurrency = decimalTrailingZeroesToExponent(formattedCurrency, maximumDecimalTrailingZeroes);
95
- }
96
-
97
- // If currency code remains in front
98
- const currencyCodeFrontMatch = formattedCurrency.match(/^[A-Z]{3}\s?/);
99
- if (currencyCodeFrontMatch != null) {
100
- const code = currencyCodeFrontMatch[0].trim(); // trim possible trailing space
101
-
102
- // Replace currency code with symbol if whitelisted.
103
- const overrideObj = symbolOverrides[code];
104
- if (
105
- overrideObj &&
106
- overrideObj.location.start &&
107
- overrideObj.forLocales[locale]
108
- ) {
109
- return formattedCurrency.replace(
110
- currencyCodeFrontMatch[0],
111
- supportedCurrencySymbols[code]
112
- );
113
- } else {
114
- return formattedCurrency;
115
- }
116
- }
117
-
118
- // If currency code is at the back
119
- const currencyCodeBackMatch = formattedCurrency.match(/[A-Z]{3}$/);
120
- if (currencyCodeBackMatch != null) {
121
- const code = currencyCodeBackMatch[0];
122
-
123
- // Replace currency code with symbol if whitelisted.
124
- const overrideObj = symbolOverrides[code];
125
- if (
126
- overrideObj &&
127
- overrideObj.location.end &&
128
- overrideObj.forLocales[locale]
129
- ) {
130
- return formattedCurrency.replace(code, supportedCurrencySymbols[code]);
131
- } else {
132
- return formattedCurrency;
133
- }
134
- }
135
-
136
- return formattedCurrency;
137
- }
138
-
139
- // Generates a formatter from Intl.NumberFormat
140
- function generateIntlNumberFormatter(isoCode, locale, numDecimals, numSigFig) {
141
- try {
142
- const params = {
143
- style: "currency",
144
- currency: isoCode,
145
- currencyDisplay: "symbol",
146
- };
147
- if (numDecimals !== undefined) {
148
- params.minimumFractionDigits = numDecimals;
149
- params.maximumFractionDigits = numDecimals;
150
- } else if (numSigFig !== undefined) {
151
- params.maximumSignificantDigits = numSigFig;
152
- }
153
- return new Intl.NumberFormat(locale, params);
154
- } catch (e) {
155
- // Unsupported currency, etc.
156
- // Use primitive fallback
157
- return generateFallbackFormatter(isoCode, locale, numDecimals, numSigFig);
158
- }
159
- }
160
-
161
- // Generates a primitive fallback formatter with no symbol support.
162
- function generateFallbackFormatter(isoCode, locale, numDecimals = 2, maximumSignificantDigits = 4) {
163
- isoCode = isoCode.toUpperCase();
164
-
165
- if (numDecimals > 2) {
166
- return {
167
- format: (value) => {
168
- return isCrypto(isoCode)
169
- ? `${value.toFixed(numDecimals)} ${isoCode}`
170
- : `${isoCode} ${value.toFixed(numDecimals)}`;
171
- },
172
- };
173
- } else {
174
- return {
175
- format: (value) => {
176
- let formattedValue = value;
177
- // try using Intl.NumberFormat when possible to support max significant digits
178
- try {
179
- formattedValue = new Intl.NumberFormat(locale, { maximumSignificantDigits }).format(value);
180
- } catch (e) {}
181
-
182
- return isCrypto(isoCode)
183
- ? `${formattedValue.toLocaleString(locale)} ${isoCode}`
184
- : `${isoCode} ${formattedValue.toLocaleString(locale)}`;
185
- },
186
- };
187
- }
188
- }
189
-
190
- function generateAbbreviatedFormatter(isoCode, locale) {
191
- // Show regular numbers if no Intl.NumberFormat support.
192
- if (!IntlNumberFormatSupported()) {
193
- return generateFallbackFormatter(isoCode, locale, 0);
194
- }
195
-
196
- let numberFormatOptions = { style: "decimal", notation: "compact", minimumFractionDigits: 0, maximumFractionDigits: 3 };
197
-
198
- // Currency symbol is supported if currency is Fiat/BTC/ETH.
199
- if (!isCrypto(isoCode) || isBTCETH(isoCode)) {
200
- numberFormatOptions.style = "currency";
201
- numberFormatOptions.currency = isoCode;
202
- }
203
-
204
- return new Intl.NumberFormat(locale, numberFormatOptions);
205
- }
206
-
207
- function generateFormatter(isoCode, locale, numDecimals, numSigFig) {
208
- const isNumberFormatSupported = IntlNumberFormatSupported();
209
-
210
- const useIntlNumberFormatter =
211
- isNumberFormatSupported && (!isCrypto(isoCode) || isBTCETH(isoCode));
212
- return useIntlNumberFormatter
213
- ? generateIntlNumberFormatter(isoCode, locale, numDecimals, numSigFig)
214
- : generateFallbackFormatter(isoCode, locale, numDecimals, numSigFig);
215
- }
216
-
217
- // State variables
218
- let currentISOCode;
219
- let currentLocale;
220
- let currencyFormatterNormal;
221
- let currencyFormatterNoDecimal;
222
- let currencyFormatterMedium;
223
- let currencyFormatterTwoDecimal;
224
- let currencyFormatterSmall;
225
- let currencyFormatterVerySmall;
226
- let currencyFormatterVeryVerySmall;
227
- let currencyFormatter15DP;
228
- let currencyFormatter18DP;
229
- let currencyFormatterAbbreviated;
230
-
231
- // If a page has to display multiple currencies, formatters would have to be created for each of them
232
- // To save some effort, we save formatters for reuse
233
- let formattersCache = {};
234
-
235
- function clearCache() {
236
- formattersCache = {};
237
- }
238
-
239
- function initializeFormatters(isoCode, locale) {
240
- const cacheKey = `${isoCode}-${locale}`;
241
- const cachedFormatter = formattersCache[cacheKey];
242
-
243
- currencyFormatterNormal = cachedFormatter
244
- ? cachedFormatter.currencyFormatterNormal
245
- : generateFormatter(isoCode, locale);
246
- currencyFormatterNoDecimal = cachedFormatter
247
- ? cachedFormatter.currencyFormatterNoDecimal
248
- : generateFormatter(isoCode, locale, 0);
249
- currencyFormatterMedium = cachedFormatter
250
- ? cachedFormatter.currencyFormatterMedium
251
- : generateFormatter(isoCode, locale, 3);
252
- currencyFormatterTwoDecimal = cachedFormatter
253
- ? cachedFormatter.currencyFormatterTwoDecimal
254
- : generateFormatter(isoCode, locale, 2);
255
- currencyFormatterSmall = cachedFormatter
256
- ? cachedFormatter.currencyFormatterSmall
257
- : generateFormatter(isoCode, locale, 6);
258
- currencyFormatterVerySmall = cachedFormatter
259
- ? cachedFormatter.currencyFormatterVerySmall
260
- : generateFormatter(isoCode, locale, 8);
261
- currencyFormatterVeryVerySmall = cachedFormatter
262
- ? cachedFormatter.currencyFormatterVeryVerySmall
263
- : generateFormatter(isoCode, locale, 12);
264
- currencyFormatter15DP = cachedFormatter
265
- ? cachedFormatter.currencyFormatter15DP
266
- : generateFormatter(isoCode, locale, 15);
267
- currencyFormatter18DP = cachedFormatter
268
- ? cachedFormatter.currencyFormatter18DP
269
- : generateFormatter(isoCode, locale, 18);
270
- currencyFormatterAbbreviated = cachedFormatter
271
- ? cachedFormatter.currencyFormatterAbbreviated
272
- : generateAbbreviatedFormatter(isoCode, locale);
273
-
274
- // Save in cache
275
- if (cachedFormatter == null) {
276
- formattersCache[cacheKey] = {};
277
- formattersCache[cacheKey].currencyFormatterNormal = currencyFormatterNormal;
278
- formattersCache[cacheKey].currencyFormatterNoDecimal = currencyFormatterNoDecimal;
279
- formattersCache[cacheKey].currencyFormatterMedium = currencyFormatterMedium;
280
- formattersCache[cacheKey].currencyFormatterTwoDecimal = currencyFormatterTwoDecimal;
281
- formattersCache[cacheKey].currencyFormatterSmall = currencyFormatterSmall;
282
- formattersCache[cacheKey].currencyFormatterVerySmall = currencyFormatterVerySmall;
283
- formattersCache[cacheKey].currencyFormatterVeryVerySmall = currencyFormatterVeryVerySmall;
284
- formattersCache[cacheKey].currencyFormatter15DP = currencyFormatter15DP;
285
- formattersCache[cacheKey].currencyFormatter18DP = currencyFormatter18DP;
286
- formattersCache[cacheKey].currencyFormatterAbbreviated = currencyFormatterAbbreviated;
287
- }
288
- }
289
-
290
- // Moderate crypto amount threshold
291
- const MEDIUM_CRYPTO_THRESHOLD = 50;
292
- // Large crypto amount threshold
293
- const LARGE_CRYPTO_THRESHOLD = 1000;
294
- // No decimal threshold for large amounts
295
- const NO_DECIMAL_THRESHOLD = 100000;
296
-
297
- function formatCurrency(
298
- amount,
299
- isoCode,
300
- locale = "en",
301
- raw = false,
302
- noDecimal = false,
303
- abbreviated = false,
304
- ) {
305
- isoCode = isoCode.toUpperCase();
306
- let maximumDecimalTrailingZeroes = undefined;
307
-
308
- if (currentISOCode !== isoCode || currentLocale != locale) {
309
- currentISOCode = isoCode;
310
- currentLocale = locale;
311
-
312
- // Formatters are tied to currency code, we try to initialize as infrequently as possible.
313
- initializeFormatters(isoCode, locale);
314
- }
315
-
316
- if (abbreviated) {
317
- let formattedAbbreviatedCurrency = currencyFormatterAbbreviated.format(amount);
318
-
319
- // Manually add currency code to the back for non-BTC/ETH crypto currencies.
320
- if (isCrypto(isoCode) && !isBTCETH(isoCode)) {
321
- formattedAbbreviatedCurrency = `${formattedAbbreviatedCurrency} ${isoCode}`;
322
- }
323
-
324
- return formatCurrencyOverride(formattedAbbreviatedCurrency, locale);
325
- }
326
-
327
- if (noDecimal === true && amount > 100.0) {
328
- return formatCurrencyOverride(
329
- currencyFormatterNoDecimal.format(amount),
330
- locale
331
- );
332
- } else if (typeof noDecimal === "object" && noDecimal !== null) {
333
- if (raw) {
334
- // Limit to max n decimal places if applicable
335
- let raw_amount = noDecimal.hasOwnProperty("decimalPlaces")
336
- ? amount.toFixed(noDecimal.decimalPlaces)
337
- : amount;
338
- // Round off to number of significant figures without trailing 0's
339
- return `${parseFloat(raw_amount).toPrecision(noDecimal.significantFigures) / 1}`;
340
- }
341
-
342
- if (noDecimal.hasOwnProperty("maximumDecimalTrailingZeroes")) {
343
- maximumDecimalTrailingZeroes = noDecimal.maximumDecimalTrailingZeroes;
344
- }
345
-
346
- if (noDecimal.hasOwnProperty("decimalPlaces") && noDecimal.hasOwnProperty("significantFigures")) {
347
- // Show specified number of significant digits with cutoff of specified fraction digits
348
- const currencyFormatterCustom = generateFormatter(
349
- isoCode,
350
- locale,
351
- undefined,
352
- noDecimal.significantFigures
353
- );
354
-
355
- return formatCurrencyOverride(
356
- currencyFormatterCustom.format(
357
- Number.parseFloat(amount.toFixed(noDecimal.decimalPlaces))
358
- ),
359
- locale,
360
- maximumDecimalTrailingZeroes
361
- );
362
- } else if (noDecimal.hasOwnProperty("decimalPlaces") || noDecimal.hasOwnProperty("significantFigures")) {
363
- const currencyFormatterCustom = generateFormatter(
364
- isoCode,
365
- locale,
366
- noDecimal.decimalPlaces,
367
- noDecimal.significantFigures
368
- );
369
-
370
- return formatCurrencyOverride(
371
- currencyFormatterCustom.format(amount),
372
- locale,
373
- maximumDecimalTrailingZeroes
374
- );
375
- }
376
- }
377
-
378
- if (isCrypto(isoCode)) {
379
- let price = parseFloat(amount);
380
-
381
- if (raw) {
382
- if (amount === 0.0) {
383
- return price.toFixed(2);
384
- }
385
- return price.toPrecision(8);
386
- }
387
-
388
- if (amount === 0.0) {
389
- return formatCurrencyOverride(
390
- currencyFormatterNormal.format(amount),
391
- locale,
392
- maximumDecimalTrailingZeroes
393
- );
394
- } else if (price >= LARGE_CRYPTO_THRESHOLD) {
395
- // Large crypto amount, show no decimal value
396
- return formatCurrencyOverride(
397
- currencyFormatterNoDecimal.format(amount),
398
- locale
399
- );
400
- } else if (
401
- price >= MEDIUM_CRYPTO_THRESHOLD &&
402
- price < LARGE_CRYPTO_THRESHOLD
403
- ) {
404
- // Medium crypto amount, show 3 fraction digits
405
- return formatCurrencyOverride(
406
- currencyFormatterMedium.format(amount),
407
- locale,
408
- maximumDecimalTrailingZeroes
409
- );
410
- } else if (price >= 1.0 && price < MEDIUM_CRYPTO_THRESHOLD) {
411
- // crypto amount, show 6 fraction digits
412
- return formatCurrencyOverride(
413
- currencyFormatterSmall.format(amount),
414
- locale,
415
- maximumDecimalTrailingZeroes
416
- );
417
- } else if (price >= 0.000001 && price < 1.0) {
418
- // crypto amount, show 8 fraction digits
419
- return formatCurrencyOverride(
420
- currencyFormatterVerySmall.format(amount),
421
- locale,
422
- maximumDecimalTrailingZeroes
423
- );
424
- } else if (price >= 10**-9 && price < 10**-6) {
425
- return formatCurrencyOverride(
426
- currencyFormatterVeryVerySmall.format(amount),
427
- locale,
428
- maximumDecimalTrailingZeroes
429
- );
430
- } else if (price >= 10**-12 && price < 10**-9) {
431
- return formatCurrencyOverride(
432
- currencyFormatter15DP.format(amount),
433
- locale,
434
- maximumDecimalTrailingZeroes
435
- );
436
- } else if (price < 10**-12) {
437
- return formatCurrencyOverride(
438
- currencyFormatter18DP.format(amount),
439
- locale,
440
- maximumDecimalTrailingZeroes
441
- );
442
- }
443
- } else {
444
- const unsigned_amount = Math.abs(amount);
445
- if (raw) {
446
- if (unsigned_amount < 10**-12) {
447
- return amount.toFixed(18);
448
- } else if (unsigned_amount < 10**-9) {
449
- return amount.toFixed(15);
450
- } else if (unsigned_amount < 10**-6) {
451
- return amount.toFixed(12);
452
- } else if (unsigned_amount < 10**-3) {
453
- return amount.toFixed(8);
454
- } else if (unsigned_amount < 1.0) {
455
- return amount.toFixed(6);
456
- } else {
457
- return amount.toFixed(2);
458
- }
459
- }
460
-
461
- if (unsigned_amount === 0.0) {
462
- return formatCurrencyOverride(
463
- currencyFormatterNormal.format(amount),
464
- locale,
465
- maximumDecimalTrailingZeroes
466
- );
467
- } else if (unsigned_amount < 10**-12) {
468
- return formatCurrencyOverride(
469
- currencyFormatter18DP.format(amount),
470
- locale,
471
- maximumDecimalTrailingZeroes
472
- );
473
- } else if (unsigned_amount < 10**-9) {
474
- return formatCurrencyOverride(
475
- currencyFormatter15DP.format(amount),
476
- locale,
477
- maximumDecimalTrailingZeroes
478
- );
479
- } else if (unsigned_amount < 10**-6) {
480
- return formatCurrencyOverride(
481
- currencyFormatterVeryVerySmall.format(amount),
482
- locale,
483
- maximumDecimalTrailingZeroes
484
- );
485
- } else if (unsigned_amount < 0.05) {
486
- return formatCurrencyOverride(
487
- currencyFormatterVerySmall.format(amount),
488
- locale,
489
- maximumDecimalTrailingZeroes
490
- );
491
- } else if (unsigned_amount < 1.0) {
492
- return formatCurrencyOverride(
493
- currencyFormatterSmall.format(amount),
494
- locale,
495
- maximumDecimalTrailingZeroes
496
- );
497
- } else if (isoCode === "JPY" && unsigned_amount < 100) {
498
- return formatCurrencyOverride(
499
- currencyFormatterTwoDecimal.format(amount),
500
- locale,
501
- maximumDecimalTrailingZeroes
502
- );
503
- } else if (unsigned_amount > NO_DECIMAL_THRESHOLD) {
504
- return formatCurrencyOverride(
505
- currencyFormatterNoDecimal.format(amount),
506
- locale
507
- );
508
- } else {
509
- // Let the formatter do what it seems best. In particular, we should not set any fraction amount for Japanese Yen
510
- return formatCurrencyOverride(
511
- currencyFormatterNormal.format(amount),
512
- locale
513
- );
514
- }
515
- }
516
- }
517
-
518
- exports.clearCache = clearCache;
519
- exports.formatCurrency = formatCurrency;
520
- exports.isCrypto = isCrypto;
521
-
522
- Object.defineProperty(exports, '__esModule', { value: true });
523
-
524
- }));
package/lib/index.d.ts DELETED
@@ -1,40 +0,0 @@
1
- export function IntlNumberFormatSupported(): boolean;
2
-
3
- export function isCrypto(isoCode: string): boolean;
4
-
5
- export function clearCache(): void;
6
-
7
- // format currency
8
- export function formatCurrency(amount: number, isoCode: string): string;
9
- export function formatCurrency(
10
- amount: number,
11
- isoCode: string,
12
- locale: string
13
- ): string;
14
- export function formatCurrency(
15
- amount: number,
16
- isoCode: string,
17
- locale: string,
18
- raw: boolean
19
- ): string;
20
- export function formatCurrency(
21
- amount: number,
22
- isoCode: string,
23
- locale: string,
24
- raw: boolean,
25
- noDecimal: boolean | decimalConfig
26
- ): string;
27
- export function formatCurrency(
28
- amount: number,
29
- isoCode: string,
30
- locale: string,
31
- raw: boolean,
32
- noDecimal: boolean | decimalConfig,
33
- abbreviated: boolean,
34
- ): string;
35
-
36
- interface decimalConfig {
37
- decimalPlaces?: number,
38
- significantFigures?: number,
39
- maximumDecimalTrailingZeroes?: number
40
- }