Skip to main content

src/molt@internal@document.erl

-module(molt@internal@document).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/document.gleam").
-export([run/2, list_keys/2, get_value/3, get_value_at/3]).

-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.gleam", 27).
?DOC(false).
-spec run(molt@types:document(), molt@ops:operation()) -> {ok,
        molt@types:document()} |
    {error, molt@error:molt_error()}.
run(Doc, Op) ->
    case Op of
        {set, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"set"/utf8>>, none}};

        {set, P, Value} ->
            molt@internal@document@values:set(Doc, P, Value);

        {remove, <<""/utf8>>} ->
            {error, {invalid_operation, <<"remove"/utf8>>, none}};

        {remove, P@1} ->
            molt@internal@document@remove:delete(Doc, P@1);

        {move, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"move"/utf8>>, none}};

        {move, _, <<""/utf8>>} ->
            {error, {invalid_operation, <<"move"/utf8>>, none}};

        {move, From, To} ->
            molt@internal@document@reshape:move(Doc, From, To);

        {rename, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"rename"/utf8>>, none}};

        {rename, P@2, To@1} ->
            molt@internal@document@reshape:rename(Doc, P@2, To@1);

        {ensure_exists, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"ensure_exists"/utf8>>, none}};

        {ensure_exists, P@3, Kind} ->
            molt@internal@document@structure:ensure_exists(Doc, P@3, Kind);

        {merge_values, <<""/utf8>>, _, _} ->
            {error, {invalid_operation, <<"merge_values"/utf8>>, none}};

        {merge_values, P@4, Entries, On_conflict} ->
            molt@internal@document@structure:merge_values(
                Doc,
                P@4,
                Entries,
                On_conflict
            );

        {move_keys, From@1, To@2, Keys, On_conflict@1} ->
            molt@internal@document@reshape:move_keys(
                Doc,
                From@1,
                To@2,
                Keys,
                On_conflict@1
            );

        {transfer, From@2, To@3, On_conflict@2} ->
            molt@internal@document@reshape:merge(
                Doc,
                From@2,
                To@3,
                On_conflict@2
            );

        {append, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"append"/utf8>>, none}};

        {append, P@5, Value@1} ->
            molt@internal@document@arrays:append(Doc, P@5, Value@1);

        {concat, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"concat"/utf8>>, none}};

        {concat, P@6, Values} ->
            molt@internal@document@arrays:concat(Doc, P@6, Values);

        {insert, <<""/utf8>>, _, _} ->
            {error, {invalid_operation, <<"insert"/utf8>>, none}};

        {insert, P@7, Before, Value@2} ->
            molt@internal@document@arrays:insert(Doc, P@7, Before, Value@2);

        {insert_key, P@8, Before@1, Key, Value@3} ->
            molt@internal@document@values:insert_key(
                Doc,
                P@8,
                Before@1,
                Key,
                Value@3
            );

        {update, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"update"/utf8>>, none}};

        {update, P@9, With} ->
            molt@internal@document@values:update(Doc, P@9, With);

        {representation, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"representation"/utf8>>, none}};

        {representation, P@10, Form} ->
            molt@internal@document@representation:set_representation(
                Doc,
                P@10,
                Form
            );

        {move_comments, From@3, To@4} ->
            molt@internal@document@comments:move_comments(Doc, From@3, To@4);

        {set_comments, P@11, Comments} ->
            molt@internal@document@comments:set_comments(Doc, P@11, Comments);

        {place, <<""/utf8>>, _} ->
            {error, {invalid_operation, <<"place"/utf8>>, none}};

        {place, P@12, Value@4} ->
            molt@internal@document@values:replace(Doc, P@12, Value@4)
    end.

-file("src/molt/internal/document.gleam", 95).
?DOC(false).
-spec list_keys(molt@types:document(), list(molt@types:path_segment())) -> {ok,
        list(binary())} |
    {error, molt@error:molt_error()}.
