-module(caffeine_lang@types). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/caffeine_lang/types.gleam"). -export([refinement_all_type_metas/0, structured_all_type_metas/0, modifier_all_type_metas/0, collection_all_type_metas/0, semantic_type_meta/1, numeric_type_meta/1, primitive_all_type_metas/0, completable_type_metas/0, all_type_metas/0, semantic_type_to_string/1, numeric_type_to_string/1, primitive_type_to_string/1, refinement_type_to_string/1, modifier_type_to_string/1, collection_type_to_string/1, accepted_type_to_string/1, parsed_type_to_string/1, try_each_inner_parsed/2, validate_modifier_default_value_recursive/3, validate_numeric_default_value/2, validate_primitive_default_value/2, get_numeric_type/1, validate_in_range/4, validate_refinement_default_value/3, parse_numeric_type/1, parse_refinement_compatible_primitive/1, parse_modifier_type/3, parse_refinement_type/3, parse_collection_type/2, parse_semantic_type/1, parse_primitive_type/1, parse_accepted_type/1, is_optional_or_defaulted/1, validate_numeric_value/2, validate_value/2, parse_list_default_string/1, resolve_primitive_to_string/3, resolve_to_string/4, try_each_inner/2, map_inner/2]). -export_type([accepted_types/0, parsed_type/0, primitive_types/0, numeric_types/0, semantic_string_types/0, collection_types/1, modifier_types/1, refinement_types/1, validation_error/0, type_meta/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 accepted_types() :: {primitive_type, primitive_types()} | {collection_type, collection_types(accepted_types())} | {modifier_type, modifier_types(accepted_types())} | {refinement_type, refinement_types(accepted_types())} | {record_type, gleam@dict:dict(binary(), accepted_types())}. -type parsed_type() :: {parsed_primitive, primitive_types()} | {parsed_collection, collection_types(parsed_type())} | {parsed_modifier, modifier_types(parsed_type())} | {parsed_refinement, refinement_types(parsed_type())} | {parsed_type_alias_ref, binary()} | {parsed_record, gleam@dict:dict(binary(), parsed_type())}. -type primitive_types() :: boolean | string | {numeric_type, numeric_types()} | {semantic_type, semantic_string_types()}. -type numeric_types() :: float | integer | percentage. -type semantic_string_types() :: u_r_l. -type collection_types(EKZ) :: {dict, EKZ, EKZ} | {list, EKZ}. -type modifier_types(ELA) :: {optional, ELA} | {defaulted, ELA, binary()}. -type refinement_types(ELB) :: {one_of, ELB, gleam@set:set(binary())} | {inclusive_range, ELB, binary(), binary()}. -type validation_error() :: {validation_error, binary(), binary(), list(binary())}. -type type_meta() :: {type_meta, binary(), binary(), binary(), binary()}. -file("src/caffeine_lang/types.gleam", 283). -spec refinement_type_meta(refinement_types(any())) -> type_meta(). refinement_type_meta(Typ) -> case Typ of {one_of, _, _} -> {type_meta, <<"OneOf"/utf8>>, <<"Value must be one of a finite set"/utf8>>, <<"T { x | x in { val1, val2, ... } }"/utf8>>, <<"String { x | x in { datadog, prometheus } }"/utf8>>}; {inclusive_range, _, _, _} -> {type_meta, <<"InclusiveRange"/utf8>>, <<"Value must be within a numeric range (inclusive)"/utf8>>, <<"T { x | x in ( low..high ) }"/utf8>>, <<"Integer { x | x in ( 0..100 ) }"/utf8>>} end. -file("src/caffeine_lang/types.gleam", 276). ?DOC(false). -spec refinement_all_type_metas() -> list(type_meta()). refinement_all_type_metas() -> [refinement_type_meta({one_of, nil, gleam@set:new()}), refinement_type_meta({inclusive_range, nil, <<""/utf8>>, <<""/utf8>>})]. -file("src/caffeine_lang/types.gleam", 304). ?DOC(false). -spec structured_all_type_metas() -> list(type_meta()). structured_all_type_metas() -> [{type_meta, <<"Record"/utf8>>, <<"A group of named, typed fields"/utf8>>, <<"{ field: T, ... }"/utf8>>, <<"{ numerator: String, denominator: String }"/utf8>>}]. -file("src/caffeine_lang/types.gleam", 255). -spec modifier_type_meta(modifier_types(any())) -> type_meta(). modifier_type_meta(Typ) -> case Typ of {optional, _} -> {type_meta, <<"Optional"/utf8>>, <<"A type where the value may be left unspecified"/utf8>>, <<"Optional(T)"/utf8>>, <<"Optional(String), Optional(Integer)"/utf8>>}; {defaulted, _, _} -> {type_meta, <<"Defaulted"/utf8>>, <<"A type with a default value if none is provided"/utf8>>, <<"Defaulted(T, default)"/utf8>>, <<"Defaulted(Integer, 30), Defaulted(String, \"prod\")"/utf8>>} end. -file("src/caffeine_lang/types.gleam", 251). ?DOC(false). -spec modifier_all_type_metas() -> list(type_meta()). modifier_all_type_metas() -> [modifier_type_meta({optional, nil}), modifier_type_meta({defaulted, nil, <<""/utf8>>})]. -file("src/caffeine_lang/types.gleam", 230). -spec collection_type_meta(collection_types(any())) -> type_meta(). collection_type_meta(Typ) -> case Typ of {list, _} -> {type_meta, <<"List"/utf8>>, <<"An ordered sequence where each element shares the same type"/utf8>>, <<"List(T)"/utf8>>, <<"List(String), List(Integer)"/utf8>>}; {dict, _, _} -> {type_meta, <<"Dict"/utf8>>, <<"A key-value map with typed keys and values"/utf8>>, <<"Dict(K, V)"/utf8>>, <<"Dict(String, String), Dict(String, Integer)"/utf8>>} end. -file("src/caffeine_lang/types.gleam", 226). ?DOC(false). -spec collection_all_type_metas() -> list(type_meta()). collection_all_type_metas() -> [collection_type_meta({list, nil}), collection_type_meta({dict, nil, nil})]. -file("src/caffeine_lang/types.gleam", 212). ?DOC(false). -spec semantic_type_meta(semantic_string_types()) -> type_meta(). semantic_type_meta(Typ) -> case Typ of u_r_l -> {type_meta, <<"URL"/utf8>>, <<"A valid URL starting with http:// or https://"/utf8>>, <<"URL"/utf8>>, <<"\"https://example.com\""/utf8>>} end. -file("src/caffeine_lang/types.gleam", 205). -spec semantic_all_type_metas() -> list(type_meta()). semantic_all_type_metas() -> [semantic_type_meta(u_r_l)]. -file("src/caffeine_lang/types.gleam", 179). ?DOC(false). -spec numeric_type_meta(numeric_types()) -> type_meta(). numeric_type_meta(Typ) -> case Typ of integer -> {type_meta, <<"Integer"/utf8>>, <<"Whole numbers"/utf8>>, <<"Integer"/utf8>>, <<"42, 0, -10"/utf8>>}; float -> {type_meta, <<"Float"/utf8>>, <<"Decimal numbers"/utf8>>, <<"Float"/utf8>>, <<"3.14, 99.9, 0.0"/utf8>>}; percentage -> {type_meta, <<"Percentage"/utf8>>, <<"A numeric value between 0.0 and 100.0 representing a percentage"/utf8>>, <<"Percentage"/utf8>>, <<"99.9%"/utf8>>} end. -file("src/caffeine_lang/types.gleam", 168). -spec numeric_all_type_metas() -> list(type_meta()). numeric_all_type_metas() -> [numeric_type_meta(integer), numeric_type_meta(float), numeric_type_meta(percentage)]. -file("src/caffeine_lang/types.gleam", 147). -spec primitive_type_meta(primitive_types()) -> type_meta(). primitive_type_meta(Typ) -> case Typ of boolean -> {type_meta, <<"Boolean"/utf8>>, <<"True or false"/utf8>>, <<"Boolean"/utf8>>, <<"true, false"/utf8>>}; string -> {type_meta, <<"String"/utf8>>, <<"Any text between double quotes"/utf8>>, <<"String"/utf8>>, <<"\"hello\", \"my-service\""/utf8>>}; {numeric_type, N} -> numeric_type_meta(N); {semantic_type, S} -> semantic_type_meta(S) end. -file("src/caffeine_lang/types.gleam", 139). ?DOC(false). -spec primitive_all_type_metas() -> list(type_meta()). primitive_all_type_metas() -> lists:append( [[primitive_type_meta(boolean), primitive_type_meta(string)], numeric_all_type_metas(), semantic_all_type_metas()] ). -file("src/caffeine_lang/types.gleam", 129). ?DOC(false). -spec completable_type_metas() -> list(type_meta()). completable_type_metas() -> lists:append( [primitive_all_type_metas(), collection_all_type_metas(), modifier_all_type_metas()] ). -file("src/caffeine_lang/types.gleam", 116). ?DOC(false). -spec all_type_metas() -> list(type_meta()). all_type_metas() -> lists:append( [completable_type_metas(), structured_all_type_metas(), refinement_all_type_metas()] ). -file("src/caffeine_lang/types.gleam", 409). ?DOC(" Generic refinement-to-string using a recursive formatter.\n"). -spec refinement_to_string(refinement_types(ELY), fun((ELY) -> binary())) -> binary(). refinement_to_string(Refinement, To_string) -> case Refinement of {one_of, Typ, Set_vals} -> <<<<<<(To_string(Typ))/binary, " { x | x in { "/utf8>>/binary, (begin _pipe = Set_vals, _pipe@1 = gleam@set:to_list(_pipe), _pipe@2 = gleam@list:sort( _pipe@1, fun gleam@string:compare/2 ), gleam@string:join(_pipe@2, <<", "/utf8>>) end)/binary>>/binary, " } }"/utf8>>; {inclusive_range, Typ@1, Low, High} -> <<<<<<<<<<(To_string(Typ@1))/binary, " { x | x in ( "/utf8>>/binary, Low/binary>>/binary, ".."/utf8>>/binary, High/binary>>/binary, " ) }"/utf8>> end. -file("src/caffeine_lang/types.gleam", 397). ?DOC(" Generic modifier-to-string using a recursive formatter.\n"). -spec modifier_to_string(modifier_types(ELW), fun((ELW) -> binary())) -> binary(). modifier_to_string(Modifier_type, To_string) -> case Modifier_type of {optional, Inner_type} -> <<<<"Optional("/utf8, (To_string(Inner_type))/binary>>/binary, ")"/utf8>>; {defaulted, Inner_type@1, Default_val} -> <<<<<<<<"Defaulted("/utf8, (To_string(Inner_type@1))/binary>>/binary, ", "/utf8>>/binary, Default_val/binary>>/binary, ")"/utf8>> end. -file("src/caffeine_lang/types.gleam", 385). ?DOC(" Generic collection-to-string using a recursive formatter.\n"). -spec collection_to_string(collection_types(ELU), fun((ELU) -> binary())) -> binary(). collection_to_string(Collection_type, To_string) -> case Collection_type of {dict, Key_type, Value_type} -> <<<<<<<<"Dict("/utf8, (To_string(Key_type))/binary>>/binary, ", "/utf8>>/binary, (To_string(Value_type))/binary>>/binary, ")"/utf8>>; {list, Inner_type} -> <<<<"List("/utf8, (To_string(Inner_type))/binary>>/binary, ")"/utf8>> end. -file("src/caffeine_lang/types.gleam", 354). ?DOC(" Converts a SemanticStringTypes to its string representation.\n"). -spec semantic_type_to_string(semantic_string_types()) -> binary(). semantic_type_to_string(Typ) -> case Typ of u_r_l -> <<"URL"/utf8>> end. -file("src/caffeine_lang/types.gleam", 345). ?DOC(" Converts a NumericTypes to its string representation.\n"). -spec numeric_type_to_string(numeric_types()) -> binary(). numeric_type_to_string(Numeric_type) -> case Numeric_type of float -> <<"Float"/utf8>>; integer -> <<"Integer"/utf8>>; percentage -> <<"Percentage"/utf8>> end. -file("src/caffeine_lang/types.gleam", 335). ?DOC(false). -spec primitive_type_to_string(primitive_types()) -> binary(). primitive_type_to_string(Primitive_type) -> case Primitive_type of boolean -> <<"Boolean"/utf8>>; string -> <<"String"/utf8>>; {numeric_type, Numeric_type} -> numeric_type_to_string(Numeric_type); {semantic_type, Semantic_type} -> semantic_type_to_string(Semantic_type) end. -file("src/caffeine_lang/types.gleam", 428). ?DOC(" Converts a record type to its string representation.\n"). -spec record_type_to_string(gleam@dict:dict(binary(), accepted_types())) -> binary(). record_type_to_string(Fields) -> Field_strs = begin _pipe = Fields, _pipe@1 = maps:to_list(_pipe), _pipe@2 = gleam@list:sort( _pipe@1, fun(A, B) -> gleam@string:compare(erlang:element(1, A), erlang:element(1, B)) end ), gleam@list:map( _pipe@2, fun(Pair) -> <<<<(erlang:element(1, Pair))/binary, ": "/utf8>>/binary, (accepted_type_to_string(erlang:element(2, Pair)))/binary>> end ) end, <<<<"{ "/utf8, (gleam@string:join(Field_strs, <<", "/utf8>>))/binary>>/binary, " }"/utf8>>. -file("src/caffeine_lang/types.gleam", 378). ?DOC(false). -spec refinement_type_to_string(refinement_types(accepted_types())) -> binary(). refinement_type_to_string(Refinement) -> refinement_to_string(Refinement, fun accepted_type_to_string/1). -file("src/caffeine_lang/types.gleam", 370). ?DOC(false). -spec modifier_type_to_string(modifier_types(accepted_types())) -> binary(). modifier_type_to_string(Modifier_type) -> modifier_to_string(Modifier_type, fun accepted_type_to_string/1). -file("src/caffeine_lang/types.gleam", 362). ?DOC(false). -spec collection_type_to_string(collection_types(accepted_types())) -> binary(). collection_type_to_string(Collection_type) -> collection_to_string(Collection_type, fun accepted_type_to_string/1). -file("src/caffeine_lang/types.gleam", 321). ?DOC(false). -spec accepted_type_to_string(accepted_types()) -> binary(). accepted_type_to_string(Accepted_type) -> case Accepted_type of {primitive_type, Primitive_type} -> primitive_type_to_string(Primitive_type); {collection_type, Collection_type} -> collection_type_to_string(Collection_type); {modifier_type, Modifier_type} -> modifier_type_to_string(Modifier_type); {refinement_type, Refinement_type} -> refinement_type_to_string(Refinement_type); {record_type, Fields} -> record_type_to_string(Fields) end. -file("src/caffeine_lang/types.gleam", 453). ?DOC(false). -spec parsed_type_to_string(parsed_type()) -> binary(). parsed_type_to_string(Parsed_type) -> case Parsed_type of {parsed_primitive, Primitive_type} -> primitive_type_to_string(Primitive_type); {parsed_collection, Collection_type} -> collection_to_string(Collection_type, fun parsed_type_to_string/1); {parsed_modifier, Modifier_type} -> modifier_to_string(Modifier_type, fun parsed_type_to_string/1); {parsed_refinement, Refinement_type} -> refinement_to_string(Refinement_type, fun parsed_type_to_string/1); {parsed_type_alias_ref, Name} -> Name; {parsed_record, Fields} -> parsed_record_to_string(Fields) end. -file("src/caffeine_lang/types.gleam", 438). ?DOC(" Converts a parsed record type to its string representation.\n"). -spec parsed_record_to_string(gleam@dict:dict(binary(), parsed_type())) -> binary(). parsed_record_to_string(Fields) -> Field_strs = begin _pipe = Fields, _pipe@1 = maps:to_list(_pipe), _pipe@2 = gleam@list:sort( _pipe@1, fun(A, B) -> gleam@string:compare(erlang:element(1, A), erlang:element(1, B)) end ), gleam@list:map( _pipe@2, fun(Pair) -> <<<<(erlang:element(1, Pair))/binary, ": "/utf8>>/binary, (parsed_type_to_string(erlang:element(2, Pair)))/binary>> end ) end, <<<<"{ "/utf8, (gleam@string:join(Field_strs, <<", "/utf8>>))/binary>>/binary, " }"/utf8>>. -file("src/caffeine_lang/types.gleam", 1723). -spec refinement_try_each_inner( refinement_types(ETT), fun((ETT) -> {ok, nil} | {error, ETV}) ) -> {ok, nil} | {error, ETV}. refinement_try_each_inner(Refinement, F) -> case Refinement of {one_of, Inner, _} -> F(Inner); {inclusive_range, Inner@1, _, _} -> F(Inner@1) end. -file("src/caffeine_lang/types.gleam", 1703). -spec modifier_try_each_inner( modifier_types(ETJ), fun((ETJ) -> {ok, nil} | {error, ETL}) ) -> {ok, nil} | {error, ETL}. modifier_try_each_inner(Modifier, F) -> case Modifier of {optional, Inner} -> F(Inner); {defaulted, Inner@1, _} -> F(Inner@1) end. -file("src/caffeine_lang/types.gleam", 1680). -spec collection_try_each_inner( collection_types(ESZ), fun((ESZ) -> {ok, nil} | {error, ETB}) ) -> {ok, nil} | {error, ETB}. collection_try_each_inner(Collection, F) -> case Collection of {list, Inner} -> F(Inner); {dict, Key, Value} -> gleam@result:'try'(F(Key), fun(_) -> F(Value) end) end. -file("src/caffeine_lang/types.gleam", 469). ?DOC(false). -spec try_each_inner_parsed( parsed_type(), fun((parsed_type()) -> {ok, nil} | {error, EME}) ) -> {ok, nil} | {error, EME}. try_each_inner_parsed(Typ, F) -> case Typ of {parsed_primitive, _} -> F(Typ); {parsed_type_alias_ref, _} -> F(Typ); {parsed_collection, Collection} -> collection_try_each_inner(Collection, F); {parsed_modifier, Modifier} -> modifier_try_each_inner(Modifier, F); {parsed_refinement, Refinement} -> refinement_try_each_inner(Refinement, F); {parsed_record, Fields} -> _pipe = maps:values(Fields), gleam@list:try_each(_pipe, F) end. -file("src/caffeine_lang/types.gleam", 1370). ?DOC(false). -spec validate_modifier_default_value_recursive( modifier_types(accepted_types()), binary(), fun((accepted_types(), binary()) -> {ok, nil} | {error, nil}) ) -> {ok, nil} | {error, nil}. validate_modifier_default_value_recursive(Modifier, Value, Validate_inner) -> case Modifier of {defaulted, Inner, _} -> Validate_inner(Inner, Value); {optional, _} -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 1071). -spec validate_url(binary()) -> {ok, nil} | {error, nil}. validate_url(S) -> case gleam_stdlib:string_starts_with(S, <<"http://"/utf8>>) orelse gleam_stdlib:string_starts_with( S, <<"https://"/utf8>> ) of true -> {ok, nil}; false -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 1359). -spec validate_semantic_default_value(semantic_string_types(), binary()) -> {ok, nil} | {error, nil}. validate_semantic_default_value(Typ, Default_val) -> case Typ of u_r_l -> validate_url(Default_val) end. -file("src/caffeine_lang/types.gleam", 1341). -spec parse_numeric_string(numeric_types(), binary()) -> {ok, float()} | {error, nil}. parse_numeric_string(Numeric, Value) -> case Numeric of integer -> _pipe = gleam_stdlib:parse_int(Value), gleam@result:map(_pipe, fun erlang:float/1); float -> gleam_stdlib:parse_float(Value); percentage -> Cleaned = case gleam_stdlib:string_ends_with(Value, <<"%"/utf8>>) of true -> gleam@string:drop_end(Value, 1); false -> Value end, gleam_stdlib:parse_float(Cleaned) end. -file("src/caffeine_lang/types.gleam", 1324). ?DOC(false). -spec validate_numeric_default_value(numeric_types(), binary()) -> {ok, nil} | {error, nil}. validate_numeric_default_value(Numeric, Default_val) -> case Numeric of percentage -> gleam@result:'try'( parse_numeric_string(percentage, Default_val), fun(F) -> case (F >= +0.0) andalso (F =< 100.0) of true -> {ok, nil}; false -> {error, nil} end end ); _ -> _pipe = parse_numeric_string(Numeric, Default_val), gleam@result:replace(_pipe, nil) end. -file("src/caffeine_lang/types.gleam", 1307). ?DOC(false). -spec validate_primitive_default_value(primitive_types(), binary()) -> {ok, nil} | {error, nil}. validate_primitive_default_value(Primitive, Default_val) -> case Primitive of boolean when (Default_val =:= <<"true"/utf8>>) orelse (Default_val =:= <<"false"/utf8>>) -> {ok, nil}; boolean -> {error, nil}; string -> {ok, nil}; {numeric_type, Numeric_type} -> validate_numeric_default_value(Numeric_type, Default_val); {semantic_type, Semantic_type} -> validate_semantic_default_value(Semantic_type, Default_val) end. -file("src/caffeine_lang/types.gleam", 933). -spec validate_string_literal_or_defaulted(accepted_types(), binary()) -> {ok, nil} | {error, nil}. validate_string_literal_or_defaulted(Typ, Value) -> case Typ of {primitive_type, Primitive} -> validate_primitive_default_value(Primitive, Value); {modifier_type, Modifier} -> validate_modifier_default_value_recursive( Modifier, Value, fun validate_string_literal_or_defaulted/2 ); _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 906). ?DOC( " Validates a list default like \"[200, 404]\" or \"[a, b]\" for a `List(inner)` type.\n" " The default must be bracket-delimited, and every element must be valid for the\n" " inner type per the supplied element validator.\n" ). -spec validate_list_default_value( accepted_types(), binary(), fun((accepted_types(), binary()) -> {ok, nil} | {error, nil}) ) -> {ok, nil} | {error, nil}. validate_list_default_value(Inner, Value, Validate_inner) -> Trimmed = gleam@string:trim(Value), case {gleam_stdlib:string_starts_with(Trimmed, <<"["/utf8>>), gleam_stdlib:string_ends_with(Trimmed, <<"]"/utf8>>)} of {true, true} -> Body = begin _pipe = Trimmed, _pipe@1 = gleam@string:drop_start(_pipe, 1), _pipe@2 = gleam@string:drop_end(_pipe@1, 1), gleam@string:trim(_pipe@2) end, case Body of <<""/utf8>> -> {ok, nil}; _ -> _pipe@3 = Body, _pipe@4 = gleam@string:split(_pipe@3, <<","/utf8>>), _pipe@5 = gleam@list:map(_pipe@4, fun gleam@string:trim/1), gleam@list:try_each( _pipe@5, fun(_capture) -> Validate_inner(Inner, _capture) end ) end; {_, _} -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 1665). ?DOC(false). -spec get_numeric_type(accepted_types()) -> numeric_types(). get_numeric_type(Typ) -> case Typ of {primitive_type, {numeric_type, Numeric}} -> Numeric; {primitive_type, {semantic_type, _}} -> integer; {primitive_type, string} -> integer; {primitive_type, boolean} -> integer; {collection_type, _} -> integer; {modifier_type, _} -> integer; {refinement_type, _} -> integer; {record_type, _} -> integer end. -file("src/caffeine_lang/types.gleam", 1404). ?DOC(false). -spec validate_in_range(numeric_types(), binary(), binary(), binary()) -> {ok, nil} | {error, list(validation_error())}. validate_in_range(Numeric, Value_str, Low_str, High_str) -> Type_name = numeric_type_to_string(Numeric), case {parse_numeric_string(Numeric, Value_str), parse_numeric_string(Numeric, Low_str), parse_numeric_string(Numeric, High_str)} of {{ok, Val}, {ok, Low}, {ok, High}} -> case {Val >= Low, Val =< High} of {true, true} -> {ok, nil}; {_, _} -> {error, [{validation_error, <<< {ok, nil} | {error, nil}) ) -> {ok, nil} | {error, nil}. validate_refinement_default_value(Refinement, Value, Validate_inner_default) -> case Refinement of {one_of, _, Allowed_values} -> case gleam@set:contains(Allowed_values, Value) of true -> {ok, nil}; false -> {error, nil} end; {inclusive_range, Inner, Low, High} -> gleam@result:'try'( Validate_inner_default(Inner, Value), fun(_) -> _pipe = validate_in_range( get_numeric_type(Inner), Value, Low, High ), gleam@result:replace_error(_pipe, nil) end ) end. -file("src/caffeine_lang/types.gleam", 877). -spec validate_string_literal(accepted_types(), binary()) -> {ok, nil} | {error, nil}. validate_string_literal(Typ, Value) -> case Typ of {primitive_type, Primitive} -> validate_primitive_default_value(Primitive, Value); {refinement_type, Refinement} -> validate_refinement_default_value( Refinement, Value, fun validate_string_literal/2 ); {modifier_type, Modifier} -> validate_modifier_default_value_recursive( Modifier, Value, fun validate_string_literal/2 ); {collection_type, {list, Inner}} -> validate_list_default_value( Inner, Value, fun validate_string_literal/2 ); {collection_type, _} -> {error, nil}; {record_type, _} -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 546). ?DOC(false). -spec parse_numeric_type(binary()) -> {ok, numeric_types()} | {error, nil}. parse_numeric_type(Raw) -> case Raw of <<"Float"/utf8>> -> {ok, float}; <<"Integer"/utf8>> -> {ok, integer}; <<"Percentage"/utf8>> -> {ok, percentage}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 533). ?DOC(false). -spec parse_refinement_compatible_primitive(binary()) -> {ok, primitive_types()} | {error, nil}. parse_refinement_compatible_primitive(Raw) -> case Raw of <<"String"/utf8>> -> {ok, string}; _ -> _pipe = parse_numeric_type(Raw), gleam@result:map(_pipe, fun(Field@0) -> {numeric_type, Field@0} end) end. -file("src/caffeine_lang/types.gleam", 635). -spec parse_defaulted_type( binary(), fun((binary()) -> {ok, ENZ} | {error, nil}), fun((ENZ, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, modifier_types(ENZ)} | {error, nil}. parse_defaulted_type(Raw, Parse_inner, Validate_default) -> gleam@result:'try'( case caffeine_lang@parsing_utils:paren_innerds_split_and_trimmed(Raw) of [Typ, Val] -> {ok, {Typ, Val}}; _ -> {error, nil} end, fun(_use0) -> {Raw_inner_type, Raw_default_value} = _use0, gleam@result:'try'( Parse_inner(Raw_inner_type), fun(Parsed_inner_type) -> case Validate_default(Parsed_inner_type, Raw_default_value) of {ok, _} -> {ok, {defaulted, Parsed_inner_type, Raw_default_value}}; {error, _} -> {error, nil} end end ) end ). -file("src/caffeine_lang/types.gleam", 621). -spec parse_optional_type(binary(), fun((binary()) -> {ok, ENT} | {error, nil})) -> {ok, modifier_types(ENT)} | {error, nil}. parse_optional_type(Raw, Parse_inner) -> case begin _pipe = Raw, _pipe@1 = caffeine_lang@parsing_utils:paren_innerds_trimmed(_pipe), Parse_inner(_pipe@1) end of {ok, Inner_type} -> {ok, {optional, Inner_type}}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 608). ?DOC(false). -spec parse_modifier_type( binary(), fun((binary()) -> {ok, ENL} | {error, nil}), fun((ENL, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, modifier_types(ENL)} | {error, nil}. parse_modifier_type(Raw, Parse_inner, Validate_default) -> case Raw of <<"Optional"/utf8, Rest/binary>> -> parse_optional_type(Rest, Parse_inner); <<"Defaulted"/utf8, Rest@1/binary>> -> parse_defaulted_type(Rest@1, Parse_inner, Validate_default); _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 859). ?DOC( " Parser for primitives or Defaulted modifiers - used for refinement type inner types.\n" " Only allows Integer, Float, String (not Boolean) or Defaulted with those types.\n" ). -spec parse_primitive_or_defaulted(binary()) -> {ok, accepted_types()} | {error, nil}. parse_primitive_or_defaulted(Raw) -> _pipe = parse_refinement_compatible_primitive(Raw), _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {primitive_type, Field@0} end ), gleam@result:lazy_or( _pipe@1, fun() -> _pipe@3 = parse_modifier_type( Raw, fun(Inner) -> _pipe@2 = parse_refinement_compatible_primitive(Inner), gleam@result:map( _pipe@2, fun(Field@0) -> {primitive_type, Field@0} end ) end, fun validate_string_literal/2 ), gleam@result:map( _pipe@3, fun(Field@0) -> {modifier_type, Field@0} end ) end ). -file("src/caffeine_lang/types.gleam", 824). ?DOC(" Validates that Percentage range bounds are within [0.0, 100.0].\n"). -spec validate_percentage_range_bounds(binary(), binary()) -> {ok, nil} | {error, nil}. validate_percentage_range_bounds(Low, High) -> case {gleam_stdlib:parse_float(Low), gleam_stdlib:parse_float(High)} of {{ok, L}, {ok, H}} -> case (L >= +0.0) andalso (H =< 100.0) of true -> {ok, nil}; false -> {error, nil} end; {_, _} -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 810). ?DOC(" Validates that bounds are in valid order (low <= high) for a numeric type.\n"). -spec validate_bounds_order(binary(), binary(), binary()) -> {ok, nil} | {error, nil}. validate_bounds_order(Raw_typ, Low, High) -> case parse_numeric_type(Raw_typ) of {ok, Numeric} -> _pipe = validate_in_range(Numeric, Low, Low, High), gleam@result:replace_error(_pipe, nil); {error, nil} -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 754). -spec parse_inclusive_range( EPD, binary(), binary(), fun((EPD, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, refinement_types(EPD)} | {error, nil}. parse_inclusive_range(Typ, Raw_typ, Raw, Validate_set_value) -> case Raw_typ of <<"Integer"/utf8>> -> case gleam_stdlib:string_ends_with(Raw, <<") }"/utf8>>) of true -> Low_high_vals = begin _pipe = Raw, _pipe@1 = gleam@string:drop_end(_pipe, 3), gleam@string:trim(_pipe@1) end, Values = begin _pipe@2 = Low_high_vals, _pipe@3 = gleam@string:split(_pipe@2, <<".."/utf8>>), _pipe@4 = gleam@list:map( _pipe@3, fun gleam@string:trim/1 ), gleam@list:filter( _pipe@4, fun(S) -> S /= <<""/utf8>> end ) end, case Values of [] -> {error, nil}; [Low, High] -> case gleam@list:try_each( Values, fun(_capture) -> Validate_set_value(Typ, _capture) end ) of {ok, _} -> case validate_bounds_order( Raw_typ, Low, High ) of {ok, _} -> case Raw_typ of <<"Percentage"/utf8>> -> _pipe@5 = validate_percentage_range_bounds( Low, High ), gleam@result:map( _pipe@5, fun(_) -> {inclusive_range, Typ, Low, High} end ); _ -> {ok, {inclusive_range, Typ, Low, High}} end; {error, _} -> {error, nil} end; {error, _} -> {error, nil} end; _ -> {error, nil} end; false -> {error, nil} end; <<"Float"/utf8>> -> case gleam_stdlib:string_ends_with(Raw, <<") }"/utf8>>) of true -> Low_high_vals = begin _pipe = Raw, _pipe@1 = gleam@string:drop_end(_pipe, 3), gleam@string:trim(_pipe@1) end, Values = begin _pipe@2 = Low_high_vals, _pipe@3 = gleam@string:split(_pipe@2, <<".."/utf8>>), _pipe@4 = gleam@list:map( _pipe@3, fun gleam@string:trim/1 ), gleam@list:filter( _pipe@4, fun(S) -> S /= <<""/utf8>> end ) end, case Values of [] -> {error, nil}; [Low, High] -> case gleam@list:try_each( Values, fun(_capture) -> Validate_set_value(Typ, _capture) end ) of {ok, _} -> case validate_bounds_order( Raw_typ, Low, High ) of {ok, _} -> case Raw_typ of <<"Percentage"/utf8>> -> _pipe@5 = validate_percentage_range_bounds( Low, High ), gleam@result:map( _pipe@5, fun(_) -> {inclusive_range, Typ, Low, High} end ); _ -> {ok, {inclusive_range, Typ, Low, High}} end; {error, _} -> {error, nil} end; {error, _} -> {error, nil} end; _ -> {error, nil} end; false -> {error, nil} end; <<"Percentage"/utf8>> -> case gleam_stdlib:string_ends_with(Raw, <<") }"/utf8>>) of true -> Low_high_vals = begin _pipe = Raw, _pipe@1 = gleam@string:drop_end(_pipe, 3), gleam@string:trim(_pipe@1) end, Values = begin _pipe@2 = Low_high_vals, _pipe@3 = gleam@string:split(_pipe@2, <<".."/utf8>>), _pipe@4 = gleam@list:map( _pipe@3, fun gleam@string:trim/1 ), gleam@list:filter( _pipe@4, fun(S) -> S /= <<""/utf8>> end ) end, case Values of [] -> {error, nil}; [Low, High] -> case gleam@list:try_each( Values, fun(_capture) -> Validate_set_value(Typ, _capture) end ) of {ok, _} -> case validate_bounds_order( Raw_typ, Low, High ) of {ok, _} -> case Raw_typ of <<"Percentage"/utf8>> -> _pipe@5 = validate_percentage_range_bounds( Low, High ), gleam@result:map( _pipe@5, fun(_) -> {inclusive_range, Typ, Low, High} end ); _ -> {ok, {inclusive_range, Typ, Low, High}} end; {error, _} -> {error, nil} end; {error, _} -> {error, nil} end; _ -> {error, nil} end; false -> {error, nil} end; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 713). -spec parse_one_of( EOX, binary(), fun((EOX, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, refinement_types(EOX)} | {error, nil}. parse_one_of(Typ, Raw, Validate_set_value) -> case gleam_stdlib:string_ends_with(Raw, <<"} }"/utf8>>) of true -> Set_vals = begin _pipe = Raw, _pipe@1 = gleam@string:drop_end(_pipe, 3), gleam@string:trim(_pipe@1) end, Values = begin _pipe@2 = Set_vals, _pipe@3 = gleam@string:split(_pipe@2, <<","/utf8>>), _pipe@4 = gleam@list:map(_pipe@3, fun gleam@string:trim/1), gleam@list:filter(_pipe@4, fun(S) -> S /= <<""/utf8>> end) end, case Values of [] -> {error, nil}; _ -> case gleam@list:try_each( Values, fun(_capture) -> Validate_set_value(Typ, _capture) end ) of {ok, _} -> Value_set = gleam@set:from_list(Values), case gleam@set:size(Value_set) =:= erlang:length( Values ) of true -> {ok, {one_of, Typ, Value_set}}; false -> {error, nil} end; {error, _} -> {error, nil} end end; false -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 702). ?DOC( " Normalizes the refinement guard syntax, allowing flexible spacing around symbols.\n" " Returns the normalized guard and the remaining string after it.\n" " Valid: \"x | x in\", \"x| x in\", \"x |x in\", \"x|x in\" (flexible around |)\n" " Invalid: \"xin\" (no space between words)\n" ). -spec normalize_refinement_guard(binary()) -> {ok, {binary(), binary()}} | {error, nil}. normalize_refinement_guard(Raw) -> case Raw of <<"x | x in"/utf8, Rest/binary>> -> {ok, {<<"x | x in"/utf8>>, Rest}}; <<"x| x in"/utf8, Rest@1/binary>> -> {ok, {<<"x | x in"/utf8>>, Rest@1}}; <<"x |x in"/utf8, Rest@2/binary>> -> {ok, {<<"x | x in"/utf8>>, Rest@2}}; <<"x|x in"/utf8, Rest@3/binary>> -> {ok, {<<"x | x in"/utf8>>, Rest@3}}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 674). -spec do_parse_refinement( EOP, binary(), binary(), fun((EOP, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, refinement_types(EOP)} | {error, nil}. do_parse_refinement(Typ, Raw_typ, Raw, Validate_set_value) -> Trimmed = gleam@string:trim(Raw), case normalize_refinement_guard(Trimmed) of {ok, {<<"x | x in"/utf8>>, Rest}} -> Rest_trimmed = gleam@string:trim(Rest), case Rest_trimmed of <<"{"/utf8, Values_rest/binary>> -> parse_one_of(Typ, Values_rest, Validate_set_value); <<"("/utf8, Values_rest@1/binary>> -> parse_inclusive_range( Typ, Raw_typ, Values_rest@1, Validate_set_value ); _ -> {error, nil} end; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 659). ?DOC(false). -spec parse_refinement_type( binary(), fun((binary()) -> {ok, EOH} | {error, nil}), fun((EOH, binary()) -> {ok, nil} | {error, nil}) ) -> {ok, refinement_types(EOH)} | {error, nil}. parse_refinement_type(Raw, Parse_inner, Validate_set_value) -> case begin _pipe = Raw, gleam@string:split_once(_pipe, <<"{"/utf8>>) end of {ok, {Typ, Rest}} -> Trimmed_typ = begin _pipe@1 = Typ, gleam@string:trim(_pipe@1) end, gleam@result:'try'( Parse_inner(Trimmed_typ), fun(Parsed_typ) -> do_parse_refinement( Parsed_typ, Trimmed_typ, Rest, Validate_set_value ) end ); _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 592). -spec parse_dict_type(binary(), fun((binary()) -> {ok, ENF} | {error, nil})) -> {ok, collection_types(ENF)} | {error, nil}. parse_dict_type(Inner_raw, Parse_inner) -> case begin _pipe = Inner_raw, _pipe@1 = caffeine_lang@parsing_utils:paren_innerds_split_and_trimmed( _pipe ), gleam@list:map(_pipe@1, Parse_inner) end of [{ok, Key_type}, {ok, Value_type}] -> {ok, {dict, Key_type, Value_type}}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 578). -spec parse_list_type(binary(), fun((binary()) -> {ok, EMZ} | {error, nil})) -> {ok, collection_types(EMZ)} | {error, nil}. parse_list_type(Inner_raw, Parse_inner) -> case begin _pipe = Inner_raw, _pipe@1 = caffeine_lang@parsing_utils:paren_innerds_trimmed(_pipe), Parse_inner(_pipe@1) end of {ok, Inner_type} -> {ok, {list, Inner_type}}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 567). ?DOC(false). -spec parse_collection_type( binary(), fun((binary()) -> {ok, EMT} | {error, nil}) ) -> {ok, collection_types(EMT)} | {error, nil}. parse_collection_type(Raw, Parse_inner) -> case Raw of <<"List"/utf8, Inside/binary>> -> parse_list_type(Inside, Parse_inner); <<"Dict"/utf8, Inside@1/binary>> -> parse_dict_type(Inside@1, Parse_inner); _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 557). ?DOC(false). -spec parse_semantic_type(binary()) -> {ok, semantic_string_types()} | {error, nil}. parse_semantic_type(Raw) -> case Raw of <<"URL"/utf8>> -> {ok, u_r_l}; _ -> {error, nil} end. -file("src/caffeine_lang/types.gleam", 516). ?DOC(false). -spec parse_primitive_type(binary()) -> {ok, primitive_types()} | {error, nil}. parse_primitive_type(Raw) -> case Raw of <<"Boolean"/utf8>> -> {ok, boolean}; <<"String"/utf8>> -> {ok, string}; _ -> _pipe = parse_numeric_type(Raw), _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {numeric_type, Field@0} end ), gleam@result:lazy_or( _pipe@1, fun() -> _pipe@2 = parse_semantic_type(Raw), gleam@result:map( _pipe@2, fun(Field@0) -> {semantic_type, Field@0} end ) end ) end. -file("src/caffeine_lang/types.gleam", 840). ?DOC( " Parser for primitives, collections (recursively nested), and refinements.\n" " Used as the inner parser for both collection and modifier type parsing.\n" ). -spec parse_primitive_or_collection(binary()) -> {ok, accepted_types()} | {error, nil}. parse_primitive_or_collection(Raw) -> _pipe = parse_primitive_type(Raw), _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {primitive_type, Field@0} end ), _pipe@3 = gleam@result:lazy_or( _pipe@1, fun() -> _pipe@2 = parse_collection_type( Raw, fun parse_primitive_or_collection/1 ), gleam@result:map( _pipe@2, fun(Field@0) -> {collection_type, Field@0} end ) end ), gleam@result:lazy_or( _pipe@3, fun() -> _pipe@4 = parse_refinement_type( Raw, fun parse_primitive_or_defaulted/1, fun validate_string_literal_or_defaulted/2 ), gleam@result:map( _pipe@4, fun(Field@0) -> {refinement_type, Field@0} end ) end ). -file("src/caffeine_lang/types.gleam", 489). ?DOC(false). -spec parse_accepted_type(binary()) -> {ok, accepted_types()} | {error, nil}. parse_accepted_type(Raw) -> _pipe = parse_primitive_type(Raw), _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {primitive_type, Field@0} end ), _pipe@3 = gleam@result:lazy_or( _pipe@1, fun() -> _pipe@2 = parse_collection_type( Raw, fun parse_primitive_or_collection/1 ), gleam@result:map( _pipe@2, fun(Field@0) -> {collection_type, Field@0} end ) end ), _pipe@5 = gleam@result:lazy_or( _pipe@3, fun() -> _pipe@4 = parse_modifier_type( Raw, fun parse_primitive_or_collection/1, fun validate_string_literal/2 ), gleam@result:map( _pipe@4, fun(Field@0) -> {modifier_type, Field@0} end ) end ), gleam@result:lazy_or( _pipe@5, fun() -> _pipe@6 = parse_refinement_type( Raw, fun parse_primitive_or_defaulted/1, fun validate_string_literal_or_defaulted/2 ), gleam@result:map( _pipe@6, fun(Field@0) -> {refinement_type, Field@0} end ) end ). -file("src/caffeine_lang/types.gleam", 1647). ?DOC(false). -spec is_optional_or_defaulted(accepted_types()) -> boolean(). is_optional_or_defaulted(Typ) -> case Typ of {modifier_type, {optional, _}} -> true; {modifier_type, {defaulted, _, _}} -> true; {refinement_type, {one_of, Inner, _}} -> is_optional_or_defaulted(Inner); {record_type, _} -> false; _ -> false end. -file("src/caffeine_lang/types.gleam", 1271). ?DOC( " Converts a Value to its string representation based on the expected type.\n" " Used internally for refinement validation and resolution.\n" ). -spec value_to_type_string(accepted_types(), caffeine_lang@value:value()) -> {ok, binary()} | {error, list(validation_error())}. value_to_type_string(Typ, Val) -> case {Typ, Val} of {{primitive_type, boolean}, {bool_value, true}} -> {ok, <<"true"/utf8>>}; {{primitive_type, boolean}, {bool_value, false}} -> {ok, <<"false"/utf8>>}; {{primitive_type, string}, {string_value, S}} -> {ok, S}; {{primitive_type, {numeric_type, integer}}, {int_value, I}} -> {ok, erlang:integer_to_binary(I)}; {{primitive_type, {numeric_type, float}}, {float_value, F}} -> {ok, gleam_stdlib:float_to_string(F)}; {{primitive_type, {numeric_type, percentage}}, {percentage_value, F@1}} -> {ok, gleam_stdlib:float_to_string(F@1)}; {{primitive_type, {semantic_type, _}}, {string_value, S@1}} -> {ok, S@1}; {{modifier_type, {optional, Inner}}, nil_value} -> _ = Inner, {ok, <<""/utf8>>}; {{modifier_type, {defaulted, _, Default_val}}, nil_value} -> {ok, Default_val}; {{modifier_type, {optional, Inner@1}}, _} -> value_to_type_string(Inner@1, Val); {{modifier_type, {defaulted, Inner@2, _}}, _} -> value_to_type_string(Inner@2, Val); {_, _} -> {error, [{validation_error, accepted_type_to_string(Typ), caffeine_lang@value:classify(Val), []}]} end. -file("src/caffeine_lang/types.gleam", 1230). -spec validate_refinement_value( refinement_types(accepted_types()), caffeine_lang@value:value() ) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_refinement_value(Refinement, Val) -> case Refinement of {one_of, Inner_type, Allowed_values} -> case value_to_type_string(Inner_type, Val) of {ok, Str_val} -> case gleam@set:contains(Allowed_values, Str_val) of true -> {ok, Val}; false -> {error, [{validation_error, <<"one of: "/utf8, (begin _pipe = Allowed_values, _pipe@1 = gleam@set:to_list( _pipe ), _pipe@2 = gleam@list:sort( _pipe@1, fun gleam@string:compare/2 ), gleam@string:join( _pipe@2, <<", "/utf8>> ) end)/binary>>, Str_val, []}]} end; {error, Errs} -> {error, Errs} end; {inclusive_range, Inner_type@1, Low, High} -> gleam@result:'try'( value_to_type_string(Inner_type@1, Val), fun(As_str) -> Numeric = get_numeric_type(Inner_type@1), case validate_in_range(Numeric, As_str, Low, High) of {ok, _} -> {ok, Val}; {error, Errs@1} -> {error, Errs@1} end end ) end. -file("src/caffeine_lang/types.gleam", 1043). -spec validate_semantic_value( semantic_string_types(), caffeine_lang@value:value() ) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_semantic_value(Typ, Val) -> case {Typ, Val} of {u_r_l, {string_value, Str}} -> case validate_url(Str) of {ok, nil} -> {ok, Val}; {error, nil} -> {error, [{validation_error, <<"URL (starting with http:// or https://)"/utf8>>, Str, []}]} end; {u_r_l, _} -> {error, [{validation_error, <<"String"/utf8>>, caffeine_lang@value:classify(Val), []}]} end. -file("src/caffeine_lang/types.gleam", 997). ?DOC(false). -spec validate_numeric_value(numeric_types(), caffeine_lang@value:value()) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_numeric_value(Numeric, Val) -> case {Numeric, Val} of {integer, {int_value, _}} -> {ok, Val}; {integer, _} -> {error, [{validation_error, <<"Int"/utf8>>, caffeine_lang@value:classify(Val), []}]}; {float, {float_value, _}} -> {ok, Val}; {float, _} -> {error, [{validation_error, <<"Float"/utf8>>, caffeine_lang@value:classify(Val), []}]}; {percentage, {percentage_value, F}} -> case (F >= +0.0) andalso (F =< 100.0) of true -> {ok, Val}; false -> {error, [{validation_error, <<"Percentage (0.0 <= x <= 100.0)"/utf8>>, gleam_stdlib:float_to_string(F), []}]} end; {percentage, {float_value, _}} -> {error, [{validation_error, <<"Percentage (use % suffix, e.g. 99.9%)"/utf8>>, caffeine_lang@value:classify(Val), []}]}; {percentage, _} -> {error, [{validation_error, <<"Percentage"/utf8>>, caffeine_lang@value:classify(Val), []}]} end. -file("src/caffeine_lang/types.gleam", 970). -spec validate_primitive_value(primitive_types(), caffeine_lang@value:value()) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_primitive_value(Primitive, Val) -> case {Primitive, Val} of {boolean, {bool_value, _}} -> {ok, Val}; {boolean, _} -> {error, [{validation_error, <<"Bool"/utf8>>, caffeine_lang@value:classify(Val), []}]}; {string, {string_value, _}} -> {ok, Val}; {string, _} -> {error, [{validation_error, <<"String"/utf8>>, caffeine_lang@value:classify(Val), []}]}; {{numeric_type, Numeric_type}, _} -> validate_numeric_value(Numeric_type, Val); {{semantic_type, Semantic_type}, _} -> validate_semantic_value(Semantic_type, Val) end. -file("src/caffeine_lang/types.gleam", 1146). -spec validate_record_value( gleam@dict:dict(binary(), accepted_types()), caffeine_lang@value:value() ) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_record_value(Schema, Val) -> case Val of {dict_value, Dict_val} -> Schema_keys = begin _pipe = maps:keys(Schema), gleam@set:from_list(_pipe) end, Val_keys = begin _pipe@1 = maps:keys(Dict_val), gleam@set:from_list(_pipe@1) end, Extra_keys = gleam@set:difference(Val_keys, Schema_keys), gleam@bool:guard( not gleam@set:is_empty(Extra_keys), {error, [{validation_error, <<"only fields: "/utf8, (begin _pipe@2 = Schema_keys, _pipe@3 = gleam@set:to_list(_pipe@2), _pipe@4 = gleam@list:sort( _pipe@3, fun gleam@string:compare/2 ), gleam@string:join(_pipe@4, <<", "/utf8>>) end)/binary>>, <<"unexpected field(s): "/utf8, (begin _pipe@5 = Extra_keys, _pipe@6 = gleam@set:to_list(_pipe@5), _pipe@7 = gleam@list:sort( _pipe@6, fun gleam@string:compare/2 ), gleam@string:join(_pipe@7, <<", "/utf8>>) end)/binary>>, []}]}, fun() -> _pipe@8 = Schema, _pipe@9 = maps:to_list(_pipe@8), _pipe@11 = gleam@list:try_map( _pipe@9, fun(Pair) -> {Field_name, Field_type} = Pair, case gleam_stdlib:map_get(Dict_val, Field_name) of {ok, Field_val} -> _pipe@10 = validate_value( Field_type, Field_val ), gleam@result:map_error( _pipe@10, fun(Errs) -> gleam@list:map( Errs, fun(E) -> {validation_error, erlang:element(2, E), erlang:element(3, E), [Field_name | erlang:element(4, E)]} end ) end ); {error, _} -> case is_optional_or_defaulted(Field_type) of true -> {ok, nil_value}; false -> {error, [{validation_error, accepted_type_to_string( Field_type ), <<"missing field"/utf8>>, [Field_name]}]} end end end ), gleam@result:map(_pipe@11, fun(_) -> Val end) end ); _ -> {error, [{validation_error, <<"Record"/utf8>>, caffeine_lang@value:classify(Val), []}]} end. -file("src/caffeine_lang/types.gleam", 1214). -spec validate_modifier_value( modifier_types(accepted_types()), caffeine_lang@value:value() ) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_modifier_value(Modifier, Val) -> Inner_type = case Modifier of {optional, T} -> T; {defaulted, T@1, _} -> T@1 end, case Val of nil_value -> {ok, Val}; _ -> validate_value(Inner_type, Val) end. -file("src/caffeine_lang/types.gleam", 1078). -spec validate_collection_value( collection_types(accepted_types()), caffeine_lang@value:value() ) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_collection_value(Collection, Val) -> case Collection of {dict, Key_type, Value_type} -> case Val of {dict_value, Dict_val} -> _pipe = Dict_val, _pipe@1 = maps:to_list(_pipe), _pipe@4 = gleam@list:try_map( _pipe@1, fun(Pair) -> {K, V} = Pair, gleam@result:'try'( begin _pipe@2 = validate_value( Key_type, {string_value, K} ), gleam@result:map_error( _pipe@2, fun(Errs) -> gleam@list:map( Errs, fun(E) -> {validation_error, erlang:element(2, E), erlang:element(3, E), [K | erlang:element(4, E)]} end ) end ) end, fun(_) -> _pipe@3 = validate_value(Value_type, V), gleam@result:map_error( _pipe@3, fun(Errs@1) -> gleam@list:map( Errs@1, fun(E@1) -> {validation_error, erlang:element(2, E@1), erlang:element(3, E@1), [K | erlang:element( 4, E@1 )]} end ) end ) end ) end ), gleam@result:map(_pipe@4, fun(_) -> Val end); _ -> {error, [{validation_error, <<"Dict"/utf8>>, caffeine_lang@value:classify(Val), []}]} end; {list, Inner_type} -> case Val of {list_value, List_val} -> _pipe@5 = List_val, _pipe@6 = gleam@list:index_map( _pipe@5, fun(V@1, I) -> {V@1, I} end ), _pipe@8 = gleam@list:try_map( _pipe@6, fun(Pair@1) -> {V@2, I@1} = Pair@1, _pipe@7 = validate_value(Inner_type, V@2), gleam@result:map_error( _pipe@7, fun(Errs@2) -> gleam@list:map( Errs@2, fun(E@2) -> {validation_error, erlang:element(2, E@2), erlang:element(3, E@2), [erlang:integer_to_binary(I@1) | erlang:element(4, E@2)]} end ) end ) end ), gleam@result:map(_pipe@8, fun(_) -> Val end); _ -> {error, [{validation_error, <<"List"/utf8>>, caffeine_lang@value:classify(Val), []}]} end end. -file("src/caffeine_lang/types.gleam", 957). ?DOC(false). -spec validate_value(accepted_types(), caffeine_lang@value:value()) -> {ok, caffeine_lang@value:value()} | {error, list(validation_error())}. validate_value(Accepted_type, Val) -> case Accepted_type of {primitive_type, Primitive} -> validate_primitive_value(Primitive, Val); {collection_type, Collection} -> validate_collection_value(Collection, Val); {modifier_type, Modifier} -> validate_modifier_value(Modifier, Val); {refinement_type, Refinement} -> validate_refinement_value(Refinement, Val); {record_type, Fields} -> validate_record_value(Fields, Val) end. -file("src/caffeine_lang/types.gleam", 1584). -spec resolve_refinement_to_string( refinement_types(accepted_types()), caffeine_lang@value:value(), fun((binary()) -> binary()) ) -> {ok, binary()} | {error, binary()}. resolve_refinement_to_string(Refinement, Val, Resolve_string) -> case Refinement of {one_of, Inner_type, _} -> case value_to_type_string(Inner_type, Val) of {ok, S} -> {ok, Resolve_string(S)}; {error, _} -> {error, <<"Unable to resolve OneOf refinement type value."/utf8>>} end; {inclusive_range, Inner_type@1, _, _} -> case value_to_type_string(Inner_type@1, Val) of {ok, S@1} -> {ok, Resolve_string(S@1)}; {error, _} -> {error, <<"Unable to resolve InclusiveRange refinement type value."/utf8>>} end end. -file("src/caffeine_lang/types.gleam", 1566). ?DOC(false). -spec parse_list_default_string(binary()) -> list(binary()). parse_list_default_string(Default_val) -> Trimmed = gleam@string:trim(Default_val), case {gleam_stdlib:string_starts_with(Trimmed, <<"["/utf8>>), gleam_stdlib:string_ends_with(Trimmed, <<"]"/utf8>>)} of {true, true} -> Inner = begin _pipe = Trimmed, _pipe@1 = gleam@string:drop_start(_pipe, 1), _pipe@2 = gleam@string:drop_end(_pipe@1, 1), gleam@string:trim(_pipe@2) end, case Inner of <<""/utf8>> -> []; _ -> _pipe@3 = Inner, _pipe@4 = gleam@string:split(_pipe@3, <<","/utf8>>), gleam@list:map(_pipe@4, fun gleam@string:trim/1) end; {_, _} -> [Default_val] end. -file("src/caffeine_lang/types.gleam", 1548). ?DOC( " Turns a Defaulted's stored default-string into a resolved output. Routes through\n" " resolve_list when the inner type is a List so list-typed defaults render as\n" " `IN (...)` rather than getting concatenated as one opaque string. Other types\n" " fall through to resolve_string (the historical behavior).\n" ). -spec resolve_default_value_to_string( accepted_types(), binary(), fun((binary()) -> binary()), fun((list(binary())) -> binary()) ) -> {ok, binary()} | {error, binary()}. resolve_default_value_to_string( Inner_type, Default_val, Resolve_string, Resolve_list ) -> case Inner_type of {collection_type, {list, _}} -> {ok, Resolve_list(parse_list_default_string(Default_val))}; _ -> {ok, Resolve_string(Default_val)} end. -file("src/caffeine_lang/types.gleam", 1481). -spec resolve_collection_to_string( collection_types(accepted_types()), caffeine_lang@value:value(), fun((list(binary())) -> binary()) ) -> {ok, binary()} | {error, binary()}. resolve_collection_to_string(Collection, Val, Resolve_list) -> case Collection of {dict, _, _} -> {error, <<<<"Unsupported templatized variable type: "/utf8, (collection_type_to_string(Collection))/binary>>/binary, ". Dict support is pending, open an issue if this is a desired use case."/utf8>>}; {list, Inner_type} -> case Val of {list_value, Items} -> Vals = begin _pipe = Items, gleam@list:map( _pipe, fun(Item) -> case value_to_type_string(Inner_type, Item) of {ok, S} -> S; {error, _} -> caffeine_lang@value:to_string(Item) end end ) end, {ok, Resolve_list(Vals)}; _ -> {error, <<"Failed to resolve list values for type: "/utf8, (collection_type_to_string(Collection))/binary>>} end end. -file("src/caffeine_lang/types.gleam", 1463). ?DOC(false). -spec resolve_primitive_to_string( primitive_types(), caffeine_lang@value:value(), fun((binary()) -> binary()) ) -> binary(). resolve_primitive_to_string(Primitive, Val, Resolve_string) -> Str = case {Primitive, Val} of {boolean, {bool_value, true}} -> <<"true"/utf8>>; {boolean, {bool_value, false}} -> <<"false"/utf8>>; {string, {string_value, S}} -> S; {{numeric_type, integer}, {int_value, I}} -> erlang:integer_to_binary(I); {{numeric_type, float}, {float_value, F}} -> gleam_stdlib:float_to_string(F); {{numeric_type, percentage}, {percentage_value, F@1}} -> gleam_stdlib:float_to_string(F@1); {{semantic_type, _}, {string_value, S@1}} -> S@1; {_, _} -> caffeine_lang@value:to_string(Val) end, Resolve_string(Str). -file("src/caffeine_lang/types.gleam", 1516). -spec resolve_modifier_to_string( modifier_types(accepted_types()), caffeine_lang@value:value(), fun((binary()) -> binary()), fun((list(binary())) -> binary()) ) -> {ok, binary()} | {error, binary()}. resolve_modifier_to_string(Modifier, Val, Resolve_string, Resolve_list) -> case Modifier of {optional, Inner_type} -> case Val of nil_value -> {ok, <<""/utf8>>}; _ -> resolve_to_string( Inner_type, Val, Resolve_string, Resolve_list ) end; {defaulted, Inner_type@1, Default_val} -> case Val of nil_value -> resolve_default_value_to_string( Inner_type@1, Default_val, Resolve_string, Resolve_list ); _ -> resolve_to_string( Inner_type@1, Val, Resolve_string, Resolve_list ) end end. -file("src/caffeine_lang/types.gleam", 1442). ?DOC(false). -spec resolve_to_string( accepted_types(), caffeine_lang@value:value(), fun((binary()) -> binary()), fun((list(binary())) -> binary()) ) -> {ok, binary()} | {error, binary()}. resolve_to_string(Typ, Val, Resolve_string, Resolve_list) -> case Typ of {primitive_type, Primitive} -> {ok, resolve_primitive_to_string(Primitive, Val, Resolve_string)}; {collection_type, Collection} -> resolve_collection_to_string(Collection, Val, Resolve_list); {modifier_type, Modifier} -> resolve_modifier_to_string( Modifier, Val, Resolve_string, Resolve_list ); {refinement_type, Refinement} -> resolve_refinement_to_string(Refinement, Val, Resolve_string); {record_type, _} -> {error, <<"Record types cannot be template variables"/utf8>>} end. -file("src/caffeine_lang/types.gleam", 1614). ?DOC(false). -spec try_each_inner( accepted_types(), fun((accepted_types()) -> {ok, nil} | {error, ESU}) ) -> {ok, nil} | {error, ESU}. try_each_inner(Typ, F) -> case Typ of {primitive_type, _} -> F(Typ); {collection_type, Collection} -> collection_try_each_inner(Collection, F); {modifier_type, Modifier} -> modifier_try_each_inner(Modifier, F); {refinement_type, Refinement} -> refinement_try_each_inner(Refinement, F); {record_type, Fields} -> _pipe = maps:values(Fields), gleam@list:try_each(_pipe, F) end. -file("src/caffeine_lang/types.gleam", 1733). -spec refinement_map_inner(refinement_types(EUA), fun((EUA) -> EUA)) -> refinement_types(EUA). refinement_map_inner(Refinement, F) -> case Refinement of {one_of, Inner, Values} -> {one_of, F(Inner), Values}; {inclusive_range, Inner@1, Min, Max} -> {inclusive_range, F(Inner@1), Min, Max} end. -file("src/caffeine_lang/types.gleam", 1713). -spec modifier_map_inner(modifier_types(ETQ), fun((ETQ) -> ETQ)) -> modifier_types(ETQ). modifier_map_inner(Modifier, F) -> case Modifier of {optional, Inner} -> {optional, F(Inner)}; {defaulted, Inner@1, Default} -> {defaulted, F(Inner@1), Default} end. -file("src/caffeine_lang/types.gleam", 1693). -spec collection_map_inner(collection_types(ETG), fun((ETG) -> ETG)) -> collection_types(ETG). collection_map_inner(Collection, F) -> case Collection of {list, Inner} -> {list, F(Inner)}; {dict, Key, Value} -> {dict, F(Key), F(Value)} end. -file("src/caffeine_lang/types.gleam", 1629). ?DOC(false). -spec map_inner(accepted_types(), fun((accepted_types()) -> accepted_types())) -> accepted_types(). map_inner(Typ, F) -> case Typ of {primitive_type, _} -> F(Typ); {collection_type, Collection} -> {collection_type, collection_map_inner(Collection, F)}; {modifier_type, Modifier} -> {modifier_type, modifier_map_inner(Modifier, F)}; {refinement_type, Refinement} -> {refinement_type, refinement_map_inner(Refinement, F)}; {record_type, Fields} -> {record_type, gleam@dict:map_values(Fields, fun(_, V) -> F(V) end)} end.