Current section
Files
Jump to
Current section
Files
src/mochi@json.erl
-module(mochi@json).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/mochi/json.gleam").
-export([describe_error/1, encode/1, encode_pretty/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" JSON serialization for Dynamic values.\n"
"\n"
" The encoder converts Dynamic into the typed value tree in `mochi/output`\n"
" once, then walks the tree. Errors propagate instead of getting silently\n"
" swallowed as `null`.\n"
).
-file("src/mochi/json.gleam", 23).
?DOC(" Human-readable description of an encode failure.\n").
-spec describe_error(mochi@output:encode_error()) -> binary().
describe_error(Err) ->
case Err of
{unsupported_value, P, K} ->
<<<<<<<<"cannot encode value of kind '"/utf8, K/binary>>/binary,
"' at path '"/utf8>>/binary,
P/binary>>/binary,
"'"/utf8>>
end.
-file("src/mochi/json.gleam", 60).
-spec to_gleam_json(mochi@output:value()) -> gleam@json:json().
to_gleam_json(V) ->
case V of
{v_bool, B} ->
gleam@json:bool(B);
{v_int, I} ->
gleam@json:int(I);
{v_float, F} ->
gleam@json:float(F);
{v_string, S} ->
gleam@json:string(S);
v_null ->
gleam@json:null();
{v_list, Items} ->
gleam@json:array(Items, fun to_gleam_json/1);
{v_object, Fields} ->
_pipe = gleam@list:map(
Fields,
fun(Kv) ->
{erlang:element(1, Kv),
to_gleam_json(erlang:element(2, Kv))}
end
),
gleam@json:object(_pipe)
end.
-file("src/mochi/json.gleam", 55).
-spec encode_value(mochi@output:value()) -> binary().
encode_value(V) ->
_pipe = to_gleam_json(V),
gleam@json:to_string(_pipe).
-file("src/mochi/json.gleam", 35).
?DOC(
" Encode a Dynamic value to a compact JSON string.\n"
"\n"
" Returns an error when the value contains a runtime shape that can't be\n"
" represented in JSON (functions, tuples, pids, references, …) — instead\n"
" of silently emitting `null` for it.\n"
).
-spec encode(gleam@dynamic:dynamic_()) -> {ok, binary()} |
{error, mochi@output:encode_error()}.
encode(Value) ->
gleam@result:map(
mochi@output:from_dynamic(Value),
fun(V) -> encode_value(V) end
).
-file("src/mochi/json.gleam", 144).
-spec pad(integer(), integer()) -> gleam@string_tree:string_tree().
pad(Indent, Depth) ->
case Indent * Depth of
0 ->
gleam@string_tree:new();
N ->
gleam_stdlib:identity(gleam@string:repeat(<<" "/utf8>>, N))
end.
-file("src/mochi/json.gleam", 151).
-spec json_string(binary()) -> gleam@string_tree:string_tree().
json_string(S) ->
_pipe = gleam@json:string(S),
_pipe@1 = gleam@json:to_string(_pipe),
gleam_stdlib:identity(_pipe@1).
-file("src/mochi/json.gleam", 98).
-spec pretty_list(list(mochi@output:value()), integer(), integer()) -> gleam@string_tree:string_tree().
pretty_list(Items, Indent, Depth) ->
Inner_pad = pad(Indent, Depth + 1),
Close_pad = pad(Indent, Depth),
Parts = gleam@list:index_map(
Items,
fun(Item, I) ->
Prefix = case I of
0 ->
gleam@string_tree:new();
_ ->
gleam_stdlib:identity(<<",\n"/utf8>>)
end,
_pipe = Prefix,
_pipe@1 = gleam_stdlib:iodata_append(_pipe, Inner_pad),
gleam_stdlib:iodata_append(
_pipe@1,
pretty_value(Item, Indent, Depth + 1)
)
end
),
_pipe@2 = gleam_stdlib:identity(<<"[\n"/utf8>>),
_pipe@3 = gleam_stdlib:iodata_append(_pipe@2, gleam_stdlib:identity(Parts)),
_pipe@4 = gleam@string_tree:append(_pipe@3, <<"\n"/utf8>>),
_pipe@5 = gleam_stdlib:iodata_append(_pipe@4, Close_pad),
gleam@string_tree:append(_pipe@5, <<"]"/utf8>>).
-file("src/mochi/json.gleam", 83).
-spec pretty_value(mochi@output:value(), integer(), integer()) -> gleam@string_tree:string_tree().
pretty_value(V, Indent, Depth) ->
case V of
{v_bool, true} ->
gleam_stdlib:identity(<<"true"/utf8>>);
{v_bool, false} ->
gleam_stdlib:identity(<<"false"/utf8>>);
v_null ->
gleam_stdlib:identity(<<"null"/utf8>>);
{v_int, I} ->
gleam_stdlib:identity(erlang:integer_to_binary(I));
{v_float, F} ->
gleam_stdlib:identity(gleam_stdlib:float_to_string(F));
{v_string, S} ->
json_string(S);
{v_list, []} ->
gleam_stdlib:identity(<<"[]"/utf8>>);
{v_list, Items} ->
pretty_list(Items, Indent, Depth);
{v_object, []} ->
gleam_stdlib:identity(<<"{}"/utf8>>);
{v_object, Fields} ->
pretty_object(Fields, Indent, Depth)
end.
-file("src/mochi/json.gleam", 42).
?DOC(
" Encode a Dynamic value to a pretty-printed JSON string with the given\n"
" indent width. Walks the value tree directly — does not re-parse JSON.\n"
).
-spec encode_pretty(gleam@dynamic:dynamic_(), integer()) -> {ok, binary()} |
{error, mochi@output:encode_error()}.
encode_pretty(Value, Indent) ->
gleam@result:map(
mochi@output:from_dynamic(Value),
fun(V) -> _pipe = pretty_value(V, Indent, 0),
unicode:characters_to_binary(_pipe) end
).
-file("src/mochi/json.gleam", 118).
-spec pretty_object(
list({binary(), mochi@output:value()}),
integer(),
integer()
) -> gleam@string_tree:string_tree().
pretty_object(Fields, Indent, Depth) ->
Inner_pad = pad(Indent, Depth + 1),
Close_pad = pad(Indent, Depth),
Parts = gleam@list:index_map(
Fields,
fun(Kv, I) ->
Prefix = case I of
0 ->
gleam@string_tree:new();
_ ->
gleam_stdlib:identity(<<",\n"/utf8>>)
end,
_pipe = Prefix,
_pipe@1 = gleam_stdlib:iodata_append(_pipe, Inner_pad),
_pipe@2 = gleam_stdlib:iodata_append(
_pipe@1,
json_string(erlang:element(1, Kv))
),
_pipe@3 = gleam@string_tree:append(_pipe@2, <<": "/utf8>>),
gleam_stdlib:iodata_append(
_pipe@3,
pretty_value(erlang:element(2, Kv), Indent, Depth + 1)
)
end
),
_pipe@4 = gleam_stdlib:identity(<<"{\n"/utf8>>),
_pipe@5 = gleam_stdlib:iodata_append(_pipe@4, gleam_stdlib:identity(Parts)),
_pipe@6 = gleam@string_tree:append(_pipe@5, <<"\n"/utf8>>),
_pipe@7 = gleam_stdlib:iodata_append(_pipe@6, Close_pad),
gleam@string_tree:append(_pipe@7, <<"}"/utf8>>).