FEEL values as JSON text and the other way (D-81): what to json(value) and from json(value) of Camunda do.
A value as JSON. null is null; a boolean, a number and a string are theirs (a number as it is written in FEEL, never
with an exponent); a list is an array and a context an object, with its keys in the order of the entries (D-135). A date, a time, a date and time and a duration are a string of their text: "2023-06-14", "10:00:00+02:00", "P3Y",
and a date and time in a zone that has an id has the offset and then the id, as Java writes it,
"2025-11-24T10:00:00+01:00[Europe/Berlin]". A value with no JSON, a range or a function, is :error.
JSON as a value. An object is a context, an array a list, a number a number (the digits are kept, 2.50 has the scale of
two), a string a string: a string that looks like a date is a string, as in the documentation's
from json("\"2023-06-14\""). Text that is not JSON, and text with anything after the value but white space, is :error,
and so is a number outside the range of a number of FEEL.
iex> Feel.Extension.Camunda.Json.encode(%{"b" => [Decimal.new("1.50"), nil, true], "a" => "x"})
{:ok, ~s({"a":"x","b":[1.50,null,true]})}
iex> context = Feel.Value.Context.new([{"b", Decimal.new(1)}, {"a", "x"}])
iex> Feel.Extension.Camunda.Json.encode(context)
{:ok, ~s({"b":1,"a":"x"})}
iex> {:ok, value} = Feel.Extension.Camunda.Json.decode(~s({"b": [1, 2.50, "2023-06-14", null], "a": 1}))
iex> Feel.Value.Context.keys(value)
["b", "a"]
iex> Feel.Value.Context.to_host(value)
%{"a" => Decimal.new("1"), "b" => [Decimal.new("1"), Decimal.new("2.50"), "2023-06-14", nil]}
iex> Feel.Extension.Camunda.Json.decode("{")
:error
Summary
Functions
The value of a JSON text, or :error if it is not one, or has a number that FEEL cannot have.
The JSON text of a value, or :error if it has none.
Functions
@spec decode(String.t()) :: {:ok, Feel.Value.t()} | :error
The value of a JSON text, or :error if it is not one, or has a number that FEEL cannot have.
@spec encode(Feel.Value.t(), non_neg_integer() | :infinity) :: {:ok, String.t()} | {:over, pos_integer()} | :error
The JSON text of a value, or :error if it has none.
With max (:infinity for none) a text that is longer than that many bytes is {:over, size}, with the bytes counted
when it passed max, and the rest of it is not written: a list can hold the same string a hundred thousand times,
and the text is as long as the product of their sizes. The walk goes on to the end all the same, as far as it looks for
a value that has no JSON, which is :error wherever it is: it is the answer when the text is short, and the cap is
not a reason to give another.
iex> Feel.Extension.Camunda.Json.encode([Decimal.new(1), "foo"], 100)
{:ok, ~s([1,"foo"])}
iex> Feel.Extension.Camunda.Json.encode([Decimal.new(1), "foo"], 6)
{:over, 9}
iex> Feel.Extension.Camunda.Json.encode(["foo", Feel.Value.Range.new(1, 2)], 3)
:error