src/lightspeed@component@template_compiler.erl

-module(lightspeed@component@template_compiler).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/component/template_compiler.gleam").
-export([required_string/1, required_int/1, required_bool/1, optional_string/2, optional_int/2, optional_bool/2, required_slot/1, optional_slot/1, schema/6, compile/3, diagnostic_label/1, diagnostics_signature/1, signature/1, rendered/1, html/1, fingerprint/1, require_string/2, require_int/2, require_bool/2, slot_rendered/2, require_slot/2]).
-export_type([attr_kind/0, attr_value/0, attr_requirement/0, attr_schema/0, slot_requirement/0, slot_schema/0, schema/2, compiled_template/2, diagnostic/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(" Compile-time-style template schema validation with deterministic diagnostics.\n").

-type attr_kind() :: attr_string | attr_int | attr_bool.

-type attr_value() :: {string_attr, binary()} |
    {int_attr, integer()} |
    {bool_attr, boolean()}.

-type attr_requirement() :: required_attr |
    {optional_attr, gleam@option:option(attr_value())}.

-type attr_schema() :: {attr_schema, binary(), attr_kind(), attr_requirement()}.

-type slot_requirement() :: required_slot | optional_slot.

-type slot_schema() :: {slot_schema, binary(), slot_requirement()}.

-type schema(IKD, IKE) :: {schema,
        binary(),
        list(attr_schema()),
        list(slot_schema()),
        fun((list({binary(), attr_value()})) -> {ok, IKD} | {error, binary()}),
        fun((list({binary(), lightspeed@component:rendered()})) -> {ok, IKE} |
            {error, binary()}),
        fun((IKD, IKE) -> lightspeed@component:rendered())}.

-type compiled_template(IKF, IKG) :: {compiled_template,
        binary(),
        list({binary(), attr_value()}),
        list({binary(), lightspeed@component:rendered()}),
        IKF,
        IKG,
        lightspeed@component:rendered(),
        binary()}.

-type diagnostic() :: {missing_attribute, binary(), binary()} |
    {duplicate_attribute, binary(), binary()} |
    {unknown_attribute, binary(), binary()} |
    {invalid_attribute_type, binary(), binary(), attr_kind(), attr_kind()} |
    {missing_slot, binary(), binary()} |
    {duplicate_slot, binary(), binary()} |
    {unknown_slot, binary(), binary()} |
    {assign_build_failed, binary(), binary()} |
    {slot_build_failed, binary(), binary()}.

-file("src/lightspeed/component/template_compiler.gleam", 90).
?DOC(" Build one required string attribute rule.\n").
-spec required_string(binary()) -> attr_schema().
required_string(Name) ->
    {attr_schema, Name, attr_string, required_attr}.

-file("src/lightspeed/component/template_compiler.gleam", 95).
?DOC(" Build one required int attribute rule.\n").
-spec required_int(binary()) -> attr_schema().
required_int(Name) ->
    {attr_schema, Name, attr_int, required_attr}.

-file("src/lightspeed/component/template_compiler.gleam", 100).
?DOC(" Build one required bool attribute rule.\n").
-spec required_bool(binary()) -> attr_schema().
required_bool(Name) ->
    {attr_schema, Name, attr_bool, required_attr}.

-file("src/lightspeed/component/template_compiler.gleam", 744).
-spec option_map_string(gleam@option:option(binary())) -> gleam@option:option(attr_value()).
option_map_string(Value) ->
    case Value of
        none ->
            none;

        {some, Default} ->
            {some, {string_attr, Default}}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 105).
?DOC(" Build one optional string attribute with optional default.\n").
-spec optional_string(binary(), gleam@option:option(binary())) -> attr_schema().
optional_string(Name, Default) ->
    {attr_schema,
        Name,
        attr_string,
        {optional_attr, option_map_string(Default)}}.

-file("src/lightspeed/component/template_compiler.gleam", 751).
-spec option_map_int(gleam@option:option(integer())) -> gleam@option:option(attr_value()).
option_map_int(Value) ->
    case Value of
        none ->
            none;

        {some, Default} ->
            {some, {int_attr, Default}}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 114).
?DOC(" Build one optional int attribute with optional default.\n").
-spec optional_int(binary(), gleam@option:option(integer())) -> attr_schema().
optional_int(Name, Default) ->
    {attr_schema, Name, attr_int, {optional_attr, option_map_int(Default)}}.