list_keys(Doc, Path) ->
    gleam@result:'try'(
        molt@internal@document@index:get_index(Doc),
        fun(Index) -> case Path of
                [] ->
                    {ok, molt@internal@document@index:root_children(Index)};

                _ ->
                    case molt@internal@document@index:get_path(Index, Path) of
                        {ok, {index_table, Children}} ->
                            {ok, Children};

                        {ok, {index_implicit_table, Children}} ->
                            {ok, Children};

                        {ok, {index_array_of_tables_entry, _, _, Children}} ->
                            {ok, Children};

                        {ok, {index_array_of_tables, _, _}} ->
                            {error,
                                {type_mismatch,
                                    {some, molt@internal@path:to_string(Path)},
                                    <<"a table entry (use an index to select an entry)"/utf8>>,
                                    <<"array of tables"/utf8>>}};

                        {ok, _} ->
                            {error,
                                {type_mismatch,
                                    {some, molt@internal@path:to_string(Path)},
                                    <<"a table"/utf8>>,
                                    <<"a value"/utf8>>}};

                        {error, nil} ->
                            {error, molt@error:not_found_path(Path)}
                    end
            end end
    ).

-file("src/molt/internal/document.gleam", 250).
?DOC(false).
-spec is_array_of_tables_with_prefix(
    greenwood:node_(molt@types:toml_kind()),
    list(binary())
) -> boolean().
is_array_of_tables_with_prefix(Node, Prefix) ->
    (erlang:element(2, Node) =:= array_of_tables) andalso (molt@internal@cst@elements:extract_key_segments(
        erlang:element(3, Node)
    )
    =:= Prefix).

-file("src/molt/internal/document.gleam", 193).
?DOC(false).
-spec navigate_flat(
    greenwood:zipper(molt@types:toml_kind()),
    list(molt@types:path_segment()),
    list(binary()),
    boolean(),
    gleam@option:option(list(binary()))
) -> gleam@option:option(greenwood:zipper(molt@types:toml_kind())).
navigate_flat(Cursor, Path, Prefix, First, Boundary) ->
    Stop = case Boundary of
        none ->
            fun(_) -> false end;

        {some, B} ->
            fun(_capture) -> is_array_of_tables_with_prefix(_capture, B) end
    end,
    case Path of
        [] ->
            greenwood@zipper:right_until(
                Cursor,
                fun(Node) ->
                    ((erlang:element(2, Node) =:= table) orelse (erlang:element(
                        2,
                        Node
                    )
                    =:= array_of_tables))
                    andalso (molt@internal@cst@elements:extract_key_segments(
                        erlang:element(3, Node)
                    )
                    =:= Prefix)
                end,
                Stop
            );

        [{key_segment, K} | Rest] ->
            navigate_flat(
                Cursor,
                Rest,
                lists:append(Prefix, [K]),
                First,
                Boundary
            );

        [{index_segment, N} | Rest@1] ->
            Pred = fun(_capture@1) ->
                is_array_of_tables_with_prefix(_capture@1, Prefix)
            end,
            Cursor@1 = case First of
                true ->
                    _pipe = greenwood@zipper:down_where(Cursor, Pred),
                    gleam@option:then(
                        _pipe,
                        fun(_capture@2) ->
                            greenwood@zipper:right_n_until(
                                _capture@2,
                                N,
                                Pred,
                                Stop
                            )
                        end
                    );

                false ->
                    _pipe@1 = greenwood@zipper:right_until(Cursor, Pred, Stop),
                    gleam@option:then(
                        _pipe@1,
                        fun(_capture@3) ->
                            greenwood@zipper:right_n_until(
                                _capture@3,
                                N,
                                Pred,
                                Stop
                            )
                        end
                    )
            end,
            gleam@option:then(Cursor@1, fun(Cursor@2) -> case Rest@1 of
                        [] ->
                            {some, Cursor@2};

                        _ ->
                            navigate_flat(
                                Cursor@2,
                                Rest@1,
                                Prefix,
                                false,
                                {some, Prefix}
                            )
                    end end)
    end.

