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