subunit-money 2.1.1 → 3.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/currency.js CHANGED
@@ -1,15 +1,7 @@
1
- "use strict";
2
1
  /**
3
2
  * Currency registry and types.
4
3
  * Manages ISO 4217 currency definitions and custom currencies.
5
4
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.registerCurrency = registerCurrency;
8
- exports.getCurrency = getCurrency;
9
- exports.hasCurrency = hasCurrency;
10
- exports.getAllCurrencies = getAllCurrencies;
11
- exports.loadCurrencyMap = loadCurrencyMap;
12
- exports.clearCurrencies = clearCurrencies;
13
5
  // Internal registry - mutable for registerCurrency()
14
6
  const currencies = new Map();
15
7
  /**
@@ -17,33 +9,33 @@ const currencies = new Map();
17
9
  * @param code - ISO 4217 currency code (e.g., 'USD', 'EUR', 'BTC')
18
10
  * @param decimalDigits - Number of decimal places (e.g., 2 for USD, 8 for BTC)
19
11
  */
20
- function registerCurrency(code, decimalDigits) {
12
+ export function registerCurrency(code, decimalDigits) {
21
13
  currencies.set(code, { code, decimalDigits });
22
14
  }
23
15
  /**
24
16
  * Get a currency definition by code.
25
17
  * @returns The currency definition, or undefined if not registered
26
18
  */
27
- function getCurrency(code) {
19
+ export function getCurrency(code) {
28
20
  return currencies.get(code);
29
21
  }
30
22
  /**
31
23
  * Check if a currency is registered.
32
24
  */
33
- function hasCurrency(code) {
25
+ export function hasCurrency(code) {
34
26
  return currencies.has(code);
35
27
  }
36
28
  /**
37
29
  * Get all registered currencies, sorted by code.
38
30
  */
39
- function getAllCurrencies() {
31
+ export function getAllCurrencies() {
40
32
  return Array.from(currencies.values()).sort((a, b) => a.code.localeCompare(b.code));
41
33
  }
42
34
  /**
43
35
  * Load currencies from the legacy currencymap.json format.
44
36
  * @param map - Object with currency codes as keys and {decimal_digits: number} as values
45
37
  */
46
- function loadCurrencyMap(map) {
38
+ export function loadCurrencyMap(map) {
47
39
  for (const [code, data] of Object.entries(map)) {
48
40
  registerCurrency(code, data.decimal_digits);
49
41
  }
@@ -51,6 +43,6 @@ function loadCurrencyMap(map) {
51
43
  /**
52
44
  * Clear all registered currencies. Useful for testing.
53
45
  */
54
- function clearCurrencies() {
46
+ export function clearCurrencies() {
55
47
  currencies.clear();
56
48
  }
package/dist/errors.js CHANGED
@@ -1,16 +1,13 @@
1
- "use strict";
2
1
  /**
3
2
  * Custom error types for Money operations.
4
3
  * All errors extend built-in Error types for proper instanceof checks.
5
4
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ExchangeRateError = exports.AmountError = exports.SubunitError = exports.CurrencyUnknownError = exports.CurrencyMismatchError = void 0;
8
5
  /**
9
6
  * Thrown when attempting operations between different currencies.
10
7
  * @example
11
8
  * new Money('USD', 10).add(new Money('EUR', 5)) // throws CurrencyMismatchError
12
9
  */
13
- class CurrencyMismatchError extends TypeError {
10
+ export class CurrencyMismatchError extends TypeError {
14
11
  constructor(fromCurrency, toCurrency) {
15
12
  super(`Cannot operate on ${fromCurrency} and ${toCurrency} - currencies must match`);
16
13
  this.name = 'CurrencyMismatchError';
@@ -19,13 +16,12 @@ class CurrencyMismatchError extends TypeError {
19
16
  Error.captureStackTrace?.(this, CurrencyMismatchError);
20
17
  }
21
18
  }
22
- exports.CurrencyMismatchError = CurrencyMismatchError;
23
19
  /**
24
20
  * Thrown when using an unregistered currency code.
25
21
  * @example
26
22
  * new Money('FAKE', 10) // throws CurrencyUnknownError
27
23
  */
28
- class CurrencyUnknownError extends TypeError {
24
+ export class CurrencyUnknownError extends TypeError {
29
25
  constructor(currency) {
30
26
  super(`Unknown currency '${currency}' - register it first with Money.registerCurrency()`);
31
27
  this.name = 'CurrencyUnknownError';
@@ -33,13 +29,12 @@ class CurrencyUnknownError extends TypeError {
33
29
  Error.captureStackTrace?.(this, CurrencyUnknownError);
34
30
  }
35
31
  }
36
- exports.CurrencyUnknownError = CurrencyUnknownError;
37
32
  /**
38
33
  * Thrown when an amount has more decimal places than the currency allows.
39
34
  * @example
40
35
  * new Money('USD', '1.234') // throws SubunitError (USD only allows 2 decimals)
41
36
  */
42
- class SubunitError extends RangeError {
37
+ export class SubunitError extends RangeError {
43
38
  constructor(currency, maxDecimals) {
44
39
  super(`${currency} only supports ${maxDecimals} decimal place(s)`);
45
40
  this.name = 'SubunitError';
@@ -48,13 +43,12 @@ class SubunitError extends RangeError {
48
43
  Error.captureStackTrace?.(this, SubunitError);
49
44
  }
50
45
  }
51
- exports.SubunitError = SubunitError;
52
46
  /**
53
47
  * Thrown when an amount cannot be parsed as a valid number.
54
48
  * @example
55
49
  * new Money('USD', 'abc') // throws AmountError
56
50
  */
57
- class AmountError extends TypeError {
51
+ export class AmountError extends TypeError {
58
52
  constructor(amount) {
59
53
  super(`Invalid amount: ${JSON.stringify(amount)}`);
60
54
  this.name = 'AmountError';
@@ -62,13 +56,12 @@ class AmountError extends TypeError {
62
56
  Error.captureStackTrace?.(this, AmountError);
63
57
  }
64
58
  }
65
- exports.AmountError = AmountError;
66
59
  /**
67
60
  * Thrown when an exchange rate is not available.
68
61
  * @example
69
62
  * converter.convert(usdMoney, 'XYZ') // throws ExchangeRateError if no USD->XYZ rate
70
63
  */
71
- class ExchangeRateError extends Error {
64
+ export class ExchangeRateError extends Error {
72
65
  constructor(fromCurrency, toCurrency) {
73
66
  super(`No exchange rate available from ${fromCurrency} to ${toCurrency}`);
74
67
  this.name = 'ExchangeRateError';
@@ -77,4 +70,3 @@ class ExchangeRateError extends Error {
77
70
  Error.captureStackTrace?.(this, ExchangeRateError);
78
71
  }
79
72
  }
80
- exports.ExchangeRateError = ExchangeRateError;
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Exchange Rate Service - Central authority for currency conversion rates.
4
3
  *
@@ -14,8 +13,6 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
14
13
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
15
14
  };
16
15
  var _ExchangeRateService_instances, _ExchangeRateService_rates, _ExchangeRateService_key;
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.ExchangeRateService = void 0;
19
16
  /**
20
17
  * Service for managing exchange rates between currencies.
21
18
  *
@@ -24,7 +21,7 @@ exports.ExchangeRateService = void 0;
24
21
  * rates.setRate('USD', 'EUR', 0.92, 'ECB')
25
22
  * rates.getRate('USD', 'EUR') // { from: 'USD', to: 'EUR', rate: '0.92', ... }
26
23
  */
27
- class ExchangeRateService {
24
+ export class ExchangeRateService {
28
25
  constructor() {
29
26
  _ExchangeRateService_instances.add(this);
30
27
  _ExchangeRateService_rates.set(this, new Map()
@@ -168,7 +165,6 @@ class ExchangeRateService {
168
165
  }
169
166
  }
170
167
  }
171
- exports.ExchangeRateService = ExchangeRateService;
172
168
  _ExchangeRateService_rates = new WeakMap(), _ExchangeRateService_instances = new WeakSet(), _ExchangeRateService_key = function _ExchangeRateService_key(from, to) {
173
169
  return `${from}:${to}`;
174
170
  };
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * subunit-money - A type-safe value object for monetary amounts
4
3
  *
@@ -16,33 +15,14 @@
16
15
  * const converter = new MoneyConverter(rates)
17
16
  * const euros = converter.convert(total, 'EUR')
18
17
  */
19
- var __importDefault = (this && this.__importDefault) || function (mod) {
20
- return (mod && mod.__esModule) ? mod : { "default": mod };
21
- };
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.clearCurrencies = exports.loadCurrencyMap = exports.getAllCurrencies = exports.hasCurrency = exports.getCurrency = exports.registerCurrency = exports.ExchangeRateError = exports.AmountError = exports.SubunitError = exports.CurrencyUnknownError = exports.CurrencyMismatchError = exports.MoneyConverter = exports.ExchangeRateService = exports.Money = void 0;
24
18
  // Core classes
25
- var money_js_1 = require("./money.js");
26
- Object.defineProperty(exports, "Money", { enumerable: true, get: function () { return money_js_1.Money; } });
27
- var exchange_rate_service_js_1 = require("./exchange-rate-service.js");
28
- Object.defineProperty(exports, "ExchangeRateService", { enumerable: true, get: function () { return exchange_rate_service_js_1.ExchangeRateService; } });
29
- var money_converter_js_1 = require("./money-converter.js");
30
- Object.defineProperty(exports, "MoneyConverter", { enumerable: true, get: function () { return money_converter_js_1.MoneyConverter; } });
19
+ export { Money } from './money.js';
20
+ export { ExchangeRateService } from './exchange-rate-service.js';
21
+ export { MoneyConverter } from './money-converter.js';
31
22
  // Error types
32
- var errors_js_1 = require("./errors.js");
33
- Object.defineProperty(exports, "CurrencyMismatchError", { enumerable: true, get: function () { return errors_js_1.CurrencyMismatchError; } });
34
- Object.defineProperty(exports, "CurrencyUnknownError", { enumerable: true, get: function () { return errors_js_1.CurrencyUnknownError; } });
35
- Object.defineProperty(exports, "SubunitError", { enumerable: true, get: function () { return errors_js_1.SubunitError; } });
36
- Object.defineProperty(exports, "AmountError", { enumerable: true, get: function () { return errors_js_1.AmountError; } });
37
- Object.defineProperty(exports, "ExchangeRateError", { enumerable: true, get: function () { return errors_js_1.ExchangeRateError; } });
23
+ export { CurrencyMismatchError, CurrencyUnknownError, SubunitError, AmountError, ExchangeRateError, } from './errors.js';
38
24
  // Currency utilities
39
- var currency_js_1 = require("./currency.js");
40
- Object.defineProperty(exports, "registerCurrency", { enumerable: true, get: function () { return currency_js_1.registerCurrency; } });
41
- Object.defineProperty(exports, "getCurrency", { enumerable: true, get: function () { return currency_js_1.getCurrency; } });
42
- Object.defineProperty(exports, "hasCurrency", { enumerable: true, get: function () { return currency_js_1.hasCurrency; } });
43
- Object.defineProperty(exports, "getAllCurrencies", { enumerable: true, get: function () { return currency_js_1.getAllCurrencies; } });
44
- Object.defineProperty(exports, "loadCurrencyMap", { enumerable: true, get: function () { return currency_js_1.loadCurrencyMap; } });
45
- Object.defineProperty(exports, "clearCurrencies", { enumerable: true, get: function () { return currency_js_1.clearCurrencies; } });
25
+ export { registerCurrency, getCurrency, hasCurrency, getAllCurrencies, loadCurrencyMap, clearCurrencies, } from './currency.js';
46
26
  // Auto-load default currencies
47
27
  // The currencymap.json file is the official ISO 4217 currency list (List One) as of 2026-01-01,
48
28
  // sourced from SIX Financial Information AG (the ISO 4217 Maintenance Agency).
@@ -53,6 +33,6 @@ Object.defineProperty(exports, "clearCurrencies", { enumerable: true, get: funct
53
33
  //
54
34
  // Note: This excludes historical currencies, supranational funds, and precious metals,
55
35
  // keeping only active national and regional currencies for practical use.
56
- const currency_js_2 = require("./currency.js");
57
- const currencymap_json_1 = __importDefault(require("../currencymap.json"));
58
- (0, currency_js_2.loadCurrencyMap)(currencymap_json_1.default);
36
+ import { loadCurrencyMap } from './currency.js';
37
+ import currencyMap from '../currencymap.json';
38
+ loadCurrencyMap(currencyMap);
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Money Converter - Safe cross-currency operations.
4
3
  *
@@ -19,11 +18,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
19
18
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
20
19
  };
21
20
  var _MoneyConverter_instances, _MoneyConverter_rateService, _MoneyConverter_bankersRound;
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.MoneyConverter = void 0;
24
- const money_js_1 = require("./money.js");
25
- const errors_js_1 = require("./errors.js");
26
- const currency_js_1 = require("./currency.js");
21
+ import { Money } from './money.js';
22
+ import { ExchangeRateError, CurrencyUnknownError } from './errors.js';
23
+ import { getCurrency } from './currency.js';
27
24
  /**
28
25
  * Converter for performing operations between different currencies.
29
26
  *
@@ -35,7 +32,7 @@ const currency_js_1 = require("./currency.js");
35
32
  * const euros = converter.convert(new Money('USD', '100'), 'EUR')
36
33
  * console.log(euros.toString()) // "92.00 EUR"
37
34
  */
38
- class MoneyConverter {
35
+ export class MoneyConverter {
39
36
  constructor(rateService) {
40
37
  _MoneyConverter_instances.add(this);
41
38
  _MoneyConverter_rateService.set(this, void 0);
@@ -53,15 +50,15 @@ class MoneyConverter {
53
50
  if (money.currency === targetCurrency) {
54
51
  return money;
55
52
  }
56
- const currencyDef = (0, currency_js_1.getCurrency)(targetCurrency);
53
+ const currencyDef = getCurrency(targetCurrency);
57
54
  if (!currencyDef) {
58
- throw new errors_js_1.CurrencyUnknownError(targetCurrency);
55
+ throw new CurrencyUnknownError(targetCurrency);
59
56
  }
60
57
  const rate = __classPrivateFieldGet(this, _MoneyConverter_rateService, "f").getRate(money.currency, targetCurrency);
61
58
  if (!rate) {
62
- throw new errors_js_1.ExchangeRateError(money.currency, targetCurrency);
59
+ throw new ExchangeRateError(money.currency, targetCurrency);
63
60
  }
64
- const sourceCurrencyDef = (0, currency_js_1.getCurrency)(money.currency);
61
+ const sourceCurrencyDef = getCurrency(money.currency);
65
62
  const sourceSubunits = money.toSubunits();
66
63
  const sourceMultiplier = 10n ** BigInt(sourceCurrencyDef.decimalDigits);
67
64
  const targetMultiplier = 10n ** BigInt(currencyDef.decimalDigits);
@@ -72,7 +69,7 @@ class MoneyConverter {
72
69
  const product = sourceSubunits * rateBigInt * targetMultiplier;
73
70
  const divisor = rateMultiplier * sourceMultiplier;
74
71
  const targetSubunits = __classPrivateFieldGet(this, _MoneyConverter_instances, "m", _MoneyConverter_bankersRound).call(this, product, divisor);
75
- return money_js_1.Money.fromSubunits(targetSubunits, targetCurrency);
72
+ return Money.fromSubunits(targetSubunits, targetCurrency);
76
73
  }
77
74
  /**
78
75
  * Add two Money amounts, converting as needed.
@@ -121,7 +118,7 @@ class MoneyConverter {
121
118
  * @returns Total in the target currency
122
119
  */
123
120
  sum(amounts, targetCurrency) {
124
- let total = money_js_1.Money.zero(targetCurrency);
121
+ let total = Money.zero(targetCurrency);
125
122
  for (const amount of amounts) {
126
123
  const converted = this.convert(amount, targetCurrency);
127
124
  total = total.add(converted);
@@ -139,7 +136,7 @@ class MoneyConverter {
139
136
  compare(a, b) {
140
137
  // Convert b to a's currency for comparison
141
138
  const bConverted = this.convert(b, a.currency);
142
- return money_js_1.Money.compare(a, bConverted);
139
+ return Money.compare(a, bConverted);
143
140
  }
144
141
  /**
145
142
  * Get the exchange rate service (for direct rate access).
@@ -148,7 +145,6 @@ class MoneyConverter {
148
145
  return __classPrivateFieldGet(this, _MoneyConverter_rateService, "f");
149
146
  }
150
147
  }
151
- exports.MoneyConverter = MoneyConverter;
152
148
  _MoneyConverter_rateService = new WeakMap(), _MoneyConverter_instances = new WeakSet(), _MoneyConverter_bankersRound = function _MoneyConverter_bankersRound(numerator, denominator) {
153
149
  if (denominator === 1n)
154
150
  return numerator;
package/dist/money.d.ts CHANGED
@@ -59,13 +59,7 @@ export declare class Money<C extends string = string> {
59
59
  * Multiply by a factor.
60
60
  *
61
61
  * DESIGN: Rounds immediately after multiplication using banker's rounding
62
- * (round half-to-even). This prevents the "split penny problem" where
63
- * line-item rounding differs from deferred rounding:
64
- * Per-item: $1.65 tax × 10 items = $16.50 ✓ (matches receipt)
65
- * Deferred: 10 × $1.649175 = $16.49 ✗ (missing penny)
66
- *
67
- * For chained calculations without intermediate rounding, perform arithmetic
68
- * in Number space first, then create a Money object with the final result.
62
+ * (round half-to-even). This prevents the "split penny problem".
69
63
  */
70
64
  multiply(factor: number): Money<C>;
71
65
  /**
@@ -74,10 +68,6 @@ export declare class Money<C extends string = string> {
74
68
  *
75
69
  * @param proportions - Array of proportions (e.g., [1, 1, 1] for three-way split)
76
70
  * @returns Array of Money objects that sum to the original amount
77
- *
78
- * @example
79
- * new Money('USD', '100').allocate([1, 1, 1])
80
- * // Returns: [Money('33.34'), Money('33.33'), Money('33.33')]
81
71
  */
82
72
  allocate(proportions: number[]): Money<C>[];
83
73
  /**