Skip to main content

src/molt@internal@emitter.erl

-module(molt@internal@emitter).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/molt/internal/emitter.gleam").
-export([normalize/1, emit_versioned/2, emit/1]).
-export_type([emit_state/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 emit_state() :: {emit_state,
        gleam@string_tree:string_tree(),
        integer(),
        integer(),
        boolean(),
        boolean()}.

-file("src/molt/internal/emitter.gleam", 812).
?DOC(false).
-spec last_ends_with_newline(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
last_ends_with_newline(Children) ->
    case gleam@list:last(Children) of
        {ok, {token_element, {token, newline, _}}} ->
            true;

        {ok, {node_element, Node}} ->
            last_ends_with_newline(erlang:element(3, Node));

        _ ->
            false
    end.

-file("src/molt/internal/emitter.gleam", 805).
?DOC(false).
-spec ensure_trailing_newline(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
ensure_trailing_newline(Children) ->
    gleam@bool:guard(
        last_ends_with_newline(Children),
        Children,
        fun() ->
            lists:append(
                Children,
                [{token_element, {token, newline, <<"\n"/utf8>>}}]
            )
        end
    ).

-file("src/molt/internal/emitter.gleam", 757).
?DOC(false).
-spec find_trailing_comment_text(list(greenwood:token(molt@types:toml_kind()))) -> gleam@option:option(binary()).
find_trailing_comment_text(Tokens) ->
    _pipe = gleam@list:find_map(Tokens, fun(T) -> case erlang:element(2, T) of
                comment ->
                    {ok, erlang:element(3, T)};

                _ ->
                    {error, nil}
            end end),
    gleam@option:from_result(_pipe).

-file("src/molt/internal/emitter.gleam", 722).
?DOC(false).
-spec normalize_trivia(greenwood:node_(molt@types:toml_kind())) -> greenwood:trivia(molt@types:toml_kind()).
normalize_trivia(Node) ->
    case erlang:element(4, Node) of
        bare ->
            bare;

        {trivia, Leading, Trailing} ->
            Comments = begin
                _pipe = gleam@list:filter_map(
                    Leading,
                    fun(T) -> case erlang:element(2, T) of
                            comment ->
                                {ok,
                                    [{token, comment, erlang:element(3, T)},
                                        {token, newline, <<"\n"/utf8>>}]};

                            _ ->
                                {error, nil}
                        end end
                ),
                lists:append(_pipe)
            end,
            Trailing@1 = case find_trailing_comment_text(Trailing) of
                {some, Text} ->
                    [{token, whitespace, <<" "/utf8>>}, {token, comment, Text}];

                none ->
                    []
            end,
            case {Comments, Trailing@1} of
                {[], []} ->
                    bare;

                {_, _} ->
                    {trivia, Comments, Trailing@1}
            end
    end.

-file("src/molt/internal/emitter.gleam", 797).
?DOC(false).
-spec extract_inline_comment(list(greenwood:element(molt@types:toml_kind()))) -> binary().
extract_inline_comment(Children) ->
    case Children of
        [] ->
            <<""/utf8>>;

        [{token_element, {token, comment, Text}} | _] ->
            Text;

        [_ | Rest] ->
            extract_inline_comment(Rest)
    end.

-file("src/molt/internal/emitter.gleam", 707).
?DOC(false).
-spec interpose_separated(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
interpose_separated(Elements) ->
    case Elements of
        [] ->
            [];

        [Single] ->
            [Single];

        [Head | Rest] ->
            [Head,
                {token_element, {token, comma, <<","/utf8>>}},
                {token_element, {token, whitespace, <<" "/utf8>>}} |
                interpose_separated(Rest)]
    end.

-file("src/molt/internal/emitter.gleam", 594).
?DOC(false).
-spec trivia_has_comment(greenwood:trivia(molt@types:toml_kind())) -> boolean().
trivia_has_comment(Trivia) ->
    case Trivia of
        bare ->
            false;

        {trivia, Leading, Trailing} ->
            gleam@list:any(
                lists:append(Leading, Trailing),
                fun(T) -> erlang:element(2, T) =:= comment end
            )
    end.

-file("src/molt/internal/emitter.gleam", 583).
?DOC(false).
-spec contains_comment(greenwood:node_(molt@types:toml_kind())) -> boolean().
contains_comment(Node) ->
    trivia_has_comment(erlang:element(4, Node)) orelse gleam@list:any(
        erlang:element(3, Node),
        fun(El) -> case El of
                {token_element, {token, comment, _}} ->
                    true;

                {token_element, _} ->
                    false;

                {node_element, Child} ->
                    contains_comment(Child)
            end end
    ).

-file("src/molt/internal/emitter.gleam", 634).
?DOC(false).
-spec canonical_array_element(
    greenwood:element(molt@types:toml_kind()),
    boolean()
) -> greenwood:node_(molt@types:toml_kind()).
canonical_array_element(Value, Last) ->
    Children = case Last of
        true ->
            [Value];

        false ->
            [Value,
                {token_element, {token, comma, <<","/utf8>>}},
                {token_element, {token, whitespace, <<" "/utf8>>}}]
    end,
    {node, array_element, Children, bare}.

-file("src/molt/internal/emitter.gleam", 679).
?DOC(false).
-spec normalize_inline_kv(greenwood:node_(molt@types:toml_kind())) -> greenwood:element(molt@types:toml_kind()).
normalize_inline_kv(Kv) ->
    {Key_side, _} = molt@internal@cst@elements:split_at_equals(
        erlang:element(3, Kv)
    ),
    Key_elements = gleam@list:filter(Key_side, fun(El) -> case El of
                {token_element, {token, whitespace, _}} ->
                    false;

                _ ->
                    true
            end end),
    Value_part = begin
        _pipe = molt@internal@cst@elements:value_tokens(erlang:element(3, Kv)),
        _pipe@1 = molt@internal@cst@elements:find_first_value(_pipe),
        _pipe@2 = gleam@option:map(
            _pipe@1,
            fun(V) -> [normalize_value_el(V)] end
        ),
        gleam@option:unwrap(_pipe@2, [])
    end,
    Children = lists:append(
        [Key_elements,
            [{token_element, {token, whitespace, <<" "/utf8>>}},
                {token_element, {token, equals, <<""/utf8>>}},
                {token_element, {token, whitespace, <<" "/utf8>>}}],
            Value_part]
    ),
    {node_element, {node, erlang:element(2, Kv), Children, bare}}.

-file("src/molt/internal/emitter.gleam", 651).
?DOC(false).
-spec canonical_inline_table(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
canonical_inline_table(Node) ->
    Entries = begin
        _pipe = molt@internal@cst@elements:extract_inline_entries(Node),
        gleam@list:map(_pipe, fun normalize_inline_kv/1)
    end,
    Children = case Entries of
        [] ->
            [{token_element, {token, left_brace, <<"{"/utf8>>}},
                {token_element, {token, right_brace, <<"}"/utf8>>}}];

        _ ->
            lists:append(
                [[{token_element, {token, left_brace, <<"{"/utf8>>}},
                        {token_element, {token, whitespace, <<" "/utf8>>}}],
                    interpose_separated(Entries),
                    [{token_element, {token, whitespace, <<" "/utf8>>}},
                        {token_element, {token, right_brace, <<"}"/utf8>>}}]]
            )
    end,
    {node, erlang:element(2, Node), Children, bare}.

-file("src/molt/internal/emitter.gleam", 608).
?DOC(false).
-spec canonical_array(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
canonical_array(Node) ->
    Values = begin
        _pipe = molt@internal@cst@elements:extract_array_items(Node),
        gleam@list:filter_map(
            _pipe,
            fun(Item) ->
                case molt@internal@cst@elements:find_first_value(
                    erlang:element(3, Item)
                ) of
                    {some, V} ->
                        {ok, normalize_value_el(V)};

                    none ->
                        {error, nil}
                end
            end
        )
    end,
    Item_count = erlang:length(Values),
    Item_elements = gleam@list:index_map(
        Values,
        fun(V@1, I) ->
            Last = I =:= (Item_count - 1),
            {node_element, canonical_array_element(V@1, Last)}
        end
    ),
    Children = lists:append(
        [[{token_element, {token, left_bracket, <<"["/utf8>>}}],
            Item_elements,
            [{token_element, {token, right_bracket, <<"]"/utf8>>}}]]
    ),
    {node, erlang:element(2, Node), Children, bare}.

-file("src/molt/internal/emitter.gleam", 559).
?DOC(false).
-spec normalize_value_el(greenwood:element(molt@types:toml_kind())) -> greenwood:element(molt@types:toml_kind()).
normalize_value_el(El) ->
    case El of
        {node_element, N} ->
            case erlang:element(2, N) of
                array ->
                    case contains_comment(N) of
                        true ->
                            El;

                        false ->
                            {node_element, canonical_array(N)}
                    end;

                inline_table ->
                    case contains_comment(N) of
                        true ->
                            El;

                        false ->
                            {node_element, canonical_inline_table(N)}
                    end;

                _ ->
                    El
            end;

        _ ->
            El
    end.

-file("src/molt/internal/emitter.gleam", 490).
?DOC(false).
-spec normalize_kv_node(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
normalize_kv_node(Node) ->
    {Key_side, _} = molt@internal@cst@elements:split_at_equals(
        erlang:element(3, Node)
    ),
    Key_elements = gleam@list:filter(Key_side, fun(El) -> case El of
                {token_element, {token, whitespace, _}} ->
                    false;

                _ ->
                    true
            end end),
    Value_el = begin
        _pipe = molt@internal@cst@elements:value_tokens(erlang:element(3, Node)),
        _pipe@1 = molt@internal@cst@elements:find_first_value(_pipe),
        gleam@option:map(_pipe@1, fun normalize_value_el/1)
    end,
    Comment = extract_inline_comment(erlang:element(3, Node)),
    Value_part = case {Value_el, Comment} of
        {{some, El@1}, <<""/utf8>>} ->
            [El@1, {token_element, {token, newline, <<"\n"/utf8>>}}];

        {{some, El@2}, C} ->
            [El@2,
                {token_element, {token, whitespace, <<" "/utf8>>}},
                {token_element, {token, comment, C}},
                {token_element, {token, newline, <<"\n"/utf8>>}}];

        {none, _} ->
            [{token_element, {token, newline, <<"\n"/utf8>>}}]
    end,
    Children = lists:append(
        [Key_elements,
            [{token_element, {token, whitespace, <<" "/utf8>>}},
                {token_element, {token, equals, <<""/utf8>>}},
                {token_element, {token, whitespace, <<" "/utf8>>}}],
            Value_part]
    ),
    {node, erlang:element(2, Node), Children, normalize_trivia(Node)}.

-file("src/molt/internal/emitter.gleam", 786).
?DOC(false).
-spec normalize_body(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
normalize_body(Children) ->
    gleam@list:filter_map(Children, fun(El) -> case El of
                {node_element, N} when erlang:element(2, N) =:= key_value ->
                    {ok, {node_element, normalize_kv_node(N)}};

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

-file("src/molt/internal/emitter.gleam", 769).
?DOC(false).
-spec extract_header_tokens(list(greenwood:element(molt@types:toml_kind()))) -> list(greenwood:element(molt@types:toml_kind())).
extract_header_tokens(Children) ->
    gleam@list:filter_map(Children, fun(El) -> case El of
                {token_element, {token, left_bracket, _}} ->
                    {ok, El};

                {token_element, {token, right_bracket, _}} ->
                    {ok, El};

                {token_element, {token, dot, _}} ->
                    {ok, El};

                {token_element, {token, bare_key, _}} ->
                    {ok, El};

                {token_element, {token, basic_string, _}} ->
                    {ok, El};

                {token_element, {token, literal_string, _}} ->
                    {ok, El};

                {token_element, {token, integer, _}} ->
                    {ok, El};

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

-file("src/molt/internal/emitter.gleam", 532).
?DOC(false).
-spec normalize_postscript(
    greenwood:node_(molt@types:toml_kind()),
    boolean(),
    list(greenwood:element(molt@types:toml_kind()))
) -> list(greenwood:element(molt@types:toml_kind())).
normalize_postscript(Node, First, Rest) ->
    case normalize_trivia(Node) of
        bare ->
            normalize_top_level(Rest, First);

        {trivia, Leading, Trailing} ->
            Leading@1 = case First of
                true ->
                    Leading;

                false ->
                    [{token, newline, <<"\n"/utf8>>} | Leading]
            end,
            [{node_element,
                    {node,
                        erlang:element(2, Node),
                        [],
                        {trivia, Leading@1, Trailing}}} |
                normalize_top_level(Rest, First)]
    end.

-file("src/molt/internal/emitter.gleam", 451).
?DOC(false).
-spec normalize_table_node(
    greenwood:node_(molt@types:toml_kind()),
    boolean(),
    list(greenwood:element(molt@types:toml_kind()))
) -> list(greenwood:element(molt@types:toml_kind())).
normalize_table_node(Node, First, Rest) ->
    Sep = case First of
        true ->
            [];

        false ->
            [{token_element, {token, newline, <<"\n"/utf8>>}}]
    end,
    Header_tokens = extract_header_tokens(erlang:element(3, Node)),
    Comment = extract_inline_comment(erlang:element(3, Node)),
    Body = normalize_body(erlang:element(3, Node)),
    Header_line = case Comment of
        <<""/utf8>> ->
            lists:append(
                [Header_tokens,
                    [{token_element, {token, newline, <<"\n"/utf8>>}}]]
            );

        C ->
            lists:append(
                [Header_tokens,
                    [{token_element, {token, whitespace, <<" "/utf8>>}},
                        {token_element, {token, comment, C}},
                        {token_element, {token, newline, <<"\n"/utf8>>}}]]
            )
    end,
    Children = lists:append([Header_line, Body]),
    Trivia = normalize_trivia(Node),
    Normalized = {node, erlang:element(2, Node), Children, Trivia},
    lists:append(
        [Sep, [{node_element, Normalized}], normalize_top_level(Rest, false)]
    ).

-file("src/molt/internal/emitter.gleam", 424).
?DOC(false).
-spec normalize_top_level(
    list(greenwood:element(molt@types:toml_kind())),
    boolean()
) -> list(greenwood:element(molt@types:toml_kind())).
normalize_top_level(Children, First) ->
    case Children of
        [] ->
            [];

        [El | Rest] ->
            case El of
                {node_element, N} when (erlang:element(2, N) =:= table) orelse (erlang:element(
                    2,
                    N
                ) =:= array_of_tables) ->
                    normalize_table_node(N, First, Rest);

                {node_element, N@1} when erlang:element(2, N@1) =:= key_value ->
                    [{node_element, normalize_kv_node(N@1)} |
                        normalize_top_level(Rest, false)];

                {node_element, N@2} when erlang:element(2, N@2) =:= post_script ->
                    normalize_postscript(N@2, First, Rest);

                {token_element, {token, comment, _}} ->
                    [El,
                        {token_element, {token, newline, <<"\n"/utf8>>}} |
                        normalize_top_level(Rest, First)];

                _ ->
                    normalize_top_level(Rest, First)
            end
    end.

-file("src/molt/internal/emitter.gleam", 44).
?DOC(false).
-spec normalize(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
normalize(Node) ->
    Children = normalize_top_level(erlang:element(3, Node), true),
    Children@1 = ensure_trailing_newline(Children),
    {node, erlang:element(2, Node), Children@1, erlang:element(4, Node)}.

-file("src/molt/internal/emitter.gleam", 328).
?DOC(false).
-spec emit_token_common(
    gleam@string_tree:string_tree(),
    greenwood:token(molt@types:toml_kind())
) -> gleam@string_tree:string_tree().
emit_token_common(Tree, Tok) ->
    case erlang:element(2, Tok) of
        equals ->
            gleam@string_tree:append(Tree, <<"="/utf8>>);

        dot ->
            gleam@string_tree:append(Tree, <<"."/utf8>>);

        comma ->
            gleam@string_tree:append(Tree, <<","/utf8>>);

        left_bracket ->
            gleam@string_tree:append(Tree, <<"["/utf8>>);

        right_bracket ->
            gleam@string_tree:append(Tree, <<"]"/utf8>>);

        left_brace ->
            gleam@string_tree:append(Tree, <<"{"/utf8>>);

        right_brace ->
            gleam@string_tree:append(Tree, <<"}"/utf8>>);

        bool_true ->
            gleam@string_tree:append(Tree, <<"true"/utf8>>);

        bool_false ->
            gleam@string_tree:append(Tree, <<"false"/utf8>>);

        inf ->
            gleam@string_tree:append(Tree, <<"inf"/utf8>>);

        pos_inf ->
            gleam@string_tree:append(Tree, <<"+inf"/utf8>>);

        neg_inf ->
            gleam@string_tree:append(Tree, <<"-inf"/utf8>>);

        na_n ->
            gleam@string_tree:append(Tree, <<"nan"/utf8>>);

        pos_na_n ->
            gleam@string_tree:append(Tree, <<"+nan"/utf8>>);

        neg_na_n ->
            gleam@string_tree:append(Tree, <<"-nan"/utf8>>);

        literal_string ->
            gleam@string_tree:append(
                Tree,
                <<<<"'"/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "'"/utf8>>
            );

        multiline_literal_string ->
            gleam@string_tree:append(
                Tree,
                <<<<"'''"/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "'''"/utf8>>
            );

        multiline_literal_string_nl ->
            gleam@string_tree:append(
                Tree,
                <<<<"'''\n"/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "'''"/utf8>>
            );

        _ ->
            gleam@string_tree:append(Tree, erlang:element(3, Tok))
    end.

-file("src/molt/internal/emitter.gleam", 316).
?DOC(false).
-spec emit_token_v1_1(
    gleam@string_tree:string_tree(),
    greenwood:token(molt@types:toml_kind())
) -> gleam@string_tree:string_tree().
emit_token_v1_1(Tree, Tok) ->
    case erlang:element(2, Tok) of
        basic_string ->
            gleam@string_tree:append(
                Tree,
                <<<<"\""/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "\""/utf8>>
            );

        multiline_basic_string ->
            gleam@string_tree:append(
                Tree,
                <<<<"\"\"\""/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "\"\"\""/utf8>>
            );

        multiline_basic_string_nl ->
            gleam@string_tree:append(
                Tree,
                <<<<"\"\"\"\n"/utf8, (erlang:element(3, Tok))/binary>>/binary,
                    "\"\"\""/utf8>>
            );

        _ ->
            emit_token_common(Tree, Tok)
    end.

-file("src/molt/internal/emitter.gleam", 114).
?DOC(false).
-spec resolve_newline_token(greenwood:token(molt@types:toml_kind()), binary()) -> greenwood:token(molt@types:toml_kind()).
resolve_newline_token(Tok, Nl) ->
    case {erlang:element(2, Tok), erlang:element(3, Tok)} of
        {newline, <<""/utf8>>} ->
            {token, erlang:element(2, Tok), Nl};

        {_, _} ->
            Tok
    end.

-file("src/molt/internal/emitter.gleam", 95).
?DOC(false).
-spec resolve_newlines(greenwood:node_(molt@types:toml_kind()), binary()) -> greenwood:node_(molt@types:toml_kind()).
resolve_newlines(Node, Nl) ->
    Children = gleam@list:map(erlang:element(3, Node), fun(El) -> case El of
                {token_element, Tok} ->
                    {token_element, resolve_newline_token(Tok, Nl)};

                {node_element, N} ->
                    {node_element, resolve_newlines(N, Nl)}
            end end),
    Trivia = case erlang:element(4, Node) of
        bare ->
            bare;

        {trivia, Leading, Trailing} ->
            {trivia,
                gleam@list:map(
                    Leading,
                    fun(_capture) -> resolve_newline_token(_capture, Nl) end
                ),
                gleam@list:map(
                    Trailing,
                    fun(_capture@1) -> resolve_newline_token(_capture@1, Nl) end
                )}
    end,
    {node, erlang:element(2, Node), Children, Trivia}.

-file("src/molt/internal/emitter.gleam", 141).
?DOC(false).
-spec trailing_newline_run(list(greenwood:token(molt@types:toml_kind()))) -> integer().
trailing_newline_run(Rev) ->
    case Rev of
        [{token, newline, _} | Rest] ->
            1 + trailing_newline_run(Rest);

        [{token, whitespace, _} | Rest@1] ->
            trailing_newline_run(Rest@1);

        _ ->
            0
    end.

-file("src/molt/internal/emitter.gleam", 137).
?DOC(false).
-spec head_separated(list(greenwood:token(molt@types:toml_kind()))) -> boolean().
head_separated(Leading) ->
    trailing_newline_run(lists:reverse(Leading)) >= 2.

-file("src/molt/internal/emitter.gleam", 125).
?DOC(false).
-spec has_statement_child(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
has_statement_child(Children) ->
    gleam@list:any(Children, fun(El) -> case El of
                {node_element, N} ->
                    erlang:element(2, N) /= post_script;

                {token_element, _} ->
                    false
            end end).

-file("src/molt/internal/emitter.gleam", 121).
?DOC(false).
-spec leading_has_comment(list(greenwood:token(molt@types:toml_kind()))) -> boolean().
leading_has_comment(Tokens) ->
    gleam@list:any(Tokens, fun(T) -> erlang:element(2, T) =:= comment end).

-file("src/molt/internal/emitter.gleam", 66).
?DOC(false).
-spec ensure_head_separation(greenwood:node_(molt@types:toml_kind())) -> greenwood:node_(molt@types:toml_kind()).
ensure_head_separation(Node) ->
    case erlang:element(4, Node) of
        {trivia, Leading, Trailing} ->
            case (leading_has_comment(Leading) andalso has_statement_child(
                erlang:element(3, Node)
            ))
            andalso not head_separated(Leading) of
                true ->
                    {node,
                        erlang:element(2, Node),
                        erlang:element(3, Node),
                        {trivia,
                            lists:append(
                                Leading,
                                [{token, newline, <<""/utf8>>}]
                            ),
                            Trailing}};

                false ->
                    Node
            end;

        bare ->
            Node
    end.

-file("src/molt/internal/emitter.gleam", 160).
?DOC(false).
-spec emit_v1_1(greenwood:node_(molt@types:toml_kind())) -> binary().
emit_v1_1(Node) ->
    Nl = molt@internal@cst@elements:document_newline(Node),
    Node@1 = begin
        _pipe = Node,
        _pipe@1 = ensure_head_separation(_pipe),
        _pipe@2 = resolve_newlines(_pipe@1, Nl),
        molt@internal@cst@elements:inline_trailing_trivia(_pipe@2)
    end,
    Visitor = begin
        _pipe@3 = greenwood:visitor(),
        _pipe@4 = greenwood:on_trivia(
            _pipe@3,
            fun(Tree, Tok) -> {continue, emit_token_v1_1(Tree, Tok)} end
        ),
        greenwood:on_token(
            _pipe@4,
            fun(Tree@1, Tok@1) -> {continue, emit_token_v1_1(Tree@1, Tok@1)} end
        )
    end,
    _pipe@5 = greenwood:traverse(Node@1, gleam@string_tree:new(), Visitor),
    unicode:characters_to_binary(_pipe@5).

-file("src/molt/internal/emitter.gleam", 420).
?DOC(false).
-spec is_newline_token(greenwood:token(molt@types:toml_kind())) -> boolean().
is_newline_token(Tok) ->
    erlang:element(2, Tok) =:= newline.

-file("src/molt/internal/emitter.gleam", 411).
?DOC(false).
-spec trivia_has_newline(greenwood:trivia(molt@types:toml_kind())) -> boolean().
trivia_has_newline(Trivia) ->
    case Trivia of
        bare ->
            false;

        {trivia, Leading, Trailing} ->
            gleam@list:any(Leading, fun is_newline_token/1) orelse gleam@list:any(
                Trailing,
                fun is_newline_token/1
            )
    end.

-file("src/molt/internal/emitter.gleam", 396).
?DOC(false).
-spec has_structural_newline(list(greenwood:element(molt@types:toml_kind()))) -> boolean().
has_structural_newline(Elements) ->
    gleam@list:any(Elements, fun(El) -> case El of
                {token_element, {token, newline, _}} ->
                    true;

                {token_element, _} ->
                    false;

                {node_element, N} ->
                    case erlang:element(2, N) of
                        array ->
                            trivia_has_newline(erlang:element(4, N));

                        inline_table ->
                            trivia_has_newline(erlang:element(4, N));

                        _ ->
                            trivia_has_newline(erlang:element(4, N)) orelse has_structural_newline(
                                erlang:element(3, N)
                            )
                    end
            end end).

-file("src/molt/internal/emitter.gleam", 392).
?DOC(false).
-spec is_multiline_inline_table(greenwood:node_(molt@types:toml_kind())) -> boolean().
is_multiline_inline_table(Node) ->
    has_structural_newline(erlang:element(3, Node)).

-file("src/molt/internal/emitter.gleam", 377).
?DOC(false).
-spec pad_local_time(binary()) -> binary().
pad_local_time(Text) ->
    gleam@bool:guard(
        string:length(Text) =:= 5,
        <<Text/binary, ":00"/utf8>>,
        fun() -> Text end
    ).

-file("src/molt/internal/emitter.gleam", 359).
?DOC(false).
-spec do_rewrite_v1_0_escapes(list(binary()), gleam@string_tree:string_tree()) -> gleam@string_tree:string_tree().
do_rewrite_v1_0_escapes(Chars, Tree) ->
    case Chars of
        [] ->
            Tree;

        [<<"\\"/utf8>>, <<"e"/utf8>> | Rest] ->
            do_rewrite_v1_0_escapes(
                Rest,
                gleam@string_tree:append(Tree, <<"\\u001B"/utf8>>)
            );

        [<<"\\"/utf8>>, <<"x"/utf8>>, H1, H2 | Rest@1] ->
            do_rewrite_v1_0_escapes(
                Rest@1,
                gleam@string_tree:append(
                    Tree,
                    <<<<"\\u00"/utf8, H1/binary>>/binary, H2/binary>>
                )
            );

        [Ch | Rest@2] ->
            do_rewrite_v1_0_escapes(Rest@2, gleam@string_tree:append(Tree, Ch))
    end.

-file("src/molt/internal/emitter.gleam", 355).
?DOC(false).
-spec rewrite_v1_0_escapes(binary()) -> gleam@string_tree:string_tree().
rewrite_v1_0_escapes(Text) ->
    do_rewrite_v1_0_escapes(
        gleam@string:to_graphemes(Text),
        gleam@string_tree:new()
    ).

-file("src/molt/internal/emitter.gleam", 296).
?DOC(false).
-spec emit_token_text_v1_0(
    gleam@string_tree:string_tree(),
    greenwood:token(molt@types:toml_kind())
) -> gleam@string_tree:string_tree().
emit_token_text_v1_0(Tree, Tok) ->
    case erlang:element(2, Tok) of
        basic_string ->
            Text = <<<<"\""/utf8, (erlang:element(3, Tok))/binary>>/binary,
                "\""/utf8>>,
            gleam_stdlib:iodata_append(Tree, rewrite_v1_0_escapes(Text));

        multiline_basic_string ->
            Text@1 = <<<<"\"\"\""/utf8, (erlang:element(3, Tok))/binary>>/binary,
                "\"\"\""/utf8>>,
            gleam_stdlib:iodata_append(Tree, rewrite_v1_0_escapes(Text@1));

        multiline_basic_string_nl ->
            Text@2 = <<<<"\"\"\"\n"/utf8, (erlang:element(3, Tok))/binary>>/binary,
                "\"\"\""/utf8>>,
            gleam_stdlib:iodata_append(Tree, rewrite_v1_0_escapes(Text@2));

        local_time ->
            gleam@string_tree:append(
                Tree,
                pad_local_time(erlang:element(3, Tok))
            );

        _ ->
            emit_token_common(Tree, Tok)
    end.

-file("src/molt/internal/emitter.gleam", 281).
?DOC(false).
-spec flush_pending(emit_state()) -> emit_state().
flush_pending(State) ->
    case {erlang:element(6, State), erlang:element(5, State)} of
        {true, _} ->
            Tree = gleam@string_tree:append(
                erlang:element(2, State),
                <<" "/utf8>>
            ),
            {emit_state,
                Tree,
                erlang:element(3, State),
                erlang:element(4, State),
                erlang:element(5, State),
                false};

        {_, true} ->
            Tree@1 = gleam@string_tree:append(
                erlang:element(2, State),
                <<", "/utf8>>
            ),
            {emit_state,
                Tree@1,
                erlang:element(3, State),
                erlang:element(4, State),
                false,
                erlang:element(6, State)};

        {_, _} ->
            State
    end.

-file("src/molt/internal/emitter.gleam", 237).
?DOC(false).
-spec emit_v1_0_token(emit_state(), greenwood:token(molt@types:toml_kind())) -> emit_state().
emit_v1_0_token(State, Tok) ->
    case {erlang:element(3, State) > 0, erlang:element(2, Tok)} of
        {true, newline} ->
            State;

        {true, comment} ->
            State;

        {true, whitespace} ->
            State;

        {true, comma} ->
            {emit_state,
                erlang:element(2, State),
                erlang:element(3, State),
                erlang:element(4, State),
                true,
                erlang:element(6, State)};

        {true, right_brace} ->
            Tree = case erlang:element(6, State) of
                true ->
                    gleam@string_tree:append(
                        erlang:element(2, State),
                        <<"}"/utf8>>
                    );

                false ->
                    gleam@string_tree:append(
                        erlang:element(2, State),
                        <<" }"/utf8>>
                    )
            end,
            {emit_state,
                Tree,
                erlang:element(3, State),
                erlang:element(4, State),
                false,
                false};

        {true, left_brace} ->
            State@1 = flush_pending(State),
            Tree@1 = gleam@string_tree:append(
                erlang:element(2, State@1),
                <<"{"/utf8>>
            ),
            {emit_state,
                Tree@1,
                erlang:element(3, State@1),
                erlang:element(4, State@1),
                erlang:element(5, State@1),
                true};

        {true, equals} ->
            Tree@2 = gleam@string_tree:append(
                erlang:element(2, State),
                <<" = "/utf8>>
            ),
            {emit_state,
                Tree@2,
                erlang:element(3, State),
                erlang:element(4, State),
                erlang:element(5, State),
                erlang:element(6, State)};

        {true, _} ->
            State@2 = flush_pending(State),
            Tree@3 = emit_token_text_v1_0(erlang:element(2, State@2), Tok),
            {emit_state,
                Tree@3,
                erlang:element(3, State@2),
                erlang:element(4, State@2),
                erlang:element(5, State@2),
                erlang:element(6, State@2)};

        {false, _} ->
            Tree@4 = emit_token_text_v1_0(erlang:element(2, State), Tok),
            {emit_state,
                Tree@4,
                erlang:element(3, State),
                erlang:element(4, State),
                erlang:element(5, State),
                erlang:element(6, State)}
    end.

-file("src/molt/internal/emitter.gleam", 190).
?DOC(false).
-spec emit_v1_0(greenwood:node_(molt@types:toml_kind())) -> binary().
emit_v1_0(Node) ->
    Nl = molt@internal@cst@elements:document_newline(Node),
    Node@1 = begin
        _pipe = Node,
        _pipe@1 = ensure_head_separation(_pipe),
        _pipe@2 = resolve_newlines(_pipe@1, Nl),
        molt@internal@cst@elements:inline_trailing_trivia(_pipe@2)
    end,
    Visitor = begin
        _pipe@3 = greenwood:visitor(),
        _pipe@4 = greenwood:on_trivia(
            _pipe@3,
            fun(State, Tok) -> {continue, emit_v1_0_token(State, Tok)} end
        ),
        _pipe@5 = greenwood:on_token(
            _pipe@4,
            fun(State@1, Tok@1) ->
                {continue, emit_v1_0_token(State@1, Tok@1)}
            end
        ),
        _pipe@6 = greenwood:on_enter_node(
            _pipe@5,
            fun(State@2, Node@2) ->
                State@3 = {emit_state,
                    erlang:element(2, State@2),
                    erlang:element(3, State@2),
                    erlang:element(4, State@2) + 1,
                    erlang:element(5, State@2),
                    erlang:element(6, State@2)},
                case (erlang:element(2, Node@2) =:= inline_table) andalso is_multiline_inline_table(
                    Node@2
                ) of
                    true ->
                        {continue,
                            {emit_state,
                                erlang:element(2, State@3),
                                erlang:element(3, State@3) + 1,
                                erlang:element(4, State@3),
                                erlang:element(5, State@3),
                                erlang:element(6, State@3)}};

                    false ->
                        {continue, State@3}
                end
            end
        ),
        greenwood:on_exit_node(
            _pipe@6,
            fun(State@4, Node@3) ->
                State@5 = {emit_state,
                    erlang:element(2, State@4),
                    erlang:element(3, State@4),
                    erlang:element(4, State@4) - 1,
                    erlang:element(5, State@4),
                    erlang:element(6, State@4)},
                case (erlang:element(2, Node@3) =:= inline_table) andalso is_multiline_inline_table(
                    Node@3
                ) of
                    true ->
                        {continue,
                            {emit_state,
                                erlang:element(2, State@5),
                                erlang:element(3, State@5) - 1,
                                erlang:element(4, State@5),
                                erlang:element(5, State@5),
                                erlang:element(6, State@5)}};

                    false ->
                        {continue, State@5}
                end
            end
        )
    end,
    State@6 = greenwood:traverse(
        Node@1,
        {emit_state, gleam@string_tree:new(), 0, 0, false, false},
        Visitor
    ),
    unicode:characters_to_binary(erlang:element(2, State@6)).

-file("src/molt/internal/emitter.gleam", 150).
?DOC(false).
-spec emit_versioned(
    greenwood:node_(molt@types:toml_kind()),
    molt@types:toml_version()
) -> binary().
emit_versioned(Node, Version) ->
    case Version =:= {toml_version, <<"1.0"/utf8>>} of
        true ->
            emit_v1_0(Node);

        false ->
            emit_v1_1(Node)
    end.

-file("src/molt/internal/emitter.gleam", 54).
?DOC(false).
-spec emit(greenwood:node_(molt@types:toml_kind())) -> binary().
emit(Node) ->
    emit_versioned(Node, {toml_version, <<"1.1"/utf8>>}).