@amboras-dev/money 0.0.0-stage → 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 (78) hide show
  1. package/README.md +401 -2
  2. package/dist/ai.cjs +185 -0
  3. package/dist/ai.d.cts +97 -0
  4. package/dist/ai.d.ts +97 -0
  5. package/dist/ai.js +175 -0
  6. package/dist/allocate-CZRg4TOP.cjs +222 -0
  7. package/dist/allocate-X7_jAtOj.js +199 -0
  8. package/dist/amount-BV0O-aN8.cjs +241 -0
  9. package/dist/amount-BoYBMgK9.js +200 -0
  10. package/dist/arithmetic-BhNwisjb.js +132 -0
  11. package/dist/arithmetic-DjT4Kzgt.cjs +233 -0
  12. package/dist/billing.cjs +184 -0
  13. package/dist/billing.d.cts +81 -0
  14. package/dist/billing.d.ts +81 -0
  15. package/dist/billing.js +175 -0
  16. package/dist/commerce.cjs +536 -0
  17. package/dist/commerce.d.cts +293 -0
  18. package/dist/commerce.d.ts +293 -0
  19. package/dist/commerce.js +516 -0
  20. package/dist/format-BdPnijvn.js +99 -0
  21. package/dist/format-DLhno7eX.cjs +128 -0
  22. package/dist/fx.cjs +407 -0
  23. package/dist/fx.d.cts +157 -0
  24. package/dist/fx.d.ts +157 -0
  25. package/dist/fx.js +374 -0
  26. package/dist/index.cjs +352 -0
  27. package/dist/index.d.cts +300 -0
  28. package/dist/index.d.ts +300 -0
  29. package/dist/index.js +276 -0
  30. package/dist/input.cjs +163 -0
  31. package/dist/input.d.cts +203 -0
  32. package/dist/input.d.ts +203 -0
  33. package/dist/input.js +153 -0
  34. package/dist/iso-minor-CqkWDxHS.js +48 -0
  35. package/dist/iso-minor-wSwJN57T.cjs +65 -0
  36. package/dist/medusa-4K8N1pUc.d.cts +87 -0
  37. package/dist/medusa-DBXJXXvF.d.ts +87 -0
  38. package/dist/medusa-DqJY1qpj.js +116 -0
  39. package/dist/medusa-lRY9xlsf.cjs +175 -0
  40. package/dist/money-B-3aFjNJ.d.cts +248 -0
  41. package/dist/money-B-3aFjNJ.d.ts +248 -0
  42. package/dist/money-B3wH_Z4S.cjs +3990 -0
  43. package/dist/money-WhnGiI00.js +3583 -0
  44. package/dist/number-text-BWu67jUq.cjs +145 -0
  45. package/dist/number-text-DE-q4jO5.js +134 -0
  46. package/dist/own-D7544D3k.js +4 -0
  47. package/dist/own-oP9DXFWv.cjs +9 -0
  48. package/dist/percent-C0InC2t2.cjs +43 -0
  49. package/dist/percent-D1VB9xXG.js +20 -0
  50. package/dist/rate-CVeMii4a.cjs +217 -0
  51. package/dist/rate-DBPiYgT1.d.ts +63 -0
  52. package/dist/rate-DicStBue.js +152 -0
  53. package/dist/rate-tqK8ijG0.d.cts +63 -0
  54. package/dist/reporting-CG-ai2sM.d.cts +31 -0
  55. package/dist/reporting-tpGJbqYp.d.ts +31 -0
  56. package/dist/retail-1mu888J1.js +69 -0
  57. package/dist/retail-C_BPLvMj.d.cts +31 -0
  58. package/dist/retail-Cml8YSKg.cjs +86 -0
  59. package/dist/retail-DRUTTQoJ.d.ts +31 -0
  60. package/dist/rounding-DHBtNCHG.cjs +79 -0
  61. package/dist/rounding-g9rvye0k.js +50 -0
  62. package/dist/sql.cjs +290 -0
  63. package/dist/sql.d.cts +147 -0
  64. package/dist/sql.d.ts +147 -0
  65. package/dist/sql.js +271 -0
  66. package/dist/testing.cjs +61995 -0
  67. package/dist/testing.d.cts +125 -0
  68. package/dist/testing.d.ts +125 -0
  69. package/dist/testing.js +61986 -0
  70. package/dist/wire-Bhuut8cW.cjs +2097 -0
  71. package/dist/wire-CaUN9Vf_.d.ts +309 -0
  72. package/dist/wire-sW0yzqth.js +1888 -0
  73. package/dist/wire-xjYXv4go.d.cts +309 -0
  74. package/dist/wire.cjs +37 -0
  75. package/dist/wire.d.cts +2 -0
  76. package/dist/wire.d.ts +2 -0
  77. package/dist/wire.js +2 -0
  78. package/package.json +158 -3
