json: use a simpler, more consumable number representation (#1195)

Amounts in JSON are now rendered as simple Numbers with up to 10
decimal places, instead of Decimal objects which would in some cases
have 255 digits, too many for most JSON parsers to handle.
A provisional fix, see the comment in Json.hs for more detail.
This commit is contained in:
Simon Michael 2020-02-25 09:26:36 -08:00
parent ca62312f55
commit a33a9d61c2
2 changed files with 37 additions and 2 deletions

View File

@ -46,7 +46,34 @@ import Hledger.Data.Types
instance ToJSON Status
instance ToJSON GenericSourcePos
-- https://github.com/simonmichael/hledger/issues/1195
-- The default JSON output for Decimal is not very practical for JSON consumers.
-- With repeating decimals, which can occur with implicit transaction prices,
-- decimalMantissa will use Decimal's maximum allowance of 255 digits.
-- (And secondly, it sometimes uses scientific notation, and that sometimes
-- looks wrong, eg e254 instead of e-1 ?)
-- JSON output is intended to be consumed by diverse apps and
-- programming languages, which can't necessarily handle numbers with
-- more than 15 or so significant digits. Eg, from #1195:
--
-- > - JavaScript uses 64-bit IEEE754 numbers which can only accurately
-- > represent integers up to 9007199254740991(i.e. a maximum of 15 digits).
-- > - Javas largest integers are limited to18digits.
-- > - Python3 integers are unbounded.
-- > - Python2 integers are limited to18digits like Java.
-- > - C and C++ number limits depend on platformmost platforms should
-- > be able to represent unsigned integers up to 64bits, i.e. 19digits.
--
-- It's not yet clear what is a good compromise.
-- For now, we make Decimals look like floating point numbers with
-- up to 10 decimal places (and an unbounded number of integer digits).
-- This still allows unparseable numbers to be generated in theory,
-- but hopefully this won't happen in practice.
instance ToJSON Decimal
where
toJSON d = Number $ fromRational $ toRational $ roundTo 10 d
instance ToJSON Amount
instance ToJSON AmountStyle
instance ToJSON Side

View File

@ -801,12 +801,20 @@ Some notes about JSON output:
- The JSON output from hledger commands is essentially the same as the
JSON served by [hledger-web's JSON API](hledger-web.html#json-api),
but pretty printed, using line breaks and indentation.
- Our pretty printer has the ability to elide data in certain cases -
Our pretty printer has the ability to elide data in certain cases -
rendering non-strings as if they were strings, or displaying "FOO.."
instead of FOO's full details. This should never happen in hledger's
JSON output; if you see otherwise, please report as a bug.
- Quantities are represented in hledger as Decimal values storing up
to 255 significant digits, eg for repeating decimals. This is too
many digits and too much hassle for most JSON users, so in JSON we
show simple Numbers with up to 10 decimal places. The number of
significant digits is still unbounded, but that part is under your
control. We hope this approach will not cause problems in practice;
if you find otherwise, please let us know. (Cf
[#1195](https://github.com/simonmichael/hledger/issues/1195))
## Regular expressions
hledger uses [regular expressions](http://www.regular-expressions.info) in a number of places: