-module(fswalk). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([builder/0, with_path/2, with_entry_filter/2, with_traversal_filter/2, walk/1, each/2, map/2, fold/3, only_dirs/1, only_files/1]). -export_type([non/0, som/0, walk_builder/3, stat/0, entry/0]). -opaque non() :: any(). -opaque som() :: any(). -opaque walk_builder(FWI, FWJ, FWK) :: {walk_builder, gleam@option:option(list(fun((entry()) -> boolean()))), gleam@option:option(list(fun((entry()) -> boolean()))), gleam@option:option(binary())} | {gleam_phantom, FWI, FWJ, FWK}. -type stat() :: {stat, boolean()}. -type entry() :: {entry, binary(), stat()}. -spec builder() -> walk_builder(non(), non(), non()). builder() -> {walk_builder, none, none, none}. -spec with_path(walk_builder(FWO, FWP, any()), binary()) -> walk_builder(FWO, FWP, som()). with_path(Builder, Path) -> {walk_builder, erlang:element(2, Builder), erlang:element(3, Builder), {some, Path}}. -spec with_entry_filter( walk_builder(any(), FWY, FWZ), fun((entry()) -> boolean()) ) -> walk_builder(som(), FWY, FWZ). with_entry_filter(Builder, Entry_filter) -> {walk_builder, {some, gleam@list:append( gleam@option:unwrap(erlang:element(2, Builder), []), [Entry_filter] )}, erlang:element(3, Builder), erlang:element(4, Builder)}. -spec with_traversal_filter( walk_builder(FXG, any(), FXI), fun((entry()) -> boolean()) ) -> walk_builder(FXG, som(), FXI). with_traversal_filter(Builder, Traversal_filter) -> {walk_builder, erlang:element(2, Builder), {some, gleam@list:append( gleam@option:unwrap(erlang:element(3, Builder), []), [Traversal_filter] )}, erlang:element(4, Builder)}. -spec to_entry(binary()) -> entry(). to_entry(Filename) -> {entry, Filename, {stat, begin _pipe = simplifile:verify_is_directory(Filename), gleam@result:unwrap(_pipe, false) end}}. -spec path_to_entry(gleam_community@path:path()) -> entry(). path_to_entry(Pth) -> to_entry(gleam_community@path:to_string(Pth)). -spec ok(FXV) -> {ok, FXV} | {error, any()}. ok(X) -> {ok, X}. -spec filter_many(list(GBG), list(fun((GBG) -> boolean()))) -> list(GBG). filter_many(Xs, Filters) -> _pipe = Xs, gleam@list:filter( _pipe, fun(Entry) -> gleam@list:all(Filters, fun(F) -> F(Entry) end) end ). -spec to_ok_iter(list(GBN)) -> gleam@iterator:iterator({ok, GBN} | {error, any()}). to_ok_iter(Xs) -> _pipe = Xs, _pipe@1 = gleam@list:map(_pipe, fun ok/1), gleam@iterator:from_list(_pipe@1). -spec walk_path( gleam_community@path:path(), list(fun((entry()) -> boolean())), list(fun((entry()) -> boolean())) ) -> gleam@iterator:iterator({ok, entry()} | {error, simplifile:file_error()}). walk_path(Pth, Entry_filters, Traversal_filters) -> _pipe = gleam@iterator:once( fun() -> simplifile:read_directory(gleam_community@path:to_string(Pth)) end ), gleam@iterator:flat_map(_pipe, fun(Readdir_result) -> case Readdir_result of {error, X} -> gleam@iterator:once(fun() -> {error, X} end); {ok, Filenames} -> {Filepaths, Folderpaths} = gleam@list:fold( Filenames, {[], []}, fun(Acc, F) -> Filepath = gleam_community@path:append_string( Pth, F ), case begin _pipe@1 = simplifile:verify_is_directory( gleam_community@path:to_string(Filepath) ), gleam@result:unwrap(_pipe@1, false) end of true -> {erlang:element(1, Acc), [Filepath | erlang:element(2, Acc)]}; false -> {[Filepath | erlang:element(1, Acc)], erlang:element(2, Acc)} end end ), Ok_filtered_files = begin _pipe@2 = Filepaths, _pipe@3 = gleam@list:map(_pipe@2, fun path_to_entry/1), _pipe@4 = filter_many(_pipe@3, Entry_filters), to_ok_iter(_pipe@4) end, Candidate_folder_entries = begin _pipe@5 = Folderpaths, gleam@list:map(_pipe@5, fun path_to_entry/1) end, Ok_filtered_folders = begin _pipe@6 = Candidate_folder_entries, _pipe@7 = filter_many(_pipe@6, Entry_filters), to_ok_iter(_pipe@7) end, Traverse_folders = begin _pipe@8 = Candidate_folder_entries, filter_many(_pipe@8, Traversal_filters) end, gleam@iterator:concat( [Ok_filtered_files, Ok_filtered_folders | gleam@list:map( Traverse_folders, fun(Ent) -> walk_path( gleam_community@path:from_string( erlang:element(2, Ent) ), Entry_filters, Traversal_filters ) end )] ) end end). -spec walk(walk_builder(any(), any(), som())) -> gleam@iterator:iterator({ok, entry()} | {error, simplifile:file_error()}). walk(Builder) -> {walk_builder, Entry_filter_opt, Traversal_filter_opt, Path_opt} = Builder, {some, Root_path} = case Path_opt of {some, _} -> Path_opt; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"fswalk"/utf8>>, function => <<"walk"/utf8>>, line => 85}) end, Entry_filters = case Entry_filter_opt of {some, Xs} -> Xs; _ -> [] end, Traversal_filters = case Traversal_filter_opt of {some, Xs@1} -> Xs@1; _ -> [] end, walk_path( gleam_community@path:from_string(Root_path), Entry_filters, Traversal_filters ). -spec each(gleam@iterator:iterator(GDT), fun((GDT) -> any())) -> nil. each(It, Fun) -> _pipe = It, gleam@iterator:each(_pipe, Fun). -spec map(gleam@iterator:iterator(GDV), fun((GDV) -> GDW)) -> gleam@iterator:iterator(GDW). map(It, Fun) -> _pipe = It, gleam@iterator:map(_pipe, Fun). -spec fold(gleam@iterator:iterator(GDX), FYO, fun((FYO, GDX) -> FYO)) -> FYO. fold(It, Init, Fun) -> _pipe = It, gleam@iterator:fold(_pipe, Init, Fun). -spec only_dirs(entry()) -> boolean(). only_dirs(Ent) -> erlang:element(2, erlang:element(3, Ent)). -spec only_files(entry()) -> boolean(). only_files(Ent) -> not only_dirs(Ent).