Tramaj.Json
- Package
- purescript-tramaj-purs
- Repository
- lucasdicioccio/purescript-tramaj-purs
JSON as Tramaj reads and writes it: like any JSON value, except that a
number is an integer or a float, decided by its text (reference.md §3,
node-json.md Numbers, decisions.md §18).
This module exists because the host's own JSON cannot carry that
difference. JSON.parse reads 3 and 3.0 as the same number, and
JSON.stringify writes both as 3, so Data.Argonaut.Core.Json, which
is that host value, has nowhere to keep the type. Everything Tramaj
takes in or hands out as JSON (the context, a Node's payloads, an
expression program's result, the symbolic envelope) is therefore this
Json, read by jsonParser and written by stringify.
The names follow Data.Argonaut.Core and Data.Argonaut.Parser where
they mean the same thing, so that moving a caller over is mostly a
change of import. fromArgonaut and toArgonaut bridge to a host
value, and say what each direction costs.
Integer range. This implementation has the guaranteed range only,
-(2^53 - 1) to 2^53 - 1 (reference.md §13): an integer is held in
a double, which is exact there and nowhere beyond.
#Json Source
data JsonA JSON value whose numbers keep their type.
JInt and JFloat both hold a double. A JInt is a whole number, and
a value Tramaj produced is always inside the integer range, finite and
not a negative zero. jsonParser is more lenient on purpose, so that
refusing a number is left to whoever decodes the value (see
normalizeNumbers): it reads an integer-form number beyond the range
as the JInt of the nearest double, and a float too large for a
double as a JFloat infinity.
Constructors
Instances
#fromBoolean Source
fromBoolean :: Boolean -> Json#fromString Source
fromString :: String -> Json#jsonParser Source
jsonParser :: String -> Either String JsonParses JSON text (RFC 8259), typing each number by its text: one with
neither a fraction nor an exponent is an integer, one with either is a
float, so 3 is an integer and 3.0 and 3e0 are floats.
No number is refused here: see Json for what a number beyond the
value domain is read as, and normalizeNumbers for where it is
refused. Of two equal keys in one object, the last wins.
#stringifyWithIndent Source
stringifyWithIndent :: Int -> Json -> StringAs stringify, on several lines, each level indented by the given
number of spaces. An empty array or object stays on one line.
#formatInteger Source
formatInteger :: Number -> StringAn integer as its decimal digits. ECMAScript's Number::toString
writes every whole number below 1e21 that way, which covers the
integer range; show is that text with .0 appended.
#formatFloat Source
formatFloat :: Number -> StringA float as the shortest round-trip text of ECMAScript's
Number::toString, with .0 appended when that text has neither a
fraction nor an exponent: 1.0, 0.1, 100000000000.0, 1e+21.
That is exactly what PureScript's show gives a Number.
An infinity has no JSON text. It is written as a float no double holds, which reads back as the same infinity.
#inIntegerRange Source
inIntegerRange :: Number -> BooleanWhether a double is an integer this implementation holds exactly: a
whole number in the guaranteed range, Number.isSafeInteger.
#normalizeNumbers Source
normalizeNumbers :: Json -> Either String JsonThe numbers of a JSON value as Tramaj values, at any depth, or why one
of them cannot be one. This is the one place that decides what a JSON
number outside the value domain becomes (reference.md §3,
node-json.md Decoding):
- an integer-form number outside the integer range is refused, not rounded;
- a float too large for a double is refused, not read as an infinity;
- a negative zero is zero:
-0.0is0.0and-0is0.
#fromArgonaut Source
fromArgonaut :: Json -> JsonA host JSON value, as JSON.parse or a host program built it. A host
number has no type of its own, so this is where this implementation
classifies one: a whole number in the integer range is an integer, and
any other number is a float. A float that happens to be whole (3.0)
therefore arrives as the integer 3; a host that must pass it as a
float builds a JFloat, or reads its JSON text with jsonParser.
#toArgonaut Source
toArgonaut :: Json -> JsonDown to a host JSON value, where the two number types become one
again: JSON.stringify of the result writes the float 3.0 as 3.
Use stringify to write JSON text that keeps the type.
Structural, with object keys unordered. An integer and a float are never equal, whatever they hold:
3and3.0are two values.