src/rally@generator@codec.erl

-module(rally@generator@codec).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/rally/generator/codec.gleam").
-export([generate/5, generate_json_type_registry_js/1, generate_json_decode_dispatch/1, generate_json_codecs/2, client_context_seeds/2]).
-export_type([codec_file/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(
    " Client package codec and page module generator.\n"
    "\n"
    " Generates:\n"
    " - codec_ffi.mjs — JS typed decoders (from walker-discovered types)\n"
    " - types.gleam — ClientMsg type for RPC dispatch\n"
    " - codec.gleam — decode_flags utility\n"
    " - Per-page client modules — tree-shaken page source\n"
    " - rally_runtime/effect.gleam — client-side effect shim\n"
).

-type codec_file() :: {codec_file, binary(), binary()}.

-file("src/rally/generator/codec.gleam", 452).
-spec drop_unused_effect_import(binary(), list(binary())) -> binary().
drop_unused_effect_import(Source, Aliases) ->
    Alias_still_used = gleam@list:any(
        Aliases,
        fun(Alias) ->
            gleam_stdlib:contains_string(Source, <<Alias/binary, "."/utf8>>)
        end
    ),
    case Alias_still_used of
        true ->
            Source;

        false ->
            _pipe = Source,
            _pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>),
            _pipe@2 = gleam@list:filter(
                _pipe@1,
                fun(Line) ->
                    not gleam_stdlib:string_starts_with(
                        gleam@string:trim(Line),
                        <<"import rally_runtime/effect"/utf8>>
                    )
                end
            ),
            gleam@string:join(_pipe@2, <<"\n"/utf8>>)
    end.

-file("src/rally/generator/codec.gleam", 441).
-spec replace_send_to_server_calls(binary(), list(binary())) -> binary().
replace_send_to_server_calls(Source, Aliases) ->
    gleam@list:fold(Aliases, Source, fun(Acc, Alias) -> _pipe = Acc,
            _pipe@1 = gleam@string:replace(
                _pipe,
                <<Alias/binary, ".send_to_server("/utf8>>,
                <<"send_to_server("/utf8>>
            ),
            gleam@string:replace(
                _pipe@1,
                <<Alias/binary, ".send_to_server ("/utf8>>,
                <<"send_to_server ("/utf8>>
            ) end).

-file("src/rally/generator/codec.gleam", 859).
-spec json_client_encoder(libero@field_type:field_type(), binary()) -> binary().
json_client_encoder(Ft, Var) ->
    case Ft of
        string_field ->
            <<<<"json.string("/utf8, Var/binary>>/binary, ")"/utf8>>;

        int_field ->
            <<<<"json.int("/utf8, Var/binary>>/binary, ")"/utf8>>;

        float_field ->
            <<<<"json.float("/utf8, Var/binary>>/binary, ")"/utf8>>;

        bool_field ->
            <<<<"json.bool("/utf8, Var/binary>>/binary, ")"/utf8>>;

        nil_field ->
            <<"json.null()"/utf8>>;

        bit_array_field ->
            erlang:error(#{gleam_error => panic,
                    message => <<"client encoder: BitArray not supported in client-side JSON encoding"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"rally/generator/codec"/utf8>>,
                    function => <<"json_client_encoder"/utf8>>,
                    line => 867});

        {user_type, Module_path, Type_name, _} ->
            Qual = libero@walker:qualified_atom_name(Module_path, Type_name),
            <<<<<<<<"json_codecs.json_encode_"/utf8, Qual/binary>>/binary,
                        "("/utf8>>/binary,
                    Var/binary>>/binary,
                ")"/utf8>>;

        {list_of, Inner} ->
            <<<<<<<<"json.array("/utf8, Var/binary>>/binary,
                        ", of: fn(x) { "/utf8>>/binary,
                    (json_client_encoder(Inner, <<"x"/utf8>>))/binary>>/binary,
                " })"/utf8>>;

        {option_of, Inner@1} ->
            <<<<<<<<<<<<<<"(fn(opt) { case opt {"/utf8,
                                        " None -> json.object([#(\"type\", json.string(\"gleam/option.Option\")), #(\"variant\", json.string(\"None\")), #(\"fields\", json.object([]))])"/utf8>>/binary,
                                    " Some(x) -> json.object([#(\"type\", json.string(\"gleam/option.Option\")), #(\"variant\", json.string(\"Some\")), #(\"fields\", json.array(["/utf8>>/binary,
                                (json_client_encoder(Inner@1, <<"x"/utf8>>))/binary>>/binary,
                            "], of: fn(y) { y }))])"/utf8>>/binary,
                        " } })("/utf8>>/binary,
                    Var/binary>>/binary,
                ")"/utf8>>;

        {result_of, Ok, Err} ->
            <<<<<<<<<<<<<<<<<<"(fn(res) { case res {"/utf8,
                                                " Ok(x) -> json.object([#(\"type\", json.string(\"gleam/result.Result\")), #(\"variant\", json.string(\"Ok\")), #(\"fields\", json.array(["/utf8>>/binary,
                                            (json_client_encoder(
                                                Ok,
                                                <<"x"/utf8>>
                                            ))/binary>>/binary,
                                        "], of: fn(y) { y }))])"/utf8>>/binary,
                                    " Error(x) -> json.object([#(\"type\", json.string(\"gleam/result.Result\")), #(\"variant\", json.string(\"Error\")), #(\"fields\", json.array(["/utf8>>/binary,
                                (json_client_encoder(Err, <<"x"/utf8>>))/binary>>/binary,
                            "], of: fn(y) { y }))])"/utf8>>/binary,
                        " } })("/utf8>>/binary,
                    Var/binary>>/binary,
                ")"/utf8>>;

        {dict_of, _, _} ->
            erlang:error(#{gleam_error => panic,
                    message => <<"client encoder: Dict not supported in client-side JSON encoding"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"rally/generator/codec"/utf8>>,
                    function => <<"json_client_encoder"/utf8>>,
                    line => 899});

        {tuple_of, _} ->
            erlang:error(#{gleam_error => panic,
                    message => <<"client encoder: Tuple not supported in client-side JSON encoding"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"rally/generator/codec"/utf8>>,
                    function => <<"json_client_encoder"/utf8>>,
                    line => 901});

        {type_var, _} ->
            erlang:error(#{gleam_error => panic,
                    message => <<"client encoder: type variable not supported in client-side JSON encoding"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"rally/generator/codec"/utf8>>,
                    function => <<"json_client_encoder"/utf8>>,
                    line => 903})
    end.

