@amboras-dev/money 0.3.0 → 0.4.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 CHANGED
@@ -252,6 +252,8 @@ parseAmountInput('1,2345', 'USD') // { ok: false, reason
252
252
  parseAmountInput('99.000', 'VND') // 99000 (3-digit tail groups in a currency without decimals)
253
253
  parseAmountInput('12.99.', 'USD') // { ok: false, reason: 'unparseable' } (groups must be thousands or lakh)
254
254
  parseAmountInput('1.500', 'TND', { decimalSeparator: '.' }) // 1.5 (an <input type="number"> value: '.' is always the decimal)
255
+ parseAmountInput('1.5', 'JPY', { decimalSeparator: '.' }) // { ok: false, reason: 'too_many_decimals' } (never rounded to 2)
256
+ parseAmountInput('1.0', 'JPY', { decimalSeparator: '.' }) // 1 (trailing zeros carry no extra precision)
255
257
  formatAmountInput(money(1500, 'TND'), { decimalSeparator: '.' }) // '1.5' (the number input's prefill, read back exactly)
256
258
  formatAmountInput(money(123456789, 'USD'), { grouped: true, locale: 'de-DE' }) // '1.234.567,89'
257
259
  parseImportAmount('1.299,00') // '1299'
@@ -266,9 +268,11 @@ inputStep('KWD') // '0.001'
266
268
  With `locale` it reads that locale's separators: the group separator is valid only in thousands groups (`'1,234,567'`) or Indian lakh groups (`'12,34,567'`: three digits on the right, then pairs), and only when every group fits (`'1,2345'` and `'12,3,456'` are `unparseable`), and extra digits are `too_many_decimals` in every currency.
267
269
  The locale's decimal separator is never read as grouping: in a currency storing 0 digits, en-US `'1.234'`, `'19.999'` and `'1.000'` JPY are `too_many_decimals` (a thousands group to some, a fraction to others, and trailing zeros would let `'1.000'` through as ¥1); grouping uses the locale's group separator (`'1,234'` en-US, `'1.234'` de-DE).
268
270
  **Every number input (`<input type="number">`) must pass `{ decimalSeparator: '.' }`**: browsers always serialise its value with a `.` decimal and no grouping, so the free-text rule would misread it (TND and IQD `'1.500'` are 1,500 there, 1.5 here).
269
- In `'.'` mode `.` is the decimal, `,` and grouping are `unparseable`, a zero whole part may be omitted (`'.5'` is 0.5), and a currency storing 0 digits rounds a fraction half-up to a whole unit, as admin `numericEntryToMinorUnits` does (`'1200.5'` JPY is 1201).
270
- It equals that function on every `.`-only value within the storage digits (`test/input/input.test.ts`), except one class:
271
- - `extra-fraction-digits`: in a currency storing 2 or 3 digits, more fraction digits than it stores is `too_many_decimals`, never rounded (`'1.239'` USD, admin 124 cents; KWD `'1.0005'`, admin 1001).
271
+ In `'.'` mode `.` is the decimal, `,` and grouping are `unparseable`, and a zero whole part may be omitted (`'.5'` is 0.5).
272
+ More fraction digits than the currency stores is `too_many_decimals` in every currency, never rounded: since 0.4.0 a currency storing 0 digits refuses any fraction (`'1.5'`, `'1.234'` and `'1200.5'` JPY and KRW; 0.3.0 rounded them half-up to ¥2, ¥1 and ¥1,201).
273
+ Trailing zeros carry no extra precision, so `'1.0'` and `'1.00'` JPY are ¥1, as with a locale; a sub-unit prefill (JPY 120050, `'1200.5'`) still reads back exactly through `original`.
274
+ It equals admin `numericEntryToMinorUnits` on every `.`-only value within the storage digits (`test/input/input.test.ts`), except one class:
275
+ - `extra-fraction-digits`: more fraction digits than the currency stores is `too_many_decimals`, never rounded (`'1.239'` USD, admin 124 cents; KWD `'1.0005'`, admin 1001; `'1.5'` JPY, admin ¥2).
272
276
  Failure reasons: `empty`, `unparseable`, `too_many_decimals`, `negative`, `zero`, `below_min`, `above_max`.
273
277
  - `formatAmountInput(m, { locale, decimalSeparator, grouped, digits })`: the field text for a stored amount, no symbol, exact: a sub-unit stored amount keeps its digits (JPY 120050, which Medusa writes today, is `'1200.5'`), never rounded on display.
274
278
  Without `locale` it prints the spelling `parseAmountInput` reads back without a locale: trailing fraction zeros dropped (USD `'12.5'`, KWD 1500 `'1.5'`, IQD 10000000 `'10000'`), and TND, which writes a decimal comma, with `,` as the decimal and `.` as the group (`'1,125'`, `'1.234,5'`).
package/dist/ai.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_money = require("./money-DWBjuuEK.cjs");
3
3
  const require_format = require("./format-92fzvTXY.cjs");
