@reventlessdev/reventless-spec 3.0.0-alpha.88 → 3.0.0-alpha.90

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.
@@ -0,0 +1,598 @@
1
+ // AUTO-GENERATED from ISO 4217 (published 2026-01-01) — do not edit.
2
+ // Run `pnpm --filter @reventlessdev/reventless-spec run generate:currency`,
3
+ // or see `scripts/generate-currency.mjs` to update the source table first.
4
+
5
+ /**
6
+ A currency, closed to the 165 codes ISO 4217 defines a minor unit for.
7
+
8
+ ## Why a type and not a three-letter string
9
+
10
+ A string field invites `"eur"` beside `"EUR"`, and two spellings of one
11
+ currency is a class of bug that reads as a data problem long after it became a
12
+ correctness problem — the values are present, and they simply never match. A
13
+ closed type makes the second spelling unwritable.
14
+
15
+ ## Why generated, and why every code
16
+
17
+ The alternative was a curated handful (EUR, USD, GBP, JPY, …), which is small
18
+ and readable and wrong the first time an application needs a currency nobody
19
+ listed — a compile error in someone else's domain, fixable only by a framework
20
+ release. The thing being avoided by curating is 165 constructors that are
21
+ machine-written and never read in full; the thing being risked is a release.
22
+
23
+ Generation also buys the property that makes this type worth having: `exponent`
24
+ comes from the *same* source as the codes, so it cannot drift from them
25
+ (17×0, 139×2, 7×3, 2×4 decimal places across the set). That is what lets
26
+ `Money.format` derive its decimal placement instead of hardcoding `/100`, and
27
+ therefore what makes it correct for JPY and TND without anyone remembering that
28
+ those two are special.
29
+
30
+ ## What is deliberately absent
31
+
32
+ The 13 entries ISO lists with no minor unit: the precious metals
33
+ (XAG, XAU, XPD, XPT), the bond market units (XBA, XBB, XBC, XBD), the accounting
34
+ units (XDR, XSU, XUA), the testing code XTS, and the "no currency"
35
+ sentinel XXX. Each would make `exponent` partial, and a weight of gold is not
36
+ an amount of money. The standard's own table draws that line, so it is not a
37
+ curated opinion after all.
38
+
39
+ ## The wire form
40
+
41
+ A payload-less variant, so the stored and transmitted form is the three-letter
42
+ code itself — `{"amount": 1000, "currency": "EUR"}`. Standard at the boundary,
43
+ a checked type in the domain.
44
+ */
45
+ @schema
46
+ type t =
47
+ | /** UAE Dirham */ AED
48
+ | /** Afghani */ AFN
49
+ | /** Lek */ ALL
50
+ | /** Armenian Dram */ AMD
51
+ | /** Kwanza */ AOA
52
+ | /** Argentine Peso */ ARS
53
+ | /** Australian Dollar */ AUD
54
+ | /** Aruban Florin */ AWG
55
+ | /** Azerbaijan Manat */ AZN
56
+ | /** Convertible Mark */ BAM
57
+ | /** Barbados Dollar */ BBD
58
+ | /** Taka */ BDT
59
+ | /** Bahraini Dinar */ BHD
60
+ | /** Burundi Franc */ BIF
61
+ | /** Bermudian Dollar */ BMD
62
+ | /** Brunei Dollar */ BND
63
+ | /** Boliviano */ BOB
64
+ | /** undefined */ BOV
65
+ | /** Brazilian Real */ BRL
66
+ | /** Bahamian Dollar */ BSD
67
+ | /** Ngultrum */ BTN
68
+ | /** Pula */ BWP
69
+ | /** Belarusian Ruble */ BYN
70
+ | /** Belize Dollar */ BZD
71
+ | /** Canadian Dollar */ CAD
72
+ | /** Congolese Franc */ CDF
73
+ | /** undefined */ CHE
74
+ | /** Swiss Franc */ CHF
75
+ | /** undefined */ CHW
76
+ | /** undefined */ CLF
77
+ | /** Chilean Peso */ CLP
78
+ | /** Yuan Renminbi */ CNY
79
+ | /** Colombian Peso */ COP
80
+ | /** undefined */ COU
81
+ | /** Costa Rican Colon */ CRC
82
+ | /** Cuban Peso */ CUP
83
+ | /** Cabo Verde Escudo */ CVE
84
+ | /** Czech Koruna */ CZK
85
+ | /** Djibouti Franc */ DJF
86
+ | /** Danish Krone */ DKK
87
+ | /** Dominican Peso */ DOP
88
+ | /** Algerian Dinar */ DZD
89
+ | /** Egyptian Pound */ EGP
90
+ | /** Nakfa */ ERN
91
+ | /** Ethiopian Birr */ ETB
92
+ | /** Euro */ EUR
93
+ | /** Fiji Dollar */ FJD
94
+ | /** Falkland Islands Pound */ FKP
95
+ | /** Pound Sterling */ GBP
96
+ | /** Lari */ GEL
97
+ | /** Ghana Cedi */ GHS
98
+ | /** Gibraltar Pound */ GIP
99
+ | /** Dalasi */ GMD
100
+ | /** Guinean Franc */ GNF
101
+ | /** Quetzal */ GTQ
102
+ | /** Guyana Dollar */ GYD
103
+ | /** Hong Kong Dollar */ HKD
104
+ | /** Lempira */ HNL
105
+ | /** Gourde */ HTG
106
+ | /** Forint */ HUF
107
+ | /** Rupiah */ IDR
108
+ | /** New Israeli Sheqel */ ILS
109
+ | /** Indian Rupee */ INR
110
+ | /** Iraqi Dinar */ IQD
111
+ | /** Iranian Rial */ IRR
112
+ | /** Iceland Krona */ ISK
113
+ | /** Jamaican Dollar */ JMD
114
+ | /** Jordanian Dinar */ JOD
115
+ | /** Yen */ JPY
116
+ | /** Kenyan Shilling */ KES
117
+ | /** Som */ KGS
118
+ | /** Riel */ KHR
119
+ | /** Comorian Franc */ KMF
120
+ | /** North Korean Won */ KPW
121
+ | /** Won */ KRW
122
+ | /** Kuwaiti Dinar */ KWD
123
+ | /** Cayman Islands Dollar */ KYD
124
+ | /** Tenge */ KZT
125
+ | /** Lao Kip */ LAK
126
+ | /** Lebanese Pound */ LBP
127
+ | /** Sri Lanka Rupee */ LKR
128
+ | /** Liberian Dollar */ LRD
129
+ | /** Loti */ LSL
130
+ | /** Libyan Dinar */ LYD
131
+ | /** Moroccan Dirham */ MAD
132
+ | /** Moldovan Leu */ MDL
133
+ | /** Malagasy Ariary */ MGA
134
+ | /** Denar */ MKD
135
+ | /** Kyat */ MMK
136
+ | /** Tugrik */ MNT
137
+ | /** Pataca */ MOP
138
+ | /** Ouguiya */ MRU
139
+ | /** Mauritius Rupee */ MUR
140
+ | /** Rufiyaa */ MVR
141
+ | /** Malawi Kwacha */ MWK
142
+ | /** Mexican Peso */ MXN
143
+ | /** undefined */ MXV
144
+ | /** Malaysian Ringgit */ MYR
145
+ | /** Mozambique Metical */ MZN
146
+ | /** Namibia Dollar */ NAD
147
+ | /** Naira */ NGN
148
+ | /** Cordoba Oro */ NIO
149
+ | /** Norwegian Krone */ NOK
150
+ | /** Nepalese Rupee */ NPR
151
+ | /** New Zealand Dollar */ NZD
152
+ | /** Rial Omani */ OMR
153
+ | /** Balboa */ PAB
154
+ | /** Sol */ PEN
155
+ | /** Kina */ PGK
156
+ | /** Philippine Peso */ PHP
157
+ | /** Pakistan Rupee */ PKR
158
+ | /** Zloty */ PLN
159
+ | /** Guarani */ PYG
160
+ | /** Qatari Rial */ QAR
161
+ | /** Romanian Leu */ RON
162
+ | /** Serbian Dinar */ RSD
163
+ | /** Russian Ruble */ RUB
164
+ | /** Rwanda Franc */ RWF
165
+ | /** Saudi Riyal */ SAR
166
+ | /** Solomon Islands Dollar */ SBD
167
+ | /** Seychelles Rupee */ SCR
168
+ | /** Sudanese Pound */ SDG
169
+ | /** Swedish Krona */ SEK
170
+ | /** Singapore Dollar */ SGD
171
+ | /** Saint Helena Pound */ SHP
172
+ | /** Leone */ SLE
173
+ | /** Somali Shilling */ SOS
174
+ | /** Surinam Dollar */ SRD
175
+ | /** South Sudanese Pound */ SSP
176
+ | /** Dobra */ STN
177
+ | /** El Salvador Colon */ SVC
178
+ | /** Syrian Pound */ SYP
179
+ | /** Lilangeni */ SZL
180
+ | /** Baht */ THB
181
+ | /** Somoni */ TJS
182
+ | /** Turkmenistan New Manat */ TMT
183
+ | /** Tunisian Dinar */ TND
184
+ | /** Pa’anga */ TOP
185
+ | /** Turkish Lira */ TRY
186
+ | /** Trinidad and Tobago Dollar */ TTD
187
+ | /** New Taiwan Dollar */ TWD
188
+ | /** Tanzanian Shilling */ TZS
189
+ | /** Hryvnia */ UAH
190
+ | /** Uganda Shilling */ UGX
191
+ | /** US Dollar */ USD
192
+ | /** undefined */ USN
193
+ | /** undefined */ UYI
194
+ | /** Peso Uruguayo */ UYU
195
+ | /** Unidad Previsional */ UYW
196
+ | /** Uzbekistan Sum */ UZS
197
+ | /** Bolívar Soberano */ VED
198
+ | /** Bolívar Soberano */ VES
199
+ | /** Dong */ VND
200
+ | /** Vatu */ VUV
201
+ | /** Tala */ WST
202
+ | /** Arab Accounting Dinar */ XAD
203
+ | /** CFA Franc BEAC */ XAF
204
+ | /** East Caribbean Dollar */ XCD
205
+ | /** Caribbean Guilder */ XCG
206
+ | /** CFA Franc BCEAO */ XOF
207
+ | /** CFP Franc */ XPF
208
+ | /** Yemeni Rial */ YER
209
+ | /** Rand */ ZAR
210
+ | /** Zambian Kwacha */ ZMW
211
+ | /** Zimbabwe Gold */ ZWG
212
+
213
+ /** Every currency, in code order. `fromString` is derived from this, so a code
214
+ that parses and a code that exists are the same set by construction. */
215
+ let all: array<t> = [
216
+ AED, AFN, ALL, AMD, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BHD, BIF, BMD, BND, BOB, BOV, BRL,
217
+ BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHE, CHF, CHW, CLF, CLP, CNY, COP, COU, CRC, CUP, CVE, CZK,
218
+ DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD,
219
+ HNL, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD,
220
+ KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK,
221
+ MXN, MXV, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR,
222
+ RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, SSP, STN, SVC, SYP, SZL,
223
+ THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, USN, UYI, UYU, UYW, UZS, VED, VES,
224
+ VND, VUV, WST, XAD, XAF, XCD, XCG, XOF, XPF, YER, ZAR, ZMW, ZWG,
225
+ ]
226
+
227
+ /** The currency's ISO 4217 alphabetic code. */
228
+ let toString = (currency: t): string =>
229
+ switch currency {
230
+ | AED => "AED"
231
+ | AFN => "AFN"
232
+ | ALL => "ALL"
233
+ | AMD => "AMD"
234
+ | AOA => "AOA"
235
+ | ARS => "ARS"
236
+ | AUD => "AUD"
237
+ | AWG => "AWG"
238
+ | AZN => "AZN"
239
+ | BAM => "BAM"
240
+ | BBD => "BBD"
241
+ | BDT => "BDT"
242
+ | BHD => "BHD"
243
+ | BIF => "BIF"
244
+ | BMD => "BMD"
245
+ | BND => "BND"
246
+ | BOB => "BOB"
247
+ | BOV => "BOV"
248
+ | BRL => "BRL"
249
+ | BSD => "BSD"
250
+ | BTN => "BTN"
251
+ | BWP => "BWP"
252
+ | BYN => "BYN"
253
+ | BZD => "BZD"
254
+ | CAD => "CAD"
255
+ | CDF => "CDF"
256
+ | CHE => "CHE"
257
+ | CHF => "CHF"
258
+ | CHW => "CHW"
259
+ | CLF => "CLF"
260
+ | CLP => "CLP"
261
+ | CNY => "CNY"
262
+ | COP => "COP"
263
+ | COU => "COU"
264
+ | CRC => "CRC"
265
+ | CUP => "CUP"
266
+ | CVE => "CVE"
267
+ | CZK => "CZK"
268
+ | DJF => "DJF"
269
+ | DKK => "DKK"
270
+ | DOP => "DOP"
271
+ | DZD => "DZD"
272
+ | EGP => "EGP"
273
+ | ERN => "ERN"
274
+ | ETB => "ETB"
275
+ | EUR => "EUR"
276
+ | FJD => "FJD"
277
+ | FKP => "FKP"
278
+ | GBP => "GBP"
279
+ | GEL => "GEL"
280
+ | GHS => "GHS"
281
+ | GIP => "GIP"
282
+ | GMD => "GMD"
283
+ | GNF => "GNF"
284
+ | GTQ => "GTQ"
285
+ | GYD => "GYD"
286
+ | HKD => "HKD"
287
+ | HNL => "HNL"
288
+ | HTG => "HTG"
289
+ | HUF => "HUF"
290
+ | IDR => "IDR"
291
+ | ILS => "ILS"
292
+ | INR => "INR"
293
+ | IQD => "IQD"
294
+ | IRR => "IRR"
295
+ | ISK => "ISK"
296
+ | JMD => "JMD"
297
+ | JOD => "JOD"
298
+ | JPY => "JPY"
299
+ | KES => "KES"
300
+ | KGS => "KGS"
301
+ | KHR => "KHR"
302
+ | KMF => "KMF"
303
+ | KPW => "KPW"
304
+ | KRW => "KRW"
305
+ | KWD => "KWD"
306
+ | KYD => "KYD"
307
+ | KZT => "KZT"
308
+ | LAK => "LAK"
309
+ | LBP => "LBP"
310
+ | LKR => "LKR"
311
+ | LRD => "LRD"
312
+ | LSL => "LSL"
313
+ | LYD => "LYD"
314
+ | MAD => "MAD"
315
+ | MDL => "MDL"
316
+ | MGA => "MGA"
317
+ | MKD => "MKD"
318
+ | MMK => "MMK"
319
+ | MNT => "MNT"
320
+ | MOP => "MOP"
321
+ | MRU => "MRU"
322
+ | MUR => "MUR"
323
+ | MVR => "MVR"
324
+ | MWK => "MWK"
325
+ | MXN => "MXN"
326
+ | MXV => "MXV"
327
+ | MYR => "MYR"
328
+ | MZN => "MZN"
329
+ | NAD => "NAD"
330
+ | NGN => "NGN"
331
+ | NIO => "NIO"
332
+ | NOK => "NOK"
333
+ | NPR => "NPR"
334
+ | NZD => "NZD"
335
+ | OMR => "OMR"
336
+ | PAB => "PAB"
337
+ | PEN => "PEN"
338
+ | PGK => "PGK"
339
+ | PHP => "PHP"
340
+ | PKR => "PKR"
341
+ | PLN => "PLN"
342
+ | PYG => "PYG"
343
+ | QAR => "QAR"
344
+ | RON => "RON"
345
+ | RSD => "RSD"
346
+ | RUB => "RUB"
347
+ | RWF => "RWF"
348
+ | SAR => "SAR"
349
+ | SBD => "SBD"
350
+ | SCR => "SCR"
351
+ | SDG => "SDG"
352
+ | SEK => "SEK"
353
+ | SGD => "SGD"
354
+ | SHP => "SHP"
355
+ | SLE => "SLE"
356
+ | SOS => "SOS"
357
+ | SRD => "SRD"
358
+ | SSP => "SSP"
359
+ | STN => "STN"
360
+ | SVC => "SVC"
361
+ | SYP => "SYP"
362
+ | SZL => "SZL"
363
+ | THB => "THB"
364
+ | TJS => "TJS"
365
+ | TMT => "TMT"
366
+ | TND => "TND"
367
+ | TOP => "TOP"
368
+ | TRY => "TRY"
369
+ | TTD => "TTD"
370
+ | TWD => "TWD"
371
+ | TZS => "TZS"
372
+ | UAH => "UAH"
373
+ | UGX => "UGX"
374
+ | USD => "USD"
375
+ | USN => "USN"
376
+ | UYI => "UYI"
377
+ | UYU => "UYU"
378
+ | UYW => "UYW"
379
+ | UZS => "UZS"
380
+ | VED => "VED"
381
+ | VES => "VES"
382
+ | VND => "VND"
383
+ | VUV => "VUV"
384
+ | WST => "WST"
385
+ | XAD => "XAD"
386
+ | XAF => "XAF"
387
+ | XCD => "XCD"
388
+ | XCG => "XCG"
389
+ | XOF => "XOF"
390
+ | XPF => "XPF"
391
+ | YER => "YER"
392
+ | ZAR => "ZAR"
393
+ | ZMW => "ZMW"
394
+ | ZWG => "ZWG"
395
+ }
396
+
397
+ /**
398
+ How many decimal places the currency's minor unit is: 2 for EUR, **0 for JPY**,
399
+ **3 for TND**, 4 for the Chilean Unidad de Fomento.
400
+
401
+ Total by construction — this is the whole reason the type is closed and the
402
+ table is generated. An amount is stored in integer minor units, so this is the
403
+ only thing that says where its decimal point goes.
404
+ */
405
+ let exponent = (currency: t): int =>
406
+ switch currency {
407
+ | AED => 2
408
+ | AFN => 2
409
+ | ALL => 2
410
+ | AMD => 2
411
+ | AOA => 2
412
+ | ARS => 2
413
+ | AUD => 2
414
+ | AWG => 2
415
+ | AZN => 2
416
+ | BAM => 2
417
+ | BBD => 2
418
+ | BDT => 2
419
+ | BHD => 3
420
+ | BIF => 0
421
+ | BMD => 2
422
+ | BND => 2
423
+ | BOB => 2
424
+ | BOV => 2
425
+ | BRL => 2
426
+ | BSD => 2
427
+ | BTN => 2
428
+ | BWP => 2
429
+ | BYN => 2
430
+ | BZD => 2
431
+ | CAD => 2
432
+ | CDF => 2
433
+ | CHE => 2
434
+ | CHF => 2
435
+ | CHW => 2
436
+ | CLF => 4
437
+ | CLP => 0
438
+ | CNY => 2
439
+ | COP => 2
440
+ | COU => 2
441
+ | CRC => 2
442
+ | CUP => 2
443
+ | CVE => 2
444
+ | CZK => 2
445
+ | DJF => 0
446
+ | DKK => 2
447
+ | DOP => 2
448
+ | DZD => 2
449
+ | EGP => 2
450
+ | ERN => 2
451
+ | ETB => 2
452
+ | EUR => 2
453
+ | FJD => 2
454
+ | FKP => 2
455
+ | GBP => 2
456
+ | GEL => 2
457
+ | GHS => 2
458
+ | GIP => 2
459
+ | GMD => 2
460
+ | GNF => 0
461
+ | GTQ => 2
462
+ | GYD => 2
463
+ | HKD => 2
464
+ | HNL => 2
465
+ | HTG => 2
466
+ | HUF => 2
467
+ | IDR => 2
468
+ | ILS => 2
469
+ | INR => 2
470
+ | IQD => 3
471
+ | IRR => 2
472
+ | ISK => 0
473
+ | JMD => 2
474
+ | JOD => 3
475
+ | JPY => 0
476
+ | KES => 2
477
+ | KGS => 2
478
+ | KHR => 2
479
+ | KMF => 0
480
+ | KPW => 2
481
+ | KRW => 0
482
+ | KWD => 3
483
+ | KYD => 2
484
+ | KZT => 2
485
+ | LAK => 2
486
+ | LBP => 2
487
+ | LKR => 2
488
+ | LRD => 2
489
+ | LSL => 2
490
+ | LYD => 3
491
+ | MAD => 2
492
+ | MDL => 2
493
+ | MGA => 2
494
+ | MKD => 2
495
+ | MMK => 2
496
+ | MNT => 2
497
+ | MOP => 2
498
+ | MRU => 2
499
+ | MUR => 2
500
+ | MVR => 2
501
+ | MWK => 2
502
+ | MXN => 2
503
+ | MXV => 2
504
+ | MYR => 2
505
+ | MZN => 2
506
+ | NAD => 2
507
+ | NGN => 2
508
+ | NIO => 2
509
+ | NOK => 2
510
+ | NPR => 2
511
+ | NZD => 2
512
+ | OMR => 3
513
+ | PAB => 2
514
+ | PEN => 2
515
+ | PGK => 2
516
+ | PHP => 2
517
+ | PKR => 2
518
+ | PLN => 2
519
+ | PYG => 0
520
+ | QAR => 2
521
+ | RON => 2
522
+ | RSD => 2
523
+ | RUB => 2
524
+ | RWF => 0
525
+ | SAR => 2
526
+ | SBD => 2
527
+ | SCR => 2
528
+ | SDG => 2
529
+ | SEK => 2
530
+ | SGD => 2
531
+ | SHP => 2
532
+ | SLE => 2
533
+ | SOS => 2
534
+ | SRD => 2
535
+ | SSP => 2
536
+ | STN => 2
537
+ | SVC => 2
538
+ | SYP => 2
539
+ | SZL => 2
540
+ | THB => 2
541
+ | TJS => 2
542
+ | TMT => 2
543
+ | TND => 3
544
+ | TOP => 2
545
+ | TRY => 2
546
+ | TTD => 2
547
+ | TWD => 2
548
+ | TZS => 2
549
+ | UAH => 2
550
+ | UGX => 0
551
+ | USD => 2
552
+ | USN => 2
553
+ | UYI => 0
554
+ | UYU => 2
555
+ | UYW => 4
556
+ | UZS => 2
557
+ | VED => 2
558
+ | VES => 2
559
+ | VND => 0
560
+ | VUV => 0
561
+ | WST => 2
562
+ | XAD => 2
563
+ | XAF => 0
564
+ | XCD => 2
565
+ | XCG => 2
566
+ | XOF => 0
567
+ | XPF => 0
568
+ | YER => 2
569
+ | ZAR => 2
570
+ | ZMW => 2
571
+ | ZWG => 2
572
+ }
573
+
574
+ let byCode: dict<t> = {
575
+ let d = Dict.make()
576
+ all->Array.forEach(c => d->Dict.set(toString(c), c))
577
+ d
578
+ }
579
+
580
+ /**
581
+ Parse an ISO 4217 alphabetic code, saying why when it is not one.
582
+
583
+ Case-sensitive on purpose: `"eur"` is rejected rather than repaired. This type
584
+ exists because a silent case mismatch is expensive to find, and quietly
585
+ accepting the wrong spelling at the boundary would put it back — a producer
586
+ sending lowercase codes should learn that at its first request, not at the first
587
+ report that two halves of a ledger disagree.
588
+ */
589
+ let fromString = (raw: string): result<t, string> =>
590
+ switch byCode->Dict.get(raw) {
591
+ | Some(c) => Ok(c)
592
+ | None =>
593
+ Error(
594
+ `expected an ISO 4217 currency code such as "EUR", got ${raw
595
+ ->JSON.Encode.string
596
+ ->JSON.stringify}. Codes are upper-case and exactly three letters.`,
597
+ )
598
+ }