Current section

Files

Jump to
caffeine_lang src caffeine_lang@types.erl
Raw

src/caffeine_lang@types.erl

-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(FIT) :: {dict, FIT, FIT} | {list, FIT}.
-type modifier_types(FIU) :: {optional, FIU} | {defaulted, FIU, binary()}.
-type refinement_types(FIV) :: {one_of, FIV, gleam@set:set(binary())} |
{inclusive_range, FIV, 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", 277).
-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", 270).
?DOC(" Returns type metadata for all refinement types.\n").
-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", 297).
?DOC(" Returns type metadata for structured types (Record).\n").
-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", 250).
-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", 246).
?DOC(" Returns type metadata for all modifier types.\n").
-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", 226).
-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", 222).
?DOC(" Returns type metadata for all collection types.\n").
-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", 209).
?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", 202).
-spec semantic_all_type_metas() -> list(type_meta()).
semantic_all_type_metas() ->
[semantic_type_meta(u_r_l)].
-file("src/caffeine_lang/types.gleam", 176).
?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", 165).
-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", 144).
-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", 136).
?DOC(" Returns type metadata for all primitive types.\n").
-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", 127).
?DOC(
" Returns type metadata for types that can be used directly in type position.\n"
" Excludes refinement types (OneOf, InclusiveRange) since those are syntactic\n"
" modifiers applied to other types (e.g. `String { x | x in { a, b } }`),\n"
" not standalone type names a user would type.\n"
).
-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", 115).
?DOC(
" Returns all type metadata across all type categories.\n"
" Includes refinement types (OneOf, InclusiveRange) which are not standalone\n"
" types but are useful for documentation (hover, CLI `types` command).\n"
).
-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", 404).
?DOC(" Generic refinement-to-string using a recursive formatter.\n").
-spec refinement_to_string(refinement_types(FJS), fun((FJS) -> 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", 392).
?DOC(" Generic modifier-to-string using a recursive formatter.\n").
-spec modifier_to_string(modifier_types(FJQ), fun((FJQ) -> 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", 380).
?DOC(" Generic collection-to-string using a recursive formatter.\n").
-spec collection_to_string(collection_types(FJO), fun((FJO) -> 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", 349).
?DOC(false).
-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", 339).
?DOC(false).
-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", 328).
?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", 423).
?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", 373).
?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", 365).
?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", 357).
?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", 314).
?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", 448).
?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", 433).
?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", 1724).
-spec refinement_try_each_inner(
refinement_types(FRN),
fun((FRN) -> {ok, nil} | {error, FRP})
) -> {ok, nil} | {error, FRP}.
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", 1704).
-spec modifier_try_each_inner(
modifier_types(FRD),
fun((FRD) -> {ok, nil} | {error, FRF})
) -> {ok, nil} | {error, FRF}.
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", 1681).
-spec collection_try_each_inner(
collection_types(FQT),
fun((FQT) -> {ok, nil} | {error, FQV})
) -> {ok, nil} | {error, FQV}.
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", 464).
?DOC(false).
-spec try_each_inner_parsed(
parsed_type(),
fun((parsed_type()) -> {ok, nil} | {error, FJY})
) -> {ok, nil} | {error, FJY}.
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", 1371).
?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", 1072).
-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", 1360).
-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", 1342).
-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", 1325).
?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", 1308).
?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", 928).
-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", 901).
?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", 1666).
?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", 1405).
?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,
<<<<Low_str/binary, " <= x <= "/utf8>>/binary,
High_str/binary>>,
Value_str,
[]}]}
end;
{_, _, _} ->
{error, [{validation_error, Type_name, Value_str, []}]}
end.
-file("src/caffeine_lang/types.gleam", 1384).
?DOC(false).
-spec validate_refinement_default_value(
refinement_types(accepted_types()),
binary(),
fun((accepted_types(), binary()) -> {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", 872).
-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", 541).
?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", 528).
?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", 630).
-spec parse_defaulted_type(
binary(),
fun((binary()) -> {ok, FLT} | {error, nil}),
fun((FLT, binary()) -> {ok, nil} | {error, nil})
) -> {ok, modifier_types(FLT)} | {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", 616).
-spec parse_optional_type(binary(), fun((binary()) -> {ok, FLN} | {error, nil})) -> {ok,
modifier_types(FLN)} |
{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", 603).
?DOC(false).
-spec parse_modifier_type(
binary(),
fun((binary()) -> {ok, FLF} | {error, nil}),
fun((FLF, binary()) -> {ok, nil} | {error, nil})
) -> {ok, modifier_types(FLF)} | {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", 854).
?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", 819).
?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", 805).
?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", 749).
-spec parse_inclusive_range(
FMX,
binary(),
binary(),
fun((FMX, binary()) -> {ok, nil} | {error, nil})
) -> {ok, refinement_types(FMX)} | {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", 708).
-spec parse_one_of(
FMR,
binary(),
fun((FMR, binary()) -> {ok, nil} | {error, nil})
) -> {ok, refinement_types(FMR)} | {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", 697).
?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", 669).
-spec do_parse_refinement(
FMJ,
binary(),
binary(),
fun((FMJ, binary()) -> {ok, nil} | {error, nil})
) -> {ok, refinement_types(FMJ)} | {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", 654).
?DOC(false).
-spec parse_refinement_type(
binary(),
fun((binary()) -> {ok, FMB} | {error, nil}),
fun((FMB, binary()) -> {ok, nil} | {error, nil})
) -> {ok, refinement_types(FMB)} | {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", 587).
-spec parse_dict_type(binary(), fun((binary()) -> {ok, FKZ} | {error, nil})) -> {ok,
collection_types(FKZ)} |
{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", 573).
-spec parse_list_type(binary(), fun((binary()) -> {ok, FKT} | {error, nil})) -> {ok,
collection_types(FKT)} |
{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", 562).
?DOC(false).
-spec parse_collection_type(
binary(),
fun((binary()) -> {ok, FKN} | {error, nil})
) -> {ok, collection_types(FKN)} | {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", 552).
?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", 511).
?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", 835).
?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", 484).
?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", 1648).
?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", 1272).
?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", 1231).
-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", 1044).
-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", 998).
?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", 965).
-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, {external_indicator_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", 1147).
-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", 1215).
-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", 1079).
-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", 952).
?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", 1585).
-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", 1567).
?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", 1549).
?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", 1482).
-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", 1464).
?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", 1517).
-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", 1443).
?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", 1615).
?DOC(false).
-spec try_each_inner(
accepted_types(),
fun((accepted_types()) -> {ok, nil} | {error, FQO})
) -> {ok, nil} | {error, FQO}.
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", 1734).
-spec refinement_map_inner(refinement_types(FRU), fun((FRU) -> FRU)) -> refinement_types(FRU).
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", 1714).
-spec modifier_map_inner(modifier_types(FRK), fun((FRK) -> FRK)) -> modifier_types(FRK).
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", 1694).
-spec collection_map_inner(collection_types(FRA), fun((FRA) -> FRA)) -> collection_types(FRA).
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", 1630).
?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.