-module(molt@internal@document@index).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/document/index.gleam").
-export([path_to_index_key/1, build_tree_index/1, get_index/1, with_index/2, has_key/2, has_path/2, get/2, get_path/2, key_to_path/1, resolve/2, insertion_site/4, rename_key/2, root_children/1, find_deepest_ancestor_entry/2, entry_for_value/2, entry_for_element/2, insert_entry/3, remove_subtree/2, prune_empty_implicit_ancestors/2, update_entry/3, ensure_implicit_tables/2, build_doc_index/1, relocate_subtree/3, resolve_negative_indices/2]).
-export_type([resolution/0, insertion_site/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 resolution() :: {hit,
list(molt@types:path_segment()),
molt@types:index_entry()} |
{miss,
list(molt@types:path_segment()),
molt@types:index_entry(),
list(molt@types:path_segment())} |
{fresh, list(molt@types:path_segment())}.
-type insertion_site() :: {concrete_append, list(molt@types:path_segment())} |
{root_dotted_key, list(molt@types:path_segment())} |
{inline_descend, list(molt@types:path_segment())}.
-file("src/molt/internal/document/index.gleam", 830).
?DOC(false).
-spec is_key_segment(molt@types:path_segment()) -> boolean().
is_key_segment(Seg) ->
case Seg of
{key_segment, _} ->
true;
_ ->
false
end.
-file("src/molt/internal/document/index.gleam", 782).
?DOC(false).
-spec add_canonical_aot_entries(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
add_canonical_aot_entries(Idx, Raw) ->
Canonical_counts = gleam@dict:fold(
Raw,
maps:new(),
fun(Acc, Key, Entry) -> case Entry of
{index_array_of_tables, _, _} ->
{index_key, Key@1} = Key,
gleam@bool:guard(
not molt@internal@path:contains_index(Key@1),
Acc,
fun() ->
Canonical_key = begin
_pipe = gleam@list:filter(
Key@1,
fun is_key_segment/1
),
{index_key, _pipe}
end,
gleam@dict:upsert(
Acc,
Canonical_key,
fun(V) -> gleam@option:unwrap(V, 0) + 1 end
)
end
);
_ ->
Acc
end end
),
gleam@dict:fold(Raw, Idx, fun(Idx@1, Key@2, Entry@1) -> case Entry@1 of
{index_array_of_tables, _, _} ->
{index_key, Key@3} = Key@2,
gleam@bool:guard(
not molt@internal@path:contains_index(Key@3),
Idx@1,
fun() ->
Canonical_key@1 = begin
_pipe@1 = gleam@list:filter(
Key@3,
fun is_key_segment/1
),
{index_key, _pipe@1}
end,
gleam@bool:guard(
gleam_stdlib:map_get(
Canonical_counts,
Canonical_key@1
)
/= {ok, 1},
Idx@1,
fun() ->
gleam@dict:upsert(
Idx@1,
Canonical_key@1,
fun(V@1) ->
gleam@option:unwrap(V@1, Entry@1)
end
)
end
)
end
);
_ ->
Idx@1
end end).
-file("src/molt/internal/document/index.gleam", 747).
?DOC(false).
-spec entry_add_child(molt@types:index_entry(), binary()) -> molt@types:index_entry().
entry_add_child(Entry, Child) ->
case Entry of
{index_table, Children} ->
case gleam@list:contains(Children, Child) of
true ->
Entry;
false ->
{index_table, [Child | Children]}
end;
{index_implicit_table, Children@1} ->
case gleam@list:contains(Children@1, Child) of
true ->
Entry;
false ->
{index_implicit_table, [Child | Children@1]}
end;
{index_array_of_tables, Count, Children@2} ->
case gleam@list:contains(Children@2, Child) of
true ->
Entry;
false ->
{index_array_of_tables, Count, [Child | Children@2]}
end;
{index_array_of_tables_entry, Parent, I, Children@3} ->
case gleam@list:contains(Children@3, Child) of
true ->
Entry;
false ->
{index_array_of_tables_entry,
Parent,
I,
[Child | Children@3]}
end;
_ ->
Entry
end.
-file("src/molt/internal/document/index.gleam", 731).
?DOC(false).
-spec add_child_to_entry(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key(),
binary()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
add_child_to_entry(Idx, Parent, Child) ->
case Parent of
{index_key, []} ->
Idx;
_ ->
case gleam_stdlib:map_get(Idx, Parent) of
{ok, Entry} ->
gleam@dict:insert(
Idx,
Parent,
entry_add_child(Entry, Child)
);
{error, nil} ->
Idx
end
end.
-file("src/molt/internal/document/index.gleam", 708).
?DOC(false).
-spec enrich_children(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
enrich_children(Raw) ->
_pipe = gleam@dict:fold(Raw, Raw, fun(Idx, Key, _) -> case Key of
{index_key, [{key_segment, Child}]} ->
add_child_to_entry(Idx, {index_key, []}, Child);
{index_key, [{key_segment, Child@1} | Parent]} ->
Parent@1 = {index_key, Parent},
gleam@bool:guard(
not gleam@dict:has_key(Idx, Parent@1),
Idx,
fun() -> add_child_to_entry(Idx, Parent@1, Child@1) end
);
_ ->
Idx
end end),
add_canonical_aot_entries(_pipe, Raw).
-file("src/molt/internal/document/index.gleam", 160).
?DOC(false).
-spec path_to_index_key(list(molt@types:path_segment())) -> molt@types:index_key().
path_to_index_key(Path) ->
{index_key, lists:reverse(Path)}.
-file("src/molt/internal/document/index.gleam", 690).
?DOC(false).
-spec classify_value_tokens(
list(greenwood:element(molt@types:toml_kind())),
list(molt@types:path_segment())
) -> molt@types:index_entry().
classify_value_tokens(Nodes, Container) ->
case Nodes of
[] ->
{index_scalar_value, Container};
[{token_element, {token, whitespace, _}} | Rest] ->
classify_value_tokens(Rest, Container);
[{token_element, {token, newline, _}} | Rest] ->
classify_value_tokens(Rest, Container);
[{node_element, N} | _] when erlang:element(2, N) =:= inline_table ->
{index_inline_table_value, Container};
[{node_element, N@1} | _] when erlang:element(2, N@1) =:= array ->
{index_array_value, Container};
_ ->
{index_scalar_value, Container}
end.
-file("src/molt/internal/document/index.gleam", 682).
?DOC(false).
-spec classify_kv_value(
greenwood:node_(molt@types:toml_kind()),
list(molt@types:path_segment())
) -> molt@types:index_entry().
classify_kv_value(Kv, Container) ->
_pipe = molt@internal@cst@elements:value_tokens(erlang:element(3, Kv)),
classify_value_tokens(_pipe, Container).
-file("src/molt/internal/document/index.gleam", 625).
?DOC(false).
-spec register_dotted_parents(
list(molt@types:path_segment()),
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
register_dotted_parents(Path, Segments, Index) ->
case Segments of
[] ->
Index;
[_] ->
Index;
_ ->
Prefix_segments = molt@internal@utils:all_prefixes(Segments),
gleam@list:fold(
Prefix_segments,
Index,
fun(Index@1, Prefix) ->
Full = lists:append(Path, Prefix),
Key = path_to_index_key(Full),
case gleam_stdlib:map_get(Index@1, Key) of
{error, nil} ->
gleam@dict:insert(
Index@1,
Key,
{index_implicit_table, []}
);
{ok, _} ->
Index@1
end
end
)
end.
-file("src/molt/internal/document/index.gleam", 606).
?DOC(false).
-spec index_kv_node(
greenwood:node_(molt@types:toml_kind()),
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
index_kv_node(Kv, Path, Index) ->
case molt@internal@cst@elements:key_path(erlang:element(3, Kv)) of
none ->
Index;
{some, Segments} ->
Key_segments = gleam@list:map(
Segments,
fun(Field@0) -> {key_segment, Field@0} end
),
Full_path = lists:append(Path, Key_segments),
Index@1 = register_dotted_parents(Path, Key_segments, Index),
Entry = classify_kv_value(Kv, Path),
gleam@dict:insert(Index@1, path_to_index_key(Full_path), Entry)
end.
-file("src/molt/internal/document/index.gleam", 473).
?DOC(false).
-spec index_table_kvs(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(greenwood:element(molt@types:toml_kind())),
list(molt@types:path_segment())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
index_table_kvs(Index, Nodes, Path) ->
gleam@list:fold(Nodes, Index, fun(Index@1, Node) -> case Node of
{node_element, Kv} when erlang:element(2, Kv) =:= key_value ->
index_kv_node(Kv, Path, Index@1);
_ ->
Index@1
end end).
-file("src/molt/internal/document/index.gleam", 670).
?DOC(false).
-spec register_header_parents(
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
register_header_parents(Path, Index) ->
Prefixes = molt@internal@utils:all_prefixes(Path),
gleam@list:fold(
Prefixes,
Index,
fun(Index@1, Prefix) ->
Key = path_to_index_key(Prefix),
case gleam_stdlib:map_get(Index@1, Key) of
{error, nil} ->
gleam@dict:insert(Index@1, Key, {index_implicit_table, []});
{ok, _} ->
Index@1
end
end
).
-file("src/molt/internal/document/index.gleam", 655).
?DOC(false).
-spec register_array_of_tables_path(
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
register_array_of_tables_path(Path, Index) ->
Index@1 = register_header_parents(Path, Index),
Key = path_to_index_key(Path),
Count = case gleam_stdlib:map_get(Index@1, Key) of
{ok, {index_array_of_tables, C, _}} ->
C + 1;
_ ->
1
end,
gleam@dict:insert(Index@1, Key, {index_array_of_tables, Count, []}).
-file("src/molt/internal/document/index.gleam", 542).
?DOC(false).
-spec do_resolve_header_path(
list(molt@types:path_segment()),
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> list(molt@types:path_segment()).
do_resolve_header_path(Remaining, Built, Index) ->
case Remaining of
[] ->
Built;
[Segment] ->
lists:append(Built, [Segment]);
[Segment@1 | Rest] ->
Candidate = lists:append(Built, [Segment@1]),
case gleam_stdlib:map_get(Index, path_to_index_key(Candidate)) of
{ok, {index_array_of_tables, Count, _}} ->
With_index = lists:append(
Candidate,
[{index_segment, Count - 1}]
),
do_resolve_header_path(Rest, With_index, Index);
_ ->
do_resolve_header_path(Rest, Candidate, Index)
end
end.
-file("src/molt/internal/document/index.gleam", 538).
?DOC(false).
-spec resolve_header_path(
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> list(molt@types:path_segment()).
resolve_header_path(Key_path, Index) ->
do_resolve_header_path(Key_path, [], Index).
-file("src/molt/internal/document/index.gleam", 648).
?DOC(false).
-spec register_table_path(
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
register_table_path(Path, Index) ->
Index@1 = register_header_parents(Path, Index),
gleam@dict:insert(Index@1, path_to_index_key(Path), {index_table, []}).
-file("src/molt/internal/document/index.gleam", 486).
?DOC(false).
-spec index_tables(
list(greenwood:element(molt@types:toml_kind())),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
index_tables(Nodes, Index) ->
gleam@list:fold(Nodes, Index, fun(Index@1, Node) -> case Node of
{node_element, N} when erlang:element(2, N) =:= table ->
Path = begin
_pipe = gleam@list:map(
molt@internal@cst@elements:extract_key_segments(
erlang:element(3, N)
),
fun(Field@0) -> {key_segment, Field@0} end
),
resolve_header_path(_pipe, Index@1)
end,
index_table_kvs(
register_table_path(Path, Index@1),
erlang:element(3, N),
Path
);
{node_element, N@1} when erlang:element(2, N@1) =:= array_of_tables ->
Path@1 = begin
_pipe@1 = gleam@list:map(
molt@internal@cst@elements:extract_key_segments(
erlang:element(3, N@1)
),
fun(Field@0) -> {key_segment, Field@0} end
),
resolve_header_path(_pipe@1, Index@1)
end,
Index@2 = register_array_of_tables_path(Path@1, Index@1),
Entry_index = case gleam_stdlib:map_get(
Index@2,
path_to_index_key(Path@1)
) of
{ok, {index_array_of_tables, Count, _}} ->
Count - 1;
_ ->
0
end,
Segment = begin
_pipe@2 = {index_segment, Entry_index},
gleam@list:wrap(_pipe@2)
end,
Entry_path = lists:append(Path@1, Segment),
Index@3 = gleam@dict:insert(
Index@2,
path_to_index_key(Entry_path),
{index_array_of_tables_entry, Path@1, Entry_index, []}
),
index_table_kvs(Index@3, erlang:element(3, N@1), Entry_path);
_ ->
Index@1
end end).
-file("src/molt/internal/document/index.gleam", 57).
?DOC(false).
-spec build_tree_index(greenwood:node_(molt@types:toml_kind())) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
build_tree_index(Tree) ->
_pipe = index_table_kvs(maps:new(), erlang:element(3, Tree), []),
_pipe@1 = index_tables(erlang:element(3, Tree), _pipe),
enrich_children(_pipe@1).
-file("src/molt/internal/document/index.gleam", 837).
?DOC(false).
-spec ensure_index(molt@types:document()) -> {ok, molt@types:document()} |
{error, molt@error:molt_error()}.
ensure_index(Doc) ->
gleam@bool:guard(
erlang:element(3, Doc) > 0,
{error, invalid_document},
fun() ->
gleam@bool:guard(
erlang:element(5, Doc) /= none,
{ok, Doc},
fun() ->
{ok,
{document,
erlang:element(2, Doc),
erlang:element(3, Doc),
erlang:element(4, Doc),
{some, build_tree_index(erlang:element(4, Doc))}}}
end
)
end
).
-file("src/molt/internal/document/index.gleam", 73).
?DOC(false).
-spec get_index(molt@types:document()) -> {ok,
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())} |
{error, molt@error:molt_error()}.
get_index(Doc) ->
gleam@result:'try'(
ensure_index(Doc),
fun(Doc@1) ->
{ok, gleam@option:unwrap(erlang:element(5, Doc@1), maps:new())}
end
).
-file("src/molt/internal/document/index.gleam", 65).
?DOC(false).
-spec with_index(
molt@types:document(),
fun((gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())) -> {ok,
OFP} |
{error, molt@error:molt_error()})
) -> {ok, OFP} | {error, molt@error:molt_error()}.
with_index(Doc, Callback) ->
gleam@result:'try'(get_index(Doc), fun(Index) -> Callback(Index) end).
-file("src/molt/internal/document/index.gleam", 82).
?DOC(false).
-spec has_key(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> boolean().
has_key(Index, Key) ->
gleam@dict:has_key(Index, Key).
-file("src/molt/internal/document/index.gleam", 78).
?DOC(false).
-spec has_path(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> boolean().
has_path(Index, Path) ->
has_key(Index, path_to_index_key(Path)).
-file("src/molt/internal/document/index.gleam", 93).
?DOC(false).
-spec get(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> {ok, molt@types:index_entry()} | {error, nil}.
get(Index, Key) ->
gleam_stdlib:map_get(Index, Key).
-file("src/molt/internal/document/index.gleam", 86).
?DOC(false).
-spec get_path(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> {ok, molt@types:index_entry()} | {error, nil}.
get_path(Index, Path) ->
get(Index, path_to_index_key(Path)).
-file("src/molt/internal/document/index.gleam", 165).
?DOC(false).
-spec key_to_path(molt@types:index_key()) -> list(molt@types:path_segment()).
key_to_path(Key) ->
{index_key, Reversed} = Key,
lists:reverse(Reversed).
-file("src/molt/internal/document/index.gleam", 847).
?DOC(false).
-spec parent_key(molt@types:index_key()) -> {ok, molt@types:index_key()} |
{error, nil}.
parent_key(Key) ->
case Key of
{index_key, [_ | Rest]} ->
{ok, {index_key, Rest}};
{index_key, []} ->
{error, nil}
end.
-file("src/molt/internal/document/index.gleam", 879).
?DOC(false).
-spec find_deepest_ancestor(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> {ok, {molt@types:index_key(), molt@types:index_entry()}} | {error, nil}.
find_deepest_ancestor(Idx, Key) ->
case gleam_stdlib:map_get(Idx, Key) of
{ok, Entry} ->
{ok, {Key, Entry}};
{error, nil} ->
case parent_key(Key) of
{ok, Parent} ->
find_deepest_ancestor(Idx, Parent);
{error, nil} ->
{error, nil}
end
end.
-file("src/molt/internal/document/index.gleam", 101).
?DOC(false).
-spec resolve(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> resolution().
resolve(Idx, Path) ->
Key = path_to_index_key(Path),
case get(Idx, Key) of
{ok, Entry} ->
{hit, Path, Entry};
{error, nil} ->
case find_deepest_ancestor(Idx, Key) of
{ok, {Ancestor_key, Ancestor}} ->
Ancestor_path = key_to_path(Ancestor_key),
Tail = gleam@list:drop(Path, erlang:length(Ancestor_path)),
{miss, Ancestor_path, Ancestor, Tail};
{error, nil} ->
{fresh, Path}
end
end.
-file("src/molt/internal/document/index.gleam", 857).
?DOC(false).
-spec find_concrete_ancestor_site(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment()),
list(molt@types:path_segment())
) -> insertion_site().
find_concrete_ancestor_site(Idx, Implicit_path, Full_path) ->
Parent = gleam@list:take(Implicit_path, erlang:length(Implicit_path) - 1),
case Parent of
[] ->
{root_dotted_key, Full_path};
_ ->
case get_path(Idx, Parent) of
{ok, {index_table, _}} ->
{concrete_append, Parent};
{ok, {index_array_of_tables_entry, _, _, _}} ->
{concrete_append, Parent};
{ok, {index_implicit_table, _}} ->
find_concrete_ancestor_site(Idx, Parent, Full_path);
_ ->
{root_dotted_key, Full_path}
end
end.
-file("src/molt/internal/document/index.gleam", 122).
?DOC(false).
-spec insertion_site(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment()),
molt@types:index_entry(),
list(molt@types:path_segment())
) -> {ok, insertion_site()} | {error, molt@error:molt_error()}.
insertion_site(Idx, Ancestor_path, Ancestor, Full_path) ->
case Ancestor of
{index_table, _} ->
{ok, {concrete_append, Ancestor_path}};
{index_array_of_tables_entry, _, _, _} ->
{ok, {concrete_append, Ancestor_path}};
{index_implicit_table, _} ->
{ok, find_concrete_ancestor_site(Idx, Ancestor_path, Full_path)};
{index_scalar_value, _} ->
{ok, {inline_descend, Full_path}};
{index_array_value, _} ->
{ok, {inline_descend, Full_path}};
{index_inline_table_value, _} ->
{ok, {inline_descend, Full_path}};
{index_array_of_tables, _, _} ->
{error,
{type_mismatch,
{some, molt@internal@path:to_string(Ancestor_path)},
<<"a table (use an index to select an entry)"/utf8>>,
<<"array of tables"/utf8>>}}
end.
-file("src/molt/internal/document/index.gleam", 152).
?DOC(false).
-spec rename_key(list(molt@types:path_segment()), binary()) -> molt@types:index_key().
rename_key(Path, To) ->
case path_to_index_key(Path) of
{index_key, [_ | Rest]} ->
{index_key, [{key_segment, To} | Rest]};
Key ->
Key
end.
-file("src/molt/internal/document/index.gleam", 171).
?DOC(false).
-spec root_children(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> list(binary()).
root_children(Idx) ->
gleam@dict:fold(Idx, [], fun(Acc, Key, _) -> case Key of
{index_key, [{key_segment, Name}]} ->
[Name | Acc];
_ ->
Acc
end end).
-file("src/molt/internal/document/index.gleam", 183).
?DOC(false).
-spec find_deepest_ancestor_entry(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> {ok, molt@types:index_entry()} | {error, nil}.
find_deepest_ancestor_entry(Idx, Key) ->
gleam@result:'try'(
find_deepest_ancestor(Idx, Key),
fun(_use0) ->
{_, Entry} = _use0,
{ok, Entry}
end
).
-file("src/molt/internal/document/index.gleam", 195).
?DOC(false).
-spec entry_for_value(molt@value:value(), list(molt@types:path_segment())) -> molt@types:index_entry().
entry_for_value(Val, Container) ->
case molt@value:type_of(Val) of
<<"array"/utf8>> ->
{index_array_value, Container};
<<"inline_table"/utf8>> ->
{index_inline_table_value, Container};
<<"table"/utf8>> ->
{index_inline_table_value, Container};
_ ->
{index_scalar_value, Container}
end.
-file("src/molt/internal/document/index.gleam", 209).
?DOC(false).
-spec entry_for_element(
greenwood:element(molt@types:toml_kind()),
list(molt@types:path_segment())
) -> molt@types:index_entry().
entry_for_element(El, Container) ->
case El of
{node_element, N} when erlang:element(2, N) =:= inline_table ->
{index_inline_table_value, Container};
{node_element, N@1} when erlang:element(2, N@1) =:= array ->
{index_array_value, Container};
_ ->
{index_scalar_value, Container}
end.
-file("src/molt/internal/document/index.gleam", 317).
?DOC(false).
-spec add_child_to_parent(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
add_child_to_parent(Idx, Key) ->
case Key of
{index_key, [{key_segment, Child} | Parent_rev]} ->
Parent = {index_key, Parent_rev},
case gleam_stdlib:map_get(Idx, Parent) of
{ok, Entry} ->
gleam@dict:insert(
Idx,
Parent,
entry_add_child(Entry, Child)
);
{error, nil} ->
Idx
end;
_ ->
Idx
end.
-file("src/molt/internal/document/index.gleam", 222).
?DOC(false).
-spec insert_entry(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key(),
molt@types:index_entry()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
insert_entry(Idx, Key, Entry) ->
Idx@1 = gleam@dict:insert(Idx, Key, Entry),
add_child_to_parent(Idx@1, Key).
-file("src/molt/internal/document/index.gleam", 311).
?DOC(false).
-spec has_suffix(
list(molt@types:path_segment()),
list(molt@types:path_segment())
) -> boolean().
has_suffix(Longer, Suffix) ->
Drop_count = erlang:length(Longer) - erlang:length(Suffix),
gleam@list:drop(Longer, Drop_count) =:= Suffix.
-file("src/molt/internal/document/index.gleam", 302).
?DOC(false).
-spec is_descendant_of(molt@types:index_key(), list(molt@types:path_segment())) -> boolean().
is_descendant_of(Child, Parent_rev) ->
{index_key, Child_rev} = Child,
(erlang:length(Child_rev) > erlang:length(Parent_rev)) andalso has_suffix(
Child_rev,
Parent_rev
).
-file("src/molt/internal/document/index.gleam", 350).
?DOC(false).
-spec entry_remove_child(molt@types:index_entry(), binary()) -> molt@types:index_entry().
entry_remove_child(Entry, Child) ->
case Entry of
{index_table, Children} ->
{index_table, gleam@list:filter(Children, fun(C) -> C /= Child end)};
{index_implicit_table, Children@1} ->
{index_implicit_table,
gleam@list:filter(Children@1, fun(C@1) -> C@1 /= Child end)};
{index_array_of_tables, Count, Children@2} ->
{index_array_of_tables,
Count,
gleam@list:filter(Children@2, fun(C@2) -> C@2 /= Child end)};
{index_array_of_tables_entry, Parent, I, Children@3} ->
{index_array_of_tables_entry,
Parent,
I,
gleam@list:filter(Children@3, fun(C@3) -> C@3 /= Child end)};
_ ->
Entry
end.
-file("src/molt/internal/document/index.gleam", 334).
?DOC(false).
-spec remove_child_from_parent(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
remove_child_from_parent(Idx, Key) ->
case Key of
{index_key, [{key_segment, Child} | Parent_rev]} ->
Parent = {index_key, Parent_rev},
case gleam_stdlib:map_get(Idx, Parent) of
{ok, Entry} ->
gleam@dict:insert(
Idx,
Parent,
entry_remove_child(Entry, Child)
);
{error, nil} ->
Idx
end;
_ ->
Idx
end.
-file("src/molt/internal/document/index.gleam", 232).
?DOC(false).
-spec remove_subtree(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
remove_subtree(Idx, Key) ->
Idx@1 = gleam@dict:delete(Idx, Key),
Idx@2 = remove_child_from_parent(Idx@1, Key),
{index_key, Prefix_rev} = Key,
gleam@dict:fold(
Idx@2,
Idx@2,
fun(Acc, Candidate, _) ->
case is_descendant_of(Candidate, Prefix_rev) of
true ->
gleam@dict:delete(Acc, Candidate);
false ->
Acc
end
end
).
-file("src/molt/internal/document/index.gleam", 251).
?DOC(false).
-spec prune_empty_implicit_ancestors(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
prune_empty_implicit_ancestors(Idx, Key) ->
case parent_key(Key) of
{error, nil} ->
Idx;
{ok, Parent} ->
case gleam_stdlib:map_get(Idx, Parent) of
{ok, {index_implicit_table, []}} ->
Idx@1 = gleam@dict:delete(Idx, Parent),
Idx@2 = remove_child_from_parent(Idx@1, Parent),
prune_empty_implicit_ancestors(Idx@2, Parent);
_ ->
Idx
end
end.
-file("src/molt/internal/document/index.gleam", 270).
?DOC(false).
-spec update_entry(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key(),
molt@types:index_entry()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
update_entry(Idx, Key, Entry) ->
gleam@dict:insert(Idx, Key, Entry).
-file("src/molt/internal/document/index.gleam", 280).
?DOC(false).
-spec ensure_implicit_tables(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
ensure_implicit_tables(Idx, Path) ->
Prefixes = molt@internal@utils:all_prefixes(Path),
gleam@list:fold(
Prefixes,
Idx,
fun(Idx@1, Prefix) ->
Key = path_to_index_key(Prefix),
case gleam_stdlib:map_get(Idx@1, Key) of
{error, nil} ->
insert_entry(Idx@1, Key, {index_implicit_table, []});
{ok, _} ->
Idx@1
end
end
).
-file("src/molt/internal/document/index.gleam", 296).
?DOC(false).
-spec build_doc_index(molt@types:document()) -> gleam@option:option(gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())).
build_doc_index(Doc) ->
{some, build_tree_index(erlang:element(4, Doc))}.
-file("src/molt/internal/document/index.gleam", 451).
?DOC(false).
-spec remap_container(
list(molt@types:path_segment()),
list(molt@types:path_segment()),
list(molt@types:path_segment())
) -> list(molt@types:path_segment()).
remap_container(Container, From_path, To_path) ->
From_len = erlang:length(From_path),
Container_len = erlang:length(Container),
case gleam@list:take(Container, From_len) =:= From_path of
true ->
lists:append(To_path, gleam@list:drop(Container, From_len));
false ->
case (From_len >= Container_len) andalso (gleam@list:take(
From_path,
Container_len
)
=:= Container) of
true ->
gleam@list:take(To_path, Container_len);
false ->
Container
end
end.
-file("src/molt/internal/document/index.gleam", 421).
?DOC(false).
-spec relocate_container(
molt@types:index_entry(),
list(molt@types:path_segment()),
list(molt@types:path_segment())
) -> molt@types:index_entry().
relocate_container(Entry, From_path, To_path) ->
case Entry of
{index_scalar_value, Container} ->
{index_scalar_value, remap_container(Container, From_path, To_path)};
{index_array_value, Container@1} ->
{index_array_value,
remap_container(Container@1, From_path, To_path)};
{index_inline_table_value, Container@2} ->
{index_inline_table_value,
remap_container(Container@2, From_path, To_path)};
_ ->
Entry
end.
-file("src/molt/internal/document/index.gleam", 378).
?DOC(false).
-spec relocate_subtree(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
molt@types:index_key(),
molt@types:index_key()
) -> gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()).
relocate_subtree(Idx, From, To) ->
{index_key, From_rev} = From,
{index_key, To_rev} = To,
From_len = erlang:length(From_rev),
From_path = key_to_path(From),
To_path = key_to_path(To),
To_move = gleam@dict:fold(
Idx,
[],
fun(Acc, Key, Entry) -> case Key =:= From of
true ->
[{To, relocate_container(Entry, From_path, To_path)} | Acc];
false ->
case is_descendant_of(Key, From_rev) of
true ->
{index_key, Key_rev} = Key,
Suffix = gleam@list:take(
Key_rev,
erlang:length(Key_rev) - From_len
),
New_key = {index_key, lists:append(Suffix, To_rev)},
[{New_key,
relocate_container(
Entry,
From_path,
To_path
)} |
Acc];
false ->
Acc
end
end end
),
Idx@1 = remove_subtree(Idx, From),
gleam@list:fold(
To_move,
Idx@1,
fun(Idx@2, Pair) ->
{Key@1, Entry@1} = Pair,
insert_entry(Idx@2, Key@1, Entry@1)
end
).
-file("src/molt/internal/document/index.gleam", 579).
?DOC(false).
-spec do_resolve_negative_indices(
list(molt@types:path_segment()),
list(molt@types:path_segment()),
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry())
) -> list(molt@types:path_segment()).
do_resolve_negative_indices(Remaining, Built, Index) ->
case Remaining of
[] ->
Built;
[{index_segment, I} | Rest] ->
Resolved = case {I < 0,
gleam_stdlib:map_get(Index, path_to_index_key(Built))} of
{true, {ok, {index_array_of_tables, Count, _}}} ->
Count + I;
{_, _} ->
I
end,
do_resolve_negative_indices(
Rest,
lists:append(Built, [{index_segment, Resolved}]),
Index
);
[Segment | Rest@1] ->
do_resolve_negative_indices(
Rest@1,
lists:append(Built, [Segment]),
Index
)
end.
-file("src/molt/internal/document/index.gleam", 572).
?DOC(false).
-spec resolve_negative_indices(
gleam@dict:dict(molt@types:index_key(), molt@types:index_entry()),
list(molt@types:path_segment())
) -> list(molt@types:path_segment()).
resolve_negative_indices(Idx, Path) ->
do_resolve_negative_indices(Path, [], Idx).