monetra 1.0.0 → 1.1.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/dist/index.d.mts +227 -25
- package/dist/index.d.ts +227 -25
- package/dist/index.js +439 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +431 -62
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/dist/index 2.js +0 -424
- package/dist/index 2.mjs +0 -381
- package/dist/index.d 2.mts +0 -76
- package/dist/index.d 2.ts +0 -76
- package/dist/index.js 2.map +0 -1
- package/dist/index.mjs 2.map +0 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
CURRENCIES: () => CURRENCIES,
|
|
24
|
+
Converter: () => Converter,
|
|
24
25
|
CurrencyMismatchError: () => CurrencyMismatchError,
|
|
25
26
|
EUR: () => EUR,
|
|
26
27
|
GBP: () => GBP,
|
|
@@ -29,17 +30,49 @@ __export(index_exports, {
|
|
|
29
30
|
JPY: () => JPY,
|
|
30
31
|
MonetraError: () => MonetraError,
|
|
31
32
|
Money: () => Money,
|
|
33
|
+
MoneyBag: () => MoneyBag,
|
|
32
34
|
OverflowError: () => OverflowError,
|
|
33
35
|
RoundingMode: () => RoundingMode,
|
|
34
36
|
RoundingRequiredError: () => RoundingRequiredError,
|
|
35
37
|
USD: () => USD,
|
|
36
38
|
ZAR: () => ZAR,
|
|
39
|
+
assertNonNegative: () => assertNonNegative,
|
|
40
|
+
assertSameCurrency: () => assertSameCurrency,
|
|
37
41
|
divideWithRounding: () => divideWithRounding,
|
|
38
42
|
getCurrency: () => getCurrency,
|
|
39
|
-
getMinorUnitExponent: () => getMinorUnitExponent
|
|
43
|
+
getMinorUnitExponent: () => getMinorUnitExponent,
|
|
44
|
+
isCurrencyRegistered: () => isCurrencyRegistered,
|
|
45
|
+
money: () => money,
|
|
46
|
+
registerCurrency: () => registerCurrency
|
|
40
47
|
});
|
|
41
48
|
module.exports = __toCommonJS(index_exports);
|
|
42
49
|
|
|
50
|
+
// src/currency/registry.ts
|
|
51
|
+
var registry = /* @__PURE__ */ new Map();
|
|
52
|
+
function registerCurrency(currency) {
|
|
53
|
+
registry.set(currency.code, currency);
|
|
54
|
+
}
|
|
55
|
+
function getCurrency(code) {
|
|
56
|
+
const currency = registry.get(code);
|
|
57
|
+
if (!currency) {
|
|
58
|
+
throw new Error(`Currency '${code}' not found in registry.`);
|
|
59
|
+
}
|
|
60
|
+
return currency;
|
|
61
|
+
}
|
|
62
|
+
function isCurrencyRegistered(code) {
|
|
63
|
+
return registry.has(code);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/rounding/strategies.ts
|
|
67
|
+
var RoundingMode = /* @__PURE__ */ ((RoundingMode3) => {
|
|
68
|
+
RoundingMode3["HALF_UP"] = "HALF_UP";
|
|
69
|
+
RoundingMode3["HALF_DOWN"] = "HALF_DOWN";
|
|
70
|
+
RoundingMode3["HALF_EVEN"] = "HALF_EVEN";
|
|
71
|
+
RoundingMode3["FLOOR"] = "FLOOR";
|
|
72
|
+
RoundingMode3["CEIL"] = "CEIL";
|
|
73
|
+
return RoundingMode3;
|
|
74
|
+
})(RoundingMode || {});
|
|
75
|
+
|
|
43
76
|
// src/errors/BaseError.ts
|
|
44
77
|
var MonetraError = class extends Error {
|
|
45
78
|
constructor(message) {
|
|
@@ -51,8 +84,13 @@ var MonetraError = class extends Error {
|
|
|
51
84
|
|
|
52
85
|
// src/errors/CurrencyMismatchError.ts
|
|
53
86
|
var CurrencyMismatchError = class extends MonetraError {
|
|
54
|
-
constructor(expected,
|
|
55
|
-
super(
|
|
87
|
+
constructor(expected, received) {
|
|
88
|
+
super(
|
|
89
|
+
`Currency mismatch: expected ${expected}, received ${received}.
|
|
90
|
+
\u{1F4A1} Tip: Use a Converter to convert between currencies:
|
|
91
|
+
const converter = new Converter('USD', { ${received}: rate });
|
|
92
|
+
const converted = converter.convert(money, '${expected}');`
|
|
93
|
+
);
|
|
56
94
|
}
|
|
57
95
|
};
|
|
58
96
|
|
|
@@ -65,8 +103,15 @@ var InvalidPrecisionError = class extends MonetraError {
|
|
|
65
103
|
|
|
66
104
|
// src/errors/RoundingRequiredError.ts
|
|
67
105
|
var RoundingRequiredError = class extends MonetraError {
|
|
68
|
-
constructor() {
|
|
69
|
-
|
|
106
|
+
constructor(operation, result) {
|
|
107
|
+
let message = "Rounding is required for this operation but was not provided.";
|
|
108
|
+
if (operation && result !== void 0) {
|
|
109
|
+
message = `Rounding required for ${operation}: result ${result} is not an integer.
|
|
110
|
+
\u{1F4A1} Tip: Provide a rounding mode:
|
|
111
|
+
money.${operation}(value, { rounding: RoundingMode.HALF_UP })
|
|
112
|
+
Available modes: HALF_UP, HALF_DOWN, HALF_EVEN, FLOOR, CEIL`;
|
|
113
|
+
}
|
|
114
|
+
super(message);
|
|
70
115
|
}
|
|
71
116
|
};
|
|
72
117
|
|
|
@@ -90,16 +135,11 @@ function assertSameCurrency(a, b) {
|
|
|
90
135
|
throw new CurrencyMismatchError(a.currency.code, b.currency.code);
|
|
91
136
|
}
|
|
92
137
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
RoundingMode3["HALF_EVEN"] = "HALF_EVEN";
|
|
99
|
-
RoundingMode3["FLOOR"] = "FLOOR";
|
|
100
|
-
RoundingMode3["CEIL"] = "CEIL";
|
|
101
|
-
return RoundingMode3;
|
|
102
|
-
})(RoundingMode || {});
|
|
138
|
+
function assertNonNegative(money2) {
|
|
139
|
+
if (money2.isNegative()) {
|
|
140
|
+
throw new Error("Money value must be non-negative");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
103
143
|
|
|
104
144
|
// src/rounding/index.ts
|
|
105
145
|
function divideWithRounding(numerator, denominator, mode) {
|
|
@@ -160,10 +200,24 @@ function multiply(amount, multiplier, rounding) {
|
|
|
160
200
|
return product / denominator;
|
|
161
201
|
}
|
|
162
202
|
if (!rounding) {
|
|
163
|
-
throw new RoundingRequiredError(
|
|
203
|
+
throw new RoundingRequiredError(
|
|
204
|
+
"multiply",
|
|
205
|
+
Number(product) / Number(denominator)
|
|
206
|
+
);
|
|
164
207
|
}
|
|
165
208
|
return divideWithRounding(product, denominator, rounding);
|
|
166
209
|
}
|
|
210
|
+
function divide(amount, divisor, rounding) {
|
|
211
|
+
const { numerator, denominator } = parseMultiplier(divisor);
|
|
212
|
+
const product = amount * denominator;
|
|
213
|
+
if (product % numerator === 0n) {
|
|
214
|
+
return product / numerator;
|
|
215
|
+
}
|
|
216
|
+
if (!rounding) {
|
|
217
|
+
throw new RoundingRequiredError("divide", Number(product) / Number(numerator));
|
|
218
|
+
}
|
|
219
|
+
return divideWithRounding(product, numerator, rounding);
|
|
220
|
+
}
|
|
167
221
|
function parseMultiplier(multiplier) {
|
|
168
222
|
const s = multiplier.toString();
|
|
169
223
|
if (/[eE]/.test(s)) {
|
|
@@ -252,11 +306,12 @@ function parseToMinor(amount, currency) {
|
|
|
252
306
|
}
|
|
253
307
|
|
|
254
308
|
// src/format/formatter.ts
|
|
255
|
-
function format(
|
|
256
|
-
const locale = options?.locale ||
|
|
309
|
+
function format(money2, options) {
|
|
310
|
+
const locale = options?.locale || money2.currency.locale || "en-US";
|
|
257
311
|
const showSymbol = options?.symbol ?? true;
|
|
258
|
-
const
|
|
259
|
-
const
|
|
312
|
+
const display = options?.display || "symbol";
|
|
313
|
+
const decimals = money2.currency.decimals;
|
|
314
|
+
const minor = money2.minor;
|
|
260
315
|
const absMinor = minor < 0n ? -minor : minor;
|
|
261
316
|
const divisor = 10n ** BigInt(decimals);
|
|
262
317
|
const integerPart = absMinor / divisor;
|
|
@@ -277,7 +332,8 @@ function format(money, options) {
|
|
|
277
332
|
}
|
|
278
333
|
const templateParts = new Intl.NumberFormat(locale, {
|
|
279
334
|
style: "currency",
|
|
280
|
-
currency:
|
|
335
|
+
currency: money2.currency.code,
|
|
336
|
+
currencyDisplay: display
|
|
281
337
|
}).formatToParts(minor < 0n ? -1 : 1);
|
|
282
338
|
let result = "";
|
|
283
339
|
let numberInserted = false;
|
|
@@ -302,66 +358,135 @@ var Money = class _Money {
|
|
|
302
358
|
this.minor = minor;
|
|
303
359
|
this.currency = currency;
|
|
304
360
|
}
|
|
361
|
+
static resolveCurrency(currency) {
|
|
362
|
+
if (typeof currency === "string") {
|
|
363
|
+
return getCurrency(currency);
|
|
364
|
+
}
|
|
365
|
+
return currency;
|
|
366
|
+
}
|
|
305
367
|
/**
|
|
306
368
|
* Creates a Money instance from minor units (e.g., cents).
|
|
307
|
-
*
|
|
369
|
+
*
|
|
308
370
|
* @param minor - The amount in minor units. Can be a number or BigInt.
|
|
309
|
-
* @param currency - The currency of the money.
|
|
371
|
+
* @param currency - The currency of the money (object or code string).
|
|
310
372
|
* @returns A new Money instance.
|
|
311
373
|
* @example
|
|
312
374
|
* const m = Money.fromMinor(100, USD); // $1.00
|
|
375
|
+
* const m2 = Money.fromMinor(100, 'USD'); // $1.00
|
|
313
376
|
*/
|
|
314
377
|
static fromMinor(minor, currency) {
|
|
315
|
-
return new _Money(BigInt(minor), currency);
|
|
378
|
+
return new _Money(BigInt(minor), _Money.resolveCurrency(currency));
|
|
316
379
|
}
|
|
317
380
|
/**
|
|
318
381
|
* Creates a Money instance from major units (e.g., "10.50").
|
|
319
|
-
*
|
|
382
|
+
*
|
|
320
383
|
* @param amount - The amount as a string. Must be a valid decimal number.
|
|
321
|
-
* @param currency - The currency of the money.
|
|
384
|
+
* @param currency - The currency of the money (object or code string).
|
|
322
385
|
* @returns A new Money instance.
|
|
323
386
|
* @throws {InvalidPrecisionError} If the amount has more decimal places than the currency allows.
|
|
324
387
|
* @example
|
|
325
388
|
* const m = Money.fromMajor("10.50", USD); // $10.50
|
|
326
389
|
*/
|
|
327
390
|
static fromMajor(amount, currency) {
|
|
328
|
-
const
|
|
329
|
-
|
|
391
|
+
const resolvedCurrency = _Money.resolveCurrency(currency);
|
|
392
|
+
const minor = parseToMinor(amount, resolvedCurrency);
|
|
393
|
+
return new _Money(minor, resolvedCurrency);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Creates a Money instance from a floating-point number.
|
|
397
|
+
*
|
|
398
|
+
* ⚠️ WARNING: Floating-point numbers can have precision issues.
|
|
399
|
+
* Prefer `Money.fromMajor("10.50", currency)` for exact values.
|
|
400
|
+
*
|
|
401
|
+
* @param amount - The float amount in major units.
|
|
402
|
+
* @param currency - The currency.
|
|
403
|
+
* @param options - Options for handling precision.
|
|
404
|
+
* @returns A new Money instance.
|
|
405
|
+
*/
|
|
406
|
+
static fromFloat(amount, currency, options) {
|
|
407
|
+
if (!options?.suppressWarning && process.env.NODE_ENV !== "production") {
|
|
408
|
+
console.warn(
|
|
409
|
+
'[monetra] Money.fromFloat() may lose precision. Consider using Money.fromMajor("' + amount + '", currency) instead.'
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
const resolvedCurrency = _Money.resolveCurrency(currency);
|
|
413
|
+
const factor = 10 ** resolvedCurrency.decimals;
|
|
414
|
+
const minorUnits = Math.round(amount * factor);
|
|
415
|
+
return new _Money(BigInt(minorUnits), resolvedCurrency);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Returns the minimum of the provided Money values.
|
|
419
|
+
* @param values - Money values to compare (must all be same currency).
|
|
420
|
+
* @returns The Money with the smallest amount.
|
|
421
|
+
* @throws {CurrencyMismatchError} If currencies don't match.
|
|
422
|
+
*/
|
|
423
|
+
static min(...values) {
|
|
424
|
+
if (values.length === 0)
|
|
425
|
+
throw new Error("At least one Money value required");
|
|
426
|
+
return values.reduce((min, current) => {
|
|
427
|
+
assertSameCurrency(min, current);
|
|
428
|
+
return current.lessThan(min) ? current : min;
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Returns the maximum of the provided Money values.
|
|
433
|
+
* @param values - Money values to compare (must all be same currency).
|
|
434
|
+
* @returns The Money with the largest amount.
|
|
435
|
+
* @throws {CurrencyMismatchError} If currencies don't match.
|
|
436
|
+
*/
|
|
437
|
+
static max(...values) {
|
|
438
|
+
if (values.length === 0)
|
|
439
|
+
throw new Error("At least one Money value required");
|
|
440
|
+
return values.reduce((max, current) => {
|
|
441
|
+
assertSameCurrency(max, current);
|
|
442
|
+
return current.greaterThan(max) ? current : max;
|
|
443
|
+
});
|
|
330
444
|
}
|
|
331
445
|
/**
|
|
332
446
|
* Creates a Money instance representing zero in the given currency.
|
|
333
|
-
*
|
|
447
|
+
*
|
|
334
448
|
* @param currency - The currency.
|
|
335
449
|
* @returns A new Money instance with value 0.
|
|
336
450
|
*/
|
|
337
451
|
static zero(currency) {
|
|
338
|
-
return new _Money(0n, currency);
|
|
452
|
+
return new _Money(0n, _Money.resolveCurrency(currency));
|
|
453
|
+
}
|
|
454
|
+
resolveOther(other) {
|
|
455
|
+
if (other instanceof _Money) {
|
|
456
|
+
return other;
|
|
457
|
+
}
|
|
458
|
+
if (typeof other === "string") {
|
|
459
|
+
return _Money.fromMajor(other, this.currency);
|
|
460
|
+
}
|
|
461
|
+
return _Money.fromMinor(other, this.currency);
|
|
339
462
|
}
|
|
340
463
|
/**
|
|
341
464
|
* Adds another Money value to this one.
|
|
342
|
-
*
|
|
343
|
-
* @param other - The
|
|
465
|
+
*
|
|
466
|
+
* @param other - The value to add (Money, minor units as number/bigint, or major units as string).
|
|
344
467
|
* @returns A new Money instance representing the sum.
|
|
345
468
|
* @throws {CurrencyMismatchError} If the currencies do not match.
|
|
346
469
|
*/
|
|
347
470
|
add(other) {
|
|
348
|
-
|
|
349
|
-
|
|
471
|
+
const otherMoney = this.resolveOther(other);
|
|
472
|
+
assertSameCurrency(this, otherMoney);
|
|
473
|
+
return new _Money(add(this.minor, otherMoney.minor), this.currency);
|
|
350
474
|
}
|
|
351
475
|
/**
|
|
352
476
|
* Subtracts another Money value from this one.
|
|
353
|
-
*
|
|
354
|
-
* @param other - The
|
|
477
|
+
*
|
|
478
|
+
* @param other - The value to subtract (Money, minor units as number/bigint, or major units as string).
|
|
355
479
|
* @returns A new Money instance representing the difference.
|
|
356
480
|
* @throws {CurrencyMismatchError} If the currencies do not match.
|
|
357
481
|
*/
|
|
358
482
|
subtract(other) {
|
|
359
|
-
|
|
360
|
-
|
|
483
|
+
const otherMoney = this.resolveOther(other);
|
|
484
|
+
assertSameCurrency(this, otherMoney);
|
|
485
|
+
return new _Money(subtract(this.minor, otherMoney.minor), this.currency);
|
|
361
486
|
}
|
|
362
487
|
/**
|
|
363
488
|
* Multiplies this Money value by a scalar.
|
|
364
|
-
*
|
|
489
|
+
*
|
|
365
490
|
* @param multiplier - The number to multiply by.
|
|
366
491
|
* @param options - Options for rounding if the result is not an integer.
|
|
367
492
|
* @returns A new Money instance representing the product.
|
|
@@ -371,12 +496,45 @@ var Money = class _Money {
|
|
|
371
496
|
const result = multiply(this.minor, multiplier, options?.rounding);
|
|
372
497
|
return new _Money(result, this.currency);
|
|
373
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Divides this Money value by a divisor.
|
|
501
|
+
*
|
|
502
|
+
* @param divisor - The number to divide by.
|
|
503
|
+
* @param options - Options for rounding if the result is not an integer.
|
|
504
|
+
* @returns A new Money instance representing the quotient.
|
|
505
|
+
* @throws {RoundingRequiredError} If the result is fractional and no rounding mode is provided.
|
|
506
|
+
* @throws {Error} If divisor is zero.
|
|
507
|
+
*/
|
|
508
|
+
divide(divisor, options) {
|
|
509
|
+
if (divisor === 0 || divisor === "0") {
|
|
510
|
+
throw new Error("Division by zero");
|
|
511
|
+
}
|
|
512
|
+
const result = divide(this.minor, divisor, options?.rounding);
|
|
513
|
+
return new _Money(result, this.currency);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Returns the absolute value of this Money.
|
|
517
|
+
* @returns A new Money instance with the absolute value.
|
|
518
|
+
*/
|
|
519
|
+
abs() {
|
|
520
|
+
return new _Money(
|
|
521
|
+
this.minor < 0n ? -this.minor : this.minor,
|
|
522
|
+
this.currency
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Returns the negated value of this Money.
|
|
527
|
+
* @returns A new Money instance with the negated value.
|
|
528
|
+
*/
|
|
529
|
+
negate() {
|
|
530
|
+
return new _Money(-this.minor, this.currency);
|
|
531
|
+
}
|
|
374
532
|
/**
|
|
375
533
|
* Allocates (splits) this Money value according to a list of ratios.
|
|
376
|
-
*
|
|
534
|
+
*
|
|
377
535
|
* The sum of the parts will always equal the original amount.
|
|
378
536
|
* Remainders are distributed to the parts with the largest fractional remainders.
|
|
379
|
-
*
|
|
537
|
+
*
|
|
380
538
|
* @param ratios - A list of numbers representing the ratios to split by.
|
|
381
539
|
* @returns An array of Money instances.
|
|
382
540
|
*/
|
|
@@ -386,7 +544,7 @@ var Money = class _Money {
|
|
|
386
544
|
}
|
|
387
545
|
/**
|
|
388
546
|
* Formats this Money value as a string.
|
|
389
|
-
*
|
|
547
|
+
*
|
|
390
548
|
* @param options - Formatting options.
|
|
391
549
|
* @returns The formatted string.
|
|
392
550
|
*/
|
|
@@ -395,38 +553,106 @@ var Money = class _Money {
|
|
|
395
553
|
}
|
|
396
554
|
/**
|
|
397
555
|
* Checks if this Money value is equal to another.
|
|
398
|
-
*
|
|
399
|
-
* @param other - The other Money value.
|
|
556
|
+
*
|
|
557
|
+
* @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
|
|
400
558
|
* @returns True if amounts and currencies are equal.
|
|
401
559
|
*/
|
|
402
560
|
equals(other) {
|
|
403
|
-
|
|
561
|
+
const otherMoney = this.resolveOther(other);
|
|
562
|
+
return this.currency.code === otherMoney.currency.code && this.minor === otherMoney.minor;
|
|
404
563
|
}
|
|
405
564
|
/**
|
|
406
565
|
* Checks if this Money value is greater than another.
|
|
407
|
-
*
|
|
408
|
-
* @param other - The other Money value.
|
|
566
|
+
*
|
|
567
|
+
* @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
|
|
409
568
|
* @returns True if this value is greater.
|
|
410
569
|
* @throws {CurrencyMismatchError} If the currencies do not match.
|
|
411
570
|
*/
|
|
412
571
|
greaterThan(other) {
|
|
413
|
-
|
|
414
|
-
|
|
572
|
+
const otherMoney = this.resolveOther(other);
|
|
573
|
+
assertSameCurrency(this, otherMoney);
|
|
574
|
+
return this.minor > otherMoney.minor;
|
|
415
575
|
}
|
|
416
576
|
/**
|
|
417
577
|
* Checks if this Money value is less than another.
|
|
418
|
-
*
|
|
419
|
-
* @param other - The other Money value.
|
|
578
|
+
*
|
|
579
|
+
* @param other - The other Money value (Money, minor units as number/bigint, or major units as string).
|
|
420
580
|
* @returns True if this value is less.
|
|
421
581
|
* @throws {CurrencyMismatchError} If the currencies do not match.
|
|
422
582
|
*/
|
|
423
583
|
lessThan(other) {
|
|
424
|
-
|
|
425
|
-
|
|
584
|
+
const otherMoney = this.resolveOther(other);
|
|
585
|
+
assertSameCurrency(this, otherMoney);
|
|
586
|
+
return this.minor < otherMoney.minor;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Checks if this Money value is greater than or equal to another.
|
|
590
|
+
*/
|
|
591
|
+
greaterThanOrEqual(other) {
|
|
592
|
+
const otherMoney = this.resolveOther(other);
|
|
593
|
+
assertSameCurrency(this, otherMoney);
|
|
594
|
+
return this.minor >= otherMoney.minor;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Checks if this Money value is less than or equal to another.
|
|
598
|
+
*/
|
|
599
|
+
lessThanOrEqual(other) {
|
|
600
|
+
const otherMoney = this.resolveOther(other);
|
|
601
|
+
assertSameCurrency(this, otherMoney);
|
|
602
|
+
return this.minor <= otherMoney.minor;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Checks if this Money value is positive (greater than zero).
|
|
606
|
+
*/
|
|
607
|
+
isPositive() {
|
|
608
|
+
return this.minor > 0n;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Compares this Money to another, returning -1, 0, or 1.
|
|
612
|
+
* Useful for sorting.
|
|
613
|
+
*/
|
|
614
|
+
compare(other) {
|
|
615
|
+
const otherMoney = this.resolveOther(other);
|
|
616
|
+
assertSameCurrency(this, otherMoney);
|
|
617
|
+
if (this.minor < otherMoney.minor) return -1;
|
|
618
|
+
if (this.minor > otherMoney.minor) return 1;
|
|
619
|
+
return 0;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Calculates a percentage of the money.
|
|
623
|
+
* @param percent - The percentage (e.g., 50 for 50%).
|
|
624
|
+
* @param rounding - Rounding mode (defaults to HALF_EVEN).
|
|
625
|
+
*/
|
|
626
|
+
percentage(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
|
|
627
|
+
return this.multiply(percent / 100, { rounding });
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Adds a percentage to the money.
|
|
631
|
+
* @param percent - The percentage to add.
|
|
632
|
+
* @param rounding - Rounding mode.
|
|
633
|
+
*/
|
|
634
|
+
addPercent(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
|
|
635
|
+
return this.add(this.percentage(percent, rounding));
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Subtracts a percentage from the money.
|
|
639
|
+
* @param percent - The percentage to subtract.
|
|
640
|
+
* @param rounding - Rounding mode.
|
|
641
|
+
*/
|
|
642
|
+
subtractPercent(percent, rounding = "HALF_EVEN" /* HALF_EVEN */) {
|
|
643
|
+
return this.subtract(this.percentage(percent, rounding));
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Splits the money into equal parts.
|
|
647
|
+
* @param parts - Number of parts.
|
|
648
|
+
*/
|
|
649
|
+
split(parts) {
|
|
650
|
+
const ratios = Array(parts).fill(1);
|
|
651
|
+
return this.allocate(ratios);
|
|
426
652
|
}
|
|
427
653
|
/**
|
|
428
654
|
* Checks if this Money value is zero.
|
|
429
|
-
*
|
|
655
|
+
*
|
|
430
656
|
* @returns True if the amount is zero.
|
|
431
657
|
*/
|
|
432
658
|
isZero() {
|
|
@@ -434,12 +660,149 @@ var Money = class _Money {
|
|
|
434
660
|
}
|
|
435
661
|
/**
|
|
436
662
|
* Checks if this Money value is negative.
|
|
437
|
-
*
|
|
663
|
+
*
|
|
438
664
|
* @returns True if the amount is negative.
|
|
439
665
|
*/
|
|
440
666
|
isNegative() {
|
|
441
667
|
return this.minor < 0n;
|
|
442
668
|
}
|
|
669
|
+
/**
|
|
670
|
+
* Returns a JSON representation of the Money object.
|
|
671
|
+
*
|
|
672
|
+
* @returns An object with amount (string), currency (code), and precision.
|
|
673
|
+
*/
|
|
674
|
+
toJSON() {
|
|
675
|
+
return {
|
|
676
|
+
amount: this.minor.toString(),
|
|
677
|
+
currency: this.currency.code,
|
|
678
|
+
precision: this.currency.decimals
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Returns a string representation of the Money object (formatted).
|
|
683
|
+
*/
|
|
684
|
+
toString() {
|
|
685
|
+
return this.format();
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// src/money/Converter.ts
|
|
690
|
+
var Converter = class {
|
|
691
|
+
/**
|
|
692
|
+
* Creates a new Converter.
|
|
693
|
+
*
|
|
694
|
+
* @param base - The base currency code (e.g., "USD").
|
|
695
|
+
* @param rates - A map of currency codes to exchange rates relative to the base.
|
|
696
|
+
* Example: { "EUR": 0.85, "GBP": 0.75 } (where 1 Base = 0.85 EUR).
|
|
697
|
+
*/
|
|
698
|
+
constructor(base, rates) {
|
|
699
|
+
this.base = base;
|
|
700
|
+
this.rates = { ...rates };
|
|
701
|
+
if (this.rates[base] === void 0) {
|
|
702
|
+
this.rates[base] = 1;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Converts a Money object to a target currency.
|
|
707
|
+
*
|
|
708
|
+
* @param money - The Money object to convert.
|
|
709
|
+
* @param toCurrency - The target currency (code or object).
|
|
710
|
+
* @returns A new Money object in the target currency.
|
|
711
|
+
* @throws {Error} If exchange rates are missing.
|
|
712
|
+
*/
|
|
713
|
+
convert(money2, toCurrency) {
|
|
714
|
+
const targetCurrency = typeof toCurrency === "string" ? getCurrency(toCurrency) : toCurrency;
|
|
715
|
+
if (money2.currency.code === targetCurrency.code) {
|
|
716
|
+
return money2;
|
|
717
|
+
}
|
|
718
|
+
const fromRate = this.rates[money2.currency.code];
|
|
719
|
+
const toRate = this.rates[targetCurrency.code];
|
|
720
|
+
if (fromRate === void 0 || toRate === void 0) {
|
|
721
|
+
throw new Error(
|
|
722
|
+
`Exchange rate missing for conversion from ${money2.currency.code} to ${targetCurrency.code}`
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
const ratio = toRate / fromRate;
|
|
726
|
+
const decimalAdjustment = 10 ** (targetCurrency.decimals - money2.currency.decimals);
|
|
727
|
+
const multiplier = ratio * decimalAdjustment;
|
|
728
|
+
const convertedAmount = money2.multiply(multiplier, {
|
|
729
|
+
rounding: "HALF_EVEN" /* HALF_EVEN */
|
|
730
|
+
});
|
|
731
|
+
return Money.fromMinor(convertedAmount.minor, targetCurrency);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// src/money/MoneyBag.ts
|
|
736
|
+
var MoneyBag = class {
|
|
737
|
+
constructor() {
|
|
738
|
+
this.contents = /* @__PURE__ */ new Map();
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Adds a Money amount to the bag.
|
|
742
|
+
* @param money The money to add.
|
|
743
|
+
*/
|
|
744
|
+
add(money2) {
|
|
745
|
+
const code = money2.currency.code;
|
|
746
|
+
const existing = this.contents.get(code);
|
|
747
|
+
if (existing) {
|
|
748
|
+
this.contents.set(code, existing.add(money2));
|
|
749
|
+
} else {
|
|
750
|
+
this.contents.set(code, money2);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Subtracts a Money amount from the bag.
|
|
755
|
+
* @param money The money to subtract.
|
|
756
|
+
*/
|
|
757
|
+
subtract(money2) {
|
|
758
|
+
const code = money2.currency.code;
|
|
759
|
+
const existing = this.contents.get(code);
|
|
760
|
+
if (existing) {
|
|
761
|
+
this.contents.set(code, existing.subtract(money2));
|
|
762
|
+
} else {
|
|
763
|
+
const zero = Money.zero(money2.currency);
|
|
764
|
+
this.contents.set(code, zero.subtract(money2));
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Gets the amount for a specific currency.
|
|
769
|
+
* @param currency The currency to retrieve.
|
|
770
|
+
* @returns The Money amount in that currency (or zero if not present).
|
|
771
|
+
*/
|
|
772
|
+
get(currency) {
|
|
773
|
+
const code = typeof currency === "string" ? currency : currency.code;
|
|
774
|
+
return this.contents.get(code) || Money.zero(
|
|
775
|
+
typeof currency === "string" ? getCurrency(currency) : currency
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Calculates the total value of the bag in a specific currency.
|
|
780
|
+
*
|
|
781
|
+
* @param targetCurrency The currency to convert everything to.
|
|
782
|
+
* @param converter The converter instance with exchange rates.
|
|
783
|
+
* @returns The total amount in the target currency.
|
|
784
|
+
*/
|
|
785
|
+
total(targetCurrency, converter) {
|
|
786
|
+
const target = typeof targetCurrency === "string" ? getCurrency(targetCurrency) : targetCurrency;
|
|
787
|
+
let total = Money.zero(target);
|
|
788
|
+
for (const money2 of this.contents.values()) {
|
|
789
|
+
const converted = converter.convert(money2, target);
|
|
790
|
+
total = total.add(converted);
|
|
791
|
+
}
|
|
792
|
+
return total;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Returns a list of all Money objects in the bag.
|
|
796
|
+
*/
|
|
797
|
+
getAll() {
|
|
798
|
+
return Array.from(this.contents.values());
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Returns a JSON representation of the bag.
|
|
802
|
+
*/
|
|
803
|
+
toJSON() {
|
|
804
|
+
return this.getAll().map((m) => m.toJSON());
|
|
805
|
+
}
|
|
443
806
|
};
|
|
444
807
|
|
|
445
808
|
// src/currency/iso4217.ts
|
|
@@ -449,6 +812,7 @@ var USD = {
|
|
|
449
812
|
symbol: "$",
|
|
450
813
|
locale: "en-US"
|
|
451
814
|
};
|
|
815
|
+
registerCurrency(USD);
|
|
452
816
|
var EUR = {
|
|
453
817
|
code: "EUR",
|
|
454
818
|
decimals: 2,
|
|
@@ -456,24 +820,28 @@ var EUR = {
|
|
|
456
820
|
locale: "de-DE"
|
|
457
821
|
// Default locale, can be overridden
|
|
458
822
|
};
|
|
823
|
+
registerCurrency(EUR);
|
|
459
824
|
var GBP = {
|
|
460
825
|
code: "GBP",
|
|
461
826
|
decimals: 2,
|
|
462
827
|
symbol: "\xA3",
|
|
463
828
|
locale: "en-GB"
|
|
464
829
|
};
|
|
830
|
+
registerCurrency(GBP);
|
|
465
831
|
var JPY = {
|
|
466
832
|
code: "JPY",
|
|
467
833
|
decimals: 0,
|
|
468
834
|
symbol: "\xA5",
|
|
469
835
|
locale: "ja-JP"
|
|
470
836
|
};
|
|
837
|
+
registerCurrency(JPY);
|
|
471
838
|
var ZAR = {
|
|
472
839
|
code: "ZAR",
|
|
473
840
|
decimals: 2,
|
|
474
841
|
symbol: "R",
|
|
475
842
|
locale: "en-ZA"
|
|
476
843
|
};
|
|
844
|
+
registerCurrency(ZAR);
|
|
477
845
|
var CURRENCIES = {
|
|
478
846
|
USD,
|
|
479
847
|
EUR,
|
|
@@ -481,21 +849,23 @@ var CURRENCIES = {
|
|
|
481
849
|
JPY,
|
|
482
850
|
ZAR
|
|
483
851
|
};
|
|
484
|
-
function getCurrency(code) {
|
|
485
|
-
const currency = CURRENCIES[code.toUpperCase()];
|
|
486
|
-
if (!currency) {
|
|
487
|
-
throw new Error(`Unknown currency code: ${code}`);
|
|
488
|
-
}
|
|
489
|
-
return currency;
|
|
490
|
-
}
|
|
491
852
|
|
|
492
853
|
// src/currency/precision.ts
|
|
493
854
|
function getMinorUnitExponent(currency) {
|
|
494
855
|
return 10n ** BigInt(currency.decimals);
|
|
495
856
|
}
|
|
857
|
+
|
|
858
|
+
// src/index.ts
|
|
859
|
+
function money(amount, currency) {
|
|
860
|
+
if (typeof amount === "string") {
|
|
861
|
+
return Money.fromMajor(amount, currency);
|
|
862
|
+
}
|
|
863
|
+
return Money.fromMinor(amount, currency);
|
|
864
|
+
}
|
|
496
865
|
// Annotate the CommonJS export names for ESM import in node:
|
|
497
866
|
0 && (module.exports = {
|
|
498
867
|
CURRENCIES,
|
|
868
|
+
Converter,
|
|
499
869
|
CurrencyMismatchError,
|
|
500
870
|
EUR,
|
|
501
871
|
GBP,
|
|
@@ -504,13 +874,19 @@ function getMinorUnitExponent(currency) {
|
|
|
504
874
|
JPY,
|
|
505
875
|
MonetraError,
|
|
506
876
|
Money,
|
|
877
|
+
MoneyBag,
|
|
507
878
|
OverflowError,
|
|
508
879
|
RoundingMode,
|
|
509
880
|
RoundingRequiredError,
|
|
510
881
|
USD,
|
|
511
882
|
ZAR,
|
|
883
|
+
assertNonNegative,
|
|
884
|
+
assertSameCurrency,
|
|
512
885
|
divideWithRounding,
|
|
513
886
|
getCurrency,
|
|
514
|
-
getMinorUnitExponent
|
|
887
|
+
getMinorUnitExponent,
|
|
888
|
+
isCurrencyRegistered,
|
|
889
|
+
money,
|
|
890
|
+
registerCurrency
|
|
515
891
|
});
|
|
516
892
|
//# sourceMappingURL=index.js.map
|