@vielzeug/coins 1.0.5 → 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 +50 -222
- package/dist/aggregate.cjs +2 -0
- package/dist/aggregate.cjs.map +1 -0
- package/dist/aggregate.d.ts +11 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +44 -0
- package/dist/aggregate.js.map +1 -0
- package/dist/coins.cjs +1 -1
- package/dist/coins.cjs.map +1 -1
- package/dist/coins.iife.js +1 -1
- package/dist/coins.iife.js.map +1 -1
- package/dist/coins.js +1 -1
- package/dist/coins.js.map +1 -1
- package/dist/currency.cjs +2 -0
- package/dist/currency.cjs.map +1 -0
- package/dist/currency.d.ts +38 -0
- package/dist/currency.d.ts.map +1 -0
- package/dist/currency.js +55 -0
- package/dist/currency.js.map +1 -0
- package/dist/decimal.cjs +2 -0
- package/dist/decimal.cjs.map +1 -0
- package/dist/decimal.d.ts +7 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +52 -0
- package/dist/decimal.js.map +1 -0
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +6 -42
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -6
- package/dist/errors.js.map +1 -1
- package/dist/exchange.cjs +1 -1
- package/dist/exchange.cjs.map +1 -1
- package/dist/exchange.d.ts +9 -27
- package/dist/exchange.d.ts.map +1 -1
- package/dist/exchange.js +24 -12
- package/dist/exchange.js.map +1 -1
- package/dist/format.cjs +1 -1
- package/dist/format.cjs.map +1 -1
- package/dist/format.d.ts +2 -39
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +57 -94
- package/dist/format.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/money.cjs +1 -1
- package/dist/money.cjs.map +1 -1
- package/dist/money.d.ts +26 -245
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +71 -184
- package/dist/money.js.map +1 -1
- package/dist/serialization.cjs +2 -0
- package/dist/serialization.cjs.map +1 -0
- package/dist/serialization.d.ts +6 -0
- package/dist/serialization.d.ts.map +1 -0
- package/dist/serialization.js +45 -0
- package/dist/serialization.js.map +1 -0
- package/dist/types.d.ts +35 -52
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/_cache.cjs +0 -2
- package/dist/_cache.cjs.map +0 -1
- package/dist/_cache.d.ts +0 -6
- package/dist/_cache.d.ts.map +0 -1
- package/dist/_cache.js +0 -14
- package/dist/_cache.js.map +0 -1
- package/dist/_dev.cjs +0 -2
- package/dist/_dev.cjs.map +0 -1
- package/dist/_dev.d.ts +0 -2
- package/dist/_dev.d.ts.map +0 -1
- package/dist/_dev.js +0 -9
- package/dist/_dev.js.map +0 -1
- package/dist/utils.cjs +0 -2
- package/dist/utils.cjs.map +0 -1
- package/dist/utils.d.ts +0 -66
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -66
- package/dist/utils.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,262 +1,90 @@
|
|
|
1
1
|
# @vielzeug/coins
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Exact monetary arithmetic for TypeScript. Coins stores bigint minor units, uses explicit currency definitions, and accepts decimal strings at every exact-input boundary.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Why Coins?
|
|
8
|
-
|
|
9
|
-
Float arithmetic silently loses precision:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
// number (float)
|
|
13
|
-
10.1 + 10.2; // 20.299999999999997
|
|
14
|
-
|
|
15
|
-
// @vielzeug/coins (bigint)
|
|
16
|
-
import { add, money } from '@vielzeug/coins';
|
|
17
|
-
add(money('10.10', 'USD'), money('10.20', 'USD')); // { amount: 2030n, currency: 'USD' } — exact
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Coins stores every value as bigint **minor units** (cents for USD, whole units for JPY, fils for KWD), so arithmetic and allocation are always lossless.
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
5
|
+
## Install
|
|
23
6
|
|
|
24
7
|
```sh
|
|
25
8
|
pnpm add @vielzeug/coins
|
|
26
9
|
```
|
|
27
10
|
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
```ts
|
|
31
|
-
import { add, allocate, exchange, format, money, multiply } from '@vielzeug/coins';
|
|
32
|
-
import type { ExchangeRate, Money } from '@vielzeug/coins';
|
|
33
|
-
|
|
34
|
-
// Create money from a decimal string (lossless) or bigint minor units
|
|
35
|
-
const price: Money = money('19.99', 'USD'); // { amount: 1999n, currency: 'USD' }
|
|
36
|
-
const tax: Money = money('1.60', 'USD');
|
|
37
|
-
const total: Money = add(price, tax); // { amount: 3559n, currency: 'USD' }
|
|
38
|
-
|
|
39
|
-
// Arithmetic with explicit rounding mode
|
|
40
|
-
multiply(total, '1.1'); // $39.15 (half-away-from-zero, default)
|
|
41
|
-
multiply(total, '1.1', 'floor'); // $39.14 (explicit mode)
|
|
42
|
-
|
|
43
|
-
// Lossless allocation — no minor unit is ever lost or gained
|
|
44
|
-
allocate(money('10.00', 'USD'), [1, 1, 1]); // [$3.34, $3.33, $3.33]
|
|
45
|
-
|
|
46
|
-
// Locale-aware formatting
|
|
47
|
-
format(total); // '$35.59'
|
|
48
|
-
format(total, { locale: 'de-DE' }); // '35,59 $'
|
|
49
|
-
format(total, { style: 'code' }); // 'USD 35.59'
|
|
50
|
-
|
|
51
|
-
// Currency exchange — ExchangeRate.from/to are plain strings; rate is a decimal string or number
|
|
52
|
-
const rate: ExchangeRate = { from: 'USD', rate: '0.92', to: 'EUR' };
|
|
53
|
-
exchange(total, rate); // { amount: 3274n, currency: 'EUR' }
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## API
|
|
57
|
-
|
|
58
|
-
### `money(amount, currency)`
|
|
59
|
-
|
|
60
|
-
Creates a `Money` value. Validates the currency code against `Intl.NumberFormat`; throws `InvalidCurrencyError` for unrecognised ISO 4217 codes.
|
|
61
|
-
|
|
62
|
-
| `amount` type | Behaviour |
|
|
63
|
-
| -------------------- | ---------------------------------------------------------------------- |
|
|
64
|
-
| `string` `'1234.56'` | Parsed losslessly; excess digits rounded half-away-from-zero |
|
|
65
|
-
| `number` `1234.56` | Converted via `String()` first — IEEE-754 limits apply; prefer strings |
|
|
66
|
-
| `bigint` `123456n` | Used as-is (already in minor units) |
|
|
11
|
+
## Start Here
|
|
67
12
|
|
|
68
13
|
```ts
|
|
69
|
-
|
|
70
|
-
money(0n, 'USD'); // { amount: 0n, currency: 'USD' } — zero accumulator
|
|
71
|
-
money('1.00', 'FAKE'); // throws InvalidCurrencyError
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Arithmetic
|
|
14
|
+
import { USD, add, money, toDecimal } from '@vielzeug/coins';
|
|
75
15
|
|
|
76
|
-
|
|
16
|
+
const subtotal = add(money('12.50', USD), money('7.25', USD));
|
|
77
17
|
|
|
78
|
-
|
|
79
|
-
add(a, b); // → Money
|
|
80
|
-
subtract(a, b); // → Money
|
|
81
|
-
multiply(money, factor, mode?); // → Money (factor: number | string)
|
|
82
|
-
divide(money, divisor, mode?); // → Money (throws RangeError on division by zero)
|
|
83
|
-
abs(money); // → Money (absolute value)
|
|
84
|
-
negate(money); // → Money (sign flip)
|
|
18
|
+
console.log(toDecimal(subtotal)); // '19.75'
|
|
85
19
|
```
|
|
86
20
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Uses the **Largest Remainder Method** — every output sums exactly to the input, no minor unit is ever lost or gained.
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
allocate(money, ratios); // → [Money, ...Money[]] (weighted; use strings for lossless decimal ratios)
|
|
93
|
-
splitEvenly(money, parts); // → [Money, ...Money[]] (equal shares; sugar over allocate)
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Both throw `RangeError` on empty ratios, negative ratios, or non-positive parts.
|
|
97
|
-
|
|
98
|
-
### Aggregates
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
sum(moneys); // → Money (throws RangeError if empty; CurrencyMismatchError on mismatch)
|
|
102
|
-
min(moneys); // → Money (non-empty array; CurrencyMismatchError on mismatch)
|
|
103
|
-
max(moneys); // → Money (non-empty array; CurrencyMismatchError on mismatch)
|
|
104
|
-
clamp(m, lower, upper); // → Money (CurrencyMismatchError on mismatch; RangeError if lower > upper)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Comparison
|
|
108
|
-
|
|
109
|
-
`isEqual` returns `false` on currency mismatch (safe for `.filter()`). All other comparison functions throw `CurrencyMismatchError` on mismatch.
|
|
21
|
+
`money()` has one common path and one explicit low-level path:
|
|
110
22
|
|
|
111
23
|
```ts
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
greaterThanOrEqual(a, b); // → boolean
|
|
116
|
-
lessThan(a, b); // → boolean
|
|
117
|
-
lessThanOrEqual(a, b); // → boolean
|
|
118
|
-
isZero(m); // → boolean
|
|
119
|
-
isPositive(m); // → boolean
|
|
120
|
-
isNegative(m); // → boolean
|
|
121
|
-
isNonNegative(m); // → boolean (>= 0)
|
|
122
|
-
isNonPositive(m); // → boolean (<= 0)
|
|
24
|
+
money('19.99', USD); // exact decimal major units
|
|
25
|
+
money('19.999', USD, { rounding: 'halfEven' });
|
|
26
|
+
money(1999n, USD, { unit: 'minor' }); // stored minor units
|
|
123
27
|
```
|
|
124
28
|
|
|
125
|
-
|
|
29
|
+
## Core API
|
|
126
30
|
|
|
127
31
|
```ts
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
32
|
+
import {
|
|
33
|
+
EUR,
|
|
34
|
+
USD,
|
|
35
|
+
allocate,
|
|
36
|
+
decimal,
|
|
37
|
+
exchange,
|
|
38
|
+
exchangeRate,
|
|
39
|
+
format,
|
|
40
|
+
money,
|
|
41
|
+
multiply,
|
|
42
|
+
sum,
|
|
43
|
+
toDecimal,
|
|
44
|
+
} from '@vielzeug/coins';
|
|
45
|
+
|
|
46
|
+
const items = [money('12.50', USD), money('7.25', USD)];
|
|
47
|
+
const subtotal = sum(items, { currency: USD });
|
|
48
|
+
const total = multiply(subtotal, '1.08', { rounding: 'halfEven' });
|
|
49
|
+
const shares = allocate(total, 3);
|
|
50
|
+
|
|
51
|
+
const usdToEur = exchangeRate({ from: USD, to: EUR, value: '0.9234' });
|
|
52
|
+
const eurTotal = exchange(total, usdToEur, { rounding: 'halfEven' });
|
|
53
|
+
|
|
54
|
+
console.log(format(eurTotal, { locale: 'de-DE' }));
|
|
55
|
+
console.log(shares.map(toDecimal));
|
|
56
|
+
console.log(decimal('1.075'));
|
|
132
57
|
```
|
|
133
58
|
|
|
134
|
-
|
|
59
|
+
## Currency Definitions
|
|
135
60
|
|
|
136
|
-
|
|
61
|
+
Built-in definitions: `USD`, `EUR`, `GBP`, `JPY`, `KRW`, `BHD`, `KWD`.
|
|
137
62
|
|
|
138
|
-
|
|
63
|
+
Define a business currency explicitly when required:
|
|
139
64
|
|
|
140
65
|
```ts
|
|
141
|
-
|
|
142
|
-
roundTo(money('1234.56', 'USD'), 1, 'floor'); // { amount: 12345n, currency: 'USD' } ($1,234.5)
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### `format(money, options?)`
|
|
146
|
-
|
|
147
|
-
Formats a `Money` value as a locale-aware currency string. Uses bigint arithmetic throughout — no floating-point precision loss.
|
|
66
|
+
import { defineCurrency, money } from '@vielzeug/coins';
|
|
148
67
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
| `locale` | `string` | `'en-US'` | BCP 47 language tag |
|
|
152
|
-
| `style` | `'symbol' \| 'code' \| 'name' \| 'narrowSymbol'` | `'symbol'` | Display style |
|
|
153
|
-
| `minimumFractionDigits` | `number` | currency default | Minimum decimal places shown |
|
|
154
|
-
| `maximumFractionDigits` | `number` | currency default | Maximum decimal places shown |
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
format(money('1234.56', 'USD')); // '$1,234.56'
|
|
158
|
-
format(money('1234.56', 'USD'), { locale: 'de-DE' }); // '1.234,56 $'
|
|
159
|
-
format(money('1234.56', 'USD'), { style: 'code' }); // 'USD 1,234.56'
|
|
68
|
+
const POINTS = defineCurrency({ code: 'PTS', minorUnit: 0 });
|
|
69
|
+
const balance = money('250', POINTS);
|
|
160
70
|
```
|
|
161
71
|
|
|
162
|
-
|
|
72
|
+
## Errors
|
|
163
73
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
Joining all `value` fields produces the same string as `format()`.
|
|
167
|
-
|
|
168
|
-
### `exchange(money, rate, mode?)`
|
|
169
|
-
|
|
170
|
-
Converts a `Money` value using an `ExchangeRate`. `ExchangeRate.from` and `.to` are plain strings; `rate.rate` is a decimal string or number (`number | string`, for symmetry with `multiply()`/`divide()` — prefer a string for lossless bigint arithmetic). Throws `CurrencyMismatchError` if `money.currency !== rate.from`.
|
|
74
|
+
All failures extend `CoinsError` and expose `code`.
|
|
171
75
|
|
|
172
76
|
```ts
|
|
173
|
-
import
|
|
174
|
-
|
|
175
|
-
const rate: ExchangeRate = { from: 'USD', rate: '0.92', to: 'EUR' };
|
|
176
|
-
exchange(money('100.00', 'USD'), rate); // { amount: 9200n, currency: 'EUR' }
|
|
177
|
-
exchange(money('100.00', 'USD'), rate, 'floor'); // explicit rounding mode
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Typed Errors
|
|
181
|
-
|
|
182
|
-
```ts
|
|
183
|
-
import { CurrencyMismatchError, InvalidCurrencyError } from '@vielzeug/coins';
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
add(money('1.00', 'USD'), money('1.00', 'EUR'));
|
|
187
|
-
} catch (e) {
|
|
188
|
-
if (e instanceof CurrencyMismatchError) {
|
|
189
|
-
console.log(e.expected, e.received); // 'USD' 'EUR'
|
|
190
|
-
}
|
|
191
|
-
}
|
|
77
|
+
import { CoinsError, money, USD } from '@vielzeug/coins';
|
|
192
78
|
|
|
193
79
|
try {
|
|
194
|
-
money(
|
|
195
|
-
} catch (
|
|
196
|
-
if (
|
|
197
|
-
|
|
80
|
+
money(100n, USD);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error instanceof CoinsError && error.code === 'INVALID_MONEY') {
|
|
83
|
+
// Bigint construction requires { unit: 'minor' }.
|
|
198
84
|
}
|
|
199
85
|
}
|
|
200
86
|
```
|
|
201
87
|
|
|
202
|
-
- `CurrencyMismatchError` extends `TypeError` — existing `instanceof TypeError` catch blocks still work.
|
|
203
|
-
- `InvalidCurrencyError` extends `RangeError` — existing `instanceof RangeError` catch blocks still work.
|
|
204
|
-
|
|
205
|
-
### Rounding Modes
|
|
206
|
-
|
|
207
|
-
Used by `multiply`, `divide`, `exchange`, and `roundTo`.
|
|
208
|
-
|
|
209
|
-
| Mode | Description |
|
|
210
|
-
| ----------------------- | ---------------------------------------------- |
|
|
211
|
-
| `'half-away-from-zero'` | Round half away from zero **(default)** |
|
|
212
|
-
| `'half-even'` | Banker's rounding — minimises cumulative error |
|
|
213
|
-
| `'down'` | Truncate toward zero |
|
|
214
|
-
| `'up'` | Away from zero |
|
|
215
|
-
| `'floor'` | Toward −∞ |
|
|
216
|
-
| `'ceiling'` | Toward +∞ |
|
|
217
|
-
|
|
218
|
-
### Key Types
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
type Money = {
|
|
222
|
-
readonly amount: bigint; // minor units (cents for USD, whole units for JPY)
|
|
223
|
-
readonly currency: string; // validated ISO 4217 code
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
type ExchangeRate = {
|
|
227
|
-
readonly from: string; // source currency code
|
|
228
|
-
readonly rate: number | string; // decimal multiplier, e.g. '0.92' or 0.92
|
|
229
|
-
readonly to: string; // target currency code
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
type RoundingMode = 'ceiling' | 'down' | 'floor' | 'half-away-from-zero' | 'half-even' | 'up';
|
|
233
|
-
|
|
234
|
-
type FormatOptions = {
|
|
235
|
-
locale?: string;
|
|
236
|
-
maximumFractionDigits?: number;
|
|
237
|
-
minimumFractionDigits?: number;
|
|
238
|
-
style?: 'code' | 'name' | 'narrowSymbol' | 'symbol';
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
type MoneyFormatPart = {
|
|
242
|
-
type: 'currency' | 'decimal' | 'fraction' | 'integer' | 'literal' | 'minusSign';
|
|
243
|
-
value: string;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
type MoneyJSON = { amount: string; currency: string };
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## Documentation
|
|
250
|
-
|
|
251
|
-
- **[Full Guide](https://vielzeug.dev/coins/)** — Overview, concepts, quick start
|
|
252
|
-
- **[Usage Guide](https://vielzeug.dev/coins/usage/)** — Common patterns and best practices
|
|
253
|
-
- **[API Reference](https://vielzeug.dev/coins/api/)** — All types and function signatures
|
|
254
|
-
- **[Examples](https://vielzeug.dev/coins/examples/)** — Real-world integration examples
|
|
255
|
-
|
|
256
|
-
## TypeScript
|
|
257
|
-
|
|
258
|
-
Requires TypeScript 5.0+ with `strict: true`.
|
|
259
|
-
|
|
260
88
|
## License
|
|
261
89
|
|
|
262
|
-
MIT
|
|
90
|
+
MIT © Helmuth Saatkamp
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./money.cjs");function r(t,r){let i=0n;for(let a of t){if(!n.isMoney(a))throw new e.CoinsError(`INVALID_MONEY`,`sum() requires canonical money values`);if(a.currency!==r.currency)throw new e.CurrencyMismatchError(r.currency.code,a.currency.code);i+=a.amount}return n.withMinor(i,r.currency)}function i(r,i){if(!n.isMoney(r))throw new e.CoinsError(`INVALID_MONEY`,`allocate() requires canonical money`);if(typeof i==`number`)return o(r,i);if(i.length===0)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let a=i.map(t.decimal);if(a.some(e=>e.numerator<0n))throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let s=a.reduce((e,n)=>t.lcm(e,n.denominator),1n),c=a.map(e=>e.numerator*(s/e.denominator)),l=c.reduce((e,t)=>e+t,0n);if(l===0n)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let u=r.amount<0n?-1n:1n,d=r.amount<0n?-r.amount:r.amount,f=c.map(e=>d*e/l),p=d-f.reduce((e,t)=>e+t,0n),m=c.map((e,t)=>({index:t,remainder:d*e%l})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of m){if(p===0n)break;f[e.index]+=1n,p-=1n}return f.map(e=>n.withMinor(e*u,r.currency))}function a(t,r){if(n.compare(r.min,r.max)===1)throw new e.CoinsError(`INVALID_ALLOCATION`,`Clamp minimum cannot exceed maximum`);return n.compare(t,r.min)===-1?r.min:n.compare(t,r.max)===1?r.max:t}function o(t,r){if(!Number.isInteger(r)||r<1)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let i=BigInt(r),a=t.amount<0n?-1n:1n,o=t.amount<0n?-t.amount:t.amount,s=o/i,c=o%i;return Array.from({length:r},(e,r)=>n.withMinor((s+(BigInt(r)<c?1n:0n))*a,t.currency))}exports.allocate=i,exports.clamp=a,exports.sum=r;
|
|
2
|
+
//# sourceMappingURL=aggregate.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.cjs","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import type { Currency, Money } from './types';\n\nimport { decimal, lcm } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { compare, isMoney, withMinor } from './money';\n\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C> {\n let amount = 0n;\n\n for (const value of values) {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'sum() requires canonical money values');\n\n if (value.currency !== options.currency)\n throw new CurrencyMismatchError(options.currency.code, value.currency.code);\n\n amount += value.amount;\n }\n\n return withMinor(amount, options.currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'allocate() requires canonical money');\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => withMinor(amount * sign, value.currency));\n}\n\nexport function clamp<C extends Currency>(\n value: Money<C>,\n options: { max: Money<NoInfer<C>>; min: Money<NoInfer<C>> },\n): Money<C> {\n if (compare(options.min, options.max) === 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Clamp minimum cannot exceed maximum');\n }\n\n return compare(value, options.min) === -1 ? options.min : compare(value, options.max) === 1 ? options.max : value;\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n withMinor((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":"oFAMA,SAAgB,EAAwB,EAA4B,EAAoC,CACtG,IAAI,EAAS,GAEb,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,CAAC,EAAA,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,uCAAuC,EAElG,GAAI,EAAM,WAAa,EAAQ,SAC7B,MAAM,IAAI,EAAA,sBAAsB,EAAQ,SAAS,KAAM,EAAM,SAAS,IAAI,EAE5E,GAAU,EAAM,MAClB,CAEA,OAAO,EAAA,UAAU,EAAQ,EAAQ,QAAQ,CAC3C,CAIA,SAAgB,EAA6B,EAAiB,EAAwD,CACpH,GAAI,CAAC,EAAA,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,qCAAqC,EAEhG,GAAI,OAAO,GAAmB,SAAU,OAAO,EAAe,EAAO,CAAc,EAEnF,GAAI,EAAe,SAAW,EAAG,MAAM,IAAI,EAAA,WAAW,qBAAsB,oCAAoC,EAEhH,IAAM,EAAU,EAAe,IAAI,EAAA,OAAO,EAE1C,GAAI,EAAQ,KAAM,GAAW,EAAO,UAAY,EAAE,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,uCAAuC,EAGpF,IAAM,EAAoB,EAAQ,QAAQ,EAAQ,IAAW,EAAA,IAAI,EAAQ,EAAO,WAAW,EAAG,EAAE,EAC1F,EAAgB,EAAQ,IAAK,GAAW,EAAO,WAAa,EAAoB,EAAO,YAAY,EACnG,EAAc,EAAc,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAEhF,GAAI,IAAgB,GAClB,MAAM,IAAI,EAAA,WAAW,qBAAsB,kDAAkD,EAE/F,IAAM,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAS,EAAc,IAAK,GAAY,EAAW,EAAU,CAAW,EAC1E,EAAY,EAAW,EAAO,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAC1E,EAAS,EACZ,KAAK,EAAQ,KAAW,CAAE,QAAO,UAAY,EAAW,EAAU,CAAY,EAAE,CAAC,CACjF,MAAM,EAAM,IACX,EAAK,YAAc,EAAM,UAAY,EAAK,MAAQ,EAAM,MAAQ,EAAK,UAAY,EAAM,UAAY,GAAK,CAC1G,EAEF,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,IAAc,GAAI,MAEtB,EAAO,EAAM,QAAW,GACxB,GAAa,EACf,CAEA,OAAO,EAAO,IAAK,GAAW,EAAA,UAAU,EAAS,EAAM,EAAM,QAAQ,CAAC,CACxE,CAEA,SAAgB,EACd,EACA,EACU,CACV,GAAI,EAAA,QAAQ,EAAQ,IAAK,EAAQ,GAAG,IAAM,EACxC,MAAM,IAAI,EAAA,WAAW,qBAAsB,qCAAqC,EAGlF,OAAO,EAAA,QAAQ,EAAO,EAAQ,GAAG,IAAM,GAAK,EAAQ,IAAM,EAAA,QAAQ,EAAO,EAAQ,GAAG,IAAM,EAAI,EAAQ,IAAM,CAC9G,CAEA,SAAS,EAAmC,EAAiB,EAAgC,CAC3F,GAAI,CAAC,OAAO,UAAU,CAAU,GAAK,EAAa,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,6CAA6C,EAG1F,IAAM,EAAQ,OAAO,CAAU,EACzB,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAO,EAAW,EAClB,EAAY,EAAW,EAE7B,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAW,GAAI,EAAG,IAC5C,EAAA,WAAW,GAAQ,OAAO,CAAK,EAAI,EAAY,GAAK,KAAO,EAAM,EAAM,QAAQ,CACjF,CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Currency, Money } from './types';
|
|
2
|
+
export declare function sum<C extends Currency>(values: Iterable<Money<C>>, options: {
|
|
3
|
+
currency: C;
|
|
4
|
+
}): Money<C>;
|
|
5
|
+
export declare function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];
|
|
6
|
+
export declare function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];
|
|
7
|
+
export declare function clamp<C extends Currency>(value: Money<C>, options: {
|
|
8
|
+
max: Money<NoInfer<C>>;
|
|
9
|
+
min: Money<NoInfer<C>>;
|
|
10
|
+
}): Money<C>;
|
|
11
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAM/C,wBAAgB,GAAG,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE;IAAE,QAAQ,EAAE,CAAC,CAAA;CAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAatG;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACzF,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAyCtG,wBAAgB,KAAK,CAAC,CAAC,SAAS,QAAQ,EACtC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,EAAE;IAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,GAC1D,KAAK,CAAC,CAAC,CAAC,CAMV"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CoinsError as e, CurrencyMismatchError as t } from "./errors.js";
|
|
2
|
+
import { decimal as n, lcm as r } from "./decimal.js";
|
|
3
|
+
import { compare as i, isMoney as a, withMinor as o } from "./money.js";
|
|
4
|
+
//#region src/aggregate.ts
|
|
5
|
+
function s(n, r) {
|
|
6
|
+
let i = 0n;
|
|
7
|
+
for (let o of n) {
|
|
8
|
+
if (!a(o)) throw new e("INVALID_MONEY", "sum() requires canonical money values");
|
|
9
|
+
if (o.currency !== r.currency) throw new t(r.currency.code, o.currency.code);
|
|
10
|
+
i += o.amount;
|
|
11
|
+
}
|
|
12
|
+
return o(i, r.currency);
|
|
13
|
+
}
|
|
14
|
+
function c(t, i) {
|
|
15
|
+
if (!a(t)) throw new e("INVALID_MONEY", "allocate() requires canonical money");
|
|
16
|
+
if (typeof i == "number") return u(t, i);
|
|
17
|
+
if (i.length === 0) throw new e("INVALID_ALLOCATION", "Allocation weights cannot be empty");
|
|
18
|
+
let s = i.map(n);
|
|
19
|
+
if (s.some((e) => e.numerator < 0n)) throw new e("INVALID_ALLOCATION", "Allocation weights cannot be negative");
|
|
20
|
+
let c = s.reduce((e, t) => r(e, t.denominator), 1n), l = s.map((e) => e.numerator * (c / e.denominator)), d = l.reduce((e, t) => e + t, 0n);
|
|
21
|
+
if (d === 0n) throw new e("INVALID_ALLOCATION", "Allocation weights must include a positive value");
|
|
22
|
+
let f = t.amount < 0n ? -1n : 1n, p = t.amount < 0n ? -t.amount : t.amount, m = l.map((e) => p * e / d), h = p - m.reduce((e, t) => e + t, 0n), g = l.map((e, t) => ({
|
|
23
|
+
index: t,
|
|
24
|
+
remainder: p * e % d
|
|
25
|
+
})).sort((e, t) => e.remainder === t.remainder ? e.index - t.index : e.remainder > t.remainder ? -1 : 1);
|
|
26
|
+
for (let e of g) {
|
|
27
|
+
if (h === 0n) break;
|
|
28
|
+
m[e.index] += 1n, h -= 1n;
|
|
29
|
+
}
|
|
30
|
+
return m.map((e) => o(e * f, t.currency));
|
|
31
|
+
}
|
|
32
|
+
function l(t, n) {
|
|
33
|
+
if (i(n.min, n.max) === 1) throw new e("INVALID_ALLOCATION", "Clamp minimum cannot exceed maximum");
|
|
34
|
+
return i(t, n.min) === -1 ? n.min : i(t, n.max) === 1 ? n.max : t;
|
|
35
|
+
}
|
|
36
|
+
function u(t, n) {
|
|
37
|
+
if (!Number.isInteger(n) || n < 1) throw new e("INVALID_ALLOCATION", "Allocation count must be a positive integer");
|
|
38
|
+
let r = BigInt(n), i = t.amount < 0n ? -1n : 1n, a = t.amount < 0n ? -t.amount : t.amount, s = a / r, c = a % r;
|
|
39
|
+
return Array.from({ length: n }, (e, n) => o((s + (BigInt(n) < c ? 1n : 0n)) * i, t.currency));
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { c as allocate, l as clamp, s as sum };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=aggregate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.js","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import type { Currency, Money } from './types';\n\nimport { decimal, lcm } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { compare, isMoney, withMinor } from './money';\n\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C> {\n let amount = 0n;\n\n for (const value of values) {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'sum() requires canonical money values');\n\n if (value.currency !== options.currency)\n throw new CurrencyMismatchError(options.currency.code, value.currency.code);\n\n amount += value.amount;\n }\n\n return withMinor(amount, options.currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'allocate() requires canonical money');\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => withMinor(amount * sign, value.currency));\n}\n\nexport function clamp<C extends Currency>(\n value: Money<C>,\n options: { max: Money<NoInfer<C>>; min: Money<NoInfer<C>> },\n): Money<C> {\n if (compare(options.min, options.max) === 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Clamp minimum cannot exceed maximum');\n }\n\n return compare(value, options.min) === -1 ? options.min : compare(value, options.max) === 1 ? options.max : value;\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n withMinor((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":";;;;AAMA,SAAgB,EAAwB,GAA4B,GAAoC;CACtG,IAAI,IAAS;CAEb,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,CAAC,EAAQ,CAAK,GAAG,MAAM,IAAI,EAAW,iBAAiB,uCAAuC;EAElG,IAAI,EAAM,aAAa,EAAQ,UAC7B,MAAM,IAAI,EAAsB,EAAQ,SAAS,MAAM,EAAM,SAAS,IAAI;EAE5E,KAAU,EAAM;CAClB;CAEA,OAAO,EAAU,GAAQ,EAAQ,QAAQ;AAC3C;AAIA,SAAgB,EAA6B,GAAiB,GAAwD;CACpH,IAAI,CAAC,EAAQ,CAAK,GAAG,MAAM,IAAI,EAAW,iBAAiB,qCAAqC;CAEhG,IAAI,OAAO,KAAmB,UAAU,OAAO,EAAe,GAAO,CAAc;CAEnF,IAAI,EAAe,WAAW,GAAG,MAAM,IAAI,EAAW,sBAAsB,oCAAoC;CAEhH,IAAM,IAAU,EAAe,IAAI,CAAO;CAE1C,IAAI,EAAQ,MAAM,MAAW,EAAO,YAAY,EAAE,GAChD,MAAM,IAAI,EAAW,sBAAsB,uCAAuC;CAGpF,IAAM,IAAoB,EAAQ,QAAQ,GAAQ,MAAW,EAAI,GAAQ,EAAO,WAAW,GAAG,EAAE,GAC1F,IAAgB,EAAQ,KAAK,MAAW,EAAO,aAAa,IAAoB,EAAO,YAAY,GACnG,IAAc,EAAc,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE;CAEhF,IAAI,MAAgB,IAClB,MAAM,IAAI,EAAW,sBAAsB,kDAAkD;CAE/F,IAAM,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAS,EAAc,KAAK,MAAY,IAAW,IAAU,CAAW,GAC1E,IAAY,IAAW,EAAO,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE,GAC1E,IAAS,EACZ,KAAK,GAAQ,OAAW;EAAE;EAAO,WAAY,IAAW,IAAU;CAAY,EAAE,CAAC,CACjF,MAAM,GAAM,MACX,EAAK,cAAc,EAAM,YAAY,EAAK,QAAQ,EAAM,QAAQ,EAAK,YAAY,EAAM,YAAY,KAAK,CAC1G;CAEF,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,MAAc,IAAI;EAGtB,AADA,EAAO,EAAM,UAAW,IACxB,KAAa;CACf;CAEA,OAAO,EAAO,KAAK,MAAW,EAAU,IAAS,GAAM,EAAM,QAAQ,CAAC;AACxE;AAEA,SAAgB,EACd,GACA,GACU;CACV,IAAI,EAAQ,EAAQ,KAAK,EAAQ,GAAG,MAAM,GACxC,MAAM,IAAI,EAAW,sBAAsB,qCAAqC;CAGlF,OAAO,EAAQ,GAAO,EAAQ,GAAG,MAAM,KAAK,EAAQ,MAAM,EAAQ,GAAO,EAAQ,GAAG,MAAM,IAAI,EAAQ,MAAM;AAC9G;AAEA,SAAS,EAAmC,GAAiB,GAAgC;CAC3F,IAAI,CAAC,OAAO,UAAU,CAAU,KAAK,IAAa,GAChD,MAAM,IAAI,EAAW,sBAAsB,6CAA6C;CAG1F,IAAM,IAAQ,OAAO,CAAU,GACzB,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAO,IAAW,GAClB,IAAY,IAAW;CAE7B,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAC5C,GAAW,KAAQ,OAAO,CAAK,IAAI,IAAY,KAAK,OAAO,GAAM,EAAM,QAAQ,CACjF;AACF"}
|
package/dist/coins.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{expected;received;constructor(e,t){super(`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},n=class extends e{code;constructor(e){super(`Invalid ISO 4217 currency code: "${e}"`),this.code=e}};function r(e){let t=new Map;return{get:e=>t.get(e),set(n,r){t.size>=e&&t.delete(t.keys().next().value),t.set(n,r)}}}var i=r(512);function a(e){let t=i.get(e);if(t!==void 0)return t;let r;try{r=new Intl.NumberFormat(`en`,{currency:e,style:`currency`}).resolvedOptions().maximumFractionDigits}catch{throw new n(e)}if(r===void 0)throw new n(e);return i.set(e,r),r}function o(e){return a(e),e}function s(e){return 10n**BigInt(e)}var c=/^-?\d+(\.\d+)?$/,l=/^(-?\d+\.?\d*)[eE]([+-]?\d+)$/,u=1e3;function d(t){let n=l.exec(t),r=n[1],i=parseInt(n[2],10);if(Math.abs(i)>u)throw new e(`Scientific notation exponent too large: "${t}" (max ±${u})`);let a=r.startsWith(`-`),o=a?r.slice(1):r,s=o.indexOf(`.`),c=s===-1?o:o.replace(`.`,``),d=i-(s===-1?0:o.length-s-1),f;if(d>=0)f=c+`0`.repeat(d);else{let e=c.length+d;f=e<=0?`0.`+`0`.repeat(-e)+c:c.slice(0,e)+`.`+c.slice(e)}return a?`-${f}`:f}function f(t){let n=l.test(t)?d(t):t;if(!c.test(n))throw new e(`Invalid decimal string: "${t}"`);let r=n.startsWith(`-`),i=r?n.slice(1):n,a=i.indexOf(`.`),o=a===-1?i:i.slice(0,a),u=a===-1?``:i.slice(a+1),f=s(u.length);return{denominator:f,negative:r,numerator:BigInt(o||`0`)*f+BigInt(u||`0`)}}function p(t,n,r,i,a=!1){if(n===0n)return t;switch(i){case`ceiling`:return a?t:t+1n;case`down`:return t;case`floor`:return a?t+1n:t;case`half-away-from-zero`:return n*2n>=r?t+1n:t;case`half-even`:{let e=n*2n;return e<r?t:e>r?t+1n:t%2n==0n?t:t+1n}case`up`:return t+1n;default:throw new e(`Unknown rounding mode: ${String(i)}`)}}function m(n,r,i=`half-away-from-zero`){if(n.currency!==r.from)throw new t(n.currency,r.from);if(r.rate===``)throw new e(`Exchange rate must be a non-empty decimal string`);let{denominator:a,negative:s,numerator:c}=f(String(r.rate));if(s)throw new e(`Exchange rate must be non-negative`);let l=n.amount<0n,u=(n.amount<0n?-n.amount:n.amount)*c,d=p(u/a,u%a,a,i,l);return{amount:l?-d:d,currency:o(r.to)}}var h=r(512),g=r(32);function _(t,n){let{locale:r=`en-US`,maximumFractionDigits:i,minimumFractionDigits:o,style:c=`symbol`}=n,l=a(t.currency),u=b(`maximumFractionDigits`,i,l),d=b(`minimumFractionDigits`,o,Math.min(l,u));if(d>u)throw new e(`minimumFractionDigits must be less than or equal to maximumFractionDigits`);let f=ee(t.amount,l,u),p=f<0n,m=p?-f:f,h=s(u),g=m/h,_=x(u===0?``:(m%h).toString().padStart(u,`0`),d),v=S(r,t.currency,c,p);return{frac:_,intStr:C(r).format(g),negative:p,template:v}}function v(e,t={}){return y(e,t).map(e=>e.value).join(``)}function y(e,t={}){let{frac:n,intStr:r,template:i}=_(e,t),a=n.length>0,o=[],s=!1;for(let e of i)if(e.type!==`group`){if(e.type===`integer`){s||=(o.push({type:`integer`,value:r}),!0);continue}if(e.type===`decimal`){a&&o.push({type:`decimal`,value:e.value});continue}if(e.type===`fraction`){a&&o.push({type:`fraction`,value:n});continue}e.type===`currency`?o.push({type:`currency`,value:e.value}):e.type===`minusSign`?o.push({type:`minusSign`,value:e.value}):o.push({type:`literal`,value:e.value})}return o}function b(t,n,r){if(n==null)return r;if(!Number.isInteger(n)||n<0)throw new e(`${t} must be a non-negative integer`);return n}function ee(e,t,n){if(t===n)return e;if(n>t)return e*s(n-t);let r=e<0n,i=r?-e:e,a=s(t-n),o=p(i/a,i%a,a,`half-away-from-zero`);return r?-o:o}function x(e,t){if(e.length===0)return``;let n=e.length;for(;n>t&&e[n-1]===`0`;)n--;return e.slice(0,n)}function S(e,t,n,r){let i=[e,t,n,r?`neg`:`pos`].join(`\0`),a=h.get(i);if(a!==void 0)return a;let o=new Intl.NumberFormat(e,{currency:t,currencyDisplay:n,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(r?-1.1:1.1);return h.set(i,o),o}function C(e){let t=g.get(e);if(t!==void 0)return t;let n=new Intl.NumberFormat(e,{maximumFractionDigits:0,minimumFractionDigits:0,useGrouping:!0});return g.set(e,n),n}var w=!globalThis.__COINS_PROD__;function T(e){w&&console.warn(`[@vielzeug/coins] ${e}`)}function E(e,t){let n=o(t);if(typeof e==`bigint`)return{amount:e,currency:n};if(typeof e==`number`){let t=a(n),r=String(e),i=l.test(r)?d(r):r,o=i.indexOf(`.`),s=o===-1?0:i.length-o-1;return s>t&&T(`money(): number input "${e}" has more decimal places (${s}) than ${n} supports (${t}). Use a decimal string to avoid IEEE-754 precision loss.`),{amount:O(r,t),currency:n}}return{amount:O(String(e),a(n)),currency:n}}function D(e,n){if(e.currency!==n.currency)throw new t(e.currency,n.currency)}function O(e,t){let{denominator:n,negative:r,numerator:i}=f(e),a=i*s(t),o=p(a/n,a%n,n,`half-away-from-zero`);return r?-o:o}function k(e,t){return{amount:t,currency:e.currency}}function A(e){if(typeof e!=`object`||!e)return!1;let t=e;return Object.hasOwn(t,`amount`)&&typeof t.amount==`bigint`&&Object.hasOwn(t,`currency`)&&typeof t.currency==`string`}function j(e,t){return D(e,t),{amount:e.amount+t.amount,currency:e.currency}}function M(e,t){return D(e,t),{amount:e.amount-t.amount,currency:e.currency}}function N(e,t,n=`half-away-from-zero`){let{denominator:r,negative:i,numerator:a}=f(String(t)),o=e.amount<0n!==i,s=(e.amount<0n?-e.amount:e.amount)*a,c=p(s/r,s%r,r,n,o);return{amount:o?-c:c,currency:e.currency}}function P(t,n,r=`half-away-from-zero`){let{denominator:i,negative:a,numerator:o}=f(String(n));if(o===0n)throw new e(`Division by zero`);let s=t.amount<0n!==a,c=(t.amount<0n?-t.amount:t.amount)*i,l=p(c/o,c%o,o,r,s);return{amount:s?-l:l,currency:t.currency}}function F(t,n){if(n.length===0)throw new e(`allocate requires at least one ratio`);let r=n.map(e=>f(String(e)));if(r.some(e=>e.negative))throw new e(`All ratios must be non-negative`);if(!r.some(e=>e.numerator>0n))throw new e(`At least one ratio must be positive`);let i=t.amount<0n,a=i?-t.amount:t.amount,o=r.reduce((e,t)=>t.denominator>e?t.denominator:e,1n),s=r.map(e=>e.numerator*(o/e.denominator)),c=s.reduce((e,t)=>e+t,0n),l=[],u=[];for(let e of s){let t=a*e;l.push(t/c),u.push(t%c)}let d=n.map((e,t)=>t).sort((e,t)=>{let n=u[t]-u[e];return n>0n?1:n<0n?-1:0}),p=[...l],m=a-l.reduce((e,t)=>e+t,0n);for(let e=0;m>0n;e++,m--)p[d[e]]+=1n;return p.map(e=>({amount:i?-e:e,currency:t.currency}))}function I(n){if(n.length===0)throw new e(`sum requires at least one Money value`);let r=n[0].currency;for(let e=1;e<n.length;e++)if(n[e].currency!==r)throw new t(r,n[e].currency);return{amount:n.reduce((e,t)=>e+t.amount,0n),currency:r}}function L(t){if(t.length===0)throw new e(`min requires at least one Money value`);let n=t[0];for(let e=1;e<t.length;e++)n=U(n,t[e])<=0?n:t[e];return n}function R(t){if(t.length===0)throw new e(`max requires at least one Money value`);let n=t[0];for(let e=1;e<t.length;e++)n=U(n,t[e])>=0?n:t[e];return n}function z(t,n){if(!Number.isInteger(n)||n<=0)throw new e(`splitEvenly requires a positive integer number of parts`);return F(t,Array.from({length:n},()=>1))}function B(n,r,i){if(n.currency!==r.currency||n.currency!==i.currency)throw new t(n.currency,n.currency===r.currency?i.currency:r.currency);if(U(r,i)>0)throw new e(`clamp: lower (${$(r)} ${r.currency}) must be <= upper (${$(i)} ${i.currency})`);return R([r,L([n,i])])}function V(e){return{amount:e.amount<0n?-e.amount:e.amount,currency:e.currency}}function H(e){return{amount:-e.amount,currency:e.currency}}function U(e,t){return D(e,t),e.amount<t.amount?-1:+(e.amount>t.amount)}function W(e,t){return e.currency===t.currency&&e.amount===t.amount}function G(e,t){return U(e,t)>0}function K(e,t){return U(e,t)>=0}function q(e,t){return U(e,t)<0}function J(e,t){return U(e,t)<=0}function Y(e){return e.amount===0n}function X(e){return e.amount>0n}function Z(e){return e.amount<0n}function Q(e){return e.amount>=0n}function te(e){return e.amount<=0n}function ne(e){return{amount:String(e.amount),currency:e.currency}}function re(t){let n=o(t.currency);if(typeof t.amount!=`string`)throw new e(`Invalid money amount in JSON: ${String(t.amount)} (expected an integer string, e.g. '123456')`);let r;try{r=BigInt(t.amount)}catch{throw new e(`Invalid money amount in JSON: "${t.amount}" (expected an integer string, e.g. '123456')`)}return{amount:r,currency:n}}function $(e){let t=a(e.currency);if(t===0)return String(e.amount);let n=e.amount<0n,r=n?-e.amount:e.amount,i=s(t),o=r/i,c=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${o}.${c}`}function ie(e){let t=a(e.currency);return Number(e.amount)/Number(s(t))}function ae(t,n,r=`half-away-from-zero`){if(!Number.isInteger(n)||n<0)throw new e(`roundTo: places must be a non-negative integer, got ${n}`);let i=a(t.currency);if(n>i)throw new e(`roundTo: places (${n}) exceeds the decimal places for ${t.currency} (${i})`);if(n===i)return t;let o=s(i-n),c=t.amount<0n,l=c?-t.amount:t.amount,u=p(l/o,l%o,o,r,c);return{amount:c?-u:u,currency:t.currency}}exports.CoinsError=e,exports.CurrencyMismatchError=t,exports.InvalidCurrencyError=n,exports.abs=V,exports.add=j,exports.allocate=F,exports.clamp=B,exports.compare=U,exports.divide=P,exports.exchange=m,exports.format=v,exports.formatParts=y,exports.fromJSON=re,exports.getCurrencyDecimals=a,exports.greaterThan=G,exports.greaterThanOrEqual=K,exports.isEqual=W,exports.isMoney=A,exports.isNegative=Z,exports.isNonNegative=Q,exports.isNonPositive=te,exports.isPositive=X,exports.isZero=Y,exports.lessThan=q,exports.lessThanOrEqual=J,exports.max=R,exports.min=L,exports.money=E,exports.multiply=N,exports.negate=H,exports.roundTo=ae,exports.splitEvenly=z,exports.subtract=M,exports.sum=I,exports.toDecimal=$,exports.toJSON=ne,exports.toNumber=ie,exports.validateCurrencyCode=o,exports.withAmount=k;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class e extends Error{code;static is(t){return t instanceof e}constructor(e,t,n){super(t,n),this.code=e,this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{expected;received;constructor(e,t){super(`CURRENCY_MISMATCH`,`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},n=class extends e{value;constructor(e){super(`INVALID_CURRENCY`,`Unsupported currency: "${String(e)}"`),this.value=e}},r=/^(-?)(\d+)(?:\.(\d+))?$/,i=1e3,a=100;function o(t){if(t.length>i)throw new e(`INVALID_DECIMAL`,`Decimal input is too long`);let n=r.exec(t);if(!n)throw new e(`INVALID_DECIMAL`,`Invalid decimal: "${t}"`);let o=(n[3]??``).replace(/0+$/,``);if(o.length>a)throw new e(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${a} places`);let s=10n**BigInt(o.length),c=BigInt(n[2])*s+BigInt(o||`0`),u=n[1]===`-`&&c!==0n?-c:c,d=l(u<0n?-u:u,s);return Object.freeze({denominator:s/d,numerator:u/d})}function s(t,n,r){if(n<=0n)throw new e(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=t<0n,a=i?-t:t,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1}})()?o+1n:o;return i?-c:c}function c(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function l(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function u(e,t){return e/l(e,t)*t}var d=new Map,f=new Map;function p(e,t){let n=w(e,t);return d.set(e,n),n}var m=p(`USD`,2),h=p(`EUR`,2),g=p(`GBP`,2),_=p(`JPY`,0),ee=p(`KRW`,0),v=p(`BHD`,3),y=p(`KWD`,3);function b({code:e,minorUnit:t}){T(e,t);let n=d.get(e);if(n){if(n.minorUnit!==t)throw E(e,n.minorUnit);return n}let r=f.get(e);if(r){if(r.minorUnit!==t)throw E(e,r.minorUnit);return r}let i=w(e,t);return f.set(e,i),i}function x(e){let t=d.get(e)??f.get(e);if(!t)throw new n(e);return t}function S(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.code==`string`&&(d.get(t.code)===e||f.get(t.code)===e)}function C(e){let t=d.get(e);if(!t)throw new n(e);return t}function w(e,t){return T(e,t),Object.freeze({code:e,minorUnit:t})}function T(t,n){if(!/^[A-Z]{3}$/.test(t))throw new e(`INVALID_CURRENCY`,`Currency code must be three uppercase letters: "${t}"`);if(!Number.isInteger(n)||n<0||n>6)throw new e(`INVALID_CURRENCY`,`Currency "${t}" must have 0–6 minor-unit digits`)}function E(t,n){return new e(`INVALID_CURRENCY`,`Currency "${t}" already has ${n} minor-unit digits`)}var D=`halfAwayFromZero`;function O(t,n,r){if(z(n),typeof t==`bigint`){if(!r||!(`unit`in r)||r.unit!==`minor`)throw new e(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return I(t,n)}if(r&&`unit`in r)throw new e(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let i=o(t),a=i.numerator*10n**BigInt(n.minorUnit);if(a%i.denominator!==0n&&!r)throw new e(`INVALID_MONEY`,`Amount "${t}" exceeds ${n.code} precision; provide rounding`);return I(s(a,i.denominator,r?.rounding??D),n)}function k(t){if(!B(t))throw new e(`INVALID_MONEY`,`Money must be a plain data object`);let n=Object.getOwnPropertyDescriptors(t),r=n.amount,i=n.currency;if(!V(r)||!V(i))throw new e(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof r.value!=`bigint`||!S(i.value))throw new e(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return I(r.value,i.value)}function A(e){try{return k(e),!0}catch{return!1}}function te(e,t){return R(e,t),I(e.amount+t.amount,e.currency)}function ne(e,t){return R(e,t),I(e.amount-t.amount,e.currency)}function re(e,t,n={}){L(e);let r=o(t);return I(s(e.amount*r.numerator,r.denominator,n.rounding??D),e.currency)}function ie(t,n,r={}){L(t);let i=o(n);if(i.numerator===0n)throw new e(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);return I(s(t.amount*i.denominator,i.numerator<0n?-i.numerator:i.numerator,r.rounding??D)*(i.numerator<0n?-1n:1n),t.currency)}function j(e,t){return R(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function ae(e){return L(e),I(e.amount<0n?-e.amount:e.amount,e.currency)}function M(e){return L(e),I(-e.amount,e.currency)}function N(t,n){L(t);let{fractionDigits:r,rounding:i=D}=n;if(!Number.isInteger(r)||r<0||r>t.currency.minorUnit)throw new e(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${t.currency.minorUnit}`);let a=10n**BigInt(t.currency.minorUnit-r);return I(s(t.amount,a,i)*a,t.currency)}function P(e){return L(e),c(e.amount,e.currency.minorUnit)}function F(e,t){return z(t),I(e,t)}function I(e,t){return Object.freeze({amount:e,currency:t})}function L(t){if(!Object.isFrozen(t)||!S(t.currency))throw new e(`INVALID_MONEY`,`Money must be a canonical Coins value`)}function R(e,n){if(L(e),L(n),e.currency!==n.currency)throw new t(e.currency.code,n.currency.code)}function z(t){if(!S(t))throw new e(`INVALID_CURRENCY`,`Money requires a registered currency`)}function B(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function V(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}function H(n,r){let i=0n;for(let a of n){if(!A(a))throw new e(`INVALID_MONEY`,`sum() requires canonical money values`);if(a.currency!==r.currency)throw new t(r.currency.code,a.currency.code);i+=a.amount}return F(i,r.currency)}function U(t,n){if(!A(t))throw new e(`INVALID_MONEY`,`allocate() requires canonical money`);if(typeof n==`number`)return G(t,n);if(n.length===0)throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let r=n.map(o);if(r.some(e=>e.numerator<0n))throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let i=r.reduce((e,t)=>u(e,t.denominator),1n),a=r.map(e=>e.numerator*(i/e.denominator)),s=a.reduce((e,t)=>e+t,0n);if(s===0n)throw new e(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let c=t.amount<0n?-1n:1n,l=t.amount<0n?-t.amount:t.amount,d=a.map(e=>l*e/s),f=l-d.reduce((e,t)=>e+t,0n),p=a.map((e,t)=>({index:t,remainder:l*e%s})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of p){if(f===0n)break;d[e.index]+=1n,f-=1n}return d.map(e=>F(e*c,t.currency))}function W(t,n){if(j(n.min,n.max)===1)throw new e(`INVALID_ALLOCATION`,`Clamp minimum cannot exceed maximum`);return j(t,n.min)===-1?n.min:j(t,n.max)===1?n.max:t}function G(t,n){if(!Number.isInteger(n)||n<1)throw new e(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let r=BigInt(n),i=t.amount<0n?-1n:1n,a=t.amount<0n?-t.amount:t.amount,o=a/r,s=a%r;return Array.from({length:n},(e,n)=>F((o+(BigInt(n)<s?1n:0n))*i,t.currency))}function K({from:t,to:n,value:r}){if(!S(t)||!S(n))throw new e(`INVALID_CURRENCY`,`Exchange rate requires registered currencies`);let i=o(r);if(i.numerator<0n)throw new e(`INVALID_DECIMAL`,`Exchange rates cannot be negative`);return Object.freeze({from:t,to:n,value:i})}function q(n,r,i={}){if(!A(n)||!oe(r))throw new e(`INVALID_MONEY`,`Exchange requires canonical money and rate values`);if(n.currency!==r.from)throw new t(n.currency.code,r.from.code);return F(s(n.amount*r.value.numerator*10n**BigInt(r.to.minorUnit),r.value.denominator*10n**BigInt(r.from.minorUnit),i.rounding??`halfAwayFromZero`),r.to)}function oe(e){if(typeof e!=`object`||!e||!Object.isFrozen(e))return!1;let t=e;return S(t.from)&&S(t.to)&&typeof t.value==`object`&&t.value!==null&&Object.isFrozen(t.value)&&typeof t.value.numerator==`bigint`&&t.value.numerator>=0n&&typeof t.value.denominator==`bigint`&&t.value.denominator>0n}var J=20,Y=new Map,X=new Map;function se(e,t={}){return Z(e,t).map(e=>e.value).join(``)}function Z(t,n={}){if(!A(t))throw new e(`INVALID_MONEY`,`format() requires canonical money`);let{locale:r=`en-US`,maximumFractionDigits:i=t.currency.minorUnit,minimumFractionDigits:a=t.currency.minorUnit,style:o=`symbol`}=n;ce(a,i);let c=10n**BigInt(i),l=i>=t.currency.minorUnit?t.amount*10n**BigInt(i-t.currency.minorUnit):s(t.amount,10n**BigInt(t.currency.minorUnit-i),`halfAwayFromZero`),u=l<0n,d=u?-l:l,f=d/c,p=(i===0?``:(d%c).toString().padStart(i,`0`)).replace(RegExp(`0{0,${Math.max(0,i-a)}}$`),``),m=le(r,t.currency.code,o,u),h=[],g=!1;for(let e of m)e.type!==`group`&&(e.type===`integer`?g||=(h.push({type:`integer`,value:ue(r).format(f)}),!0):e.type===`decimal`?p&&h.push({type:`decimal`,value:e.value}):e.type===`fraction`?p&&h.push({type:`fraction`,value:p}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?h.push({type:e.type,value:e.value}):h.push({type:`literal`,value:e.value}));return h}function ce(t,n){if(!Number.isInteger(n)||!Number.isInteger(t)||t<0||n<t||n>J)throw new e(`INVALID_ROUNDING`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${J}`)}function le(t,n,r,i){let a=`${t}\0${n}\0${r}\0${i}`,o=X.get(a);if(o)return o;try{let e=new Intl.NumberFormat(t,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return X.set(a,e),e}catch(r){throw new e(`INVALID_CURRENCY`,`Cannot format currency "${n}" for locale "${t}"`,{cause:r})}}function ue(t){let n=Y.get(t);if(n)return n;try{let e=new Intl.NumberFormat(t,{maximumFractionDigits:0,useGrouping:!0});return Y.set(t,e),e}catch(n){throw new e(`INVALID_ROUNDING`,`Cannot create number formatter for locale "${t}"`,{cause:n})}}var Q=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,$=[`amount`,`currency`,`unit`];function de(e){return{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function fe(t,n={}){try{let e=pe(t),r=n.currency??C;return O(BigInt(e.amount),r(e.currency),{unit:`minor`})}catch(t){throw new e(`INVALID_MONEY`,`Invalid Money JSON`,{cause:t})}}function pe(e){if(typeof e!=`object`||!e||Object.getPrototypeOf(e)!==Object.prototype)throw TypeError(`Money JSON must be a plain object`);let t=Object.getOwnPropertyDescriptors(e),n=Reflect.ownKeys(e);if(n.length!==$.length||!$.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of $){let n=t[e];if(!n||!(`value`in n)||n.get||n.set)throw TypeError(`Money JSON property "${e}" must be a data value`)}let r=t.amount.value,i=t.currency.value,a=t.unit.value;if(typeof r!=`string`||!Q.test(r))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof i!=`string`||a!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:r,currency:i,unit:a}}exports.BHD=v,exports.CoinsError=e,exports.CurrencyMismatchError=t,exports.EUR=h,exports.GBP=g,exports.InvalidCurrencyError=n,exports.JPY=_,exports.KRW=ee,exports.KWD=y,exports.USD=m,exports.abs=ae,exports.add=te,exports.allocate=U,exports.clamp=W,exports.compare=j,exports.currency=x,exports.decimal=o,exports.defineCurrency=b,exports.divide=ie,exports.exchange=q,exports.exchangeRate=K,exports.format=se,exports.formatParts=Z,exports.isCurrency=S,exports.isMoney=A,exports.money=O,exports.multiply=re,exports.negate=M,exports.parseMoney=k,exports.parseMoneyJSON=fe,exports.round=N,exports.subtract=ne,exports.sum=H,exports.toDecimal=P,exports.toJSON=de;
|
|
2
2
|
//# sourceMappingURL=coins.cjs.map
|