-module(gleedoc@generate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleedoc/generate.gleam").
-export([generate_tests/2, clean_generated/1]).
-export_type([config/0, import/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 config() :: {config, binary()}.
-type import() :: {import, binary(), list(binary())}.
-file("src/gleedoc/generate.gleam", 243).
?DOC(" Replace characters that aren't valid in function names\n").
-spec sanitize_name(binary()) -> binary().
sanitize_name(Name) ->
_pipe = Name,
_pipe@1 = gleam@string:replace(_pipe, <<"."/utf8>>, <<"_"/utf8>>),
gleam@string:replace(_pipe@1, <<"-"/utf8>>, <<"_"/utf8>>).
-file("src/gleedoc/generate.gleam", 216).
-spec generate_test_function(gleedoc@parse:code_block(), integer()) -> binary().
generate_test_function(Block, Index) ->
Target_name = gleam@option:unwrap(
erlang:element(3, erlang:element(4, Block)),
<<"module"/utf8>>
),
Test_func_name = <<<<<<(sanitize_name(Target_name))/binary, "_"/utf8>>/binary,
(erlang:integer_to_binary(Index + 1))/binary>>/binary,
"_test"/utf8>>,
Source_info = <<<<<<"// From: "/utf8,
(erlang:element(4, erlang:element(4, Block)))/binary>>/binary,
":"/utf8>>/binary,
(erlang:integer_to_binary(
(erlang:element(5, erlang:element(4, Block)) + erlang:element(
5,
Block
))
- 1
))/binary>>,
Code = begin
_pipe = erlang:element(3, Block),
gleam@string:trim(_pipe)
end,
gleam@string:join(
[<<""/utf8>>,
Source_info,
<<<<"pub fn "/utf8, Test_func_name/binary>>/binary, "() {"/utf8>>,
<<" "/utf8,
(gleam@string:replace(Code, <<"\n"/utf8>>, <<"\n "/utf8>>))/binary>>,
<<"}"/utf8>>],
<<"\n"/utf8>>
).
-file("src/gleedoc/generate.gleam", 211).
-spec generate_test_functions(list(gleedoc@parse:code_block())) -> list(binary()).
generate_test_functions(Blocks) ->
_pipe = Blocks,
gleam@list:index_map(_pipe, fun generate_test_function/2).
-file("src/gleedoc/generate.gleam", 140).
-spec import_to_string(import()) -> binary().
import_to_string(Imp) ->
case erlang:element(3, Imp) of
[] ->
<<"import "/utf8, (erlang:element(2, Imp))/binary>>;
Names ->
Types = begin
_pipe = Names,
_pipe@1 = gleam@list:filter(
_pipe,
fun(N) ->
gleam_stdlib:string_starts_with(N, <<"type "/utf8>>)
end
),
gleam@list:sort(_pipe@1, fun gleam@string:compare/2)
end,
Values = begin
_pipe@2 = Names,
_pipe@3 = gleam@list:filter(
_pipe@2,
fun(N@1) ->
not gleam_stdlib:string_starts_with(
N@1,
<<"type "/utf8>>
)
end
),
gleam@list:sort(_pipe@3, fun gleam@string:compare/2)
end,
Names_str = gleam@string:join(
lists:append(Types, Values),
<<", "/utf8>>
),
<<<<<<<<"import "/utf8, (erlang:element(2, Imp))/binary>>/binary,
".{"/utf8>>/binary,
Names_str/binary>>/binary,
"}"/utf8>>
end.
-file("src/gleedoc/generate.gleam", 179).
-spec list_find_import(list(import()), binary()) -> {ok, import()} |
{error, nil}.
list_find_import(Imports, Module) ->
gleam@list:find(Imports, fun(Imp) -> erlang:element(2, Imp) =:= Module end).
-file("src/gleedoc/generate.gleam", 124).
-spec parse_import(binary()) -> import().
parse_import(Line) ->
Rest = begin
_pipe = Line,
_pipe@1 = gleam@string:trim(_pipe),
_pipe@2 = gleam@string:drop_start(_pipe@1, 7),
gleam@string:trim_start(_pipe@2)
end,
case gleam@string:split_once(Rest, <<".{"/utf8>>) of
{ok, {Module, Names_part}} ->
Names = begin
_pipe@3 = Names_part,
_pipe@4 = gleam@string:replace(
_pipe@3,
<<"}"/utf8>>,
<<""/utf8>>
),
_pipe@5 = gleam@string:split(_pipe@4, <<","/utf8>>),
_pipe@6 = gleam@list:map(_pipe@5, fun gleam@string:trim/1),
gleam@list:filter(_pipe@6, fun(S) -> S /= <<""/utf8>> end)
end,
{import, Module, Names};
{error, nil} ->
{import, Rest, []}
end.
-file("src/gleedoc/generate.gleam", 158).
-spec merge_imports(list(binary())) -> list(binary()).
merge_imports(Imports) ->
_pipe = Imports,
_pipe@1 = gleam@list:map(_pipe, fun parse_import/1),
_pipe@2 = gleam@list:fold(
_pipe@1,
[],
fun(Acc, Imp) -> case list_find_import(Acc, erlang:element(2, Imp)) of
{ok, Existing} ->
Merged_names = gleam@list:unique(
lists:append(
erlang:element(3, Existing),
erlang:element(3, Imp)
)
),
gleam@list:map(
Acc,
fun(Existing_imp) ->
case erlang:element(2, Existing_imp) =:= erlang:element(
2,
Imp
) of
true ->
{import,
erlang:element(2, Existing_imp),
Merged_names};
false ->
Existing_imp
end
end
);
{error, nil} ->
[Imp | Acc]
end end
),
_pipe@3 = gleam@list:map(_pipe@2, fun import_to_string/1),
gleam@list:sort(_pipe@3, fun gleam@string:compare/2).
-file("src/gleedoc/generate.gleam", 186).
-spec unique_imports(binary(), binary()) -> list(binary()).
unique_imports(File, Module_name) ->
case simplifile:read(File) of
{ok, Source} ->
Names = begin
_pipe = gleedoc@scan:public_names(File, Source),
gleam@result:unwrap(_pipe, [])
end,
Target_import = case Names of
[] ->
<<"import "/utf8, Module_name/binary>>;
_ ->
<<<<<<<<"import "/utf8, Module_name/binary>>/binary,
".{"/utf8>>/binary,
(gleam@string:join(Names, <<", "/utf8>>))/binary>>/binary,
"}"/utf8>>
end,
Source_imports = begin
_pipe@1 = gleedoc@scan:module_imports(File, Source),
gleam@result:unwrap(_pipe@1, [])
end,
[Target_import | Source_imports];
{error, _} ->
[<<"import "/utf8, Module_name/binary>>]
end.
-file("src/gleedoc/generate.gleam", 102).
-spec module_name_from_file(binary()) -> binary().
module_name_from_file(File) ->
_pipe = gleam@string:split_once(File, <<"/"/utf8>>),
_pipe@1 = gleam@result:map(_pipe, fun(Pair) -> erlang:element(2, Pair) end),
_pipe@2 = gleam@result:unwrap(_pipe@1, File),
gleam@string:replace(_pipe@2, <<".gleam"/utf8>>, <<""/utf8>>).
-file("src/gleedoc/generate.gleam", 109).
-spec test_file_name(binary()) -> binary().
test_file_name(Source_file) ->
Name = begin
_pipe = gleam@string:split_once(Source_file, <<"/"/utf8>>),
_pipe@1 = gleam@result:map(
_pipe,
fun(Pair) -> erlang:element(2, Pair) end
),
_pipe@2 = gleam@result:unwrap(_pipe@1, Source_file),
_pipe@3 = gleam@string:replace(_pipe@2, <<".gleam"/utf8>>, <<""/utf8>>),
gleam@string:replace(_pipe@3, <<"/"/utf8>>, <<"_"/utf8>>)
end,
<<Name/binary, "_gleedoc_test.gleam"/utf8>>.
-file("src/gleedoc/generate.gleam", 95).
-spec find_group(list({binary(), list(gleedoc@parse:code_block())}), binary()) -> {ok,
{binary(), list(gleedoc@parse:code_block())}} |
{error, nil}.
find_group(Groups, File) ->
gleam@list:find(Groups, fun(Pair) -> erlang:element(1, Pair) =:= File end).
-file("src/gleedoc/generate.gleam", 76).
-spec group_by_file(list(gleedoc@parse:code_block())) -> list({binary(),
list(gleedoc@parse:code_block())}).
group_by_file(Blocks) ->
_pipe = Blocks,
_pipe@1 = gleam@list:fold(
_pipe,
[],
fun(Groups, Block) ->
File = erlang:element(4, erlang:element(4, Block)),
case find_group(Groups, File) of
{ok, {_, Existing}} ->
gleam@list:map(
Groups,
fun(Pair) -> case erlang:element(1, Pair) =:= File of
true ->
{File, [Block | Existing]};
false ->
Pair
end end
);
{error, nil} ->
[{File, [Block]} | Groups]
end
end
),
gleam@list:map(
_pipe@1,
fun(Pair@1) ->
{erlang:element(1, Pair@1),
lists:reverse(erlang:element(2, Pair@1))}
end
).
-file("src/gleedoc/generate.gleam", 20).
?DOC(" Generate test files from extracted code blocks.\n").
-spec generate_tests(list(gleedoc@parse:code_block()), config()) -> {ok,
list(binary())} |
{error, snag:snag()}.
generate_tests(Blocks, Config) ->
By_file = group_by_file(Blocks),
_pipe = By_file,
gleam@list:try_map(
_pipe,
fun(Pair) ->
{File, File_blocks} = Pair,
Test_file_name = test_file_name(File),
Output_dir = <<(erlang:element(2, Config))/binary, "/gleedoc"/utf8>>,
Test_path = <<<<Output_dir/binary, "/"/utf8>>/binary,
Test_file_name/binary>>,
Module_name = module_name_from_file(File),
gleam@result:'try'(
begin
_pipe@1 = simplifile:create_directory_all(Output_dir),
gleam@result:map_error(
_pipe@1,
fun(Err) ->
snag:new(
<<<<<<"Failed to create directory: "/utf8,
Output_dir/binary>>/binary,
" - "/utf8>>/binary,
(gleam@string:inspect(Err))/binary>>
)
end
)
end,
fun(_) ->
Block_imports = begin
_pipe@2 = File_blocks,
gleam@list:flat_map(
_pipe@2,
fun(B) -> erlang:element(6, B) end
)
end,
Auto_imports = unique_imports(File, Module_name),
All_imports = merge_imports(
lists:append(Block_imports, Auto_imports)
),
Test_functions = generate_test_functions(File_blocks),
Content = gleam@string:join(
begin
_pipe@3 = [<<"// Generated by gleedoc - do not edit manually"/utf8>>,
<<""/utf8>> |
All_imports],
lists:append(_pipe@3, Test_functions)
end,
<<"\n"/utf8>>
),
gleam@result:'try'(
begin
_pipe@4 = simplifile:write(Test_path, Content),
gleam@result:map_error(
_pipe@4,
fun(Err@1) ->
snag:new(
<<<<<<"Failed to write test file: "/utf8,
Test_path/binary>>/binary,
" - "/utf8>>/binary,
(gleam@string:inspect(Err@1))/binary>>
)
end
)
end,
fun(_) -> {ok, Test_path} end
)
end
)
end
).
-file("src/gleedoc/generate.gleam", 250).
?DOC(" Clean up generated test files.\n").
-spec clean_generated(binary()) -> {ok, nil} | {error, snag:snag()}.
clean_generated(Output_dir) ->
Dir = <<Output_dir/binary, "/gleedoc"/utf8>>,
case simplifile_erl:read_directory(Dir) of
{ok, Files} ->
_pipe = Files,
_pipe@1 = gleam@list:filter(
_pipe,
fun(F) ->
gleam_stdlib:string_ends_with(
F,
<<"_gleedoc_test.gleam"/utf8>>
)
end
),
gleam@list:each(
_pipe@1,
fun(F@1) ->
Path = <<<<Dir/binary, "/"/utf8>>/binary, F@1/binary>>,
_ = simplifile_erl:delete(Path),
nil
end
),
{ok, nil};
{error, Err} ->
case gleam@string:inspect(Err) of
<<"Enoent"/utf8>> ->
{ok, nil};
_ ->
{error,
snag:new(
<<"Failed to clean generated files: "/utf8,
(gleam@string:inspect(Err))/binary>>
)}
end
end.