-module(molt@internal@path). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/molt/internal/path.gleam"). -export([parse/1, to_string/1, with_segment_key_name/3, split_last_segment/1, split_at_last_index/1, drop_last_segment/1, path_to_table_header/1, contains_index/1]). -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). -file("src/molt/internal/path.gleam", 119). ?DOC(false). -spec validate_segments(list(molt@types:path_segment())) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. validate_segments(Segments) -> case Segments of [{index_segment, _} | _] -> {error, {invalid_path, <<"index segments must follow a key segment"/utf8>>}}; _ -> {ok, Segments} end. -file("src/molt/internal/path.gleam", 237). ?DOC(false). -spec parse_path_bracket_index(list(binary()), binary()) -> {ok, {integer(), list(binary())}} | {error, molt@error:molt_error()}. parse_path_bracket_index(Chars, Acc) -> case Chars of [] -> {error, {invalid_path, <<"unterminated bracket"/utf8>>}}; [<<"]"/utf8>> | Rest] -> case gleam_stdlib:parse_int(Acc) of {ok, N} -> {ok, {N, Rest}}; {error, _} -> {error, {invalid_path, <<"non-integer in brackets: "/utf8, Acc/binary>>}} end; [Ch | Rest@1] -> parse_path_bracket_index(Rest@1, <>) end. -file("src/molt/internal/path.gleam", 270). ?DOC(false). -spec parse_path_double_quoted( list(binary()), list(molt@types:path_segment()), binary() ) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. parse_path_double_quoted(Chars, Segments, Acc) -> case Chars of [] -> {error, {invalid_path, <<"unterminated double quote"/utf8>>}}; [<<"\\"/utf8>> | Chars@1] -> case Chars@1 of [] -> {error, {invalid_path, <<"unterminated double quote"/utf8>>}}; [Escaped | Chars@2] -> Ch = case Escaped of <<"n"/utf8>> -> <<"\n"/utf8>>; <<"t"/utf8>> -> <<"\t"/utf8>>; <<"r"/utf8>> -> <<"\r"/utf8>>; <<"\\"/utf8>> -> <<"\\"/utf8>>; <<"\""/utf8>> -> <<"\""/utf8>>; _ -> <<"\\"/utf8, Escaped/binary>> end, parse_path_double_quoted( Chars@2, Segments, <> ) end; [<<"\""/utf8>> | Chars@3] -> parse_path_segments( Chars@3, [{key_segment, Acc} | Segments], <<""/utf8>>, false ); [Ch@1 | Chars@4] -> parse_path_double_quoted( Chars@4, Segments, <> ) end. -file("src/molt/internal/path.gleam", 252). ?DOC(false). -spec parse_path_single_quoted( list(binary()), list(molt@types:path_segment()), binary() ) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. parse_path_single_quoted(Chars, Segments, Acc) -> case Chars of [] -> {error, {invalid_path, <<"unterminated single quote"/utf8>>}}; [<<"'"/utf8>> | Chars@1] -> parse_path_segments( Chars@1, [{key_segment, Acc} | Segments], <<""/utf8>>, false ); [Ch | Chars@2] -> parse_path_single_quoted( Chars@2, Segments, <> ) end. -file("src/molt/internal/path.gleam", 216). ?DOC(false). -spec parse_path_after_bracket(list(binary()), list(molt@types:path_segment())) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. parse_path_after_bracket(Chars, Segments) -> case Chars of [] -> {ok, lists:reverse(Segments)}; [<<"."/utf8>> | Rest] -> parse_path_segments(Rest, Segments, <<""/utf8>>, true); [<<"["/utf8>> | Rest@1] -> case parse_path_bracket_index(Rest@1, <<""/utf8>>) of {ok, {Index, Remaining}} -> parse_path_after_bracket( Remaining, [{index_segment, Index} | Segments] ); {error, Error} -> {error, Error} end; _ -> {error, {invalid_path, <<"expected dot or bracket after index"/utf8>>}} end. -file("src/molt/internal/path.gleam", 127). ?DOC(false). -spec parse_path_segments( list(binary()), list(molt@types:path_segment()), binary(), boolean() ) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. parse_path_segments(Chars, Segments, Current, Need_segment) -> case Chars of [] -> case {Current, Need_segment} of {<<""/utf8>>, true} -> {error, {invalid_path, <<"trailing dot"/utf8>>}}; {<<""/utf8>>, false} -> {ok, lists:reverse(Segments)}; {_, _} -> {ok, lists:reverse([{key_segment, Current} | Segments])} end; [<<"."/utf8>> | Rest] -> case {Current, Need_segment orelse (Segments =:= [])} of {<<""/utf8>>, true} -> {error, {invalid_path, <<"empty segment"/utf8>>}}; {<<""/utf8>>, false} -> parse_path_segments(Rest, Segments, <<""/utf8>>, true); {_, _} -> parse_path_segments( Rest, [{key_segment, Current} | Segments], <<""/utf8>>, true ) end; [<<"["/utf8>> | Rest@1] -> gleam@bool:guard( Need_segment andalso (Current =:= <<""/utf8>>), {error, {invalid_path, <<"empty segment before bracket"/utf8>>}}, fun() -> Segments@1 = case Current of <<""/utf8>> -> Segments; _ -> [{key_segment, Current} | Segments] end, case parse_path_bracket_index(Rest@1, <<""/utf8>>) of {ok, {Index, Remaining}} -> parse_path_after_bracket( Remaining, [{index_segment, Index} | Segments@1] ); {error, Error} -> {error, Error} end end ); [<<"'"/utf8>> | Chars@1] -> gleam@bool:guard( Current /= <<""/utf8>>, {error, {invalid_path, <<"unexpected quote in bare key"/utf8>>}}, fun() -> parse_path_single_quoted(Chars@1, Segments, <<""/utf8>>) end ); [<<"\""/utf8>> | Chars@2] -> gleam@bool:guard( Current /= <<""/utf8>>, {error, {invalid_path, <<"unexpected quote in bare key"/utf8>>}}, fun() -> parse_path_double_quoted(Chars@2, Segments, <<""/utf8>>) end ); [Ch | Chars@3] -> gleam@bool:guard( not molt@internal@utils:is_bare_key(Ch), {error, {invalid_path, <<<<"invalid character '"/utf8, Ch/binary>>/binary, "' in bare key segment; quote the segment with ' or \""/utf8>>}}, fun() -> parse_path_segments( Chars@3, Segments, <>, false ) end ) end. -file("src/molt/internal/path.gleam", 19). ?DOC(false). -spec parse(binary()) -> {ok, list(molt@types:path_segment())} | {error, molt@error:molt_error()}. parse(Input) -> case Input of <<""/utf8>> -> {ok, []}; _ -> case parse_path_segments( gleam@string:to_graphemes(Input), [], <<""/utf8>>, false ) of {ok, Segments} -> validate_segments(Segments); {error, Error} -> {error, Error} end end. -file("src/molt/internal/path.gleam", 37). ?DOC(false). -spec to_string(list(molt@types:path_segment())) -> binary(). to_string(Segments) -> molt@internal@utils:path_to_string(Segments). -file("src/molt/internal/path.gleam", 41). ?DOC(false). -spec with_segment_key_name( molt@types:path_segment(), IHN, fun((binary()) -> IHN) ) -> IHN. with_segment_key_name(Segment, Return, Do) -> case Segment of {key_segment, Name} -> Do(Name); {index_segment, _} -> Return end. -file("src/molt/internal/path.gleam", 52). ?DOC(false). -spec split_last_segment(list(molt@types:path_segment())) -> {list(molt@types:path_segment()), molt@types:path_segment()}. split_last_segment(Segments) -> gleam@bool:guard( Segments =:= [], {[], {key_segment, <<""/utf8>>}}, fun() -> case lists:reverse(Segments) of [Last | Rest] -> {lists:reverse(Rest), Last}; [] -> {[], {key_segment, <<""/utf8>>}} end end ). -file("src/molt/internal/path.gleam", 71). ?DOC(false). -spec do_split_at_last_index( list(molt@types:path_segment()), list(molt@types:path_segment()) ) -> {ok, {list(molt@types:path_segment()), list(molt@types:path_segment())}} | {error, nil}. do_split_at_last_index(Rev_remaining, After) -> case Rev_remaining of [] -> {error, nil}; [{index_segment, I} | Rest] -> {ok, {lists:reverse([{index_segment, I} | Rest]), After}}; [Segment | Rest@1] -> do_split_at_last_index(Rest@1, [Segment | After]) end. -file("src/molt/internal/path.gleam", 67). ?DOC(false). -spec split_at_last_index(list(molt@types:path_segment())) -> {ok, {list(molt@types:path_segment()), list(molt@types:path_segment())}} | {error, nil}. split_at_last_index(Segments) -> do_split_at_last_index(lists:reverse(Segments), []). -file("src/molt/internal/path.gleam", 83). ?DOC(false). -spec drop_last_segment(list(molt@types:path_segment())) -> list(molt@types:path_segment()). drop_last_segment(Path) -> {Path@1, _} = split_last_segment(Path), Path@1. -file("src/molt/internal/path.gleam", 94). ?DOC(false). -spec path_to_table_header(list(molt@types:path_segment())) -> list(binary()). path_to_table_header(Segments) -> gleam@list:filter_map(Segments, fun(Seg) -> case Seg of {key_segment, K} -> {ok, K}; {index_segment, _} -> {error, nil} end end). -file("src/molt/internal/path.gleam", 112). ?DOC(false). -spec is_index_segment(molt@types:path_segment()) -> boolean(). is_index_segment(Seg) -> case Seg of {index_segment, _} -> true; {key_segment, _} -> false end. -file("src/molt/internal/path.gleam", 108). ?DOC(false). -spec contains_index(list(molt@types:path_segment())) -> boolean(). contains_index(Segments) -> gleam@list:any(Segments, fun is_index_segment/1).