@ducatjs/money 0.1.0 → 0.2.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.
Files changed (253) hide show
  1. package/NOTICE +73 -0
  2. package/README.md +479 -62
  3. package/data/cash-rounding.json +123 -2
  4. package/data/cldr-cash.json +101 -0
  5. package/data/historic.json +78 -0
  6. package/data/iso4217-list-three.xml +1185 -0
  7. package/dist/adyen-fx.d.ts.map +1 -1
  8. package/dist/adyen-fx.js +22 -4
  9. package/dist/adyen-fx.js.map +1 -1
  10. package/dist/boc.d.ts +31 -0
  11. package/dist/boc.d.ts.map +1 -0
  12. package/dist/boc.js +114 -0
  13. package/dist/boc.js.map +1 -0
  14. package/dist/boe.d.ts +33 -0
  15. package/dist/boe.d.ts.map +1 -0
  16. package/dist/boe.js +114 -0
  17. package/dist/boe.js.map +1 -0
  18. package/dist/cash.d.ts +30 -1
  19. package/dist/cash.d.ts.map +1 -1
  20. package/dist/cash.js +50 -2
  21. package/dist/cash.js.map +1 -1
  22. package/dist/convert.d.ts +10 -9
  23. package/dist/convert.d.ts.map +1 -1
  24. package/dist/convert.js +13 -3
  25. package/dist/convert.js.map +1 -1
  26. package/dist/drizzle/mysql.d.ts +105 -0
  27. package/dist/drizzle/mysql.d.ts.map +1 -0
  28. package/dist/drizzle/mysql.js +60 -0
  29. package/dist/drizzle/mysql.js.map +1 -0
  30. package/dist/drizzle/pg.d.ts +103 -0
  31. package/dist/drizzle/pg.d.ts.map +1 -0
  32. package/dist/drizzle/pg.js +60 -0
  33. package/dist/drizzle/pg.js.map +1 -0
  34. package/dist/drizzle/sqlite.d.ts +102 -0
  35. package/dist/drizzle/sqlite.d.ts.map +1 -0
  36. package/dist/drizzle/sqlite.js +59 -0
  37. package/dist/drizzle/sqlite.js.map +1 -0
  38. package/dist/ecb.d.ts +37 -2
  39. package/dist/ecb.d.ts.map +1 -1
  40. package/dist/ecb.js +148 -10
  41. package/dist/ecb.js.map +1 -1
  42. package/dist/fed.d.ts +35 -0
  43. package/dist/fed.d.ts.map +1 -0
  44. package/dist/fed.js +134 -0
  45. package/dist/fed.js.map +1 -0
  46. package/dist/fetch.d.ts +45 -0
  47. package/dist/fetch.d.ts.map +1 -1
  48. package/dist/fetch.js +167 -24
  49. package/dist/fetch.js.map +1 -1
  50. package/dist/fn.d.ts +8 -1
  51. package/dist/fn.d.ts.map +1 -1
  52. package/dist/fn.js +8 -1
  53. package/dist/fn.js.map +1 -1
  54. package/dist/generated/cash.d.ts +2 -0
  55. package/dist/generated/cash.d.ts.map +1 -1
  56. package/dist/generated/cash.js +101 -0
  57. package/dist/generated/cash.js.map +1 -1
  58. package/dist/generated/historic.d.ts +337 -0
  59. package/dist/generated/historic.d.ts.map +1 -0
  60. package/dist/generated/historic.js +66 -0
  61. package/dist/generated/historic.js.map +1 -0
  62. package/dist/historic.d.ts +40 -0
  63. package/dist/historic.d.ts.map +1 -0
  64. package/dist/historic.js +43 -0
  65. package/dist/historic.js.map +1 -0
  66. package/dist/history.d.ts +96 -0
  67. package/dist/history.d.ts.map +1 -0
  68. package/dist/history.js +213 -0
  69. package/dist/history.js.map +1 -0
  70. package/dist/hmrc.d.ts +28 -0
  71. package/dist/hmrc.d.ts.map +1 -0
  72. package/dist/hmrc.js +108 -0
  73. package/dist/hmrc.js.map +1 -0
  74. package/dist/index.d.ts +1 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/kysely.d.ts +120 -0
  79. package/dist/kysely.d.ts.map +1 -0
  80. package/dist/kysely.js +309 -0
  81. package/dist/kysely.js.map +1 -0
  82. package/dist/money.d.ts +93 -9
  83. package/dist/money.d.ts.map +1 -1
  84. package/dist/money.js +135 -9
  85. package/dist/money.js.map +1 -1
  86. package/dist/parse.d.ts +45 -1
  87. package/dist/parse.d.ts.map +1 -1
  88. package/dist/parse.js +290 -3
  89. package/dist/parse.js.map +1 -1
  90. package/dist/pg.d.ts +100 -0
  91. package/dist/pg.d.ts.map +1 -0
  92. package/dist/pg.js +343 -0
  93. package/dist/pg.js.map +1 -0
  94. package/dist/plugins/adyen.d.ts +1 -1
  95. package/dist/plugins/adyen.d.ts.map +1 -1
  96. package/dist/plugins/adyen.js.map +1 -1
  97. package/dist/plugins/all.d.ts +8 -1
  98. package/dist/plugins/all.d.ts.map +1 -1
  99. package/dist/plugins/all.js +8 -1
  100. package/dist/plugins/all.js.map +1 -1
  101. package/dist/plugins/allocate.d.ts +1 -1
  102. package/dist/plugins/allocate.d.ts.map +1 -1
  103. package/dist/plugins/allocate.js.map +1 -1
  104. package/dist/plugins/braintree.d.ts +1 -1
  105. package/dist/plugins/braintree.d.ts.map +1 -1
  106. package/dist/plugins/braintree.js.map +1 -1
  107. package/dist/plugins/cash.d.ts +1 -1
  108. package/dist/plugins/cash.d.ts.map +1 -1
  109. package/dist/plugins/cash.js.map +1 -1
  110. package/dist/plugins/checkout.d.ts +1 -1
  111. package/dist/plugins/checkout.d.ts.map +1 -1
  112. package/dist/plugins/checkout.js.map +1 -1
  113. package/dist/plugins/convert.d.ts +5 -5
  114. package/dist/plugins/convert.d.ts.map +1 -1
  115. package/dist/plugins/convert.js.map +1 -1
  116. package/dist/plugins/exact.d.ts +1 -1
  117. package/dist/plugins/exact.d.ts.map +1 -1
  118. package/dist/plugins/exact.js.map +1 -1
  119. package/dist/plugins/fixed.d.ts +1 -1
  120. package/dist/plugins/fixed.d.ts.map +1 -1
  121. package/dist/plugins/fixed.js.map +1 -1
  122. package/dist/plugins/format.d.ts +1 -1
  123. package/dist/plugins/format.d.ts.map +1 -1
  124. package/dist/plugins/format.js.map +1 -1
  125. package/dist/plugins/klarna.d.ts +1 -1
  126. package/dist/plugins/klarna.d.ts.map +1 -1
  127. package/dist/plugins/klarna.js.map +1 -1
  128. package/dist/plugins/paypal.d.ts +1 -1
  129. package/dist/plugins/paypal.d.ts.map +1 -1
  130. package/dist/plugins/paypal.js +0 -4
  131. package/dist/plugins/paypal.js.map +1 -1
  132. package/dist/plugins/prisma.d.ts +1 -1
  133. package/dist/plugins/prisma.d.ts.map +1 -1
  134. package/dist/plugins/prisma.js +0 -4
  135. package/dist/plugins/prisma.js.map +1 -1
  136. package/dist/plugins/stripe.d.ts +1 -1
  137. package/dist/plugins/stripe.d.ts.map +1 -1
  138. package/dist/plugins/stripe.js +0 -4
  139. package/dist/plugins/stripe.js.map +1 -1
  140. package/dist/plugins/tax.d.ts +6 -6
  141. package/dist/plugins/tax.d.ts.map +1 -1
  142. package/dist/plugins/tax.js.map +1 -1
  143. package/dist/policy.d.ts +34 -0
  144. package/dist/policy.d.ts.map +1 -0
  145. package/dist/policy.js +90 -0
  146. package/dist/policy.js.map +1 -0
  147. package/dist/prisma.d.ts +25 -14
  148. package/dist/prisma.d.ts.map +1 -1
  149. package/dist/prisma.js +29 -19
  150. package/dist/prisma.js.map +1 -1
  151. package/dist/provider.d.ts +21 -7
  152. package/dist/provider.d.ts.map +1 -1
  153. package/dist/provider.js +51 -11
  154. package/dist/provider.js.map +1 -1
  155. package/dist/rate-text.d.ts +38 -0
  156. package/dist/rate-text.d.ts.map +1 -0
  157. package/dist/rate-text.js +143 -0
  158. package/dist/rate-text.js.map +1 -0
  159. package/dist/rate.d.ts +61 -5
  160. package/dist/rate.d.ts.map +1 -1
  161. package/dist/rate.js +133 -33
  162. package/dist/rate.js.map +1 -1
  163. package/dist/rounding.js +1 -1
  164. package/dist/rounding.js.map +1 -1
  165. package/dist/schema.d.ts +43 -0
  166. package/dist/schema.d.ts.map +1 -0
  167. package/dist/schema.js +77 -0
  168. package/dist/schema.js.map +1 -0
  169. package/dist/sql.d.ts +54 -0
  170. package/dist/sql.d.ts.map +1 -0
  171. package/dist/sql.js +131 -0
  172. package/dist/sql.js.map +1 -0
  173. package/dist/tax.d.ts +13 -9
  174. package/dist/tax.d.ts.map +1 -1
  175. package/dist/tax.js +20 -4
  176. package/dist/tax.js.map +1 -1
  177. package/dist/testing/arbitraries.d.ts +43 -0
  178. package/dist/testing/arbitraries.d.ts.map +1 -0
  179. package/dist/testing/arbitraries.js +98 -0
  180. package/dist/testing/arbitraries.js.map +1 -0
  181. package/dist/testing/index.d.ts +67 -0
  182. package/dist/testing/index.d.ts.map +1 -0
  183. package/dist/testing/index.js +159 -0
  184. package/dist/testing/index.js.map +1 -0
  185. package/dist/testing/jest.d.ts +2 -0
  186. package/dist/testing/jest.d.ts.map +1 -0
  187. package/dist/testing/jest.js +15 -0
  188. package/dist/testing/jest.js.map +1 -0
  189. package/dist/testing/vitest.d.ts +7 -0
  190. package/dist/testing/vitest.d.ts.map +1 -0
  191. package/dist/testing/vitest.js +12 -0
  192. package/dist/testing/vitest.js.map +1 -0
  193. package/dist/valibot.d.ts +33 -0
  194. package/dist/valibot.d.ts.map +1 -0
  195. package/dist/valibot.js +61 -0
  196. package/dist/valibot.js.map +1 -0
  197. package/dist/zod.d.ts +36 -0
  198. package/dist/zod.d.ts.map +1 -0
  199. package/dist/zod.js +58 -0
  200. package/dist/zod.js.map +1 -0
  201. package/package.json +116 -5
  202. package/src/adyen-fx.ts +25 -4
  203. package/src/boc.ts +136 -0
  204. package/src/boe.ts +131 -0
  205. package/src/cash.ts +70 -2
  206. package/src/convert.ts +33 -15
  207. package/src/drizzle/mysql.ts +78 -0
  208. package/src/drizzle/pg.ts +78 -0
  209. package/src/drizzle/sqlite.ts +70 -0
  210. package/src/ecb.ts +179 -13
  211. package/src/fed.ts +146 -0
  212. package/src/fetch.ts +207 -28
  213. package/src/fn.ts +14 -0
  214. package/src/generated/cash.ts +103 -0
  215. package/src/generated/historic.ts +67 -0
  216. package/src/historic.ts +77 -0
  217. package/src/history.ts +333 -0
  218. package/src/hmrc.ts +125 -0
  219. package/src/index.ts +4 -0
  220. package/src/kysely.ts +588 -0
  221. package/src/money.ts +210 -12
  222. package/src/parse.ts +371 -4
  223. package/src/pg.ts +410 -0
  224. package/src/plugins/adyen.ts +3 -2
  225. package/src/plugins/all.ts +10 -0
  226. package/src/plugins/allocate.ts +3 -2
  227. package/src/plugins/braintree.ts +3 -2
  228. package/src/plugins/cash.ts +3 -2
  229. package/src/plugins/checkout.ts +3 -2
  230. package/src/plugins/convert.ts +6 -6
  231. package/src/plugins/exact.ts +3 -2
  232. package/src/plugins/fixed.ts +3 -2
  233. package/src/plugins/format.ts +3 -2
  234. package/src/plugins/klarna.ts +3 -2
  235. package/src/plugins/paypal.ts +3 -2
  236. package/src/plugins/prisma.ts +3 -2
  237. package/src/plugins/stripe.ts +3 -2
  238. package/src/plugins/tax.ts +11 -11
  239. package/src/policy.ts +124 -0
  240. package/src/prisma.ts +91 -10
  241. package/src/provider.ts +81 -16
  242. package/src/rate-text.ts +151 -0
  243. package/src/rate.ts +205 -36
  244. package/src/rounding.ts +1 -1
  245. package/src/schema.ts +119 -0
  246. package/src/sql.ts +178 -0
  247. package/src/tax.ts +40 -9
  248. package/src/testing/arbitraries.ts +134 -0
  249. package/src/testing/index.ts +247 -0
  250. package/src/testing/jest.ts +18 -0
  251. package/src/testing/vitest.ts +18 -0
  252. package/src/valibot.ts +87 -0
  253. package/src/zod.ts +78 -0
package/src/valibot.ts ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `@ducatjs/money/valibot`: Valibot schemas for the JSON form of Money, `{ "amount": "12.34",
3
+ * "currency": "EUR" }`, for API boundaries. Valibot is an optional peer dependency: only this entry
4
+ * imports it.
5
+ */
6
+ import * as valibot from 'valibot';
7
+ import { isMoney, type Money, type MoneyJSON } from './money.js';
8
+ import {
9
+ checkSchemaOptions,
10
+ readMoneyJSON,
11
+ type MoneyFor,
12
+ type MoneyIssue,
13
+ type MoneySchemaOptions,
14
+ } from './schema.js';
15
+
16
+ export type { MoneyFor, MoneySchemaOptions } from './schema.js';
17
+
18
+ const jsonShape = valibot.object({ amount: valibot.string(), currency: valibot.string() });
19
+
20
+ /** The schema type both functions return: the JSON shape, then a transformation. */
21
+ export type MoneySchema<TOutput> = valibot.SchemaWithPipe<
22
+ readonly [typeof jsonShape, valibot.RawTransformAction<MoneyJSON, TOutput>]
23
+ >;
24
+
25
+ /** A Valibot issue path pointing at the field that is wrong. */
26
+ function pathTo(json: MoneyJSON, issue: MoneyIssue): [valibot.ObjectPathItem] {
27
+ return [
28
+ {
29
+ type: 'object',
30
+ origin: 'value',
31
+ input: json as unknown as Record<string, unknown>,
32
+ key: issue.field,
33
+ value: json[issue.field],
34
+ },
35
+ ];
36
+ }
37
+
38
+ /**
39
+ * Parses `{ amount, currency }` into Money, accepting exactly what the Zod entry accepts (see its
40
+ * `moneySchema`): an exact decimal string with no more decimals than the scale and at most
41
+ * `maxDigits` digits, padded to the scale, and a listed or known currency. Problems are Valibot
42
+ * issues on `amount` or `currency`; other keys are dropped. Bad options throw when the schema is
43
+ * built. Valibot has no codecs, so encode with `money.toJSON()` (or `JSON.stringify`), which this
44
+ * schema reads back.
45
+ *
46
+ * const Order = valibot.object({ total: moneySchema({ currency: 'EUR' }) })
47
+ * v.parse(Order, { total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
48
+ */
49
+ export function moneySchema<C extends string = string>(
50
+ options?: MoneySchemaOptions<C>,
51
+ ): MoneySchema<MoneyFor<C>> {
52
+ checkSchemaOptions(options);
53
+ return valibot.pipe(
54
+ jsonShape,
55
+ valibot.rawTransform<MoneyJSON, MoneyFor<C>>(({ dataset, addIssue, NEVER }) => {
56
+ const json = dataset.value;
57
+ const result = readMoneyJSON(json, options);
58
+ if (isMoney(result)) {
59
+ return result as Money as MoneyFor<C>;
60
+ }
61
+ addIssue({ message: result.message, path: pathTo(json, result) });
62
+ return NEVER;
63
+ }),
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Like `moneySchema`, but the output stays the JSON object: it checks that the input would parse,
69
+ * for code that passes the JSON on rather than computing with it.
70
+ */
71
+ export function moneyJSONSchema<C extends string = string>(
72
+ options?: MoneySchemaOptions<C>,
73
+ ): MoneySchema<MoneyJSON<C>> {
74
+ checkSchemaOptions(options);
75
+ return valibot.pipe(
76
+ jsonShape,
77
+ valibot.rawTransform<MoneyJSON, MoneyJSON<C>>(({ dataset, addIssue, NEVER }) => {
78
+ const json = dataset.value;
79
+ const result = readMoneyJSON(json, options);
80
+ if (isMoney(result)) {
81
+ return json as MoneyJSON<C>;
82
+ }
83
+ addIssue({ message: result.message, path: pathTo(json, result) });
84
+ return NEVER;
85
+ }),
86
+ );
87
+ }
package/src/zod.ts ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `@ducatjs/money/zod`: Zod schemas for the JSON form of Money, `{ "amount": "12.34", "currency":
3
+ * "EUR" }`, for API boundaries. Zod is an optional peer dependency: only this entry imports it.
4
+ */
5
+ import { z } from 'zod';
6
+ import { isMoney, type Money, type MoneyJSON } from './money.js';
7
+ import {
8
+ checkSchemaOptions,
9
+ readMoneyJSON,
10
+ type MoneyFor,
11
+ type MoneySchemaOptions,
12
+ } from './schema.js';
13
+
14
+ export type { MoneyFor, MoneySchemaOptions } from './schema.js';
15
+
16
+ const jsonShape = z.object({ amount: z.string(), currency: z.string() });
17
+
18
+ /** The schema `moneySchema` returns: a Zod codec between the JSON form and Money. */
19
+ export type MoneyCodec<C extends string> = z.ZodCodec<typeof jsonShape, z.ZodCustom<MoneyFor<C>>>;
20
+
21
+ /**
22
+ * Parses `{ amount, currency }` into Money, and encodes Money back to that JSON form. It is a Zod
23
+ * codec, so `schema.parse(json)` (or `z.decode`) gives Money and `z.encode(schema, money)` gives
24
+ * `{ amount, currency }`, written at the amount's own scale.
25
+ *
26
+ * The amount must be an exact decimal string with no more decimals than the scale (the
27
+ * currency's exponent unless `scale` is given; `rounding` allows more), and at most `maxDigits`
28
+ * digits. The currency must be one of `currency`, or any known code. Shorter amounts are padded to
29
+ * the scale ("1.5" EUR gives 1.50 EUR). Problems are Zod issues on `amount` or `currency`; keys
30
+ * other than those two are dropped. Bad options throw when the schema is built.
31
+ *
32
+ * const Order = z.object({ total: moneySchema({ currency: 'EUR' }) })
33
+ * Order.parse({ total: { amount: '12.34', currency: 'EUR' } }).total // Money<'EUR'>
34
+ */
35
+ export function moneySchema<C extends string = string>(
36
+ options?: MoneySchemaOptions<C>,
37
+ ): MoneyCodec<C> {
38
+ checkSchemaOptions(options);
39
+ return z.codec(
40
+ jsonShape,
41
+ z.custom<MoneyFor<C>>((value) => isMoney(value)),
42
+ {
43
+ decode: (json, payload) => {
44
+ const result = readMoneyJSON(json, options);
45
+ if (isMoney(result)) {
46
+ return result as Money as MoneyFor<C>;
47
+ }
48
+ payload.issues.push({
49
+ code: 'custom',
50
+ message: result.message,
51
+ input: json,
52
+ path: [result.field],
53
+ });
54
+ return z.NEVER;
55
+ },
56
+ encode: (value) => (value as Money).toJSON(),
57
+ },
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Like `moneySchema`, but the output stays the JSON object (with only `amount` and `currency`): it
63
+ * checks that the input would parse, for code that passes the JSON on rather than computing with
64
+ * it.
65
+ */
66
+ export function moneyJSONSchema<C extends string = string>(
67
+ options?: MoneySchemaOptions<C>,
68
+ ): z.ZodType<MoneyJSON<C>, MoneyJSON> {
69
+ checkSchemaOptions(options);
70
+ return jsonShape.transform((json, context) => {
71
+ const result = readMoneyJSON(json, options);
72
+ if (isMoney(result)) {
73
+ return json as MoneyJSON<C>;
74
+ }
75
+ context.addIssue({ code: 'custom', message: result.message, path: [result.field] });
76
+ return z.NEVER;
77
+ });
78
+ }