Skip to main content

src/gg_cn@internal@merge.erl

-module(gg_cn@internal@merge).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gg_cn/internal/merge.gleam").
-export([new/1, merge_class_list/2]).
-export_type([engine/0, descriptor/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 engine() :: {engine,
        gg_cn@internal@config:config(),
        gg_cn@internal@class_map:class_part(),
        gleam@set:set(binary()),
        gleam@set:set(binary())}.

-type descriptor() :: external | {managed, binary(), list(binary())}.

-file("src/gg_cn/internal/merge.gleam", 31).
?DOC(false).
-spec new(gg_cn@internal@config:config()) -> engine().
new(Config) ->
    {engine,
        Config,
        gg_cn@internal@class_map:build(Config),
        gleam@set:from_list(erlang:element(7, Config)),
        gleam@set:from_list(erlang:element(6, Config))}.

-file("src/gg_cn/internal/merge.gleam", 153).
?DOC(false).
-spec modifier_id(engine(), gg_cn@internal@parse:parsed()) -> binary().
modifier_id(Engine, Parsed) ->
    Variant = case erlang:element(2, Parsed) of
        [] ->
            <<""/utf8>>;

        [Single] ->
            Single;

        Many ->
            _pipe = gg_cn@internal@sort_modifiers:sort_modifiers(
                erlang:element(4, Engine),
                Many
            ),
            gleam@string:join(_pipe, <<":"/utf8>>)
    end,
    case erlang:element(3, Parsed) of
        true ->
            <<Variant/binary, "!"/utf8>>;

        false ->
            Variant
    end.

-file("src/gg_cn/internal/merge.gleam", 136).
?DOC(false).
-spec finish(engine(), gg_cn@internal@parse:parsed(), binary(), boolean()) -> descriptor().
finish(Engine, Parsed, Group_id, Has_postfix_modifier) ->
    Modifier_id = modifier_id(Engine, Parsed),
    Conflict_groups = gg_cn@internal@class_map:get_conflicting_class_group_ids(
        erlang:element(2, Engine),
        Group_id,
        Has_postfix_modifier
    ),
    Conflict_ids = gleam@list:map(
        Conflict_groups,
        fun(G) -> <<Modifier_id/binary, G/binary>> end
    ),
    {managed, <<Modifier_id/binary, Group_id/binary>>, Conflict_ids}.

-file("src/gg_cn/internal/merge.gleam", 86).
?DOC(false).
-spec compute_descriptor(engine(), binary()) -> descriptor().
compute_descriptor(Engine, Class_name) ->
    Parsed = gg_cn@internal@parse:parse_class_name(Class_name),
    case erlang:element(5, Parsed) of
        {some, Position} ->
            Base_without_postfix = gleam@string:slice(
                erlang:element(4, Parsed),
                0,
                Position
            ),
            case gg_cn@internal@class_map:get_class_group_id(
                erlang:element(3, Engine),
                Base_without_postfix
            ) of
                {some, Group_id} ->
                    case gleam@set:contains(erlang:element(5, Engine), Group_id) of
                        true ->
                            case gg_cn@internal@class_map:get_class_group_id(
                                erlang:element(3, Engine),
                                erlang:element(4, Parsed)
                            ) of
                                {some, Group_with_postfix} when Group_with_postfix =/= Group_id ->
                                    finish(
                                        Engine,
                                        Parsed,
                                        Group_with_postfix,
                                        false
                                    );

                                _ ->
                                    finish(Engine, Parsed, Group_id, true)
                            end;

                        false ->
                            finish(Engine, Parsed, Group_id, true)
                    end;

                none ->
                    case gg_cn@internal@class_map:get_class_group_id(
                        erlang:element(3, Engine),
                        erlang:element(4, Parsed)
                    ) of
                        {some, Group_id@1} ->
                            finish(Engine, Parsed, Group_id@1, false);

                        none ->
                            external
                    end
            end;

        none ->
            case gg_cn@internal@class_map:get_class_group_id(
                erlang:element(3, Engine),
                erlang:element(4, Parsed)
            ) of
                {some, Group_id@2} ->
                    finish(Engine, Parsed, Group_id@2, false);

                none ->
                    external
            end
    end.

-file("src/gg_cn/internal/merge.gleam", 64).
?DOC(false).
-spec resolve(engine(), list(binary())) -> list(binary()).
resolve(Engine, Tokens) ->
    {Kept@1, _} = gleam@list:fold(
        lists:reverse(Tokens),
        {[], gleam@set:new()},
        fun(Acc, Token) ->
            {Kept, Claimed} = Acc,
            case compute_descriptor(Engine, Token) of
                external ->
                    {[Token | Kept], Claimed};

                {managed, Class_id, Conflict_ids} ->
                    case gleam@set:contains(Claimed, Class_id) of
                        true ->
                            {Kept, Claimed};

                        false ->
                            Claimed@1 = gleam@list:fold(
                                [Class_id | Conflict_ids],
                                Claimed,
                                fun(S, Key) -> gleam@set:insert(S, Key) end
                            ),
                            {[Token | Kept], Claimed@1}
                    end
            end
        end
    ),
    Kept@1.

-file("src/gg_cn/internal/merge.gleam", 193).
?DOC(false).
-spec is_whitespace(binary()) -> boolean().
is_whitespace(Char) ->
    (((((Char =:= <<" "/utf8>>) orelse (Char =:= <<"\t"/utf8>>)) orelse (Char
    =:= <<"\n"/utf8>>))
    orelse (Char =:= <<"\r"/utf8>>))
    orelse (Char =:= <<"\f"/utf8>>))
    orelse (Char =:= <<"\x{000B}"/utf8>>).

-file("src/gg_cn/internal/merge.gleam", 169).
?DOC(false).
-spec split_class_list(binary()) -> list(binary()).
split_class_list(Class_list) ->
    _pipe = Class_list,
    _pipe@1 = gleam@string:to_graphemes(_pipe),
    _pipe@2 = gleam@list:fold(
        _pipe@1,
        {[], <<""/utf8>>},
        fun(Acc, Char) ->
            {Tokens_rev, Current} = Acc,
            case is_whitespace(Char) of
                true ->
                    case Current of
                        <<""/utf8>> ->
                            {Tokens_rev, <<""/utf8>>};

                        _ ->
                            {[Current | Tokens_rev], <<""/utf8>>}
                    end;

                false ->
                    {Tokens_rev, <<Current/binary, Char/binary>>}
            end
        end
    ),
    _pipe@3 = (fun(State) ->
        {Tokens_rev@1, Current@1} = State,
        case Current@1 of
            <<""/utf8>> ->
                Tokens_rev@1;

            _ ->
                [Current@1 | Tokens_rev@1]
        end
    end)(_pipe@2),
    lists:reverse(_pipe@3).

-file("src/gg_cn/internal/merge.gleam", 48).
?DOC(false).
-spec merge_class_list(engine(), binary()) -> binary().
merge_class_list(Engine, Class_list) ->
    Tokens = split_class_list(Class_list),
    case Tokens of
        [Single] ->
            Single;

        _ ->
            Kept = resolve(Engine, Tokens),
            gleam@string:join(Kept, <<" "/utf8>>)
    end.