The tagged-value codec for the conformance corpus (px-35i.4).
Plain JSON scalars, arrays, and objects mean themselves. docs/isa.md
section 3's value domain also includes Date, DateTime, duration, and
:undefined, none of which JSON can represent directly, so each is carried
as an object with a $type key:
{"$type": "date", "value": "2026-08-06"}
{"$type": "datetime", "value": "2026-08-06T12:00:00Z"}
{"$type": "datetime", "value": "2026-08-06T12:00:00.500000Z"}
{"$type": "duration", "value": {"years":0,"months":0,"weeks":0,"days":3,"hours":0,"minutes":0,"seconds":0}}
{"$type": "undefined"}A duration tag's value carries the normative seven-key map from
docs/isa.md:100-106 - years, months, weeks, days, hours,
minutes, seconds, always present, plus milliseconds only when it is
non-zero (predicator's own duration values default milliseconds to 0
the same way the other six units do, so an absent key and a zero key decode
identically).
An object with a literal "$type" key that is not one of predicator's own
values (i.e. supplied inside an authored case's plain map) would be
ambiguous with the tag namespace, so to_json/1 rejects it rather than
silently emitting a tag.
Summary
Types
A JSON-shaped term: what Predicator.Conformance.JSON writes and JSON.decode/1 reads.
Functions
Decodes a tagged-JSON term back into a predicator value.
Encodes a predicator value (Predicator.Types.value/0, plus plain maps
and lists of the same) into the tagged JSON encoding.
Types
A JSON-shaped term: what Predicator.Conformance.JSON writes and JSON.decode/1 reads.
Functions
Decodes a tagged-JSON term back into a predicator value.
The inverse of to_json/1 up to canonicalization: to_json(from_json(to_json(v))) == to_json(v) for every value to_json/1 accepts, and from_json(to_json(v)) == {:ok, v} for every value except a DateTime whose precision field
disagrees with its own sub-second component, which comes back canonicalized.
Returns {:error, {:unknown_type, type}} for an object whose $type is not
one of "date", "datetime", "duration", or "undefined".
Examples
iex> Predicator.Conformance.Values.from_json(%{"$type" => "undefined"})
{:ok, :undefined}
iex> Predicator.Conformance.Values.from_json(%{"$type" => "date", "value" => "2026-08-06"})
{:ok, ~D[2026-08-06]}
iex> Predicator.Conformance.Values.from_json(42)
{:ok, 42}
iex> Predicator.Conformance.Values.from_json(%{"$type" => "nope"})
{:error, {:unknown_type, "nope"}}
Encodes a predicator value (Predicator.Types.value/0, plus plain maps
and lists of the same) into the tagged JSON encoding.
Returns {:error, {:unencodable, term}} for anything outside the ISA
value domain, and for a plain map that contains a literal "$type" key.
Examples
iex> Predicator.Conformance.Values.to_json(:undefined)
{:ok, %{"$type" => "undefined"}}
iex> Predicator.Conformance.Values.to_json(~D[2026-08-06])
{:ok, %{"$type" => "date", "value" => "2026-08-06"}}
iex> Predicator.Conformance.Values.to_json(~U[2026-08-06T12:00:00Z])
{:ok, %{"$type" => "datetime", "value" => "2026-08-06T12:00:00Z"}}
iex> Predicator.Conformance.Values.to_json(~U[2026-08-06T12:00:00.5Z])
{:ok, %{"$type" => "datetime", "value" => "2026-08-06T12:00:00.500000Z"}}
iex> Predicator.Conformance.Values.to_json(42)
{:ok, 42}
iex> Predicator.Conformance.Values.to_json(%{"$type" => "oops"})
{:error, {:unencodable, %{"$type" => "oops"}}}
iex> Predicator.Conformance.Values.to_json({:not, :a, :json, :value})
{:error, {:unencodable, {:not, :a, :json, :value}}}