src/rally@generator@json_rpc_dispatch.erl

-module(rally@generator@json_rpc_dispatch).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/rally/generator/json_rpc_dispatch.gleam").
-export([to_pascal_case/1, handler_alias/1, endpoint_json_tag/1, closure_param_for_fieldtype/1, json_encoder_for_fieldtype/2, json_response_encode/1, json_handler_call/3, json_dispatch_arm/3, generate_json_dispatch_function_with_prefix/3, generate_json_dispatch_function/2, handler_imports/1]).

-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-specific RPC dispatch codegen.\n"
    "\n"
    " Generates dispatch functions that route JSON-encoded RPC calls to\n"
    " server_* handlers. Handles JSON response encoding and type registry\n"
    " building for the JSON protocol path.\n"
).

-file("src/rally/generator/json_rpc_dispatch.gleam", 17).
-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/json_rpc_dispatch.gleam", 29).
-spec handler_alias(binary()) -> binary().
handler_alias(Module_path) ->
    <<(gleam@string:replace(Module_path, <<"/"/utf8>>, <<"_"/utf8>>))/binary,
        "_handler"/utf8>>.

-file("src/rally/generator/json_rpc_dispatch.gleam", 33).
-spec endpoint_json_tag(libero@scanner:handler_endpoint()) -> binary().
endpoint_json_tag(Endpoint) ->
    {Module_path@1, Type_name@1} = case erlang:element(8, Endpoint) of
        {some, {Module_path, Type_name}} ->
            {Module_path, Type_name};

        _ ->
            {erlang:element(2, Endpoint),
                to_pascal_case(
                    <<"server_"/utf8, (erlang:element(3, Endpoint))/binary>>
                )}
    end,
    <<<<Module_path@1/binary, "."/utf8>>/binary, Type_name@1/binary>>.

-file("src/rally/generator/json_rpc_dispatch.gleam", 188).
-spec closure_param_for_fieldtype(libero@field_type:field_type()) -> binary().
closure_param_for_fieldtype(Ft) ->
    case Ft of
        nil_field ->
            <<"_x"/utf8>>;

        _ ->
            <<"x"/utf8>>
    end.