-file("src/lightspeed/component/template_compiler.gleam", 758).
-spec option_map_bool(gleam@option:option(boolean())) -> gleam@option:option(attr_value()).
option_map_bool(Value) ->
    case Value of
        none ->
            none;

        {some, Default} ->
            {some, {bool_attr, Default}}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 123).
?DOC(" Build one optional bool attribute with optional default.\n").
-spec optional_bool(binary(), gleam@option:option(boolean())) -> attr_schema().
optional_bool(Name, Default) ->
    {attr_schema, Name, attr_bool, {optional_attr, option_map_bool(Default)}}.

-file("src/lightspeed/component/template_compiler.gleam", 132).
?DOC(" Build one required slot rule.\n").
-spec required_slot(binary()) -> slot_schema().
required_slot(Name) ->
    {slot_schema, Name, required_slot}.

-file("src/lightspeed/component/template_compiler.gleam", 137).
?DOC(" Build one optional slot rule.\n").
-spec optional_slot(binary()) -> slot_schema().
optional_slot(Name) ->
    {slot_schema, Name, optional_slot}.

-file("src/lightspeed/component/template_compiler.gleam", 142).
?DOC(" Build one template compilation schema.\n").
-spec schema(
    binary(),
    list(attr_schema()),
    list(slot_schema()),
    fun((list({binary(), attr_value()})) -> {ok, IKN} | {error, binary()}),
    fun((list({binary(), lightspeed@component:rendered()})) -> {ok, IKR} |
        {error, binary()}),
    fun((IKN, IKR) -> lightspeed@component:rendered())
) -> schema(IKN, IKR).
schema(Name, Attrs, Slots, Build_assigns, Build_slots, Render) ->
    {schema, Name, Attrs, Slots, Build_assigns, Build_slots, Render}.

-file("src/lightspeed/component/template_compiler.gleam", 773).
-spec concat_lists(list(IOU), list(IOU)) -> list(IOU).
concat_lists(First, Second) ->
    case First of
        [] ->
            Second;

        [Value | Rest] ->
            [Value | concat_lists(Rest, Second)]
    end.

-file("src/lightspeed/component/template_compiler.gleam", 765).
-spec join_with(binary(), list(binary())) -> binary().
join_with(Separator, Values) ->
    case Values of
        [] ->
            <<""/utf8>>;

        [Value] ->
            Value;

        [Value@1 | Rest] ->
            <<<<Value@1/binary, Separator/binary>>/binary,
                (join_with(Separator, Rest))/binary>>
    end.

-file("src/lightspeed/component/template_compiler.gleam", 724).
-spec attr_value_label(attr_value()) -> binary().
attr_value_label(Value) ->
    case Value of
        {string_attr, String_value} ->
            <<"string:"/utf8, String_value/binary>>;

        {int_attr, Int_value} ->
            <<"int:"/utf8, (erlang:integer_to_binary(Int_value))/binary>>;

        {bool_attr, Bool_value} ->
            case Bool_value of
                true ->
                    <<"bool:true"/utf8>>;

                false ->
                    <<"bool:false"/utf8>>
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 689).
-spec compile_signature(
    binary(),
    list({binary(), attr_value()}),
    list({binary(), lightspeed@component:rendered()}),
    lightspeed@component:rendered()
) -> binary().
compile_signature(Name, Attrs, Slots, Rendered) ->
    Attr_labels = gleam@list:map(
        Attrs,
        fun(Attribute) ->
            {Attr_name, Attr_value} = Attribute,
            <<<<Attr_name/binary, "="/utf8>>/binary,
                (attr_value_label(Attr_value))/binary>>
        end
    ),
    Attr_signature = join_with(<<","/utf8>>, Attr_labels),
    Slot_labels = gleam@list:map(
        Slots,
        fun(Slot) ->
            {Slot_name, Slot_rendered} = Slot,
            <<<<<<<<Slot_name/binary, ":fingerprint="/utf8>>/binary,
                        (lightspeed@component:fingerprint(Slot_rendered))/binary>>/binary,
                    ":html="/utf8>>/binary,
                (lightspeed@component:to_html(Slot_rendered))/binary>>
        end
    ),
    Slot_signature = join_with(<<","/utf8>>, Slot_labels),
    <<<<<<<<<<<<<<<<<<"template="/utf8, Name/binary>>/binary, "|attrs="/utf8>>/binary,
                                Attr_signature/binary>>/binary,
                            "|slots="/utf8>>/binary,
                        Slot_signature/binary>>/binary,
                    "|rendered_fingerprint="/utf8>>/binary,
                (lightspeed@component:fingerprint(Rendered))/binary>>/binary,
            "|rendered_html="/utf8>>/binary,
        (lightspeed@component:to_html(Rendered))/binary>>.

