The canonical JSON encoder that makes ADR-0005's byte-comparable golden traces real.
JSON.encode!/1 alone is not enough: Erlang map iteration order tracks
insertion order only below the small-map threshold, so two runs of the
same producer can build the same keys in different orders and get
different bytes back. encode/1 walks the term itself instead - objects
emit their keys in Enum.sort/1 (lexicographic) order at every nesting
level, arrays emit in the order given (the producer has already put them
in the order docs/wire-format.md requires), and every scalar and string
is delegated to JSON.encode_to_iodata!/1 so escaping is the stdlib's
problem, not this module's.
This encoder rejects nothing: a term outside StatifierUI.Trace.Message.json()
is a producer bug that JSON.encode_to_iodata!/1 raises on, which is the
right failure for an invariant StatifierUI.Trace.Normalizer is supposed
to have already established.
Summary
Functions
Encodes a JSON-ready term to canonical iodata - object keys lexicographic at every level, arrays in the order given.
Renders a list of messages as JSON Lines: one encode_message/1 result
per line, each terminated by "\n" - the shape the golden fixtures use.
Renders one %Message{} to a canonical JSON string - Message.to_map/1
followed by encode_to_string/1.
encode/1, flattened to a binary.
Functions
@spec encode(StatifierUI.Trace.Message.json()) :: iodata()
Encodes a JSON-ready term to canonical iodata - object keys lexicographic at every level, arrays in the order given.
@spec encode_lines([StatifierUI.Trace.Message.t()]) :: String.t()
Renders a list of messages as JSON Lines: one encode_message/1 result
per line, each terminated by "\n" - the shape the golden fixtures use.
@spec encode_message(StatifierUI.Trace.Message.t()) :: String.t()
Renders one %Message{} to a canonical JSON string - Message.to_map/1
followed by encode_to_string/1.
@spec encode_to_string(StatifierUI.Trace.Message.json()) :: String.t()
encode/1, flattened to a binary.