Current section
Files
Jump to
Current section
Files
src/libero@gen_error.erl
-module(libero@gen_error).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/libero/gen_error.gleam").
-export([error_box/4, print_error/1]).
-export_type([gen_error/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.
-type gen_error() :: {cannot_read_dir, binary(), simplifile:file_error()} |
{cannot_read_file, binary(), simplifile:file_error()} |
{cannot_write_file, binary(), simplifile:file_error()} |
{cannot_create_dir, binary(), simplifile:file_error()} |
{parse_failed, binary(), glance:error()} |
{unresolved_type_module, binary(), binary()} |
{type_not_found, binary(), binary()} |
{no_endpoints_found, binary()} |
{duplicate_endpoint, binary(), list(binary())}.
-file("src/libero/gen_error.gleam", 36).
?DOC(
" Format a structured error as the boxed message libero prints to the\n"
" terminal. `title` is the one-line headline, `path` is the source file\n"
" or context the error refers to (rendered after `┌─`), `body_lines`\n"
" are the explanation lines (each prefixed with `│`), and `hint` is an\n"
" optional remediation tip rendered below a separator.\n"
"\n"
" Used by both typed `GenError` rendering and the TOML parser to keep\n"
" every error in the codebase consistent without duplicating the box\n"
" drawing.\n"
).
-spec error_box(
binary(),
binary(),
list(binary()),
gleam@option:option(binary())
) -> binary().
error_box(Title, Path, Body_lines, Hint) ->
Body = begin
_pipe = Body_lines,
_pipe@1 = gleam@list:map(
_pipe,
fun(Line) -> <<" \x{2502} "/utf8, Line/binary>> end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end,
Hint_block = case Hint of
none ->
<<""/utf8>>;
{some, H} ->
<<"\n \x{2502}\n hint: "/utf8, H/binary>>
end,
<<<<<<<<<<<<"error: "/utf8, Title/binary>>/binary,
"\n \x{250c}\x{2500} "/utf8>>/binary,
Path/binary>>/binary,
"\n \x{2502}\n"/utf8>>/binary,
Body/binary>>/binary,
Hint_block/binary>>.
-file("src/libero/gen_error.gleam", 167).
?DOC(
" Format a `glance.Error` cause into the body lines of a parse-failure\n"
" box. Surfaces the offending token's source text and its byte offset\n"
" so the user can locate the problem without re-running another tool.\n"
" `byte_offset` is the lexer's offset (codeunit offset on JavaScript).\n"
).
-spec format_glance_error(glance:error()) -> list(binary()).
format_glance_error(Err) ->
case Err of
unexpected_end_of_input ->
[<<"glance hit unexpected end of input while parsing this file"/utf8>>];
{unexpected_token, Tok, {position, Byte_offset}} ->
[<<<<<<"unexpected token `"/utf8,
(glexer@token:to_source(Tok))/binary>>/binary,
"` at byte offset "/utf8>>/binary,
(erlang:integer_to_binary(Byte_offset))/binary>>]
end.
-file("src/libero/gen_error.gleam", 159).
-spec format_file_error(simplifile:file_error()) -> binary().
format_file_error(Err) ->
simplifile:describe_error(Err).
-file("src/libero/gen_error.gleam", 59).
-spec to_string(gen_error()) -> binary().
to_string(Err) ->
case Err of
{cannot_read_dir, Path, Cause} ->
error_box(
<<"Cannot read directory"/utf8>>,
Path,
[format_file_error(Cause)],
none
);
{cannot_read_file, Path@1, Cause@1} ->
error_box(
<<"Cannot read file"/utf8>>,
Path@1,
[format_file_error(Cause@1)],
none
);
{cannot_write_file, Path@2, Cause@2} ->
error_box(
<<"Cannot write file"/utf8>>,
Path@2,
[format_file_error(Cause@2)],
{some,
<<"Check that the directory exists and you have write permission"/utf8>>}
);
{cannot_create_dir, Path@3, Cause@3} ->
error_box(
<<"Cannot create directory"/utf8>>,
Path@3,
[format_file_error(Cause@3)],
{some,
<<"Check parent directory exists and you have write permission"/utf8>>}
);
{parse_failed, Path@4, Cause@4} ->
error_box(
<<"Failed to parse Gleam source"/utf8>>,
Path@4,
format_glance_error(Cause@4),
{some,
<<"Run `gleam check` to see the full compiler error"/utf8>>}
);
{unresolved_type_module, Module_path, Type_name} ->
error_box(
<<"Unresolved type module"/utf8>>,
Module_path,
[<<<<"Type `"/utf8, Type_name/binary>>/binary,
"` could not be resolved to a file path"/utf8>>],
{some,
<<<<"Ensure the module is a path dependency of the client package.\n Check that `"/utf8,
Module_path/binary>>/binary,
"` appears in the shared/ directory\n or is listed as a dependency in gleam.toml"/utf8>>}
);
{type_not_found, Module_path@1, Type_name@1} ->
error_box(
<<"Type not found"/utf8>>,
<<Module_path@1/binary, ".gleam"/utf8>>,
[<<<<"Type `"/utf8, Type_name@1/binary>>/binary,
"` was not found in this module"/utf8>>],
{some,
<<"The type may be private (add `pub`) or the module path may be\n incorrect. Libero scans for custom types, not type aliases."/utf8>>}
);
{no_endpoints_found, Server_src} ->
error_box(
<<"No handler endpoints found"/utf8>>,
Server_src,
[<<"The server source tree contains no public function whose last"/utf8>>,
<<"parameter is HandlerContext and whose return type is"/utf8>>,
<<"#(Result(_, _), HandlerContext)."/utf8>>],
{some,
<<"Add at least one handler function before running `libero gen`."/utf8>>}
);
{duplicate_endpoint, Fn_name, Modules} ->
error_box(
<<"Duplicate handler endpoint"/utf8>>,
Fn_name,
[<<"The same function name is exported from multiple handler"/utf8>>,
<<"modules:"/utf8>> |
gleam@list:map(
Modules,
fun(M) -> <<" "/utf8, M/binary>> end
)],
{some,
<<"Handler function names must be unique across the server source\n tree, since each one becomes a ClientMsg variant."/utf8>>}
)
end.
-file("src/libero/gen_error.gleam", 23).
-spec print_error(gen_error()) -> nil.
print_error(Err) ->
gleam_stdlib:println_error(to_string(Err)).