Packages

CLI for vendoring Drip elements into a Lustre project.

Current section

Files

Jump to
drip src drip@internal@project.erl
Raw

src/drip@internal@project.erl

-module(drip@internal@project).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/drip/internal/project.gleam").
-export([root/1, name/1, prefix/1, with_overrides/3, source/1, vendor_directory/1, file_path/2, relative_path/2, vendored_files/2, is_vendored/2, ensure_initialized/1, load_from/1, load/0, write_settings/3, write_changes/1, delete_files/1, vendored_filenames/1, vendored_in/2, rewrite_index_css/1, scaffold/2]).
-export_type([project/0, file_change/0, overwrite/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.
?MODULEDOC(false).
-opaque project() :: {project,
binary(),
binary(),
binary(),
drip@internal@source:source()}.
-type file_change() :: {created, binary()} |
{modified, binary()} |
{unmodified, binary()} |
{deleted, binary()}.
-type overwrite() :: force | preserve.
-file("src/drip/internal/project.gleam", 17).
?DOC(false).
-spec root(project()) -> binary().
root(Project) ->
erlang:element(2, Project).
-file("src/drip/internal/project.gleam", 21).
?DOC(false).
-spec name(project()) -> binary().
name(Project) ->
erlang:element(3, Project).
-file("src/drip/internal/project.gleam", 25).
?DOC(false).
-spec prefix(project()) -> binary().
prefix(Project) ->
erlang:element(4, Project).
-file("src/drip/internal/project.gleam", 503).
?DOC(false).
-spec is_digit(binary()) -> boolean().
is_digit(Char) ->
gleam_stdlib:contains_string(<<"0123456789"/utf8>>, Char).
-file("src/drip/internal/project.gleam", 499).
?DOC(false).
-spec is_lower_alpha(binary()) -> boolean().
is_lower_alpha(Char) ->
gleam_stdlib:contains_string(<<"abcdefghijklmnopqrstuvwxyz"/utf8>>, Char).
-file("src/drip/internal/project.gleam", 495).
?DOC(false).
-spec is_identifier(binary()) -> boolean().
is_identifier(Char) ->
(is_lower_alpha(Char) orelse is_digit(Char)) orelse (Char =:= <<"_"/utf8>>).
-file("src/drip/internal/project.gleam", 488).
?DOC(false).
-spec is_valid_path_segment(binary()) -> boolean().
is_valid_path_segment(Segment) ->
case gleam@string:to_graphemes(Segment) of
[] ->
false;
[First | Rest] ->
is_lower_alpha(First) andalso gleam@list:all(
Rest,
fun is_identifier/1
)
end.
-file("src/drip/internal/project.gleam", 484).
?DOC(false).
-spec is_valid_prefix(binary()) -> boolean().
is_valid_prefix(Prefix) ->
_pipe = gleam@string:split(Prefix, <<"/"/utf8>>),
gleam@list:all(_pipe, fun is_valid_path_segment/1).
-file("src/drip/internal/project.gleam", 29).
?DOC(false).
-spec with_overrides(
project(),
gleam@option:option(binary()),
gleam@option:option(binary())
) -> {ok, project()} | {error, drip@internal@error:error()}.
with_overrides(Project, Prefix, Source) ->
gleam@result:'try'(case Prefix of
{some, Value} ->
case is_valid_prefix(Value) of
true ->
{ok,
{project,
erlang:element(2, Project),
erlang:element(3, Project),
Value,
erlang:element(5, Project)}};
false ->
{error, {invalid_prefix, Value}}
end;
none ->
{ok, Project}
end, fun(Project@1) -> case Source of
{some, Value@1} ->
gleam@result:map(
drip@internal@source:parse(Value@1),
fun(Source@1) ->
{project,
erlang:element(2, Project@1),
erlang:element(3, Project@1),
erlang:element(4, Project@1),
Source@1}
end
);
none ->
{ok, Project@1}
end end).
-file("src/drip/internal/project.gleam", 51).
?DOC(false).
-spec source(project()) -> drip@internal@source:source().
source(Project) ->
erlang:element(5, Project).
-file("src/drip/internal/project.gleam", 55).
?DOC(false).
-spec vendor_directory(project()) -> binary().
vendor_directory(Project) ->
filepath:join(
erlang:element(2, Project),
<<"src/"/utf8, (erlang:element(4, Project))/binary>>
).
-file("src/drip/internal/project.gleam", 59).
?DOC(false).
-spec theme_css_path(project()) -> binary().
theme_css_path(Project) ->
filepath:join(vendor_directory(Project), <<"theme.css"/utf8>>).
-file("src/drip/internal/project.gleam", 63).
?DOC(false).
-spec index_css_path(project()) -> binary().
index_css_path(Project) ->
filepath:join(vendor_directory(Project), <<"index.css"/utf8>>).
-file("src/drip/internal/project.gleam", 67).
?DOC(false).
-spec entry_css_path(project()) -> binary().
entry_css_path(Project) ->
filepath:join(
erlang:element(2, Project),
<<<<"src/"/utf8, (erlang:element(3, Project))/binary>>/binary,
".css"/utf8>>
).
-file("src/drip/internal/project.gleam", 71).
?DOC(false).
-spec file_path(project(), binary()) -> binary().
file_path(Project, Filename) ->
filepath:join(vendor_directory(Project), Filename).
-file("src/drip/internal/project.gleam", 86).
?DOC(false).
-spec trim_leading_slash(binary()) -> binary().
trim_leading_slash(Path) ->
case gleam_stdlib:string_starts_with(Path, <<"/"/utf8>>) of
true ->
gleam@string:drop_start(Path, 1);
false ->
Path
end.
-file("src/drip/internal/project.gleam", 76).
?DOC(false).
-spec relative_path(project(), binary()) -> binary().
relative_path(Project, Path) ->
case gleam_stdlib:string_starts_with(Path, erlang:element(2, Project)) of
true ->
_pipe = Path,
_pipe@1 = gleam@string:drop_start(
_pipe,
string:length(erlang:element(2, Project))
),
trim_leading_slash(_pipe@1);
false ->
Path
end.
-file("src/drip/internal/project.gleam", 329).
?DOC(false).
-spec read_vendor_directory(project()) -> {ok, list(binary())} |
{error, drip@internal@error:error()}.
read_vendor_directory(Project) ->
Directory = vendor_directory(Project),
case simplifile_erl:read_directory(Directory) of
{ok, Names} ->
{ok, Names};
{error, enoent} ->
{ok, []};
{error, Cause} ->
{error, {failed_to_read_project_directory, Directory, Cause}}
end.
-file("src/drip/internal/project.gleam", 308).
?DOC(false).
-spec vendored_files(project(), binary()) -> {ok, list(binary())} |
{error, drip@internal@error:error()}.
vendored_files(Project, Name) ->
gleam@result:map(
read_vendor_directory(Project),
fun(Filenames) -> _pipe = Filenames,
_pipe@1 = gleam@list:filter(
_pipe,
fun(Filename) ->
gleam_stdlib:string_starts_with(
Filename,
<<Name/binary, "."/utf8>>
)
end
),
_pipe@2 = gleam@list:sort(_pipe@1, fun gleam@string:compare/2),
gleam@list:map(
_pipe@2,
fun(_capture) -> file_path(Project, _capture) end
) end
).
-file("src/drip/internal/project.gleam", 93).
?DOC(false).
-spec is_vendored(project(), binary()) -> {ok, boolean()} |
{error, drip@internal@error:error()}.
is_vendored(Project, Name) ->
gleam@result:map(
vendored_files(Project, Name),
fun(Files) -> Files /= [] end
).
-file("src/drip/internal/project.gleam", 246).
?DOC(false).
-spec file_exists(binary()) -> {ok, boolean()} |
{error, drip@internal@error:error()}.
file_exists(Path) ->
case simplifile_erl:is_file(Path) of
{ok, Present} ->
{ok, Present};
{error, Cause} ->
{error, {failed_to_check_if_project_file_exists, Path, Cause}}
end.
-file("src/drip/internal/project.gleam", 98).
?DOC(false).
-spec is_initialized(project()) -> {ok, boolean()} |
{error, drip@internal@error:error()}.
is_initialized(Project) ->
file_exists(index_css_path(Project)).
-file("src/drip/internal/project.gleam", 103).
?DOC(false).
-spec ensure_initialized(project()) -> {ok, nil} |
{error, drip@internal@error:error()}.
ensure_initialized(Project) ->
gleam@result:'try'(
is_initialized(Project),
fun(Initialized) -> case Initialized of
true ->
{ok, nil};
false ->
{error,
{failed_to_find_index_stylesheet,
index_css_path(Project)}}
end end
).
-file("src/drip/internal/project.gleam", 165).
?DOC(false).
-spec find_project_root(binary(), integer()) -> {ok, binary()} |
{error, drip@internal@error:error()}.
find_project_root(Directory, Depth) ->
case simplifile_erl:is_file(filepath:join(Directory, <<"gleam.toml"/utf8>>)) of
{ok, true} ->
{ok, Directory};
_ ->
case Depth < 64 of
true ->
find_project_root(
filepath:join(Directory, <<"../"/utf8>>),
Depth + 1
);
false ->
{error, {failed_to_find_project_root, Directory}}
end
end.
-file("src/drip/internal/project.gleam", 121).
?DOC(false).
-spec load_from(binary()) -> {ok, project()} |
{error, drip@internal@error:error()}.
load_from(Directory) ->
gleam@result:'try'(
find_project_root(Directory, 0),
fun(Root) ->
gleam@result:'try'(
begin
_pipe = simplifile:read(
filepath:join(Root, <<"gleam.toml"/utf8>>)
),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {failed_to_read_gleam_toml, Field@0} end
)
end,
fun(Toml) ->
gleam@result:'try'(
begin
_pipe@1 = tomlet:parse(Toml),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {failed_to_parse_gleam_toml, Field@0} end
)
end,
fun(Document) ->
gleam@result:'try'(
begin
_pipe@2 = tomlet:get_string(
Document,
[<<"name"/utf8>>]
),
gleam@result:map_error(
_pipe@2,
fun(Field@0) -> {failed_to_get_gleam_toml_value, Field@0} end
)
end,
fun(Name) ->
gleam@result:'try'(
case tomlet:get_string(
Document,
[<<"tools"/utf8>>,
<<"drip"/utf8>>,
<<"prefix"/utf8>>]
) of
{ok, Prefix} ->
case is_valid_prefix(Prefix) of
true ->
{ok, Prefix};
false ->
{error,
{invalid_prefix,
Prefix}}
end;
{error, {key_not_found, _}} ->
{ok, <<"ui"/utf8>>};
{error, Cause} ->
{error,
{failed_to_get_gleam_toml_value,
Cause}}
end,
fun(Prefix@1) ->
gleam@result:'try'(
case tomlet:get_string(
Document,
[<<"tools"/utf8>>,
<<"drip"/utf8>>,
<<"source"/utf8>>]
) of
{ok, Source} ->
{ok, Source};
{error, {key_not_found, _}} ->
{ok,
<<"https://github.com/scott-ray-wilson/drip/releases/latest/download"/utf8>>};
{error, Cause@1} ->
{error,
{failed_to_get_gleam_toml_value,
Cause@1}}
end,
fun(Raw_source) ->
gleam@result:map(
drip@internal@source:parse(
Raw_source
),
fun(Source@1) ->
{project,
Root,
Name,
Prefix@1,
Source@1}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/drip/internal/project.gleam", 117).
?DOC(false).
-spec load() -> {ok, project()} | {error, drip@internal@error:error()}.
load() ->
load_from(<<"./"/utf8>>).
-file("src/drip/internal/project.gleam", 179).
?DOC(false).
-spec gleam_toml_path(project()) -> binary().
gleam_toml_path(Project) ->
filepath:join(erlang:element(2, Project), <<"gleam.toml"/utf8>>).
-file("src/drip/internal/project.gleam", 258).
?DOC(false).
-spec write_file(binary(), binary()) -> {ok, nil} |
{error, drip@internal@error:error()}.
write_file(Path, Body) ->
gleam@result:'try'(
begin
_pipe = simplifile:create_directory_all(
filepath:directory_name(Path)
),
gleam@result:map_error(
_pipe,
fun(_capture) ->
{failed_to_create_project_directory, Path, _capture}
end
)
end,
fun(_) -> _pipe@1 = simplifile:write(Path, Body),
gleam@result:map_error(
_pipe@1,
fun(_capture@1) ->
{failed_to_write_project_file, Path, _capture@1}
end
) end
).
-file("src/drip/internal/project.gleam", 253).
?DOC(false).
-spec read_file(binary()) -> {ok, binary()} |
{error, drip@internal@error:error()}.
read_file(Path) ->
_pipe = simplifile:read(Path),
gleam@result:map_error(
_pipe,
fun(_capture) -> {failed_to_read_project_file, Path, _capture} end
).
-file("src/drip/internal/project.gleam", 276).
?DOC(false).
-spec write_change(binary(), binary()) -> {ok, file_change()} |
{error, drip@internal@error:error()}.
write_change(Path, Body) ->
gleam@result:'try'(file_exists(Path), fun(Exists) -> case Exists of
false ->
gleam@result:'try'(
write_file(Path, Body),
fun(_) -> {ok, {created, Path}} end
);
true ->
gleam@result:'try'(
read_file(Path),
fun(Current) -> case Current =:= Body of
true ->
{ok, {unmodified, Path}};
false ->
gleam@result:'try'(
write_file(Path, Body),
fun(_) -> {ok, {modified, Path}} end
)
end end
)
end end).
-file("src/drip/internal/project.gleam", 184).
?DOC(false).
-spec write_settings(
project(),
gleam@option:option(binary()),
gleam@option:option(binary())
) -> {ok, list(file_change())} | {error, drip@internal@error:error()}.
write_settings(Project, Prefix, Source) ->
Settings = lists:append([case Prefix of
{some, Value} ->
[{<<"prefix"/utf8>>, Value}];
none ->
[]
end, case Source of
{some, Value@1} ->
[{<<"source"/utf8>>, Value@1}];
none ->
[]
end]),
case Settings of
[] ->
{ok, []};
_ ->
Path = gleam_toml_path(Project),
gleam@result:'try'(
read_file(Path),
fun(Raw) ->
gleam@result:'try'(
begin
_pipe = tomlet:parse(Raw),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {failed_to_parse_gleam_toml, Field@0} end
)
end,
fun(Document) ->
gleam@result:'try'(
case tomlet:get(
Document,
[<<"tools"/utf8>>, <<"drip"/utf8>>]
) of
{ok, _} ->
{ok, Document};
{error, _} ->
_pipe@1 = tomlet:parse(
<<(gleam@string:trim_end(Raw))/binary,
"\n\n"/utf8>>
),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {failed_to_parse_gleam_toml, Field@0} end
)
end,
fun(Document@1) ->
gleam@result:'try'(
gleam@list:try_fold(
Settings,
Document@1,
fun(Document@2, Setting) ->
{Key, Value@2} = Setting,
_pipe@2 = tomlet:set_string(
Document@2,
[<<"tools"/utf8>>,
<<"drip"/utf8>>,
Key],
Value@2
),
gleam@result:map_error(
_pipe@2,
fun(Field@0) -> {failed_to_edit_gleam_toml, Field@0} end
)
end
),
fun(Updated) ->
gleam@result:map(
write_change(
Path,
tomlet:to_string(Updated)
),
fun(Change) -> [Change] end
)
end
)
end
)
end
)
end
)
end.
-file("src/drip/internal/project.gleam", 267).
?DOC(false).
-spec write_changes(list({binary(), binary()})) -> {ok, list(file_change())} |
{error, drip@internal@error:error()}.
write_changes(Files) ->
gleam@list:try_map(
Files,
fun(File) ->
{Path, Body} = File,
write_change(Path, Body)
end
).
-file("src/drip/internal/project.gleam", 303).
?DOC(false).
-spec delete_file(binary()) -> {ok, nil} | {error, drip@internal@error:error()}.
delete_file(Path) ->
_pipe = simplifile_erl:delete(Path),
gleam@result:map_error(
_pipe,
fun(_capture) -> {failed_to_delete_project_file, Path, _capture} end
).
-file("src/drip/internal/project.gleam", 296).
?DOC(false).
-spec delete_files(list(binary())) -> {ok, list(file_change())} |
{error, drip@internal@error:error()}.
delete_files(Paths) ->
gleam@list:try_map(
Paths,
fun(Path) ->
gleam@result:map(delete_file(Path), fun(_) -> {deleted, Path} end)
end
).
-file("src/drip/internal/project.gleam", 320).
?DOC(false).
-spec vendored_filenames(project()) -> {ok, list(binary())} |
{error, drip@internal@error:error()}.
vendored_filenames(Project) ->
read_vendor_directory(Project).
-file("src/drip/internal/project.gleam", 325).
?DOC(false).
-spec vendored_in(list(binary()), binary()) -> boolean().
vendored_in(Filenames, Name) ->
gleam@list:any(
Filenames,
fun(Filename) ->
gleam_stdlib:string_starts_with(Filename, <<Name/binary, "."/utf8>>)
end
).
-file("src/drip/internal/project.gleam", 358).
?DOC(false).
-spec index_css_body(list(binary())) -> binary().
index_css_body(Css_files) ->
Imports = begin
_pipe = Css_files,
_pipe@1 = gleam@list:unique(_pipe),
_pipe@2 = gleam@list:sort(_pipe@1, fun gleam@string:compare/2),
gleam@list:map(
_pipe@2,
fun(Name) ->
<<<<"@import \"./"/utf8, Name/binary>>/binary, "\";"/utf8>>
end
)
end,
<<(gleam@string:join(
[<<"/* Generated by drip; do not edit. "/utf8,
"Run drip add / drip remove to change it. */"/utf8>>,
<<"@import \"./theme.css\";"/utf8>> |
Imports],
<<"\n"/utf8>>
))/binary,
"\n"/utf8>>.
-file("src/drip/internal/project.gleam", 367).
?DOC(false).
-spec is_element_css(binary()) -> boolean().
is_element_css(Name) ->
(gleam_stdlib:string_ends_with(Name, <<".css"/utf8>>) andalso (Name /= <<"theme.css"/utf8>>))
andalso (Name /= <<"index.css"/utf8>>).
-file("src/drip/internal/project.gleam", 347).
?DOC(false).
-spec current_index_css_body(project()) -> {ok, binary()} |
{error, drip@internal@error:error()}.
current_index_css_body(Project) ->
gleam@result:'try'(
read_vendor_directory(Project),
fun(Filenames) ->
Css_files = gleam@list:filter(Filenames, fun is_element_css/1),
{ok, index_css_body(Css_files)}
end
).
-file("src/drip/internal/project.gleam", 340).
?DOC(false).
-spec rewrite_index_css(project()) -> {ok, file_change()} |
{error, drip@internal@error:error()}.
rewrite_index_css(Project) ->
gleam@result:'try'(
current_index_css_body(Project),
fun(Body) -> write_change(index_css_path(Project), Body) end
).
-file("src/drip/internal/project.gleam", 381).
?DOC(false).
-spec index_import(project()) -> binary().
index_import(Project) ->
<<<<"@import \"./"/utf8, (prefix(Project))/binary>>/binary,
"/index.css\";"/utf8>>.
-file("src/drip/internal/project.gleam", 377).
?DOC(false).
-spec entry_css_body(project()) -> binary().
entry_css_body(Project) ->
<<<<<<"@import \"tailwindcss\";"/utf8, "\n"/utf8>>/binary,
(index_import(Project))/binary>>/binary,
"\n"/utf8>>.
-file("src/drip/internal/project.gleam", 439).
?DOC(false).
-spec is_tailwind_import(binary()) -> boolean().
is_tailwind_import(Line) ->
Line@1 = gleam@string:trim(Line),
gleam_stdlib:string_starts_with(Line@1, <<"@import"/utf8>>) andalso gleam_stdlib:contains_string(
Line@1,
<<"tailwindcss"/utf8>>
).
-file("src/drip/internal/project.gleam", 428).
?DOC(false).
-spec splice_after_tailwind(list(binary()), binary()) -> list(binary()).
splice_after_tailwind(Lines, Import_line) ->
case gleam@list:split_while(
Lines,
fun(Line) -> not is_tailwind_import(Line) end
) of
{_, []} ->
Lines;
{Before, [Anchor | After]} ->
lists:append(Before, [Anchor, Import_line | After])
end.
-file("src/drip/internal/project.gleam", 408).
?DOC(false).
-spec merge_index_import(project(), binary()) -> gleam@option:option(binary()).
merge_index_import(Project, Body) ->
Import_line = index_import(Project),
Lines = gleam@string:split(Body, <<"\n"/utf8>>),
Has_index = gleam@list:any(
Lines,
fun(Line) -> gleam@string:trim(Line) =:= Import_line end
),
Has_tailwind = gleam@list:any(Lines, fun is_tailwind_import/1),
case {Has_index, Has_tailwind} of
{true, true} ->
none;
{true, false} ->
{some,
<<<<"@import \"tailwindcss\";"/utf8, "\n"/utf8>>/binary,
Body/binary>>};
{false, true} ->
{some,
gleam@string:join(
splice_after_tailwind(Lines, Import_line),
<<"\n"/utf8>>
)};
{false, false} ->
{some, <<(entry_css_body(Project))/binary, Body/binary>>}
end.
-file("src/drip/internal/project.gleam", 387).
?DOC(false).
-spec wire_entry_css(project()) -> {ok, file_change()} |
{error, drip@internal@error:error()}.
wire_entry_css(Project) ->
Path = entry_css_path(Project),
gleam@result:'try'(file_exists(Path), fun(Exists) -> case Exists of
false ->
gleam@result:'try'(
write_file(Path, entry_css_body(Project)),
fun(_) -> {ok, {created, Path}} end
);
true ->
gleam@result:'try'(
read_file(Path),
fun(Body) -> case merge_index_import(Project, Body) of
none ->
{ok, {unmodified, Path}};
{some, Merged} ->
gleam@result:'try'(
write_file(Path, Merged),
fun(_) -> {ok, {modified, Path}} end
)
end end
)
end end).
-file("src/drip/internal/project.gleam", 464).
?DOC(false).
-spec guard_overwrite(list(binary()), overwrite()) -> {ok, nil} |
{error, drip@internal@error:error()}.
guard_overwrite(Paths, Overwrite) ->
case Overwrite of
force ->
{ok, nil};
preserve ->
gleam@list:try_each(
Paths,
fun(Path) ->
gleam@result:'try'(
file_exists(Path),
fun(Exists) -> case Exists of
true ->
{error, {project_file_already_exists, Path}};
false ->
{ok, nil}
end end
)
end
)
end.
-file("src/drip/internal/project.gleam", 446).
?DOC(false).
-spec scaffold(project(), overwrite()) -> {ok, list(file_change())} |
{error, drip@internal@error:error()}.
scaffold(Project, Overwrite) ->
Theme = theme_css_path(Project),
Index = index_css_path(Project),
gleam@result:'try'(
guard_overwrite([Theme, Index], Overwrite),
fun(_) ->
gleam@result:'try'(
drip@internal@source:fetch(
erlang:element(5, Project),
<<"theme.css"/utf8>>
),
fun(Theme_body) ->
gleam@result:'try'(
write_change(Theme, Theme_body),
fun(Theme_change) ->
gleam@result:'try'(
current_index_css_body(Project),
fun(Index_body) ->
gleam@result:'try'(
write_change(Index, Index_body),
fun(Index_change) ->
gleam@result:'try'(
wire_entry_css(Project),
fun(Entry) ->
{ok,
[Theme_change,
Index_change,
Entry]}
end
)
end
)
end
)
end
)
end
)
end
).