-file("src/lightspeed/component/template_compiler.gleam", 642).
-spec find_slot(list({binary(), lightspeed@component:rendered()}), binary()) -> gleam@option:option(lightspeed@component:rendered()).
find_slot(Slots, Name) ->
    case Slots of
        [] ->
            none;

        [{Entry_name, Entry_value} | Rest] ->
            case Entry_name =:= Name of
                true ->
                    {some, Entry_value};

                false ->
                    find_slot(Rest, Name)
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 583).
-spec validate_schema_slots(
    binary(),
    list(slot_schema()),
    list({binary(), lightspeed@component:rendered()}),
    list({binary(), lightspeed@component:rendered()})
) -> {ok, list({binary(), lightspeed@component:rendered()})} |
    {error, list(diagnostic())}.
validate_schema_slots(
    Template_name,
    Schema_slots,
    Provided_slots,
    Normalized_rev
) ->
    case Schema_slots of
        [] ->
            {ok, lists:reverse(Normalized_rev)};

        [Schema | Rest] ->
            case {erlang:element(3, Schema),
                find_slot(Provided_slots, erlang:element(2, Schema))} of
                {required_slot, none} ->
                    {error,
                        [{missing_slot,
                                Template_name,
                                erlang:element(2, Schema)}]};

                {required_slot, {some, Rendered}} ->
                    validate_schema_slots(
                        Template_name,
                        Rest,
                        Provided_slots,
                        [{erlang:element(2, Schema), Rendered} | Normalized_rev]
                    );

                {optional_slot, none} ->
                    validate_schema_slots(
                        Template_name,
                        Rest,
                        Provided_slots,
                        Normalized_rev
                    );

                {optional_slot, {some, Rendered@1}} ->
                    validate_schema_slots(
                        Template_name,
                        Rest,
                        Provided_slots,
                        [{erlang:element(2, Schema), Rendered@1} |
                            Normalized_rev]
                    )
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 667).
-spec slot_in_schema(list(slot_schema()), binary()) -> boolean().
slot_in_schema(Slots, Name) ->
    case Slots of
        [] ->
            false;

        [Schema | Rest] ->
            case erlang:element(2, Schema) =:= Name of
                true ->
                    true;

                false ->
                    slot_in_schema(Rest, Name)
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 678).
-spec contains_name(list(binary()), binary()) -> boolean().
contains_name(Names, Expected) ->
    case Names of
        [] ->
            false;

        [Name | Rest] ->
            case Name =:= Expected of
                true ->
                    true;

                false ->
                    contains_name(Rest, Expected)
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 535).
-spec find_slot_input_diagnostics_loop(
    binary(),
    list(slot_schema()),
    list({binary(), lightspeed@component:rendered()}),
    list(binary()),
    list(diagnostic())
) -> list(diagnostic()).
find_slot_input_diagnostics_loop(
    Template_name,
    Schema_slots,
    Provided_slots,
    Seen,
    Diagnostics_rev
) ->
    case Provided_slots of
        [] ->
            lists:reverse(Diagnostics_rev);

        [{Name, _} | Rest] ->
            case {contains_name(Seen, Name), slot_in_schema(Schema_slots, Name)} of
                {true, _} ->
                    find_slot_input_diagnostics_loop(
                        Template_name,
                        Schema_slots,
                        Rest,
                        Seen,
                        [{duplicate_slot, Template_name, Name} |
                            Diagnostics_rev]
                    );

                {false, false} ->
                    find_slot_input_diagnostics_loop(
                        Template_name,
                        Schema_slots,
                        Rest,
                        [Name | Seen],
                        [{unknown_slot, Template_name, Name} | Diagnostics_rev]
                    );

                {false, true} ->
                    find_slot_input_diagnostics_loop(
                        Template_name,
                        Schema_slots,
                        Rest,
                        [Name | Seen],
                        Diagnostics_rev
                    )
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 521).
-spec find_slot_input_diagnostics(
    binary(),
    list(slot_schema()),
    list({binary(), lightspeed@component:rendered()})
) -> list(diagnostic()).
find_slot_input_diagnostics(Template_name, Schema_slots, Provided_slots) ->
    find_slot_input_diagnostics_loop(
        Template_name,
        Schema_slots,
        Provided_slots,
        [],
        []
    ).

