-module(caffeine_lang@frontend@validator). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/caffeine_lang/frontend/validator.gleam"). -export([validate_blueprints_file/1, validate_expects_file/1]). -export_type([validator_error/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. -type validator_error() :: {duplicate_extendable, binary()} | {undefined_extendable, binary(), binary(), list(binary())} | {duplicate_extends_reference, binary(), binary()} | {invalid_extendable_kind, binary(), binary(), binary()} | {undefined_type_alias, binary(), binary(), list(binary())} | {duplicate_type_alias, binary()} | {circular_type_alias, binary(), list(binary())} | {invalid_dict_key_type_alias, binary(), binary(), binary()} | {extendable_overshadowing, binary(), binary(), binary()} | {extendable_type_alias_name_collision, binary()} | {invalid_refinement_value, binary(), binary(), binary()} | {invalid_percentage_bounds, binary(), binary()}. -file("src/caffeine_lang/frontend/validator.gleam", 165). -spec validate_no_duplicates_loop( list(MEE), fun((MEE) -> binary()), fun((binary()) -> validator_error()), gleam@set:set(binary()) ) -> {ok, nil} | {error, validator_error()}. validate_no_duplicates_loop(Items, Get_name, Make_error, Seen) -> case Items of [] -> {ok, nil}; [First | Rest] -> Name = Get_name(First), gleam@bool:guard( gleam@set:contains(Seen, Name), {error, Make_error(Name)}, fun() -> validate_no_duplicates_loop( Rest, Get_name, Make_error, gleam@set:insert(Seen, Name) ) end ) end. -file("src/caffeine_lang/frontend/validator.gleam", 157). ?DOC(" Validates that no two items in a list share the same name.\n"). -spec validate_no_duplicates( list(MEA), fun((MEA) -> binary()), fun((binary()) -> validator_error()) ) -> {ok, nil} | {error, validator_error()}. validate_no_duplicates(Items, Get_name, Make_error) -> validate_no_duplicates_loop(Items, Get_name, Make_error, gleam@set:new()). -file("src/caffeine_lang/frontend/validator.gleam", 190). ?DOC(" Validates that no extendable shares a name with a type alias.\n"). -spec validate_no_extendable_type_alias_collision( list(caffeine_lang@frontend@ast:extendable()), list(caffeine_lang@frontend@ast:type_alias()) ) -> {ok, nil} | {error, validator_error()}. validate_no_extendable_type_alias_collision(Extendables, Type_aliases) -> Type_alias_names = begin _pipe = Type_aliases, _pipe@1 = gleam@list:map(_pipe, fun(Ta) -> erlang:element(2, Ta) end), gleam@set:from_list(_pipe@1) end, gleam@list:try_each( Extendables, fun(Ext) -> gleam@bool:guard( gleam@set:contains(Type_alias_names, erlang:element(2, Ext)), {error, {extendable_type_alias_name_collision, erlang:element(2, Ext)}}, fun() -> {ok, nil} end ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 209). ?DOC(" Validates that all extendables in an expects file are Provides kind.\n"). -spec validate_extendables_are_provides( list(caffeine_lang@frontend@ast:extendable()) ) -> {ok, nil} | {error, validator_error()}. validate_extendables_are_provides(Extendables) -> case Extendables of [] -> {ok, nil}; [First | Rest] -> case erlang:element(3, First) of extendable_provides -> validate_extendables_are_provides(Rest); extendable_requires -> {error, {invalid_extendable_kind, erlang:element(2, First), <<"Provides"/utf8>>, <<"Requires"/utf8>>}} end end. -file("src/caffeine_lang/frontend/validator.gleam", 293). ?DOC(" Validates that all names in extends list exist as extendables.\n"). -spec validate_extends_exist(list(binary()), binary(), gleam@set:set(binary())) -> {ok, nil} | {error, validator_error()}. validate_extends_exist(Extends, Item_name, Extendable_names) -> case Extends of [] -> {ok, nil}; [First | Rest] -> gleam@bool:guard( not gleam@set:contains(Extendable_names, First), {error, {undefined_extendable, First, Item_name, gleam@set:to_list(Extendable_names)}}, fun() -> validate_extends_exist(Rest, Item_name, Extendable_names) end ) end. -file("src/caffeine_lang/frontend/validator.gleam", 322). -spec validate_no_duplicate_extends_loop( list(binary()), binary(), gleam@set:set(binary()) ) -> {ok, nil} | {error, validator_error()}. validate_no_duplicate_extends_loop(Extends, Item_name, Seen) -> case Extends of [] -> {ok, nil}; [First | Rest] -> gleam@bool:guard( gleam@set:contains(Seen, First), {error, {duplicate_extends_reference, First, Item_name}}, fun() -> validate_no_duplicate_extends_loop( Rest, Item_name, gleam@set:insert(Seen, First) ) end ) end. -file("src/caffeine_lang/frontend/validator.gleam", 315). ?DOC(" Validates that no extendable is referenced twice in the same extends list.\n"). -spec validate_no_duplicate_extends(list(binary()), binary()) -> {ok, nil} | {error, validator_error()}. validate_no_duplicate_extends(Extends, Item_name) -> validate_no_duplicate_extends_loop(Extends, Item_name, gleam@set:new()). -file("src/caffeine_lang/frontend/validator.gleam", 347). ?DOC(" Builds a map of extendable name to its field names for overshadowing checks.\n"). -spec build_extendable_field_map(list(caffeine_lang@frontend@ast:extendable())) -> gleam@dict:dict(binary(), gleam@set:set(binary())). build_extendable_field_map(Extendables) -> _pipe = Extendables, _pipe@3 = gleam@list:map( _pipe, fun(E) -> Field_names = begin _pipe@1 = erlang:element(2, erlang:element(4, E)), _pipe@2 = gleam@list:map( _pipe@1, fun(F) -> erlang:element(2, F) end ), gleam@set:from_list(_pipe@2) end, {erlang:element(2, E), Field_names} end ), maps:from_list(_pipe@3). -file("src/caffeine_lang/frontend/validator.gleam", 362). ?DOC(" Validates that an item's field sets don't overshadow fields from its extended extendables.\n"). -spec validate_no_overshadowing( binary(), list(binary()), list(gleam@set:set(binary())), gleam@dict:dict(binary(), gleam@set:set(binary())) ) -> {ok, nil} | {error, validator_error()}. validate_no_overshadowing(Item_name, Extends, Field_sets, Extendable_map) -> gleam@list:try_each( Extends, fun(Ext_name) -> case gleam_stdlib:map_get(Extendable_map, Ext_name) of {error, _} -> {ok, nil}; {ok, Ext_fields} -> gleam@list:try_each( Field_sets, fun(Item_fields) -> case begin _pipe = gleam@set:intersection( Item_fields, Ext_fields ), gleam@set:to_list(_pipe) end of [] -> {ok, nil}; [Field | _] -> {error, {extendable_overshadowing, Field, Item_name, Ext_name}} end end ) end end ). -file("src/caffeine_lang/frontend/validator.gleam", 229). ?DOC(" Validates extends references for blueprint items.\n"). -spec validate_blueprint_items_extends( list(caffeine_lang@frontend@ast:blueprint_item()), list(caffeine_lang@frontend@ast:extendable()) ) -> {ok, nil} | {error, validator_error()}. validate_blueprint_items_extends(Items, Extendables) -> Extendable_names = begin _pipe = Extendables, _pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(2, E) end), gleam@set:from_list(_pipe@1) end, Extendable_map = build_extendable_field_map(Extendables), gleam@list:try_each( Items, fun(Item) -> gleam@result:'try'( validate_extends_exist( erlang:element(3, Item), erlang:element(2, Item), Extendable_names ), fun(_) -> gleam@result:'try'( validate_no_duplicate_extends( erlang:element(3, Item), erlang:element(2, Item) ), fun(_) -> Requires_fields = begin _pipe@2 = erlang:element( 2, erlang:element(4, Item) ), _pipe@3 = gleam@list:map( _pipe@2, fun(F) -> erlang:element(2, F) end ), gleam@set:from_list(_pipe@3) end, Provides_fields = begin _pipe@4 = erlang:element( 2, erlang:element(5, Item) ), _pipe@5 = gleam@list:map( _pipe@4, fun(F@1) -> erlang:element(2, F@1) end ), gleam@set:from_list(_pipe@5) end, validate_no_overshadowing( erlang:element(2, Item), erlang:element(3, Item), [Requires_fields, Provides_fields], Extendable_map ) end ) end ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 262). ?DOC(" Validates extends references for expect items.\n"). -spec validate_expect_items_extends( list(caffeine_lang@frontend@ast:expect_item()), list(caffeine_lang@frontend@ast:extendable()) ) -> {ok, nil} | {error, validator_error()}. validate_expect_items_extends(Items, Extendables) -> Extendable_names = begin _pipe = Extendables, _pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(2, E) end), gleam@set:from_list(_pipe@1) end, Extendable_map = build_extendable_field_map(Extendables), gleam@list:try_each( Items, fun(Item) -> gleam@result:'try'( validate_extends_exist( erlang:element(3, Item), erlang:element(2, Item), Extendable_names ), fun(_) -> gleam@result:'try'( validate_no_duplicate_extends( erlang:element(3, Item), erlang:element(2, Item) ), fun(_) -> Provides_fields = begin _pipe@2 = erlang:element( 2, erlang:element(4, Item) ), _pipe@3 = gleam@list:map( _pipe@2, fun(F) -> erlang:element(2, F) end ), gleam@set:from_list(_pipe@3) end, validate_no_overshadowing( erlang:element(2, Item), erlang:element(3, Item), [Provides_fields], Extendable_map ) end ) end ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 392). ?DOC(" Builds a map of type alias name to its type for validation.\n"). -spec build_type_alias_map(list(caffeine_lang@frontend@ast:type_alias())) -> list({binary(), caffeine_lang@types:parsed_type()}). build_type_alias_map(Type_aliases) -> caffeine_lang@frontend@ast:build_type_alias_pairs(Type_aliases). -file("src/caffeine_lang/frontend/validator.gleam", 413). ?DOC( " Checks if a type contains a circular reference.\n" " Uses try_each_inner_parsed to handle the structural decomposition of compound types,\n" " with leaf-specific logic for ParsedPrimitive and ParsedTypeAliasRef.\n" ). -spec validate_type_alias_not_circular( binary(), caffeine_lang@types:parsed_type(), list({binary(), caffeine_lang@types:parsed_type()}), list(binary()) ) -> {ok, nil} | {error, validator_error()}. validate_type_alias_not_circular(Original_name, Typ, Type_alias_map, Visited) -> case Typ of {parsed_primitive, _} -> {ok, nil}; {parsed_type_alias_ref, Name} -> gleam@bool:guard( gleam@list:contains(Visited, Name), {error, {circular_type_alias, Original_name, Visited}}, fun() -> case gleam@list:key_find(Type_alias_map, Name) of {ok, Resolved} -> validate_type_alias_not_circular( Original_name, Resolved, Type_alias_map, [Name | Visited] ); {error, _} -> {ok, nil} end end ); _ -> caffeine_lang@types:try_each_inner_parsed( Typ, fun(Inner) -> validate_type_alias_not_circular( Original_name, Inner, Type_alias_map, Visited ) end ) end. -file("src/caffeine_lang/frontend/validator.gleam", 399). ?DOC(" Validates that no type alias has circular references.\n"). -spec validate_no_circular_type_aliases( list(caffeine_lang@frontend@ast:type_alias()) ) -> {ok, nil} | {error, validator_error()}. validate_no_circular_type_aliases(Type_aliases) -> Type_alias_map = build_type_alias_map(Type_aliases), gleam@list:try_each( Type_aliases, fun(Ta) -> validate_type_alias_not_circular( erlang:element(2, Ta), erlang:element(3, Ta), Type_alias_map, [erlang:element(2, Ta)] ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 613). ?DOC(" Checks if a parsed type is String-based (String primitive or String refinement).\n"). -spec is_string_based_parsed_type(caffeine_lang@types:parsed_type()) -> boolean(). is_string_based_parsed_type(Typ) -> case Typ of {parsed_primitive, string} -> true; {parsed_refinement, {one_of, {parsed_primitive, string}, _}} -> true; _ -> false end. -file("src/caffeine_lang/frontend/validator.gleam", 574). ?DOC(" Validates that a Dict key type resolves to a String-based type.\n"). -spec validate_dict_key_type( caffeine_lang@types:parsed_type(), binary(), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_dict_key_type(Key_type, Context_name, Type_alias_map) -> case Key_type of {parsed_primitive, string} -> {ok, nil}; {parsed_type_alias_ref, Alias_name} -> case gleam@list:key_find(Type_alias_map, Alias_name) of {ok, Resolved} -> gleam@bool:guard( is_string_based_parsed_type(Resolved), {ok, nil}, fun() -> {error, {invalid_dict_key_type_alias, Alias_name, caffeine_lang@types:parsed_type_to_string( Resolved ), Context_name}} end ); {error, _} -> {ok, nil} end; {parsed_refinement, {one_of, {parsed_primitive, string}, _}} -> {ok, nil}; _ -> {error, {invalid_dict_key_type_alias, <<"inline"/utf8>>, caffeine_lang@types:parsed_type_to_string(Key_type), Context_name}} end. -file("src/caffeine_lang/frontend/validator.gleam", 659). ?DOC(" Extracts the primitive type from a ParsedType, unwrapping Defaulted modifiers.\n"). -spec extract_primitive_from_parsed(caffeine_lang@types:parsed_type()) -> {ok, caffeine_lang@types:primitive_types()} | {error, nil}. extract_primitive_from_parsed(Typ) -> case Typ of {parsed_primitive, Primitive} -> {ok, Primitive}; {parsed_modifier, {defaulted, Inner, _}} -> extract_primitive_from_parsed(Inner); _ -> {error, nil} end. -file("src/caffeine_lang/frontend/validator.gleam", 668). ?DOC(" Validates that a string value is valid for the given primitive type.\n"). -spec validate_string_matches_primitive( binary(), caffeine_lang@types:primitive_types(), binary() ) -> {ok, nil} | {error, validator_error()}. validate_string_matches_primitive(Value, Primitive, Context_name) -> Is_valid = case Primitive of string -> true; {semantic_type, _} -> true; boolean -> (Value =:= <<"True"/utf8>>) orelse (Value =:= <<"False"/utf8>>); {numeric_type, integer} -> gleam@result:is_ok(gleam_stdlib:parse_int(Value)); {numeric_type, float} -> gleam@result:is_ok(gleam_stdlib:parse_float(Value)); {numeric_type, percentage} -> Raw = case gleam_stdlib:string_ends_with(Value, <<"%"/utf8>>) of true -> gleam@string:drop_end(Value, 1); false -> Value end, case gleam_stdlib:parse_float(Raw) of {ok, F} -> gleam@bool:guard( (F < +0.0) orelse (F > 100.0), (false), fun() -> true end ); {error, _} -> false end end, case Is_valid of true -> {ok, nil}; false -> case Primitive of {numeric_type, percentage} -> Raw@1 = case gleam_stdlib:string_ends_with( Value, <<"%"/utf8>> ) of true -> gleam@string:drop_end(Value, 1); false -> Value end, case gleam_stdlib:parse_float(Raw@1) of {ok, _} -> {error, {invalid_percentage_bounds, Value, Context_name}}; {error, _} -> {error, {invalid_refinement_value, Value, caffeine_lang@types:primitive_type_to_string( Primitive ), Context_name}} end; _ -> {error, {invalid_refinement_value, Value, caffeine_lang@types:primitive_type_to_string( Primitive ), Context_name}} end end. -file("src/caffeine_lang/frontend/validator.gleam", 626). ?DOC(" Validates that refinement string values match the declared primitive type.\n"). -spec validate_refinement_values( caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()), binary() ) -> {ok, nil} | {error, validator_error()}. validate_refinement_values(Refinement, Context_name) -> case Refinement of {one_of, Inner, Values} -> case extract_primitive_from_parsed(Inner) of {ok, Primitive} -> _pipe = Values, _pipe@1 = gleam@set:to_list(_pipe), gleam@list:try_each( _pipe@1, fun(Value) -> validate_string_matches_primitive( Value, Primitive, Context_name ) end ); {error, _} -> {ok, nil} end; {inclusive_range, Inner@1, Low, High} -> case extract_primitive_from_parsed(Inner@1) of {ok, Primitive@1} -> gleam@result:'try'( validate_string_matches_primitive( Low, Primitive@1, Context_name ), fun(_) -> validate_string_matches_primitive( High, Primitive@1, Context_name ) end ); {error, _} -> {ok, nil} end end. -file("src/caffeine_lang/frontend/validator.gleam", 513). ?DOC( " Validates that all ParsedTypeAliasRef in a type are defined.\n" " Uses try_each_inner_parsed to handle the structural decomposition of compound types.\n" " Adds special Dict key validation and refinement value validation.\n" ). -spec validate_type_refs( caffeine_lang@types:parsed_type(), binary(), gleam@set:set(binary()), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_type_refs(Typ, Context_name, Type_alias_names, Type_alias_map) -> case Typ of {parsed_primitive, _} -> {ok, nil}; {parsed_type_alias_ref, Name} -> gleam@bool:guard( gleam@set:contains(Type_alias_names, Name), {ok, nil}, fun() -> {error, {undefined_type_alias, Name, Context_name, gleam@set:to_list(Type_alias_names)}} end ); {parsed_collection, {dict, Key, _}} -> gleam@result:'try'( validate_dict_key_type(Key, Context_name, Type_alias_map), fun(_) -> caffeine_lang@types:try_each_inner_parsed( Typ, fun(Inner) -> validate_type_refs( Inner, Context_name, Type_alias_names, Type_alias_map ) end ) end ); {parsed_refinement, Refinement} -> gleam@result:'try'( validate_refinement_values(Refinement, Context_name), fun(_) -> caffeine_lang@types:try_each_inner_parsed( Typ, fun(Inner@1) -> validate_type_refs( Inner@1, Context_name, Type_alias_names, Type_alias_map ) end ) end ); _ -> caffeine_lang@types:try_each_inner_parsed( Typ, fun(Inner@2) -> validate_type_refs( Inner@2, Context_name, Type_alias_names, Type_alias_map ) end ) end. -file("src/caffeine_lang/frontend/validator.gleam", 452). ?DOC(" Validates type alias definitions for type refs and refinement values.\n"). -spec validate_type_aliases_type_refs( list(caffeine_lang@frontend@ast:type_alias()), gleam@set:set(binary()), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_type_aliases_type_refs(Type_aliases, Type_alias_names, Type_alias_map) -> gleam@list:try_each( Type_aliases, fun(Ta) -> validate_type_refs( erlang:element(3, Ta), erlang:element(2, Ta), Type_alias_names, Type_alias_map ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 495). ?DOC(" Validates type alias references in a list of fields.\n"). -spec validate_fields_type_refs( list(caffeine_lang@frontend@ast:field()), binary(), gleam@set:set(binary()), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_fields_type_refs( Fields, Context_name, Type_alias_names, Type_alias_map ) -> gleam@list:try_each(Fields, fun(Field) -> case erlang:element(3, Field) of {type_value, Typ} -> validate_type_refs( Typ, Context_name, Type_alias_names, Type_alias_map ); {literal_value, _} -> {ok, nil} end end). -file("src/caffeine_lang/frontend/validator.gleam", 463). ?DOC(" Validates type alias references in extendables.\n"). -spec validate_extendables_type_refs( list(caffeine_lang@frontend@ast:extendable()), gleam@set:set(binary()), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_extendables_type_refs(Extendables, Type_alias_names, Type_alias_map) -> gleam@list:try_each( Extendables, fun(Ext) -> validate_fields_type_refs( erlang:element(2, erlang:element(4, Ext)), erlang:element(2, Ext), Type_alias_names, Type_alias_map ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 479). ?DOC(" Validates type alias references in blueprint items.\n"). -spec validate_blueprint_items_type_refs( list(caffeine_lang@frontend@ast:blueprint_item()), gleam@set:set(binary()), list({binary(), caffeine_lang@types:parsed_type()}) ) -> {ok, nil} | {error, validator_error()}. validate_blueprint_items_type_refs(Items, Type_alias_names, Type_alias_map) -> gleam@list:try_each( Items, fun(Item) -> validate_fields_type_refs( erlang:element(2, erlang:element(4, Item)), erlang:element(2, Item), Type_alias_names, Type_alias_map ) end ). -file("src/caffeine_lang/frontend/validator.gleam", 736). ?DOC(" Converts a single-error Result to a list of errors (empty on Ok).\n"). -spec errors_to_list({ok, nil} | {error, validator_error()}) -> list(validator_error()). errors_to_list(Result) -> case Result of {ok, _} -> []; {error, Err} -> [Err] end. -file("src/caffeine_lang/frontend/validator.gleam", 744). ?DOC(" Collects errors from a list of independent validation results.\n"). -spec collect_errors(list({ok, nil} | {error, validator_error()})) -> list(validator_error()). collect_errors(Results) -> _pipe = Results, gleam@list:flat_map(_pipe, fun errors_to_list/1). -file("src/caffeine_lang/frontend/validator.gleam", 752). ?DOC( " Guards against accumulated errors. If errors is non-empty, returns them;\n" " otherwise continues with the provided callback.\n" ). -spec guard_errors( list(validator_error()), fun(() -> {ok, MHU} | {error, list(validator_error())}) ) -> {ok, MHU} | {error, list(validator_error())}. guard_errors(Errors, Otherwise) -> case Errors of [] -> Otherwise(); _ -> {error, Errors} end. -file("src/caffeine_lang/frontend/validator.gleam", 64). ?DOC(false). -spec validate_blueprints_file(caffeine_lang@frontend@ast:blueprints_file()) -> {ok, caffeine_lang@frontend@ast:blueprints_file()} | {error, list(validator_error())}. validate_blueprints_file(File) -> Type_aliases = erlang:element(2, File), Extendables = erlang:element(3, File), Items = begin _pipe = erlang:element(4, File), gleam@list:flat_map(_pipe, fun(Block) -> erlang:element(3, Block) end) end, Type_alias_errors = begin _pipe@1 = validate_no_duplicates( Type_aliases, fun(Ta) -> erlang:element(2, Ta) end, fun(Field@0) -> {duplicate_type_alias, Field@0} end ), _pipe@2 = gleam@result:'try'( _pipe@1, fun(_) -> validate_no_circular_type_aliases(Type_aliases) end ), errors_to_list(_pipe@2) end, Extendable_errors = collect_errors( [validate_no_duplicates( Extendables, fun(E) -> erlang:element(2, E) end, fun(Field@0) -> {duplicate_extendable, Field@0} end ), validate_no_extendable_type_alias_collision( Extendables, Type_aliases )] ), Structural_errors = lists:append(Type_alias_errors, Extendable_errors), guard_errors( Structural_errors, fun() -> Type_alias_names = begin _pipe@3 = Type_aliases, _pipe@4 = gleam@list:map( _pipe@3, fun(Ta@1) -> erlang:element(2, Ta@1) end ), gleam@set:from_list(_pipe@4) end, Type_alias_map = build_type_alias_map(Type_aliases), Type_ref_errors = collect_errors( [validate_type_aliases_type_refs( Type_aliases, Type_alias_names, Type_alias_map ), validate_extendables_type_refs( Extendables, Type_alias_names, Type_alias_map ), validate_blueprint_items_type_refs( Items, Type_alias_names, Type_alias_map )] ), Extends_errors = begin _pipe@5 = validate_blueprint_items_extends(Items, Extendables), errors_to_list(_pipe@5) end, Dependent_errors = lists:append(Type_ref_errors, Extends_errors), guard_errors(Dependent_errors, fun() -> {ok, File} end) end ). -file("src/caffeine_lang/frontend/validator.gleam", 132). ?DOC(false). -spec validate_expects_file(caffeine_lang@frontend@ast:expects_file()) -> {ok, caffeine_lang@frontend@ast:expects_file()} | {error, list(validator_error())}. validate_expects_file(File) -> Extendables = erlang:element(2, File), Items = begin _pipe = erlang:element(3, File), gleam@list:flat_map(_pipe, fun(Block) -> erlang:element(3, Block) end) end, Structural_errors = collect_errors( [validate_no_duplicates( Extendables, fun(E) -> erlang:element(2, E) end, fun(Field@0) -> {duplicate_extendable, Field@0} end ), validate_extendables_are_provides(Extendables)] ), guard_errors( Structural_errors, fun() -> Extends_errors = begin _pipe@1 = validate_expect_items_extends(Items, Extendables), errors_to_list(_pipe@1) end, guard_errors(Extends_errors, fun() -> {ok, File} end) end ).