-file("src/rally/generator/codec.gleam", 907).
-spec json_primitive_encoder(libero@field_type:field_type(), binary()) -> binary().
json_primitive_encoder(Ft, Var) ->
    json_client_encoder(Ft, Var).

-file("src/rally/generator/codec.gleam", 374).
-spec generate_json_page_msg_encoder(list(rally@types:variant_info()), binary()) -> binary().
generate_json_page_msg_encoder(Variants, Page_module_path) ->
    Arms = begin
        _pipe = gleam@list:map(
            Variants,
            fun(V) ->
                Type_id = <<Page_module_path/binary, ".Msg"/utf8>>,
                Fields = case erlang:element(3, V) of
                    [] ->
                        <<"json.object([])"/utf8>>;

                    _ ->
                        Pairs = gleam@list:map(
                            erlang:element(3, V),
                            fun(F) ->
                                <<<<<<<<"#(\""/utf8,
                                                (erlang:element(2, F))/binary>>/binary,
                                            "\", "/utf8>>/binary,
                                        (json_primitive_encoder(
                                            erlang:element(3, F),
                                            erlang:element(2, F)
                                        ))/binary>>/binary,
                                    ")"/utf8>>
                            end
                        ),
                        <<<<"json.object(["/utf8,
                                (gleam@string:join(Pairs, <<", "/utf8>>))/binary>>/binary,
                            "])"/utf8>>
                end,
                <<<<<<<<<<<<<<<<<<<<<<<<"    "/utf8,
                                                                (erlang:element(
                                                                    2,
                                                                    V
                                                                ))/binary>>/binary,
                                                            " -> json.object([\n"/utf8>>/binary,
                                                        "      #(\"type\", json.string(\""/utf8>>/binary,
                                                    Type_id/binary>>/binary,
                                                "\")),\n"/utf8>>/binary,
                                            "      #(\"variant\", json.string(\""/utf8>>/binary,
                                        (erlang:element(2, V))/binary>>/binary,
                                    "\")),\n"/utf8>>/binary,
                                "      #(\"fields\", "/utf8>>/binary,
                            Fields/binary>>/binary,
                        "),\n"/utf8>>/binary,
                    "    ])"/utf8>>
            end
        ),
        gleam@string:join(_pipe, <<"\n"/utf8>>)
    end,
    <<<<"\npub fn json_encode_msg(msg: Msg) -> json.Json {\n  case msg {\n"/utf8,
            Arms/binary>>/binary,
        "\n  }\n}\n"/utf8>>.

-file("src/rally/generator/codec.gleam", 415).
-spec effect_module_aliases(binary()) -> list(binary()).
effect_module_aliases(Source) ->
    case glance:module(Source) of
        {error, unexpected_end_of_input} ->
            [<<"rally_effect"/utf8>>];

        {error, {unexpected_token, _, _}} ->
            [<<"rally_effect"/utf8>>];

        {ok, Ast} ->
            _pipe = erlang:element(2, Ast),
            _pipe@1 = gleam@list:filter_map(
                _pipe,
                fun(Def) ->
                    Import_ = erlang:element(3, Def),
                    case erlang:element(3, Import_) =:= <<"rally_runtime/effect"/utf8>> of
                        false ->
                            {error, nil};

                        true ->
                            case erlang:element(4, Import_) of
                                {some, {named, Name}} ->
                                    {ok, Name};

                                _ ->
                                    {ok, <<"effect"/utf8>>}
                            end
                    end
                end
            ),
            (fun(Aliases) -> case Aliases of
                    [] ->
                        [<<"rally_effect"/utf8>>];

                    _ ->
                        Aliases
                end end)(_pipe@1)
    end.

-file("src/rally/generator/codec.gleam", 304).
?DOC(
    " Post-process tree-shaken source for client usage:\n"
    " - Replace rally_effect.send_to_server with local wrapper\n"
    " - Add transport import and local send_to_server wrapper\n"
    " - For JSON protocol, generate json_encode_msg for page Msg type\n"
).
-spec post_process_page(
    binary(),
    binary(),
    binary(),
    rally@types:page_contract(),
    binary()
) -> binary().
post_process_page(Source, Variant_name, Protocol, Contract, Page_module_path) ->
    Effect_aliases = effect_module_aliases(Source),
    Has_send_to_server = gleam@list:any(
        Effect_aliases,
        fun(Alias) ->
            gleam_stdlib:contains_string(
                Source,
                <<Alias/binary, ".send_to_server("/utf8>>
            )
            orelse gleam_stdlib:contains_string(
                Source,
                <<Alias/binary, ".send_to_server ("/utf8>>
            )
        end
    ),
    Json_msg_encoder = case {Protocol, erlang:element(3, Contract)} of
        {<<"json"/utf8>>, []} ->
            <<""/utf8>>;

        {<<"json"/utf8>>, _} ->
            Encoder = generate_json_page_msg_encoder(
                erlang:element(3, Contract),
                Page_module_path
            ),
            Has_user_type = gleam@list:any(
                erlang:element(3, Contract),
                fun(V) ->
                    gleam@list:any(
                        erlang:element(3, V),
                        fun(F) -> case erlang:element(3, F) of
                                {user_type, _, _, _} ->
                                    true;

                                _ ->
                                    false
                            end end
                    )
                end
            ),
            case Has_user_type of
                true ->
                    <<"import generated/json_codecs as json_codecs\n\n"/utf8,
                        Encoder/binary>>;

                false ->
                    Encoder
            end;

        {_, _} ->
            <<""/utf8>>
    end,
    Wrapper = case Has_send_to_server of
        true ->
            Transport_import = <<"\nimport generated/transport\n"/utf8>>,
            Json_import = case Protocol of
                <<"json"/utf8>> ->
                    <<"import gleam/json\n"/utf8>>;

                _ ->
                    <<""/utf8>>
            end,
            Encoded_msg = case Protocol of
                <<"json"/utf8>> ->
                    <<"json_encode_msg(msg)"/utf8>>;

                _ ->
                    <<"msg"/utf8>>
            end,
            <<<<<<<<<<<<<<<<<<<<<<<<Transport_import/binary,
                                                            Json_import/binary>>/binary,
                                                        "\nfn send_to_server(msg: a) -> effect.Effect(b) {\n"/utf8>>/binary,
                                                    "  effect.from(fn(_dispatch) {\n"/utf8>>/binary,
                                                "    transport.send_to_server(\""/utf8>>/binary,
                                            Variant_name/binary>>/binary,
                                        "\", "/utf8>>/binary,
                                    Encoded_msg/binary>>/binary,
                                ")\n"/utf8>>/binary,
                            "    Nil\n"/utf8>>/binary,
                        "  })\n"/utf8>>/binary,
                    "}\n"/utf8>>/binary,
                Json_msg_encoder/binary>>;

        false ->
            <<""/utf8>>
    end,
    _pipe = Source,
    _pipe@1 = replace_send_to_server_calls(_pipe, Effect_aliases),
    _pipe@2 = drop_unused_effect_import(_pipe@1, Effect_aliases),
    (fun(S) -> <<S/binary, Wrapper/binary>> end)(_pipe@2).

