@ultimat3/money 21.0.0 → 22.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/README.md +9 -0
- package/package.json +3 -3
- package/src/format.ts +11 -3
- package/src/money.ts +4 -2
package/README.md
CHANGED
|
@@ -137,6 +137,15 @@ the epoch: `ExchangeRate.at` is the audit trail.
|
|
|
137
137
|
| `X_ALLOCATION_INVALID` | bad part count, empty/negative/all-zero ratios, percentages ≠ 100 |
|
|
138
138
|
| `X_RATE_MISSING` | no rate for the pair — never assumes parity |
|
|
139
139
|
|
|
140
|
+
### Error classes
|
|
141
|
+
|
|
142
|
+
Every error class `src/index.ts` exports, for `instanceof` inside one process. Across a wire or
|
|
143
|
+
a job boundary the class is gone and the `code` is what survives — match on that.
|
|
144
|
+
|
|
145
|
+
| Class | Code | Declared in |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `MoneyError` | any `MoneyErrorCode` — `MONEY_ERROR_CODES` | `src/errors.ts` |
|
|
148
|
+
|
|
140
149
|
## Why it exists
|
|
141
150
|
|
|
142
151
|
Every money bug in production is one of three things: a float, a missing currency, or a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/money",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.1.0",
|
|
4
4
|
"description": "Integer minor units with an attached currency: arithmetic, allocation, rounding, Intl formatting",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "bun test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@ultimat3/core": "
|
|
38
|
-
"@ultimat3/schema": "
|
|
37
|
+
"@ultimat3/core": "22.1.0",
|
|
38
|
+
"@ultimat3/schema": "22.1.0"
|
|
39
39
|
}
|
|
40
40
|
}
|
package/src/format.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { assertLocale, cachedFormatter } from '@ultimat3/core';
|
|
7
7
|
import { exponentOf } from './currency';
|
|
8
|
-
import { type Money,
|
|
8
|
+
import { type Money, toDecimalString } from './money';
|
|
9
9
|
import { moneyScale } from './scale';
|
|
10
10
|
|
|
11
11
|
export interface FormatMoneyOptions {
|
|
@@ -56,7 +56,7 @@ export function formatMoneyParts(
|
|
|
56
56
|
options: FormatMoneyOptions = {},
|
|
57
57
|
): Intl.NumberFormatPart[] {
|
|
58
58
|
return formatterFor(amount.currency, locale, options, moneyScale(amount)).formatToParts(
|
|
59
|
-
|
|
59
|
+
exactDecimal(amount),
|
|
60
60
|
);
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -87,9 +87,17 @@ export function formatMoneyDecimal(amount: Money, locale: string): string {
|
|
|
87
87
|
maximumFractionDigits: digits,
|
|
88
88
|
useGrouping: false,
|
|
89
89
|
}),
|
|
90
|
-
).format(
|
|
90
|
+
).format(exactDecimal(amount));
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* The amount as the decimal STRING `Intl` accepts (Intl.NumberFormat v3), never a float: dividing
|
|
95
|
+
* `9007199254740991` minor units by `10 ** 6` in floating point lands on `…740992` before any
|
|
96
|
+
* formatter sees it, so the largest amount a `Money` can hold rendered a digit it does not have.
|
|
97
|
+
* The cast is the one `toDecimalString` earns: it only ever writes `-?\d+(\.\d+)?`.
|
|
98
|
+
*/
|
|
99
|
+
const exactDecimal = (amount: Money): `${number}` => toDecimalString(amount) as `${number}`;
|
|
100
|
+
|
|
93
101
|
const cache = new Map<string, Intl.NumberFormat>();
|
|
94
102
|
const decimalCache = new Map<string, Intl.NumberFormat>();
|
|
95
103
|
|
package/src/money.ts
CHANGED
|
@@ -112,8 +112,10 @@ export function toDecimalString(amount: Money): string {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
* Major units as a float
|
|
116
|
-
*
|
|
115
|
+
* Major units as a float — lossy past 2^53 / 10^scale, so never for arithmetic and no longer for
|
|
116
|
+
* formatting either: `format.ts` hands `Intl` the exact `toDecimalString`, since a float rendered
|
|
117
|
+
* `money(9007199254740991, 'USD', 6)` as `…740992`. Kept as public API for a chart axis or a sort
|
|
118
|
+
* key, where an approximation is the point.
|
|
117
119
|
*/
|
|
118
120
|
export function toDecimalNumber(amount: Money): number {
|
|
119
121
|
return amount.minor / 10 ** moneyScale(amount);
|