@ducatjs/money 0.1.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.
Files changed (201) hide show
  1. package/README.md +479 -62
  2. package/data/cash-rounding.json +123 -2
  3. package/data/cldr-cash.json +101 -0
  4. package/data/historic.json +78 -0
  5. package/data/iso4217-list-three.xml +1185 -0
  6. package/dist/adyen-fx.d.ts.map +1 -1
  7. package/dist/adyen-fx.js +22 -4
  8. package/dist/adyen-fx.js.map +1 -1
  9. package/dist/boc.d.ts +31 -0
  10. package/dist/boc.d.ts.map +1 -0
  11. package/dist/boc.js +114 -0
  12. package/dist/boc.js.map +1 -0
  13. package/dist/boe.d.ts +33 -0
  14. package/dist/boe.d.ts.map +1 -0
  15. package/dist/boe.js +114 -0
  16. package/dist/boe.js.map +1 -0
  17. package/dist/cash.d.ts +30 -1
  18. package/dist/cash.d.ts.map +1 -1
  19. package/dist/cash.js +50 -2
  20. package/dist/cash.js.map +1 -1
  21. package/dist/convert.d.ts +10 -9
  22. package/dist/convert.d.ts.map +1 -1
  23. package/dist/convert.js +13 -3
  24. package/dist/convert.js.map +1 -1
  25. package/dist/drizzle/mysql.d.ts +105 -0
  26. package/dist/drizzle/mysql.d.ts.map +1 -0
  27. package/dist/drizzle/mysql.js +60 -0
  28. package/dist/drizzle/mysql.js.map +1 -0
  29. package/dist/drizzle/pg.d.ts +103 -0
  30. package/dist/drizzle/pg.d.ts.map +1 -0
  31. package/dist/drizzle/pg.js +60 -0
  32. package/dist/drizzle/pg.js.map +1 -0
  33. package/dist/drizzle/sqlite.d.ts +102 -0
  34. package/dist/drizzle/sqlite.d.ts.map +1 -0
  35. package/dist/drizzle/sqlite.js +59 -0
  36. package/dist/drizzle/sqlite.js.map +1 -0
  37. package/dist/ecb.d.ts +37 -2
  38. package/dist/ecb.d.ts.map +1 -1
  39. package/dist/ecb.js +148 -10
  40. package/dist/ecb.js.map +1 -1
  41. package/dist/fed.d.ts +35 -0
  42. package/dist/fed.d.ts.map +1 -0
  43. package/dist/fed.js +134 -0
  44. package/dist/fed.js.map +1 -0
  45. package/dist/fetch.d.ts +45 -0
  46. package/dist/fetch.d.ts.map +1 -1
  47. package/dist/fetch.js +167 -24
  48. package/dist/fetch.js.map +1 -1
  49. package/dist/fn.d.ts +8 -1
  50. package/dist/fn.d.ts.map +1 -1
  51. package/dist/fn.js +8 -1
  52. package/dist/fn.js.map +1 -1
  53. package/dist/generated/cash.d.ts +2 -0
  54. package/dist/generated/cash.d.ts.map +1 -1
  55. package/dist/generated/cash.js +101 -0
  56. package/dist/generated/cash.js.map +1 -1
  57. package/dist/generated/historic.d.ts +337 -0
  58. package/dist/generated/historic.d.ts.map +1 -0
  59. package/dist/generated/historic.js +66 -0
  60. package/dist/generated/historic.js.map +1 -0
  61. package/dist/historic.d.ts +40 -0
  62. package/dist/historic.d.ts.map +1 -0
  63. package/dist/historic.js +43 -0
  64. package/dist/historic.js.map +1 -0
  65. package/dist/history.d.ts +96 -0
  66. package/dist/history.d.ts.map +1 -0
  67. package/dist/history.js +213 -0
  68. package/dist/history.js.map +1 -0
  69. package/dist/hmrc.d.ts +28 -0
  70. package/dist/hmrc.d.ts.map +1 -0
  71. package/dist/hmrc.js +108 -0
  72. package/dist/hmrc.js.map +1 -0
  73. package/dist/index.d.ts +1 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +1 -1
  76. package/dist/index.js.map +1 -1
  77. package/dist/kysely.d.ts +120 -0
  78. package/dist/kysely.d.ts.map +1 -0
  79. package/dist/kysely.js +309 -0
  80. package/dist/kysely.js.map +1 -0
  81. package/dist/money.d.ts +93 -9
  82. package/dist/money.d.ts.map +1 -1
  83. package/dist/money.js +135 -9
  84. package/dist/money.js.map +1 -1
  85. package/dist/parse.d.ts +45 -1
  86. package/dist/parse.d.ts.map +1 -1
  87. package/dist/parse.js +290 -3
  88. package/dist/parse.js.map +1 -1
  89. package/dist/pg.d.ts +100 -0
  90. package/dist/pg.d.ts.map +1 -0
  91. package/dist/pg.js +343 -0
  92. package/dist/pg.js.map +1 -0
  93. package/dist/plugins/all.d.ts +8 -1
  94. package/dist/plugins/all.d.ts.map +1 -1
  95. package/dist/plugins/all.js +8 -1
  96. package/dist/plugins/all.js.map +1 -1
  97. package/dist/plugins/convert.d.ts +3 -4
  98. package/dist/plugins/convert.d.ts.map +1 -1
  99. package/dist/plugins/convert.js.map +1 -1
  100. package/dist/plugins/tax.d.ts +4 -5
  101. package/dist/plugins/tax.d.ts.map +1 -1
  102. package/dist/plugins/tax.js.map +1 -1
  103. package/dist/policy.d.ts +34 -0
  104. package/dist/policy.d.ts.map +1 -0
  105. package/dist/policy.js +90 -0
  106. package/dist/policy.js.map +1 -0
  107. package/dist/prisma.d.ts +25 -14
  108. package/dist/prisma.d.ts.map +1 -1
  109. package/dist/prisma.js +29 -19
  110. package/dist/prisma.js.map +1 -1
  111. package/dist/provider.d.ts +21 -7
  112. package/dist/provider.d.ts.map +1 -1
  113. package/dist/provider.js +51 -11
  114. package/dist/provider.js.map +1 -1
  115. package/dist/rate-text.d.ts +38 -0
  116. package/dist/rate-text.d.ts.map +1 -0
  117. package/dist/rate-text.js +143 -0
  118. package/dist/rate-text.js.map +1 -0
  119. package/dist/rate.d.ts +61 -5
  120. package/dist/rate.d.ts.map +1 -1
  121. package/dist/rate.js +133 -33
  122. package/dist/rate.js.map +1 -1
  123. package/dist/rounding.js +1 -1
  124. package/dist/rounding.js.map +1 -1
  125. package/dist/schema.d.ts +43 -0
  126. package/dist/schema.d.ts.map +1 -0
  127. package/dist/schema.js +77 -0
  128. package/dist/schema.js.map +1 -0
  129. package/dist/sql.d.ts +54 -0
  130. package/dist/sql.d.ts.map +1 -0
  131. package/dist/sql.js +131 -0
  132. package/dist/sql.js.map +1 -0
  133. package/dist/tax.d.ts +13 -9
  134. package/dist/tax.d.ts.map +1 -1
  135. package/dist/tax.js +20 -4
  136. package/dist/tax.js.map +1 -1
  137. package/dist/testing/arbitraries.d.ts +43 -0
  138. package/dist/testing/arbitraries.d.ts.map +1 -0
  139. package/dist/testing/arbitraries.js +98 -0
  140. package/dist/testing/arbitraries.js.map +1 -0
  141. package/dist/testing/index.d.ts +67 -0
  142. package/dist/testing/index.d.ts.map +1 -0
  143. package/dist/testing/index.js +159 -0
  144. package/dist/testing/index.js.map +1 -0
  145. package/dist/testing/jest.d.ts +2 -0
  146. package/dist/testing/jest.d.ts.map +1 -0
  147. package/dist/testing/jest.js +15 -0
  148. package/dist/testing/jest.js.map +1 -0
  149. package/dist/testing/vitest.d.ts +7 -0
  150. package/dist/testing/vitest.d.ts.map +1 -0
  151. package/dist/testing/vitest.js +12 -0
  152. package/dist/testing/vitest.js.map +1 -0
  153. package/dist/valibot.d.ts +33 -0
  154. package/dist/valibot.d.ts.map +1 -0
  155. package/dist/valibot.js +61 -0
  156. package/dist/valibot.js.map +1 -0
  157. package/dist/zod.d.ts +36 -0
  158. package/dist/zod.d.ts.map +1 -0
  159. package/dist/zod.js +58 -0
  160. package/dist/zod.js.map +1 -0
  161. package/package.json +116 -5
  162. package/src/adyen-fx.ts +25 -4
  163. package/src/boc.ts +136 -0
  164. package/src/boe.ts +131 -0
  165. package/src/cash.ts +70 -2
  166. package/src/convert.ts +33 -15
  167. package/src/drizzle/mysql.ts +78 -0
  168. package/src/drizzle/pg.ts +78 -0
  169. package/src/drizzle/sqlite.ts +70 -0
  170. package/src/ecb.ts +179 -13
  171. package/src/fed.ts +146 -0
  172. package/src/fetch.ts +207 -28
  173. package/src/fn.ts +14 -0
  174. package/src/generated/cash.ts +103 -0
  175. package/src/generated/historic.ts +67 -0
  176. package/src/historic.ts +77 -0
  177. package/src/history.ts +333 -0
  178. package/src/hmrc.ts +125 -0
  179. package/src/index.ts +4 -0
  180. package/src/kysely.ts +588 -0
  181. package/src/money.ts +210 -12
  182. package/src/parse.ts +371 -4
  183. package/src/pg.ts +410 -0
  184. package/src/plugins/all.ts +10 -0
  185. package/src/plugins/convert.ts +4 -5
  186. package/src/plugins/tax.ts +9 -10
  187. package/src/policy.ts +124 -0
  188. package/src/prisma.ts +91 -10
  189. package/src/provider.ts +81 -16
  190. package/src/rate-text.ts +151 -0
  191. package/src/rate.ts +205 -36
  192. package/src/rounding.ts +1 -1
  193. package/src/schema.ts +119 -0
  194. package/src/sql.ts +178 -0
  195. package/src/tax.ts +40 -9
  196. package/src/testing/arbitraries.ts +134 -0
  197. package/src/testing/index.ts +247 -0
  198. package/src/testing/jest.ts +18 -0
  199. package/src/testing/vitest.ts +18 -0
  200. package/src/valibot.ts +87 -0
  201. package/src/zod.ts +78 -0
