-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).