@storepass/money 0.2.1 → 0.3.1
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 +42 -1
- package/dist/currency.d.ts +14 -0
- package/dist/index.cjs +67 -17
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +67 -17
- package/dist/money.d.ts +37 -1
- package/dist/zod.cjs +7 -7
- package/dist/zod.mjs +7 -7
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -60,6 +60,11 @@ const diff = a.subtract(b); // 7.5
|
|
|
60
60
|
|
|
61
61
|
Money.compare(a, b); // 1
|
|
62
62
|
Money.greaterThan(a, b); // true
|
|
63
|
+
|
|
64
|
+
Money.zero(Currency.USD); // $0.00
|
|
65
|
+
Money.sum([], Currency.USD); // $0.00; without a currency, an empty list throws
|
|
66
|
+
Money.sum([a, b], Currency.USD); // 12.5; every item must be USD
|
|
67
|
+
Money.sameCurrency([a, b], Currency.USD); // true; never throws
|
|
63
68
|
```
|
|
64
69
|
|
|
65
70
|
### Allocation
|
|
@@ -92,6 +97,26 @@ subtotal.incrementByPercent(8.25).toNumber(); // 108.25
|
|
|
92
97
|
subtotal.decrementByPercent(10).toNumber(); // 90
|
|
93
98
|
```
|
|
94
99
|
|
|
100
|
+
### Ratio scaling
|
|
101
|
+
|
|
102
|
+
`scaleByRatio` multiplies by `numerator ÷ denominator` exactly on BigInt minor
|
|
103
|
+
units and rounds once. Use it instead of turning a ratio into a float percent.
|
|
104
|
+
The ratio's two values must share a currency with each other, but not with the
|
|
105
|
+
value being scaled.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const value = Money.fromMinor(Currency.USD, 123456789);
|
|
109
|
+
const one = Money.fromMinor(Currency.EUR, 1);
|
|
110
|
+
const six = Money.fromMinor(Currency.EUR, 6);
|
|
111
|
+
|
|
112
|
+
value.scaleByRatio(one, six); // 20576132 minor units (exact 20576131.5, rounded once)
|
|
113
|
+
value.scaleByRatio(one, six, { rounding: "floor" }); // 20576131
|
|
114
|
+
Money.scaleByRatio(value, one, six); // static form
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
It throws on a zero denominator, when the ratio's currencies differ, and when
|
|
118
|
+
the result exceeds the safe integer range.
|
|
119
|
+
|
|
95
120
|
### Custom currencies
|
|
96
121
|
|
|
97
122
|
```ts
|
|
@@ -101,6 +126,18 @@ const XAU = defineCurrency("XAU", 4);
|
|
|
101
126
|
const gold = Money.fromNumber(XAU, 1.2345);
|
|
102
127
|
```
|
|
103
128
|
|
|
129
|
+
`resolveCurrency` looks a definition up by code. A built-in code returns the
|
|
130
|
+
same object as `Currency[code]`; an unknown code returns `undefined`, or, with
|
|
131
|
+
`fallbackDecimalPlaces`, a cached `defineCurrency(code, fallbackDecimalPlaces)`.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { resolveCurrency } from "@storepass/money";
|
|
135
|
+
|
|
136
|
+
resolveCurrency("USD"); // Currency.USD
|
|
137
|
+
resolveCurrency("XYZ"); // undefined
|
|
138
|
+
resolveCurrency("XYZ", { fallbackDecimalPlaces: 2 }); // same object on every call
|
|
139
|
+
```
|
|
140
|
+
|
|
104
141
|
### Serialization
|
|
105
142
|
|
|
106
143
|
```ts
|
|
@@ -192,7 +229,11 @@ and update both `decimalPlaces` and `numericCode` for any drift.
|
|
|
192
229
|
|
|
193
230
|
- Currency mismatch operations throw (for example, adding USD to EUR).
|
|
194
231
|
- Results that exceed JavaScript safe integer range throw.
|
|
195
|
-
- Rounding modes supported: `"floor" | "ceil" | "round" | "trunc"`.
|
|
232
|
+
- Rounding modes supported: `"floor" | "ceil" | "round" | "trunc"`. `"floor"`
|
|
233
|
+
goes toward -Infinity, `"ceil"` toward +Infinity, and `"trunc"` toward zero.
|
|
234
|
+
`"round"` (the default) goes to the nearest minor unit and resolves an exact
|
|
235
|
+
half toward +Infinity: 2.5 becomes 3 and -2.5 becomes -2. It is not half away
|
|
236
|
+
from zero.
|
|
196
237
|
- `Money` instances are immutable; operations return new instances.
|
|
197
238
|
|
|
198
239
|
## Development
|
package/dist/currency.d.ts
CHANGED
|
@@ -195,6 +195,20 @@ export declare const Currency: {
|
|
|
195
195
|
};
|
|
196
196
|
export type CurrencyCode = keyof typeof Currency;
|
|
197
197
|
export type CurrencyType = (typeof Currency)[CurrencyCode];
|
|
198
|
+
export interface ResolveCurrencyOptions {
|
|
199
|
+
/**
|
|
200
|
+
* When set, an unknown code resolves to `defineCurrency(code, fallbackDecimalPlaces)`
|
|
201
|
+
* instead of `undefined`. The definition is cached, so repeated calls with
|
|
202
|
+
* the same code and decimal places return the same object.
|
|
203
|
+
*/
|
|
204
|
+
fallbackDecimalPlaces?: number;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Looks up a currency definition by code. A built-in code returns the same
|
|
208
|
+
* object as `Currency[code]`; an unknown code returns `undefined` unless
|
|
209
|
+
* `fallbackDecimalPlaces` is given.
|
|
210
|
+
*/
|
|
211
|
+
export declare function resolveCurrency(code: string, options?: ResolveCurrencyOptions): CurrencyDefinition | undefined;
|
|
198
212
|
export interface DefineCurrencyOptions {
|
|
199
213
|
numericCode?: number;
|
|
200
214
|
iso4217?: boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -39,9 +39,10 @@ var __export = (target, all) => {
|
|
|
39
39
|
// src/index.ts
|
|
40
40
|
var exports_src = {};
|
|
41
41
|
__export(exports_src, {
|
|
42
|
-
|
|
42
|
+
Currency: () => Currency,
|
|
43
43
|
Money: () => Money,
|
|
44
|
-
|
|
44
|
+
defineCurrency: () => defineCurrency,
|
|
45
|
+
resolveCurrency: () => resolveCurrency
|
|
45
46
|
});
|
|
46
47
|
module.exports = __toCommonJS(exports_src);
|
|
47
48
|
|
|
@@ -76,6 +77,23 @@ var Currency = {
|
|
|
76
77
|
SAR: { code: "SAR", decimalPlaces: 2, numericCode: 682, iso4217: true },
|
|
77
78
|
BTC: { code: "BTC", decimalPlaces: 8, iso4217: false }
|
|
78
79
|
};
|
|
80
|
+
var builtInCurrencies = new Map(Object.entries(Currency));
|
|
81
|
+
var fallbackCurrencies = new Map;
|
|
82
|
+
function resolveCurrency(code, options = {}) {
|
|
83
|
+
const builtIn = builtInCurrencies.get(code);
|
|
84
|
+
if (builtIn !== undefined)
|
|
85
|
+
return builtIn;
|
|
86
|
+
const { fallbackDecimalPlaces } = options;
|
|
87
|
+
if (fallbackDecimalPlaces === undefined)
|
|
88
|
+
return;
|
|
89
|
+
const key = `${code}:${fallbackDecimalPlaces}`;
|
|
90
|
+
let definition = fallbackCurrencies.get(key);
|
|
91
|
+
if (definition === undefined) {
|
|
92
|
+
definition = defineCurrency(code, fallbackDecimalPlaces);
|
|
93
|
+
fallbackCurrencies.set(key, definition);
|
|
94
|
+
}
|
|
95
|
+
return definition;
|
|
96
|
+
}
|
|
79
97
|
var ISO_ALPHA3 = /^[A-Z]{3}$/;
|
|
80
98
|
function defineCurrency(code, decimalPlaces, options = {}) {
|
|
81
99
|
if (!code || typeof code !== "string") {
|
|
@@ -156,16 +174,17 @@ function parseDecimalStringToScaled(str) {
|
|
|
156
174
|
const result = scaledInt + scaledDec;
|
|
157
175
|
return negative ? -result : result;
|
|
158
176
|
}
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
177
|
+
function divideAndRound(dividend, divisor, mode) {
|
|
178
|
+
if (divisor < 0n) {
|
|
179
|
+
dividend = -dividend;
|
|
180
|
+
divisor = -divisor;
|
|
181
|
+
}
|
|
182
|
+
const quotient = dividend / divisor;
|
|
183
|
+
const remainder = dividend % divisor;
|
|
164
184
|
if (remainder === 0n)
|
|
165
185
|
return quotient;
|
|
166
|
-
const isNegative =
|
|
167
|
-
const
|
|
168
|
-
const halfDivisor = divisor / 2n;
|
|
186
|
+
const isNegative = dividend < 0n;
|
|
187
|
+
const doubledRemainder = (isNegative ? -remainder : remainder) * 2n;
|
|
169
188
|
switch (mode) {
|
|
170
189
|
case "floor":
|
|
171
190
|
return isNegative ? quotient - 1n : quotient;
|
|
@@ -174,14 +193,21 @@ function roundScaledToMinor(scaled, targetDecimalPlaces, mode) {
|
|
|
174
193
|
case "trunc":
|
|
175
194
|
return quotient;
|
|
176
195
|
default:
|
|
177
|
-
if (
|
|
196
|
+
if (doubledRemainder > divisor || doubledRemainder === divisor && !isNegative) {
|
|
178
197
|
return isNegative ? quotient - 1n : quotient + 1n;
|
|
179
198
|
}
|
|
180
199
|
return quotient;
|
|
181
200
|
}
|
|
182
201
|
}
|
|
202
|
+
function roundScaledToMinor(scaled, targetDecimalPlaces, mode) {
|
|
203
|
+
const targetScale = 10n ** BigInt(targetDecimalPlaces);
|
|
204
|
+
return divideAndRound(scaled, INTERNAL_SCALE / targetScale, mode);
|
|
205
|
+
}
|
|
206
|
+
function currenciesMatch(a, b) {
|
|
207
|
+
return a.code === b.code && a.decimalPlaces === b.decimalPlaces;
|
|
208
|
+
}
|
|
183
209
|
function assertCurrenciesMatch(a, b, operation) {
|
|
184
|
-
if (a
|
|
210
|
+
if (!currenciesMatch(a, b)) {
|
|
185
211
|
throw new Error(`Cannot ${operation} ${a.code} and ${b.code}: currency mismatch`);
|
|
186
212
|
}
|
|
187
213
|
}
|
|
@@ -245,6 +271,9 @@ class Money {
|
|
|
245
271
|
static fromMinor(currency, minor) {
|
|
246
272
|
return new Money(BigInt(minor), currency);
|
|
247
273
|
}
|
|
274
|
+
static zero(currency) {
|
|
275
|
+
return new Money(0n, currency);
|
|
276
|
+
}
|
|
248
277
|
toNumber() {
|
|
249
278
|
const divisor = 10 ** this.#currency.decimalPlaces;
|
|
250
279
|
return Number(this.#minor) / divisor;
|
|
@@ -264,12 +293,14 @@ class Money {
|
|
|
264
293
|
assertSafeResult(result);
|
|
265
294
|
return new Money(result, a.#currency);
|
|
266
295
|
}
|
|
267
|
-
static sum(items) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
296
|
+
static sum(items, currency) {
|
|
297
|
+
if (currency === undefined) {
|
|
298
|
+
const first = items[0];
|
|
299
|
+
if (first === undefined) {
|
|
300
|
+
throw new Error("Cannot sum empty array: at least one Money value required");
|
|
301
|
+
}
|
|
302
|
+
currency = first.#currency;
|
|
271
303
|
}
|
|
272
|
-
const currency = first.#currency;
|
|
273
304
|
let total = 0n;
|
|
274
305
|
for (const item of items) {
|
|
275
306
|
assertCurrenciesMatch(item.#currency, currency, "sum");
|
|
@@ -278,6 +309,12 @@ class Money {
|
|
|
278
309
|
assertSafeResult(total);
|
|
279
310
|
return new Money(total, currency);
|
|
280
311
|
}
|
|
312
|
+
static sameCurrency(items, currency) {
|
|
313
|
+
const target = currency ?? items[0]?.currency;
|
|
314
|
+
if (target === undefined)
|
|
315
|
+
return true;
|
|
316
|
+
return items.every((item) => currenciesMatch(item.#currency, target));
|
|
317
|
+
}
|
|
281
318
|
static equals(a, b) {
|
|
282
319
|
assertCurrenciesMatch(a.#currency, b.#currency, "compare");
|
|
283
320
|
return a.#minor === b.#minor;
|
|
@@ -427,6 +464,19 @@ class Money {
|
|
|
427
464
|
round(increment, mode) {
|
|
428
465
|
return Money.roundTo(this, increment, mode);
|
|
429
466
|
}
|
|
467
|
+
static scaleByRatio(money, numerator, denominator, options = {}) {
|
|
468
|
+
assertCurrenciesMatch(numerator.#currency, denominator.#currency, "form a ratio from");
|
|
469
|
+
if (denominator.#minor === 0n) {
|
|
470
|
+
throw new Error("Cannot scale by a ratio with a zero denominator");
|
|
471
|
+
}
|
|
472
|
+
const { rounding = "round" } = options;
|
|
473
|
+
const resultMinor = divideAndRound(money.#minor * numerator.#minor, denominator.#minor, rounding);
|
|
474
|
+
assertSafeResult(resultMinor);
|
|
475
|
+
return new Money(resultMinor, money.#currency);
|
|
476
|
+
}
|
|
477
|
+
scaleByRatio(numerator, denominator, options) {
|
|
478
|
+
return Money.scaleByRatio(this, numerator, denominator, options);
|
|
479
|
+
}
|
|
430
480
|
static percentOf(money, percent, options = {}) {
|
|
431
481
|
const { rounding = "round" } = options;
|
|
432
482
|
const scaledPercent = parseDecimalStringToScaled(numberToDecimalString(percent));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Currency, type CurrencyCode, type CurrencyDefinition, type CurrencyType, type DefineCurrencyOptions, defineCurrency, } from "./currency";
|
|
1
|
+
export { Currency, type CurrencyCode, type CurrencyDefinition, type CurrencyType, type DefineCurrencyOptions, defineCurrency, type ResolveCurrencyOptions, resolveCurrency, } from "./currency";
|
|
2
2
|
export { type FromNumberOptions, Money, type RoundingMode, type SerializedMoney, } from "./money";
|
package/dist/index.mjs
CHANGED
|
@@ -29,6 +29,23 @@ var Currency = {
|
|
|
29
29
|
SAR: { code: "SAR", decimalPlaces: 2, numericCode: 682, iso4217: true },
|
|
30
30
|
BTC: { code: "BTC", decimalPlaces: 8, iso4217: false }
|
|
31
31
|
};
|
|
32
|
+
var builtInCurrencies = new Map(Object.entries(Currency));
|
|
33
|
+
var fallbackCurrencies = new Map;
|
|
34
|
+
function resolveCurrency(code, options = {}) {
|
|
35
|
+
const builtIn = builtInCurrencies.get(code);
|
|
36
|
+
if (builtIn !== undefined)
|
|
37
|
+
return builtIn;
|
|
38
|
+
const { fallbackDecimalPlaces } = options;
|
|
39
|
+
if (fallbackDecimalPlaces === undefined)
|
|
40
|
+
return;
|
|
41
|
+
const key = `${code}:${fallbackDecimalPlaces}`;
|
|
42
|
+
let definition = fallbackCurrencies.get(key);
|
|
43
|
+
if (definition === undefined) {
|
|
44
|
+
definition = defineCurrency(code, fallbackDecimalPlaces);
|
|
45
|
+
fallbackCurrencies.set(key, definition);
|
|
46
|
+
}
|
|
47
|
+
return definition;
|
|
48
|
+
}
|
|
32
49
|
var ISO_ALPHA3 = /^[A-Z]{3}$/;
|
|
33
50
|
function defineCurrency(code, decimalPlaces, options = {}) {
|
|
34
51
|
if (!code || typeof code !== "string") {
|
|
@@ -109,16 +126,17 @@ function parseDecimalStringToScaled(str) {
|
|
|
109
126
|
const result = scaledInt + scaledDec;
|
|
110
127
|
return negative ? -result : result;
|
|
111
128
|
}
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
function divideAndRound(dividend, divisor, mode) {
|
|
130
|
+
if (divisor < 0n) {
|
|
131
|
+
dividend = -dividend;
|
|
132
|
+
divisor = -divisor;
|
|
133
|
+
}
|
|
134
|
+
const quotient = dividend / divisor;
|
|
135
|
+
const remainder = dividend % divisor;
|
|
117
136
|
if (remainder === 0n)
|
|
118
137
|
return quotient;
|
|
119
|
-
const isNegative =
|
|
120
|
-
const
|
|
121
|
-
const halfDivisor = divisor / 2n;
|
|
138
|
+
const isNegative = dividend < 0n;
|
|
139
|
+
const doubledRemainder = (isNegative ? -remainder : remainder) * 2n;
|
|
122
140
|
switch (mode) {
|
|
123
141
|
case "floor":
|
|
124
142
|
return isNegative ? quotient - 1n : quotient;
|
|
@@ -127,14 +145,21 @@ function roundScaledToMinor(scaled, targetDecimalPlaces, mode) {
|
|
|
127
145
|
case "trunc":
|
|
128
146
|
return quotient;
|
|
129
147
|
default:
|
|
130
|
-
if (
|
|
148
|
+
if (doubledRemainder > divisor || doubledRemainder === divisor && !isNegative) {
|
|
131
149
|
return isNegative ? quotient - 1n : quotient + 1n;
|
|
132
150
|
}
|
|
133
151
|
return quotient;
|
|
134
152
|
}
|
|
135
153
|
}
|
|
154
|
+
function roundScaledToMinor(scaled, targetDecimalPlaces, mode) {
|
|
155
|
+
const targetScale = 10n ** BigInt(targetDecimalPlaces);
|
|
156
|
+
return divideAndRound(scaled, INTERNAL_SCALE / targetScale, mode);
|
|
157
|
+
}
|
|
158
|
+
function currenciesMatch(a, b) {
|
|
159
|
+
return a.code === b.code && a.decimalPlaces === b.decimalPlaces;
|
|
160
|
+
}
|
|
136
161
|
function assertCurrenciesMatch(a, b, operation) {
|
|
137
|
-
if (a
|
|
162
|
+
if (!currenciesMatch(a, b)) {
|
|
138
163
|
throw new Error(`Cannot ${operation} ${a.code} and ${b.code}: currency mismatch`);
|
|
139
164
|
}
|
|
140
165
|
}
|
|
@@ -198,6 +223,9 @@ class Money {
|
|
|
198
223
|
static fromMinor(currency, minor) {
|
|
199
224
|
return new Money(BigInt(minor), currency);
|
|
200
225
|
}
|
|
226
|
+
static zero(currency) {
|
|
227
|
+
return new Money(0n, currency);
|
|
228
|
+
}
|
|
201
229
|
toNumber() {
|
|
202
230
|
const divisor = 10 ** this.#currency.decimalPlaces;
|
|
203
231
|
return Number(this.#minor) / divisor;
|
|
@@ -217,12 +245,14 @@ class Money {
|
|
|
217
245
|
assertSafeResult(result);
|
|
218
246
|
return new Money(result, a.#currency);
|
|
219
247
|
}
|
|
220
|
-
static sum(items) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
248
|
+
static sum(items, currency) {
|
|
249
|
+
if (currency === undefined) {
|
|
250
|
+
const first = items[0];
|
|
251
|
+
if (first === undefined) {
|
|
252
|
+
throw new Error("Cannot sum empty array: at least one Money value required");
|
|
253
|
+
}
|
|
254
|
+
currency = first.#currency;
|
|
224
255
|
}
|
|
225
|
-
const currency = first.#currency;
|
|
226
256
|
let total = 0n;
|
|
227
257
|
for (const item of items) {
|
|
228
258
|
assertCurrenciesMatch(item.#currency, currency, "sum");
|
|
@@ -231,6 +261,12 @@ class Money {
|
|
|
231
261
|
assertSafeResult(total);
|
|
232
262
|
return new Money(total, currency);
|
|
233
263
|
}
|
|
264
|
+
static sameCurrency(items, currency) {
|
|
265
|
+
const target = currency ?? items[0]?.currency;
|
|
266
|
+
if (target === undefined)
|
|
267
|
+
return true;
|
|
268
|
+
return items.every((item) => currenciesMatch(item.#currency, target));
|
|
269
|
+
}
|
|
234
270
|
static equals(a, b) {
|
|
235
271
|
assertCurrenciesMatch(a.#currency, b.#currency, "compare");
|
|
236
272
|
return a.#minor === b.#minor;
|
|
@@ -380,6 +416,19 @@ class Money {
|
|
|
380
416
|
round(increment, mode) {
|
|
381
417
|
return Money.roundTo(this, increment, mode);
|
|
382
418
|
}
|
|
419
|
+
static scaleByRatio(money, numerator, denominator, options = {}) {
|
|
420
|
+
assertCurrenciesMatch(numerator.#currency, denominator.#currency, "form a ratio from");
|
|
421
|
+
if (denominator.#minor === 0n) {
|
|
422
|
+
throw new Error("Cannot scale by a ratio with a zero denominator");
|
|
423
|
+
}
|
|
424
|
+
const { rounding = "round" } = options;
|
|
425
|
+
const resultMinor = divideAndRound(money.#minor * numerator.#minor, denominator.#minor, rounding);
|
|
426
|
+
assertSafeResult(resultMinor);
|
|
427
|
+
return new Money(resultMinor, money.#currency);
|
|
428
|
+
}
|
|
429
|
+
scaleByRatio(numerator, denominator, options) {
|
|
430
|
+
return Money.scaleByRatio(this, numerator, denominator, options);
|
|
431
|
+
}
|
|
383
432
|
static percentOf(money, percent, options = {}) {
|
|
384
433
|
const { rounding = "round" } = options;
|
|
385
434
|
const scaledPercent = parseDecimalStringToScaled(numberToDecimalString(percent));
|
|
@@ -453,7 +502,8 @@ class Money {
|
|
|
453
502
|
}
|
|
454
503
|
}
|
|
455
504
|
export {
|
|
456
|
-
|
|
505
|
+
Currency,
|
|
457
506
|
Money,
|
|
458
|
-
|
|
507
|
+
defineCurrency,
|
|
508
|
+
resolveCurrency
|
|
459
509
|
};
|
package/dist/money.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { CurrencyDefinition } from "./currency";
|
|
2
|
+
/**
|
|
3
|
+
* How a value between two minor units is resolved.
|
|
4
|
+
*
|
|
5
|
+
* - `"floor"`: toward -Infinity.
|
|
6
|
+
* - `"ceil"`: toward +Infinity.
|
|
7
|
+
* - `"trunc"`: toward zero.
|
|
8
|
+
* - `"round"`: to the nearest minor unit; an exact half goes toward
|
|
9
|
+
* +Infinity, so 2.5 becomes 3 and -2.5 becomes -2 (not half away from zero).
|
|
10
|
+
*/
|
|
2
11
|
export type RoundingMode = "floor" | "ceil" | "round" | "trunc";
|
|
3
12
|
export interface FromNumberOptions {
|
|
4
13
|
rounding?: RoundingMode;
|
|
@@ -19,11 +28,23 @@ export declare class Money {
|
|
|
19
28
|
get currency(): CurrencyDefinition;
|
|
20
29
|
static fromNumber(currency: CurrencyDefinition, value: number, options?: FromNumberOptions): Money;
|
|
21
30
|
static fromMinor(currency: CurrencyDefinition, minor: number): Money;
|
|
31
|
+
static zero(currency: CurrencyDefinition): Money;
|
|
22
32
|
toNumber(): number;
|
|
23
33
|
toMinor(): number;
|
|
24
34
|
static add(a: Money, b: Money): Money;
|
|
25
35
|
static subtract(a: Money, b: Money): Money;
|
|
26
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Adds every item. Without `currency`, the list must be non-empty and the
|
|
38
|
+
* first item sets the currency. With `currency`, an empty list returns
|
|
39
|
+
* `Money.zero(currency)` and every item must match `currency`.
|
|
40
|
+
*/
|
|
41
|
+
static sum(items: readonly Money[], currency?: CurrencyDefinition): Money;
|
|
42
|
+
/**
|
|
43
|
+
* True when every item's currency matches `currency` (or the first item's
|
|
44
|
+
* currency when omitted), using the same rule as arithmetic: equal `code`
|
|
45
|
+
* and `decimalPlaces`. An empty list is true.
|
|
46
|
+
*/
|
|
47
|
+
static sameCurrency(items: readonly Money[], currency?: CurrencyDefinition): boolean;
|
|
27
48
|
static equals(a: Money, b: Money): boolean;
|
|
28
49
|
static compare(a: Money, b: Money): number;
|
|
29
50
|
static lessThan(a: Money, b: Money): boolean;
|
|
@@ -51,6 +72,21 @@ export declare class Money {
|
|
|
51
72
|
}): Money;
|
|
52
73
|
static roundTo(money: Money, increment: number, mode?: RoundingMode): Money;
|
|
53
74
|
round(increment: number, mode?: RoundingMode): Money;
|
|
75
|
+
/**
|
|
76
|
+
* Returns `money × numerator ÷ denominator` in `money`'s currency, computed
|
|
77
|
+
* exactly on minor units with a single rounding (default `"round"`).
|
|
78
|
+
*
|
|
79
|
+
* The ratio is dimensionless: `numerator` and `denominator` must share a
|
|
80
|
+
* currency with each other, but not with `money`. Throws when the
|
|
81
|
+
* denominator is zero, when the ratio's currencies differ, or when the
|
|
82
|
+
* result exceeds the safe integer range.
|
|
83
|
+
*/
|
|
84
|
+
static scaleByRatio(money: Money, numerator: Money, denominator: Money, options?: {
|
|
85
|
+
rounding?: RoundingMode;
|
|
86
|
+
}): Money;
|
|
87
|
+
scaleByRatio(numerator: Money, denominator: Money, options?: {
|
|
88
|
+
rounding?: RoundingMode;
|
|
89
|
+
}): Money;
|
|
54
90
|
static percentOf(money: Money, percent: number, options?: {
|
|
55
91
|
rounding?: RoundingMode;
|
|
56
92
|
}): Money;
|
package/dist/zod.cjs
CHANGED
|
@@ -39,14 +39,14 @@ var __export = (target, all) => {
|
|
|
39
39
|
// src/zod.ts
|
|
40
40
|
var exports_zod = {};
|
|
41
41
|
__export(exports_zod, {
|
|
42
|
-
|
|
43
|
-
moneySchema: () => moneySchema,
|
|
44
|
-
moneyInstanceSchema: () => moneyInstanceSchema,
|
|
45
|
-
moneyCodec: () => moneyCodec,
|
|
46
|
-
currencyDefinitionSchema: () => currencyDefinitionSchema,
|
|
47
|
-
currencyCodeSchema: () => currencyCodeSchema,
|
|
42
|
+
builtInSerializedMoneySchema: () => builtInSerializedMoneySchema,
|
|
48
43
|
createMoneyCodec: () => createMoneyCodec,
|
|
49
|
-
|
|
44
|
+
currencyCodeSchema: () => currencyCodeSchema,
|
|
45
|
+
currencyDefinitionSchema: () => currencyDefinitionSchema,
|
|
46
|
+
moneyCodec: () => moneyCodec,
|
|
47
|
+
moneyInstanceSchema: () => moneyInstanceSchema,
|
|
48
|
+
moneySchema: () => moneySchema,
|
|
49
|
+
serializedMoneySchema: () => serializedMoneySchema
|
|
50
50
|
});
|
|
51
51
|
module.exports = __toCommonJS(exports_zod);
|
|
52
52
|
var import_money = require("@storepass/money");
|
package/dist/zod.mjs
CHANGED
|
@@ -72,12 +72,12 @@ function createMoneyCodec(currencies) {
|
|
|
72
72
|
}
|
|
73
73
|
var moneyCodec = createMoneyCodec(Currency);
|
|
74
74
|
export {
|
|
75
|
-
|
|
76
|
-
moneySchema,
|
|
77
|
-
moneyInstanceSchema,
|
|
78
|
-
moneyCodec,
|
|
79
|
-
currencyDefinitionSchema,
|
|
80
|
-
currencyCodeSchema,
|
|
75
|
+
builtInSerializedMoneySchema,
|
|
81
76
|
createMoneyCodec,
|
|
82
|
-
|
|
77
|
+
currencyCodeSchema,
|
|
78
|
+
currencyDefinitionSchema,
|
|
79
|
+
moneyCodec,
|
|
80
|
+
moneyInstanceSchema,
|
|
81
|
+
moneySchema,
|
|
82
|
+
serializedMoneySchema
|
|
83
83
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storepass/money",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Money primitive library",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"author": "darling (https://github.com/darling)",
|
|
47
47
|
"repository": {
|
|
48
48
|
"type": "git",
|
|
49
|
-
"url": "https://github.com/
|
|
49
|
+
"url": "git+https://github.com/Storepass/money.git"
|
|
50
50
|
},
|
|
51
|
-
"homepage": "https://github.com/
|
|
51
|
+
"homepage": "https://github.com/Storepass/money#readme",
|
|
52
52
|
"bugs": {
|
|
53
|
-
"url": "https://github.com/
|
|
53
|
+
"url": "https://github.com/Storepass/money/issues"
|
|
54
54
|
},
|
|
55
55
|
"keywords": [
|
|
56
56
|
"money",
|