package/dist/input.cjs ADDED
@@ -0,0 +1,163 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_money = require("./money-B3wH_Z4S.cjs");
3
+ const require_number_text = require("./number-text-BWu67jUq.cjs");
4
+ const require_rate = require("./rate-CVeMii4a.cjs");
5
+ const require_amount = require("./amount-BV0O-aN8.cjs");
6
+ //#region src/input/import.ts
7
+ /**
8
+ * Amount text from a file or a third party to canonical DecimalText (major units, exactly as
9
+ * written: `'1.299,00'` gives `'1299'`), or null when it is not an amount (empty, exponent,
10
+ * hex, garbage, negative without `allowNegative`). Never 0 for bad input.
11
+ */
12
+ function parseImportAmount(text, options = {}) {
13
+ const read = require_number_text.readNumberText(text, {
14
+ decimalSeparator: options.decimalSeparator ?? "auto",
15
+ currency: options.currency,
16
+ allowTrailingText: options.allowTrailingText
17
+ });
18
+ if ("reason" in read || read.sign < 0 && !options.allowNegative) return null;
19
+ return require_money.toDecimalText(require_amount.decimalOfText(read));
20
+ }
21
+ /**
22
+ * Strict decimal entry: `.` decimal, no grouping, at most `maxDecimals` fraction digits (cost
23
+ * entry at 4, metafields). `'4.5'` gives `'4.5'`, `'.5'` gives `'0.5'`; `'1,000'` is `'unparseable'`.
24
+ */
25
+ function parseDecimalInput(text, options) {
26
+ const read = require_number_text.readNumberText(text, {
27
+ decimalSeparator: ".",
28
+ groupSeparator: null
29
+ });
30
+ if ("reason" in read) return {
31
+ ok: false,
32
+ reason: read.reason
33
+ };
34
+ const value = require_amount.decimalOfText(read);
35
+ if (require_money.fractionDigitsOf(value) > options.maxDecimals) return {
36
+ ok: false,
37
+ reason: "too_many_decimals"
38
+ };
39
+ if (value.units < 0n && !options.allowNegative) return {
40
+ ok: false,
41
+ reason: "negative"
42
+ };
43
+ if (options.min !== void 0 && require_money.compareDecimal(value, require_money.decimalOf(options.min)) < 0) return {
44
+ ok: false,
45
+ reason: "below_min"
46
+ };
47
+ if (options.max !== void 0 && require_money.compareDecimal(value, require_money.decimalOf(options.max)) > 0) return {
48
+ ok: false,
49
+ reason: "above_max"
50
+ };
51
+ return {
52
+ ok: true,
53
+ value: require_money.toDecimalText(value)
54
+ };
55
+ }
56
+ //#endregion
57
+ //#region src/input/percent-rate.ts
58
+ /**
59
+ * A typed percent (`'20'`, `'12.5'`, `'12,5 %'` in de-DE) as DecimalText. A `%` before or after
60
+ * the number is allowed. Default range 0..100 with 2 decimals; below 0 (with a non-negative
61
+ * `min`) is `'negative'`.
62
+ */
63
+ function parsePercentInput(text, options = {}) {
64
+ const bare = typeof text === "string" ? text.trim().replace(/^%\s*|\s*%$/g, "") : text;
65
+ const read = require_number_text.readNumberText(bare, require_amount.localeSeparators(options.locale));
66
+ if ("reason" in read) return {
67
+ ok: false,
68
+ reason: read.reason
69
+ };
70
+ const value = require_amount.decimalOfText(read);
71
+ const min = require_money.decimalOf(options.min ?? 0, true, "min");
72
+ const max = require_money.decimalOf(options.max ?? 100, true, "max");
73
+ if (require_money.fractionDigitsOf(value) > (options.maxDecimals ?? 2)) return {
74
+ ok: false,
75
+ reason: "too_many_decimals"
76
+ };
77
+ if (require_money.compareDecimal(value, min) < 0) return {
78
+ ok: false,
79
+ reason: value.units < 0n && min.units >= 0n ? "negative" : "below_min"
80
+ };
81
+ if (require_money.compareDecimal(value, max) > 0) return {
82
+ ok: false,
83
+ reason: "above_max"
84
+ };
85
+ return {
86
+ ok: true,
87
+ value: require_money.toDecimalText(value)
88
+ };
89
+ }
90
+ /**
91
+ * A typed exchange rate ("1 store-currency unit equals this many units") as a precise Rate
92
+ * (`fx.rateFromDecimal(value, { encoding: 'precise' })`), or null when the text is not a
93
+ * positive number or the rate is outside `RATE_BOUNDS` (0.0000001 to 1000000000).
94
+ */
95
+ function parseRateInput(text, options = {}) {
96
+ const read = require_number_text.readNumberText(text, require_amount.localeSeparators(options.locale));
97
+ if ("reason" in read || read.sign < 0 || read.units === 0n) return null;
98
+ try {
99
+ const precise = require_rate.rateFromDecimal(require_money.formatDecimal(require_amount.decimalOfText(read)), { encoding: "precise" });
100
+ return require_rate.rate(precise.numerator, precise.denominator);
101
+ } catch (error) {
102
+ if (error instanceof require_money.MoneyError && error.code === "rate_invalid") return null;
103
+ throw error;
104
+ }
105
+ }
106
+ //#endregion
107
+ //#region src/input/template.ts
108
+ const DEFAULT_TEMPLATE = Object.freeze({
109
+ prefix: "",
110
+ suffix: "",
111
+ fractionDigits: 2,
112
+ decimalSeparator: ".",
113
+ groupSeparator: ","
114
+ });
115
+ const NUMBER_RUN = /\d[\d.,'’\s]*\d|\d/u;
116
+ const counterpart = (separator) => separator === "," ? "." : ",";
117
+ /**
118
+ * The print template of one captured literal (cloner `analyzeMoneyFormat`): prefix and suffix
119
+ * around the number, the decimal separator and digit count of its fraction (1 or 2 digits
120
+ * read as 2, 3 as 3, none as 0), the separator it groups thousands with (else the decimal's
121
+ * counterpart), all as the separator engine's `'auto'` rule reads them. A
122
+ * sample with no number gives `{ prefix: '', suffix: '', fractionDigits: 2, '.', ',' }`.
123
+ */
124
+ function moneyTemplateOf(sample) {
125
+ const text = typeof sample === "string" ? sample : "";
126
+ const run = NUMBER_RUN.exec(text);
127
+ if (!run) return DEFAULT_TEMPLATE;
128
+ const read = require_number_text.readNumberText(run[0], { decimalSeparator: "auto" });
129
+ if ("reason" in read) return DEFAULT_TEMPLATE;
130
+ const decimalSeparator = read.decimalMark ?? counterpart(read.groupMark ?? ",");
131
+ return Object.freeze({
132
+ prefix: text.slice(0, run.index),
133
+ suffix: text.slice(run.index + run[0].length),
134
+ fractionDigits: read.scale === 0 ? 0 : read.scale === 3 ? 3 : 2,
135
+ decimalSeparator,
136
+ groupSeparator: read.groupMark ?? counterpart(decimalSeparator)
137
+ });
138
+ }
139
+ /**
140
+ * Money printed with a captured template: the exact major amount (stored / storageScale)
141
+ * rounded half-up to the template's digits, grouped, the sign after the prefix
142
+ * (`moneyTemplateOf('Rp 199.000')` prints IDR 2500050 as `'Rp 25.001'`).
143
+ */
144
+ function formatWithTemplate(m, template) {
145
+ const { value } = require_money.storedDecimal(m);
146
+ const rounded = require_money.formatDecimal(require_money.roundToScale(value, template.fractionDigits, "half-up"));
147
+ const negative = rounded.startsWith("-");
148
+ const [whole, fraction] = (negative ? rounded.slice(1) : rounded).split(".");
149
+ const grouped = require_amount.groupDigits(whole, template.groupSeparator);
150
+ const tail = fraction === void 0 ? "" : `${template.decimalSeparator}${fraction}`;
151
+ return `${template.prefix}${negative ? "-" : ""}${grouped}${tail}${template.suffix}`;
152
+ }
153
+ //#endregion
154
+ exports.formatAmountInput = require_amount.formatAmountInput;
155
+ exports.formatWithTemplate = formatWithTemplate;
156
+ exports.inputPlaceholder = require_amount.inputPlaceholder;
157
+ exports.inputStep = require_amount.inputStep;
158
+ exports.moneyTemplateOf = moneyTemplateOf;
159
+ exports.parseAmountInput = require_amount.parseAmountInput;
160
+ exports.parseDecimalInput = parseDecimalInput;
161
+ exports.parseImportAmount = parseImportAmount;
162
+ exports.parsePercentInput = parsePercentInput;
163
+ exports.parseRateInput = parseRateInput;
@@ -0,0 +1,203 @@
1
+ import { R as DecimalText, b as FractionDigits, i as Money } from "./money-B-3aFjNJ.cjs";
2
+ import { r as Rate } from "./rate-tqK8ijG0.cjs";
3
+ //#region src/input/amount.d.ts
4
+ /** Why typed text is not an acceptable amount. */
5
+ type ParseFailureReason = 'empty' | 'unparseable' | 'too_many_decimals' | 'negative' | 'zero' | 'below_min' | 'above_max';
6
+ interface ParseAmountInputOptions {
7
+ /**
8
+ * Decides the decimal and group separators (unsupported tags fall back to `'en-US'`). Absent
9
+ * (default): the 'auto' rule of `parseImportAmount`, today's admin price-entry rule except the
10
+ * listed behaviour changes: the text and the currency decide (`'29,99'` EUR is 29.99,
11
+ * `'1.299,00'` is 1299, KWD `'1,5'` is 1.5), and a currency storing 0 digits rounds a
12
+ * fraction half-up to a whole unit (`'1200.5'` JPY is 1201).
13
+ */
14
+ locale?: string;
15
+ /**
16
+ * `'.'`: machine decimal text, the value of an `<input type="number">` (browsers always
17
+ * serialise it with a `.` decimal and no grouping). `.` is the decimal (`'.5'` is 0.5), `,`
18
+ * and any grouping are `'unparseable'`, and a currency storing 0 digits rounds a fraction
19
+ * half-up to a whole unit, as admin `numericEntryToMinorUnits` does (`'1200.5'` JPY is
20
+ * 1201, `'1.500'` JPY is 2). TND and IQD `'1.500'` are 1.5. Extra fraction digits in a
21
+ * currency with decimals are `'too_many_decimals'`, never rounded. Every number input must
22
+ * use it; not with `locale`.
23
+ */
24
+ decimalSeparator?: '.';
25
+ /** Default false: a leading `-` gives `'negative'`. */
26
+ allowNegative?: boolean;
27
+ /** Default true; false gives `'zero'` for a zero amount. */
28
+ allowZero?: boolean;
29
+ /** Inclusive lower bound, in the same currency. */
30
+ min?: Money;
31
+ /** Inclusive upper bound, in the same currency. */
32
+ max?: Money;
33
+ /**
34
+ * The stored amount the field was prefilled with (`formatAmountInput(original)`). Text whose
35
+ * value equals it returns `original` unchanged, even when it has more fraction digits than
36
+ * the currency stores (JPY 120050 shows `'1200.50'`), so saving an untouched field never
37
+ * rewrites the amount. Any other text is held to the normal rule. Must be in `currency`.
38
+ */
39
+ original?: Money;
40
+ }
41
+ /**
42
+ * `text` is the canonical machine text on success (`'1250.00'`, `'1200'`, `'1.500'`: the major
43
+ * amount at the currency's storage digits) and the trimmed input on failure.
44
+ */
45
+ type ParseAmountResult = {
46
+ readonly ok: true;
47
+ readonly money: Money;
48
+ readonly text: string;
49
+ } | {
50
+ readonly ok: false;
51
+ readonly reason: ParseFailureReason;
52
+ readonly text: string;
53
+ };
54
+ /**
55
+ * Typed text to Money, one rule for every money field: the currency's symbols and code and all
56
+ * whitespace are stripped; a leading `-` or U+2212 is the sign.
57
+ * - Without `locale` (the chat wizard, any field with no locale): the 'auto' rule decides `.`
58
+ * against `,` (see `parseImportAmount`): `'29,99'` EUR is 29.99, `'1.299,00'` and `'1,299'`
59
+ * are 1299, KWD `'1,5'` is 1.5; a currency storing 0 digits rounds a fraction half-up to a
60
+ * whole unit (`'1200.5'` JPY is 1201).
61
+ * - With `locale`: its decimal separator is the decimal and its group separator is valid only in
62
+ * 3-digit (or Indian lakh) groups; in a currency that stores no fraction (JPY, VND) a separator
63
+ * before exactly three digits in grouping position is grouping (`'1.500'` JPY is 1500).
64
+ * en-US `'29,99'` USD is `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY
65
+ * is `'too_many_decimals'`.
66
+ * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
67
+ * groups (`'1,299'` is `'unparseable'`), TND and IQD `'1.500'` are 1.5, and a currency storing
68
+ * 0 digits rounds a fraction half-up to a whole unit (`'1.5'` JPY is 2).
69
+ * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
70
+ * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
71
+ * `'1200.50'`). An unknown currency, or an `original` in another currency, throws.
72
+ */
73
+ export declare function parseAmountInput(text: string, currency: string, options?: ParseAmountInputOptions): ParseAmountResult;
74
+ /**
75
+ * The text a money field shows for a stored amount, no symbol, exact: a stored amount finer than
76
+ * the storage digits keeps its digits (JPY 120050 is never rounded on display).
77
+ * - Without `locale`: the spelling `parseAmountInput` reads back without a locale. Trailing
78
+ * fraction zeros are dropped (`'12.5'`, `'1200'`, KWD 1500 is `'1.5'`, JPY 120050 is
79
+ * `'1200.5'`), a currency written with a decimal comma (TND, `commaDecimal`) uses `,` and
80
+ * groups with `.` (`'1,125'`, `'1.234,5'`), every other currency `.` and `,`. Two amounts have no
81
+ * such spelling: IQD with a three-digit fraction (`'1.125'` reads as 1125, IQD displays no
82
+ * decimals) and a sub-unit amount of a currency storing 0 digits (`'1200.5'` JPY reads as a
83
+ * whole 1201); pass `{ original: m }` so the untouched text returns `m` itself.
84
+ * - With `locale`: its decimal and group separators and the storage digits (`'12,50'` de-DE).
85
+ * - With `decimalSeparator: '.'` (the value of an `<input type="number">`): `.` decimal, never
86
+ * grouped, trailing zeros dropped (TND 1500 is `'1.5'`, JPY 120050 `'1200.5'`), read back
87
+ * exactly by `parseAmountInput(text, currency, { decimalSeparator: '.' })` (JPY sub-unit
88
+ * amounts through `original`).
89
+ * `grouped` adds group separators (not in `'.'` mode); `digits` overrides the zeros
90
+ * (`'storage'` keeps them, `'trim-zero'` drops them).
91
+ */
92
+ export declare function formatAmountInput(m: Money, options?: {
93
+ locale?: string;
94
+ decimalSeparator?: '.';
95
+ grouped?: boolean;
96
+ digits?: 'storage' | 'trim-zero';
97
+ }): string;
98
+ /** The `step` of a money number input: `'1'` (JPY), `'0.01'` (USD), `'0.001'` (KWD), from the storage digits. */
99
+ export declare function inputStep(currency: string): '1' | '0.01' | '0.001';
100
+ /** The placeholder of a money input: `'0'`, `'0.00'` or `'0.000'`, from the storage digits. */
101
+ export declare function inputPlaceholder(currency: string): '0' | '0.00' | '0.000';
102
+ //#endregion
103
+ //#region src/input/import.d.ts
104
+ interface ImportAmountOptions {
105
+ /**
106
+ * `'auto'` (default): spaces, NBSP, thin spaces and apostrophes are grouping, and the
107
+ * separator engine's 'auto' rule decides `.` against `,` (`'1.299,00'`, `'1.299'` and
108
+ * `'1,299'` are 1299, `'29,99'` is 29.99, `'0,500'` is 0.5, KWD `'1.500'` is 1.5; a `currency`
109
+ * storing 0 digits rounds to a whole unit). An explicit separator validates 3-digit groups of the other.
110
+ */
111
+ decimalSeparator?: '.' | ',' | 'auto';
112
+ /** Strips this currency's symbols and code, and decides the 3-digit rule above. */
113
+ currency?: string;
114
+ /** Default false: a negative amount gives null. */
115
+ allowNegative?: boolean;
116
+ /** Read the first numeric run and ignore the rest (`'22.67 + KDV'`, `'$1,299.00 incl. VAT'`). Default false. */
117
+ allowTrailingText?: boolean;
118
+ }
119
+ /**
120
+ * Amount text from a file or a third party to canonical DecimalText (major units, exactly as
121
+ * written: `'1.299,00'` gives `'1299'`), or null when it is not an amount (empty, exponent,
122
+ * hex, garbage, negative without `allowNegative`). Never 0 for bad input.
123
+ */
124
+ export declare function parseImportAmount(text: string, options?: ImportAmountOptions): DecimalText | null;
125
+ interface DecimalInputOptions {
126
+ /** Most fraction digits allowed (trailing zeros do not count). */
127
+ maxDecimals: number;
128
+ /** Inclusive bounds, decimal text. */
129
+ min?: DecimalText | string;
130
+ max?: DecimalText | string;
131
+ /** Default false. */
132
+ allowNegative?: boolean;
133
+ }
134
+ /**
135
+ * Strict decimal entry: `.` decimal, no grouping, at most `maxDecimals` fraction digits (cost
136
+ * entry at 4, metafields). `'4.5'` gives `'4.5'`, `'.5'` gives `'0.5'`; `'1,000'` is `'unparseable'`.
137
+ */
138
+ export declare function parseDecimalInput(text: string, options: DecimalInputOptions): {
139
+ ok: true;
140
+ value: DecimalText;
141
+ } | {
142
+ ok: false;
143
+ reason: ParseFailureReason;
144
+ };
145
+ //#endregion
146
+ //#region src/input/percent-rate.d.ts
147
+ interface PercentInputOptions {
148
+ /** Inclusive, default 0. */
149
+ min?: number;
150
+ /** Inclusive, default 100. */
151
+ max?: number;
152
+ /** Default 2. */
153
+ maxDecimals?: number;
154
+ /** Decides the separators; default `'en-US'`. */
155
+ locale?: string;
156
+ }
157
+ /**
158
+ * A typed percent (`'20'`, `'12.5'`, `'12,5 %'` in de-DE) as DecimalText. A `%` before or after
159
+ * the number is allowed. Default range 0..100 with 2 decimals; below 0 (with a non-negative
160
+ * `min`) is `'negative'`.
161
+ */
162
+ export declare function parsePercentInput(text: string, options?: PercentInputOptions): {
163
+ ok: true;
164
+ value: DecimalText;
165
+ } | {
166
+ ok: false;
167
+ reason: ParseFailureReason;
168
+ };
169
+ /**
170
+ * A typed exchange rate ("1 store-currency unit equals this many units") as a precise Rate
171
+ * (`fx.rateFromDecimal(value, { encoding: 'precise' })`), or null when the text is not a
172
+ * positive number or the rate is outside `RATE_BOUNDS` (0.0000001 to 1000000000).
173
+ */
174
+ export declare function parseRateInput(text: string, options?: {
175
+ locale?: string;
176
+ }): Rate | null;
177
+ //#endregion
178
+ //#region src/input/template.d.ts
179
+ interface MoneyTemplate {
180
+ /** Text before the number (`'Rp '`, `'€'`), the sign goes after it. */
181
+ readonly prefix: string;
182
+ /** Text after the number (`' CHF'`, `' ₫'`). */
183
+ readonly suffix: string;
184
+ readonly fractionDigits: FractionDigits;
185
+ readonly decimalSeparator: string;
186
+ readonly groupSeparator: string;
187
+ }
188
+ /**
189
+ * The print template of one captured literal (cloner `analyzeMoneyFormat`): prefix and suffix
190
+ * around the number, the decimal separator and digit count of its fraction (1 or 2 digits
191
+ * read as 2, 3 as 3, none as 0), the separator it groups thousands with (else the decimal's
192
+ * counterpart), all as the separator engine's `'auto'` rule reads them. A
193
+ * sample with no number gives `{ prefix: '', suffix: '', fractionDigits: 2, '.', ',' }`.
194
+ */
195
+ export declare function moneyTemplateOf(sample: string): MoneyTemplate;
196
+ /**
197
+ * Money printed with a captured template: the exact major amount (stored / storageScale)
198
+ * rounded half-up to the template's digits, grouped, the sign after the prefix
199
+ * (`moneyTemplateOf('Rp 199.000')` prints IDR 2500050 as `'Rp 25.001'`).
200
+ */
201
+ export declare function formatWithTemplate(m: Money, template: MoneyTemplate): string;
202
+ //#endregion
203
+ export type { DecimalInputOptions, ImportAmountOptions, MoneyTemplate, ParseAmountInputOptions, ParseAmountResult, ParseFailureReason, PercentInputOptions };
@@ -0,0 +1,203 @@
1
+ import { R as DecimalText, b as FractionDigits, i as Money } from "./money-B-3aFjNJ.js";
2
+ import { r as Rate } from "./rate-DBPiYgT1.js";
3
+ //#region src/input/amount.d.ts
4
+ /** Why typed text is not an acceptable amount. */
5
+ type ParseFailureReason = 'empty' | 'unparseable' | 'too_many_decimals' | 'negative' | 'zero' | 'below_min' | 'above_max';
6
+ interface ParseAmountInputOptions {
7
+ /**
8
+ * Decides the decimal and group separators (unsupported tags fall back to `'en-US'`). Absent
9
+ * (default): the 'auto' rule of `parseImportAmount`, today's admin price-entry rule except the
10
+ * listed behaviour changes: the text and the currency decide (`'29,99'` EUR is 29.99,
11
+ * `'1.299,00'` is 1299, KWD `'1,5'` is 1.5), and a currency storing 0 digits rounds a
12
+ * fraction half-up to a whole unit (`'1200.5'` JPY is 1201).
13
+ */
14
+ locale?: string;
15
+ /**
16
+ * `'.'`: machine decimal text, the value of an `<input type="number">` (browsers always
17
+ * serialise it with a `.` decimal and no grouping). `.` is the decimal (`'.5'` is 0.5), `,`
18
+ * and any grouping are `'unparseable'`, and a currency storing 0 digits rounds a fraction
19
+ * half-up to a whole unit, as admin `numericEntryToMinorUnits` does (`'1200.5'` JPY is
20
+ * 1201, `'1.500'` JPY is 2). TND and IQD `'1.500'` are 1.5. Extra fraction digits in a
21
+ * currency with decimals are `'too_many_decimals'`, never rounded. Every number input must
22
+ * use it; not with `locale`.
23
+ */
24
+ decimalSeparator?: '.';
25
+ /** Default false: a leading `-` gives `'negative'`. */
26
+ allowNegative?: boolean;
27
+ /** Default true; false gives `'zero'` for a zero amount. */
28
+ allowZero?: boolean;
29
+ /** Inclusive lower bound, in the same currency. */
30
+ min?: Money;
31
+ /** Inclusive upper bound, in the same currency. */
32
+ max?: Money;
33
+ /**
34
+ * The stored amount the field was prefilled with (`formatAmountInput(original)`). Text whose
35
+ * value equals it returns `original` unchanged, even when it has more fraction digits than
36
+ * the currency stores (JPY 120050 shows `'1200.50'`), so saving an untouched field never
37
+ * rewrites the amount. Any other text is held to the normal rule. Must be in `currency`.
38
+ */
39
+ original?: Money;
40
+ }
41
+ /**
42
+ * `text` is the canonical machine text on success (`'1250.00'`, `'1200'`, `'1.500'`: the major
43
+ * amount at the currency's storage digits) and the trimmed input on failure.
44
+ */
45
+ type ParseAmountResult = {
46
+ readonly ok: true;
47
+ readonly money: Money;
48
+ readonly text: string;
49
+ } | {
50
+ readonly ok: false;
51
+ readonly reason: ParseFailureReason;
52
+ readonly text: string;
53
+ };
54
+ /**
55
+ * Typed text to Money, one rule for every money field: the currency's symbols and code and all
56
+ * whitespace are stripped; a leading `-` or U+2212 is the sign.
57
+ * - Without `locale` (the chat wizard, any field with no locale): the 'auto' rule decides `.`
58
+ * against `,` (see `parseImportAmount`): `'29,99'` EUR is 29.99, `'1.299,00'` and `'1,299'`
59
+ * are 1299, KWD `'1,5'` is 1.5; a currency storing 0 digits rounds a fraction half-up to a
60
+ * whole unit (`'1200.5'` JPY is 1201).
61
+ * - With `locale`: its decimal separator is the decimal and its group separator is valid only in
62
+ * 3-digit (or Indian lakh) groups; in a currency that stores no fraction (JPY, VND) a separator
63
+ * before exactly three digits in grouping position is grouping (`'1.500'` JPY is 1500).
64
+ * en-US `'29,99'` USD is `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY
65
+ * is `'too_many_decimals'`.
66
+ * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
67
+ * groups (`'1,299'` is `'unparseable'`), TND and IQD `'1.500'` are 1.5, and a currency storing
68
+ * 0 digits rounds a fraction half-up to a whole unit (`'1.5'` JPY is 2).
69
+ * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
70
+ * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
71
+ * `'1200.50'`). An unknown currency, or an `original` in another currency, throws.
72
+ */
73
+ export declare function parseAmountInput(text: string, currency: string, options?: ParseAmountInputOptions): ParseAmountResult;
74
+ /**
75
+ * The text a money field shows for a stored amount, no symbol, exact: a stored amount finer than
76
+ * the storage digits keeps its digits (JPY 120050 is never rounded on display).
77
+ * - Without `locale`: the spelling `parseAmountInput` reads back without a locale. Trailing
78
+ * fraction zeros are dropped (`'12.5'`, `'1200'`, KWD 1500 is `'1.5'`, JPY 120050 is
79
+ * `'1200.5'`), a currency written with a decimal comma (TND, `commaDecimal`) uses `,` and
80
+ * groups with `.` (`'1,125'`, `'1.234,5'`), every other currency `.` and `,`. Two amounts have no
81
+ * such spelling: IQD with a three-digit fraction (`'1.125'` reads as 1125, IQD displays no
82
+ * decimals) and a sub-unit amount of a currency storing 0 digits (`'1200.5'` JPY reads as a
83
+ * whole 1201); pass `{ original: m }` so the untouched text returns `m` itself.
84
+ * - With `locale`: its decimal and group separators and the storage digits (`'12,50'` de-DE).
85
+ * - With `decimalSeparator: '.'` (the value of an `<input type="number">`): `.` decimal, never
86
+ * grouped, trailing zeros dropped (TND 1500 is `'1.5'`, JPY 120050 `'1200.5'`), read back
87
+ * exactly by `parseAmountInput(text, currency, { decimalSeparator: '.' })` (JPY sub-unit
88
+ * amounts through `original`).
89
+ * `grouped` adds group separators (not in `'.'` mode); `digits` overrides the zeros
90
+ * (`'storage'` keeps them, `'trim-zero'` drops them).
91
+ */
92
+ export declare function formatAmountInput(m: Money, options?: {
93
+ locale?: string;
94
+ decimalSeparator?: '.';
95
+ grouped?: boolean;
96
+ digits?: 'storage' | 'trim-zero';
97
+ }): string;
98
+ /** The `step` of a money number input: `'1'` (JPY), `'0.01'` (USD), `'0.001'` (KWD), from the storage digits. */
99
+ export declare function inputStep(currency: string): '1' | '0.01' | '0.001';
100
+ /** The placeholder of a money input: `'0'`, `'0.00'` or `'0.000'`, from the storage digits. */
101
+ export declare function inputPlaceholder(currency: string): '0' | '0.00' | '0.000';
102
+ //#endregion
103
+ //#region src/input/import.d.ts
104
+ interface ImportAmountOptions {
105
+ /**
106
+ * `'auto'` (default): spaces, NBSP, thin spaces and apostrophes are grouping, and the
107
+ * separator engine's 'auto' rule decides `.` against `,` (`'1.299,00'`, `'1.299'` and
108
+ * `'1,299'` are 1299, `'29,99'` is 29.99, `'0,500'` is 0.5, KWD `'1.500'` is 1.5; a `currency`
109
+ * storing 0 digits rounds to a whole unit). An explicit separator validates 3-digit groups of the other.
110
+ */
111
+ decimalSeparator?: '.' | ',' | 'auto';
112
+ /** Strips this currency's symbols and code, and decides the 3-digit rule above. */
113
+ currency?: string;
114
+ /** Default false: a negative amount gives null. */
115
+ allowNegative?: boolean;
116
+ /** Read the first numeric run and ignore the rest (`'22.67 + KDV'`, `'$1,299.00 incl. VAT'`). Default false. */
117
+ allowTrailingText?: boolean;
118
+ }
119
+ /**
120
+ * Amount text from a file or a third party to canonical DecimalText (major units, exactly as
121
+ * written: `'1.299,00'` gives `'1299'`), or null when it is not an amount (empty, exponent,
122
+ * hex, garbage, negative without `allowNegative`). Never 0 for bad input.
123
+ */
124
+ export declare function parseImportAmount(text: string, options?: ImportAmountOptions): DecimalText | null;
125
+ interface DecimalInputOptions {
126
+ /** Most fraction digits allowed (trailing zeros do not count). */
127
+ maxDecimals: number;
128
+ /** Inclusive bounds, decimal text. */
129
+ min?: DecimalText | string;
130
+ max?: DecimalText | string;
131
+ /** Default false. */
132
+ allowNegative?: boolean;
133
+ }
134
+ /**
135
+ * Strict decimal entry: `.` decimal, no grouping, at most `maxDecimals` fraction digits (cost
136
+ * entry at 4, metafields). `'4.5'` gives `'4.5'`, `'.5'` gives `'0.5'`; `'1,000'` is `'unparseable'`.
137
+ */
138
+ export declare function parseDecimalInput(text: string, options: DecimalInputOptions): {
139
+ ok: true;
140
+ value: DecimalText;
141
+ } | {
142
+ ok: false;
143
+ reason: ParseFailureReason;
144
+ };
145
+ //#endregion
146
+ //#region src/input/percent-rate.d.ts
147
+ interface PercentInputOptions {
148
+ /** Inclusive, default 0. */
149
+ min?: number;
150
+ /** Inclusive, default 100. */
151
+ max?: number;
152
+ /** Default 2. */
153
+ maxDecimals?: number;
154
+ /** Decides the separators; default `'en-US'`. */
155
+ locale?: string;
156
+ }
157
+ /**
158
+ * A typed percent (`'20'`, `'12.5'`, `'12,5 %'` in de-DE) as DecimalText. A `%` before or after
159
+ * the number is allowed. Default range 0..100 with 2 decimals; below 0 (with a non-negative
160
+ * `min`) is `'negative'`.
161
+ */
162
+ export declare function parsePercentInput(text: string, options?: PercentInputOptions): {
163
+ ok: true;
164
+ value: DecimalText;
165
+ } | {
166
+ ok: false;
167
+ reason: ParseFailureReason;
168
+ };
169
+ /**
170
+ * A typed exchange rate ("1 store-currency unit equals this many units") as a precise Rate
171
+ * (`fx.rateFromDecimal(value, { encoding: 'precise' })`), or null when the text is not a
172
+ * positive number or the rate is outside `RATE_BOUNDS` (0.0000001 to 1000000000).
173
+ */
174
+ export declare function parseRateInput(text: string, options?: {
175
+ locale?: string;
176
+ }): Rate | null;
177
+ //#endregion
178
+ //#region src/input/template.d.ts
179
+ interface MoneyTemplate {
180
+ /** Text before the number (`'Rp '`, `'€'`), the sign goes after it. */
181
+ readonly prefix: string;
182
+ /** Text after the number (`' CHF'`, `' ₫'`). */
183
+ readonly suffix: string;
184
+ readonly fractionDigits: FractionDigits;
185
+ readonly decimalSeparator: string;
186
+ readonly groupSeparator: string;
187
+ }
188
+ /**
189
+ * The print template of one captured literal (cloner `analyzeMoneyFormat`): prefix and suffix
190
+ * around the number, the decimal separator and digit count of its fraction (1 or 2 digits
191
+ * read as 2, 3 as 3, none as 0), the separator it groups thousands with (else the decimal's
192
+ * counterpart), all as the separator engine's `'auto'` rule reads them. A
193
+ * sample with no number gives `{ prefix: '', suffix: '', fractionDigits: 2, '.', ',' }`.
194
+ */
195
+ export declare function moneyTemplateOf(sample: string): MoneyTemplate;
196
+ /**
197
+ * Money printed with a captured template: the exact major amount (stored / storageScale)
198
+ * rounded half-up to the template's digits, grouped, the sign after the prefix
199
+ * (`moneyTemplateOf('Rp 199.000')` prints IDR 2500050 as `'Rp 25.001'`).
200
+ */
201
+ export declare function formatWithTemplate(m: Money, template: MoneyTemplate): string;
202
+ //#endregion
203
+ export type { DecimalInputOptions, ImportAmountOptions, MoneyTemplate, ParseAmountInputOptions, ParseAmountResult, ParseFailureReason, PercentInputOptions };