-file("src/lightspeed/component/template_compiler.gleam", 366).
-spec validate_slots(
    binary(),
    list(slot_schema()),
    list({binary(), lightspeed@component:rendered()})
) -> {ok, list({binary(), lightspeed@component:rendered()})} |
    {error, list(diagnostic())}.
validate_slots(Template_name, Schema_slots, Provided_slots) ->
    Unknown_or_duplicate = find_slot_input_diagnostics(
        Template_name,
        Schema_slots,
        Provided_slots
    ),
    Schema_validation = validate_schema_slots(
        Template_name,
        Schema_slots,
        Provided_slots,
        []
    ),
    case {Unknown_or_duplicate, Schema_validation} of
        {[], {ok, Normalized}} ->
            {ok, Normalized};

        {[], {error, Diagnostics}} ->
            {error, Diagnostics};

        {Diagnostics@1, {ok, _}} ->
            {error, Diagnostics@1};

        {Diagnostics@2, {error, Other}} ->
            {error, concat_lists(Diagnostics@2, Other)}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 620).
-spec kind_of_value(attr_value()) -> attr_kind().
kind_of_value(Value) ->
    case Value of
        {string_attr, _} ->
            attr_string;

        {int_attr, _} ->
            attr_int;

        {bool_attr, _} ->
            attr_bool
    end.

-file("src/lightspeed/component/template_compiler.gleam", 628).
-spec find_attr(list({binary(), attr_value()}), binary()) -> gleam@option:option(attr_value()).
find_attr(Attrs, Name) ->
    case Attrs of
        [] ->
            none;

        [{Entry_name, Entry_value} | Rest] ->
            case Entry_name =:= Name of
                true ->
                    {some, Entry_value};

                false ->
                    find_attr(Rest, Name)
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 446).
-spec validate_schema_attrs(
    binary(),
    list(attr_schema()),
    list({binary(), attr_value()}),
    list({binary(), attr_value()})
) -> {ok, list({binary(), attr_value()})} | {error, list(diagnostic())}.
validate_schema_attrs(
    Template_name,
    Schema_attrs,
    Provided_attrs,
    Normalized_rev
) ->
    case Schema_attrs of
        [] ->
            {ok, lists:reverse(Normalized_rev)};

        [Schema | Rest] ->
            Value = find_attr(Provided_attrs, erlang:element(2, Schema)),
            case {erlang:element(4, Schema), Value} of
                {required_attr, none} ->
                    {error,
                        [{missing_attribute,
                                Template_name,
                                erlang:element(2, Schema)}]};

                {required_attr, {some, Actual}} ->
                    case kind_of_value(Actual) =:= erlang:element(3, Schema) of
                        true ->
                            validate_schema_attrs(
                                Template_name,
                                Rest,
                                Provided_attrs,
                                [{erlang:element(2, Schema), Actual} |
                                    Normalized_rev]
                            );

                        false ->
                            {error,
                                [{invalid_attribute_type,
                                        Template_name,
                                        erlang:element(2, Schema),
                                        erlang:element(3, Schema),
                                        kind_of_value(Actual)}]}
                    end;

                {{optional_attr, Default}, none} ->
                    case Default of
                        {some, Value@1} ->
                            validate_schema_attrs(
                                Template_name,
                                Rest,
                                Provided_attrs,
                                [{erlang:element(2, Schema), Value@1} |
                                    Normalized_rev]
                            );

                        none ->
                            validate_schema_attrs(
                                Template_name,
                                Rest,
                                Provided_attrs,
                                Normalized_rev
                            )
                    end;

                {{optional_attr, _}, {some, Actual@1}} ->
                    case kind_of_value(Actual@1) =:= erlang:element(3, Schema) of
                        true ->
                            validate_schema_attrs(
                                Template_name,
                                Rest,
                                Provided_attrs,
                                [{erlang:element(2, Schema), Actual@1} |
                                    Normalized_rev]
                            );

                        false ->
                            {error,
                                [{invalid_attribute_type,
                                        Template_name,
                                        erlang:element(2, Schema),
                                        erlang:element(3, Schema),
                                        kind_of_value(Actual@1)}]}
                    end
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 656).
-spec attr_in_schema(list(attr_schema()), binary()) -> boolean().
attr_in_schema(Attrs, Name) ->
    case Attrs of
        [] ->
            false;

        [Schema | Rest] ->
            case erlang:element(2, Schema) =:= Name of
                true ->
                    true;

                false ->
                    attr_in_schema(Rest, Name)
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 398).
-spec find_attr_input_diagnostics_loop(
    binary(),
    list(attr_schema()),
    list({binary(), attr_value()}),
    list(binary()),
    list(diagnostic())
) -> list(diagnostic()).
find_attr_input_diagnostics_loop(
    Template_name,
    Schema_attrs,
    Provided_attrs,
    Seen,
    Diagnostics_rev
) ->
    case Provided_attrs of
        [] ->
            lists:reverse(Diagnostics_rev);

        [{Name, _} | Rest] ->
            case {contains_name(Seen, Name), attr_in_schema(Schema_attrs, Name)} of
                {true, _} ->
                    find_attr_input_diagnostics_loop(
                        Template_name,
                        Schema_attrs,
                        Rest,
                        Seen,
                        [{duplicate_attribute, Template_name, Name} |
                            Diagnostics_rev]
                    );

                {false, false} ->
                    find_attr_input_diagnostics_loop(
                        Template_name,
                        Schema_attrs,
                        Rest,
                        [Name | Seen],
                        [{unknown_attribute, Template_name, Name} |
                            Diagnostics_rev]
                    );

                {false, true} ->
                    find_attr_input_diagnostics_loop(
                        Template_name,
                        Schema_attrs,
                        Rest,
                        [Name | Seen],
                        Diagnostics_rev
                    )
            end
    end.

