@ducatjs/money 0.0.0 → 0.2.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/LICENSE +21 -0
- package/NOTICE +51 -0
- package/README.md +1034 -3
- package/assets/CREDITS.md +12 -0
- package/data/adyen-fx.json +19 -0
- package/data/adyen.json +171 -0
- package/data/braintree.json +223 -0
- package/data/cash-rounding.json +520 -0
- package/data/checkout.json +230 -0
- package/data/cldr-cash.json +101 -0
- package/data/historic.json +78 -0
- package/data/iso4217-list-one.xml +1956 -0
- package/data/iso4217-list-three.xml +1185 -0
- package/data/klarna.json +95 -0
- package/data/paypal.json +65 -0
- package/data/stripe-fx.json +17 -0
- package/data/stripe.json +285 -0
- package/dist/adyen-fx.d.ts +25 -0
- package/dist/adyen-fx.d.ts.map +1 -0
- package/dist/adyen-fx.js +140 -0
- package/dist/adyen-fx.js.map +1 -0
- package/dist/adyen.d.ts +25 -0
- package/dist/adyen.d.ts.map +1 -0
- package/dist/adyen.js +34 -0
- package/dist/adyen.js.map +1 -0
- package/dist/allocate.d.ts +72 -0
- package/dist/allocate.d.ts.map +1 -0
- package/dist/allocate.js +314 -0
- package/dist/allocate.js.map +1 -0
- package/dist/bag.d.ts +58 -0
- package/dist/bag.d.ts.map +1 -0
- package/dist/bag.js +122 -0
- package/dist/bag.js.map +1 -0
- package/dist/boc.d.ts +31 -0
- package/dist/boc.d.ts.map +1 -0
- package/dist/boc.js +114 -0
- package/dist/boc.js.map +1 -0
- package/dist/boe.d.ts +33 -0
- package/dist/boe.d.ts.map +1 -0
- package/dist/boe.js +114 -0
- package/dist/boe.js.map +1 -0
- package/dist/braintree.d.ts +34 -0
- package/dist/braintree.d.ts.map +1 -0
- package/dist/braintree.js +45 -0
- package/dist/braintree.js.map +1 -0
- package/dist/cash.d.ts +64 -0
- package/dist/cash.d.ts.map +1 -0
- package/dist/cash.js +134 -0
- package/dist/cash.js.map +1 -0
- package/dist/checkout.d.ts +42 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +52 -0
- package/dist/checkout.js.map +1 -0
- package/dist/convert.d.ts +52 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +65 -0
- package/dist/convert.js.map +1 -0
- package/dist/currency.d.ts +22 -0
- package/dist/currency.d.ts.map +1 -0
- package/dist/currency.js +38 -0
- package/dist/currency.js.map +1 -0
- package/dist/decimal.d.ts +52 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +251 -0
- package/dist/decimal.js.map +1 -0
- package/dist/drizzle/mysql.d.ts +105 -0
- package/dist/drizzle/mysql.d.ts.map +1 -0
- package/dist/drizzle/mysql.js +60 -0
- package/dist/drizzle/mysql.js.map +1 -0
- package/dist/drizzle/pg.d.ts +103 -0
- package/dist/drizzle/pg.d.ts.map +1 -0
- package/dist/drizzle/pg.js +60 -0
- package/dist/drizzle/pg.js.map +1 -0
- package/dist/drizzle/sqlite.d.ts +102 -0
- package/dist/drizzle/sqlite.d.ts.map +1 -0
- package/dist/drizzle/sqlite.js +59 -0
- package/dist/drizzle/sqlite.js.map +1 -0
- package/dist/ecb.d.ts +52 -0
- package/dist/ecb.d.ts.map +1 -0
- package/dist/ecb.js +285 -0
- package/dist/ecb.js.map +1 -0
- package/dist/exact.d.ts +62 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +147 -0
- package/dist/exact.js.map +1 -0
- package/dist/fed.d.ts +35 -0
- package/dist/fed.d.ts.map +1 -0
- package/dist/fed.js +134 -0
- package/dist/fed.js.map +1 -0
- package/dist/fetch.d.ts +103 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +222 -0
- package/dist/fetch.js.map +1 -0
- package/dist/fixed.d.ts +121 -0
- package/dist/fixed.d.ts.map +1 -0
- package/dist/fixed.js +420 -0
- package/dist/fixed.js.map +1 -0
- package/dist/fn.d.ts +34 -0
- package/dist/fn.d.ts.map +1 -0
- package/dist/fn.js +37 -0
- package/dist/fn.js.map +1 -0
- package/dist/format.d.ts +13 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +90 -0
- package/dist/format.js.map +1 -0
- package/dist/generated/adyen.d.ts +3 -0
- package/dist/generated/adyen.d.ts.map +1 -0
- package/dist/generated/adyen.js +144 -0
- package/dist/generated/adyen.js.map +1 -0
- package/dist/generated/braintree.d.ts +3 -0
- package/dist/generated/braintree.d.ts.map +1 -0
- package/dist/generated/braintree.js +140 -0
- package/dist/generated/braintree.js.map +1 -0
- package/dist/generated/cash.d.ts +14 -0
- package/dist/generated/cash.d.ts.map +1 -0
- package/dist/generated/cash.js +465 -0
- package/dist/generated/cash.js.map +1 -0
- package/dist/generated/checkout.d.ts +3 -0
- package/dist/generated/checkout.d.ts.map +1 -0
- package/dist/generated/checkout.js +151 -0
- package/dist/generated/checkout.js.map +1 -0
- package/dist/generated/historic.d.ts +337 -0
- package/dist/generated/historic.d.ts.map +1 -0
- package/dist/generated/historic.js +66 -0
- package/dist/generated/historic.js.map +1 -0
- package/dist/generated/iso4217.d.ts +174 -0
- package/dist/generated/iso4217.d.ts.map +1 -0
- package/dist/generated/iso4217.js +175 -0
- package/dist/generated/iso4217.js.map +1 -0
- package/dist/generated/kernel.d.ts +17 -0
- package/dist/generated/kernel.d.ts.map +1 -0
- package/dist/generated/kernel.js +208 -0
- package/dist/generated/kernel.js.map +1 -0
- package/dist/generated/klarna.d.ts +3 -0
- package/dist/generated/klarna.d.ts.map +1 -0
- package/dist/generated/klarna.js +21 -0
- package/dist/generated/klarna.js.map +1 -0
- package/dist/generated/paypal.d.ts +3 -0
- package/dist/generated/paypal.d.ts.map +1 -0
- package/dist/generated/paypal.js +31 -0
- package/dist/generated/paypal.js.map +1 -0
- package/dist/generated/stripe.d.ts +8 -0
- package/dist/generated/stripe.d.ts.map +1 -0
- package/dist/generated/stripe.js +150 -0
- package/dist/generated/stripe.js.map +1 -0
- package/dist/historic.d.ts +40 -0
- package/dist/historic.d.ts.map +1 -0
- package/dist/historic.js +43 -0
- package/dist/historic.js.map +1 -0
- package/dist/history.d.ts +96 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +213 -0
- package/dist/history.js.map +1 -0
- package/dist/hmrc.d.ts +28 -0
- package/dist/hmrc.d.ts.map +1 -0
- package/dist/hmrc.js +108 -0
- package/dist/hmrc.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/klarna.d.ts +31 -0
- package/dist/klarna.d.ts.map +1 -0
- package/dist/klarna.js +38 -0
- package/dist/klarna.js.map +1 -0
- package/dist/kysely.d.ts +120 -0
- package/dist/kysely.d.ts.map +1 -0
- package/dist/kysely.js +309 -0
- package/dist/kysely.js.map +1 -0
- package/dist/money.d.ts +302 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +703 -0
- package/dist/money.js.map +1 -0
- package/dist/parse.d.ts +55 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +419 -0
- package/dist/parse.js.map +1 -0
- package/dist/paypal.d.ts +41 -0
- package/dist/paypal.d.ts.map +1 -0
- package/dist/paypal.js +58 -0
- package/dist/paypal.js.map +1 -0
- package/dist/pg.d.ts +100 -0
- package/dist/pg.d.ts.map +1 -0
- package/dist/pg.js +343 -0
- package/dist/pg.js.map +1 -0
- package/dist/plugins/adyen.d.ts +15 -0
- package/dist/plugins/adyen.d.ts.map +1 -0
- package/dist/plugins/adyen.js +10 -0
- package/dist/plugins/adyen.js.map +1 -0
- package/dist/plugins/all.d.ts +29 -0
- package/dist/plugins/all.d.ts.map +1 -0
- package/dist/plugins/all.js +30 -0
- package/dist/plugins/all.js.map +1 -0
- package/dist/plugins/allocate.d.ts +20 -0
- package/dist/plugins/allocate.d.ts.map +1 -0
- package/dist/plugins/allocate.js +26 -0
- package/dist/plugins/allocate.js.map +1 -0
- package/dist/plugins/braintree.d.ts +12 -0
- package/dist/plugins/braintree.d.ts.map +1 -0
- package/dist/plugins/braintree.js +12 -0
- package/dist/plugins/braintree.js.map +1 -0
- package/dist/plugins/cash.d.ts +19 -0
- package/dist/plugins/cash.d.ts.map +1 -0
- package/dist/plugins/cash.js +16 -0
- package/dist/plugins/cash.js.map +1 -0
- package/dist/plugins/checkout.d.ts +21 -0
- package/dist/plugins/checkout.d.ts.map +1 -0
- package/dist/plugins/checkout.js +16 -0
- package/dist/plugins/checkout.js.map +1 -0
- package/dist/plugins/convert.d.ts +19 -0
- package/dist/plugins/convert.d.ts.map +1 -0
- package/dist/plugins/convert.js +13 -0
- package/dist/plugins/convert.js.map +1 -0
- package/dist/plugins/exact.d.ts +15 -0
- package/dist/plugins/exact.d.ts.map +1 -0
- package/dist/plugins/exact.js +13 -0
- package/dist/plugins/exact.js.map +1 -0
- package/dist/plugins/fixed.d.ts +17 -0
- package/dist/plugins/fixed.d.ts.map +1 -0
- package/dist/plugins/fixed.js +13 -0
- package/dist/plugins/fixed.js.map +1 -0
- package/dist/plugins/format.d.ts +9 -0
- package/dist/plugins/format.d.ts.map +1 -0
- package/dist/plugins/format.js +16 -0
- package/dist/plugins/format.js.map +1 -0
- package/dist/plugins/klarna.d.ts +10 -0
- package/dist/plugins/klarna.d.ts.map +1 -0
- package/dist/plugins/klarna.js +10 -0
- package/dist/plugins/klarna.js.map +1 -0
- package/dist/plugins/paypal.d.ts +14 -0
- package/dist/plugins/paypal.d.ts.map +1 -0
- package/dist/plugins/paypal.js +16 -0
- package/dist/plugins/paypal.js.map +1 -0
- package/dist/plugins/prisma.d.ts +8 -0
- package/dist/plugins/prisma.d.ts.map +1 -0
- package/dist/plugins/prisma.js +13 -0
- package/dist/plugins/prisma.js.map +1 -0
- package/dist/plugins/stripe.d.ts +14 -0
- package/dist/plugins/stripe.d.ts.map +1 -0
- package/dist/plugins/stripe.js +16 -0
- package/dist/plugins/stripe.js.map +1 -0
- package/dist/plugins/tax.d.ts +20 -0
- package/dist/plugins/tax.d.ts.map +1 -0
- package/dist/plugins/tax.js +18 -0
- package/dist/plugins/tax.js.map +1 -0
- package/dist/policy.d.ts +34 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +90 -0
- package/dist/policy.js.map +1 -0
- package/dist/prisma.d.ts +77 -0
- package/dist/prisma.d.ts.map +1 -0
- package/dist/prisma.js +76 -0
- package/dist/prisma.js.map +1 -0
- package/dist/processor.d.ts +28 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +118 -0
- package/dist/processor.js.map +1 -0
- package/dist/provider.d.ts +103 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +280 -0
- package/dist/provider.js.map +1 -0
- package/dist/rate-text.d.ts +38 -0
- package/dist/rate-text.d.ts.map +1 -0
- package/dist/rate-text.js +143 -0
- package/dist/rate-text.js.map +1 -0
- package/dist/rate.d.ts +175 -0
- package/dist/rate.d.ts.map +1 -0
- package/dist/rate.js +371 -0
- package/dist/rate.js.map +1 -0
- package/dist/rounding-error.d.ts +9 -0
- package/dist/rounding-error.d.ts.map +1 -0
- package/dist/rounding-error.js +9 -0
- package/dist/rounding-error.js.map +1 -0
- package/dist/rounding.d.ts +50 -0
- package/dist/rounding.d.ts.map +1 -0
- package/dist/rounding.js +87 -0
- package/dist/rounding.js.map +1 -0
- package/dist/schema.d.ts +43 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql.d.ts +54 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +131 -0
- package/dist/sql.js.map +1 -0
- package/dist/stripe-fx.d.ts +22 -0
- package/dist/stripe-fx.d.ts.map +1 -0
- package/dist/stripe-fx.js +30 -0
- package/dist/stripe-fx.js.map +1 -0
- package/dist/stripe.d.ts +36 -0
- package/dist/stripe.d.ts.map +1 -0
- package/dist/stripe.js +39 -0
- package/dist/stripe.js.map +1 -0
- package/dist/tax.d.ts +33 -0
- package/dist/tax.d.ts.map +1 -0
- package/dist/tax.js +55 -0
- package/dist/tax.js.map +1 -0
- package/dist/testing/arbitraries.d.ts +43 -0
- package/dist/testing/arbitraries.d.ts.map +1 -0
- package/dist/testing/arbitraries.js +98 -0
- package/dist/testing/arbitraries.js.map +1 -0
- package/dist/testing/index.d.ts +67 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +159 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/jest.d.ts +2 -0
- package/dist/testing/jest.d.ts.map +1 -0
- package/dist/testing/jest.js +15 -0
- package/dist/testing/jest.js.map +1 -0
- package/dist/testing/vitest.d.ts +7 -0
- package/dist/testing/vitest.d.ts.map +1 -0
- package/dist/testing/vitest.js +12 -0
- package/dist/testing/vitest.js.map +1 -0
- package/dist/valibot.d.ts +33 -0
- package/dist/valibot.d.ts.map +1 -0
- package/dist/valibot.js +61 -0
- package/dist/valibot.js.map +1 -0
- package/dist/zod.d.ts +36 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +58 -0
- package/dist/zod.js.map +1 -0
- package/package.json +280 -5
- package/src/adyen-fx.ts +175 -0
- package/src/adyen.ts +46 -0
- package/src/allocate.ts +393 -0
- package/src/bag.ts +170 -0
- package/src/boc.ts +136 -0
- package/src/boe.ts +131 -0
- package/src/braintree.ts +71 -0
- package/src/cash.ts +183 -0
- package/src/checkout.ts +77 -0
- package/src/convert.ts +177 -0
- package/src/currency.ts +61 -0
- package/src/decimal.ts +283 -0
- package/src/drizzle/mysql.ts +78 -0
- package/src/drizzle/pg.ts +78 -0
- package/src/drizzle/sqlite.ts +70 -0
- package/src/ecb.ts +328 -0
- package/src/exact.ts +182 -0
- package/src/fed.ts +146 -0
- package/src/fetch.ts +306 -0
- package/src/fixed.ts +558 -0
- package/src/fn.ts +94 -0
- package/src/format.ts +106 -0
- package/src/generated/adyen.ts +144 -0
- package/src/generated/braintree.ts +140 -0
- package/src/generated/cash.ts +478 -0
- package/src/generated/checkout.ts +151 -0
- package/src/generated/historic.ts +67 -0
- package/src/generated/iso4217.ts +179 -0
- package/src/generated/kernel.ts +230 -0
- package/src/generated/klarna.ts +21 -0
- package/src/generated/paypal.ts +31 -0
- package/src/generated/stripe.ts +150 -0
- package/src/historic.ts +77 -0
- package/src/history.ts +333 -0
- package/src/hmrc.ts +125 -0
- package/src/index.ts +41 -0
- package/src/klarna.ts +54 -0
- package/src/kysely.ts +588 -0
- package/src/money.ts +979 -0
- package/src/parse.ts +511 -0
- package/src/paypal.ts +93 -0
- package/src/pg.ts +410 -0
- package/src/plugins/adyen.ts +25 -0
- package/src/plugins/all.ts +57 -0
- package/src/plugins/allocate.ts +53 -0
- package/src/plugins/braintree.ts +23 -0
- package/src/plugins/cash.ts +33 -0
- package/src/plugins/checkout.ts +32 -0
- package/src/plugins/convert.ts +49 -0
- package/src/plugins/exact.ts +23 -0
- package/src/plugins/fixed.ts +28 -0
- package/src/plugins/format.ts +28 -0
- package/src/plugins/klarna.ts +21 -0
- package/src/plugins/paypal.ts +29 -0
- package/src/plugins/prisma.ts +24 -0
- package/src/plugins/stripe.ts +29 -0
- package/src/plugins/tax.ts +40 -0
- package/src/policy.ts +124 -0
- package/src/prisma.ts +199 -0
- package/src/processor.ts +181 -0
- package/src/provider.ts +389 -0
- package/src/rate-text.ts +151 -0
- package/src/rate.ts +546 -0
- package/src/rounding-error.ts +8 -0
- package/src/rounding.ts +122 -0
- package/src/schema.ts +119 -0
- package/src/sql.ts +178 -0
- package/src/stripe-fx.ts +49 -0
- package/src/stripe.ts +69 -0
- package/src/tax.ts +102 -0
- package/src/testing/arbitraries.ts +134 -0
- package/src/testing/index.ts +247 -0
- package/src/testing/jest.ts +18 -0
- package/src/testing/vitest.ts +18 -0
- package/src/valibot.ts +87 -0
- package/src/zod.ts +78 -0
package/dist/schema.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isCurrency } from './currency.js';
|
|
2
|
+
import { MAX_DECIMAL_SCALE } from './decimal.js';
|
|
3
|
+
import { money } from './money.js';
|
|
4
|
+
import { Rounding } from './rounding.js';
|
|
5
|
+
/** The default `maxDigits`: far beyond any real amount, small enough to be cheap to reject. */
|
|
6
|
+
export const DEFAULT_MAX_DIGITS = 50;
|
|
7
|
+
const MODES = new Set(Object.values(Rounding));
|
|
8
|
+
/**
|
|
9
|
+
* @internal Checks the options when the schema is built, so a mistake there throws at once
|
|
10
|
+
* instead of turning every input into a validation error.
|
|
11
|
+
*/
|
|
12
|
+
export function checkSchemaOptions(options) {
|
|
13
|
+
if (options === undefined) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const allowed = options.currency;
|
|
17
|
+
const codes = typeof allowed === 'string' || allowed === undefined ? [allowed] : allowed;
|
|
18
|
+
for (const code of codes) {
|
|
19
|
+
if (code !== undefined && !isCurrency(code)) {
|
|
20
|
+
throw new RangeError(`Unknown currency ${String(code)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const scale = options.scale;
|
|
24
|
+
if (scale !== undefined &&
|
|
25
|
+
!(Number.isInteger(scale) && scale >= 0 && scale <= MAX_DECIMAL_SCALE)) {
|
|
26
|
+
throw new RangeError(`Invalid scale ${scale}`);
|
|
27
|
+
}
|
|
28
|
+
if (options.rounding !== undefined && !MODES.has(options.rounding)) {
|
|
29
|
+
throw new RangeError(`Invalid rounding mode ${String(options.rounding)}`);
|
|
30
|
+
}
|
|
31
|
+
const maxDigits = options.maxDigits;
|
|
32
|
+
if (maxDigits !== undefined && !(Number.isSafeInteger(maxDigits) && maxDigits >= 1)) {
|
|
33
|
+
throw new RangeError(`Invalid maxDigits ${maxDigits}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// The exact decimal strings `toJSON` writes: an optional minus, digits, and an optional fraction.
|
|
37
|
+
// No exponent, no plus sign, no whitespace and no grouping, so the wire format stays unambiguous.
|
|
38
|
+
const DECIMAL = /^-?\d+(?:\.\d+)?$/;
|
|
39
|
+
/**
|
|
40
|
+
* @internal Reads `{ amount, currency }` (already known to have two string fields) into Money, or
|
|
41
|
+
* says what is wrong with it. Shared by the Zod and Valibot entries, so both accept exactly the
|
|
42
|
+
* same inputs.
|
|
43
|
+
*/
|
|
44
|
+
export function readMoneyJSON(json, options) {
|
|
45
|
+
const currency = json.currency;
|
|
46
|
+
const allowed = options?.currency;
|
|
47
|
+
if (allowed === undefined) {
|
|
48
|
+
if (!isCurrency(currency)) {
|
|
49
|
+
return { field: 'currency', message: `Unknown currency "${currency}"` };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (typeof allowed === 'string' ? currency !== allowed : !allowed.includes(currency)) {
|
|
53
|
+
const expected = typeof allowed === 'string' ? allowed : allowed.join(', ');
|
|
54
|
+
return { field: 'currency', message: `Expected currency ${expected}, got "${currency}"` };
|
|
55
|
+
}
|
|
56
|
+
const amount = json.amount;
|
|
57
|
+
// Checked before the pattern, so a huge string is rejected without scanning it.
|
|
58
|
+
const maxLength = (options?.maxDigits ?? DEFAULT_MAX_DIGITS) + 2;
|
|
59
|
+
if (amount.length > maxLength || !DECIMAL.test(amount)) {
|
|
60
|
+
return { field: 'amount', message: 'Expected a decimal string such as "12.34"' };
|
|
61
|
+
}
|
|
62
|
+
const digitCount = amount.length - (amount[0] === '-' ? 1 : 0) - (amount.includes('.') ? 1 : 0);
|
|
63
|
+
if (digitCount > (options?.maxDigits ?? DEFAULT_MAX_DIGITS)) {
|
|
64
|
+
return {
|
|
65
|
+
field: 'amount',
|
|
66
|
+
message: `More than ${options?.maxDigits ?? DEFAULT_MAX_DIGITS} digits`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
return money(amount, currency, options);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// the options are checked up front, so this is too many decimals for the scale
|
|
74
|
+
return { field: 'amount', message: error.message };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/sql.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Money } from './money.js';
|
|
2
|
+
/** The declared size of a NUMERIC/DECIMAL column. */
|
|
3
|
+
export interface DecimalColumnSize {
|
|
4
|
+
/** Total number of significant digits the column holds. */
|
|
5
|
+
readonly precision: number;
|
|
6
|
+
/** Digits after the decimal point. */
|
|
7
|
+
readonly scale: number;
|
|
8
|
+
}
|
|
9
|
+
/** NUMERIC(19,4): 15 integer digits and 4 decimals, enough for every ISO 4217 exponent. */
|
|
10
|
+
export declare const DEFAULT_DECIMAL_SIZE: DecimalColumnSize;
|
|
11
|
+
/** Throws unless the money is in the column's currency (when the column has a fixed currency). */
|
|
12
|
+
export declare function checkCurrency(money: Money, currency: string | undefined): void;
|
|
13
|
+
/**
|
|
14
|
+
* Throws unless the money is at its currency's exponent. Columns store amounts at the currency's
|
|
15
|
+
* scale, so a value with sub-minor digits would have to be rounded, and the caller should choose how.
|
|
16
|
+
*/
|
|
17
|
+
export declare function checkIsoScale(money: Money): void;
|
|
18
|
+
/**
|
|
19
|
+
* Minor units for a BIGINT column, as a bigint. Throws beyond the column's range, ±9.2·10^18:
|
|
20
|
+
* MySQL outside strict mode would store the nearest limit instead.
|
|
21
|
+
*/
|
|
22
|
+
export declare function minorToDriver(money: Money, currency: string | undefined): bigint;
|
|
23
|
+
/**
|
|
24
|
+
* Money from a BIGINT driver value. Accepts a bigint, a safe-integer number, or an integer string
|
|
25
|
+
* (node-postgres returns int8 as a string). A number beyond 2^53 has already lost digits, so it
|
|
26
|
+
* throws.
|
|
27
|
+
*/
|
|
28
|
+
export declare function minorFromDriver<C extends string>(value: unknown, currency: C): Money<C>;
|
|
29
|
+
/** Throws if a decimal column of this size would round amounts in this currency. */
|
|
30
|
+
export declare function checkDecimalSize(currency: string, size: DecimalColumnSize): void;
|
|
31
|
+
/**
|
|
32
|
+
* The exact decimal string for a NUMERIC/DECIMAL column. Throws if the column could not hold it
|
|
33
|
+
* unchanged: MySQL outside strict mode clamps an out-of-range value instead of failing.
|
|
34
|
+
*/
|
|
35
|
+
export declare function decimalToDriver(money: Money, currency: string | undefined, size: DecimalColumnSize | undefined): string;
|
|
36
|
+
/**
|
|
37
|
+
* Throws if the decimal (the money's `toDecimal`) has more integer digits than a column of this
|
|
38
|
+
* size holds: Postgres rejects it, and MySQL outside strict mode clamps it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function checkIntegerDigits(money: Money, decimal: string, size: DecimalColumnSize): void;
|
|
41
|
+
/**
|
|
42
|
+
* Money from a NUMERIC/DECIMAL driver value, which must be a string: a number has been through a
|
|
43
|
+
* float. Trailing zeros (`12.3400` from NUMERIC(19,4)) are fine; more decimals than the currency
|
|
44
|
+
* has, `NaN` and `Infinity` throw.
|
|
45
|
+
*/
|
|
46
|
+
export declare function decimalFromDriver<C extends string>(value: unknown, currency: C): Money<C>;
|
|
47
|
+
/** `{"amount":"12.34","currency":"EUR"}` for a JSON, JSONB or TEXT column. */
|
|
48
|
+
export declare function jsonToDriver(money: Money, currency: string | undefined): string;
|
|
49
|
+
/**
|
|
50
|
+
* Money from a JSON column: the parsed object (JSONB in node-postgres, JSON in mysql2) or the
|
|
51
|
+
* text (SQLite).
|
|
52
|
+
*/
|
|
53
|
+
export declare function jsonFromDriver<C extends string>(value: unknown, currency: C | undefined): Money<C>;
|
|
54
|
+
//# sourceMappingURL=sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAKA,OAAO,EAOL,KAAK,KAAK,EAEX,MAAM,YAAY,CAAC;AAOpB,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,2FAA2F;AAC3F,eAAO,MAAM,oBAAoB,EAAE,iBAA+C,CAAC;AAEnF,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAI9E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAOhD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAShF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAWvF;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAkBhF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,EAAE,iBAAiB,GAAG,SAAS,GAClC,MAAM,CASR;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAU/F;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAQzF;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI/E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,EAC7C,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,GAAG,SAAS,GACtB,KAAK,CAAC,CAAC,CAAC,CAOV"}
|
package/dist/sql.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Conversions between Money and the values SQL drivers send and receive, shared by the ORM and
|
|
2
|
+
// query-builder integrations (`/drizzle/*`, `/kysely`). Every reader is strict: a driver value that
|
|
3
|
+
// may already have lost digits (an unsafe number, a float for a DECIMAL) is rejected rather than
|
|
4
|
+
// trusted, and every writer refuses a value the column would change.
|
|
5
|
+
import { currencyExponent } from './currency.js';
|
|
6
|
+
import { CurrencyMismatchError, fromJSON, fromMinor, money as parseMoney, toDecimal, toMinor, } from './money.js';
|
|
7
|
+
const INTEGER_TEXT = /^-?\d+$/;
|
|
8
|
+
// a BIGINT (SQLite INTEGER) column's range: MySQL outside strict mode clips anything beyond it
|
|
9
|
+
const BIGINT_MIN = -(2n ** 63n);
|
|
10
|
+
const BIGINT_MAX = 2n ** 63n - 1n;
|
|
11
|
+
/** NUMERIC(19,4): 15 integer digits and 4 decimals, enough for every ISO 4217 exponent. */
|
|
12
|
+
export const DEFAULT_DECIMAL_SIZE = { precision: 19, scale: 4 };
|
|
13
|
+
/** Throws unless the money is in the column's currency (when the column has a fixed currency). */
|
|
14
|
+
export function checkCurrency(money, currency) {
|
|
15
|
+
if (currency !== undefined && money.currency !== currency) {
|
|
16
|
+
throw new CurrencyMismatchError(currency, money.currency);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Throws unless the money is at its currency's exponent. Columns store amounts at the currency's
|
|
21
|
+
* scale, so a value with sub-minor digits would have to be rounded, and the caller should choose how.
|
|
22
|
+
*/
|
|
23
|
+
export function checkIsoScale(money) {
|
|
24
|
+
const exponent = currencyExponent(money.currency);
|
|
25
|
+
if (money.scale !== exponent) {
|
|
26
|
+
throw new RangeError(`${money} has scale ${money.scale}; round() it to ${exponent} decimals before storing it`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Minor units for a BIGINT column, as a bigint. Throws beyond the column's range, ±9.2·10^18:
|
|
31
|
+
* MySQL outside strict mode would store the nearest limit instead.
|
|
32
|
+
*/
|
|
33
|
+
export function minorToDriver(money, currency) {
|
|
34
|
+
checkCurrency(money, currency);
|
|
35
|
+
checkIsoScale(money);
|
|
36
|
+
const minor = toMinor(money);
|
|
37
|
+
if (minor < BIGINT_MIN || minor > BIGINT_MAX) {
|
|
38
|
+
throw new RangeError(`${money} is ${minor} minor units, beyond the range of a BIGINT column`);
|
|
39
|
+
}
|
|
40
|
+
return minor;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Money from a BIGINT driver value. Accepts a bigint, a safe-integer number, or an integer string
|
|
44
|
+
* (node-postgres returns int8 as a string). A number beyond 2^53 has already lost digits, so it
|
|
45
|
+
* throws.
|
|
46
|
+
*/
|
|
47
|
+
export function minorFromDriver(value, currency) {
|
|
48
|
+
if (typeof value === 'string') {
|
|
49
|
+
if (!INTEGER_TEXT.test(value)) {
|
|
50
|
+
throw new SyntaxError(`Expected an integer from a BIGINT column, got "${value}"`);
|
|
51
|
+
}
|
|
52
|
+
return fromMinor(BigInt(value), currency);
|
|
53
|
+
}
|
|
54
|
+
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
55
|
+
return fromMinor(value, currency);
|
|
56
|
+
}
|
|
57
|
+
throw new TypeError(`Expected an integer from a BIGINT column, got ${typeof value}`);
|
|
58
|
+
}
|
|
59
|
+
/** Throws if a decimal column of this size would round amounts in this currency. */
|
|
60
|
+
export function checkDecimalSize(currency, size) {
|
|
61
|
+
const { precision, scale } = size;
|
|
62
|
+
const isValidSize = Number.isInteger(precision) &&
|
|
63
|
+
Number.isInteger(scale) &&
|
|
64
|
+
precision >= 1 &&
|
|
65
|
+
scale >= 0 &&
|
|
66
|
+
scale <= precision;
|
|
67
|
+
if (!isValidSize) {
|
|
68
|
+
throw new RangeError(`NUMERIC(${precision},${scale}) is not a valid column size`);
|
|
69
|
+
}
|
|
70
|
+
const exponent = currencyExponent(currency);
|
|
71
|
+
if (size.scale < exponent) {
|
|
72
|
+
throw new RangeError(`NUMERIC(${size.precision},${size.scale}) would round ${currency}, which has ${exponent} decimals`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The exact decimal string for a NUMERIC/DECIMAL column. Throws if the column could not hold it
|
|
77
|
+
* unchanged: MySQL outside strict mode clamps an out-of-range value instead of failing.
|
|
78
|
+
*/
|
|
79
|
+
export function decimalToDriver(money, currency, size) {
|
|
80
|
+
checkCurrency(money, currency);
|
|
81
|
+
checkIsoScale(money);
|
|
82
|
+
const decimal = toDecimal(money);
|
|
83
|
+
if (size !== undefined) {
|
|
84
|
+
checkIntegerDigits(money, decimal, size);
|
|
85
|
+
}
|
|
86
|
+
return decimal;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Throws if the decimal (the money's `toDecimal`) has more integer digits than a column of this
|
|
90
|
+
* size holds: Postgres rejects it, and MySQL outside strict mode clamps it.
|
|
91
|
+
*/
|
|
92
|
+
export function checkIntegerDigits(money, decimal, size) {
|
|
93
|
+
const integerPart = decimal.replace('-', '').split('.')[0];
|
|
94
|
+
// "0.12" has no integer digits: NUMERIC(4,4) holds it
|
|
95
|
+
const integerDigits = integerPart === '0' ? 0 : integerPart.length;
|
|
96
|
+
if (integerDigits > size.precision - size.scale) {
|
|
97
|
+
throw new RangeError(`${money} does not fit NUMERIC(${size.precision},${size.scale}), which holds ` +
|
|
98
|
+
`${size.precision - size.scale} integer digits`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Money from a NUMERIC/DECIMAL driver value, which must be a string: a number has been through a
|
|
103
|
+
* float. Trailing zeros (`12.3400` from NUMERIC(19,4)) are fine; more decimals than the currency
|
|
104
|
+
* has, `NaN` and `Infinity` throw.
|
|
105
|
+
*/
|
|
106
|
+
export function decimalFromDriver(value, currency) {
|
|
107
|
+
if (typeof value !== 'string') {
|
|
108
|
+
throw new TypeError(`Expected a string from a DECIMAL column, got ${typeof value}; ` +
|
|
109
|
+
'configure the driver to return decimals as strings');
|
|
110
|
+
}
|
|
111
|
+
return parseMoney(value, currency);
|
|
112
|
+
}
|
|
113
|
+
/** `{"amount":"12.34","currency":"EUR"}` for a JSON, JSONB or TEXT column. */
|
|
114
|
+
export function jsonToDriver(money, currency) {
|
|
115
|
+
checkCurrency(money, currency);
|
|
116
|
+
checkIsoScale(money);
|
|
117
|
+
return JSON.stringify(money);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Money from a JSON column: the parsed object (JSONB in node-postgres, JSON in mysql2) or the
|
|
121
|
+
* text (SQLite).
|
|
122
|
+
*/
|
|
123
|
+
export function jsonFromDriver(value, currency) {
|
|
124
|
+
if (typeof value !== 'string' && (typeof value !== 'object' || value === null)) {
|
|
125
|
+
throw new TypeError(`Expected JSON from a money column, got ${String(value)}`);
|
|
126
|
+
}
|
|
127
|
+
const parsed = fromJSON(value);
|
|
128
|
+
checkCurrency(parsed, currency);
|
|
129
|
+
return parsed;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=sql.js.map
|
package/dist/sql.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Money } from './money.js';
|
|
2
|
+
import { type Rate } from './rate.js';
|
|
3
|
+
/** The fields of a Stripe BalanceTransaction used here. */
|
|
4
|
+
export interface StripeBalanceTransaction {
|
|
5
|
+
readonly amount: number;
|
|
6
|
+
readonly currency: string;
|
|
7
|
+
readonly exchange_rate?: number | null;
|
|
8
|
+
/** Seconds since the Unix epoch. */
|
|
9
|
+
readonly created?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The rate Stripe quotes on a balance transaction, from the charge currency `from` to the balance
|
|
13
|
+
* currency: "the amount in currency A, multiplied by the exchange_rate, equals the amount in
|
|
14
|
+
* currency B". The JSON number is read at its shortest decimal form, so 1.234 is exactly 1234/1000.
|
|
15
|
+
* `asOf` is the balance transaction's `created` time, the closest timestamp Stripe gives for the
|
|
16
|
+
* conversion; it is not the charge's creation time, and Stripe doesn't say when the rate was
|
|
17
|
+
* quoted. `undefined` when nothing was converted.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stripeRate<From extends string>(from: From, transaction: StripeBalanceTransaction): Rate<Uppercase<From>, Uppercase<string>> | undefined;
|
|
20
|
+
/** The exact rate Stripe applied: the balance transaction's gross amount ÷ the charged amount. */
|
|
21
|
+
export declare function stripeImpliedRate<From extends string>(charged: Money<From>, transaction: StripeBalanceTransaction): Rate<From, Uppercase<string>>;
|
|
22
|
+
//# sourceMappingURL=stripe-fx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-fx.d.ts","sourceRoot":"","sources":["../src/stripe-fx.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAA6B,KAAK,IAAI,EAAiB,MAAM,WAAW,CAAC;AAGhF,2DAA2D;AAC3D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,oCAAoC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AASD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,SAAS,MAAM,EAC5C,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,wBAAwB,GACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAOtD;AAED,kGAAkG;AAClG,wBAAgB,iBAAiB,CAAC,IAAI,SAAS,MAAM,EACnD,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,EACpB,WAAW,EAAE,wBAAwB,GACpC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAG/B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { exchangeRate, impliedRate } from './rate.js';
|
|
2
|
+
import { fromStripe } from './stripe.js';
|
|
3
|
+
function stripeInfo(transaction) {
|
|
4
|
+
if (transaction.created === undefined) {
|
|
5
|
+
return { source: 'stripe' };
|
|
6
|
+
}
|
|
7
|
+
return { source: 'stripe', asOf: new Date(transaction.created * 1000) };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The rate Stripe quotes on a balance transaction, from the charge currency `from` to the balance
|
|
11
|
+
* currency: "the amount in currency A, multiplied by the exchange_rate, equals the amount in
|
|
12
|
+
* currency B". The JSON number is read at its shortest decimal form, so 1.234 is exactly 1234/1000.
|
|
13
|
+
* `asOf` is the balance transaction's `created` time, the closest timestamp Stripe gives for the
|
|
14
|
+
* conversion; it is not the charge's creation time, and Stripe doesn't say when the rate was
|
|
15
|
+
* quoted. `undefined` when nothing was converted.
|
|
16
|
+
*/
|
|
17
|
+
export function stripeRate(from, transaction) {
|
|
18
|
+
if (transaction.exchange_rate === undefined || transaction.exchange_rate === null) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const charged = from.toUpperCase();
|
|
22
|
+
const balance = transaction.currency.toUpperCase();
|
|
23
|
+
return exchangeRate(charged, balance, transaction.exchange_rate, stripeInfo(transaction));
|
|
24
|
+
}
|
|
25
|
+
/** The exact rate Stripe applied: the balance transaction's gross amount ÷ the charged amount. */
|
|
26
|
+
export function stripeImpliedRate(charged, transaction) {
|
|
27
|
+
const settled = fromStripe(transaction.amount, transaction.currency.toUpperCase());
|
|
28
|
+
return impliedRate(charged, settled, stripeInfo(transaction));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=stripe-fx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-fx.js","sourceRoot":"","sources":["../src/stripe-fx.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,WAAW,EAA4B,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAWzC,SAAS,UAAU,CAAC,WAAqC;IACvD,IAAI,WAAW,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,IAAU,EACV,WAAqC;IAErC,IAAI,WAAW,CAAC,aAAa,KAAK,SAAS,IAAI,WAAW,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QAClF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAqB,CAAC;IACtD,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAuB,CAAC;IACxE,OAAO,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,iBAAiB,CAC/B,OAAoB,EACpB,WAAqC;IAErC,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACnF,OAAO,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;AAChE,CAAC"}
|
package/dist/stripe.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe's minor-unit view. Stripe uses ISO exponents except where documented otherwise
|
|
3
|
+
* (https://docs.stripe.com/currencies, encoded in data/stripe.json):
|
|
4
|
+
* - zero-decimal: BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF (note MGA: ISO says
|
|
5
|
+
* 2)
|
|
6
|
+
* - ISK, UGX: sent as two-decimal values whose last two digits are 00 (5 ISK -> 500)
|
|
7
|
+
* - HUF, TWD: two decimals for charges, but payouts must be whole units (multiple of 100)
|
|
8
|
+
* - BHD JOD KWD OMR TND: three decimals, last digit must be 0 (UAE accounts only)
|
|
9
|
+
*/
|
|
10
|
+
import { STRIPE_RULES } from './generated/stripe.js';
|
|
11
|
+
import { type CurrencyInput, type Money } from './money.js';
|
|
12
|
+
import type { RoundingMode } from './rounding.js';
|
|
13
|
+
export { STRIPE_RULES };
|
|
14
|
+
/** Whether Stripe supports the currency as a presentment currency. */
|
|
15
|
+
export declare const isStripeCurrency: (currency: string) => boolean;
|
|
16
|
+
/** The exponent Stripe's API uses for a currency (ISK 2, JPY 0, KWD 3, MGA 0). */
|
|
17
|
+
export declare const stripeExponent: (currency: string) => number;
|
|
18
|
+
/**
|
|
19
|
+
* Options for the Stripe amount: payout rules and how to round when Stripe needs a coarser amount.
|
|
20
|
+
*/
|
|
21
|
+
export interface StripeAmountOptions {
|
|
22
|
+
/** Payout amounts have stricter rules (HUF, TWD: whole units). */
|
|
23
|
+
readonly payout?: boolean;
|
|
24
|
+
/** How to round when Stripe needs a coarser amount (default 'unnecessary': throw). */
|
|
25
|
+
readonly rounding?: RoundingMode;
|
|
26
|
+
}
|
|
27
|
+
/** The integer `amount` to send to Stripe, e.g. toStripeAmount(money('5', 'ISK')) === 500. */
|
|
28
|
+
export declare function toStripeAmount(money: Money, options?: StripeAmountOptions): number;
|
|
29
|
+
/** `{ amount, currency }` with Stripe's lowercase currency code, ready for a PaymentIntent. */
|
|
30
|
+
export declare function toStripe(money: Money, options?: StripeAmountOptions): {
|
|
31
|
+
amount: number;
|
|
32
|
+
currency: string;
|
|
33
|
+
};
|
|
34
|
+
/** Reads a Stripe amount (e.g. from a webhook): fromStripe(500, 'isk') is 5 ISK. */
|
|
35
|
+
export declare function fromStripe<C extends CurrencyInput>(amount: number | bigint, currency: C): Money<Uppercase<C>>;
|
|
36
|
+
//# sourceMappingURL=stripe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../src/stripe.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,CAAC;AAUxB,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,KAAG,OACA,CAAC;AAErD,kFAAkF;AAClF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAA2B,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;CAClC;AAED,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,MAAM,CASlF;AAED,+FAA+F;AAC/F,wBAAgB,QAAQ,CACtB,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,mBAAmB,GAC5B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAEtC;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,CAAC,SAAS,aAAa,EAChD,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,EAAE,CAAC,GACV,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAGrB"}
|
package/dist/stripe.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe's minor-unit view. Stripe uses ISO exponents except where documented otherwise
|
|
3
|
+
* (https://docs.stripe.com/currencies, encoded in data/stripe.json):
|
|
4
|
+
* - zero-decimal: BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF (note MGA: ISO says
|
|
5
|
+
* 2)
|
|
6
|
+
* - ISK, UGX: sent as two-decimal values whose last two digits are 00 (5 ISK -> 500)
|
|
7
|
+
* - HUF, TWD: two decimals for charges, but payouts must be whole units (multiple of 100)
|
|
8
|
+
* - BHD JOD KWD OMR TND: three decimals, last digit must be 0 (UAE accounts only)
|
|
9
|
+
*/
|
|
10
|
+
import { STRIPE_RULES } from './generated/stripe.js';
|
|
11
|
+
import {} from './money.js';
|
|
12
|
+
import { fromProcessorAmount, toProcessorAmount } from './processor.js';
|
|
13
|
+
export { STRIPE_RULES };
|
|
14
|
+
function rule(currency) {
|
|
15
|
+
const found = STRIPE_RULES[currency.toUpperCase()];
|
|
16
|
+
if (!found) {
|
|
17
|
+
throw new RangeError(`${currency} is not a Stripe presentment currency`);
|
|
18
|
+
}
|
|
19
|
+
return found;
|
|
20
|
+
}
|
|
21
|
+
/** Whether Stripe supports the currency as a presentment currency. */
|
|
22
|
+
export const isStripeCurrency = (currency) => STRIPE_RULES[currency.toUpperCase()] !== undefined;
|
|
23
|
+
/** The exponent Stripe's API uses for a currency (ISK 2, JPY 0, KWD 3, MGA 0). */
|
|
24
|
+
export const stripeExponent = (currency) => rule(currency)[0];
|
|
25
|
+
/** The integer `amount` to send to Stripe, e.g. toStripeAmount(money('5', 'ISK')) === 500. */
|
|
26
|
+
export function toStripeAmount(money, options) {
|
|
27
|
+
const [exp, charge, payout] = rule(money.currency);
|
|
28
|
+
return toProcessorAmount('Stripe', money, exp, options?.payout ? payout : charge, options?.rounding ?? 'unnecessary');
|
|
29
|
+
}
|
|
30
|
+
/** `{ amount, currency }` with Stripe's lowercase currency code, ready for a PaymentIntent. */
|
|
31
|
+
export function toStripe(money, options) {
|
|
32
|
+
return { amount: toStripeAmount(money, options), currency: money.currency.toLowerCase() };
|
|
33
|
+
}
|
|
34
|
+
/** Reads a Stripe amount (e.g. from a webhook): fromStripe(500, 'isk') is 5 ISK. */
|
|
35
|
+
export function fromStripe(amount, currency) {
|
|
36
|
+
const code = currency.toUpperCase();
|
|
37
|
+
return fromProcessorAmount('Stripe', amount, code, rule(code)[0]);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=stripe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../src/stripe.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAkC,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxE,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,SAAS,IAAI,CAAC,QAAgB;IAC5B,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,GAAG,QAAQ,uCAAuC,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAW,EAAE,CAC5D,YAAY,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,SAAS,CAAC;AAErD,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAY9E,8FAA8F;AAC9F,MAAM,UAAU,cAAc,CAAC,KAAY,EAAE,OAA6B;IACxE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACnD,OAAO,iBAAiB,CACtB,QAAQ,EACR,KAAK,EACL,GAAG,EACH,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EACjC,OAAO,EAAE,QAAQ,IAAI,aAAa,CACnC,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,QAAQ,CACtB,KAAY,EACZ,OAA6B;IAE7B,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;AAC5F,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,UAAU,CACxB,MAAuB,EACvB,QAAW;IAEX,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAkB,CAAC;IACpD,OAAO,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC"}
|
package/dist/tax.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Factor } from './decimal.js';
|
|
2
|
+
import { type Money, type RoundingInput } from './money.js';
|
|
3
|
+
/**
|
|
4
|
+
* percent% of m: percentage(EUR 80, '12.5', 'halfEven') = EUR 10.00. Rounding defaults to
|
|
5
|
+
* 'halfExpand'.
|
|
6
|
+
*/
|
|
7
|
+
export declare function percentage<C extends string>(money: Money<C>, percent: Factor, rounding?: RoundingInput): Money<C>;
|
|
8
|
+
/** A tax split: net + tax is always exactly gross. */
|
|
9
|
+
export interface TaxBreakdown<C extends string> {
|
|
10
|
+
readonly net: Money<C>;
|
|
11
|
+
readonly tax: Money<C>;
|
|
12
|
+
/** Always exactly net + tax. */
|
|
13
|
+
readonly gross: Money<C>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Tax-exclusive: adds percent% tax to a net amount. addTax(EUR 10, '20', 'halfEven') -> net 10, tax
|
|
17
|
+
* 2, gross 12. A rounding mode rounds the tax; a rounding policy rounds the gross (the amount
|
|
18
|
+
* charged) to its scale and increment. The other part is always the exact difference.
|
|
19
|
+
*/
|
|
20
|
+
export declare function addTax<C extends string>(net: Money<C>, percent: Factor, rounding?: RoundingInput): TaxBreakdown<C>;
|
|
21
|
+
/**
|
|
22
|
+
* Tax-inclusive: extracts percent% tax contained in a gross amount (VAT extraction).
|
|
23
|
+
* net = gross / (1 + percent/100) rounded; tax = gross - net, so the parts always add up.
|
|
24
|
+
* extractTax(EUR 12, '20', 'halfEven') -> net 10.00, tax 2.00. A rounding policy rounds the net; the
|
|
25
|
+
* tax is on the policy's increment too whenever the gross is.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractTax<C extends string>(gross: Money<C>, percent: Factor, rounding?: RoundingInput): TaxBreakdown<C>;
|
|
28
|
+
/**
|
|
29
|
+
* Price after a percent% discount. A rounding mode rounds the discount amount; a rounding policy
|
|
30
|
+
* rounds the discounted price itself, so the price lands on the policy's scale and increment.
|
|
31
|
+
*/
|
|
32
|
+
export declare function discount<C extends string>(price: Money<C>, percent: Factor, rounding?: RoundingInput): Money<C>;
|
|
33
|
+
//# sourceMappingURL=tax.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tax.d.ts","sourceRoot":"","sources":["../src/tax.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,MAAM,EAAc,MAAM,cAAc,CAAC;AAC9D,OAAO,EAKL,KAAK,KAAK,EACV,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAQpB;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,aAAgC,GACzC,KAAK,CAAC,CAAC,CAAC,CAEV;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EACrC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,aAAgC,GACzC,YAAY,CAAC,CAAC,CAAC,CAejB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,aAAgC,GACzC,YAAY,CAAC,CAAC,CAAC,CASjB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACvC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,aAAgC,GACzC,KAAK,CAAC,CAAC,CAAC,CAUV"}
|
package/dist/tax.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ratio } from './decimal.js';
|
|
2
|
+
import { add, multiplyByRatio, roundWithPolicy, subtract, } from './money.js';
|
|
3
|
+
import { DEFAULT_ROUNDING } from './rounding.js';
|
|
4
|
+
const percentRatio = (percent) => {
|
|
5
|
+
const asRatio = ratio(percent);
|
|
6
|
+
return ratio(asRatio.num, asRatio.den * 100n);
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* percent% of m: percentage(EUR 80, '12.5', 'halfEven') = EUR 10.00. Rounding defaults to
|
|
10
|
+
* 'halfExpand'.
|
|
11
|
+
*/
|
|
12
|
+
export function percentage(money, percent, rounding = DEFAULT_ROUNDING) {
|
|
13
|
+
return multiplyByRatio(money, percentRatio(percent), rounding);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Tax-exclusive: adds percent% tax to a net amount. addTax(EUR 10, '20', 'halfEven') -> net 10, tax
|
|
17
|
+
* 2, gross 12. A rounding mode rounds the tax; a rounding policy rounds the gross (the amount
|
|
18
|
+
* charged) to its scale and increment. The other part is always the exact difference.
|
|
19
|
+
*/
|
|
20
|
+
export function addTax(net, percent, rounding = DEFAULT_ROUNDING) {
|
|
21
|
+
// A rounding mode rounds the tax; a policy rounds the gross, the amount charged, so it lands on
|
|
22
|
+
// the policy's increment (CHF 0.05 for cash). Either way the other part is the exact difference.
|
|
23
|
+
if (typeof rounding === 'function') {
|
|
24
|
+
const percentAsRatio = ratio(percent);
|
|
25
|
+
const gross = roundWithPolicy(net, ratio(100n * percentAsRatio.den + percentAsRatio.num, 100n * percentAsRatio.den), rounding);
|
|
26
|
+
return { net, tax: subtract(gross, net), gross };
|
|
27
|
+
}
|
|
28
|
+
const tax = multiplyByRatio(net, percentRatio(percent), rounding);
|
|
29
|
+
const gross = add(net, tax);
|
|
30
|
+
return { net, tax, gross };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tax-inclusive: extracts percent% tax contained in a gross amount (VAT extraction).
|
|
34
|
+
* net = gross / (1 + percent/100) rounded; tax = gross - net, so the parts always add up.
|
|
35
|
+
* extractTax(EUR 12, '20', 'halfEven') -> net 10.00, tax 2.00. A rounding policy rounds the net; the
|
|
36
|
+
* tax is on the policy's increment too whenever the gross is.
|
|
37
|
+
*/
|
|
38
|
+
export function extractTax(gross, percent, rounding = DEFAULT_ROUNDING) {
|
|
39
|
+
const percentAsRatio = ratio(percent);
|
|
40
|
+
// 1 / (1 + p/100) = 100 den / (100 den + num)
|
|
41
|
+
const net = multiplyByRatio(gross, ratio(100n * percentAsRatio.den, 100n * percentAsRatio.den + percentAsRatio.num), rounding);
|
|
42
|
+
return { net, tax: subtract(gross, net), gross };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Price after a percent% discount. A rounding mode rounds the discount amount; a rounding policy
|
|
46
|
+
* rounds the discounted price itself, so the price lands on the policy's scale and increment.
|
|
47
|
+
*/
|
|
48
|
+
export function discount(price, percent, rounding = DEFAULT_ROUNDING) {
|
|
49
|
+
if (typeof rounding === 'function') {
|
|
50
|
+
const percentAsRatio = ratio(percent);
|
|
51
|
+
return roundWithPolicy(price, ratio(100n * percentAsRatio.den - percentAsRatio.num, 100n * percentAsRatio.den), rounding);
|
|
52
|
+
}
|
|
53
|
+
return subtract(price, multiplyByRatio(price, percentRatio(percent), rounding));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=tax.js.map
|
package/dist/tax.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tax.js","sourceRoot":"","sources":["../src/tax.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA2B,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,GAAG,EACH,eAAe,EACf,eAAe,EACf,QAAQ,GAGT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,YAAY,GAAG,CAAC,OAAe,EAAS,EAAE;IAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;AAChD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,KAAe,EACf,OAAe,EACf,WAA0B,gBAAgB;IAE1C,OAAO,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AACjE,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,GAAa,EACb,OAAe,EACf,WAA0B,gBAAgB;IAE1C,gGAAgG;IAChG,iGAAiG;IACjG,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,eAAe,CAC3B,GAAG,EACH,KAAK,CAAC,IAAI,GAAG,cAAc,CAAC,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,EAChF,QAAQ,CACT,CAAC;QACF,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IACD,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,KAAe,EACf,OAAe,EACf,WAA0B,gBAAgB;IAE1C,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,8CAA8C;IAC9C,MAAM,GAAG,GAAG,eAAe,CACzB,KAAK,EACL,KAAK,CAAC,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,GAAG,cAAc,CAAC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,EAChF,QAAQ,CACT,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAe,EACf,OAAe,EACf,WAA0B,gBAAgB;IAE1C,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,OAAO,eAAe,CACpB,KAAK,EACL,KAAK,CAAC,IAAI,GAAG,cAAc,CAAC,GAAG,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,EAChF,QAAQ,CACT,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ducatjs/money/testing/arbitraries`: fast-check arbitraries for property tests. They cover what
|
|
3
|
+
* hand-written cases tend to miss: amounts beyond 2^53 (bigint minor units), currencies with
|
|
4
|
+
* unusual exponents (JPY 0, KWD 3, CLF 4) and scales above the currency's exponent. fast-check is
|
|
5
|
+
* an optional peer dependency, needed only for this entry.
|
|
6
|
+
*/
|
|
7
|
+
import fc from 'fast-check';
|
|
8
|
+
import { type Money } from '../money.js';
|
|
9
|
+
/** Options for `arbCurrency`. */
|
|
10
|
+
export interface ArbCurrencyOptions {
|
|
11
|
+
/** Only currencies with one of these exponents (default: the representative mix). */
|
|
12
|
+
readonly exponents?: readonly number[];
|
|
13
|
+
/** Draw from every ISO 4217 code instead of the representative mix. */
|
|
14
|
+
readonly all?: boolean;
|
|
15
|
+
/** More codes to draw from, such as ones registered with `defineCurrency`. */
|
|
16
|
+
readonly extra?: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Currency codes, by default a representative mix of exponents 0, 2, 3 and 4 (JPY, EUR, KWD,
|
|
20
|
+
* CLF...). `{ all: true }` draws from every ISO 4217 code, `extra` adds codes (custom ones from
|
|
21
|
+
* `defineCurrency`), and `exponents` narrows whichever pool that is.
|
|
22
|
+
*/
|
|
23
|
+
export declare function arbCurrency(options?: ArbCurrencyOptions): fc.Arbitrary<string>;
|
|
24
|
+
/** Options for `arbMoney`. */
|
|
25
|
+
export interface ArbMoneyOptions<C extends string = string> {
|
|
26
|
+
/** The currency, or an arbitrary of currencies (default: `arbCurrency()`). */
|
|
27
|
+
readonly currency?: C | fc.Arbitrary<C>;
|
|
28
|
+
/** The smallest amount, in major units (default: none, down to -10^30 minor units). */
|
|
29
|
+
readonly min?: string | number | bigint;
|
|
30
|
+
/** The largest amount, in major units (default: none, up to 10^30 minor units). */
|
|
31
|
+
readonly max?: string | number | bigint;
|
|
32
|
+
/**
|
|
33
|
+
* The scale, or an arbitrary of scales. By default mostly the currency's exponent, sometimes up
|
|
34
|
+
* to three more decimals.
|
|
35
|
+
*/
|
|
36
|
+
readonly scale?: number | fc.Arbitrary<number>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Money values for property tests: `arbMoney()`, `arbMoney({ currency: 'EUR', min: '0', max:
|
|
40
|
+
* '100' })`. With bounds, every value is within them; without, minor units reach ±10^30.
|
|
41
|
+
*/
|
|
42
|
+
export declare function arbMoney<C extends string = string>(options?: ArbMoneyOptions<C>): fc.Arbitrary<Money<C>>;
|
|
43
|
+
//# sourceMappingURL=arbitraries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arbitraries.d.ts","sourceRoot":"","sources":["../../src/testing/arbitraries.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAK3D,iCAAiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,uEAAuE;IACvE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAYlF;AAED,8BAA8B;AAC9B,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACxC,uFAAuF;IACvF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;CAChD;AA0BD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAChD,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAC/B,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CA6CxB"}
|