4
4
  const require_number_text = require("./number-text-CWuVwrlg.cjs");
5
- const require_amount = require("./amount-CwFzcxUl.cjs");
5
+ const require_amount = require("./amount-Bzxw9aD4.cjs");
6
6
  // src/ai/mentions.ts
7
7
  const ACTIVE = require_money.CURRENCIES.filter((c) => c.status === "active");
8
8
  const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
package/dist/ai.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { $ as describeValue, E as resolveCurrency, Q as MoneyError, l as toMajorNumber, m as currencyMarks, n as fromMajor, pt as toDecimalText, s as storedDecimal, u as CURRENCIES } from "./money-BxbAw7BP.js";
2
2
  import { t as formatMoney } from "./format-BJC513u4.js";
3
3
  import { n as readNumberText, t as digitGroupingSource } from "./number-text-Bj-gZXiF.js";
4
- import { s as parseAmountInput } from "./amount-DHFOK2Yd.js";
4
+ import { s as parseAmountInput } from "./amount-off8IMBJ.js";
5
5
  // src/ai/mentions.ts
6
6
  const ACTIVE = CURRENCIES.filter((c) => c.status === "active");
7
7
  const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -109,7 +109,8 @@ const ENTRY_SEPARATORS = {
109
109
  * `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY is `'too_many_decimals'`.
110
110
  * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
111
111
  * groups (`'1,299'` is `'unparseable'`), TND and IQD `'1.500'` are 1.5, and a currency storing
112
- * 0 digits rounds a fraction half-up to a whole unit (`'1.5'` JPY is 2).
112
+ * 0 digits refuses any fraction as `'too_many_decimals'` (`'1.5'` JPY), never rounded;
113
+ * trailing zeros read as whole (`'1.0'` JPY is 1).
113
114
  * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
114
115
  * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
115
116
  * `'1200.50'`), except the ambiguous zero-digit text above. An unknown currency, or an `original` in another currency, throws.
@@ -144,7 +145,7 @@ function parseAmountInput(text, currency, options = {}) {
144
145
  }
145
146
  const result = entryMoney(value, info, {
146
147
  ...options,
147
- roundExtraDigits: mode !== "locale" && info.storageDigits === 0
148
+ roundExtraDigits: mode === "auto" && info.storageDigits === 0
148
149
  });
149
150
  if (!result.ok) return {
150
151
  ok: false,
@@ -109,7 +109,8 @@ const ENTRY_SEPARATORS = {
109
109
  * `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY is `'too_many_decimals'`.
110
110
  * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
111
111
  * groups (`'1,299'` is `'unparseable'`), TND and IQD `'1.500'` are 1.5, and a currency storing
112
- * 0 digits rounds a fraction half-up to a whole unit (`'1.5'` JPY is 2).
112
+ * 0 digits refuses any fraction as `'too_many_decimals'` (`'1.5'` JPY), never rounded;
113
+ * trailing zeros read as whole (`'1.0'` JPY is 1).
113
114
  * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
114
115
  * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
115
116
  * `'1200.50'`), except the ambiguous zero-digit text above. An unknown currency, or an `original` in another currency, throws.
@@ -144,7 +145,7 @@ function parseAmountInput(text, currency, options = {}) {
144
145
  }
145
146
  const result = entryMoney(value, info, {
146
147
  ...options,
147
- roundExtraDigits: mode !== "locale" && info.storageDigits === 0
148
+ roundExtraDigits: mode === "auto" && info.storageDigits === 0
148
149
  });
