-module(molt@internal@document@remove).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/document/remove.gleam").
-export([prune/3, delete/2]).
-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/document/remove.gleam", 176).
?DOC(false).
-spec remove_missing(
molt@types:document(),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key(),
list(molt@types:path_segment())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
remove_missing(Doc, Idx, Key, Segments) ->
case molt@internal@document@index:find_deepest_ancestor_entry(Idx, Key) of
{ok, {index_scalar_value, _}} ->
gleam@result:'try'(
begin
_pipe = molt@internal@cst@query:get_cursor(
erlang:element(4, Doc),
Segments
),
gleam@result:replace_error(
_pipe,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor) ->
gleam@result:'try'(
begin
_pipe@1 = greenwood@zipper:delete(Cursor),
gleam@option:to_result(
_pipe@1,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor@1) ->
_pipe@2 = greenwood@zipper:unzip(Cursor@1),
_pipe@3 = molt@internal@document@primitives:patch(
Doc,
_pipe@2,
Idx
),
{ok, _pipe@3}
end
)
end
);
{ok, {index_array_value, _}} ->
gleam@result:'try'(
begin
_pipe = molt@internal@cst@query:get_cursor(
erlang:element(4, Doc),
Segments
),
gleam@result:replace_error(
_pipe,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor) ->
gleam@result:'try'(
begin
_pipe@1 = greenwood@zipper:delete(Cursor),
gleam@option:to_result(
_pipe@1,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor@1) ->
_pipe@2 = greenwood@zipper:unzip(Cursor@1),
_pipe@3 = molt@internal@document@primitives:patch(
Doc,
_pipe@2,
Idx
),
{ok, _pipe@3}
end
)
end
);
{ok, {index_inline_table_value, _}} ->
gleam@result:'try'(
begin
_pipe = molt@internal@cst@query:get_cursor(
erlang:element(4, Doc),
Segments
),
gleam@result:replace_error(
_pipe,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor) ->
gleam@result:'try'(
begin
_pipe@1 = greenwood@zipper:delete(Cursor),
gleam@option:to_result(
_pipe@1,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor@1) ->
_pipe@2 = greenwood@zipper:unzip(Cursor@1),
_pipe@3 = molt@internal@document@primitives:patch(
Doc,
_pipe@2,
Idx
),
{ok, _pipe@3}
end
)
end
);
_ ->
{error, molt@error:not_found_path(Segments)}
end.
-file("src/molt/internal/document/remove.gleam", 326).
?DOC(false).
-spec counters_match(list({list(binary()), integer()}), list(integer())) -> boolean().
counters_match(Scopes, Counters) ->
case {Scopes, Counters} of
{[], []} ->
true;
{[{_, Idx} | S], [C | Cs]} ->
(Idx =:= C) andalso counters_match(S, Cs);
{_, _} ->
false
end.
-file("src/molt/internal/document/remove.gleam", 311).
?DOC(false).
-spec bump_counters(
list({list(binary()), integer()}),
list(integer()),
list(binary())
) -> list(integer()).
bump_counters(Scopes, Counters, Kp) ->
case {Scopes, Counters} of
{[{Family, _} | S_rest], [C | C_rest]} ->
case Family =:= Kp of
true ->
[C + 1 | gleam@list:map(C_rest, fun(_) -> -1 end)];
false ->
[C | bump_counters(S_rest, C_rest, Kp)]
end;
{_, _} ->
Counters
end.
-file("src/molt/internal/document/remove.gleam", 280).
?DOC(false).
-spec remove_scoped_family(
list(greenwood:element(molt@types:toml_kind())),
list({list(binary()), integer()}),
list(binary()),
list(integer()),
list(greenwood:element(molt@types:toml_kind()))
) -> list(greenwood:element(molt@types:toml_kind())).
remove_scoped_family(Children, Scopes, Target, Counters, Acc) ->
case Children of
[] ->
lists:reverse(Acc);
[{node_element, N} | Rest] when (erlang:element(2, N) =:= array_of_tables) orelse (erlang:element(
2,
N
) =:= table) ->
Kp = molt@internal@cst@elements:extract_key_segments(
erlang:element(3, N)
),
Counters@1 = bump_counters(Scopes, Counters, Kp),
Drop = (gleam@list:take(Kp, erlang:length(Target)) =:= Target)
andalso counters_match(Scopes, Counters@1),
Acc@1 = case Drop of
true ->
Acc;
false ->
[{node_element, N} | Acc]
end,
remove_scoped_family(Rest, Scopes, Target, Counters@1, Acc@1);
[El | Rest@1] ->
remove_scoped_family(Rest@1, Scopes, Target, Counters, [El | Acc])
end.
-file("src/molt/internal/document/remove.gleam", 261).
?DOC(false).
-spec do_index_scopes(
list(molt@types:path_segment()),
list(binary()),
list({list(binary()), integer()})
) -> list({list(binary()), integer()}).
do_index_scopes(Remaining, Keys, Acc) ->
case Remaining of
[] ->
lists:reverse(Acc);
[{key_segment, K} | Rest] ->
do_index_scopes(Rest, lists:append(Keys, [K]), Acc);
[{index_segment, I} | Rest@1] ->
do_index_scopes(Rest@1, Keys, [{Keys, I} | Acc])
end.
-file("src/molt/internal/document/remove.gleam", 257).
?DOC(false).
-spec index_scopes(list(molt@types:path_segment())) -> list({list(binary()),
integer()}).
index_scopes(Segments) ->
do_index_scopes(Segments, [], []).
-file("src/molt/internal/document/remove.gleam", 65).
?DOC(false).
-spec remove_existing_array_of_tables(
molt@types:document(),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
remove_existing_array_of_tables(Doc, Idx, Segments) ->
case molt@internal@path:contains_index(Segments) of
false ->
Target_path = molt@internal@path:path_to_table_header(Segments),
New_tree = greenwood:remove_children(
erlang:element(4, Doc),
fun(El) -> case El of
{node_element, N} when erlang:element(2, N) =:= array_of_tables ->
molt@internal@cst@elements:extract_key_segments(
erlang:element(3, N)
)
=:= Target_path;
_ ->
false
end end
),
{ok, molt@internal@document@primitives:patch(Doc, New_tree, Idx)};
true ->
Norm = molt@internal@document@index:resolve_negative_indices(
Idx,
Segments
),
Scopes = index_scopes(Norm),
Target = molt@internal@path:path_to_table_header(Norm),
New_children = remove_scoped_family(
erlang:element(3, erlang:element(4, Doc)),
Scopes,
Target,
gleam@list:map(Scopes, fun(_) -> -1 end),
[]
),
{ok,
molt@internal@document@primitives:rebuild(
Doc,
begin
_record = erlang:element(4, Doc),
{node,
erlang:element(2, _record),
New_children,
erlang:element(4, _record)}
end
)}
end.
-file("src/molt/internal/document/remove.gleam", 337).
?DOC(false).
-spec is_kv_under_prefix(
greenwood:node_(molt@types:toml_kind()),
list(binary())
) -> boolean().
is_kv_under_prefix(Kv, Prefix) ->
case molt@internal@cst@elements:key_path(erlang:element(3, Kv)) of
{some, Key_parts} ->
gleam@list:take(Key_parts, erlang:length(Prefix)) =:= Prefix;
none ->
false
end.
-file("src/molt/internal/document/remove.gleam", 239).
?DOC(false).
-spec under_prefix(list(binary())) -> fun((greenwood:element(molt@types:toml_kind())) -> boolean()).
under_prefix(Prefix) ->
fun(El) -> case El of
{node_element, N} when (erlang:element(2, N) =:= table) orelse (erlang:element(
2,
N
) =:= array_of_tables) ->
gleam@list:take(
molt@internal@cst@elements:extract_key_segments(
erlang:element(3, N)
),
erlang:length(Prefix)
)
=:= Prefix;
{node_element, N@1} when erlang:element(2, N@1) =:= key_value ->
is_kv_under_prefix(N@1, Prefix);
_ ->
false
end end.
-file("src/molt/internal/document/remove.gleam", 204).
?DOC(false).
-spec remove_implicit_table(
molt@types:document(),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
remove_implicit_table(Doc, Idx, Segments) ->
case molt@internal@path:split_at_last_index(Segments) of
{error, nil} ->
Prefix = molt@internal@path:path_to_table_header(Segments),
New_tree = greenwood:remove_children(
erlang:element(4, Doc),
under_prefix(Prefix)
),
Key = molt@internal@document@index:path_to_index_key(Segments),
Idx@1 = molt@internal@document@index:prune_empty_implicit_ancestors(
Idx,
Key
),
{ok, molt@internal@document@primitives:patch(Doc, New_tree, Idx@1)};
{ok, {Entry_path, Rel_segments}} ->
Prefix@1 = molt@internal@path:path_to_table_header(Rel_segments),
gleam@result:'try'(
begin
_pipe = molt@internal@cst@query:get_cursor(
erlang:element(4, Doc),
Entry_path
),
gleam@result:replace_error(
_pipe,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor) ->
New_entry = greenwood:remove_children(
erlang:element(2, Cursor),
under_prefix(Prefix@1)
),
New_tree@1 = begin
_pipe@1 = greenwood@zipper:set_focus(Cursor, New_entry),
greenwood@zipper:unzip(_pipe@1)
end,
{ok,
molt@internal@document@primitives:rebuild(
Doc,
New_tree@1
)}
end
)
end.
-file("src/molt/internal/document/remove.gleam", 166).
?DOC(false).
-spec drop_leading_newlines(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
drop_leading_newlines(Node) ->
case erlang:element(4, Node) of
bare ->
Node;
{trivia, Leading, Trailing} ->
Stripped = gleam@list:drop_while(
Leading,
fun(T) -> erlang:element(2, T) =:= newline end
),
{node,
erlang:element(2, Node),
erlang:element(3, Node),
{trivia, Stripped, Trailing}}
end.
-file("src/molt/internal/document/remove.gleam", 109).
?DOC(false).
-spec remove_value(
molt@types:document(),
list(molt@types:path_segment()),
boolean()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
remove_value(Doc, Segments, Strip_first_blank) ->
gleam@result:'try'(
begin
_pipe = molt@internal@cst@query:get_cursor(
erlang:element(4, Doc),
Segments
),
gleam@result:replace_error(
_pipe,
molt@error:not_found_path(Segments)
)
end,
fun(Cursor) ->
Is_first_with_right_sibling = case {Strip_first_blank,
erlang:element(3, Cursor)} of
{true, [Crumb | _]} ->
not gleam@list:any(
erlang:element(4, Crumb),
fun(El) -> case El of
{node_element, _} ->
true;
_ ->
false
end end
)
andalso gleam@list:any(
erlang:element(5, Crumb),
fun(El@1) -> case El@1 of
{node_element, _} ->
true;
_ ->
false
end end
);
{_, _} ->
false
end,
case greenwood@zipper:delete(Cursor) of
{some, Cursor@1} ->
Cursor@2 = case Is_first_with_right_sibling of
false ->
Cursor@1;
true ->
greenwood@zipper:set_focus(
Cursor@1,
drop_leading_newlines(
erlang:element(2, Cursor@1)
)
)
end,
{ok,
molt@internal@document@primitives:rebuild(
Doc,
greenwood@zipper:unzip(Cursor@2)
)};
none ->
gleam@result:'try'(
molt@cst:delete(erlang:element(4, Doc), Segments),
fun(New_tree) ->
{ok,
molt@internal@document@primitives:rebuild(
Doc,
New_tree
)}
end
)
end
end
).
-file("src/molt/internal/document/remove.gleam", 39).
?DOC(false).
-spec remove_existing(
molt@types:document(),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment()),
molt@types:index_entry()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
remove_existing(Doc, Idx, Segments, Entry) ->
Key = molt@internal@document@index:path_to_index_key(Segments),
Idx@1 = molt@internal@document@index:remove_subtree(Idx, Key),
case Entry of
{index_scalar_value, _} ->
remove_value(Doc, Segments, false);
{index_array_value, _} ->
remove_value(Doc, Segments, false);
{index_inline_table_value, _} ->
remove_value(Doc, Segments, false);
{index_table, _} ->
remove_value(Doc, Segments, false);
{index_array_of_tables_entry, _, _, _} ->
remove_value(Doc, Segments, true);
{index_implicit_table, _} ->
remove_implicit_table(Doc, Idx@1, Segments);
{index_array_of_tables, _, _} ->
remove_existing_array_of_tables(Doc, Idx@1, Segments)
end.
-file("src/molt/internal/document/remove.gleam", 24).
?DOC(false).
-spec prune(
molt@types:document(),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
prune(Doc, Idx, Segments) ->
Lookup = molt@internal@document@index:resolve_negative_indices(
Idx,
Segments
),
Key = molt@internal@document@index:path_to_index_key(Lookup),
case molt@internal@document@index:get(Idx, Key) of
{ok, Entry} ->
remove_existing(Doc, Idx, Segments, Entry);
{error, nil} ->
remove_missing(Doc, Idx, Key, Segments)
end.
-file("src/molt/internal/document/remove.gleam", 15).
?DOC(false).
-spec delete(molt@types:document(), binary()) -> {ok, molt@types:document()} |
{error, molt@error:molt_error()}.
delete(Doc, P) ->
gleam@result:'try'(
molt@internal@path:parse(P),
fun(Segments) ->
molt@internal@document@index:with_index(
Doc,
fun(Idx) -> prune(Doc, Idx, Segments) end
)
end
).