Current section
Files
Jump to
Current section
Files
src/libero@cli@gen.erl
-module(libero@cli@gen).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libero/cli/gen.gleam").
-export([run/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(
" `libero gen`: TOML-driven codegen command.\n"
"\n"
" Reads `gleam.toml` from the project path, scans the server source tree\n"
" for handler endpoint functions, and runs the full codegen pipeline for\n"
" each declared client.\n"
).
-file("src/libero/cli/gen.gleam", 153).
?DOC(
" Print a GenError to stderr and translate it into a short String error\n"
" the CLI can return. Centralising this keeps each codegen call site to\n"
" one line and makes adding a new step a one-liner instead of five.\n"
" nolint: stringly_typed_error -- CLI module, String errors are user-facing messages\n"
).
-spec run_step(binary(), {ok, AEXC} | {error, libero@gen_error:gen_error()}) -> {ok,
AEXC} |
{error, binary()}.
run_step(Label, Result) ->
gleam@result:map_error(
Result,
fun(Err) ->
libero@gen_error:print_error(Err),
<<Label/binary, " failed"/utf8>>
end
).
-file("src/libero/cli/gen.gleam", 121).
-spec generate_main(
binary(),
libero@toml_config:toml_config(),
list(libero@toml_config:client_config())
) -> {ok, nil} | {error, binary()}.
generate_main(Project_path, Toml_cfg, Clients) ->
Js_client_names = gleam@list:filter_map(
Clients,
fun(C) -> case erlang:element(3, C) of
<<"javascript"/utf8>> ->
{ok, erlang:element(2, C)};
_ ->
{error, nil}
end end
),
gleam@result:'try'(
run_step(
<<"write_main"/utf8>>,
libero@codegen_server:write_main(
erlang:element(2, Toml_cfg),
erlang:element(3, Toml_cfg),
<<<<Project_path/binary, "/"/utf8>>/binary,
(erlang:element(6, Toml_cfg))/binary>>,
erlang:element(9, Toml_cfg),
Js_client_names,
Project_path
)
),
fun(_) ->
gleam_stdlib:println(<<"libero: done"/utf8>>),
{ok, nil}
end
).
-file("src/libero/cli/gen.gleam", 166).
?DOC(
" Create the directory if it doesn't exist, surfacing failures through\n"
" the standard `gen_error` boxed format.\n"
" nolint: stringly_typed_error -- CLI module, String errors are user-facing messages\n"
).
-spec ensure_dir(binary()) -> {ok, nil} | {error, binary()}.
ensure_dir(Path) ->
case simplifile:create_directory_all(Path) of
{ok, _} ->
{ok, nil};
{error, Err} ->
libero@gen_error:print_error({cannot_create_dir, Path, Err}),
{error, <<"ensure_dir failed"/utf8>>}
end.
-file("src/libero/cli/gen.gleam", 177).
-spec run_client_codegen(
binary(),
libero@toml_config:toml_config(),
libero@toml_config:client_config(),
list(libero@scanner:handler_endpoint()),
binary(),
list(libero@walker:discovered_type())
) -> {ok, nil} | {error, binary()}.
run_client_codegen(
Project_path,
Toml_cfg,
Client,
Endpoints,
Wire_module_tag,
Discovered
) ->
gleam_stdlib:println(
<<"libero: generating stubs for client: "/utf8,
(erlang:element(2, Client))/binary>>
),
gleam@result:'try'(
libero@toml_config:to_codegen_config(
Toml_cfg,
erlang:element(2, Client),
<<"/ws"/utf8>>
),
fun(Raw_config) ->
Config = libero@config:prefix_paths(Raw_config, Project_path),
gleam@result:'try'(
ensure_dir(erlang:element(10, Config)),
fun(_) ->
gleam@result:'try'(
ensure_dir(erlang:element(11, Config)),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_endpoint_dispatch"/utf8>>,
libero@codegen_dispatch:write_endpoint_dispatch(
Endpoints,
erlang:element(10, Config),
erlang:element(4, Config),
erlang:element(9, Toml_cfg),
Wire_module_tag
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_endpoint_client_stubs"/utf8>>,
libero@codegen_stubs:write_endpoint_client_stubs(
Endpoints,
erlang:element(11, Config),
Wire_module_tag
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_websocket"/utf8>>,
libero@codegen_server:write_websocket(
erlang:element(
10,
Config
),
erlang:element(
9,
Toml_cfg
)
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_atoms"/utf8>>,
libero@codegen_server:write_atoms(
Config,
Discovered
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_config"/utf8>>,
libero@codegen_stubs:write_config(
Config
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_decoders_gleam"/utf8>>,
libero@codegen_decoders:write_decoders_gleam(
Config
)
),
fun(_) ->
gleam@result:'try'(
run_step(
<<"write_decoders_ffi"/utf8>>,
libero@codegen_decoders:write_decoders_ffi(
Config,
Discovered,
Endpoints
)
),
fun(
_
) ->
gleam@result:'try'(
run_step(
<<"write_ssr_flags"/utf8>>,
libero@codegen_stubs:write_ssr_flags(
erlang:element(
11,
Config
)
)
),
fun(
_
) ->
{ok,
nil}
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/libero/cli/gen.gleam", 56).
-spec run_with_clients(
binary(),
libero@toml_config:toml_config(),
list(libero@toml_config:client_config())
) -> {ok, nil} | {error, binary()}.
run_with_clients(Project_path, Toml_cfg, Clients) ->
Shared_src = <<<<Project_path/binary, "/"/utf8>>/binary,
(erlang:element(8, Toml_cfg))/binary>>,
Server_src = <<<<Project_path/binary, "/"/utf8>>/binary,
(erlang:element(5, Toml_cfg))/binary>>,
gleam@result:'try'(
begin
_pipe = libero@scanner:scan_handler_endpoints(
Server_src,
Shared_src
),
gleam@result:map_error(
_pipe,
fun(Errors) ->
gleam@list:each(Errors, fun libero@gen_error:print_error/1),
<<"endpoint scan failed"/utf8>>
end
)
end,
fun(Endpoints) -> gleam@result:'try'(case Endpoints of
[] ->
libero@gen_error:print_error(
{no_endpoints_found, Server_src}
),
{error, <<"no handler endpoints found"/utf8>>};
_ ->
{ok, Endpoints}
end, fun(Endpoints@1) ->
gleam_stdlib:println(
<<<<<<"libero: found "/utf8,
(erlang:integer_to_binary(
erlang:length(Endpoints@1)
))/binary>>/binary,
" handler endpoint(s) in "/utf8>>/binary,
(erlang:element(5, Toml_cfg))/binary>>
),
Wire_module_tag = <<"rpc"/utf8>>,
gleam@result:'try'(
begin
_pipe@1 = libero@walker:walk_shared_types(
Shared_src
),
gleam@result:map_error(
_pipe@1,
fun(Errors@1) ->
gleam@list:each(
Errors@1,
fun libero@gen_error:print_error/1
),
<<"type walk failed"/utf8>>
end
)
end,
fun(Discovered) ->
gleam@result:'try'(
gleam@list:try_map(
Clients,
fun(Client) ->
run_client_codegen(
Project_path,
Toml_cfg,
Client,
Endpoints@1,
Wire_module_tag,
Discovered
)
end
),
fun(_) ->
generate_main(
Project_path,
Toml_cfg,
Clients
)
end
)
end
)
end) end
).
-file("src/libero/cli/gen.gleam", 28).
?DOC(
" Run the `gen` command from the given project path (usually `\".\"`).\n"
"\n"
" Reads `gleam.toml`, discovers handler endpoints in the server src dir,\n"
" and runs codegen for each declared client.\n"
" nolint: stringly_typed_error -- CLI module, String errors are user-facing messages\n"
).
-spec run(binary()) -> {ok, nil} | {error, binary()}.
run(Project_path) ->
gleam@result:'try'(
begin
_pipe = simplifile:read(<<Project_path/binary, "/gleam.toml"/utf8>>),
gleam@result:map_error(
_pipe,
fun(Err) ->
libero@gen_error:error_box(
<<"Cannot read gleam.toml"/utf8>>,
<<"gleam.toml"/utf8>>,
[simplifile:describe_error(Err)],
{some,
<<"Run this command from your project root directory"/utf8>>}
)
end
)
end,
fun(Toml_content) ->
gleam@result:'try'(
libero@toml_config:parse(Toml_content),
fun(Toml_cfg) -> case erlang:element(4, Toml_cfg) of
[] ->
gleam_stdlib:println(
<<"libero: no clients declared in gleam.toml"/utf8>>
),
{ok, nil};
Clients ->
run_with_clients(Project_path, Toml_cfg, Clients)
end end
)
end
).