josdejong / lossless-json

Parse JSON without risk of losing numeric information
MIT License
430 stars 28 forks source link

Support for +-Infinity and NaN #242

Closed y-polonsk closed 2 years ago

y-polonsk commented 2 years ago

I suppose this may be outside the scope of this project, but I think it would be really helpful to support stringifying and parsing of Infinity and NaN tokens. In my case I would like to support both big decimal numbers as well as Infinity and NaN, and I cannot seem to find a library that does both.

Thanks.

josdejong commented 2 years ago

Infinity and NaN are no valid values in JSON (see https://www.json.org), but with a combination of a BigNumber library and a JSON reviver and stringifier, you can achieve what you want. For example mathjs has that in place:

import { bignumber, reviver } from 'mathjs'

const x = bignumber('230088910051792740019')
// BigNumber 230088910051792740019
const str = JSON.stringify(x)
// '{"mathjs":"BigNumber","value":"230088910051792740019"}'
const x2 = JSON.parse(str, reviver)
// BigNumber 230088910051792740019

const inf = bignumber('Infinity')
// BigNumber Infinity
const infStr = JSON.stringify(inf)
// '{"mathjs":"BigNumber","value":"Infinity"}'
const inf2 = JSON.parse(infStr, reviver)
// BigNumber Infinity

Is that what you mean?

mathjs docs on serialization: https://mathjs.org/docs/core/serialization.html

y-polonsk commented 2 years ago

Thanks for quick response. I think the above approach is not the same though. From what I understand, this approach (using replacer/reviver) will allow to represent Infinity and NaN as strings "Infinity" and "NaN" inside JSON. Is this correct? But this is not exactly the same as having numeric values of Ininity and NaN. I would like to be able to parse/stringify something like this:

{ "x": Infinity, "y": NaN }

Note that the values are without quotes. When parsing JSON i would like to know if the value is numeric type or string. So Infinity and "Infinity" are not exactly the same. The first is numeric value Infinity (typeof val === "number") and the second is a string (typeof val === "string"). I believe the above can only be achieved by changing the parser and stringifier to introduce new tokens. Please correct me if I m wrong.

josdejong commented 2 years ago

I understand what you mean, but the numeric values Infinity and NaN are simply not supported in the JSON standard, so you can't use them (unless you manage to get the standard changed).

So if you need these kind of values (and the same holds for Date for example), you will have to use a reviver and stringifier and encode your data somehow as a string.

y-polonsk commented 2 years ago

Thanks. I understand that it is not in the JSON standard. You can close the issue if you'd like. Note though that there are other implementations that support it, e.g. json5. However they don't seem to support handling numbers with large precision like your library does. So far, I couldn't find any viable solution when both features (Infinity/NaN and big numbers) are needed.

josdejong commented 2 years ago

👍

I couldn't find any viable solution when both features

I shared a solution that supports both BigNumbers and Infinity/NaN above. I understand it's not exactly what you would like to see, but at least it is a working solution. You can write such a JSON reviver and stringifier yourself and use your favorite BigNumber library.

I'll close this issue how. I hope you'll come up with something that works for your case.