-module(molt@internal@cst@insert). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/molt/internal/cst/insert.gleam"). -export([place/4, table_ordered/3, ensure_table/2, ensure_array_of_tables/2]). -export_type([placement/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). -type placement() :: kv_region_end | {before_kv_key, binary()} | {family_scope_end, list(binary())} | {before_family_index, list(binary()), integer()}. -file("src/molt/internal/cst/insert.gleam", 147). ?DOC(false). -spec do_insert_before_index( list(greenwood:element(molt@types:toml_kind())), list(binary()), integer(), greenwood:node_(molt@types:toml_kind()), integer(), list(greenwood:element(molt@types:toml_kind())) ) -> list(greenwood:element(molt@types:toml_kind())). do_insert_before_index(Children, Segments, Index, Entry, Current, Acc) -> case Children of [] -> lists:reverse([{node_element, Entry} | Acc]); [{node_element, N} = El | Rest] when erlang:element(2, N) =:= array_of_tables -> case molt@internal@cst@elements:extract_key_segments( erlang:element(3, N) ) =:= Segments of true when Current =:= Index -> lists:append( lists:reverse(Acc), [{node_element, Entry}, El | Rest] ); true -> do_insert_before_index( Rest, Segments, Index, Entry, Current + 1, [El | Acc] ); false -> do_insert_before_index( Rest, Segments, Index, Entry, Current, [El | Acc] ) end; [El@1 | Rest@1] -> do_insert_before_index( Rest@1, Segments, Index, Entry, Current, [El@1 | Acc] ) end. -file("src/molt/internal/cst/insert.gleam", 291). ?DOC(false). -spec do_insert_after_path_scope( list(greenwood:element(molt@types:toml_kind())), greenwood:node_(molt@types:toml_kind()), list(binary()), boolean(), list(greenwood:element(molt@types:toml_kind())) ) -> list(greenwood:element(molt@types:toml_kind())). do_insert_after_path_scope(Children, New_header, Prefix, Saw_in_scope, Acc) -> case Children of [] -> lists:reverse([{node_element, New_header} | Acc]); [{node_element, N} = El | Rest] when (erlang:element(2, N) =:= table) orelse (erlang:element( 2, N ) =:= array_of_tables) -> Header_path = molt@internal@cst@elements:extract_key_segments( erlang:element(3, N) ), case gleam@list:take(Header_path, erlang:length(Prefix)) =:= Prefix of true -> do_insert_after_path_scope( Rest, New_header, Prefix, true, [El | Acc] ); false -> case Saw_in_scope of true -> _pipe = lists:reverse( [{node_element, New_header} | Acc] ), lists:append(_pipe, [El | Rest]); false -> do_insert_after_path_scope( Rest, New_header, Prefix, false, [El | Acc] ) end end; [El@1 | Rest@1] -> do_insert_after_path_scope( Rest@1, New_header, Prefix, Saw_in_scope, [El@1 | Acc] ) end. -file("src/molt/internal/cst/insert.gleam", 277). ?DOC(false). -spec insert_after_path_scope( list(greenwood:element(molt@types:toml_kind())), greenwood:node_(molt@types:toml_kind()), list(binary()) ) -> list(greenwood:element(molt@types:toml_kind())). insert_after_path_scope(Children, New_header, Prefix) -> do_insert_after_path_scope(Children, New_header, Prefix, false, []). -file("src/molt/internal/cst/insert.gleam", 128). ?DOC(false). -spec do_insert_before_key( list(greenwood:element(molt@types:toml_kind())), binary(), greenwood:node_(molt@types:toml_kind()), list(greenwood:element(molt@types:toml_kind())) ) -> list(greenwood:element(molt@types:toml_kind())). do_insert_before_key(Children, Before, Kv, Acc) -> case Children of [] -> lists:reverse([{node_element, Kv} | Acc]); [{node_element, N} = El | Rest] when erlang:element(2, N) =:= key_value -> case molt@internal@cst@elements:key_name(erlang:element(3, N)) =:= {some, Before} of true -> lists:append( lists:reverse(Acc), [{node_element, Kv}, El | Rest] ); false -> do_insert_before_key(Rest, Before, Kv, [El | Acc]) end; [El@1 | Rest@1] -> do_insert_before_key(Rest@1, Before, Kv, [El@1 | Acc]) end. -file("src/molt/internal/cst/insert.gleam", 192). ?DOC(false). -spec insert_after_last_kv( list(greenwood:element(molt@types:toml_kind())), greenwood:node_(molt@types:toml_kind()), list(greenwood:element(molt@types:toml_kind())) ) -> list(greenwood:element(molt@types:toml_kind())). insert_after_last_kv(Children, Kv, Acc) -> case Children of [] -> lists:reverse([{node_element, Kv} | Acc]); [{node_element, N} = El | Rest] when (erlang:element(2, N) =:= table) orelse (erlang:element( 2, N ) =:= array_of_tables) -> lists:append(lists:reverse([{node_element, Kv} | Acc]), [El | Rest]); [El@1 | Rest@1] -> insert_after_last_kv(Rest@1, Kv, [El@1 | Acc]) end. -file("src/molt/internal/cst/insert.gleam", 83). ?DOC(false). -spec do_insert_kv_in_placement( greenwood:node_(molt@types:toml_kind()), greenwood:node_(molt@types:toml_kind()), placement() ) -> greenwood:node_(molt@types:toml_kind()). do_insert_kv_in_placement(Container, New, At) -> case At of kv_region_end -> Children = insert_after_last_kv( erlang:element(3, Container), New, [] ), {node, erlang:element(2, Container), Children, erlang:element(4, Container)}; {before_kv_key, Key} -> Children@1 = do_insert_before_key( erlang:element(3, Container), Key, New, [] ), {node, erlang:element(2, Container), Children@1, erlang:element(4, Container)}; {family_scope_end, Family} -> New_children = insert_after_path_scope( erlang:element(3, Container), New, Family ), {node, erlang:element(2, Container), New_children, erlang:element(4, Container)}; {before_family_index, Family@1, Index} -> Children@2 = do_insert_before_index( erlang:element(3, Container), Family@1, Index, New, 0, [] ), {node, erlang:element(2, Container), Children@2, erlang:element(4, Container)} end. -file("src/molt/internal/cst/insert.gleam", 32). ?DOC(false). -spec place( greenwood:node_(molt@types:toml_kind()), list(molt@types:path_segment()), greenwood:node_(molt@types:toml_kind()), placement() ) -> {ok, greenwood:node_(molt@types:toml_kind())} | {error, molt@error:molt_error()}. place(Node, Container, New, At) -> case Container of [] -> {ok, do_insert_kv_in_placement(Node, New, At)}; _ -> gleam@result:'try'( molt@internal@cst@query:get_cursor(Node, Container), fun(Cursor) -> case erlang:element(2, erlang:element(2, Cursor)) of root -> _pipe = greenwood@zipper:map_focus( Cursor, fun(_capture) -> do_insert_kv_in_placement(_capture, New, At) end ), _pipe@1 = greenwood@zipper:unzip(_pipe), {ok, _pipe@1}; table -> _pipe = greenwood@zipper:map_focus( Cursor, fun(_capture) -> do_insert_kv_in_placement(_capture, New, At) end ), _pipe@1 = greenwood@zipper:unzip(_pipe), {ok, _pipe@1}; array_of_tables -> _pipe = greenwood@zipper:map_focus( Cursor, fun(_capture) -> do_insert_kv_in_placement(_capture, New, At) end ), _pipe@1 = greenwood@zipper:unzip(_pipe), {ok, _pipe@1}; _ -> {error, {type_mismatch, none, <<"table-node"/utf8>>, molt@internal@utils:toml_kind( erlang:element( 2, erlang:element(2, Cursor) ) )}} end end ) end. -file("src/molt/internal/cst/insert.gleam", 363). ?DOC(false). -spec is_child_path(list(binary()), list(binary())) -> boolean(). is_child_path(Parent, Child) -> case {Parent, Child} of {[], [_ | _]} -> true; {[P | Prest], [C | Crest]} when P =:= C -> is_child_path(Prest, Crest); {_, _} -> false end. -file("src/molt/internal/cst/insert.gleam", 340). ?DOC(false). -spec table_path(greenwood:node_(molt@types:toml_kind())) -> {ok, list(binary())} | {error, nil}. table_path(Node) -> case erlang:element(2, Node) of table -> {ok, molt@internal@cst@elements:extract_key_segments( erlang:element(3, Node) )}; array_of_tables -> {ok, molt@internal@cst@elements:extract_key_segments( erlang:element(3, Node) )}; _ -> {error, nil} end. -file("src/molt/internal/cst/insert.gleam", 355). ?DOC(false). -spec in_parent_family(greenwood:node_(molt@types:toml_kind()), list(binary())) -> boolean(). in_parent_family(Node, Parent) -> case table_path(Node) of {ok, P} -> (P =:= Parent) orelse is_child_path(Parent, P); _ -> false end. -file("src/molt/internal/cst/insert.gleam", 348). ?DOC(false). -spec is_descendant_table( greenwood:node_(molt@types:toml_kind()), list(binary()) ) -> boolean(). is_descendant_table(Node, Parent) -> case table_path(Node) of {ok, P} -> is_child_path(Parent, P); _ -> false end. -file("src/molt/internal/cst/insert.gleam", 211). ?DOC(false). -spec table_ordered( greenwood:node_(molt@types:toml_kind()), greenwood:node_(molt@types:toml_kind()), list(binary()) ) -> greenwood:node_(molt@types:toml_kind()). table_ordered(Node, New_table, Segments) -> Parent_path = gleam@list:take(Segments, erlang:length(Segments) - 1), Append = fun(Into) -> Table = case erlang:element(3, Into) of [] -> molt@internal@cst@builder:drop_leading_newlines(New_table); _ -> molt@internal@cst@builder:ensure_leading_newline(New_table) end, greenwood:append_child(Into, {node_element, Table}) end, case greenwood@zipper:down_where( greenwood@zipper:zip(Node), fun(_capture) -> is_descendant_table(_capture, Segments) end ) of {some, Cursor} -> Table@1 = case greenwood@zipper:left(Cursor) of none -> molt@internal@cst@builder:drop_leading_newlines(New_table); {some, _} -> molt@internal@cst@builder:ensure_leading_newline(New_table) end, _pipe = greenwood@zipper:insert_left( Cursor, {node_element, Table@1} ), _pipe@1 = gleam@option:map(_pipe, fun greenwood@zipper:unzip/1), gleam@option:unwrap(_pipe@1, Node); none -> case Parent_path of [_ | _] -> case greenwood@zipper:down_last_where( greenwood@zipper:zip(Node), fun(_capture@1) -> in_parent_family(_capture@1, Parent_path) end ) of {some, Cursor@1} -> _pipe@2 = greenwood@zipper:insert_right( Cursor@1, {node_element, molt@internal@cst@builder:ensure_leading_newline( New_table )} ), _pipe@3 = gleam@option:map( _pipe@2, fun greenwood@zipper:unzip/1 ), gleam@option:unwrap(_pipe@3, Node); none -> Append(Node) end; [] -> Append(Node) end end. -file("src/molt/internal/cst/insert.gleam", 63). ?DOC(false). -spec ensure_table(greenwood:node_(molt@types:toml_kind()), list(binary())) -> greenwood:node_(molt@types:toml_kind()). ensure_table(Node, Path) -> New_table = molt@internal@cst@builder:build_empty_table(Path), table_ordered(Node, New_table, Path). -file("src/molt/internal/cst/insert.gleam", 73). ?DOC(false). -spec ensure_array_of_tables( greenwood:node_(molt@types:toml_kind()), list(binary()) ) -> greenwood:node_(molt@types:toml_kind()). ensure_array_of_tables(Node, Path) -> New_table = molt@internal@cst@builder:build_empty_array_of_tables(Path), table_ordered(Node, New_table, Path).