-module(automata@fsevent@path).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/fsevent/path.gleam").
-export([path_to_string/1, path_segments/1, path_is_absolute/1, path_equals/2, path_starts_with/2, normalize/1]).
-export_type([normalized_path/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.
-opaque normalized_path() :: {normalized_path,
binary(),
list(binary()),
boolean()}.
-file("src/automata/fsevent/path.gleam", 43).
?DOC(" The canonical string rendering of a normalised path.\n").
-spec path_to_string(normalized_path()) -> binary().
path_to_string(Path) ->
erlang:element(2, Path).
-file("src/automata/fsevent/path.gleam", 48).
?DOC(" The path's segments in source order (the empty root has no segments).\n").
-spec path_segments(normalized_path()) -> list(binary()).
path_segments(Path) ->
erlang:element(3, Path).
-file("src/automata/fsevent/path.gleam", 56).
?DOC(
" `True` when the path is rooted: it either begins with a leading\n"
" separator after normalisation (`/foo`, `\\\\srv\\share` → `//srv/share`)\n"
" or its first segment is a Windows drive letter (`C:\\foo` → first\n"
" segment `C:`). Relative paths return `False`.\n"
).
-spec path_is_absolute(normalized_path()) -> boolean().
path_is_absolute(Path) ->
erlang:element(4, Path).
-file("src/automata/fsevent/path.gleam", 61).
?DOC(" Structural equality on the canonicalised representation.\n").
-spec path_equals(normalized_path(), normalized_path()) -> boolean().
path_equals(Left, Right) ->
erlang:element(2, Left) =:= erlang:element(2, Right).
-file("src/automata/fsevent/path.gleam", 81).
-spec segments_start_with(list(binary()), list(binary())) -> boolean().
segments_start_with(Path, Prefix) ->
case Prefix of
[] ->
true;
[Head_prefix | Rest_prefix] ->
case Path of
[] ->
false;
[Head_path | Rest_path] ->
case Head_path =:= Head_prefix of
false ->
false;
true ->
segments_start_with(Rest_path, Rest_prefix)
end
end
end.
-file("src/automata/fsevent/path.gleam", 71).
?DOC(
" `True` when `path` is `prefix` itself or sits beneath `prefix` as a\n"
" proper ancestor relation (segment-wise; `/var/log` does not start\n"
" with `/var/lo`).\n"
).
-spec path_starts_with(normalized_path(), normalized_path()) -> boolean().
path_starts_with(Path, Prefix) ->
case erlang:element(4, Prefix) =:= erlang:element(4, Path) of
false ->
false;
true ->
segments_start_with(
erlang:element(3, Path),
erlang:element(3, Prefix)
)
end.
-file("src/automata/fsevent/path.gleam", 96).
-spec validate_segments(binary(), list(binary())) -> {ok, nil} |
{error, automata@fsevent@ast:fsevent_error()}.
validate_segments(Original, Segments) ->
case Segments of
[] ->
{ok, nil};
[Head | Rest] ->
case Head of
<<"."/utf8>> ->
{error, {path_contains_dot_segment, Original, <<"."/utf8>>}};
<<".."/utf8>> ->
{error,
{path_contains_dot_segment, Original, <<".."/utf8>>}};
_ ->
validate_segments(Original, Rest)
end
end.
-file("src/automata/fsevent/path.gleam", 118).
-spec is_drive_letter(binary()) -> boolean().
is_drive_letter(Segment) ->
case Segment of
<<"A:"/utf8>> ->
true;
<<"B:"/utf8>> ->
true;
<<"C:"/utf8>> ->
true;
<<"D:"/utf8>> ->
true;
<<"E:"/utf8>> ->
true;
<<"F:"/utf8>> ->
true;
<<"G:"/utf8>> ->
true;
<<"H:"/utf8>> ->
true;
<<"I:"/utf8>> ->
true;
<<"J:"/utf8>> ->
true;
<<"K:"/utf8>> ->
true;
<<"L:"/utf8>> ->
true;
<<"M:"/utf8>> ->
true;
<<"N:"/utf8>> ->
true;
<<"O:"/utf8>> ->
true;
<<"P:"/utf8>> ->
true;
<<"Q:"/utf8>> ->
true;
<<"R:"/utf8>> ->
true;
<<"S:"/utf8>> ->
true;
<<"T:"/utf8>> ->
true;
<<"U:"/utf8>> ->
true;
<<"V:"/utf8>> ->
true;
<<"W:"/utf8>> ->
true;
<<"X:"/utf8>> ->
true;
<<"Y:"/utf8>> ->
true;
<<"Z:"/utf8>> ->
true;
<<"a:"/utf8>> ->
true;
<<"b:"/utf8>> ->
true;
<<"c:"/utf8>> ->
true;
<<"d:"/utf8>> ->
true;
<<"e:"/utf8>> ->
true;
<<"f:"/utf8>> ->
true;
<<"g:"/utf8>> ->
true;
<<"h:"/utf8>> ->
true;
<<"i:"/utf8>> ->
true;
<<"j:"/utf8>> ->
true;
<<"k:"/utf8>> ->
true;
<<"l:"/utf8>> ->
true;
<<"m:"/utf8>> ->
true;
<<"n:"/utf8>> ->
true;
<<"o:"/utf8>> ->
true;
<<"p:"/utf8>> ->
true;
<<"q:"/utf8>> ->
true;
<<"r:"/utf8>> ->
true;
<<"s:"/utf8>> ->
true;
<<"t:"/utf8>> ->
true;
<<"u:"/utf8>> ->
true;
<<"v:"/utf8>> ->
true;
<<"w:"/utf8>> ->
true;
<<"x:"/utf8>> ->
true;
<<"y:"/utf8>> ->
true;
<<"z:"/utf8>> ->
true;
_ ->
false
end.
-file("src/automata/fsevent/path.gleam", 111).
-spec starts_with_drive_letter(list(binary())) -> boolean().
starts_with_drive_letter(Segments) ->
case Segments of
[First | _] ->
is_drive_letter(First);
[] ->
false
end.
-file("src/automata/fsevent/path.gleam", 176).
-spec build(binary(), list(binary())) -> normalized_path().
build(Unified, Segments) ->
Joined = gleam@string:join(Segments, <<"/"/utf8>>),
Slash_prefix = gleam_stdlib:string_starts_with(Unified, <<"/"/utf8>>),
Absolute = Slash_prefix orelse starts_with_drive_letter(Segments),
Value = case {Slash_prefix, Joined} of
{true, <<""/utf8>>} ->
<<"/"/utf8>>;
{true, _} ->
<<"/"/utf8, Joined/binary>>;
{false, _} ->
Joined
end,
{normalized_path, Value, Segments, Absolute}.
-file("src/automata/fsevent/path.gleam", 23).
?DOC(
" Canonicalise a string into a `NormalizedPath`.\n"
"\n"
" The library does not call `os.path.realpath`-style resolution: it\n"
" works at the string level so it stays pure and produces the same\n"
" output on every platform regardless of the underlying filesystem.\n"
).
-spec normalize(binary()) -> {ok, normalized_path()} |
{error, automata@fsevent@ast:fsevent_error()}.
normalize(Path) ->
case Path of
<<""/utf8>> ->
{error, empty_path};
_ ->
case gleam_stdlib:contains_string(Path, <<"\x{0000}"/utf8>>) of
true ->
{error, {path_contains_null_byte, Path}};
false ->
Unified = gleam@string:replace(
Path,
<<"\\"/utf8>>,
<<"/"/utf8>>
),
Raw_segments = gleam@string:split(Unified, <<"/"/utf8>>),
Segments = gleam@list:filter(
Raw_segments,
fun(S) -> S /= <<""/utf8>> end
),
case validate_segments(Path, Segments) of
{error, Error} ->
{error, Error};
{ok, _} ->
{ok, build(Unified, Segments)}
end
end
end.