-file("src/molt/internal/document.gleam", 171).
?DOC(false).
-spec find_container_indexed(
    greenwood:node_(molt@types:toml_kind()),
    list(molt@types:path_segment())
) -> {ok, greenwood:node_(molt@types:toml_kind())} | {error, nil}.
find_container_indexed(Tree, Path) ->
    _pipe = navigate_flat(greenwood@zipper:zip(Tree), Path, [], true, none),
    _pipe@1 = gleam@option:map(_pipe, fun(C) -> erlang:element(2, C) end),
    gleam@option:to_result(_pipe@1, nil).

-file("src/molt/internal/document.gleam", 272).
?DOC(false).
-spec has_index_segment(list(molt@types:path_segment())) -> boolean().
has_index_segment(Path) ->
    gleam@list:any(Path, fun(S) -> case S of
                {index_segment, _} ->
                    true;

                _ ->
                    false
            end end).

-file("src/molt/internal/document.gleam", 152).
?DOC(false).
-spec find_container(molt@types:document(), list(molt@types:path_segment())) -> {ok,
        greenwood:node_(molt@types:toml_kind())} |
    {error, molt@error:molt_error()}.
find_container(Doc, Segments) ->
    gleam@bool:guard(
        Segments =:= [],
        {ok, erlang:element(4, Doc)},
        fun() ->
            gleam@bool:lazy_guard(
                has_index_segment(Segments),
                fun() ->
                    _pipe = find_container_indexed(
                        erlang:element(4, Doc),
                        Segments
                    ),
                    gleam@result:replace_error(
                        _pipe,
                        molt@error:not_found_path(Segments)
                    )
                end,
                fun() ->
                    _pipe@1 = molt@cst:get(erlang:element(4, Doc), Segments),
                    gleam@result:replace_error(
                        _pipe@1,
                        molt@error:not_found_path(Segments)
                    )
                end
            )
        end
    ).

-file("src/molt/internal/document.gleam", 259).
?DOC(false).
-spec require_key(
    molt@types:document(),
    list(molt@types:path_segment()),
    binary()
) -> {ok, greenwood:node_(molt@types:toml_kind())} |
    {error, molt@error:molt_error()}.
require_key(Doc, Segments, Key) ->
    gleam@result:'try'(
        find_container(Doc, Segments),
        fun(Table_node) ->
            _pipe = molt@cst:get(Table_node, [{key_segment, Key}]),
            gleam@result:replace_error(
                _pipe,
                begin
                    _pipe@1 = lists:append(Segments, [{key_segment, Key}]),
                    molt@error:not_found_path(_pipe@1)
                end
            )
        end
    ).

-file("src/molt/internal/document.gleam", 124).
?DOC(false).
-spec get_value(
    molt@types:document(),
    list(molt@types:path_segment()),
    binary()
) -> {ok, molt@value:value()} | {error, molt@error:molt_error()}.
get_value(Doc, Path, Key) ->
    gleam@result:'try'(
        require_key(Doc, Path, Key),
        fun(Kv_node) -> {ok, molt@value:from_cst(Kv_node)} end
    ).

-file("src/molt/internal/document.gleam", 136).
?DOC(false).
-spec get_value_at(
    molt@types:document(),
    list(molt@types:path_segment()),
    list(molt@types:path_segment())
) -> {ok, molt@value:value()} | {error, molt@error:molt_error()}.
get_value_at(Doc, Container, Kv_key) ->
    Full_path = lists:append(Container, Kv_key),
    gleam@result:'try'(
        find_container(Doc, Container),
        fun(Container_node) ->
            gleam@result:'try'(
                begin
                    _pipe = molt@cst:get(Container_node, Kv_key),
                    gleam@result:replace_error(
                        _pipe,
                        molt@error:not_found_path(Full_path)
                    )
                end,
                fun(Kv_node) -> {ok, molt@value:from_cst(Kv_node)} end
            )
        end
    ).