-file("src/lightspeed/component/template_compiler.gleam", 384).
-spec find_attr_input_diagnostics(
    binary(),
    list(attr_schema()),
    list({binary(), attr_value()})
) -> list(diagnostic()).
find_attr_input_diagnostics(Template_name, Schema_attrs, Provided_attrs) ->
    find_attr_input_diagnostics_loop(
        Template_name,
        Schema_attrs,
        Provided_attrs,
        [],
        []
    ).

-file("src/lightspeed/component/template_compiler.gleam", 348).
-spec validate_attrs(
    binary(),
    list(attr_schema()),
    list({binary(), attr_value()})
) -> {ok, list({binary(), attr_value()})} | {error, list(diagnostic())}.
validate_attrs(Template_name, Schema_attrs, Provided_attrs) ->
    Unknown_or_duplicate = find_attr_input_diagnostics(
        Template_name,
        Schema_attrs,
        Provided_attrs
    ),
    Schema_validation = validate_schema_attrs(
        Template_name,
        Schema_attrs,
        Provided_attrs,
        []
    ),
    case {Unknown_or_duplicate, Schema_validation} of
        {[], {ok, Normalized}} ->
            {ok, Normalized};

        {[], {error, Diagnostics}} ->
            {error, Diagnostics};

        {Diagnostics@1, {ok, _}} ->
            {error, Diagnostics@1};

        {Diagnostics@2, {error, Other}} ->
            {error, concat_lists(Diagnostics@2, Other)}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 161).