-file("src/rally/generator/codec.gleam", 296).
?DOC(
    " Convert a server module path to a client page path.\n"
    " \"pages/home_\" -> \"pages/home_\"\n"
    " \"pages/article/slug_\" -> \"pages/article/slug_\"\n"
).
-spec page_module_path(binary()) -> binary().
page_module_path(Module_path) ->
    Module_path.

-file("src/rally/generator/codec.gleam", 64).
?DOC(" Generate per-page client modules from tree-shaken source.\n").
-spec generate_page_modules(
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    list(binary()),
    binary()
) -> list(codec_file()).
generate_page_modules(Contracts, Server_symbols, Protocol) ->
    gleam@list:filter_map(
        Contracts,
        fun(Pair) ->
            {Route, Contract} = Pair,
            case erlang:element(7, Contract) of
                false ->
                    {error, nil};

                true ->
                    Shaken = rally@tree_shaker:shake(
                        erlang:element(10, Contract),
                        Server_symbols
                    ),
                    Page_path = page_module_path(erlang:element(5, Route)),
                    Content = post_process_page(
                        Shaken,
                        erlang:element(3, Route),
                        Protocol,
                        Contract,
                        erlang:element(5, Route)
                    ),
                    {ok,
                        {codec_file,
                            <<<<"src/"/utf8, Page_path/binary>>/binary,
                                ".gleam"/utf8>>,
                            Content}}
            end
        end
    ).

-file("src/rally/generator/codec.gleam", 587).
-spec emit_rally_effect_ffi() -> binary().
emit_rally_effect_ffi() ->
    <<"// Generated by Rally — do not edit.

