-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>>).