?DOC(" Validate and compile one template invocation.\n").
-spec compile(
    schema(IKY, IKZ),
    list({binary(), attr_value()}),
    list({binary(), lightspeed@component:rendered()})
) -> {ok, compiled_template(IKY, IKZ)} | {error, list(diagnostic())}.
compile(Schema, Attrs, Slots) ->
    Attr_validation = validate_attrs(
        erlang:element(2, Schema),
        erlang:element(3, Schema),
        Attrs
    ),
    Slot_validation = validate_slots(
        erlang:element(2, Schema),
        erlang:element(4, Schema),
        Slots
    ),
    case {Attr_validation, Slot_validation} of
        {{ok, Normalized_attrs}, {ok, Normalized_slots}} ->
            case {(erlang:element(5, Schema))(Normalized_attrs),
                (erlang:element(6, Schema))(Normalized_slots)} of
                {{ok, Assigns}, {ok, Slot_assigns}} ->
                    Rendered = lightspeed@component@template:render(
                        erlang:element(7, Schema),
                        Assigns,
                        Slot_assigns
                    ),
                    Signature = compile_signature(
                        erlang:element(2, Schema),
                        Normalized_attrs,
                        Normalized_slots,
                        Rendered
                    ),
                    {ok,
                        {compiled_template,
                            erlang:element(2, Schema),
                            Normalized_attrs,
                            Normalized_slots,
                            Assigns,
                            Slot_assigns,
                            Rendered,
                            Signature}};

                {{error, Reason}, _} ->
                    {error,
                        [{assign_build_failed,
                                erlang:element(2, Schema),
                                Reason}]};

                {_, {error, Reason@1}} ->
                    {error,
                        [{slot_build_failed,
                                erlang:element(2, Schema),
                                Reason@1}]}
            end;

        {{error, Attr_diagnostics}, {ok, _}} ->
            {error, Attr_diagnostics};

        {{ok, _}, {error, Slot_diagnostics}} ->
            {error, Slot_diagnostics};

        {{error, Attr_diagnostics@1}, {error, Slot_diagnostics@1}} ->
            {error, concat_lists(Attr_diagnostics@1, Slot_diagnostics@1)}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 736).
-spec kind_label(attr_kind()) -> binary().
kind_label(Kind) ->
    case Kind of
        attr_string ->
            <<"string"/utf8>>;

        attr_int ->
            <<"int"/utf8>>;

        attr_bool ->
            <<"bool"/utf8>>
    end.

-file("src/lightspeed/component/template_compiler.gleam", 213).
?DOC(" Stable diagnostic label.\n").
-spec diagnostic_label(diagnostic()) -> binary().
diagnostic_label(Diagnostic) ->
    case Diagnostic of
        {missing_attribute, Template, Attribute} ->
            <<<<<<"missing_attribute:"/utf8, Template/binary>>/binary,
                    ":"/utf8>>/binary,
                Attribute/binary>>;

        {duplicate_attribute, Template@1, Attribute@1} ->
            <<<<<<"duplicate_attribute:"/utf8, Template@1/binary>>/binary,
                    ":"/utf8>>/binary,
                Attribute@1/binary>>;

        {unknown_attribute, Template@2, Attribute@2} ->
            <<<<<<"unknown_attribute:"/utf8, Template@2/binary>>/binary,
                    ":"/utf8>>/binary,
                Attribute@2/binary>>;

        {invalid_attribute_type, Template@3, Attribute@3, Expected, Actual} ->
            <<<<<<<<<<<<<<"invalid_attribute_type:"/utf8, Template@3/binary>>/binary,
                                    ":"/utf8>>/binary,
                                Attribute@3/binary>>/binary,
                            ":expected="/utf8>>/binary,
                        (kind_label(Expected))/binary>>/binary,
                    ":actual="/utf8>>/binary,
                (kind_label(Actual))/binary>>;

        {missing_slot, Template@4, Slot} ->
            <<<<<<"missing_slot:"/utf8, Template@4/binary>>/binary, ":"/utf8>>/binary,
                Slot/binary>>;

        {duplicate_slot, Template@5, Slot@1} ->
            <<<<<<"duplicate_slot:"/utf8, Template@5/binary>>/binary, ":"/utf8>>/binary,
                Slot@1/binary>>;

        {unknown_slot, Template@6, Slot@2} ->
            <<<<<<"unknown_slot:"/utf8, Template@6/binary>>/binary, ":"/utf8>>/binary,
                Slot@2/binary>>;

        {assign_build_failed, Template@7, Reason} ->
            <<<<<<"assign_build_failed:"/utf8, Template@7/binary>>/binary,
                    ":"/utf8>>/binary,
                Reason/binary>>;

        {slot_build_failed, Template@8, Reason@1} ->
            <<<<<<"slot_build_failed:"/utf8, Template@8/binary>>/binary,
                    ":"/utf8>>/binary,
                Reason@1/binary>>
    end.