export function navigate(path) {
  globalThis.history?.pushState(null, \"\", path);
  globalThis.dispatchEvent(new PopStateEvent(\"popstate\"));
}

export function setDarkMode(enabled) {
  document.documentElement.classList.toggle(\"dark\", enabled);
  document.cookie = \"__rally_dark_mode=\" + (enabled ? \"1\" : \"0\") + \";path=/;max-age=31536000;SameSite=Lax\";
}

export function setLang(lang) {
  document.cookie = \"__rally_lang=\" + lang + \";path=/;max-age=31536000;SameSite=Lax\";
}

export function readDarkModeCookie() {
  var c = document.cookie;
  if (c.includes('__rally_dark_mode=1')) return true;
  if (c.includes('__rally_dark_mode=0')) return false;
  return window.matchMedia('(prefers-color-scheme:dark)').matches;
}

export function readLangCookie() {
  var m = document.cookie.match(/(?:^|;)\\s*__rally_lang=([^;]+)/);
  if (m) return m[1];
  var lang = navigator.language || navigator.userLanguage || '';
  return lang ? lang.split('-')[0] : 'en';
}
"/utf8>>.

-file("src/rally/generator/codec.gleam", 482).
-spec emit_rally_effect_shim(binary()) -> binary().
emit_rally_effect_shim(Protocol) ->
    Rpc_fn = case Protocol of
        <<"json"/utf8>> ->
            <<<<<<<<<<<<"\npub fn rpc(msg: a, on_response on_response: fn(b) -> msg) -> Effect(msg) {\n"/utf8,
                                    "  effect.from(fn(dispatch) {\n"/utf8>>/binary,
                                "    transport.send_rpc(types.json_encode_client_msg(transport.coerce(msg)), fn(response) {\n"/utf8>>/binary,
                            "      dispatch(on_response(transport.coerce(response)))\n"/utf8>>/binary,
                        "    })\n"/utf8>>/binary,
                    "  })\n"/utf8>>/binary,
                "}\n"/utf8>>;

        _ ->
            <<<<<<<<<<<<"\npub fn rpc(msg: a, on_response on_response: fn(b) -> msg) -> Effect(msg) {\n"/utf8,
                                    "  effect.from(fn(dispatch) {\n"/utf8>>/binary,
                                "    transport.send_rpc(msg, fn(response) {\n"/utf8>>/binary,
                            "      dispatch(on_response(response))\n"/utf8>>/binary,
                        "    })\n"/utf8>>/binary,
                    "  })\n"/utf8>>/binary,
                "}\n"/utf8>>
    end,
    Client_context_fn = case Protocol of
        <<"json"/utf8>> ->
            <<<<"\npub fn send_to_client_context(_msg: a) -> Effect(b) {\n"/utf8,
                    "  panic as \"send_to_client_context: JSON client context encoding is not yet implemented\"\n"/utf8>>/binary,
                "}\n"/utf8>>;

        _ ->
            <<<<<<<<<<"\npub fn send_to_client_context(msg: a) -> Effect(b) {\n"/utf8,
                                "  effect.from(fn(_dispatch) {\n"/utf8>>/binary,
                            "    transport.send_to_server(\"__ClientContext__\", msg)\n"/utf8>>/binary,
                        "    Nil\n"/utf8>>/binary,
                    "  })\n"/utf8>>/binary,
                "}\n"/utf8>>
    end,
    Imports = case Protocol of
        <<"json"/utf8>> ->
            <<"import generated/transport\nimport generated/types\n\n"/utf8>>;

        _ ->
            <<"import generated/transport\n\n"/utf8>>
    end,
    <<<<<<<<Imports/binary,
                    "// Generated by Rally — do not edit.
////
//// Client-side effect shim. Provides the same API as
//// rally_runtime/effect but backed by the client transport.

import lustre/effect.{type Effect}"/utf8>>/binary,
                Rpc_fn/binary>>/binary,
            Client_context_fn/binary>>/binary,
        "
pub fn navigate(path: String) -> Effect(a) {
  effect.from(fn(_dispatch) {
    do_navigate(path)
    Nil
  })
}

@external(javascript, \"./rally_effect_ffi.mjs\", \"navigate\")
fn do_navigate(_path: String) -> Nil {
  Nil
}

pub fn none() -> Effect(a) {
  effect.none()
}

pub fn from(f: fn(fn(a) -> Nil) -> Nil) -> Effect(a) {
  effect.from(f)
}

pub fn get_ws_session() -> String {
  \"\"
}

pub fn set_dark_mode(enabled: Bool) -> Effect(a) {
  effect.from(fn(_dispatch) {
    do_set_dark_mode(enabled)
    Nil
  })
}

@external(javascript, \"./rally_effect_ffi.mjs\", \"setDarkMode\")
fn do_set_dark_mode(_enabled: Bool) -> Nil {
  Nil
}

pub fn set_lang(lang: String) -> Effect(a) {
  effect.from(fn(_dispatch) {
    do_set_lang(lang)
    Nil
  })
}

@external(javascript, \"./rally_effect_ffi.mjs\", \"setLang\")
fn do_set_lang(_lang: String) -> Nil {
  Nil
}

@external(javascript, \"./rally_effect_ffi.mjs\", \"readDarkModeCookie\")
pub fn read_dark_mode() -> Bool {
  False
}

@external(javascript, \"./rally_effect_ffi.mjs\", \"readLangCookie\")
pub fn read_lang() -> String {
  \"\"
}
"/utf8>>.

-file("src/rally/generator/codec.gleam", 952).
-spec etf_codec_gleam_content() -> binary().
etf_codec_gleam_content() ->
    <<"// Generated by Rally — do not edit.
////
//// Typed flags helpers. Delegates to Libero for the actual
//// base64 + ETF + typed decode pipeline.

import libero/error.{type DecodeError}
import libero/wire

/// Decode SSR flags and apply a typed decoder in one call.
/// The decoder_name is the function name in codec_ffi.mjs,
/// e.g. \"decode_pages_home__model\".
pub fn decode_flags_typed(
  flags: String,
  decoder_name: String,
) -> Result(a, DecodeError) {
  wire.decode_flags_typed(flags:, decoder_name:)
}
"/utf8>>.

-file("src/rally/generator/codec.gleam", 920).
-spec json_codec_gleam_content() -> binary().
json_codec_gleam_content() ->
    <<"// Generated by Rally — do not edit.
////
//// Typed flags helpers. Parses JSON SSR flags and returns
//// the parsed value. Typed decode is handled by the JS facade
//// (typedJsonToGleamValue) for response/push, and by the
//// generated json_decode_dispatch for SSR model hydration
//// on the server side.

import gleam/dynamic.{type Dynamic}
import gleam/result
import libero/json/error.{type JsonError}

@external(javascript, \"./protocol_wire.mjs\", \"decode_flags_typed\")
fn decode_json_flags(flags: String) -> Result(Dynamic, List(JsonError))

@external(javascript, \"./protocol_wire.mjs\", \"identity\")
fn coerce(value: a) -> b

/// Decode SSR flags from JSON text.
/// Returns the parsed JSON value as Dynamic; the caller
/// type-casts via coerce or uses typedJsonToGleamValue on the JS side.
pub fn decode_flags_typed(
  flags: String,
  _decoder_name: String,
) -> Result(a, List(JsonError)) {
  use parsed <- result.try(decode_json_flags(flags))
  Ok(coerce(parsed))
}
"/utf8>>.

-file("src/rally/generator/codec.gleam", 913).
-spec emit_codec_gleam(binary()) -> binary().
emit_codec_gleam(Protocol) ->
    case Protocol of
        <<"json"/utf8>> ->
            json_codec_gleam_content();

        _ ->
            etf_codec_gleam_content()
    end.

-file("src/rally/generator/codec.gleam", 845).
-spec collect_user_type_modules(libero@field_type:field_type()) -> list(binary()).
collect_user_type_modules(Ft) ->
    case Ft of
        {user_type, Module_path, _, _} ->
            [Module_path];

        {list_of, Inner} ->
            collect_user_type_modules(Inner);

        {option_of, Inner@1} ->
            collect_user_type_modules(Inner@1);

        {result_of, Ok, Err} ->
            lists:append(
                collect_user_type_modules(Ok),
                collect_user_type_modules(Err)
            );

        {dict_of, K, V} ->
            lists:append(
                collect_user_type_modules(K),
                collect_user_type_modules(V)
            );

        {tuple_of, Elems} ->
            gleam@list:flat_map(Elems, fun collect_user_type_modules/1);

        _ ->
            []
    end.

-file("src/rally/generator/codec.gleam", 620).
-spec to_pascal_case(binary()) -> binary().
to_pascal_case(Name) ->
    _pipe = Name,
    _pipe@1 = gleam@string:split(_pipe, <<"_"/utf8>>),
    _pipe@2 = gleam@list:map(
        _pipe@1,
        fun(Word) -> case gleam_stdlib:string_pop_grapheme(Word) of
                {ok, {First, Rest}} ->
                    <<(string:uppercase(First))/binary, Rest/binary>>;

                {error, nil} ->
                    Word
            end end
    ),
    gleam@string:join(_pipe@2, <<""/utf8>>).

-file("src/rally/generator/codec.gleam", 818).
?DOC(
    " Build a resolver that uses the last segment when unique, or the full\n"
    " underscored path when two modules share the same last segment.\n"
).
-spec build_type_alias_resolver(list(libero@scanner:handler_endpoint())) -> fun((binary()) -> binary()).
build_type_alias_resolver(Endpoints) ->
    All_modules = begin
        _pipe = Endpoints,
        _pipe@1 = gleam@list:flat_map(
            _pipe,
            fun(E) ->
                gleam@list:flat_map(
                    erlang:element(6, E),
                    fun(P) ->
                        collect_user_type_modules(erlang:element(2, P))
                    end
                )
            end
        ),
        gleam@list:unique(_pipe@1)
    end,
    Segment_counts = gleam@list:fold(
        All_modules,
        maps:new(),
        fun(Acc, Mod) ->
            Seg = libero@field_type:last_segment(Mod),
            Count = case gleam_stdlib:map_get(Acc, Seg) of
                {ok, N} ->
                    N + 1;

                {error, nil} ->
                    1
            end,
            gleam@dict:insert(Acc, Seg, Count)
        end
    ),
    fun(Module_path) ->
        Seg@1 = libero@field_type:last_segment(Module_path),
        case gleam_stdlib:map_get(Segment_counts, Seg@1) of
            {ok, N@1} when N@1 > 1 ->
                gleam@string:replace(Module_path, <<"/"/utf8>>, <<"_"/utf8>>);

            _ ->
                Seg@1
        end
    end.

-file("src/rally/generator/codec.gleam", 649).
-spec emit_types_gleam(
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    list(libero@scanner:handler_endpoint()),
    binary()
) -> binary().
emit_types_gleam(_, Endpoints, Protocol) ->
    Resolve_alias = build_type_alias_resolver(Endpoints),
    Client_msg_type = case Endpoints of
        [] ->
            <<""/utf8>>;

        _ ->
            Variants = gleam@list:map(
                Endpoints,
                fun(E) ->
                    Variant_name = to_pascal_case(
                        <<"server_"/utf8, (erlang:element(3, E))/binary>>
                    ),
                    case erlang:element(6, E) of
                        [] ->
                            <<"  "/utf8, Variant_name/binary>>;

                        Params ->
                            Fields = gleam@list:map(
                                Params,
                                fun(P) ->
                                    <<<<(erlang:element(1, P))/binary,
                                            ": "/utf8>>/binary,
                                        (libero@field_type:to_gleam_source_with_alias(
                                            erlang:element(2, P),
                                            Resolve_alias
                                        ))/binary>>
                                end
                            ),
                            <<<<<<<<"  "/utf8, Variant_name/binary>>/binary,
                                        "("/utf8>>/binary,
                                    (gleam@string:join(Fields, <<", "/utf8>>))/binary>>/binary,
                                ")"/utf8>>
                    end
                end
            ),
            <<<<"\npub type ClientMsg {\n"/utf8,
                    (gleam@string:join(Variants, <<"\n"/utf8>>))/binary>>/binary,
                "\n}\n"/utf8>>
    end,
    Json_encode_fn = case Protocol of
        <<"json"/utf8>> ->
            case Endpoints of
                [] ->
                    <<""/utf8>>;

                _ ->
                    Json_import = <<"import gleam/json\n"/utf8>>,
                    Arms = begin
                        _pipe = gleam@list:map(
                            Endpoints,
                            fun(E@1) ->
                                Variant_name@1 = to_pascal_case(
                                    <<"server_"/utf8,
                                        (erlang:element(3, E@1))/binary>>
                                ),
                                case erlang:element(8, E@1) of
                                    {some, {Type_module, Type_name}} ->
                                        Param_pattern = case erlang:element(
                                            6,
                                            E@1
                                        ) of
                                            [] ->
                                                <<""/utf8>>;

                                            Params@1 ->
                                                <<<<"("/utf8,
                                                        (gleam@string:join(
                                                            gleam@list:map(
                                                                Params@1,
                                                                fun(P@1) ->
                                                                    <<<<(erlang:element(
                                                                                1,
                                                                                P@1
                                                                            ))/binary,
                                                                            ": "/utf8>>/binary,
                                                                        (erlang:element(
                                                                            1,
                                                                            P@1
                                                                        ))/binary>>
                                                                end
                                                            ),
                                                            <<", "/utf8>>
                                                        ))/binary>>/binary,
                                                    ")"/utf8>>
                                        end,
                                        Field_encoders = case erlang:element(
                                            6,
                                            E@1
                                        ) of
                                            [] ->
                                                <<"json.object([])"/utf8>>;

                                            Params@2 ->
                                                Pairs = gleam@list:map(
                                                    Params@2,
                                                    fun(P@2) ->
                                                        <<<<<<<<"#(\""/utf8,
                                                                        (erlang:element(
                                                                            1,
                                                                            P@2
                                                                        ))/binary>>/binary,
                                                                    "\", "/utf8>>/binary,
                                                                (json_primitive_encoder(
                                                                    erlang:element(
                                                                        2,
                                                                        P@2
                                                                    ),
                                                                    erlang:element(
                                                                        1,
                                                                        P@2
                                                                    )
                                                                ))/binary>>/binary,
                                                            ")"/utf8>>
                                                    end
                                                ),
                                                <<<<"json.object(["/utf8,
                                                        (gleam@string:join(
                                                            Pairs,
                                                            <<", "/utf8>>
                                                        ))/binary>>/binary,
                                                    "])"/utf8>>
                                        end,
                                        <<<<<<<<<<<<<<<<<<<<<<<<<<<<Variant_name@1/binary,
                                                                                                Param_pattern/binary>>/binary,
                                                                                            " -> json.object([\n"/utf8>>/binary,
                                                                                        "        #(\"type\", json.string(\""/utf8>>/binary,
                                                                                    Type_module/binary>>/binary,
                                                                                "."/utf8>>/binary,
                                                                            Type_name/binary>>/binary,
                                                                        "\")),\n"/utf8>>/binary,
                                                                    "        #(\"variant\", json.string(\""/utf8>>/binary,
                                                                Type_name/binary>>/binary,
                                                            "\")),\n"/utf8>>/binary,
                                                        "        #(\"fields\", "/utf8>>/binary,
                                                    Field_encoders/binary>>/binary,
                                                "),\n"/utf8>>/binary,
                                            "      ])"/utf8>>;

                                    none ->
                                        Field_encoders@1 = gleam@list:map(
                                            erlang:element(6, E@1),
                                            fun(P@3) ->
                                                <<<<<<<<"#(\""/utf8,
                                                                (erlang:element(
                                                                    1,
                                                                    P@3
                                                                ))/binary>>/binary,
                                                            "\", "/utf8>>/binary,
                                                        (json_primitive_encoder(
                                                            erlang:element(
                                                                2,
                                                                P@3
                                                            ),
                                                            erlang:element(
                                                                1,
                                                                P@3
                                                            )
                                                        ))/binary>>/binary,
                                                    ")"/utf8>>
                                            end
                                        ),
                                        <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Variant_name@1/binary,
                                                                                                    "("/utf8>>/binary,
                                                                                                (gleam@string:join(
                                                                                                    gleam@list:map(
                                                                                                        erlang:element(
                                                                                                            6,
                                                                                                            E@1
                                                                                                        ),
                                                                                                        fun(
                                                                                                            P@4
                                                                                                        ) ->
                                                                                                            <<<<(erlang:element(
                                                                                                                        1,
                                                                                                                        P@4
                                                                                                                    ))/binary,
                                                                                                                    ": "/utf8>>/binary,
                                                                                                                (erlang:element(
                                                                                                                    1,
                                                                                                                    P@4
                                                                                                                ))/binary>>
                                                                                                        end
                                                                                                    ),
                                                                                                    <<", "/utf8>>
                                                                                                ))/binary>>/binary,
                                                                                            ") -> json.object([\n"/utf8>>/binary,
                                                                                        "        #(\"type\", json.string(\""/utf8>>/binary,
                                                                                    (erlang:element(
                                                                                        2,
                                                                                        E@1
                                                                                    ))/binary>>/binary,
                                                                                "."/utf8>>/binary,
                                                                            (to_pascal_case(
                                                                                <<"server_"/utf8,
                                                                                    (erlang:element(
                                                                                        3,
                                                                                        E@1
                                                                                    ))/binary>>
                                                                            ))/binary>>/binary,
                                                                        "\")),\n"/utf8>>/binary,
                                                                    "        #(\"variant\", json.string(\""/utf8>>/binary,
                                                                (to_pascal_case(
                                                                    <<"server_"/utf8,
                                                                        (erlang:element(
                                                                            3,
                                                                            E@1
                                                                        ))/binary>>
                                                                ))/binary>>/binary,
                                                            "\")),\n"/utf8>>/binary,
                                                        "        #(\"fields\", json.object(["/utf8>>/binary,
                                                    (gleam@string:join(
                                                        Field_encoders@1,
                                                        <<", "/utf8>>
                                                    ))/binary>>/binary,
                                                "])),\n"/utf8>>/binary,
                                            "      ])"/utf8>>
                                end
                            end
                        ),
                        gleam@string:join(_pipe, <<"\n"/utf8>>)
                    end,
                    <<<<<<Json_import/binary,
                                "\npub fn json_encode_client_msg(msg: ClientMsg) -> json.Json {\n  case msg {\n    "/utf8>>/binary,
                            Arms/binary>>/binary,
                        "\n  }\n}\n"/utf8>>
            end;

        _ ->
            <<""/utf8>>
    end,
    All_modules = begin
        _pipe@1 = Endpoints,
        _pipe@2 = gleam@list:flat_map(
            _pipe@1,
            fun(E@2) ->
                gleam@list:flat_map(
                    erlang:element(6, E@2),
                    fun(P@5) ->
                        collect_user_type_modules(erlang:element(2, P@5))
                    end
                )
            end
        ),
        gleam@list:unique(_pipe@2)
    end,
    Type_imports = begin
        _pipe@3 = All_modules,
        _pipe@4 = gleam@list:map(
            _pipe@3,
            fun(Mod) ->
                Alias = Resolve_alias(Mod),
                case Alias =:= libero@field_type:last_segment(Mod) of
                    true ->
                        <<"import "/utf8, Mod/binary>>;

                    false ->
                        <<<<<<"import "/utf8, Mod/binary>>/binary, " as "/utf8>>/binary,
                            Alias/binary>>
                end
            end
        ),
        _pipe@5 = gleam@string:join(_pipe@4, <<"\n"/utf8>>),
        (fun(S) -> case S of
                <<""/utf8>> ->
                    <<""/utf8>>;

                _ ->
                    <<S/binary, "\n"/utf8>>
            end end)(_pipe@5)
    end,
    Option_import = libero@codegen:import_if(
        Endpoints,
        fun libero@codegen:is_option/1,
        <<"import gleam/option.{type Option}"/utf8>>
    ),
    Dict_import = libero@codegen:import_if(
        Endpoints,
        fun libero@codegen:is_dict/1,
        <<"import gleam/dict.{type Dict}"/utf8>>
    ),
    <<<<<<<<<<<<"// Generated by Rally — do not edit.
////
//// Mirrored page types for the client package.

"/utf8,
                            Type_imports/binary>>/binary,
                        Option_import/binary>>/binary,
                    Dict_import/binary>>/binary,
                Client_msg_type/binary>>/binary,
            "\n"/utf8>>/binary,
        Json_encode_fn/binary>>.

-file("src/rally/generator/codec.gleam", 634).
-spec emit_codec_ffi_with_endpoints(
    list(libero@walker:discovered_type()),
    list(libero@scanner:handler_endpoint())
) -> binary().
emit_codec_ffi_with_endpoints(Discovered, Endpoints) ->
    libero@codegen_decoders:generate_decoders_ffi(
        Discovered,
        Endpoints,
        <<"../../"/utf8>>,
        <<"client"/utf8>>,
        {some, <<"generated/types"/utf8>>}
    ).

-file("src/rally/generator/codec.gleam", 34).
?DOC(" Generate all codec files for the client package.\n").
-spec generate(
    list({rally@types:scanned_route(), rally@types:page_contract()}),
    list(libero@walker:discovered_type()),
    list(libero@scanner:handler_endpoint()),
    list(binary()),
    binary()
) -> list(codec_file()).
generate(Contracts, Discovered, Endpoints, Server_symbols, Protocol) ->
    Codec_files = [{codec_file,
            <<"src/generated/codec_ffi.mjs"/utf8>>,
            emit_codec_ffi_with_endpoints(Discovered, Endpoints)},
        {codec_file,
            <<"src/generated/types.gleam"/utf8>>,
            emit_types_gleam(Contracts, Endpoints, Protocol)},
        {codec_file,
            <<"src/generated/codec.gleam"/utf8>>,
            emit_codec_gleam(Protocol)},
        {codec_file,
            <<"src/rally_runtime/effect.gleam"/utf8>>,
            emit_rally_effect_shim(Protocol)},
        {codec_file,
            <<"src/rally_runtime/rally_effect_ffi.mjs"/utf8>>,
            emit_rally_effect_ffi()}],
    Page_files = generate_page_modules(Contracts, Server_symbols, Protocol),
    lists:append(Codec_files, Page_files).

-file("src/rally/generator/codec.gleam", 168).
?DOC(
    " Generate a JS type registry that maps \"<module>.<type>#<variant>\"\n"
    " identities to Gleam JS constructors. The registry is imported by\n"
    " protocol_wire.mjs and used in typedJsonToGleamValue to produce\n"
    " properly typed instances instead of generic CustomType objects.\n"
    "\n"
    " Keys include the parent type name so a mismatched \"type\" field\n"
    " (e.g. { type: \"some/module.OldType\", variant: \"Discount\" }) never\n"
    " resolves to the registry entry for \"some/module.Discount#Discount\".\n"
).
-spec next_unused_alias(gleam@dict:dict(binary(), nil), binary(), integer()) -> binary().
next_unused_alias(Used, Candidate, N) ->
    Alias = case N of
        -1 ->
            Candidate;

        _ ->
            <<<<Candidate/binary, "_"/utf8>>/binary,
                (erlang:integer_to_binary(N))/binary>>
    end,
    case gleam@dict:has_key(Used, Alias) of
        false ->
            Alias;

        true ->
            next_unused_alias(Used, Candidate, N + 1)
    end.

-file("src/rally/generator/codec.gleam", 189).
?DOC(
    " Build a collision-safe mapping from module_path to JS import alias.\n"
    " Maintains a global used-aliases set. For each module the clean\n"
    " candidate is tried first; if already taken, `_0`, `_1`, ... suffixes\n"
    " are appended until an unused alias is found. This handles both\n"
    " slash/underscore collisions (`admin/foo_bar/baz` vs `admin/foo/bar_baz`)\n"
    " and suffix-poisoning (`admin/foo/bar_0` vs a suffixed `admin/foo/bar`).\n"
).
-spec build_module_aliases(list(binary())) -> gleam@dict:dict(binary(), binary()).
build_module_aliases(Modules) ->
    {_, Aliases@2} = gleam@list:fold(
        Modules,
        {maps:new(), maps:new()},
        fun(State, Mod) ->
            {Used, Aliases} = State,
            Candidate = <<"_m_"/utf8,
                (gleam@string:replace(Mod, <<"/"/utf8>>, <<"_"/utf8>>))/binary>>,
            Alias = next_unused_alias(Used, Candidate, -1),
            Used@1 = gleam@dict:insert(Used, Alias, nil),
            Aliases@1 = gleam@dict:insert(Aliases, Mod, Alias),
            {Used@1, Aliases@1}
        end
    ),
    Aliases@2.

-file("src/rally/generator/codec.gleam", 202).
-spec generate_json_type_registry_js(list(libero@walker:discovered_type())) -> codec_file().
generate_json_type_registry_js(Discovered) ->
    Modules = begin
        _pipe = Discovered,
        _pipe@1 = gleam@list:map(_pipe, fun(Dt) -> erlang:element(2, Dt) end),
        gleam@list:unique(_pipe@1)
    end,
    Aliases = build_module_aliases(Modules),
    Imports = case Modules of
        [] ->
            <<""/utf8>>;

        _ ->
            _pipe@2 = gleam@list:map(
                Modules,
                fun(Mod) ->
                    Alias = case gleam_stdlib:map_get(Aliases, Mod) of
                        {ok, A} ->
                            A;

                        {error, nil} ->
                            <<"_m_"/utf8,
                                (gleam@string:replace(
                                    Mod,
                                    <<"/"/utf8>>,
                                    <<"_"/utf8>>
                                ))/binary>>
                    end,
                    <<<<<<<<"import * as "/utf8, Alias/binary>>/binary,
                                " from \"../../client/"/utf8>>/binary,
                            Mod/binary>>/binary,
                        ".mjs\";"/utf8>>
                end
            ),
            gleam@string:join(_pipe@2, <<"\n"/utf8>>)
    end,
    Entries = begin
        _pipe@5 = gleam@list:flat_map(
            Discovered,
            fun(Dt@1) ->
                Mod_alias = case gleam_stdlib:map_get(
                    Aliases,
                    erlang:element(2, Dt@1)
                ) of
                    {ok, A@1} ->
                        A@1;

                    {error, nil} ->
                        <<"_m_"/utf8,
                            (gleam@string:replace(
                                erlang:element(2, Dt@1),
                                <<"/"/utf8>>,
                                <<"_"/utf8>>
                            ))/binary>>
                end,
                gleam@list:map(
                    erlang:element(5, Dt@1),
                    fun(V) ->
                        Key = <<<<<<<<(erlang:element(2, Dt@1))/binary,
                                        "."/utf8>>/binary,
                                    (erlang:element(3, Dt@1))/binary>>/binary,
                                "#"/utf8>>/binary,
                            (erlang:element(3, V))/binary>>,
                        Ctor_expr = case erlang:element(7, V) of
                            [] ->
                                <<<<<<<<"() => new "/utf8, Mod_alias/binary>>/binary,
                                            "."/utf8>>/binary,
                                        (erlang:element(3, V))/binary>>/binary,
                                    "()"/utf8>>;

                            _ ->
                                All_labelled = gleam@list:all(
                                    erlang:element(6, V),
                                    fun(L) -> L /= none end
                                ),
                                case All_labelled of
                                    true ->
                                        Args = begin
                                            _pipe@3 = gleam@list:filter_map(
                                                gleam@list:zip(
                                                    erlang:element(7, V),
                                                    erlang:element(6, V)
                                                ),
                                                fun(Pair) ->
                                                    {_, Label} = Pair,
                                                    case Label of
                                                        {some, Name} ->
                                                            {ok,
                                                                <<"fields."/utf8,
                                                                    Name/binary>>};

                                                        none ->
                                                            {error, nil}
                                                    end
                                                end
                                            ),
                                            gleam@string:join(
                                                _pipe@3,
                                                <<", "/utf8>>
                                            )
                                        end,
                                        <<<<<<<<<<<<"(fields) => new "/utf8,
                                                                Mod_alias/binary>>/binary,
                                                            "."/utf8>>/binary,
                                                        (erlang:element(3, V))/binary>>/binary,
                                                    "("/utf8>>/binary,
                                                Args/binary>>/binary,
                                            ")"/utf8>>;

                                    false ->
                                        Args@1 = begin
                                            _pipe@4 = gleam@list:index_map(
                                                erlang:element(7, V),
                                                fun(_, I) ->
                                                    <<<<"fields["/utf8,
                                                            (erlang:integer_to_binary(
                                                                I
                                                            ))/binary>>/binary,
                                                        "]"/utf8>>
                                                end
                                            ),
                                            gleam@string:join(
                                                _pipe@4,
                                                <<", "/utf8>>
                                            )
                                        end,
                                        <<<<<<<<<<<<"(fields) => new "/utf8,
                                                                Mod_alias/binary>>/binary,
                                                            "."/utf8>>/binary,
                                                        (erlang:element(3, V))/binary>>/binary,
                                                    "("/utf8>>/binary,
                                                Args@1/binary>>/binary,
                                            ")"/utf8>>
                                end
                        end,
                        <<<<<<<<"  \""/utf8, Key/binary>>/binary, "\": "/utf8>>/binary,
                                Ctor_expr/binary>>/binary,
                            ","/utf8>>
                    end
                )
            end
        ),
        gleam@string:join(_pipe@5, <<"\n"/utf8>>)
    end,
    Body = <<<<<<<<<<<<<<<<"// Generated by Rally — do not edit.\n"/utf8,
                                    "// Type registry for JSON decode path.\n"/utf8>>/binary,
                                "// Maps \"<module>.<type>#<variant>\" identities to Gleam JS constructors.\n"/utf8>>/binary,
                            "\n"/utf8>>/binary,
                        Imports/binary>>/binary,
                    "\n\n"/utf8>>/binary,
                "export const typeRegistry = {\n"/utf8>>/binary,
            Entries/binary>>/binary,
        "\n};\n"/utf8>>,
    {codec_file, <<"src/generated/type_registry.mjs"/utf8>>, Body}.

-file("src/rally/generator/codec.gleam", 118).
?DOC(
    " Generate a Gleam module that dispatches decoder names to the\n"
    " corresponding JSON typed decoders at runtime.\n"
    "\n"
    " The decoder_name follows the ETF codec convention\n"
    " (e.g. \"decode_pages_home__model\") and is mapped to the\n"
    " `json_decode_<qualified_atom_name>` function in json_codecs.\n"
).
-spec generate_json_decode_dispatch(list(libero@walker:discovered_type())) -> codec_file().
generate_json_decode_dispatch(Discovered) ->
    Cases = gleam@list:map(
        Discovered,
        fun(Dt) ->
            Qual = libero@walker:qualified_atom_name(
                erlang:element(2, Dt),
                erlang:element(3, Dt)
            ),
            <<<<<<<<"    \"decode_"/utf8, Qual/binary>>/binary,
                        "\" -> result.map(json_codecs.json_decode_"/utf8>>/binary,
                    Qual/binary>>/binary,
                "(value), identity)"/utf8>>
        end
    ),
    Body = <<<<"// Generated by Rally — do not edit.
////
//// JSON typed decode dispatch. Routes decoder names to the
//// corresponding typed decoders generated by libero JSON codegen.

import gleam/dynamic.{type Dynamic}
import gleam/result
import generated/json_codecs as json_codecs
import libero/json/error.{type JsonError, JsonError}

@external(javascript, \"./protocol_wire.mjs\", \"identity\")
fn identity(value: a) -> b

/// Decode a Dynamic value using the named typed decoder.
/// The decoder_name follows the pattern decode_<module>__<type>,
/// matching the ETF codec naming convention.
pub fn decode_json_typed(
  value: Dynamic,
  decoder_name: String,
) -> Result(Dynamic, List(JsonError)) {
  case decoder_name {
"/utf8,
            (gleam@string:join(Cases, <<"\n"/utf8>>))/binary>>/binary,
        "\n    _ -> Error([JsonError(\"decoder\", \"unknown: \" <> decoder_name)])
  }
}
"/utf8>>,
    {codec_file, <<"src/generated/json_decode_dispatch.gleam"/utf8>>, Body}.

-file("src/rally/generator/codec.gleam", 93).
?DOC(
    " Generate JSON typed encoder/decoder source for the client package.\n"
    " Uses libero's JSON codegen to produce per-type json.Json builders\n"
    " and typed decoders for all discovered types.\n"
).
-spec generate_json_codecs(
    list(libero@walker:discovered_type()),
    list(libero@scanner:handler_endpoint())
) -> list(codec_file()).
generate_json_codecs(Discovered, _) ->
    case libero@json@codegen:generate(Discovered) of
        {ok, Content} ->
            [{codec_file, <<"src/generated/json_codecs.gleam"/utf8>>, Content},
                generate_json_decode_dispatch(Discovered),
                generate_json_type_registry_js(Discovered)];

        {error, Errors} ->
            gleam@list:each(
                Errors,
                fun(E) ->
                    gleam_stdlib:println_error(
                        <<<<<<"JSON codegen error: "/utf8,
                                    (erlang:element(2, E))/binary>>/binary,
                                ": "/utf8>>/binary,
                            (erlang:element(3, E))/binary>>
                    )
                end
            ),
            []
    end.

-file("src/rally/generator/codec.gleam", 470).
?DOC(
    " Extract (module_path, type_name) seeds from a client_context.gleam\n"
    " source so the walker can discover ClientContext types with proper\n"
    " field type resolution, instead of the old hardcoded-StringField path.\n"
).
-spec client_context_seeds(binary(), binary()) -> list({binary(), binary()}).
client_context_seeds(Source, Module_path) ->
    case glance:module(Source) of
        {error, unexpected_end_of_input} ->
            [];

        {error, {unexpected_token, _, _}} ->
            [];

        {ok, Ast} ->
            gleam@list:map(
                erlang:element(3, Ast),
                fun(Def) ->
                    {Module_path, erlang:element(3, erlang:element(3, Def))}
                end
            )
    end.