@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.
- package/README.md +479 -62
- package/data/cash-rounding.json +123 -2
- package/data/cldr-cash.json +101 -0
- package/data/historic.json +78 -0
- package/data/iso4217-list-three.xml +1185 -0
- package/dist/adyen-fx.d.ts.map +1 -1
- package/dist/adyen-fx.js +22 -4
- package/dist/adyen-fx.js.map +1 -1
- 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/cash.d.ts +30 -1
- package/dist/cash.d.ts.map +1 -1
- package/dist/cash.js +50 -2
- package/dist/cash.js.map +1 -1
- package/dist/convert.d.ts +10 -9
- package/dist/convert.d.ts.map +1 -1
- package/dist/convert.js +13 -3
- package/dist/convert.js.map +1 -1
- 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 +37 -2
- package/dist/ecb.d.ts.map +1 -1
- package/dist/ecb.js +148 -10
- package/dist/ecb.js.map +1 -1
- 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 +45 -0
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +167 -24
- package/dist/fetch.js.map +1 -1
- package/dist/fn.d.ts +8 -1
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +8 -1
- package/dist/fn.js.map +1 -1
- package/dist/generated/cash.d.ts +2 -0
- package/dist/generated/cash.d.ts.map +1 -1
- package/dist/generated/cash.js +101 -0
- package/dist/generated/cash.js.map +1 -1
- 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/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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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 +93 -9
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +135 -9
- package/dist/money.js.map +1 -1
- package/dist/parse.d.ts +45 -1
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +290 -3
- package/dist/parse.js.map +1 -1
- 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/all.d.ts +8 -1
- package/dist/plugins/all.d.ts.map +1 -1
- package/dist/plugins/all.js +8 -1
- package/dist/plugins/all.js.map +1 -1
- package/dist/plugins/convert.d.ts +3 -4
- package/dist/plugins/convert.d.ts.map +1 -1
- package/dist/plugins/convert.js.map +1 -1
- package/dist/plugins/tax.d.ts +4 -5
- package/dist/plugins/tax.d.ts.map +1 -1
- package/dist/plugins/tax.js.map +1 -1
- 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 +25 -14
- package/dist/prisma.d.ts.map +1 -1
- package/dist/prisma.js +29 -19
- package/dist/prisma.js.map +1 -1
- package/dist/provider.d.ts +21 -7
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +51 -11
- package/dist/provider.js.map +1 -1
- 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 +61 -5
- package/dist/rate.d.ts.map +1 -1
- package/dist/rate.js +133 -33
- package/dist/rate.js.map +1 -1
- package/dist/rounding.js +1 -1
- package/dist/rounding.js.map +1 -1
- 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/tax.d.ts +13 -9
- package/dist/tax.d.ts.map +1 -1
- package/dist/tax.js +20 -4
- package/dist/tax.js.map +1 -1
- 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 +116 -5
- package/src/adyen-fx.ts +25 -4
- package/src/boc.ts +136 -0
- package/src/boe.ts +131 -0
- package/src/cash.ts +70 -2
- package/src/convert.ts +33 -15
- 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 +179 -13
- package/src/fed.ts +146 -0
- package/src/fetch.ts +207 -28
- package/src/fn.ts +14 -0
- package/src/generated/cash.ts +103 -0
- package/src/generated/historic.ts +67 -0
- package/src/historic.ts +77 -0
- package/src/history.ts +333 -0
- package/src/hmrc.ts +125 -0
- package/src/index.ts +4 -0
- package/src/kysely.ts +588 -0
- package/src/money.ts +210 -12
- package/src/parse.ts +371 -4
- package/src/pg.ts +410 -0
- package/src/plugins/all.ts +10 -0
- package/src/plugins/convert.ts +4 -5
- package/src/plugins/tax.ts +9 -10
- package/src/policy.ts +124 -0
- package/src/prisma.ts +91 -10
- package/src/provider.ts +81 -16
- package/src/rate-text.ts +151 -0
- package/src/rate.ts +205 -36
- package/src/rounding.ts +1 -1
- package/src/schema.ts +119 -0
- package/src/sql.ts +178 -0
- package/src/tax.ts +40 -9
- 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/adyen-fx.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adyen-fx.d.ts","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,IAAI,EAAiB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"adyen-fx.d.ts","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,IAAI,EAAiB,MAAM,WAAW,CAAC;AAkInE,6BAA6B;AAC7B,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,iGAAiG;AACjG,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAmB/F"}
|
package/dist/adyen-fx.js
CHANGED
|
@@ -50,9 +50,18 @@ function offsetMinutes(zone) {
|
|
|
50
50
|
}
|
|
51
51
|
return numeric[1] === '-' ? -total : total;
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// Building an Intl.DateTimeFormat is far slower than using one, and a report has thousands of rows
|
|
54
|
+
// in one zone, so keep one formatter per zone. The bound stops a stream of distinct zone names
|
|
55
|
+
// (case variants are accepted by Intl) from growing the cache without limit.
|
|
56
|
+
const MAX_CACHED_FORMATTERS = 32;
|
|
57
|
+
const formatters = new Map();
|
|
58
|
+
/** The cached wall-clock formatter for an IANA time zone. */
|
|
59
|
+
function wallClockFormatter(timeZone) {
|
|
60
|
+
let formatter = formatters.get(timeZone);
|
|
61
|
+
if (formatter !== undefined) {
|
|
62
|
+
return formatter;
|
|
63
|
+
}
|
|
64
|
+
formatter = new Intl.DateTimeFormat('en-US', {
|
|
56
65
|
timeZone,
|
|
57
66
|
hourCycle: 'h23',
|
|
58
67
|
year: 'numeric',
|
|
@@ -61,7 +70,16 @@ function ianaOffsetMinutes(timeZone, utcMs) {
|
|
|
61
70
|
hour: 'numeric',
|
|
62
71
|
minute: 'numeric',
|
|
63
72
|
second: 'numeric',
|
|
64
|
-
})
|
|
73
|
+
});
|
|
74
|
+
if (formatters.size >= MAX_CACHED_FORMATTERS) {
|
|
75
|
+
formatters.clear();
|
|
76
|
+
}
|
|
77
|
+
formatters.set(timeZone, formatter);
|
|
78
|
+
return formatter;
|
|
79
|
+
}
|
|
80
|
+
/** The offset of an IANA time zone at a UTC instant, in minutes. */
|
|
81
|
+
function ianaOffsetMinutes(timeZone, utcMs) {
|
|
82
|
+
const parts = wallClockFormatter(timeZone).formatToParts(new Date(utcMs));
|
|
65
83
|
const field = (type) => Number(parts.find((part) => part.type === type).value);
|
|
66
84
|
const wallClockAsUtc = Date.UTC(field('year'), field('month') - 1, field('day'), field('hour'), field('minute'), field('second'));
|
|
67
85
|
return Math.round((wallClockAsUtc - Math.floor(utcMs / 1000) * 1000) / 60_000);
|
package/dist/adyen-fx.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adyen-fx.js","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,YAAY,EAA4B,MAAM,WAAW,CAAC;AAEnE,mGAAmG;AACnG,iGAAiG;AACjG,cAAc;AACd,MAAM,mBAAmB,GAAqC;IAC5D,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,EAAE;IACP,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;CACV,CAAC;AAEF,MAAM,UAAU,GAAG,wDAAwD,CAAC;AAC5E,MAAM,cAAc,GAAG,+CAA+C,CAAC;AAEvE,8CAA8C;AAC9C,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,CAAC;AAEnC,sFAAsF;AACtF,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,OAAO,CAAC;IACnC,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,GAAG,kBAAkB,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7C,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"adyen-fx.js","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,YAAY,EAA4B,MAAM,WAAW,CAAC;AAEnE,mGAAmG;AACnG,iGAAiG;AACjG,cAAc;AACd,MAAM,mBAAmB,GAAqC;IAC5D,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,EAAE;IACP,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;IACT,GAAG,EAAE,CAAC,GAAG;CACV,CAAC;AAEF,MAAM,UAAU,GAAG,wDAAwD,CAAC;AAC5E,MAAM,cAAc,GAAG,+CAA+C,CAAC;AAEvE,8CAA8C;AAC9C,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,CAAC;AAEnC,sFAAsF;AACtF,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,OAAO,CAAC;IACnC,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,GAAG,kBAAkB,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7C,CAAC;AAED,mGAAmG;AACnG,+FAA+F;AAC/F,6EAA6E;AAC7E,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACjC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAC;AAE1D,6DAA6D;AAC7D,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,IAAI,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC3C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IACH,IAAI,UAAU,CAAC,IAAI,IAAI,qBAAqB,EAAE,CAAC;QAC7C,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IACD,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,SAAS,iBAAiB,CAAC,QAAgB,EAAE,KAAa;IACxD,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAE,CAAC,KAAK,CAAC,CAAC;IAChG,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAC7B,KAAK,CAAC,MAAM,CAAC,EACb,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAClB,KAAK,CAAC,KAAK,CAAC,EACZ,KAAK,CAAC,MAAM,CAAC,EACb,KAAK,CAAC,QAAQ,CAAC,EACf,KAAK,CAAC,QAAQ,CAAC,CAChB,CAAC;IACF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;AACjF,CAAC;AAED,kFAAkF;AAClF,SAAS,SAAS,CAAC,YAAoB,EAAE,QAAgB;IACvD,6FAA6F;IAC7F,wCAAwC;IACxC,MAAM,UAAU,GAAG,YAAY,GAAG,iBAAiB,CAAC,QAAQ,EAAE,YAAY,CAAC,GAAG,MAAM,CAAC;IACrF,OAAO,YAAY,GAAG,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC;AACzE,CAAC;AAED,sFAAsF;AACtF,SAAS,YAAY,CACnB,OAAe,EACf,KAAyB,EACzB,QAA4B;IAE5B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;AAChE,CAAC;AAcD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,GAAuB,EAAE,OAA0B;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC;IAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACtC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;IACrC,IAAI,IAAI,GAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACzC,MAAM,IAAI,GACR,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChG,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,OAAO,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC"}
|
package/dist/boc.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RateTable } from './provider.js';
|
|
2
|
+
/** Options for parseBankOfCanadaJson. */
|
|
3
|
+
export interface BankOfCanadaOptions {
|
|
4
|
+
/**
|
|
5
|
+
* When each day's rates were published, or false for none. Default: 16:30 Toronto time that day,
|
|
6
|
+
* when the Bank says it publishes them.
|
|
7
|
+
*/
|
|
8
|
+
readonly availableAt?: false | ((day: string) => string | Date);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parses the Bank of Canada's daily exchange rates from the Valet API's JSON (the
|
|
12
|
+
* `FX_RATES_DAILY` group, or single `FX…CAD` series) into one CAD-based table per business day,
|
|
13
|
+
* newest first. The Bank quotes CAD per unit of each currency (FXUSDCAD 1.3748), so each table
|
|
14
|
+
* holds the exact inverse, CAD → currency, and keeps the published quote: `rate.inverse()` prints
|
|
15
|
+
* '1.3748' again. Rates have `source: 'BoC'`, `type: 'average'` (an average of a day's quotes, not
|
|
16
|
+
* a market rate) and `availableAt` 16:30 Toronto time, when the Bank says it publishes them (a late
|
|
17
|
+
* rate can come later; pass `availableAt` to change it). Valet leaves a series out of a day
|
|
18
|
+
* without a value, so a series listed in `seriesDetail` but absent on a day, an empty value or a
|
|
19
|
+
* null one, is in that day's `missing`. Anything but daily `FX…CAD` series (monthly or annual
|
|
20
|
+
* groups, other data) throws SyntaxError, as do two different values for one series on one day.
|
|
21
|
+
*
|
|
22
|
+
* Precision: the Bank quotes four decimals, up to six for small rates, so a small rate has only
|
|
23
|
+
* about four significant digits (JPY 0.008760, KRW 0.000929, and IDR 0.000082 with two). Its
|
|
24
|
+
* inverse is exact, but only as precise as that. For such currencies, prefer a source that quotes
|
|
25
|
+
* them the other way round.
|
|
26
|
+
*
|
|
27
|
+
* const tables = parseBankOfCanadaJson(await (await fetch(url)).text());
|
|
28
|
+
* tables[0].rate('CAD', 'USD')?.inverse().toString(); // '1.3748'
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseBankOfCanadaJson(json: string, options?: BankOfCanadaOptions): RateTable[];
|
|
31
|
+
//# sourceMappingURL=boc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boc.d.ts","sourceRoot":"","sources":["../src/boc.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AA+B/C,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,EAAE,CAuE9F"}
|
package/dist/boc.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// `@ducatjs/money/convert/boc`: an offline parser for the Bank of Canada's daily exchange rates
|
|
2
|
+
// (the Valet API). No I/O: fetch the JSON yourself, or use fetchBankOfCanada from
|
|
3
|
+
// @ducatjs/money/convert/fetch. Rates are kept exactly as published.
|
|
4
|
+
import { quotedTable } from './history.js';
|
|
5
|
+
import { addDayRate, isCalendarDay, newestFirst, readRateCell } from './rate-text.js';
|
|
6
|
+
const SERIES = /^FX([A-Z]{3})CAD$/;
|
|
7
|
+
const ZERO = /^0+(?:\.0+)?$/;
|
|
8
|
+
// The Bank publishes "once each business day by 16:30 (ET)". One formatter for the zone, built on
|
|
9
|
+
// first use, gives the Toronto offset on any day, summer time included.
|
|
10
|
+
let torontoFormatter;
|
|
11
|
+
/** 16:30 in Toronto on `day`, as a UTC instant. */
|
|
12
|
+
function publishedBy(day) {
|
|
13
|
+
torontoFormatter ??= new Intl.DateTimeFormat('en-US', {
|
|
14
|
+
timeZone: 'America/Toronto',
|
|
15
|
+
timeZoneName: 'shortOffset',
|
|
16
|
+
});
|
|
17
|
+
// Noon UTC is 07:00 or 08:00 in Toronto, after any clock change that day (they happen at 02:00).
|
|
18
|
+
const noon = new Date(`${day}T12:00:00Z`);
|
|
19
|
+
const zone = torontoFormatter.formatToParts(noon).find((part) => part.type === 'timeZoneName');
|
|
20
|
+
const offset = /^GMT([+-]\d+)$/.exec(zone?.value ?? '');
|
|
21
|
+
if (offset === null) {
|
|
22
|
+
throw new RangeError(`Can't tell Toronto's UTC offset on ${day} (${zone?.value})`);
|
|
23
|
+
}
|
|
24
|
+
const utcMs = Date.parse(`${day}T16:30:00Z`) - Number(offset[1]) * 3_600_000;
|
|
25
|
+
return new Date(utcMs).toISOString();
|
|
26
|
+
}
|
|
27
|
+
function notValet(why) {
|
|
28
|
+
throw new SyntaxError(`Not a Bank of Canada Valet daily FX file: ${why}`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parses the Bank of Canada's daily exchange rates from the Valet API's JSON (the
|
|
32
|
+
* `FX_RATES_DAILY` group, or single `FX…CAD` series) into one CAD-based table per business day,
|
|
33
|
+
* newest first. The Bank quotes CAD per unit of each currency (FXUSDCAD 1.3748), so each table
|
|
34
|
+
* holds the exact inverse, CAD → currency, and keeps the published quote: `rate.inverse()` prints
|
|
35
|
+
* '1.3748' again. Rates have `source: 'BoC'`, `type: 'average'` (an average of a day's quotes, not
|
|
36
|
+
* a market rate) and `availableAt` 16:30 Toronto time, when the Bank says it publishes them (a late
|
|
37
|
+
* rate can come later; pass `availableAt` to change it). Valet leaves a series out of a day
|
|
38
|
+
* without a value, so a series listed in `seriesDetail` but absent on a day, an empty value or a
|
|
39
|
+
* null one, is in that day's `missing`. Anything but daily `FX…CAD` series (monthly or annual
|
|
40
|
+
* groups, other data) throws SyntaxError, as do two different values for one series on one day.
|
|
41
|
+
*
|
|
42
|
+
* Precision: the Bank quotes four decimals, up to six for small rates, so a small rate has only
|
|
43
|
+
* about four significant digits (JPY 0.008760, KRW 0.000929, and IDR 0.000082 with two). Its
|
|
44
|
+
* inverse is exact, but only as precise as that. For such currencies, prefer a source that quotes
|
|
45
|
+
* them the other way round.
|
|
46
|
+
*
|
|
47
|
+
* const tables = parseBankOfCanadaJson(await (await fetch(url)).text());
|
|
48
|
+
* tables[0].rate('CAD', 'USD')?.inverse().toString(); // '1.3748'
|
|
49
|
+
*/
|
|
50
|
+
export function parseBankOfCanadaJson(json, options) {
|
|
51
|
+
const parsed = JSON.parse(json);
|
|
52
|
+
const observations = parsed?.observations;
|
|
53
|
+
if (!Array.isArray(observations)) {
|
|
54
|
+
notValet('no observations');
|
|
55
|
+
}
|
|
56
|
+
// The series the file says it has; each must be a daily FX…CAD series.
|
|
57
|
+
const expected = new Set();
|
|
58
|
+
for (const series of Object.keys(parsed?.seriesDetail ?? {})) {
|
|
59
|
+
if (!SERIES.test(series)) {
|
|
60
|
+
notValet(`series ${series} isn't a daily FX…CAD rate`);
|
|
61
|
+
}
|
|
62
|
+
expected.add(series);
|
|
63
|
+
}
|
|
64
|
+
const days = new Map();
|
|
65
|
+
for (const observation of observations) {
|
|
66
|
+
const day = observation?.['d'];
|
|
67
|
+
if (typeof day !== 'string' || !isCalendarDay(day)) {
|
|
68
|
+
notValet(`bad date ${JSON.stringify(day)}`);
|
|
69
|
+
}
|
|
70
|
+
for (const [series, cell] of Object.entries(observation)) {
|
|
71
|
+
if (series === 'd') {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const currency = SERIES.exec(series)?.[1];
|
|
75
|
+
if (currency === undefined) {
|
|
76
|
+
notValet(`series ${series} isn't a daily FX…CAD rate`);
|
|
77
|
+
}
|
|
78
|
+
const where = `${series} on ${day}`;
|
|
79
|
+
const value = cell?.v;
|
|
80
|
+
if (value !== null && typeof value !== 'string') {
|
|
81
|
+
throw new SyntaxError(`Malformed Valet value for ${where}`);
|
|
82
|
+
}
|
|
83
|
+
const rate = value === null ? null : readRateCell(value, where);
|
|
84
|
+
if (rate !== null && ZERO.test(rate)) {
|
|
85
|
+
throw new SyntaxError(`A zero rate for ${where}`);
|
|
86
|
+
}
|
|
87
|
+
addDayRate(days, day, currency, rate);
|
|
88
|
+
}
|
|
89
|
+
// Valet leaves out a series without a value that day.
|
|
90
|
+
for (const series of expected) {
|
|
91
|
+
const currency = SERIES.exec(series)[1];
|
|
92
|
+
if (days.get(day)?.[currency] === undefined) {
|
|
93
|
+
addDayRate(days, day, currency, null);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const tables = [];
|
|
98
|
+
for (const [day, rates] of days) {
|
|
99
|
+
if (!Object.values(rates).some((rate) => rate !== null)) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
let availableAt;
|
|
103
|
+
if (options?.availableAt === undefined) {
|
|
104
|
+
availableAt = publishedBy(day);
|
|
105
|
+
}
|
|
106
|
+
else if (options.availableAt !== false) {
|
|
107
|
+
availableAt = options.availableAt(day);
|
|
108
|
+
}
|
|
109
|
+
const info = { base: 'CAD', inverted: true, source: 'BoC', type: 'average', asOf: day };
|
|
110
|
+
tables.push(quotedTable({ ...info, ...(availableAt === undefined ? {} : { availableAt }), rates }));
|
|
111
|
+
}
|
|
112
|
+
return newestFirst(tables);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=boc.js.map
|
package/dist/boc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boc.js","sourceRoot":"","sources":["../src/boc.ts"],"names":[],"mappings":"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"}
|
package/dist/boe.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RateTable } from './provider.js';
|
|
2
|
+
/** Options for parseBankOfEnglandCsv. */
|
|
3
|
+
export interface BankOfEnglandOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The decimals the Bank publishes, rebuilt because its CSV strips trailing zeros ('1.35' for
|
|
6
|
+
* 1.3500). Default 4, as its database shows every spot series.
|
|
7
|
+
*/
|
|
8
|
+
readonly decimals?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parses the Bank of England database's CSV of daily spot rates against sterling (series XUDL…,
|
|
12
|
+
* downloaded with codes as column titles: `DATE,XUDLUSS,XUDLERS,…` and dates like `22 Dec 2025`)
|
|
13
|
+
* into one GBP-based table per day, newest first. Rates are currency units per £1, with `source:
|
|
14
|
+
* 'BoE'` and `type: 'spot'`. The CSV strips trailing zeros, so they are rebuilt to `decimals`
|
|
15
|
+
* (default 4). Holidays have no row; an empty cell (before a series starts, or after it ends, as
|
|
16
|
+
* for BGN) is a missing value. An unknown series code, a bad date, two different values for a day
|
|
17
|
+
* or any other unreadable cell throws SyntaxError. No `availableAt` is set: the Bank says only
|
|
18
|
+
* that daily rates are updated "no more than two working days after the date to which they
|
|
19
|
+
* relate".
|
|
20
|
+
*
|
|
21
|
+
* **Licensing: you must check the licence of every Bank of England series you load.** The database
|
|
22
|
+
* is under the Open Government Licence,
|
|
23
|
+
* but the Bank's legal page says "selected exchange rate data and series are excluded from this
|
|
24
|
+
* licence" and "reproduced by the Bank under licence from third parties", and its spot rates
|
|
25
|
+
* page says LSEG and Bloomberg BFIX may be sources, with LSEG content not to be redistributed
|
|
26
|
+
* without LSEG's consent. No series is named either way, so ducat ships no Bank of England data
|
|
27
|
+
* and no fetcher. Parse only files you have downloaded and are allowed to use, and get the Bank's
|
|
28
|
+
* (or LSEG's) permission before you republish any of it. The Bank also says these "are not
|
|
29
|
+
* official rates". For a licensed UK source, see HMRC's monthly rates
|
|
30
|
+
* (@ducatjs/money/convert/hmrc).
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseBankOfEnglandCsv(csv: string, options?: BankOfEnglandOptions): RateTable[];
|
|
33
|
+
//# sourceMappingURL=boe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boe.d.ts","sourceRoot":"","sources":["../src/boe.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAkD/C,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,EAAE,CA8C9F"}
|
package/dist/boe.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// `@ducatjs/money/convert/boe`: an offline parser for the Bank of England's daily spot exchange
|
|
2
|
+
// rates against sterling. Parser only: see parseBankOfEnglandCsv on licensing.
|
|
3
|
+
import { quotedTable } from './history.js';
|
|
4
|
+
import { addDayRate, csvRows, isCalendarDay, newestFirst, readRateCell } from './rate-text.js';
|
|
5
|
+
// The Bank's daily spot series against sterling, by code (currency units per £1).
|
|
6
|
+
const BOE_SERIES = {
|
|
7
|
+
XUDLADS: 'AUD',
|
|
8
|
+
XUDLZOS3: 'BGN',
|
|
9
|
+
XUDLCDS: 'CAD',
|
|
10
|
+
XUDLBK89: 'CNY',
|
|
11
|
+
XUDLBK25: 'CZK',
|
|
12
|
+
XUDLDKS: 'DKK',
|
|
13
|
+
XUDLERS: 'EUR',
|
|
14
|
+
XUDLHDS: 'HKD',
|
|
15
|
+
XUDLBK33: 'HUF',
|
|
16
|
+
XUDLBK97: 'INR',
|
|
17
|
+
XUDLBK78: 'ILS',
|
|
18
|
+
XUDLJYS: 'JPY',
|
|
19
|
+
XUDLBK83: 'MYR',
|
|
20
|
+
XUDLNDS: 'NZD',
|
|
21
|
+
XUDLNKS: 'NOK',
|
|
22
|
+
XUDLBK47: 'PLN',
|
|
23
|
+
XUDLZOS4: 'RON',
|
|
24
|
+
XUDLSRS: 'SAR',
|
|
25
|
+
XUDLSGS: 'SGD',
|
|
26
|
+
XUDLZRS: 'ZAR',
|
|
27
|
+
XUDLBK93: 'KRW',
|
|
28
|
+
XUDLSKS: 'SEK',
|
|
29
|
+
XUDLSFS: 'CHF',
|
|
30
|
+
XUDLTWS: 'TWD',
|
|
31
|
+
XUDLBK87: 'THB',
|
|
32
|
+
XUDLBK95: 'TRY',
|
|
33
|
+
XUDLUSS: 'USD',
|
|
34
|
+
};
|
|
35
|
+
const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
36
|
+
function notBoe(why) {
|
|
37
|
+
throw new SyntaxError(`Not a Bank of England spot rates CSV file: ${why}`);
|
|
38
|
+
}
|
|
39
|
+
/** '22 Dec 2025' as an ISO date, or SyntaxError. */
|
|
40
|
+
function isoDate(text) {
|
|
41
|
+
const match = /^(\d\d) ([A-Z][a-z]{2}) (\d{4})$/.exec(text.trim());
|
|
42
|
+
const month = match === null ? 0 : MONTHS.indexOf(match[2]) + 1;
|
|
43
|
+
const day = match === null ? '' : `${match[3]}-${String(month).padStart(2, '0')}-${match[1]}`;
|
|
44
|
+
if (month === 0 || !isCalendarDay(day)) {
|
|
45
|
+
notBoe(`bad date ${JSON.stringify(text)}`);
|
|
46
|
+
}
|
|
47
|
+
return day;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parses the Bank of England database's CSV of daily spot rates against sterling (series XUDL…,
|
|
51
|
+
* downloaded with codes as column titles: `DATE,XUDLUSS,XUDLERS,…` and dates like `22 Dec 2025`)
|
|
52
|
+
* into one GBP-based table per day, newest first. Rates are currency units per £1, with `source:
|
|
53
|
+
* 'BoE'` and `type: 'spot'`. The CSV strips trailing zeros, so they are rebuilt to `decimals`
|
|
54
|
+
* (default 4). Holidays have no row; an empty cell (before a series starts, or after it ends, as
|
|
55
|
+
* for BGN) is a missing value. An unknown series code, a bad date, two different values for a day
|
|
56
|
+
* or any other unreadable cell throws SyntaxError. No `availableAt` is set: the Bank says only
|
|
57
|
+
* that daily rates are updated "no more than two working days after the date to which they
|
|
58
|
+
* relate".
|
|
59
|
+
*
|
|
60
|
+
* **Licensing: you must check the licence of every Bank of England series you load.** The database
|
|
61
|
+
* is under the Open Government Licence,
|
|
62
|
+
* but the Bank's legal page says "selected exchange rate data and series are excluded from this
|
|
63
|
+
* licence" and "reproduced by the Bank under licence from third parties", and its spot rates
|
|
64
|
+
* page says LSEG and Bloomberg BFIX may be sources, with LSEG content not to be redistributed
|
|
65
|
+
* without LSEG's consent. No series is named either way, so ducat ships no Bank of England data
|
|
66
|
+
* and no fetcher. Parse only files you have downloaded and are allowed to use, and get the Bank's
|
|
67
|
+
* (or LSEG's) permission before you republish any of it. The Bank also says these "are not
|
|
68
|
+
* official rates". For a licensed UK source, see HMRC's monthly rates
|
|
69
|
+
* (@ducatjs/money/convert/hmrc).
|
|
70
|
+
*/
|
|
71
|
+
export function parseBankOfEnglandCsv(csv, options) {
|
|
72
|
+
const decimals = options?.decimals ?? 4;
|
|
73
|
+
const [header, ...rows] = csvRows(csv.charCodeAt(0) === 0xfeff ? csv.slice(1) : csv);
|
|
74
|
+
if (header === undefined || header[0]?.trim() !== 'DATE' || header.length < 2) {
|
|
75
|
+
notBoe('no DATE column');
|
|
76
|
+
}
|
|
77
|
+
const currencies = header.slice(1).map((code) => {
|
|
78
|
+
const currency = BOE_SERIES[code.trim()];
|
|
79
|
+
if (currency === undefined) {
|
|
80
|
+
notBoe(`unknown series ${code} (use the daily spot series against sterling, XUDL…)`);
|
|
81
|
+
}
|
|
82
|
+
return currency;
|
|
83
|
+
});
|
|
84
|
+
if (new Set(currencies).size !== currencies.length) {
|
|
85
|
+
notBoe('a series appears twice');
|
|
86
|
+
}
|
|
87
|
+
// A download always has a row per business day, so none at all is a cut-off file, not a range
|
|
88
|
+
// of holidays.
|
|
89
|
+
if (rows.length === 0) {
|
|
90
|
+
notBoe('no observations');
|
|
91
|
+
}
|
|
92
|
+
const days = new Map();
|
|
93
|
+
for (const cells of rows) {
|
|
94
|
+
if (cells.length !== header.length) {
|
|
95
|
+
notBoe(`a row has ${cells.length} cells, the header ${header.length}`);
|
|
96
|
+
}
|
|
97
|
+
const day = isoDate(cells[0]);
|
|
98
|
+
currencies.forEach((currency, i) => {
|
|
99
|
+
addDayRate(days, day, currency, readRateCell(cells[i + 1], `${currency} on ${day}`));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const tables = [];
|
|
103
|
+
for (const [day, rates] of days) {
|
|
104
|
+
if (Object.values(rates).some((rate) => rate !== null)) {
|
|
105
|
+
tables.push(quotedTable({ base: 'GBP', source: 'BoE', type: 'spot', asOf: day, decimals, rates }));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// A download only has rows for business days, so rows without a single rate aren't data.
|
|
109
|
+
if (tables.length === 0) {
|
|
110
|
+
notBoe('no rates in any row');
|
|
111
|
+
}
|
|
112
|
+
return newestFirst(tables);
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=boe.js.map
|
package/dist/boe.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boe.js","sourceRoot":"","sources":["../src/boe.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,+EAA+E;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE/F,kFAAkF;AAClF,MAAM,UAAU,GAAqC;IACnD,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,KAAK;CACf,CAAC;AACF,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAEpG,SAAS,MAAM,CAAC,GAAW;IACzB,MAAM,IAAI,WAAW,CAAC,8CAA8C,GAAG,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,oDAAoD;AACpD,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAWD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW,EAAE,OAA8B;IAC/E,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACrF,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9E,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9C,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACzC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,CAAC,kBAAkB,IAAI,sDAAsD,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,CAAC,wBAAwB,CAAC,CAAC;IACnC,CAAC;IAED,8FAA8F;IAC9F,eAAe;IACf,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAyC,CAAC;IAC9D,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,CAAC,aAAa,KAAK,CAAC,MAAM,sBAAsB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QAC/B,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE;YACjC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,GAAG,QAAQ,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,IAAI,CACT,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CACtF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,yFAAyF;IACzF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
|
package/dist/cash.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CASH_RULES, type CashRule } from './generated/cash.js';
|
|
2
|
-
import { type Money } from './money.js';
|
|
2
|
+
import { type Money, type RoundingPolicy } from './money.js';
|
|
3
3
|
import { type RoundingMode } from './rounding.js';
|
|
4
4
|
/**
|
|
5
5
|
* Rounds to a multiple of `increment` (same currency): roundToIncrement(CHF 10.03, CHF 0.05) = CHF
|
|
@@ -31,5 +31,34 @@ export interface CashRoundOptions {
|
|
|
31
31
|
* only call this for cash tenders. Returns m unchanged when no rule applies.
|
|
32
32
|
*/
|
|
33
33
|
export declare function cashRound<C extends string>(money: Money<C>, options?: CashRoundOptions): Money<C>;
|
|
34
|
+
/**
|
|
35
|
+
* The cash-rounding rule for a currency as a `RoundingPolicy`, to pass wherever a rounding mode
|
|
36
|
+
* goes: `m.multiply('1.075', cashPolicy('CHF'))` rounds once, straight to CHF 0.05. The policy only
|
|
37
|
+
* accepts amounts in `currency`. Throws a RangeError when no rule applies (EUR needs a country);
|
|
38
|
+
* use `isoPolicy` for currencies without cash rounding.
|
|
39
|
+
*/
|
|
40
|
+
export declare function cashPolicy(currency: string, options?: CashRoundOptions): RoundingPolicy;
|
|
41
|
+
/** Options for `currencyDigits`. */
|
|
42
|
+
export interface CurrencyDigitsOptions {
|
|
43
|
+
/** 'standard' (the default): the ISO 4217 exponent. 'cash': the decimals of a cash amount. */
|
|
44
|
+
readonly usage?: 'standard' | 'cash';
|
|
45
|
+
/** For cash: the country (ISO 3166 alpha-2), which EUR needs. */
|
|
46
|
+
readonly country?: string;
|
|
47
|
+
/** For cash: whether to use rules backed only by secondary sources (default true). */
|
|
48
|
+
readonly includeUnverified?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The number of decimals a currency's amounts are shown with: its ISO 4217 exponent, or with
|
|
52
|
+
* `{ usage: 'cash' }`, the decimals of a cash amount (what CLDR calls `cashDigits`): none when cash
|
|
53
|
+
* is rounded to whole units, the exponent otherwise.
|
|
54
|
+
*
|
|
55
|
+
* currencyDigits('SEK') // 2
|
|
56
|
+
* currencyDigits('SEK', { usage: 'cash' }) // 0: cash is rounded to whole kronor
|
|
57
|
+
* currencyDigits('CHF', { usage: 'cash' }) // 2: CHF 0.05 still needs two decimals
|
|
58
|
+
*
|
|
59
|
+
* A currency without a cash rule (or EUR without a country that has one) takes its exponent.
|
|
60
|
+
* Throws for unknown codes, like `currencyExponent`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function currencyDigits(currency: string, options?: CurrencyDigitsOptions): number;
|
|
34
63
|
export { CASH_RULES, type CashRule };
|
|
35
64
|
//# sourceMappingURL=cash.d.ts.map
|
package/dist/cash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cash.d.ts","sourceRoot":"","sources":["../src/cash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"cash.d.ts","sourceRoot":"","sources":["../src/cash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAKL,KAAK,KAAK,EACV,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGxF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAC/C,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAC5B,QAAQ,GAAE,YAA2B,GACpC,KAAK,CAAC,CAAC,CAAC,CAyBV;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAkBjF;AAuBD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC,CAAC,CAAC,CAOjG;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,cAAc,CAYvF;AAED,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACrC,iEAAiE;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,sFAAsF;IACtF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAgBxF;AAED,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,CAAC"}
|
package/dist/cash.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CASH_RULES } from './generated/cash.js';
|
|
2
|
-
import { CurrencyMismatchError, make, scaleUp, toScale } from './money.js';
|
|
2
|
+
import { CurrencyMismatchError, make, scaleUp, toScale, } from './money.js';
|
|
3
|
+
import { roundingPolicy } from './policy.js';
|
|
3
4
|
import { divideAndRound, divideAndRoundBigint } from './rounding.js';
|
|
4
5
|
import { currencyExponent } from './currency.js';
|
|
5
6
|
/**
|
|
@@ -80,7 +81,54 @@ export function cashRound(money, options) {
|
|
|
80
81
|
return money;
|
|
81
82
|
}
|
|
82
83
|
const inc = make(money.currency, rule.increment, currencyExponent(money.currency));
|
|
83
|
-
return roundToIncrement(money, inc, options?.rounding ?? 'halfExpand');
|
|
84
|
+
return roundToIncrement(money, inc, options?.rounding ?? rule.rounding ?? 'halfExpand');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The cash-rounding rule for a currency as a `RoundingPolicy`, to pass wherever a rounding mode
|
|
88
|
+
* goes: `m.multiply('1.075', cashPolicy('CHF'))` rounds once, straight to CHF 0.05. The policy only
|
|
89
|
+
* accepts amounts in `currency`. Throws a RangeError when no rule applies (EUR needs a country);
|
|
90
|
+
* use `isoPolicy` for currencies without cash rounding.
|
|
91
|
+
*/
|
|
92
|
+
export function cashPolicy(currency, options) {
|
|
93
|
+
const rule = cashRule(currency, options?.country);
|
|
94
|
+
if (!rule || (options?.includeUnverified === false && !rule.verified)) {
|
|
95
|
+
const where = options?.country === undefined ? '' : ` in ${options.country}`;
|
|
96
|
+
throw new RangeError(`No cash-rounding rule for ${currency}${where}`);
|
|
97
|
+
}
|
|
98
|
+
return roundingPolicy({
|
|
99
|
+
scale: currencyExponent(currency),
|
|
100
|
+
increment: rule.increment,
|
|
101
|
+
rounding: options?.rounding ?? rule.rounding ?? 'halfExpand',
|
|
102
|
+
currency,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The number of decimals a currency's amounts are shown with: its ISO 4217 exponent, or with
|
|
107
|
+
* `{ usage: 'cash' }`, the decimals of a cash amount (what CLDR calls `cashDigits`): none when cash
|
|
108
|
+
* is rounded to whole units, the exponent otherwise.
|
|
109
|
+
*
|
|
110
|
+
* currencyDigits('SEK') // 2
|
|
111
|
+
* currencyDigits('SEK', { usage: 'cash' }) // 0: cash is rounded to whole kronor
|
|
112
|
+
* currencyDigits('CHF', { usage: 'cash' }) // 2: CHF 0.05 still needs two decimals
|
|
113
|
+
*
|
|
114
|
+
* A currency without a cash rule (or EUR without a country that has one) takes its exponent.
|
|
115
|
+
* Throws for unknown codes, like `currencyExponent`.
|
|
116
|
+
*/
|
|
117
|
+
export function currencyDigits(currency, options) {
|
|
118
|
+
const exponent = currencyExponent(currency);
|
|
119
|
+
if (options?.usage !== 'cash') {
|
|
120
|
+
return exponent;
|
|
121
|
+
}
|
|
122
|
+
const rule = cashRule(currency, options.country);
|
|
123
|
+
if (!rule || (options.includeUnverified === false && !rule.verified)) {
|
|
124
|
+
return exponent;
|
|
125
|
+
}
|
|
126
|
+
// Cash amounts show no decimals once the step is whole units (SEK 1, HUF 5, UZS 50), and the
|
|
127
|
+
// currency's usual decimals otherwise: DKK 0.50 is shown as 10.50, not 10.5, as in CLDR.
|
|
128
|
+
if (rule.increment % 10 ** exponent === 0) {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
return exponent;
|
|
84
132
|
}
|
|
85
133
|
export { CASH_RULES };
|
|
86
134
|
//# sourceMappingURL=cash.js.map
|
package/dist/cash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cash.js","sourceRoot":"","sources":["../src/cash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,qBAAqB,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"cash.js","sourceRoot":"","sources":["../src/cash.ts"],"names":[],"mappings":"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"}
|
package/dist/convert.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { type Rounded } from './exact.js';
|
|
2
2
|
import { type Factor } from './decimal.js';
|
|
3
|
-
import { type CurrencyInput, type Money } from './money.js';
|
|
3
|
+
import { type CurrencyInput, type Money, type RoundingInput } from './money.js';
|
|
4
4
|
import { type RateProvider } from './provider.js';
|
|
5
5
|
import { type ConvertOptions, type Rate } from './rate.js';
|
|
6
|
-
|
|
7
|
-
export { exchangeRate, impliedRate, isRate, multiplyByRatioAtScale, Rate, RateExpiredError, rateFromJSON, type ConvertOptions, type RateInfo, type RateJSON, type RateType, } from './rate.js';
|
|
6
|
+
export { exchangeRate, impliedRate, isRate, multiplyByRatioAtScale, Rate, RateExpiredError, rateFromJSON, type ConvertOptions, type RateInfo, type RateJSON, type RateQuote, type RateType, } from './rate.js';
|
|
8
7
|
export { bag, comparator, MoneyBag, sortByValue, sumByCurrency, type ComparatorOptions, type TotalOptions, } from './bag.js';
|
|
9
8
|
export { chain, identity, rateOf, rateTable, RateUnavailableError, reversed, snapshots, snapshotsFrom, via, type RateProvider, type RateQuery, type RateTable, type RateTableSpec, type SnapshotOptions, type Snapshots, } from './provider.js';
|
|
10
9
|
/** Options for converting through a provider. */
|
|
@@ -13,27 +12,28 @@ export interface ProviderConvertOptions extends ConvertOptions {
|
|
|
13
12
|
readonly asOf?: string | Date;
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
|
-
* Converts `money` at a Rate, rounding once to the target currency's exponent (or `options.scale`)
|
|
15
|
+
* Converts `money` at a Rate, rounding once to the target currency's exponent (or `options.scale`),
|
|
16
|
+
* or with a rounding policy to its scale and increment (`@ducatjs/money/policy`).
|
|
17
17
|
* The rate's pair is checked, at compile time for literal currencies and at run time otherwise.
|
|
18
18
|
*
|
|
19
19
|
* convert(money('100', 'EUR'), eurUsd, 'halfEven') // 111.65 USD
|
|
20
20
|
* convert(money('100', 'USD'), eurUsd.inverse().andThen(eurJpy)) // composed exactly, rounded once
|
|
21
21
|
*/
|
|
22
|
-
export declare function convert<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?:
|
|
22
|
+
export declare function convert<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?: RoundingInput, options?: ConvertOptions): Money<To>;
|
|
23
23
|
/**
|
|
24
24
|
* Converts at a bare rate: units of `to` per unit of money's currency, as a decimal string so that
|
|
25
25
|
* no float is involved ('1.0832', every digit kept). Rounds once.
|
|
26
26
|
*
|
|
27
27
|
* convert(money('100', 'EUR'), 'JPY', '162.457', 'halfEven') // 16246 JPY
|
|
28
28
|
*/
|
|
29
|
-
export declare function convert<To extends CurrencyInput>(money: Money, to: To, rate: Factor, rounding?:
|
|
29
|
+
export declare function convert<To extends CurrencyInput>(money: Money, to: To, rate: Factor, rounding?: RoundingInput, options?: ConvertOptions): Money<To>;
|
|
30
30
|
/**
|
|
31
31
|
* Converts through a provider: looks up money's currency → `to` (as of `options.asOf`) and rounds
|
|
32
32
|
* once. Throws RateUnavailableError when the provider has no rate.
|
|
33
33
|
*
|
|
34
34
|
* convert(money('100', 'USD'), 'JPY', via('EUR', ecb), 'halfEven')
|
|
35
35
|
*/
|
|
36
|
-
export declare function convert<To extends CurrencyInput>(money: Money, to: To, provider: RateProvider, rounding?:
|
|
36
|
+
export declare function convert<To extends CurrencyInput>(money: Money, to: To, provider: RateProvider, rounding?: RoundingInput, options?: ProviderConvertOptions): Money<To>;
|
|
37
37
|
/**
|
|
38
38
|
* A conversion's rounded value, what rounding left out, and the rate used (for the audit trail).
|
|
39
39
|
*/
|
|
@@ -42,10 +42,11 @@ export interface DetailedConversion<From extends string, To extends string> exte
|
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* Converts at `rate` like convert(), and also reports the residual: `value + residual` is exactly
|
|
45
|
-
* money × rate, so a ledger can book the rounding difference.
|
|
45
|
+
* money × rate, so a ledger can book the rounding difference. With a rounding policy, the value
|
|
46
|
+
* is on the policy's scale and increment, and the residual is still the exact difference.
|
|
46
47
|
*
|
|
47
48
|
* const { value, residual } = convertDetailed(money('0.07', 'EUR'), eurUsd, 'halfEven');
|
|
48
49
|
* // value 0.08 USD, residual -0.001845 USD (as an exact ExactMoney)
|
|
49
50
|
*/
|
|
50
|
-
export declare function convertDetailed<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?:
|
|
51
|
+
export declare function convertDetailed<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?: RoundingInput, options?: ConvertOptions): DetailedConversion<From, To>;
|
|
51
52
|
//# sourceMappingURL=convert.d.ts.map
|
package/dist/convert.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAQ,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAQ,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,IAAI,EACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,sBAAsB,EACtB,IAAI,EACJ,gBAAgB,EAChB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,GAAG,EACH,UAAU,EACV,QAAQ,EACR,WAAW,EACX,aAAa,EACb,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,aAAa,EACb,GAAG,EACH,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AAEvB,iDAAiD;AACjD,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,gFAAgF;IAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAMD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EAC5D,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAC7B,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,cAAc,GACvB,KAAK,CAAC,EAAE,CAAC,CAAC;AACb;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,SAAS,aAAa,EAC9C,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,cAAc,GACvB,KAAK,CAAC,EAAE,CAAC,CAAC;AACb;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,SAAS,aAAa,EAC9C,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,YAAY,EACtB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,KAAK,CAAC,EAAE,CAAC,CAAC;AA0Cb;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,CAAE,SAAQ,OAAO,CAAC,EAAE,CAAC;IAC7F,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EACpE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAC7B,QAAQ,GAAE,aAAgC,EAC1C,OAAO,CAAC,EAAE,cAAc,GACvB,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,CAS9B"}
|