-module(glacier). -compile(no_auto_import). -export([main/0]). -export_type([target/0, module_kind/0, parse_mode/0]). -type target() :: erlang_target | java_script_target. -type module_kind() :: src_module_kind | test_module_kind. -type parse_mode() :: parse_mode_in_comment | parse_mode_in_string | parse_mode_search. -spec main() -> nil. main() -> Start_args = start_args(), Is_incremental = gleam@list:contains(Start_args, <<"--glacier"/utf8>>), Is_empty_args = Start_args =:= [], case {Is_empty_args, Is_incremental} of {true, _@1} -> gleeunit2:main(); {_@2, true} -> _pipe = <<"๐Ÿ” Glacier is watching for changesโ€ฆ"/utf8>>, _pipe@2 = shellout:style( _pipe, begin _pipe@1 = shellout:display([<<"italic"/utf8>>]), gleam@map:merge( _pipe@1, shellout:color([<<"lightblue"/utf8>>]) ) end, [{[<<"color"/utf8>>, <<"background"/utf8>>], [{<<"lightblue"/utf8>>, [<<"156"/utf8>>, <<"231"/utf8>>, <<"255"/utf8>>]}]}] ), gleam@io:println(_pipe@2), start_file_change_watcher( fun(Modules) -> execute_tests(Modules) end ); {_@3, _@4} -> gleeunit2:run(Start_args) end. -spec execute_tests(list({module_kind(), binary()})) -> nil. execute_tests(Modules) -> Test_modules@1 = begin _pipe@2 = gleam@list:fold( Modules, [], fun(Test_modules_acc, Module) -> Module_kind = erlang:element(1, Module), Full_module_path = erlang:element(2, Module), Test_modules = case Module_kind of src_module_kind -> _pipe = detect_distinct_import_module_dependency_chain( [file_name_to_module_name( Full_module_path, src_module_kind )], [] ), _pipe@1 = derive_test_modules_from_src_import_dependencies( _pipe ), gleam@list:map( _pipe@1, fun(Test_module) -> <<<<"test/"/utf8, Test_module/binary>>/binary, ".gleam"/utf8>> end ); test_module_kind -> [to_relative_path(Full_module_path)] end, gleam@list:append(Test_modules_acc, Test_modules) end ), gleam@list:unique(_pipe@2) end, case Test_modules@1 of [] -> _pipe@3 = <<"๐Ÿ” Did not detect any matching test modules!"/utf8>>, _pipe@5 = shellout:style( _pipe@3, begin _pipe@4 = shellout:display([<<"bold"/utf8>>]), gleam@map:merge( _pipe@4, shellout:color([<<"lightblue"/utf8>>]) ) end, [{[<<"color"/utf8>>, <<"background"/utf8>>], [{<<"lightblue"/utf8>>, [<<"156"/utf8>>, <<"231"/utf8>>, <<"255"/utf8>>]}]}] ), gleam@io:println(_pipe@5), nil; Test_modules@2 -> _pipe@6 = <<"๐Ÿ” Detected test modules:"/utf8>>, _pipe@8 = shellout:style( _pipe@6, begin _pipe@7 = shellout:display([<<"bold"/utf8>>]), gleam@map:merge( _pipe@7, shellout:color([<<"lightblue"/utf8>>]) ) end, [{[<<"color"/utf8>>, <<"background"/utf8>>], [{<<"lightblue"/utf8>>, [<<"156"/utf8>>, <<"231"/utf8>>, <<"255"/utf8>>]}]}] ), gleam@io:println(_pipe@8), _pipe@9 = gleam@list:map( Test_modules@2, fun(Test_module@1) -> <<" โ„ "/utf8, Test_module@1/binary>> end ), _pipe@10 = gleam@string:join(_pipe@9, <<"\n"/utf8>>), _pipe@11 = shellout:style( _pipe@10, shellout:color([<<"lightblue"/utf8>>]), [{[<<"color"/utf8>>, <<"background"/utf8>>], [{<<"lightblue"/utf8>>, [<<"156"/utf8>>, <<"231"/utf8>>, <<"255"/utf8>>]}]}] ), gleam@io:println(_pipe@11), Args = [<<"test"/utf8>>, <<"--target"/utf8>>, case target() of erlang_target -> <<"erlang"/utf8>>; java_script_target -> <<"javascript"/utf8>> end, <<"--"/utf8>> | Test_modules@2], case shellout:command( <<"gleam"/utf8>>, Args, <<"."/utf8>>, [let_be_stderr] ) of {ok, Msg} -> gleam@io:print(Msg), nil; {error, _@1} -> nil end end. -spec start_file_change_watcher(fun((list({module_kind(), binary()})) -> nil)) -> nil. start_file_change_watcher(File_change_handler) -> glacier_ffi:start_file_change_watcher(File_change_handler), nil. -spec detect_distinct_import_module_dependency_chain( list(binary()), list(binary()) ) -> list(binary()). detect_distinct_import_module_dependency_chain( Module_names, Processed_module_names ) -> case Module_names of [] -> Processed_module_names; [Module_name | Rest_module_names] -> case gleam@list:contains(Processed_module_names, Module_name) of true -> detect_distinct_import_module_dependency_chain( Rest_module_names, Processed_module_names ); false -> Unchecked_module_names = begin _pipe = Module_name, _pipe@1 = module_name_to_file_name( _pipe, src_module_kind ), _pipe@2 = parse_module_for_imports(_pipe@1), _pipe@3 = gleam@list:append(_pipe@2, Module_names), gleam@list:filter( _pipe@3, fun(Module_name@1) -> (gleam@list:contains( Processed_module_names, Module_name@1 ) =:= false) andalso file_exists( module_name_to_file_name( Module_name@1, src_module_kind ) ) end ) end, detect_distinct_import_module_dependency_chain( gleam@list:append( Rest_module_names, Unchecked_module_names ), gleam@list:append(Processed_module_names, [Module_name]) ) end end. -spec parse_module_for_imports(binary()) -> list(binary()). parse_module_for_imports(Module_file_name) -> _pipe = Module_file_name, _pipe@1 = read_module_file(_pipe), _pipe@2 = gleam@string:to_graphemes(_pipe@1), _pipe@3 = parse_module_string(_pipe@2, [], parse_mode_search, <<""/utf8>>), gleam@list:unique(_pipe@3). -spec parse_module_string( list(binary()), list(binary()), parse_mode(), binary() ) -> list(binary()). parse_module_string(Chars, Imports, Context, Collected) -> case Chars of [] -> Imports; [Char | Rest_chars] -> case {Context, Collected, Char} of {parse_mode_search, <<""/utf8>>, <<"/"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<"/"/utf8>> ); {parse_mode_search, <<"/"/utf8>>, <<"/"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_in_comment, <<""/utf8>> ); {parse_mode_search, _@1, <<"\""/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<""/utf8>> ); {parse_mode_search, Collected@1, Char@1} when ((((((Collected@1 =:= <<""/utf8>>) andalso (Char@1 =:= <<"i"/utf8>>)) orelse ((Collected@1 =:= <<"i"/utf8>>) andalso (Char@1 =:= <<"m"/utf8>>))) orelse ((Collected@1 =:= <<"im"/utf8>>) andalso (Char@1 =:= <<"p"/utf8>>))) orelse ((Collected@1 =:= <<"imp"/utf8>>) andalso (Char@1 =:= <<"o"/utf8>>))) orelse ((Collected@1 =:= <<"impo"/utf8>>) andalso (Char@1 =:= <<"r"/utf8>>))) orelse ((Collected@1 =:= <<"impor"/utf8>>) andalso (Char@1 =:= <<"t"/utf8>>)) -> parse_module_string( Rest_chars, Imports, parse_mode_search, <> ); {parse_mode_search, <<"import"/utf8>>, Char@2} when (((Char@2 =:= <<" "/utf8>>) orelse (Char@2 =:= <<"\t"/utf8>>)) orelse (Char@2 =:= <<"\n"/utf8>>)) orelse (Char@2 =:= <<"\r\n"/utf8>>) -> {Rest_chars@1, New_import} = parse_import_chars( Rest_chars, gleam@string_builder:new() ), New_import@1 = gleam@string_builder:to_string(New_import), Updated_imports = [New_import@1 | Imports], parse_module_string( Rest_chars@1, Updated_imports, parse_mode_search, <<""/utf8>> ); {parse_mode_search, <<"import\r"/utf8>>, <<"\n"/utf8>>} -> {Rest_chars@2, New_import@2} = parse_import_chars( Rest_chars, gleam@string_builder:new() ), Imports@1 = [gleam@string_builder:to_string(New_import@2) | Imports], parse_module_string( Rest_chars@2, Imports@1, parse_mode_search, <<""/utf8>> ); {parse_mode_search, _@2, _@3} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _@4, <<"\n"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _@5, <<"\r"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _@6, <<"\r\n"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _@7, _@8} -> parse_module_string( Rest_chars, Imports, parse_mode_in_comment, <<""/utf8>> ); {parse_mode_in_string, <<"\\"/utf8>>, _@9} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<""/utf8>> ); {parse_mode_in_string, _@10, <<"\""/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_string, _@11, <<"\\"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<"\\"/utf8>> ); {parse_mode_in_string, _@12, _@13} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<""/utf8>> ) end end. -spec parse_import_chars(list(binary()), gleam@string_builder:string_builder()) -> {list(binary()), gleam@string_builder:string_builder()}. parse_import_chars(Chars, Import_module) -> case Chars of [] -> {[], Import_module}; [<<"\r\n"/utf8>> | Rest_chars] -> {Rest_chars, Import_module}; [<<"\n"/utf8>> | Rest_chars@1] -> {Rest_chars@1, Import_module}; [Char | Rest_chars@2] when ((((Char =:= <<" "/utf8>>) orelse (Char =:= <<"\t"/utf8>>)) orelse (Char =:= <<"\r"/utf8>>)) orelse (Char =:= <<"\n"/utf8>>)) orelse (Char =:= <<"\r\n"/utf8>>) -> parse_import_chars(Rest_chars@2, Import_module); [Char@1 | Rest_chars@3] -> parse_import_chars( Rest_chars@3, gleam@string_builder:append(Import_module, Char@1) ) end. -spec derive_test_modules_from_src_import_dependencies(list(binary())) -> list(binary()). derive_test_modules_from_src_import_dependencies(Src_modules) -> Project_test_files = find_project_files(<<"test"/utf8>>), All_test_modules = begin _pipe = Project_test_files, gleam@list:map( _pipe, fun(Module_name_dot_gleam) -> {ok, {Module_name@1, _@2}} = case gleam@string:split_once( Module_name_dot_gleam, <<".gleam"/utf8>> ) of {ok, {Module_name, _@1}} -> {ok, {Module_name, _@1}}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"glacier"/utf8>>, function => <<"derive_test_modules_from_src_import_dependencies"/utf8>>, line => 304}) end, Module_name@1 end ) end, Dirty_test_modules = begin _pipe@1 = All_test_modules, gleam@list:filter( _pipe@1, fun(Test_module) -> Test_module_imports = derive_src_imports_off_test_module( Test_module ), gleam@list:any( Src_modules, fun(Src_module) -> _pipe@2 = Test_module_imports, gleam@list:contains(_pipe@2, Src_module) end ) end ) end, Dirty_test_modules. -spec derive_src_imports_off_test_module(binary()) -> list(binary()). derive_src_imports_off_test_module(Test_module_name) -> _pipe = Test_module_name, _pipe@1 = module_name_to_file_name(_pipe, test_module_kind), parse_module_for_imports(_pipe@1). -spec module_name_to_file_name(binary(), module_kind()) -> binary(). module_name_to_file_name(Module_name, Module_kind) -> case Module_kind of src_module_kind -> <<<<<<(get_src_dir())/binary, "/"/utf8>>/binary, Module_name/binary>>/binary, ".gleam"/utf8>>; test_module_kind -> <<<<<<(get_test_dir())/binary, "/"/utf8>>/binary, Module_name/binary>>/binary, ".gleam"/utf8>> end. -spec file_name_to_module_name(binary(), module_kind()) -> binary(). file_name_to_module_name(Module_name, Module_kind) -> {ok, {_@2, Module_name_dot_gleam@1}} = case case Module_kind of src_module_kind -> gleam@string:split_once( Module_name, <<(get_src_dir())/binary, "/"/utf8>> ); test_module_kind -> gleam@string:split_once( Module_name, <<(get_test_dir())/binary, "/"/utf8>> ) end of {ok, {_@1, Module_name_dot_gleam}} -> {ok, {_@1, Module_name_dot_gleam}}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 346}) end, case gleam@string:ends_with(Module_name, <<".erl"/utf8>>) of true -> {ok, {Module_name@2, _@4}} = case gleam@string:split_once( Module_name_dot_gleam@1, <<".erl"/utf8>> ) of {ok, {Module_name@1, _@3}} -> {ok, {Module_name@1, _@3}}; _try@1 -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try@1, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 352}) end, Module_name@2; false -> {ok, {Module_name@4, _@6}} = case gleam@string:split_once( Module_name_dot_gleam@1, <<".gleam"/utf8>> ) of {ok, {Module_name@3, _@5}} -> {ok, {Module_name@3, _@5}}; _try@2 -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try@2, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 357}) end, Module_name@4 end. -spec file_exists(binary()) -> boolean(). file_exists(Absolute_file_name) -> filelib:is_regular(Absolute_file_name). -spec find_project_files(binary()) -> list(binary()). find_project_files(Sub_directory) -> do_find_project_files(Sub_directory). -spec target() -> target(). target() -> do_target(). -spec start_args() -> list(binary()). start_args() -> do_start_args(). -spec get_cwd() -> binary(). get_cwd() -> glacier_ffi:get_cwd_as_binary(). -spec get_src_dir() -> binary(). get_src_dir() -> <<(get_cwd())/binary, "/src"/utf8>>. -spec get_test_dir() -> binary(). get_test_dir() -> <<(get_cwd())/binary, "/test"/utf8>>. -spec to_relative_path(binary()) -> binary(). to_relative_path(Path) -> {ok, {_@2, Relative_file_name@1}} = case gleam@string:split_once( Path, <<(get_cwd())/binary, "/"/utf8>> ) of {ok, {_@1, Relative_file_name}} -> {ok, {_@1, Relative_file_name}}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"glacier"/utf8>>, function => <<"to_relative_path"/utf8>>, line => 409}) end, Relative_file_name@1. -spec do_target() -> target(). do_target() -> erlang_target. -spec do_start_args() -> list(binary()). do_start_args() -> gleam@erlang:start_arguments(). -spec read_module_file(binary()) -> binary(). read_module_file(Module_path) -> {ok, Contents@1} = case gleam@erlang@file:read(Module_path) of {ok, Contents} -> {ok, Contents}; _try -> erlang:error(#{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"glacier"/utf8>>, function => <<"read_module_file"/utf8>>, line => 432}) end, Contents@1. -spec do_find_project_files(binary()) -> list(binary()). do_find_project_files(In) -> glacier_ffi:find_files_recursive(In, <<"**/*.{gleam}"/utf8>>).