-file("src/lightspeed/component/template_compiler.gleam", 246).
?DOC(" Stable diagnostics signature.\n").
-spec diagnostics_signature(list(diagnostic())) -> binary().
diagnostics_signature(Diagnostics) ->
    Labels = gleam@list:map(Diagnostics, fun diagnostic_label/1),
    join_with(<<";"/utf8>>, Labels).

-file("src/lightspeed/component/template_compiler.gleam", 252).
?DOC(" Compiled template stable signature.\n").
-spec signature(compiled_template(any(), any())) -> binary().
signature(Compiled) ->
    erlang:element(8, Compiled).

-file("src/lightspeed/component/template_compiler.gleam", 257).
?DOC(" Compiled template rendered output.\n").
-spec rendered(compiled_template(any(), any())) -> lightspeed@component:rendered().
rendered(Compiled) ->
    erlang:element(7, Compiled).

-file("src/lightspeed/component/template_compiler.gleam", 264).
?DOC(" Compiled template HTML.\n").
-spec html(compiled_template(any(), any())) -> binary().
html(Compiled) ->
    _pipe = erlang:element(7, Compiled),
    lightspeed@component:to_html(_pipe).

-file("src/lightspeed/component/template_compiler.gleam", 270).
?DOC(" Compiled template fingerprint.\n").
-spec fingerprint(compiled_template(any(), any())) -> binary().
fingerprint(Compiled) ->
    _pipe = erlang:element(7, Compiled),
    lightspeed@component:fingerprint(_pipe).

-file("src/lightspeed/component/template_compiler.gleam", 276).
?DOC(" Find one required string attribute from normalized attrs.\n").
-spec require_string(list({binary(), attr_value()}), binary()) -> {ok, binary()} |
    {error, binary()}.
require_string(Attrs, Name) ->
    case find_attr(Attrs, Name) of
        none ->
            {error, <<"missing_attr:"/utf8, Name/binary>>};

        {some, {string_attr, Value}} ->
            {ok, Value};

        {some, Other} ->
            {error,
                <<<<<<"invalid_attr_type:"/utf8, Name/binary>>/binary,
                        ":expected=string:actual="/utf8>>/binary,
                    (kind_label(kind_of_value(Other)))/binary>>}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 294).
?DOC(" Find one required int attribute from normalized attrs.\n").
-spec require_int(list({binary(), attr_value()}), binary()) -> {ok, integer()} |
    {error, binary()}.
require_int(Attrs, Name) ->
    case find_attr(Attrs, Name) of
        none ->
            {error, <<"missing_attr:"/utf8, Name/binary>>};

        {some, {int_attr, Value}} ->
            {ok, Value};

        {some, Other} ->
            {error,
                <<<<<<"invalid_attr_type:"/utf8, Name/binary>>/binary,
                        ":expected=int:actual="/utf8>>/binary,
                    (kind_label(kind_of_value(Other)))/binary>>}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 312).
?DOC(" Find one required bool attribute from normalized attrs.\n").
-spec require_bool(list({binary(), attr_value()}), binary()) -> {ok, boolean()} |
    {error, binary()}.
require_bool(Attrs, Name) ->
    case find_attr(Attrs, Name) of
        none ->
            {error, <<"missing_attr:"/utf8, Name/binary>>};

        {some, {bool_attr, Value}} ->
            {ok, Value};

        {some, Other} ->
            {error,
                <<<<<<"invalid_attr_type:"/utf8, Name/binary>>/binary,
                        ":expected=bool:actual="/utf8>>/binary,
                    (kind_label(kind_of_value(Other)))/binary>>}
    end.

-file("src/lightspeed/component/template_compiler.gleam", 330).
?DOC(" Find optional slot by name.\n").
-spec slot_rendered(list({binary(), lightspeed@component:rendered()}), binary()) -> gleam@option:option(lightspeed@component:rendered()).
slot_rendered(Slots, Name) ->
    find_slot(Slots, Name).

-file("src/lightspeed/component/template_compiler.gleam", 338).
?DOC(" Find required slot by name with deterministic errors.\n").
-spec require_slot(list({binary(), lightspeed@component:rendered()}), binary()) -> {ok,
        lightspeed@component:rendered()} |
    {error, binary()}.
require_slot(Slots, Name) ->
    case find_slot(Slots, Name) of
        {some, Rendered} ->
            {ok, Rendered};

        none ->
            {error, <<"missing_slot:"/utf8, Name/binary>>}
    end.