-module(atproto_codegen@emit@union). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/atproto_codegen/emit/union.gleam"). -export([emit_union/4]). -export_type([union_parts/0, variant/0]). -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( " Open-union synthesis: a named type per union field with one variant per\n" " ref plus `Other(Dynamic)`, `$type`-dispatching codecs included.\n" "\n" " The three parts (type, encoder, decoder) are returned separately rather\n" " than as one joined string: the `types` plugin renders the first two, the\n" " `decode-json` plugin the third, and the host interleaves them with the\n" " def's own type/encoder/decoder so the emitted file matches the order the\n" " monolithic emitter used to produce.\n" ). -type union_parts() :: {union_parts, binary(), binary(), binary()}. -type variant() :: {variant, binary(), binary(), list(binary()), binary(), binary()}. -file("src/atproto_codegen/emit/union.gleam", 31). -spec union_variant( atproto_codegen@config:config(), binary(), binary(), binary() ) -> variant(). union_variant(Cfg, Nsid, Name, Ref) -> R = atproto_codegen@naming:parse_ref(Nsid, Ref), Ref_name = atproto_codegen@naming:ref_type_name(erlang:element(5, Cfg), R), Qual = atproto_codegen@naming:qualifier( erlang:element(5, Cfg), Nsid, erlang:element(2, R) ), Type_keys = case erlang:element(3, R) of <<"main"/utf8>> -> [erlang:element(2, R), <<(erlang:element(2, R))/binary, "#main"/utf8>>]; Def_name -> [<<<<(erlang:element(2, R))/binary, "#"/utf8>>/binary, Def_name/binary>>] end, {variant, <>, <>, Type_keys, <<<>/binary, "_fields"/utf8>>, <<<>/binary, "_decoder()"/utf8>>}. -file("src/atproto_codegen/emit/union.gleam", 56). ?DOC( " An open union: one variant per ref plus `Other(Dynamic)`, which round-trips\n" " unrecognized `$type`s untouched instead of destroying them.\n" ). -spec emit_union( atproto_codegen@config:config(), binary(), binary(), list(binary()) ) -> union_parts(). emit_union(Cfg, Nsid, Name, Refs) -> Variants = gleam@list:map( Refs, fun(_capture) -> union_variant(Cfg, Nsid, Name, _capture) end ), Snake = justin:snake_case(Name), Type_lines = begin _pipe = gleam@list:map( Variants, fun(V) -> <<<<<<<<" "/utf8, (erlang:element(2, V))/binary>>/binary, "("/utf8>>/binary, (erlang:element(3, V))/binary>>/binary, ")"/utf8>> end ), lists:append( _pipe, [<<<<" "/utf8, Name/binary>>/binary, "Other(dynamic.Dynamic)"/utf8>>] ) end, Type_def = <<<<<<<<"pub type "/utf8, Name/binary>>/binary, " {\n"/utf8>>/binary, (gleam@string:join(Type_lines, <<"\n"/utf8>>))/binary>>/binary, "\n}"/utf8>>, Encode_arms = begin _pipe@1 = gleam@list:map( Variants, fun(V@1) -> Primary@1 = case erlang:element(4, V@1) of [Primary | _] -> Primary; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"atproto_codegen/emit/union"/utf8>>, function => <<"emit_union"/utf8>>, line => 73, value => _assert_fail, start => 2295, 'end' => 2333, pattern_start => 2306, pattern_end => 2319}) end, <<<<<<<<<<<<" "/utf8, (erlang:element(2, V@1))/binary>>/binary, "(inner) ->\n json.object([\n #(\"$type\", json.string(\""/utf8>>/binary, (atproto_codegen@emit@exprs:escape(Primary@1))/binary>>/binary, "\")),\n .."/utf8>>/binary, (erlang:element(5, V@1))/binary>>/binary, "(inner)\n ])"/utf8>> end ), lists:append( _pipe@1, [<<<<" "/utf8, Name/binary>>/binary, "Other(inner) -> internal.dynamic_to_json(inner)"/utf8>>] ) end, Encoder = <<<<<<<<<<<<"pub fn encode_"/utf8, Snake/binary>>/binary, "(value: "/utf8>>/binary, Name/binary>>/binary, ") -> json.Json {\n case value {\n"/utf8>>/binary, (gleam@string:join(Encode_arms, <<"\n"/utf8>>))/binary>>/binary, "\n }\n}"/utf8>>, Decode_arms = begin _pipe@4 = gleam@list:map( Variants, fun(V@2) -> Patterns = begin _pipe@2 = erlang:element(4, V@2), _pipe@3 = gleam@list:map( _pipe@2, fun(K) -> <<<<"\""/utf8, (atproto_codegen@emit@exprs:escape(K))/binary>>/binary, "\""/utf8>> end ), gleam@string:join(_pipe@3, <<" | "/utf8>>) end, <<<<<<<<<<<<" "/utf8, Patterns/binary>>/binary, " -> decode.map("/utf8>>/binary, (erlang:element(6, V@2))/binary>>/binary, ", "/utf8>>/binary, (erlang:element(2, V@2))/binary>>/binary, ")"/utf8>> end ), lists:append( _pipe@4, [<<<<" _ -> decode.map(decode.dynamic, "/utf8, Name/binary>>/binary, "Other)"/utf8>>] ) end, Decoder = <<<<<<<<<<<<"pub fn "/utf8, Snake/binary>>/binary, "_decoder() -> decode.Decoder("/utf8>>/binary, Name/binary>>/binary, ") {\n use tag <- decode.optional_field(\"$type\", \"\", decode.string)\n case tag {\n"/utf8>>/binary, (gleam@string:join(Decode_arms, <<"\n"/utf8>>))/binary>>/binary, "\n }\n}"/utf8>>, {union_parts, Type_def, Encoder, Decoder}.