atomic-fns 1.2.0 → 2.0.0
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/README.md +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { Decimal } from './decimal.js';
|
|
3
|
+
import { quoteForError } from './internal/echo.js';
|
|
4
|
+
import { isoMinorUnits } from './internal/minor-units.js';
|
|
5
|
+
/** Fraction digits {@link Currency.format} shows by default, so an exact amount keeps its digits. */
|
|
6
|
+
const EXACT_FRACTION_DIGITS = 20;
|
|
7
|
+
const CURRENCY_CODE = /^[A-Za-z]{3}$/;
|
|
8
|
+
function minorUnitDigits(code) {
|
|
9
|
+
const digits = isoMinorUnits(code);
|
|
10
|
+
if (digits === undefined) {
|
|
11
|
+
throw new RangeError(`${code} has no ISO 4217 minor unit; pass the digits to round()`);
|
|
12
|
+
}
|
|
13
|
+
return digits;
|
|
14
|
+
}
|
|
15
|
+
/** True unless `options` already say how many digits to show. */
|
|
16
|
+
function showsExactDigits(options) {
|
|
17
|
+
return (options.maximumFractionDigits === undefined &&
|
|
18
|
+
options.minimumSignificantDigits === undefined &&
|
|
19
|
+
options.maximumSignificantDigits === undefined &&
|
|
20
|
+
(options.roundingIncrement ?? 1) === 1 &&
|
|
21
|
+
(options.notation ?? 'standard') === 'standard');
|
|
22
|
+
}
|
|
23
|
+
function assertCurrency(value) {
|
|
24
|
+
if (!(value instanceof Currency))
|
|
25
|
+
throw new TypeError('expected a Currency');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* An exact amount of money in one ISO 4217 currency, as the TC39 Amount proposal pairs a value
|
|
29
|
+
* with its unit. Arithmetic and ordering with another currency throw `RangeError`; nothing
|
|
30
|
+
* converts between currencies.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const price = new Currency('19.99', 'USD')
|
|
35
|
+
* price.multiply(3).format('en-US') // '$59.97'
|
|
36
|
+
* price.add(new Currency('0.01', 'USD')).toString() // '20 USD'
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class Currency {
|
|
40
|
+
/**
|
|
41
|
+
* Orders two amounts of the same currency, for `toSorted` and sorted collections.
|
|
42
|
+
* @throws {TypeError} when `a` or `b` is not a Currency.
|
|
43
|
+
* @throws {RangeError} when the currencies differ.
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* [new Currency(5, 'EUR'), new Currency(2, 'EUR')].toSorted(Currency.compare).map(String)
|
|
47
|
+
* // ['2 EUR', '5 EUR']
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
static compare(a, b) {
|
|
51
|
+
assertCurrency(a);
|
|
52
|
+
return a.compare(b);
|
|
53
|
+
}
|
|
54
|
+
#amount;
|
|
55
|
+
#currency;
|
|
56
|
+
/**
|
|
57
|
+
* Pairs an amount with a currency code.
|
|
58
|
+
* @param amount The amount, read as {@link Decimal} reads it.
|
|
59
|
+
* @param currency A three-letter ISO 4217 code, in any case.
|
|
60
|
+
* @throws {TypeError} when `currency` is not a string, or `amount` not a Decimal input.
|
|
61
|
+
* @throws {RangeError} when `currency` is not three letters, or `amount` is malformed.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* new Currency('12.50', 'usd').currency // 'USD'
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
constructor(amount, currency) {
|
|
68
|
+
if (typeof currency !== 'string')
|
|
69
|
+
throw new TypeError('currency must be a string');
|
|
70
|
+
if (!CURRENCY_CODE.test(currency)) {
|
|
71
|
+
throw new RangeError(`currency must be a three-letter ISO 4217 code, not ${quoteForError(currency)}`);
|
|
72
|
+
}
|
|
73
|
+
this.#amount = amount instanceof Decimal ? amount : new Decimal(amount);
|
|
74
|
+
this.#currency = currency.toUpperCase();
|
|
75
|
+
}
|
|
76
|
+
/** The exact amount. */
|
|
77
|
+
get amount() {
|
|
78
|
+
return this.#amount;
|
|
79
|
+
}
|
|
80
|
+
/** The upper-case ISO 4217 code, such as `'USD'`. */
|
|
81
|
+
get currency() {
|
|
82
|
+
return this.#currency;
|
|
83
|
+
}
|
|
84
|
+
#with(amount) {
|
|
85
|
+
return new _a(amount, this.#currency);
|
|
86
|
+
}
|
|
87
|
+
#amountOf(other) {
|
|
88
|
+
assertCurrency(other);
|
|
89
|
+
if (other.#currency !== this.#currency) {
|
|
90
|
+
throw new RangeError(`currency mismatch: ${this.#currency} and ${other.#currency}`);
|
|
91
|
+
}
|
|
92
|
+
return other.#amount;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The sum of two amounts of the same currency.
|
|
96
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
97
|
+
* @throws {RangeError} when the currencies differ.
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* new Currency('0.1', 'USD').add(new Currency('0.2', 'USD')).toString() // '0.3 USD'
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
add(other) {
|
|
104
|
+
return this.#with(this.#amount.add(this.#amountOf(other)));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The difference of two amounts of the same currency.
|
|
108
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
109
|
+
* @throws {RangeError} when the currencies differ.
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* new Currency(10, 'EUR').subtract(new Currency('2.5', 'EUR')).toString() // '7.5 EUR'
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
subtract(other) {
|
|
116
|
+
return this.#with(this.#amount.subtract(this.#amountOf(other)));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* This amount times a plain factor.
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* new Currency('19.99', 'USD').multiply(3).toString() // '59.97 USD'
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
multiply(factor) {
|
|
126
|
+
return this.#with(this.#amount.multiply(factor));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* This amount divided by a plain divisor, rounded as {@link Decimal.divide} rounds, to 34
|
|
130
|
+
* significant digits by default; follow with {@link Currency.round} for the minor unit.
|
|
131
|
+
* @throws {RangeError} for a zero divisor.
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* new Currency(10, 'USD').divide(3).round().toString() // '3.33 USD'
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
divide(divisor, options) {
|
|
138
|
+
return this.#with(this.#amount.divide(divisor, options));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* This amount with the opposite sign.
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* new Currency(5, 'USD').negate().toString() // '-5 USD'
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
negate() {
|
|
148
|
+
return this.#with(this.#amount.negate());
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The absolute amount.
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* new Currency(-5, 'USD').abs().toString() // '5 USD'
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
abs() {
|
|
158
|
+
return this.#with(this.#amount.abs());
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Rounds the amount, by default to the currency's ISO 4217 minor unit (2 digits for USD, 0 for
|
|
162
|
+
* JPY, 3 for IQD). The mode defaults to `'halfEven'`, while {@link Currency.format} rounds what
|
|
163
|
+
* it shows half away from zero, as `Intl.NumberFormat` does.
|
|
164
|
+
* @param digits Fractional digits (may be negative); defaults to the minor unit.
|
|
165
|
+
* @param roundingMode One of the `Intl.NumberFormat` rounding modes; defaults to `'halfEven'`.
|
|
166
|
+
* @throws {RangeError} when `digits` is left out and ISO 4217 gives the code no minor unit, as
|
|
167
|
+
* for XAU or a code it does not list.
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* new Currency('2.675', 'USD').round().toString() // '2.68 USD'
|
|
171
|
+
* new Currency('1234.5', 'JPY').round().toString() // '1234 JPY'
|
|
172
|
+
* new Currency('2.665', 'USD').round(undefined, 'halfExpand').toString() // '2.67 USD'
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
round(digits = minorUnitDigits(this.#currency), roundingMode) {
|
|
176
|
+
return this.#with(this.#amount.round(digits, roundingMode));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Orders this amount against another of the same currency: -1, 0 or 1.
|
|
180
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
181
|
+
* @throws {RangeError} when the currencies differ.
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* new Currency(1, 'USD').compare(new Currency('1.00', 'USD')) // 0
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
compare(other) {
|
|
188
|
+
return this.#amount.compare(this.#amountOf(other));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* True for a Currency with the same code and amount; false for anything else, including the
|
|
192
|
+
* same amount in another currency.
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* new Currency(1, 'USD').equals(new Currency(1, 'EUR')) // false
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
equals(other) {
|
|
199
|
+
return (other instanceof _a &&
|
|
200
|
+
other.#currency === this.#currency &&
|
|
201
|
+
this.#amount.equals(other.#amount));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* True when this amount is less than `other`.
|
|
205
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
206
|
+
* @throws {RangeError} when the currencies differ.
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* new Currency(1, 'USD').lessThan(new Currency(2, 'USD')) // true
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
lessThan(other) {
|
|
213
|
+
return this.compare(other) < 0;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* True when this amount is less than or equal to `other`.
|
|
217
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
218
|
+
* @throws {RangeError} when the currencies differ.
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* new Currency(2, 'USD').lessThanOrEqual(new Currency(2, 'USD')) // true
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
lessThanOrEqual(other) {
|
|
225
|
+
return this.compare(other) <= 0;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* True when this amount is greater than `other`.
|
|
229
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
230
|
+
* @throws {RangeError} when the currencies differ.
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* new Currency(3, 'USD').greaterThan(new Currency(2, 'USD')) // true
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
greaterThan(other) {
|
|
237
|
+
return this.compare(other) > 0;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* True when this amount is greater than or equal to `other`.
|
|
241
|
+
* @throws {TypeError} when `other` is not a Currency.
|
|
242
|
+
* @throws {RangeError} when the currencies differ.
|
|
243
|
+
* @example
|
|
244
|
+
* ```ts
|
|
245
|
+
* new Currency(2, 'USD').greaterThanOrEqual(new Currency(3, 'USD')) // false
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
greaterThanOrEqual(other) {
|
|
249
|
+
return this.compare(other) >= 0;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Formats with `Intl.NumberFormat` in currency style. Unless `options` set the digits, the
|
|
253
|
+
* amount keeps its own fraction digits, up to 20, instead of rounding to the minor unit, so
|
|
254
|
+
* `0.125` dollars show as `$0.125`; pass `{ maximumFractionDigits: 2 }` or {@link Currency.round}
|
|
255
|
+
* first for minor units. A `roundingMode` alone changes nothing, since no digits are cut; pair it
|
|
256
|
+
* with `maximumFractionDigits`. `style` and `currency` always come from this amount.
|
|
257
|
+
* @throws {RangeError} when the amount is beyond `Number.MAX_VALUE`, which `Intl` shows as `∞`,
|
|
258
|
+
* or the locale is malformed or longer than 255 characters.
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* new Currency('1234.5', 'EUR').format('de-DE') // '1.234,50 €'
|
|
262
|
+
* new Currency('0.125', 'USD').format('en-US', { maximumFractionDigits: 2 }) // '$0.13'
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
format(locale, options = {}) {
|
|
266
|
+
const merged = {
|
|
267
|
+
...options,
|
|
268
|
+
style: 'currency',
|
|
269
|
+
currency: this.#currency
|
|
270
|
+
};
|
|
271
|
+
if (showsExactDigits(merged)) {
|
|
272
|
+
merged.maximumFractionDigits = Math.max(EXACT_FRACTION_DIGITS, merged.minimumFractionDigits ?? 0);
|
|
273
|
+
}
|
|
274
|
+
return this.#amount.toLocaleString(locale, merged);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The same as {@link Currency.format}, under the name `Intl` and Temporal use.
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* new Currency(5, 'GBP').toLocaleString('en-GB') // '£5.00'
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
toLocaleString(locales, options) {
|
|
284
|
+
return this.format(locales, options);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The amount's canonical string and the code, such as `'12.5 USD'`, for logs and keys.
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* new Currency('12.50', 'usd').toString() // '12.5 USD'
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
toString() {
|
|
294
|
+
return `${this.#amount.toString()} ${this.#currency}`;
|
|
295
|
+
}
|
|
296
|
+
/** The same string as {@link Currency.toString}, so `JSON.stringify` keeps every digit. */
|
|
297
|
+
toJSON() {
|
|
298
|
+
return this.toString();
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* What `console.log` and `util.inspect` show, such as `Currency { 12.5 USD }`. The symbol is
|
|
302
|
+
* the runtime's own inspection hook, read by Node and runtimes compatible with it, not a
|
|
303
|
+
* protocol of this package.
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* console.log(new Currency('12.50', 'USD')) // Currency { 12.5 USD }
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
310
|
+
return `Currency { ${this.toString()} }`;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Throws, so `<` and `+` cannot silently compare or add amounts. Use {@link Currency.compare}
|
|
314
|
+
* or {@link Currency.add}.
|
|
315
|
+
* @throws {TypeError} always.
|
|
316
|
+
*/
|
|
317
|
+
valueOf() {
|
|
318
|
+
throw new TypeError('Currency cannot be converted to a primitive implicitly; use compare(), add() or format()');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
_a = Currency;
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How {@link Decimal.divide}, {@link Decimal.round}, {@link Decimal.sqrt} and
|
|
3
|
+
* {@link Decimal.toFixed} round, with the names `Intl.NumberFormat` uses:
|
|
4
|
+
* - `ceil`: toward +Infinity.
|
|
5
|
+
* - `floor`: toward -Infinity.
|
|
6
|
+
* - `expand`: away from zero.
|
|
7
|
+
* - `trunc`: toward zero.
|
|
8
|
+
* - `halfCeil`: nearest, ties toward +Infinity (as `Math.round`).
|
|
9
|
+
* - `halfFloor`: nearest, ties toward -Infinity.
|
|
10
|
+
* - `halfExpand`: nearest, ties away from zero (as `Number.prototype.toFixed`).
|
|
11
|
+
* - `halfTrunc`: nearest, ties toward zero.
|
|
12
|
+
* - `halfEven`: nearest, ties to the even neighbor (the default).
|
|
13
|
+
*/
|
|
14
|
+
export type RoundingMode = 'ceil' | 'floor' | 'expand' | 'trunc' | 'halfCeil' | 'halfFloor' | 'halfExpand' | 'halfTrunc' | 'halfEven';
|
|
15
|
+
/** Options for {@link Decimal.divide} and {@link Decimal.sqrt}. */
|
|
16
|
+
export interface DivideOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Significant digits of the result, from 1 to `Decimal.MAX_DIGITS` (default 34, as the TC39
|
|
19
|
+
* draft's 128-bit decimals carry). It counts significant digits, not fractional ones.
|
|
20
|
+
*/
|
|
21
|
+
precision?: number;
|
|
22
|
+
/** How the last digit rounds (default `'halfEven'`). */
|
|
23
|
+
roundingMode?: RoundingMode;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A value {@link Decimal} reads: a Decimal, a decimal string, a bigint or a finite number.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const inputs: DecimalInput[] = [new Decimal('1.5'), '2.5', 3n, 4.5]
|
|
30
|
+
* inputs.map((value) => new Decimal(value).toString()) // ['1.5', '2.5', '3', '4.5']
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export type DecimalInput = Decimal | string | bigint | number;
|
|
34
|
+
/**
|
|
35
|
+
* An exact decimal number, shaped after the TC39 Decimal proposal: immutable, with arithmetic
|
|
36
|
+
* methods instead of operators. Values carry up to {@link Decimal.MAX_DIGITS} significant digits
|
|
37
|
+
* and an exponent within {@link Decimal.MAX_EXPONENT}; a result past either throws `RangeError`.
|
|
38
|
+
* Each operation costs time that grows with the digits of its operands, so size-limit untrusted
|
|
39
|
+
* lists before summing them.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const total = new Decimal('0.1').add('0.2')
|
|
44
|
+
* total.toString() // '0.3'
|
|
45
|
+
* total.equals('0.3') // true
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class Decimal {
|
|
49
|
+
#private;
|
|
50
|
+
/** Significant digits a Decimal holds; longer inputs and results throw `RangeError`. */
|
|
51
|
+
static get MAX_DIGITS(): number;
|
|
52
|
+
/** Largest absolute exponent a Decimal stores; larger values throw `RangeError`. */
|
|
53
|
+
static get MAX_EXPONENT(): number;
|
|
54
|
+
/** Largest fractional `digits` {@link Decimal.round} and {@link Decimal.toFixed} take. */
|
|
55
|
+
static get MAX_PRECISION(): number;
|
|
56
|
+
/**
|
|
57
|
+
* Orders two values, for `toSorted` and sorted collections.
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* ['10', '9', '9.5'].map((s) => new Decimal(s)).toSorted(Decimal.compare).map(String)
|
|
61
|
+
* // ['9', '9.5', '10']
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
static compare(a: DecimalInput, b: DecimalInput): -1 | 0 | 1;
|
|
65
|
+
/**
|
|
66
|
+
* Reads a Decimal, a decimal string (`'-1.5'`, `'.5'`, `'2e-3'`, surrounding spaces allowed),
|
|
67
|
+
* a bigint, or a finite number through its shortest round-trip string, so `new Decimal(0.1)`
|
|
68
|
+
* is exactly `0.1`.
|
|
69
|
+
* @throws {TypeError} for any other type.
|
|
70
|
+
* @throws {RangeError} for a malformed string, a non-finite number, or a value past the bounds.
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* new Decimal('1.50').toString() // '1.5'
|
|
74
|
+
* new Decimal(2n ** 64n).toString() // '18446744073709551616'
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
constructor(value: DecimalInput);
|
|
78
|
+
/**
|
|
79
|
+
* The exact sum.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* new Decimal('0.1').add('0.2').toString() // '0.3'
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
add(other: DecimalInput): Decimal;
|
|
86
|
+
/**
|
|
87
|
+
* The exact difference.
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* new Decimal('1').subtract('0.9').toString() // '0.1'
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
subtract(other: DecimalInput): Decimal;
|
|
94
|
+
/**
|
|
95
|
+
* The exact product.
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* new Decimal('1.5').multiply('-2').toString() // '-3'
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
multiply(other: DecimalInput): Decimal;
|
|
102
|
+
/**
|
|
103
|
+
* The quotient rounded to `precision` significant digits (default 34), as the TC39 draft
|
|
104
|
+
* rounds, so `new Decimal('1e-30').divide(3)` keeps its scale. An exact quotient with fewer
|
|
105
|
+
* digits is returned whole.
|
|
106
|
+
* @throws {TypeError} for `options` that is not an object.
|
|
107
|
+
* @throws {RangeError} for a zero divisor, a `precision` out of range, an unknown mode, or a
|
|
108
|
+
* rounded quotient past the exponent bound: one too large, or one whose last digit falls below
|
|
109
|
+
* `10^-Decimal.MAX_EXPONENT`, as `new Decimal('1e-9990').divide(3)` does at 34 digits.
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* new Decimal(1).divide(3).toString() // '0.3333333333333333333333333333333333'
|
|
113
|
+
* new Decimal(2).divide(3, { precision: 2, roundingMode: 'trunc' }).toString() // '0.66'
|
|
114
|
+
* new Decimal(1).divide(8).toString() // '0.125'
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
divide(other: DecimalInput, options?: DivideOptions): Decimal;
|
|
118
|
+
/**
|
|
119
|
+
* The exact remainder of truncating division, with the sign of this value, as `%` gives.
|
|
120
|
+
* @throws {RangeError} for a zero divisor.
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* new Decimal('7.5').remainder(2).toString() // '1.5'
|
|
124
|
+
* new Decimal('-7.5').remainder(2).toString() // '-1.5'
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
remainder(other: DecimalInput): Decimal;
|
|
128
|
+
/**
|
|
129
|
+
* This value with the opposite sign.
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* new Decimal('5').negate().toString() // '-5'
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
negate(): Decimal;
|
|
136
|
+
/**
|
|
137
|
+
* The absolute value.
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* new Decimal('-1.5').abs().toString() // '1.5'
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
abs(): Decimal;
|
|
144
|
+
/**
|
|
145
|
+
* Rounds to `digits` fractional digits; a negative count rounds to tens, hundreds, and so on.
|
|
146
|
+
* @param digits Fractional digits, from `-Decimal.MAX_EXPONENT` to `Decimal.MAX_PRECISION`
|
|
147
|
+
* (default 0).
|
|
148
|
+
* @param roundingMode How ties and remainders round (default `'halfEven'`).
|
|
149
|
+
* @throws {RangeError} for `digits` out of range, an unknown mode, or a result past the
|
|
150
|
+
* exponent bound.
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* new Decimal('2.5').round().toString() // '2'
|
|
154
|
+
* new Decimal('2.5').round(0, 'halfExpand').toString() // '3'
|
|
155
|
+
* new Decimal('1234').round(-2).toString() // '1200'
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
round(digits?: number, roundingMode?: RoundingMode): Decimal;
|
|
159
|
+
/**
|
|
160
|
+
* The square root rounded to `precision` significant digits (default 34). An exact root with
|
|
161
|
+
* fewer digits is returned whole.
|
|
162
|
+
* @throws {TypeError} for `options` that is not an object.
|
|
163
|
+
* @throws {RangeError} for a negative value, a `precision` out of range, an unknown mode, or a
|
|
164
|
+
* rounded root whose last digit falls below `10^-Decimal.MAX_EXPONENT`.
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* new Decimal(2).sqrt().toString() // '1.414213562373095048801688724209698'
|
|
168
|
+
* new Decimal('6.25').sqrt().toString() // '2.5'
|
|
169
|
+
* new Decimal(2).sqrt({ precision: 5 }).toString() // '1.4142'
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
sqrt(options?: DivideOptions): Decimal;
|
|
173
|
+
/**
|
|
174
|
+
* Orders this value against `other`: -1, 0 or 1.
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* new Decimal('1.10').compare('1.1') // 0
|
|
178
|
+
* new Decimal('-2').compare(1) // -1
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
compare(other: DecimalInput): -1 | 0 | 1;
|
|
182
|
+
/**
|
|
183
|
+
* True when both are the same number, whatever their written form.
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* new Decimal('2.50').equals('2.5') // true
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
equals(other: DecimalInput): boolean;
|
|
190
|
+
/**
|
|
191
|
+
* True when this value is less than `other`.
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* new Decimal('0.1').lessThan('0.2') // true
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
lessThan(other: DecimalInput): boolean;
|
|
198
|
+
/**
|
|
199
|
+
* True when this value is less than or equal to `other`.
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* new Decimal('0.2').lessThanOrEqual('0.20') // true
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
lessThanOrEqual(other: DecimalInput): boolean;
|
|
206
|
+
/**
|
|
207
|
+
* True when this value is greater than `other`.
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* new Decimal('1e3').greaterThan(999) // true
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
greaterThan(other: DecimalInput): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* True when this value is greater than or equal to `other`.
|
|
216
|
+
* @example
|
|
217
|
+
* ```ts
|
|
218
|
+
* new Decimal('-0').greaterThanOrEqual(0) // true
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
greaterThanOrEqual(other: DecimalInput): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* The canonical string: plain notation while that pads at most 64 zeros, scientific past that
|
|
224
|
+
* (`'1e+65'`, `'1.5e-70'`), so its length follows the significant digits and not the exponent.
|
|
225
|
+
* The constructor reads both forms back.
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* new Decimal('1.50').toString() // '1.5'
|
|
229
|
+
* new Decimal('1e100').toString() // '1e+100'
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
toString(): string;
|
|
233
|
+
/**
|
|
234
|
+
* Plain notation at any magnitude. A short input such as `'1e10000'` expands to 10,001
|
|
235
|
+
* characters, so prefer {@link Decimal.toString} for untrusted values.
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* new Decimal('1e5').toPlainString() // '100000'
|
|
239
|
+
* new Decimal('-1.5e-3').toPlainString() // '-0.0015'
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
toPlainString(): string;
|
|
243
|
+
/**
|
|
244
|
+
* Plain notation with exactly `digits` fractional digits. Ties round half away from zero
|
|
245
|
+
* (`'halfExpand'`), as `Number.prototype.toFixed` rounds, not half to even as
|
|
246
|
+
* {@link Decimal.round} does by default; pass `roundingMode` to choose another.
|
|
247
|
+
* @param digits Fractional digits, from 0 to `Decimal.MAX_PRECISION` (default 0).
|
|
248
|
+
* @param roundingMode How the last digit rounds (default `'halfExpand'`).
|
|
249
|
+
* @throws {RangeError} for `digits` out of range or an unknown mode.
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* new Decimal('2.5').toFixed() // '3'
|
|
253
|
+
* new Decimal('1.005').toFixed(2) // '1.01'
|
|
254
|
+
* new Decimal('3').toFixed(2) // '3.00'
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
toFixed(digits?: number, roundingMode?: RoundingMode): string;
|
|
258
|
+
/** The canonical string, as {@link Decimal.toString}, so `JSON.stringify` keeps every digit. */
|
|
259
|
+
toJSON(): string;
|
|
260
|
+
/**
|
|
261
|
+
* Formats the exact value with `Intl.NumberFormat`, which reads decimal strings without going
|
|
262
|
+
* through a `Number`, so digits past 2^53 survive.
|
|
263
|
+
* @throws {RangeError} when the value is beyond `Number.MAX_VALUE`, which `Intl` shows as `∞`,
|
|
264
|
+
* or so close to zero that it rounds to a `Number` zero, which `Intl` may show as `0`.
|
|
265
|
+
* @throws {RangeError} for a malformed locale tag, or a locale list longer than 255 characters
|
|
266
|
+
* joined, which `Intl` canonicalizes in quadratic time.
|
|
267
|
+
* @throws {TypeError} for a locale that is neither a string nor an `Intl.Locale`.
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* new Decimal('12345678901234567.25').toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
271
|
+
* // '12,345,678,901,234,567.25'
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
toLocaleString(locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions): string;
|
|
275
|
+
/**
|
|
276
|
+
* The nearest `Number`, read from the coefficient and exponent, so extreme exponents stay cheap.
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* new Decimal('0.1').toNumber() // 0.1
|
|
280
|
+
* new Decimal('1e400').toNumber() // Infinity
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
toNumber(): number;
|
|
284
|
+
/**
|
|
285
|
+
* The value as a bigint.
|
|
286
|
+
* @throws {RangeError} when the value has a fractional part.
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* new Decimal('1.2e3').toBigInt() // 1200n
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
toBigInt(): bigint;
|
|
293
|
+
/**
|
|
294
|
+
* Throws, so `<`, `+` and `==` cannot silently turn a Decimal into a lossy `Number`. Use
|
|
295
|
+
* {@link Decimal.compare}, {@link Decimal.add} or {@link Decimal.toNumber}.
|
|
296
|
+
* @throws {TypeError} always.
|
|
297
|
+
*/
|
|
298
|
+
valueOf(): never;
|
|
299
|
+
}
|