149
150
  if (!result.ok) return {
150
151
  ok: false,
package/dist/input.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_money = require("./money-DWBjuuEK.cjs");
3
3
  const require_number_text = require("./number-text-CWuVwrlg.cjs");
4
4
  const require_rate = require("./rate-CEjWTATc.cjs");
5
- const require_amount = require("./amount-CwFzcxUl.cjs");
5
+ const require_amount = require("./amount-Bzxw9aD4.cjs");
6
6
  // src/input/import.ts
7
7
  /**
8
8
  * Amount text from a file or a third party to canonical DecimalText (major units, exactly as
package/dist/input.d.cts CHANGED
@@ -14,11 +14,11 @@ interface ParseAmountInputOptions {
14
14
  /**
15
15
  * `'.'`: machine decimal text, the value of an `<input type="number">` (browsers always
16
16
  * serialise it with a `.` decimal and no grouping). `.` is the decimal (`'.5'` is 0.5), `,`
17
- * and any grouping are `'unparseable'`, and a currency storing 0 digits rounds a fraction
18
- * half-up to a whole unit, as admin `numericEntryToMinorUnits` does (`'1200.5'` JPY is
19
- * 1201, `'1.500'` JPY is 2). TND and IQD `'1.500'` are 1.5. Extra fraction digits in a
20
- * currency with decimals are `'too_many_decimals'`, never rounded. Every number input must
21
- * use it; not with `locale`.
17
+ * and any grouping are `'unparseable'`. More fraction digits than the currency stores are
18
+ * `'too_many_decimals'`, never rounded, in every currency: a currency storing 0 digits
19
+ * refuses any fraction (`'1.5'`, `'1.234'` and `'1200.5'` JPY), while trailing zeros carry no
20
+ * extra precision and read as whole (`'1.0'` and `'1.00'` JPY are 1). TND and IQD `'1.500'`
21
+ * are 1.5. Every number input must use it; not with `locale`.
22
22
  */
23
23
  decimalSeparator?: '.';
24
24
  /** Default false: a leading `-` gives `'negative'`. */
@@ -65,7 +65,8 @@ type ParseAmountResult = {
65
65
  * `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY is `'too_many_decimals'`.
66
66
  * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
67
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).
68
+ * 0 digits refuses any fraction as `'too_many_decimals'` (`'1.5'` JPY), never rounded;
69
+ * trailing zeros read as whole (`'1.0'` JPY is 1).
69
70
  * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
70
71
  * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
71
72
  * `'1200.50'`), except the ambiguous zero-digit text above. An unknown currency, or an `original` in another currency, throws.
package/dist/input.d.ts CHANGED
@@ -14,11 +14,11 @@ interface ParseAmountInputOptions {
14
14
  /**
15
15
  * `'.'`: machine decimal text, the value of an `<input type="number">` (browsers always
16
16
  * serialise it with a `.` decimal and no grouping). `.` is the decimal (`'.5'` is 0.5), `,`
17
- * and any grouping are `'unparseable'`, and a currency storing 0 digits rounds a fraction
18
- * half-up to a whole unit, as admin `numericEntryToMinorUnits` does (`'1200.5'` JPY is
19
- * 1201, `'1.500'` JPY is 2). TND and IQD `'1.500'` are 1.5. Extra fraction digits in a
20
- * currency with decimals are `'too_many_decimals'`, never rounded. Every number input must
21
- * use it; not with `locale`.
17
+ * and any grouping are `'unparseable'`. More fraction digits than the currency stores are
18
+ * `'too_many_decimals'`, never rounded, in every currency: a currency storing 0 digits
19
+ * refuses any fraction (`'1.5'`, `'1.234'` and `'1200.5'` JPY), while trailing zeros carry no
20
+ * extra precision and read as whole (`'1.0'` and `'1.00'` JPY are 1). TND and IQD `'1.500'`
21
+ * are 1.5. Every number input must use it; not with `locale`.
22
22
  */
23
23
  decimalSeparator?: '.';
24
24
  /** Default false: a leading `-` gives `'negative'`. */
@@ -65,7 +65,8 @@ type ParseAmountResult = {
65
65
  * `'unparseable'`; de-DE `'29,99'` EUR is 29.99; en-US `'1200.5'` JPY is `'too_many_decimals'`.
66
66
  * - With `decimalSeparator: '.'` (every `<input type="number">`): `.` is the decimal, nothing
67
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).
68
+ * 0 digits refuses any fraction as `'too_many_decimals'` (`'1.5'` JPY), never rounded;
69
+ * trailing zeros read as whole (`'1.0'` JPY is 1).
69
70
  * Otherwise more fraction digits than the currency stores is `'too_many_decimals'`, never rounded
70
71
  * (`'1,2345'` USD). Text equal to `original` returns it unchanged (JPY 120050 shown as
71
72
  * `'1200.50'`), except the ambiguous zero-digit text above. An unknown currency, or an `original` in another currency, throws.
package/dist/input.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { B as decimalOf, Q as MoneyError, at as fractionDigitsOf, dt as roundToScale, it as formatDecimal, pt as toDecimalText, s as storedDecimal, tt as compareDecimal } from "./money-BxbAw7BP.js";
2
2
  import { n as readNumberText } from "./number-text-Bj-gZXiF.js";
3
3
  import { c as rateFromDecimal, o as rate } from "./rate-D6S2_wgZ.js";
4
- import { a as inputStep, i as inputPlaceholder, n as formatAmountInput, o as localeSeparators, r as groupDigits, s as parseAmountInput, t as decimalOfText } from "./amount-DHFOK2Yd.js";
4
+ import { a as inputStep, i as inputPlaceholder, n as formatAmountInput, o as localeSeparators, r as groupDigits, s as parseAmountInput, t as decimalOfText } from "./amount-off8IMBJ.js";
5
5
  // src/input/import.ts
6
6
  /**
7
7
  * Amount text from a file or a third party to canonical DecimalText (major units, exactly as
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amboras-dev/money",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Money for Amboras: the storage rule (x100 for every currency, x1000 for seven), a generated currency registry, exact decimal arithmetic, Medusa amount parsing, PSP wire codecs, SQL builders, FX, commerce and billing math, agent-tool money and text entry. Zero dependencies.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {