-module(glacier). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([main/0]). -export_type([target/0, module_kind/0, parse_mode/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 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. -file("src/glacier.gleam", 24). -spec light_cyan_ansi_colour() -> gleam_community@colour:colour(). light_cyan_ansi_colour() -> _assert_subject = gleam_community@colour:from_rgb255(156, 231, 255), {ok, Colour} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"glacier"/utf8>>, function => <<"light_cyan_ansi_colour"/utf8>>, line => 25}) end, Colour. -file("src/glacier.gleam", 268). ?DOC(" Parses an import statement\n"). -spec parse_import_chars(list(binary()), gleam@string_tree:string_tree()) -> {list(binary()), gleam@string_tree:string_tree()}. parse_import_chars(Chars, Import_module) -> case Chars of [] -> {[], Import_module}; [<<"."/utf8>> | Rest_chars] -> {Rest_chars, Import_module}; [<<" "/utf8>> | Rest_chars@1] -> {Rest_chars@1, Import_module}; [<<"\r\n"/utf8>> | Rest_chars@2] -> {Rest_chars@2, Import_module}; [<<"\n"/utf8>> | Rest_chars@3] -> {Rest_chars@3, Import_module}; [Char | Rest_chars@4] when (((Char =:= <<"\t"/utf8>>) orelse (Char =:= <<"\r"/utf8>>)) orelse (Char =:= <<"\n"/utf8>>)) orelse (Char =:= <<"\r\n"/utf8>>) -> parse_import_chars(Rest_chars@4, Import_module); [Char@1 | Rest_chars@5] -> parse_import_chars( Rest_chars@5, gleam@string_tree:append(Import_module, Char@1) ) end. -file("src/glacier.gleam", 179). ?DOC(" Parses a module string for its import statements\n"). -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, _, <<"\""/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_tree:new() ), New_import@1 = unicode:characters_to_binary(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_tree:new() ), Imports@1 = [unicode:characters_to_binary(New_import@2) | Imports], parse_module_string( Rest_chars@2, Imports@1, parse_mode_search, <<""/utf8>> ); {parse_mode_search, _, _} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _, <<"\n"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _, <<"\r"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _, <<"\r\n"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_comment, _, _} -> parse_module_string( Rest_chars, Imports, parse_mode_in_comment, <<""/utf8>> ); {parse_mode_in_string, <<"\\"/utf8>>, _} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<""/utf8>> ); {parse_mode_in_string, _, <<"\""/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_search, <<""/utf8>> ); {parse_mode_in_string, _, <<"\\"/utf8>>} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<"\\"/utf8>> ); {parse_mode_in_string, _, _} -> parse_module_string( Rest_chars, Imports, parse_mode_in_string, <<""/utf8>> ) end end. -file("src/glacier.gleam", 416). -spec do_target() -> target(). do_target() -> erlang_target. -file("src/glacier.gleam", 374). ?DOC(" Gets the target at runtime\n"). -spec target() -> target(). target() -> do_target(). -file("src/glacier.gleam", 424). -spec do_start_args() -> list(binary()). do_start_args() -> erlang:element(4, argv:load()). -file("src/glacier.gleam", 380). ?DOC(" Gets the start arguments sometimes called argv.\n"). -spec start_args() -> list(binary()). start_args() -> do_start_args(). -file("src/glacier.gleam", 110). ?DOC(" Starts the file watcher.\n"). -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. -file("src/glacier.gleam", 436). -spec read_module_file(binary()) -> {ok, binary()} | {error, nil}. read_module_file(Module_path) -> case simplifile:read(Module_path) of {ok, Text} -> {ok, Text}; {error, File_reason} -> _pipe = {<<"Could not read file"/utf8>>, Module_path, <<"with reason"/utf8>>, File_reason}, _pipe@1 = gleam@string:inspect(_pipe), gleam_stdlib:println_error(_pipe@1), {error, nil} end. -file("src/glacier.gleam", 156). ?DOC(" Parses a module file for its import statements.\n"). -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), (fun(Result) -> case Result of {ok, Text} -> _pipe@2 = Text, _pipe@3 = gleam@string:to_graphemes(_pipe@2), _pipe@4 = parse_module_string( _pipe@3, [], parse_mode_search, <<""/utf8>> ), gleam@list:unique(_pipe@4); {error, nil} -> [] end end)(_pipe@1). -file("src/glacier.gleam", 386). ?DOC(" Gets the current project directory.\n"). -spec get_cwd() -> binary(). get_cwd() -> glacier_ffi:get_cwd_as_binary(). -file("src/glacier.gleam", 392). ?DOC(" Gets the project's `src` directory.\n"). -spec get_src_dir() -> binary(). get_src_dir() -> <<(get_cwd())/binary, "/src"/utf8>>. -file("src/glacier.gleam", 398). ?DOC(" Gets the project's `test` directory.\n"). -spec get_test_dir() -> binary(). get_test_dir() -> <<(get_cwd())/binary, "/test"/utf8>>. -file("src/glacier.gleam", 329). ?DOC(" Converts a module name to a module file name\n"). -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. -file("src/glacier.gleam", 321). ?DOC(" Derives src imports from test module\n"). -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). -file("src/glacier.gleam", 341). ?DOC(" Converts a module file name to a module name\n"). -spec file_name_to_module_name(binary(), module_kind()) -> binary(). file_name_to_module_name(Module_name, Module_kind) -> _assert_subject = 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, {ok, {_, Module_name_dot_gleam}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 342}) end, case gleam_stdlib:string_ends_with(Module_name, <<".erl"/utf8>>) of true -> _assert_subject@1 = gleam@string:split_once( Module_name_dot_gleam, <<".erl"/utf8>> ), {ok, {Module_name@1, _}} = case _assert_subject@1 of {ok, {_, _}} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@1, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 348}) end, Module_name@1; false -> _assert_subject@2 = gleam@string:split_once( Module_name_dot_gleam, <<".gleam"/utf8>> ), {ok, {Module_name@2, _}} = case _assert_subject@2 of {ok, {_, _}} -> _assert_subject@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@2, module => <<"glacier"/utf8>>, function => <<"file_name_to_module_name"/utf8>>, line => 353}) end, Module_name@2 end. -file("src/glacier.gleam", 404). ?DOC(" Cuts off the base path from the project directory.\n"). -spec to_relative_path(binary()) -> binary(). to_relative_path(Path) -> _assert_subject = gleam@string:split_once( Path, <<(get_cwd())/binary, "/"/utf8>> ), {ok, {_, Relative_file_name}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"glacier"/utf8>>, function => <<"to_relative_path"/utf8>>, line => 405}) end, Relative_file_name. -file("src/glacier.gleam", 362). ?DOC(" Checks if a given absolute file path exists\n"). -spec file_exists(binary()) -> boolean(). file_exists(Absolute_file_name) -> filelib:is_regular(Absolute_file_name). -file("src/glacier.gleam", 119). ?DOC(" Detects distinct import module dependency chain.\n"). -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 = lists: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( lists:append(Rest_module_names, Unchecked_module_names), lists:append(Processed_module_names, [Module_name]) ) end end. -file("src/glacier.gleam", 457). -spec do_find_project_files(binary()) -> list(binary()). do_find_project_files(In) -> glacier_ffi:find_files_recursive(In, <<"**/*.{gleam}"/utf8>>). -file("src/glacier.gleam", 368). ?DOC(" Finds files in project sub directory\n"). -spec find_project_files(binary()) -> list(binary()). find_project_files(Sub_directory) -> do_find_project_files(Sub_directory). -file("src/glacier.gleam", 296). ?DOC(" Derives test modules from its src import dependencies\n"). -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) -> _assert_subject = gleam@string:split_once( Module_name_dot_gleam, <<".gleam"/utf8>> ), {ok, {Module_name, _}} = case _assert_subject of {ok, {_, _}} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"glacier"/utf8>>, function => <<"derive_test_modules_from_src_import_dependencies"/utf8>>, line => 303}) end, Module_name 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. -file("src/glacier.gleam", 469). -spec shell_exec_print(list(binary())) -> nil. shell_exec_print(Args) -> case shellout:command(<<"gleam"/utf8>>, Args, <<"."/utf8>>, [let_be_stderr]) of {ok, Msg} -> gleam_stdlib:print(Msg), nil; {error, _} -> nil end. -file("src/glacier.gleam", 53). ?DOC(" Executes tests\n"). -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, lists: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@4 = gleam_community@ansi:colour( _pipe@3, light_cyan_ansi_colour() ), _pipe@5 = gleam_community@ansi:bold(_pipe@4), gleam_stdlib:println(_pipe@5), nil; Test_modules@2 -> _pipe@6 = gleam@list:map( Test_modules@2, fun(Test_module@1) -> <<"๐Ÿ” "/utf8, Test_module@1/binary>> end ), _pipe@7 = gleam@string:join(_pipe@6, <<"\n"/utf8>>), _pipe@8 = gleam_community@ansi:colour( _pipe@7, light_cyan_ansi_colour() ), gleam_stdlib:println(_pipe@8), Args = [<<"test"/utf8>>, <<"--target"/utf8>>, case target() of erlang_target -> <<"erlang"/utf8>>; java_script_target -> <<"javascript"/utf8>> end, <<"--"/utf8>> | Test_modules@2], shell_exec_print(Args) end. -file("src/glacier.gleam", 32). ?DOC( " Runs either `glacier` or `gleeunit` bundled as `gleeunit`, depending on\n" " the given command line arguments.\n" ). -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, _} -> gleeunit:main(); {_, true} -> _pipe = <<"๐Ÿ” Glacier is watching for changesโ€ฆ"/utf8>>, _pipe@1 = gleam_community@ansi:colour( _pipe, light_cyan_ansi_colour() ), _pipe@2 = gleam_community@ansi:italic(_pipe@1), gleam_stdlib:println(_pipe@2), start_file_change_watcher( fun(Modules) -> execute_tests(Modules) end ); {_, _} -> gleeunit:run(Start_args, false) end.