Functional Weave
Code in TypeScript

money.parse@1.0.0

README.md

2,562 bytes · view raw

# money.parse

Turns text such as `"£1,234.50"`, `"1.234,50 €"`, `"CHF 1'234.50"` or
`"1 234,56 kr"` into a `Money` in integer minor units, and refuses anything it
would have to guess at.

**The caller says the currency and the number style.** `"1.234"` is one
thousand two hundred and thirty-four in Germany and one point two three four in
the UK, and no amount of cleverness can tell which from the text alone. So:

| style            | groups thousands with                 | decimal mark |
|------------------|---------------------------------------|--------------|
| `comma-dot`      | `,`                                   | `.`          |
| `dot-comma`      | `.`                                   | `,`          |
| `space-comma`    | space, no-break space or narrow no-break space | `,` |
| `apostrophe-dot` | `'` or `’`                            | `.`          |

Grouping is optional, but when it is used it must be real thousands grouping:
one to three digits, then groups of exactly three (`1,234,567`). `1,23,456`
(Indian lakh grouping) and `12,34` are refused rather than read as something.

**The decimal places come from ISO 4217** via `money.currency-digits`. More
decimals than the currency has is an error, not a rounding: `"£1.234"` in the
`comma-dot` style is refused, because either it is a typo or it is a German
thousand, and neither should become £1.23. Fewer are fine: `"£5"` and `"£5.5"`
are 500 and 550 pence. Yen take no decimal part at all.

**A symbol must agree with the currency.** One currency symbol or ISO code may
appear, before the number or after it, with at most one space (ordinary,
no-break or narrow no-break) between. It must be the currency's own ISO code
or one of its symbols in `data/currency-symbols.json`; `"€5"` parsed as GBP is
an error. `"$"` is accepted for every dollar and peso in the table because the
caller has already said which one it is; `"US$"` is only accepted for USD.

**Signs.** A leading `-`, before or after a leading symbol (`-£5`, `£-5`).
Accounting brackets, trailing minus signs and `+` are refused.

**Whitespace.** Ordinary spaces around the whole text are ignored; nothing
else is trimmed.

The result must fit in ±(2^53 - 1) minor units. Anything else - letters,
two decimal marks, a group separator from another style, an empty string - is
`"… is not a valid amount"`.

The symbol table is a convenience for recognising common symbols, not a
standard; codes are always accepted. The decimal places are ISO 4217 List One
(see `money.currency-digits` for the source).