Skip to main content

src/molt@internal@document@primitives.erl

-module(molt@internal@document@primitives).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/document/primitives.gleam").
-export([patch/3, rebuild_kv_value/2, rebuild_array_element/2, cursor_replace_value/4, insert_kv_before_first_header/2, write_at_site/5, rebuild/2, find_kv_value/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/primitives.gleam", 23).
?DOC(false).
-spec patch(
    molt@types:document(),
    greenwood:node_(molt@types:toml_kind()),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> molt@types:document().
patch(Doc, Tree, Idx) ->
    {document,
        erlang:element(2, Doc),
        erlang:element(3, Doc),
        Tree,
        {some, Idx}}.

-file("src/molt/internal/document/primitives.gleam", 67).
?DOC(false).
-spec rebuild_kv_value(
    greenwood:node_(molt@types:toml_kind()),
    greenwood:element(molt@types:toml_kind())
) -> greenwood:node_(molt@types:toml_kind()).
rebuild_kv_value(Kv, New_value) ->
    case molt@internal@cst@elements:split_at_equals(erlang:element(3, Kv)) of
        {Prefix, [Eq | After_eq]} ->
            {Ws, After_ws} = molt@internal@cst@elements:split_leading_ws(
                After_eq
            ),
            {Old_value, Trailing} = molt@internal@cst@elements:split_before_trivia(
                After_ws
            ),
            Trailing_ws = molt@internal@cst@elements:take_trailing_ws(Old_value),
            {node,
                erlang:element(2, Kv),
                lists:append(
                    [Prefix, [Eq], Ws, [New_value], Trailing_ws, Trailing]
                ),
                erlang:element(4, Kv)};

        {_, []} ->
            Kv
    end.

-file("src/molt/internal/document/primitives.gleam", 57).
?DOC(false).
-spec rebuild_array_element(
    greenwood:node_(molt@types:toml_kind()),
    greenwood:element(molt@types:toml_kind())
) -> greenwood:node_(molt@types:toml_kind()).
rebuild_array_element(Element, New_value) ->
    case erlang:element(3, Element) of
        [_ | Trailing] ->
            {node,
                erlang:element(2, Element),
                [New_value | Trailing],
                erlang:element(4, Element)};

        [] ->
            {node,
                erlang:element(2, Element),
                [New_value],
                erlang:element(4, Element)}
    end.

-file("src/molt/internal/document/primitives.gleam", 32).
?DOC(false).
-spec cursor_replace_value(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    greenwood:element(molt@types:toml_kind())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
cursor_replace_value(Doc, Idx, Segments, New_value) ->
    Key = molt@internal@document@index:path_to_index_key(Segments),
    {Container, _} = molt@internal@path:split_last_segment(Segments),
    Entry = molt@internal@document@index:entry_for_element(New_value, Container),
    Idx@1 = molt@internal@document@index:update_entry(Idx, Key, Entry),
    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) ->
            New_node = case erlang:element(2, erlang:element(2, Cursor)) of
                array_element ->
                    rebuild_array_element(erlang:element(2, Cursor), New_value);

                _ ->
                    rebuild_kv_value(erlang:element(2, Cursor), New_value)
            end,
            _pipe@1 = greenwood@zipper:set_focus(Cursor, New_node),
            _pipe@2 = greenwood@zipper:unzip(_pipe@1),
            _pipe@3 = patch(Doc, _pipe@2, Idx@1),
            {ok, _pipe@3}
        end
    ).

-file("src/molt/internal/document/primitives.gleam", 290).
?DOC(false).
-spec insert_kv_into_inline_container(
    greenwood:node_(molt@types:toml_kind()),
    greenwood:element(molt@types:toml_kind())
) -> greenwood:node_(molt@types:toml_kind()).
insert_kv_into_inline_container(Container, Kv_el) ->
    Children = lists:reverse(erlang:element(3, Container)),
    New_children = case Children of
        [{token_element, {token, right_brace, _}} = Rb | Rest] ->
            lists:reverse(
                [Rb,
                    Kv_el,
                    {token_element, {token, whitespace, <<" "/utf8>>}},
                    {token_element, {token, comma, <<""/utf8>>}} |
                    Rest]
            );

        _ ->
            lists:append(erlang:element(3, Container), [Kv_el])
    end,
    {node,
        erlang:element(2, Container),
        New_children,
        erlang:element(4, Container)}.

-file("src/molt/internal/document/primitives.gleam", 269).
?DOC(false).
-spec focus_inline_container(greenwood:zipper(molt@types:toml_kind())) -> {ok,
        greenwood:zipper(molt@types:toml_kind())} |
    {error, molt@error:molt_error()}.
focus_inline_container(Cursor) ->
    case erlang:element(2, erlang:element(2, Cursor)) of
        inline_table ->
            {ok, Cursor};

        key_value ->
            _pipe = greenwood@zipper:down_where(
                Cursor,
                fun(N) -> erlang:element(2, N) =:= inline_table end
            ),
            gleam@option:to_result(
                _pipe,
                {type_mismatch,
                    none,
                    <<"inline table"/utf8>>,
                    molt@internal@utils:toml_kind(
                        erlang:element(2, erlang:element(2, Cursor))
                    )}
            );

        Other ->
            {error,
                {type_mismatch,
                    none,
                    <<"inline table"/utf8>>,
                    molt@internal@utils:toml_kind(Other)}}
    end.

-file("src/molt/internal/document/primitives.gleam", 232).
?DOC(false).
-spec write_new_inline_descend_missing(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    molt@value:value()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_new_inline_descend_missing(Doc, Idx, Full_path, Val) ->
    {Container_path, Last} = molt@internal@path:split_last_segment(Full_path),
    case Last of
        {key_segment, Key} ->
            gleam@result:'try'(
                begin
                    _pipe = molt@internal@cst@query:get_cursor(
                        erlang:element(4, Doc),
                        Container_path
                    ),
                    gleam@result:replace_error(
                        _pipe,
                        molt@error:not_found_path(Full_path)
                    )
                end,
                fun(Parent_cursor) ->
                    Kv_el = {node_element,
                        molt@internal@cst@builder:build_inline_kv(
                            molt@internal@utils:quote_key(Key),
                            molt@value:to_cst(Val)
                        )},
                    gleam@result:'try'(
                        focus_inline_container(Parent_cursor),
                        fun(Insert_cursor) ->
                            New_inline = insert_kv_into_inline_container(
                                erlang:element(2, Insert_cursor),
                                Kv_el
                            ),
                            _pipe@1 = greenwood@zipper:set_focus(
                                Insert_cursor,
                                New_inline
                            ),
                            _pipe@2 = greenwood@zipper:unzip(_pipe@1),
                            _pipe@3 = patch(Doc, _pipe@2, Idx),
                            {ok, _pipe@3}
                        end
                    )
                end
            );

        _ ->
            {error, molt@error:not_found_path(Full_path)}
    end.

-file("src/molt/internal/document/primitives.gleam", 206).
?DOC(false).
-spec write_new_inline_descend(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    molt@value:value()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_new_inline_descend(Doc, Idx, Full_path, Val) ->
    case molt@internal@cst@query:get_cursor(erlang:element(4, Doc), Full_path) of
        {ok, Cursor} ->
            New_node = case erlang:element(2, erlang:element(2, Cursor)) of
                array_element ->
                    rebuild_array_element(
                        erlang:element(2, Cursor),
                        molt@value:to_cst(Val)
                    );

                _ ->
                    rebuild_kv_value(
                        erlang:element(2, Cursor),
                        molt@value:to_cst(Val)
                    )
            end,
            _pipe = greenwood@zipper:set_focus(Cursor, New_node),
            _pipe@1 = greenwood@zipper:unzip(_pipe),
            _pipe@2 = patch(Doc, _pipe@1, Idx),
            {ok, _pipe@2};

        _ ->
            write_new_inline_descend_missing(Doc, Idx, Full_path, Val)
    end.

-file("src/molt/internal/document/primitives.gleam", 119).
?DOC(false).
-spec insert_kv_before_first_header(
    greenwood:node_(molt@types:toml_kind()),
    greenwood:node_(molt@types:toml_kind())
) -> greenwood:node_(molt@types:toml_kind()).
insert_kv_before_first_header(Tree, Kv) ->
    Kv_el = {node_element, Kv},
    {Before, After} = gleam@list:split_while(
        erlang:element(3, Tree),
        fun(El) -> case El of
                {node_element, N} ->
                    (erlang:element(2, N) /= table) andalso (erlang:element(
                        2,
                        N
                    )
                    /= array_of_tables);

                _ ->
                    true
            end end
    ),
    {node,
        erlang:element(2, Tree),
        lists:append([Before, [Kv_el], After]),
        erlang:element(4, Tree)}.

-file("src/molt/internal/document/primitives.gleam", 188).
?DOC(false).
-spec write_new_root_dotted_key(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    molt@value:value()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_new_root_dotted_key(Doc, Idx, Full_path, Val) ->
    Key_names = gleam@list:filter_map(Full_path, fun(Seg) -> case Seg of
                {key_segment, Name} ->
                    {ok, molt@internal@utils:quote_key(Name)};

                {index_segment, _} ->
                    {error, nil}
            end end),
    Kv = molt@internal@cst@builder:build_kv_from_path(
        Key_names,
        molt@value:to_cst(Val)
    ),
    New_tree = insert_kv_before_first_header(erlang:element(4, Doc), Kv),
    {ok, patch(Doc, New_tree, Idx)}.

-file("src/molt/internal/document/primitives.gleam", 157).
?DOC(false).
-spec write_new_concrete_append(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    molt@value:value(),
    list(molt@types:path_segment())
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_new_concrete_append(Doc, Idx, Full_path, Val, Container_path) ->
    Tail = gleam@list:drop(Full_path, erlang:length(Container_path)),
    Key_names = gleam@list:filter_map(Tail, fun(Seg) -> case Seg of
                {key_segment, Name} ->
                    {ok, molt@internal@utils:quote_key(Name)};

                {index_segment, _} ->
                    {error, nil}
            end end),
    Kv = molt@internal@cst@builder:build_kv_from_path(
        Key_names,
        molt@value:to_cst(Val)
    ),
    gleam@result:'try'(
        begin
            _pipe = molt@internal@cst@query:get_cursor(
                erlang:element(4, Doc),
                Container_path
            ),
            gleam@result:replace_error(
                _pipe,
                molt@error:not_found_path(Container_path)
            )
        end,
        fun(Cursor) ->
            _pipe@1 = greenwood@zipper:map_focus(
                Cursor,
                fun(_capture) ->
                    greenwood:append_child(_capture, {node_element, Kv})
                end
            ),
            _pipe@2 = greenwood@zipper:unzip(_pipe@1),
            _pipe@3 = patch(Doc, _pipe@2, Idx),
            {ok, _pipe@3}
        end
    ).

-file("src/molt/internal/document/primitives.gleam", 138).
?DOC(false).
-spec do_write_new(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    list(molt@types:path_segment()),
    molt@value:value(),
    molt@internal@document@index:insertion_site()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
do_write_new(Doc, Idx, Full_path, Val, Site) ->
    case Site of
        {concrete_append, Container_path} ->
            write_new_concrete_append(Doc, Idx, Full_path, Val, Container_path);

        {root_dotted_key, Full_path@1} ->
            write_new_root_dotted_key(Doc, Idx, Full_path@1, Val);

        {inline_descend, Full_path@2} ->
            write_new_inline_descend(Doc, Idx, Full_path@2, Val)
    end.

-file("src/molt/internal/document/primitives.gleam", 94).
?DOC(false).
-spec write_at_site(
    molt@types:document(),
    gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
    molt@internal@document@index:insertion_site(),
    list(molt@types:path_segment()),
    molt@value:value()
) -> {ok, molt@types:document()} | {error, molt@error:molt_error()}.
write_at_site(Doc, Idx, Site, Full_path, Val) ->
    Idx_key = molt@internal@document@index:path_to_index_key(Full_path),
    Container = case Site of
        {root_dotted_key, _} ->
            [];

        {concrete_append, Container_path} ->
            Container_path;

        {inline_descend, _} ->
            erlang:element(1, molt@internal@path:split_last_segment(Full_path))
    end,
    Entry = molt@internal@document@index:entry_for_value(Val, Container),
    Idx@1 = molt@internal@document@index:ensure_implicit_tables(Idx, Full_path),
    Idx@2 = molt@internal@document@index:insert_entry(Idx@1, Idx_key, Entry),
    do_write_new(Doc, Idx@2, Full_path, Val, Site).

-file("src/molt/internal/document/primitives.gleam", 313).
?DOC(false).
-spec rebuild(molt@types:document(), greenwood:node_(molt@types:toml_kind())) -> molt@types:document().
rebuild(Doc, Tree) ->
    {document,
        erlang:element(2, Doc),
        erlang:element(3, Doc),
        Tree,
        begin
            _pipe = molt@internal@document@index:build_tree_index(Tree),
            {some, _pipe}
        end}.

-file("src/molt/internal/document/primitives.gleam", 319).
?DOC(false).
-spec find_kv_value(
    greenwood:node_(molt@types:toml_kind()),
    molt@types:toml_kind()
) -> {ok, greenwood:node_(molt@types:toml_kind())} | {error, nil}.
find_kv_value(Kv, Kind) ->
    gleam@list:find_map(erlang:element(3, Kv), fun(El) -> case El of
                {node_element, N} when erlang:element(2, N) =:= Kind ->
                    {ok, N};

                _ ->
                    {error, nil}
            end end).