Packages
caffeine_lang
1.0.1
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@common@decoders.erl
-module(caffeine_lang@common@decoders).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/common/decoders.gleam").
-export([named_reference_decoder/2, non_empty_string_decoder/0, decode_value_to_string/1, decode_list_values_to_strings/1, accepted_types_decoder/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.
-file("src/caffeine_lang/common/decoders.gleam", 15).
?DOC(
" Creates a decoder that validates a string is a valid reference to an item in a collection.\n"
" Returns the string if it matches a name in the collection, otherwise fails decoding.\n"
).
-spec named_reference_decoder(list(FSX), fun((FSX) -> binary())) -> gleam@dynamic@decode:decoder(binary()).
named_reference_decoder(Collection, Name_extraction) ->
Names = begin
_pipe = Collection,
gleam@list:map(_pipe, Name_extraction)
end,
Default = {error, <<""/utf8>>},
gleam@dynamic@decode:new_primitive_decoder(
<<"NamedReference"/utf8>>,
fun(Dyn) ->
case gleam@dynamic@decode:run(
Dyn,
{decoder, fun gleam@dynamic@decode:decode_string/1}
) of
{ok, X} ->
case begin
_pipe@1 = Names,
gleam@list:contains(_pipe@1, X)
end of
true ->
{ok, X};
false ->
Default
end;
_ ->
Default
end
end
).
-file("src/caffeine_lang/common/decoders.gleam", 36).
?DOC(" Decoder for non-empty strings. Fails if the string is empty.\n").
-spec non_empty_string_decoder() -> gleam@dynamic@decode:decoder(binary()).
non_empty_string_decoder() ->
Default = {error, <<""/utf8>>},
gleam@dynamic@decode:new_primitive_decoder(
<<"NonEmptyString"/utf8>>,
fun(Dyn) ->
case gleam@dynamic@decode:run(
Dyn,
{decoder, fun gleam@dynamic@decode:decode_string/1}
) of
{ok, <<""/utf8>>} ->
Default;
{ok, S} ->
{ok, S};
_ ->
Default
end
end
).
-file("src/caffeine_lang/common/decoders.gleam", 63).
?DOC(" Decoder that decodes a dynamic value based on an AcceptedTypes and returns its String representation.\n").
-spec decode_value_to_string(caffeine_lang@common@helpers:accepted_types()) -> gleam@dynamic@decode:decoder(binary()).
decode_value_to_string(Typ) ->
case Typ of
boolean ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_bool/1},
fun(Val) ->
gleam@dynamic@decode:success(gleam@bool:to_string(Val))
end
);
float ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_float/1},
fun(Val@1) ->
gleam@dynamic@decode:success(
gleam_stdlib:float_to_string(Val@1)
)
end
);
integer ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Val@2) ->
gleam@dynamic@decode:success(
erlang:integer_to_binary(Val@2)
)
end
);
string ->
{decoder, fun gleam@dynamic@decode:decode_string/1};
{dict, _, _} ->
gleam@dynamic@decode:failure(<<""/utf8>>, <<"Dict"/utf8>>);
{list, _} ->
gleam@dynamic@decode:failure(<<""/utf8>>, <<"List"/utf8>>);
{optional, Inner_type} ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optional(
decode_value_to_string(Inner_type)
),
fun(Maybe_val) -> case Maybe_val of
{some, Val@3} ->
gleam@dynamic@decode:success(Val@3);
none ->
gleam@dynamic@decode:success(<<""/utf8>>)
end end
);
{defaulted, Inner_type@1, Default_val} ->
gleam@dynamic@decode:then(
gleam@dynamic@decode:optional(
decode_value_to_string(Inner_type@1)
),
fun(Maybe_val@1) -> case Maybe_val@1 of
{some, Val@4} ->
gleam@dynamic@decode:success(Val@4);
none ->
gleam@dynamic@decode:success(Default_val)
end end
)
end.
-file("src/caffeine_lang/common/decoders.gleam", 102).
?DOC(" Decoder that decodes a list of dynamic values and returns a List(String).\n").
-spec decode_list_values_to_strings(
caffeine_lang@common@helpers:accepted_types()
) -> gleam@dynamic@decode:decoder(list(binary())).
decode_list_values_to_strings(Inner_type) ->
gleam@dynamic@decode:list(decode_value_to_string(Inner_type)).
-file("src/caffeine_lang/common/decoders.gleam", 185).
?DOC(
" Validates that a default value string is compatible with the given type.\n"
" For basic types, checks that the string can be parsed as that type.\n"
" For complex types (List, Dict), we accept any string since the default\n"
" is used as a literal string value in templates.\n"
).
-spec validate_default_value(
caffeine_lang@common@helpers:accepted_types(),
binary()
) -> boolean().
validate_default_value(Typ, Default_val) ->
case Typ of
boolean ->
(Default_val =:= <<"True"/utf8>>) orelse (Default_val =:= <<"False"/utf8>>);
integer ->
case gleam_stdlib:parse_int(Default_val) of
{ok, _} ->
true;
{error, _} ->
false
end;
float ->
case gleam_stdlib:parse_float(Default_val) of
{ok, _} ->
true;
{error, _} ->
false
end;
string ->
true;
{list, _} ->
true;
{dict, _, _} ->
true;
{optional, _} ->
false;
{defaulted, _, _} ->
false
end.
-file("src/caffeine_lang/common/decoders.gleam", 217).
-spec find_type_default_split_helper(binary(), binary(), integer(), integer()) -> {ok,
{binary(), binary()}} |
{error, nil}.
find_type_default_split_helper(Original, S, Index, Paren_depth) ->
case gleam_stdlib:string_pop_grapheme(S) of
{error, nil} ->
{error, nil};
{ok, {Char, Rest}} ->
case {Char, Paren_depth} of
{<<"("/utf8>>, _} ->
find_type_default_split_helper(
Original,
Rest,
Index + 1,
Paren_depth + 1
);
{<<")"/utf8>>, _} ->
find_type_default_split_helper(
Original,
Rest,
Index + 1,
Paren_depth - 1
);
{<<","/utf8>>, 0} ->
Type_str = gleam@string:slice(Original, 0, Index),
Default_val = Rest,
{ok, {Type_str, Default_val}};
{_, _} ->
find_type_default_split_helper(
Original,
Rest,
Index + 1,
Paren_depth
)
end
end.
-file("src/caffeine_lang/common/decoders.gleam", 213).
?DOC(
" Finds the split point between the type and default value in a Defaulted inner string.\n"
" For \"Integer, 10\" returns Ok(#(\"Integer\", \"10\"))\n"
" For \"List(String), hello\" returns Ok(#(\"List(String)\", \"hello\"))\n"
" Handles nested parentheses correctly.\n"
).
-spec find_type_default_split(binary()) -> {ok, {binary(), binary()}} |
{error, nil}.
find_type_default_split(Inner) ->
find_type_default_split_helper(Inner, Inner, 0, 0).
-file("src/caffeine_lang/common/decoders.gleam", 148).
?DOC(
" Parses a Defaulted type string like \"Defaulted(Integer, 10)\" into Defaulted(Integer, \"10\")\n"
" Also validates that the default value is compatible with the inner type.\n"
).
-spec parse_defaulted_type(binary()) -> {ok,
caffeine_lang@common@helpers:accepted_types()} |
{error, nil}.
parse_defaulted_type(Raw) ->
case gleam_stdlib:string_starts_with(Raw, <<"Defaulted("/utf8>>) andalso gleam_stdlib:string_ends_with(
Raw,
<<")"/utf8>>
) of
false ->
{error, nil};
true ->
Inner = begin
_pipe = Raw,
_pipe@1 = gleam@string:drop_start(_pipe, 10),
gleam@string:drop_end(_pipe@1, 1)
end,
case find_type_default_split(Inner) of
{error, nil} ->
{error, nil};
{ok, {Type_str, Default_val}} ->
Trimmed_type = gleam@string:trim(Type_str),
Trimmed_default = gleam@string:trim(Default_val),
case parse_accepted_type(Trimmed_type) of
{ok, Inner_type} ->
case validate_default_value(
Inner_type,
Trimmed_default
) of
true ->
{ok,
{defaulted, Inner_type, Trimmed_default}};
false ->
{error, nil}
end;
{error, nil} ->
{error, nil}
end
end
end.
-file("src/caffeine_lang/common/decoders.gleam", 109).
?DOC(" Parses a raw string into an AcceptedType.\n").
-spec parse_accepted_type(binary()) -> {ok,
caffeine_lang@common@helpers:accepted_types()} |
{error, nil}.
parse_accepted_type(Raw_accepted_type) ->
case Raw_accepted_type of
<<"Boolean"/utf8>> ->
{ok, boolean};
<<"Float"/utf8>> ->
{ok, float};
<<"Integer"/utf8>> ->
{ok, integer};
<<"String"/utf8>> ->
{ok, string};
<<"Dict(String, String)"/utf8>> ->
{ok, {dict, string, string}};
<<"Dict(String, Integer)"/utf8>> ->
{ok, {dict, string, integer}};
<<"Dict(String, Float)"/utf8>> ->
{ok, {dict, string, float}};
<<"Dict(String, Boolean)"/utf8>> ->
{ok, {dict, string, boolean}};
<<"List(String)"/utf8>> ->
{ok, {list, string}};
<<"List(Integer)"/utf8>> ->
{ok, {list, integer}};
<<"List(Boolean)"/utf8>> ->
{ok, {list, boolean}};
<<"List(Float)"/utf8>> ->
{ok, {list, float}};
<<"Optional(String)"/utf8>> ->
{ok, {optional, string}};
<<"Optional(Integer)"/utf8>> ->
{ok, {optional, integer}};
<<"Optional(Float)"/utf8>> ->
{ok, {optional, float}};
<<"Optional(Boolean)"/utf8>> ->
{ok, {optional, boolean}};
<<"Optional(List(String))"/utf8>> ->
{ok, {optional, {list, string}}};
<<"Optional(List(Integer))"/utf8>> ->
{ok, {optional, {list, integer}}};
<<"Optional(List(Float))"/utf8>> ->
{ok, {optional, {list, float}}};
<<"Optional(List(Boolean))"/utf8>> ->
{ok, {optional, {list, boolean}}};
<<"Optional(Dict(String, String))"/utf8>> ->
{ok, {optional, {dict, string, string}}};
<<"Optional(Dict(String, Integer))"/utf8>> ->
{ok, {optional, {dict, string, integer}}};
<<"Optional(Dict(String, Float))"/utf8>> ->
{ok, {optional, {dict, string, float}}};
<<"Optional(Dict(String, Boolean))"/utf8>> ->
{ok, {optional, {dict, string, boolean}}};
_ ->
parse_defaulted_type(Raw_accepted_type)
end.
-file("src/caffeine_lang/common/decoders.gleam", 54).
?DOC(
" Decoder for AcceptedTypes from a raw string representation.\n"
" i.e. for \"Dict(String, String)\" will return a decoder for \n"
" Ok(helpers.Dict(helpers.String, helpers.String))).\n"
" \n"
" Note that the default for the error is decode.failure(Boolean, \"AcceptedType\")\n"
" which is a bit odd, but nonetheless should do the job for now.\n"
).
-spec accepted_types_decoder() -> gleam@dynamic@decode:decoder(caffeine_lang@common@helpers:accepted_types()).
accepted_types_decoder() ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Raw_string) -> case parse_accepted_type(Raw_string) of
{ok, T} ->
gleam@dynamic@decode:success(T);
{error, nil} ->
gleam@dynamic@decode:failure(
boolean,
<<"AcceptedType"/utf8>>
)
end end
).