-file("src/rally/generator/json_rpc_dispatch.gleam", 195).
-spec json_encoder_for_fieldtype(libero@field_type:field_type(), binary()) -> binary().
json_encoder_for_fieldtype(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 ->
            <<<<"json.string(bit_array.base64_encode("/utf8, Var/binary>>/binary,
                ", True))"/utf8>>;

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

        {list_of, Inner} ->
            <<<<<<<<"json_codecs.json_encode_gleam__list("/utf8, Var/binary>>/binary,
                        ", fn(x) { "/utf8>>/binary,
                    (json_encoder_for_fieldtype(Inner, <<"x"/utf8>>))/binary>>/binary,
                " })"/utf8>>;

        {option_of, Inner@1} ->
            <<<<<<<<"json_codecs.json_encode_gleam_option__option("/utf8,
                            Var/binary>>/binary,
                        ", fn(x) { "/utf8>>/binary,
                    (json_encoder_for_fieldtype(Inner@1, <<"x"/utf8>>))/binary>>/binary,
                " })"/utf8>>;

        {result_of, Ok, Err} ->
            <<<<<<<<<<<<"json_codecs.json_encode_gleam_result__result("/utf8,
                                    Var/binary>>/binary,
                                ", fn(x) { "/utf8>>/binary,
                            (json_encoder_for_fieldtype(Ok, <<"x"/utf8>>))/binary>>/binary,
                        " }, fn(x) { "/utf8>>/binary,
                    (json_encoder_for_fieldtype(Err, <<"x"/utf8>>))/binary>>/binary,
                " })"/utf8>>;

        {dict_of, _, _} ->
            <<<<"json_codecs.json_encode_gleam__dict("/utf8, Var/binary>>/binary,
                ")"/utf8>>;

        {tuple_of, _} ->
            <<<<"json_codecs.json_encode_gleam__tuple("/utf8, Var/binary>>/binary,
                ")"/utf8>>;

        {type_var, _} ->
            <<"panic as \"cannot encode type variable\""/utf8>>
    end.

-file("src/rally/generator/json_rpc_dispatch.gleam", 172).
-spec json_response_encode(libero@scanner:handler_endpoint()) -> binary().
json_response_encode(E) ->
    Ok_encoder = json_encoder_for_fieldtype(erlang:element(4, E), <<"x"/utf8>>),
    Err_encoder = json_encoder_for_fieldtype(erlang:element(5, E), <<"x"/utf8>>),
    Ok_param = closure_param_for_fieldtype(erlang:element(4, E)),
    Err_param = closure_param_for_fieldtype(erlang:element(5, E)),
    <<<<<<<<<<<<<<<<"let encoded = json_codecs.json_encode_gleam_result__result(result, fn("/utf8,
                                    Ok_param/binary>>/binary,
                                ") { "/utf8>>/binary,
                            Ok_encoder/binary>>/binary,
                        " }, fn("/utf8>>/binary,
                    Err_param/binary>>/binary,
                ") { "/utf8>>/binary,
            Err_encoder/binary>>/binary,
        " })"/utf8>>.

-file("src/rally/generator/json_rpc_dispatch.gleam", 139).
-spec json_handler_call(libero@scanner:handler_endpoint(), binary(), boolean()) -> binary().
json_handler_call(E, Alias, Has_auth) ->
    Extra = case Has_auth of
        true ->
            <<", identity:"/utf8>>;

        false ->
            <<""/utf8>>
    end,
    case erlang:element(8, E) of
        {some, _} ->
            <<<<<<<<<<<<Alias/binary, "."/utf8>>/binary, "server_"/utf8>>/binary,
                            (erlang:element(3, E))/binary>>/binary,
                        "(msg: msg, server_context: server_context"/utf8>>/binary,
                    Extra/binary>>/binary,
                ")"/utf8>>;

        _ ->
            Labeled = gleam@list:map(
                erlang:element(6, E),
                fun(P) ->
                    <<<<(erlang:element(1, P))/binary, ": "/utf8>>/binary,
                        (erlang:element(1, P))/binary>>
                end
            ),
            Args = lists:append(
                Labeled,
                [<<"server_context: server_context"/utf8, Extra/binary>>]
            ),
            <<<<<<<<<<<<Alias/binary, "."/utf8>>/binary, "server_"/utf8>>/binary,
                            (erlang:element(3, E))/binary>>/binary,
                        "("/utf8>>/binary,
                    (gleam@string:join(Args, <<", "/utf8>>))/binary>>/binary,
                ")"/utf8>>
    end.

-file("src/rally/generator/json_rpc_dispatch.gleam", 93).
-spec json_dispatch_arm(libero@scanner:handler_endpoint(), boolean(), binary()) -> binary().
json_dispatch_arm(E, Has_auth, Encode_prefix) ->
    Alias = handler_alias(erlang:element(2, E)),
    {Type_module, Type_name} = case erlang:element(8, E) of
        {some, {Mod, Name}} ->
            {Mod, Name};

        _ ->
            {erlang:element(2, E),
                to_pascal_case(
                    <<"server_"/utf8, (erlang:element(3, E))/binary>>
                )}
    end,
    Type_str = <<<<Type_module/binary, "."/utf8>>/binary, Type_name/binary>>,
    Msg_decoder = <<"json_codecs.json_decode_"/utf8,
        (libero@walker:qualified_atom_name(Type_module, Type_name))/binary>>,
    Handler_call = json_handler_call(E, Alias, Has_auth),
    {Ok_destructure, Ok_ctx} = case erlang:element(7, E) of
        true ->
            {<<"#(result, new_ctx)"/utf8>>, <<"new_ctx"/utf8>>};

        false ->
            {<<"result"/utf8>>, <<"server_context"/utf8>>}
    end,
    Response_encode = json_response_encode(E),
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"    Ok(\""/utf8, Type_str/binary>>/binary,
                                                                                "\") -> {
      case "/utf8>>/binary,
                                                                            Msg_decoder/binary>>/binary,
                                                                        "(message) {
        Error(errors) -> {
          let error_frame = "/utf8>>/binary,
                                                                    Encode_prefix/binary>>/binary,
                                                                "encode_error(Some(request_id), errors)
          #(error_frame, server_context)
        }
        Ok(msg) -> {
          case trace.try_call(fn() { "/utf8>>/binary,
                                                            Handler_call/binary>>/binary,
                                                        " }) {
            Ok("/utf8>>/binary,
                                                    Ok_destructure/binary>>/binary,
                                                ") -> {
              "/utf8>>/binary,
                                            Response_encode/binary>>/binary,
                                        "
              let frame = "/utf8>>/binary,
                                    Encode_prefix/binary>>/binary,
                                "encode_response(request_id, encoded)
              #(frame, "/utf8>>/binary,
                            Ok_ctx/binary>>/binary,
                        ")
            }
            Error(reason) -> {
              let trace_id = trace.new_trace_id()
              io.println_error(\"[libero] \" <> trace_id <> \" "/utf8>>/binary,
                    (erlang:element(3, E))/binary>>/binary,
                ": \" <> reason)
              let error_frame = "/utf8>>/binary,
            Encode_prefix/binary>>/binary,
        "encode_error(Some(request_id), [JsonError(\"handler\", \"Something went wrong\")])
              #(error_frame, server_context)
            }
          }
        }
      }
    }"/utf8>>.

-file("src/rally/generator/json_rpc_dispatch.gleam", 48).
-spec generate_json_dispatch_function_with_prefix(
    list(libero@scanner:handler_endpoint()),
    boolean(),
    binary()
) -> binary().
generate_json_dispatch_function_with_prefix(Endpoints, Has_auth, Encode_prefix) ->
    case Endpoints of
        [] ->
            <<<<<<<<"\nfn json_dispatch(
  message _message: Dynamic,
  request_id request_id: Int,
  server_context server_context: ServerContext,"/utf8,
                            (case Has_auth of
                                true ->
                                    <<"\n  identity _identity: auth.Identity,"/utf8>>;

                                false ->
                                    <<""/utf8>>
                            end)/binary>>/binary,
                        "
) -> #(String, ServerContext) {
  let error_frame = "/utf8>>/binary,
                    Encode_prefix/binary>>/binary,
                "encode_error(Some(request_id), [JsonError(\"rpc\", \"no endpoints configured\")])
  #(error_frame, server_context)
}\n"/utf8>>;

        _ ->
            Arms = begin
                _pipe = gleam@list:map(
                    Endpoints,
                    fun(E) -> json_dispatch_arm(E, Has_auth, Encode_prefix) end
                ),
                gleam@string:join(_pipe, <<"\n"/utf8>>)
            end,
            Catch_all = <<<<"      Ok(other) -> {
        let error_frame = "/utf8,
                    Encode_prefix/binary>>/binary,
                "encode_error(Some(request_id), [JsonError(\"type\", \"unknown: \" <> other)])
        #(error_frame, server_context)
      }"/utf8>>,
            <<<<<<<<<<<<<<<<"\nfn json_dispatch(
  message message: Dynamic,
  request_id request_id: Int,
  server_context server_context: ServerContext,"/utf8,
                                            (case Has_auth of
                                                true ->
                                                    <<"\n  identity identity: auth.Identity,"/utf8>>;

                                                false ->
                                                    <<""/utf8>>
                                            end)/binary>>/binary,
                                        "
) -> #(String, ServerContext) {
  case decode.run(message, decode.field(\"type\", decode.string, fn(x) { decode.success(x) })) {
    Error(_) -> {
      let error_frame = "/utf8>>/binary,
                                    Encode_prefix/binary>>/binary,
                                "encode_error(Some(request_id), [JsonError(\"type\", \"missing or not a string\")])
      #(error_frame, server_context)
    }\n"/utf8>>/binary,
                            Arms/binary>>/binary,
                        "\n"/utf8>>/binary,
                    Catch_all/binary>>/binary,
                "\n  }\n}\n"/utf8>>
    end.

-file("src/rally/generator/json_rpc_dispatch.gleam", 41).
-spec generate_json_dispatch_function(
    list(libero@scanner:handler_endpoint()),
    boolean()
) -> binary().
generate_json_dispatch_function(Endpoints, Has_auth) ->
    generate_json_dispatch_function_with_prefix(
        Endpoints,
        Has_auth,
        <<"wire."/utf8>>
    ).

-file("src/rally/generator/json_rpc_dispatch.gleam", 235).
-spec handler_imports(list(libero@scanner:handler_endpoint())) -> list(binary()).
handler_imports(Endpoints) ->
    _pipe = Endpoints,
    _pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(2, E) end),
    _pipe@2 = gleam@list:unique(_pipe@1),
    gleam@list:map(
        _pipe@2,
        fun(Mod) ->
            Alias = handler_alias(Mod),
            case begin
                _pipe@3 = gleam@string:split(Mod, <<"/"/utf8>>),
                gleam@list:last(_pipe@3)
            end of
                {ok, Seg} when Seg =:= Alias ->
                    <<"import "/utf8, Mod/binary>>;

                _ ->
                    <<<<<<"import "/utf8, Mod/binary>>/binary, " as "/utf8>>/binary,
                        Alias/binary>>
            end
        end
    ).