package/dist/prisma.d.ts CHANGED
@@ -1,13 +1,3 @@
1
- /**
2
- * Prisma / SQL interop with no dependency on @prisma/client (works with any Decimal class that has
3
- * toFixed(): Prisma.Decimal, decimal.js, big.js).
4
- *
5
- * Storage options (see README "Databases"):
6
- * 1. two columns: amount_minor BIGINT + currency CHAR(3)
7
- * -> minorMoneyField / toMinorColumns
8
- * 2. a DECIMAL/NUMERIC column (+ a currency column or constant)
9
- * -> decimalMoneyField / toDecimalValue
10
- */
11
1
  import { type CurrencyInput, type Money, type MoneyOptions } from './money.js';
12
2
  /** Structural type of Prisma.Decimal / decimal.js / big.js values. */
13
3
  export interface DecimalLike {
@@ -23,19 +13,38 @@ export declare function toDecimalValue<D>(money: Money, Decimal: new (value: str
23
13
  type Row<A extends string, V> = {
24
14
  [P in A]: V;
25
15
  };
16
+ /** Options for `minorMoneyField` and `toMinorColumns`: a column that records each amount's scale. */
17
+ export interface ScaleColumnOption<S extends string> {
18
+ /**
19
+ * The integer column holding the number of decimals the minor units are counted in (2 for
20
+ * cents). With it, any scale round-trips, and stored amounts keep their meaning even if a
21
+ * currency's exponent changes.
22
+ */
23
+ readonly scale: S;
24
+ }
26
25
  /**
27
26
  * A Prisma result-extension field that exposes a Money built from `amount_minor` + `currency`
28
- * columns:
27
+ * columns, and optionally a scale column:
29
28
  *
30
29
  * const db = new PrismaClient().$extends({
31
30
  * result: { order: { total: minorMoneyField('totalMinor', 'currency') } },
32
31
  * });
33
32
  * (await db.order.findFirstOrThrow()).total // Money
33
+ *
34
+ * Without a scale column the minor units are read at the currency's current exponent.
34
35
  */
35
36
  export declare function minorMoneyField<const A extends string, const K extends string>(amount: A, currency: K): {
36
- needs: { [P in A | K]: true; };
37
+ needs: {
38
+ [P in A | K]: true;
39
+ };
37
40
  compute: (row: Row<A, bigint | number> & Row<K, string>) => Money;
38
41
  };
42
+ export declare function minorMoneyField<const A extends string, const K extends string, const S extends string>(amount: A, currency: K, options: ScaleColumnOption<S>): {
43
+ needs: {
44
+ [P in A | K | S]: true;
45
+ };
46
+ compute: (row: Row<A, bigint | number> & Row<K, string> & Row<S, bigint | number>) => Money;
47
+ };
39
48
  /**
40
49
  * A Prisma result-extension field for a Decimal column, with the currency taken from another column
41
50
  * (`{ currencyField: 'currency' }`) or fixed (`{ currency: 'EUR' }`).
@@ -58,9 +67,11 @@ export declare function decimalMoneyField<const A extends string, const C extend
58
67
  };
59
68
  /**
60
69
  * Column values for writes: `data: { ...toMinorColumns(total, 'totalMinor', 'currency') }`.
61
- * Minor units are a bigint (Prisma BigInt). Throws if the value has a non-standard scale, because
62
- * the column cannot record it.
70
+ * Minor units are a bigint (Prisma BigInt). Without a scale column, throws if the value has a
71
+ * non-standard scale, because the columns cannot record it. With `{ scale: 'amountScale' }`, any
72
+ * scale is stored, next to the minor units it counts.
63
73
  */
64
74
  export declare function toMinorColumns<const A extends string, const K extends string>(money: Money, amount: A, currency: K): Row<A, bigint> & Row<K, string>;
75
+ export declare function toMinorColumns<const A extends string, const K extends string, const S extends string>(money: Money, amount: A, currency: K, options: ScaleColumnOption<S>): Row<A, bigint> & Row<K, string> & Row<S, number>;
65
76
  export {};
66
77
  //# sourceMappingURL=prisma.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,OAAO,IAAI,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,aAAa,EACjD,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,QAAQ,EAAE,CAAC,EACX,OAAO,CAAC,EAAE,YAAY,GACrB,KAAK,CAAC,CAAC,CAAC,CAEV;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAEpF;AAED,KAAK,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI;KAAG,CAAC,IAAI,CAAC,GAAG,CAAC;CAAE,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,EAC5E,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,CAAC;WAGsC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAE;mBACtD,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAG,KAAK;EAGlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,EAC9E,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE;IAAE,aAAa,EAAE,CAAC,CAAA;CAAE,GAC7B;IAAE,KAAK,EAAE;SAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;KAAE,CAAC;IAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,KAAK,CAAA;CAAE,CAAC;AACpG,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,aAAa,EACrF,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE;IAAE,QAAQ,EAAE,CAAC,CAAA;CAAE,GACxB;IAAE,KAAK,EAAE;SAAG,CAAC,IAAI,CAAC,GAAG,IAAI;KAAE,CAAC;IAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC;AAoBlF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,EAC3E,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,CAAC,GACV,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAGjC"}
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"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"}
package/dist/prisma.js CHANGED
@@ -8,6 +8,7 @@
8
8
  * 2. a DECIMAL/NUMERIC column (+ a currency column or constant)
9
9
  * -> decimalMoneyField / toDecimalValue
10
10
  */
11
+ import { MAX_DECIMAL_SCALE } from './decimal.js';
11
12
  import { fromMinor, money, toDecimal, toMinor, } from './money.js';
12
13
  /**
13
14
  * Money from a Decimal (or decimal string) column. Exact; throws if it has more decimals than the
@@ -20,19 +21,30 @@ export function fromDecimal(value, currency, options) {
20
21
  export function toDecimalValue(money, Decimal) {
21
22
  return new Decimal(toDecimal(money));
22
23
  }
23
- /**
24
- * A Prisma result-extension field that exposes a Money built from `amount_minor` + `currency`
25
- * columns:
26
- *
27
- * const db = new PrismaClient().$extends({
28
- * result: { order: { total: minorMoneyField('totalMinor', 'currency') } },
29
- * });
30
- * (await db.order.findFirstOrThrow()).total // Money
31
- */
32
- export function minorMoneyField(amount, currency) {
24
+ /** A scale read from a row: a safe, non-negative integer (a SMALLINT or INT column). */
25
+ function readScale(value, column) {
26
+ const scale = typeof value === 'bigint' ? Number(value) : value;
27
+ // capped like parsed decimals: a corrupt row must not make toDecimal build a huge power of ten
28
+ const isValid = typeof scale === 'number' &&
29
+ Number.isInteger(scale) &&
30
+ scale >= 0 &&
31
+ scale <= MAX_DECIMAL_SCALE;
32
+ if (!isValid) {
33
+ throw new RangeError(`Expected an integer scale from 0 to ${MAX_DECIMAL_SCALE} in "${column}", got ${String(value)}`);
34
+ }
35
+ return scale;
36
+ }
37
+ export function minorMoneyField(amount, currency, options) {
38
+ if (options === undefined) {
39
+ return {
40
+ needs: { [amount]: true, [currency]: true },
41
+ compute: (row) => fromMinor(row[amount], row[currency]),
42
+ };
43
+ }
44
+ const scaleColumn = options.scale;
33
45
  return {
34
- needs: { [amount]: true, [currency]: true },
35
- compute: (row) => fromMinor(row[amount], row[currency]),
46
+ needs: { [amount]: true, [currency]: true, [scaleColumn]: true },
47
+ compute: (row) => fromMinor(row[amount], row[currency], readScale(row[scaleColumn], scaleColumn)),
36
48
  };
37
49
  }
38
50
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -48,13 +60,11 @@ export function decimalMoneyField(amount, currencySource) {
48
60
  compute: (row) => fromDecimal(row[amount], currencySource.currency),
49
61
  };
50
62
  }
51
- /**
52
- * Column values for writes: `data: { ...toMinorColumns(total, 'totalMinor', 'currency') }`.
53
- * Minor units are a bigint (Prisma BigInt). Throws if the value has a non-standard scale, because
54
- * the column cannot record it.
55
- */
56
- export function toMinorColumns(money, amount, currency) {
57
- return { [amount]: toMinorAtIsoScale(money), [currency]: money.currency };
63
+ export function toMinorColumns(money, amount, currency, options) {
64
+ if (options === undefined) {
65
+ return { [amount]: toMinorAtIsoScale(money), [currency]: money.currency };
66
+ }
67
+ return { [amount]: toMinor(money), [currency]: money.currency, [options.scale]: money.scale };
58
68
  }
59
69
  function toMinorAtIsoScale(money) {
60
70
  const iso = fromMinor(0, money.currency).scale;
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.js","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,SAAS,EACT,KAAK,EACL,SAAS,EACT,OAAO,GAIR,MAAM,YAAY,CAAC;AAOpB;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAA2B,EAC3B,QAAW,EACX,OAAsB;IAEtB,OAAO,KAAK,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACvF,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAI,KAAY,EAAE,OAAiC;IAC/E,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACvC,CAAC;AAID;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAS,EACT,QAAW;IAEX,OAAO;QACL,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAA4B;QACrE,OAAO,EAAE,CAAC,GAA6C,EAAS,EAAE,CAChE,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;KACxC,CAAC;AACJ,CAAC;AAcD,8DAA8D;AAC9D,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,cAAgE;IAEhE,IAAI,eAAe,IAAI,cAAc,EAAE,CAAC;QACtC,OAAO;YACL,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE;YAC/D,OAAO,EAAE,CAAC,GAA4B,EAAE,EAAE,CACxC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAgB,EAAE,GAAG,CAAC,cAAc,CAAC,aAAa,CAAW,CAAC;SACvF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE;QACzB,OAAO,EAAE,CAAC,GAA4B,EAAE,EAAE,CACxC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAgB,EAAE,cAAc,CAAC,QAAQ,CAAC;KACnE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAY,EACZ,MAAS,EACT,QAAW;IAEX,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,QAAQ,EACvD,CAAC;AACnB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAY;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;IAC/C,IAAI,KAAK,CAAC,KAAK,KAAK,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAClB,GAAG,KAAK,cAAc,KAAK,CAAC,KAAK,mBAAmB,GAAG,sCAAsC,CAC9F,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"prisma.js","sourceRoot":"","sources":["../src/prisma.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,12 @@ export interface RateTable extends RateProvider {
16
16
  readonly base?: string;
17
17
  /** The table's date, when it has one. */
18
18
  readonly asOf?: string;
19
+ /** When the table was published, when that is known. */
20
+ readonly availableAt?: string;
21
+ /** The last day (or instant) the table applies to, for a table valid for a period. */
22
+ readonly validUntil?: string;
23
+ /** Currencies the source listed without a value (holidays, `ND`, `N/A`). */
24
+ readonly missing?: readonly string[];
19
25
  }
20
26
  /** Thrown when no provider has a rate for the pair. */
21
27
  export declare class RateUnavailableError extends Error {
@@ -28,18 +34,24 @@ export declare class RateUnavailableError extends Error {
28
34
  export declare function rateOf<From extends string, To extends string>(provider: RateProvider, from: From, to: To, query?: RateQuery): Rate<From, To>;
29
35
  /** 1:1 for a currency to itself; nothing otherwise. */
30
36
  export declare function identity(): RateProvider;
31
- /** A one-base table: `rates.USD` is the number of USD per 1 `base`. */
32
- export interface RateTableSpec extends RateInfo {
37
+ /**
38
+ * A one-base table: `rates.USD` is the number of USD per 1 `base` (or a base → USD Rate), or null
39
+ * when the source has no value for the day. For rates published the other way round or per 100
40
+ * units, see `quotedTable` in `@ducatjs/money/convert/history`.
41
+ */
42
+ export interface RateTableSpec extends Omit<RateInfo, 'quote'> {
33
43
  readonly base: string;
34
- readonly rates: Readonly<Record<string, Factor>>;
44
+ readonly rates: Readonly<Record<string, Factor | Rate | null>>;
35
45
  }
36
46
  /**
37
47
  * A fixed table of rates: one base currency against many (ECB style), or a list of Rates. Only the
38
48
  * pairs given are answered; wrap it in `reversed()` or `via()` for the others.
39
49
  *
40
- * Lookups are by whole UTC day: a query for a day before a rate's asOf gets nothing, and a query at
41
- * any time on the rate's own day gets the rate, even before its publication time (the ECB publishes
42
- * at about 15:00 UTC). If that matters, query with the previous day until the table is published.
50
+ * A query with an `asOf` gets nothing from a rate that doesn't apply then: one dated after it, one
51
+ * published (`availableAt`) after it, or one whose `validUntil` has passed. Days are UTC days, and
52
+ * a date query covers the whole day: without an `availableAt`, a query at any time on the rate's
53
+ * own day gets the rate, even before the source published it (the ECB publishes at about 15:00
54
+ * UTC). Give `availableAt` to rule that out.
43
55
  *
44
56
  * const ecb = rateTable({ base: 'EUR', source: 'ECB', asOf: '2026-11-06', rates: { USD: '1.1165' } });
45
57
  */
@@ -73,7 +85,9 @@ export interface Snapshots {
73
85
  * undefined when there is none. Days are UTC days. Loaded tables are cached by day. Misses and
74
86
  * failures are not cached, so a table that isn't published yet is tried again next time. A loader
75
87
  * that throws fails the lookup rather than falling back to an older day, so an outage doesn't
76
- * silently become a stale rate. The rates carry the day they're from.
88
+ * silently become a stale rate. The rates carry the day they're from. A table with an
89
+ * `availableAt` after an instant asked for is passed over, so a lookup at 09:00 on a publication
90
+ * day gets the day before.
77
91
  *
78
92
  * const history = snapshots(async (day) => parseEcbXml(await readFile(`ecb/${day}.xml`, 'utf8'))[0]);
79
93
  * const fx = await history.at('2026-11-08'); // a Sunday: Friday 2026-11-06's table
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAqC,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAIxF,iCAAiC;AACjC,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EACzC,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,EAAE,EACN,KAAK,CAAC,EAAE,SAAS,GAChB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC;CAC/B;AAED,kGAAkG;AAClG,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uDAAuD;AACvD,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEtB,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;CAe3D;AAOD,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EAC3D,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,EAAE,EACN,KAAK,CAAC,EAAE,SAAS,GAChB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAehB;AAED,uDAAuD;AACvD,wBAAgB,QAAQ,IAAI,YAAY,CAUvC;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,IAAI,EAAE,GAAG,SAAS,CAqC1E;AAMD,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,GAAG,SAAS,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,CAYzE;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAM7D;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,YAAY,CA6BtE;AAED,+BAA+B;AAC/B,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACxB,gGAAgG;IAChG,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAChD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,EACxD,OAAO,CAAC,EAAE,eAAe,GACxB,SAAS,CA8DX;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAQhG"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAML,KAAK,IAAI,EACT,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAInB,iCAAiC;AACjC,MAAM,WAAW,SAAS;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EACzC,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,EAAE,EACN,KAAK,CAAC,EAAE,SAAS,GAChB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC;CAC/B;AAED,kGAAkG;AAClG,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,uDAAuD;AACvD,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEtB,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;CAe3D;AAOD,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EAC3D,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,EAAE,EACN,KAAK,CAAC,EAAE,SAAS,GAChB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAehB;AAED,uDAAuD;AACvD,wBAAgB,QAAQ,IAAI,YAAY,CAUvC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;CAChE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,IAAI,EAAE,GAAG,SAAS,CAgE1E;AAoBD,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,GAAG,SAAS,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,CAYzE;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAM7D;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,YAAY,CA6BtE;AAED,+BAA+B;AAC/B,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACxB,gGAAgG;IAChG,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAChD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,EACxD,OAAO,CAAC,EAAE,eAAe,GACxB,SAAS,CAgEX;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAQhG"}
package/dist/provider.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CurrencyMismatchError } from './money.js';
2
- import { exchangeRate, isRate, toIsoString } from './rate.js';
2
+ import { exchangeRate, hasEnded, hasStarted, isRate, toIsoString, } from './rate.js';
3
3
  const DAY_MS = 86_400_000;
4
4
  /** Thrown when no provider has a rate for the pair. */
5
5
  export class RateUnavailableError extends Error {
@@ -58,9 +58,11 @@ export function identity() {
58
58
  * A fixed table of rates: one base currency against many (ECB style), or a list of Rates. Only the
59
59
  * pairs given are answered; wrap it in `reversed()` or `via()` for the others.
60
60
  *
61
- * Lookups are by whole UTC day: a query for a day before a rate's asOf gets nothing, and a query at
62
- * any time on the rate's own day gets the rate, even before its publication time (the ECB publishes
63
- * at about 15:00 UTC). If that matters, query with the previous day until the table is published.
61
+ * A query with an `asOf` gets nothing from a rate that doesn't apply then: one dated after it, one
62
+ * published (`availableAt`) after it, or one whose `validUntil` has passed. Days are UTC days, and
63
+ * a date query covers the whole day: without an `availableAt`, a query at any time on the rate's
64
+ * own day gets the rate, even before the source published it (the ECB publishes at about 15:00
65
+ * UTC). Give `availableAt` to rule that out.
64
66
  *
65
67
  * const ecb = rateTable({ base: 'EUR', source: 'ECB', asOf: '2026-11-06', rates: { USD: '1.1165' } });
66
68
  */
@@ -71,11 +73,36 @@ export function rateTable(spec) {
71
73
  rates = [...spec];
72
74
  }
73
75
  else {
74
- rates = Object.entries(spec.rates).map(([to, rate]) => exchangeRate(spec.base, to, rate, spec));
76
+ rates = [];
77
+ const missing = [];
78
+ for (const [currency, entry] of Object.entries(spec.rates)) {
79
+ if (entry === null) {
80
+ missing.push(currency);
81
+ }
82
+ else if (isRate(entry)) {
83
+ // A ready-made Rate is looked up under its own pair, so it must be the one its key says.
84
+ if (entry.from !== spec.base || entry.to !== currency) {
85
+ throw new CurrencyMismatchError(`${spec.base}→${currency}`, `${entry.from}→${entry.to}`);
86
+ }
87
+ rates.push(entry);
88
+ }
89
+ else {
90
+ rates.push(exchangeRate(spec.base, currency, entry, spec));
91
+ }
92
+ }
75
93
  header.base = spec.base;
76
94
  if (spec.asOf !== undefined) {
77
95
  header.asOf = toIsoString(spec.asOf);
78
96
  }
97
+ if (spec.availableAt !== undefined) {
98
+ header.availableAt = toIsoString(spec.availableAt);
99
+ }
100
+ if (spec.validUntil !== undefined) {
101
+ header.validUntil = toIsoString(spec.validUntil);
102
+ }
103
+ if (missing.length > 0) {
104
+ header.missing = missing;
105
+ }
79
106
  }
80
107
  const byPair = new Map();
81
108
  for (const rate of rates) {
@@ -89,10 +116,9 @@ export function rateTable(spec) {
89
116
  if (rate === undefined) {
90
117
  return undefined;
91
118
  }
92
- const askedBeforeRateExisted = query?.asOf !== undefined &&
93
- rate.asOf !== undefined &&
94
- dayOf(query.asOf) < dayOf(rate.asOf);
95
- if (askedBeforeRateExisted) {
119
+ // The table's own dates count too: a ready-made Rate entry doesn't carry them.
120
+ const asOf = query?.asOf;
121
+ if (asOf !== undefined && (!appliesAt(rate, asOf) || !appliesAt(header, asOf))) {
96
122
  return undefined;
97
123
  }
98
124
  // The key matched, so the rate's currencies are exactly `from` and `to`.
@@ -100,6 +126,16 @@ export function rateTable(spec) {
100
126
  },
101
127
  };
102
128
  }
129
+ /** Whether a rate (or a table) applies at `at`: dated, published and still valid then. */
130
+ function appliesAt(rate, at) {
131
+ if (rate.asOf !== undefined && dayOf(at) < dayOf(rate.asOf)) {
132
+ return false;
133
+ }
134
+ if (rate.availableAt !== undefined && !hasStarted(rate.availableAt, at)) {
135
+ return false;
136
+ }
137
+ return rate.validUntil === undefined || !hasEnded(rate.validUntil, at);
138
+ }
103
139
  function isRateList(spec) {
104
140
  return Array.isArray(spec) && spec.every(isRate);
105
141
  }
@@ -158,7 +194,9 @@ export function via(base, provider) {
158
194
  * undefined when there is none. Days are UTC days. Loaded tables are cached by day. Misses and
159
195
  * failures are not cached, so a table that isn't published yet is tried again next time. A loader
160
196
  * that throws fails the lookup rather than falling back to an older day, so an outage doesn't
161
- * silently become a stale rate. The rates carry the day they're from.
197
+ * silently become a stale rate. The rates carry the day they're from. A table with an
198
+ * `availableAt` after an instant asked for is passed over, so a lookup at 09:00 on a publication
199
+ * day gets the day before.
162
200
  *
163
201
  * const history = snapshots(async (day) => parseEcbXml(await readFile(`ecb/${day}.xml`, 'utf8'))[0]);
164
202
  * const fx = await history.at('2026-11-08'); // a Sunday: Friday 2026-11-06's table
@@ -214,7 +252,9 @@ export function snapshots(load, options) {
214
252
  // Sequential on purpose: stop at the first day that has a table, without loading older
215
253
  // days. oxlint-disable-next-line no-await-in-loop
216
254
  const table = await loadDay(day);
217
- if (table !== undefined) {
255
+ // A table not yet published at the instant asked for is passed over like a missing one.
256
+ const availableAt = table?.availableAt;
257
+ if (table !== undefined && (availableAt === undefined || hasStarted(availableAt, asOf))) {
218
258
  return table;
219
259
  }
220
260
  }
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @internal
3
+ * A published rate cell: the decimal text, or null when the source marks the value as missing
4
+ * (holidays, `ND`, `N/A`). Anything else throws SyntaxError: a cell that can't be read must not
5
+ * look like "not quoted".
6
+ */
7
+ export declare function readRateCell(cell: string, where: string): string | null;
8
+ /**
9
+ * @internal
10
+ * The published digits of a rate from a feed that strips trailing zeros, given the number of
11
+ * decimals the publisher states: '1.175' with 4 decimals is '1.1750'. Text with more decimals than
12
+ * stated is kept as it is, since dropping digits would change the rate.
13
+ */
14
+ export declare function withDecimals(text: string, decimals: number): string;
15
+ /**
16
+ * @internal
17
+ * The records of a CSV file, RFC 4180 style: a cell may be quoted ("a, b", with "" for a quote),
18
+ * and a quote anywhere else, or one left open, is a SyntaxError, so a stray quote can't swallow
19
+ * the lines after it. Blank lines are skipped.
20
+ */
21
+ export declare function csvRows(text: string): string[][];
22
+ /**
23
+ * @internal
24
+ * Whether `text` is a real calendar day in ISO form. '2026-02-30' is not, although Date.parse rolls
25
+ * it over to 2 March.
26
+ */
27
+ export declare function isCalendarDay(text: string): boolean;
28
+ /**
29
+ * @internal
30
+ * Records a currency's rate (or null, missing) for a day. The same currency twice on one day is
31
+ * either a repeat, which is fine, or a contradiction, which throws: a parser never picks one.
32
+ */
33
+ export declare function addDayRate(days: Map<string, Record<string, string | null>>, day: string, currency: string, rate: string | null): void;
34
+ /** @internal Dated tables, newest first (ISO dates sort as strings). */
35
+ export declare function newestFirst<T extends {
36
+ readonly asOf?: string;
37
+ }>(tables: T[]): T[];
38
+ //# sourceMappingURL=rate-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-text.d.ts","sourceRoot":"","sources":["../src/rate-text.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASvE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAuDhD;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAChD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,IAAI,GAClB,IAAI,CAWN;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAElF"}
@@ -0,0 +1,143 @@
1
+ // Reading rate cells from published files, shared by the source parsers so that every source
2
+ // handles missing values and stripped digits the same way.
3
+ // What sources write for "no value this day": blank (ECB CSV, BoE), ND (Fed H.10), N/A (ECB CSV),
4
+ // NA (IMF), and dashes and NaN in other files. Compared upper-cased.
5
+ const MISSING_MARKERS = new Set(['', 'ND', 'N/A', 'NA', 'N.A.', '-', '–', '—', 'NAN', 'NULL']);
6
+ const PLAIN_DECIMAL = /^\d+(?:\.\d+)?$/;
7
+ /**
8
+ * @internal
9
+ * A published rate cell: the decimal text, or null when the source marks the value as missing
10
+ * (holidays, `ND`, `N/A`). Anything else throws SyntaxError: a cell that can't be read must not
11
+ * look like "not quoted".
12
+ */
13
+ export function readRateCell(cell, where) {
14
+ const text = cell.trim();
15
+ if (MISSING_MARKERS.has(text.toUpperCase())) {
16
+ return null;
17
+ }
18
+ if (!PLAIN_DECIMAL.test(text)) {
19
+ throw new SyntaxError(`Not a rate: ${JSON.stringify(cell)} (${where})`);
20
+ }
21
+ return text;
22
+ }
23
+ /**
24
+ * @internal
25
+ * The published digits of a rate from a feed that strips trailing zeros, given the number of
26
+ * decimals the publisher states: '1.175' with 4 decimals is '1.1750'. Text with more decimals than
27
+ * stated is kept as it is, since dropping digits would change the rate.
28
+ */
29
+ export function withDecimals(text, decimals) {
30
+ if (!Number.isSafeInteger(decimals) || decimals < 0 || decimals > 30) {
31
+ throw new RangeError(`decimals must be an integer from 0 to 30, got ${decimals}`);
32
+ }
33
+ const point = text.indexOf('.');
34
+ const present = point === -1 ? 0 : text.length - point - 1;
35
+ if (present >= decimals) {
36
+ return text;
37
+ }
38
+ const integerPart = point === -1 ? text : text.slice(0, point);
39
+ const fraction = point === -1 ? '' : text.slice(point + 1);
40
+ return `${integerPart}.${fraction.padEnd(decimals, '0')}`;
41
+ }
42
+ /**
43
+ * @internal
44
+ * The records of a CSV file, RFC 4180 style: a cell may be quoted ("a, b", with "" for a quote),
45
+ * and a quote anywhere else, or one left open, is a SyntaxError, so a stray quote can't swallow
46
+ * the lines after it. Blank lines are skipped.
47
+ */
48
+ export function csvRows(text) {
49
+ const rows = [];
50
+ let row = [];
51
+ let cell = '';
52
+ // 'start' of a cell, inside an unquoted one, inside quotes, or just after the closing quote
53
+ let state = 'start';
54
+ const endRow = () => {
55
+ row.push(cell);
56
+ if (row.length > 1 || row[0].trim() !== '') {
57
+ rows.push(row);
58
+ }
59
+ row = [];
60
+ cell = '';
61
+ state = 'start';
62
+ };
63
+ for (let i = 0; i < text.length; i++) {
64
+ const char = text[i];
65
+ if (state === 'quoted') {
66
+ if (char !== '"') {
67
+ cell += char;
68
+ }
69
+ else if (text[i + 1] === '"') {
70
+ cell += '"';
71
+ i++;
72
+ }
73
+ else {
74
+ state = 'closed';
75
+ }
76
+ continue;
77
+ }
78
+ if (char === ',') {
79
+ row.push(cell);
80
+ cell = '';
81
+ state = 'start';
82
+ }
83
+ else if (char === '\n') {
84
+ endRow();
85
+ }
86
+ else if (char === '\r' && text[i + 1] === '\n') {
87
+ continue;
88
+ }
89
+ else if (char === '"' && state === 'start') {
90
+ state = 'quoted';
91
+ }
92
+ else if (char === '"' || state === 'closed') {
93
+ throw new SyntaxError(`Malformed CSV: unexpected ${JSON.stringify(char)} on line ${rows.length + 1}`);
94
+ }
95
+ else {
96
+ cell += char;
97
+ state = 'plain';
98
+ }
99
+ }
100
+ if (state === 'quoted') {
101
+ throw new SyntaxError('Malformed CSV: a quoted cell is never closed');
102
+ }
103
+ if (cell !== '' || row.length > 0) {
104
+ endRow();
105
+ }
106
+ return rows;
107
+ }
108
+ const ISO_DAY = /^(\d{4})-(\d\d)-(\d\d)$/;
109
+ /**
110
+ * @internal
111
+ * Whether `text` is a real calendar day in ISO form. '2026-02-30' is not, although Date.parse rolls
112
+ * it over to 2 March.
113
+ */
114
+ export function isCalendarDay(text) {
115
+ const match = ISO_DAY.exec(text);
116
+ if (match === null) {
117
+ return false;
118
+ }
119
+ const date = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
120
+ return date.toISOString().slice(0, 10) === text;
121
+ }
122
+ /**
123
+ * @internal
124
+ * Records a currency's rate (or null, missing) for a day. The same currency twice on one day is
125
+ * either a repeat, which is fine, or a contradiction, which throws: a parser never picks one.
126
+ */
127
+ export function addDayRate(days, day, currency, rate) {
128
+ let rates = days.get(day);
129
+ if (rates === undefined) {
130
+ rates = {};
131
+ days.set(day, rates);
132
+ }
133
+ const earlier = rates[currency];
134
+ if (earlier !== undefined && earlier !== rate) {
135
+ throw new SyntaxError(`Two different values for ${currency} on ${day}: ${earlier} and ${rate}`);
136
+ }
137
+ rates[currency] = rate;
138
+ }
139
+ /** @internal Dated tables, newest first (ISO dates sort as strings). */
140
+ export function newestFirst(tables) {
141
+ return tables.sort((table, other) => other.asOf.localeCompare(table.asOf));
142
+ }
143
+ //# sourceMappingURL=rate-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-text.js","sourceRoot":"","sources":["../src/rate-text.ts"],"names":[],"mappings":"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"}