-module(envie@decode). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/envie/decode.gleam"). -export([string/0, int/0, float/0, bool/0, map/2, then/2, validated/2, int_range/2, float_range/2, url/0, url_with_scheme/1, web_url/0, string_prefix/1, non_empty_string/0, string_list/1, int_list/1, port/0, one_of/1]). -export_type([decoder/1]). -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 decoder(DKX) :: {decoder, fun((binary()) -> {ok, DKX} | {error, binary()})}. -file("src/envie/decode.gleam", 22). ?DOC(" Accept any string as-is.\n"). -spec string() -> decoder(binary()). string() -> {decoder, fun(S) -> {ok, S} end}. -file("src/envie/decode.gleam", 27). ?DOC(" Parse an integer.\n"). -spec int() -> decoder(integer()). int() -> {decoder, fun(S) -> _pipe = gleam_stdlib:parse_int(S), gleam@result:replace_error( _pipe, <<"Expected integer, got: "/utf8, S/binary>> ) end}. -file("src/envie/decode.gleam", 35). ?DOC(" Parse a float.\n"). -spec float() -> decoder(float()). float() -> {decoder, fun(S) -> _pipe = gleam_stdlib:parse_float(S), gleam@result:replace_error( _pipe, <<"Expected float, got: "/utf8, S/binary>> ) end}. -file("src/envie/decode.gleam", 43). ?DOC(" Parse a boolean. Accepts (case-insensitive): true/yes/1/on → True; false/no/0/off → False.\n"). -spec bool() -> decoder(boolean()). bool() -> {decoder, fun(S) -> case string:lowercase(S) of <<"true"/utf8>> -> {ok, true}; <<"yes"/utf8>> -> {ok, true}; <<"1"/utf8>> -> {ok, true}; <<"on"/utf8>> -> {ok, true}; <<"false"/utf8>> -> {ok, false}; <<"no"/utf8>> -> {ok, false}; <<"0"/utf8>> -> {ok, false}; <<"off"/utf8>> -> {ok, false}; _ -> {error, <<"Expected boolean, got: "/utf8, S/binary>>} end end}. -file("src/envie/decode.gleam", 58). ?DOC(" Transform the decoded value with a pure function.\n"). -spec map(decoder(DLC), fun((DLC) -> DLE)) -> decoder(DLE). map(Decoder, F) -> {decoder, fun(S) -> gleam@result:'try'( (erlang:element(2, Decoder))(S), fun(Value) -> {ok, F(Value)} end ) end}. -file("src/envie/decode.gleam", 66). ?DOC(" Chain a decoder with a fallible transformation.\n"). -spec then(decoder(DLG), fun((DLG) -> {ok, DLI} | {error, binary()})) -> decoder(DLI). then(Decoder, F) -> {decoder, fun(S) -> gleam@result:'try'( (erlang:element(2, Decoder))(S), fun(Value) -> F(Value) end ) end}. -file("src/envie/decode.gleam", 74). ?DOC(" Run an additional validation on the decoded value.\n"). -spec validated(decoder(DLM), fun((DLM) -> {ok, DLM} | {error, binary()})) -> decoder(DLM). validated(Decoder, Validator) -> {decoder, fun(S) -> gleam@result:'try'( (erlang:element(2, Decoder))(S), fun(Value) -> Validator(Value) end ) end}. -file("src/envie/decode.gleam", 89). ?DOC(" Parse an integer that must be within `[min, max]`.\n"). -spec int_range(integer(), integer()) -> decoder(integer()). int_range(Min, Max) -> _pipe = int(), validated(_pipe, fun(N) -> case (N >= Min) andalso (N =< Max) of true -> {ok, N}; false -> {error, <<<<<<"Must be between "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " and "/utf8>>/binary, (erlang:integer_to_binary(Max))/binary>>} end end). -file("src/envie/decode.gleam", 106). ?DOC(" Parse a float that must be within `[min, max]`.\n"). -spec float_range(float(), float()) -> decoder(float()). float_range(Min, Max) -> _pipe = float(), validated(_pipe, fun(N) -> case (N >= Min) andalso (N =< Max) of true -> {ok, N}; false -> {error, <<<<<<"Must be between "/utf8, (gleam_stdlib:float_to_string(Min))/binary>>/binary, " and "/utf8>>/binary, (gleam_stdlib:float_to_string(Max))/binary>>} end end). -file("src/envie/decode.gleam", 124). ?DOC( " Parse a valid URI. Note that this is very permissive (accepts \"localhost\", etc.).\n" " Use `url_with_scheme` or `web_url` for stricter validation.\n" ). -spec url() -> decoder(gleam@uri:uri()). url() -> _pipe = string(), then(_pipe, fun(S) -> _pipe@1 = gleam_stdlib:uri_parse(S), gleam@result:replace_error( _pipe@1, <<"Invalid URL format: "/utf8, S/binary>> ) end). -file("src/envie/decode.gleam", 133). ?DOC(" Parse a valid URI that must have one of requested schemes (e.g., [\"https\"]).\n"). -spec url_with_scheme(list(binary())) -> decoder(gleam@uri:uri()). url_with_scheme(Schemes) -> _pipe = url(), validated(_pipe, fun(U) -> case erlang:element(2, U) of {some, S} -> case gleam@list:contains(Schemes, S) of true -> {ok, U}; false -> {error, <<<<<<"Invalid scheme: "/utf8, S/binary>>/binary, ". Expected one of: "/utf8>>/binary, (gleam@string:join(Schemes, <<", "/utf8>>))/binary>>} end; none -> {error, <<"Missing URL scheme. Expected one of: "/utf8, (gleam@string:join(Schemes, <<", "/utf8>>))/binary>>} end end). -file("src/envie/decode.gleam", 158). ?DOC(" Shortcut for `url_with_scheme([\"http\", \"https\"])`.\n"). -spec web_url() -> decoder(gleam@uri:uri()). web_url() -> url_with_scheme([<<"http"/utf8>>, <<"https"/utf8>>]). -file("src/envie/decode.gleam", 163). ?DOC(" Require that the string starts with a given prefix.\n"). -spec string_prefix(binary()) -> decoder(binary()). string_prefix(Prefix) -> _pipe = string(), validated( _pipe, fun(S) -> case gleam_stdlib:string_starts_with(S, Prefix) of true -> {ok, S}; false -> {error, <<<<"Must start with \""/utf8, Prefix/binary>>/binary, "\""/utf8>>} end end ). -file("src/envie/decode.gleam", 174). ?DOC(" Require a non-empty (after trimming) string.\n"). -spec non_empty_string() -> decoder(binary()). non_empty_string() -> _pipe = string(), validated(_pipe, fun(S) -> case gleam@string:trim(S) of <<""/utf8>> -> {error, <<"Must not be empty"/utf8>>}; Trimmed -> {ok, Trimmed} end end). -file("src/envie/decode.gleam", 185). ?DOC(" Split a string by a separator into a list of trimmed, non-empty strings.\n"). -spec string_list(binary()) -> decoder(list(binary())). string_list(Separator) -> _pipe = string(), map(_pipe, fun(S) -> _pipe@1 = S, _pipe@2 = gleam@string:split(_pipe@1, Separator), _pipe@3 = gleam@list:map(_pipe@2, fun gleam@string:trim/1), gleam@list:filter(_pipe@3, fun(X) -> X /= <<""/utf8>> end) end). -file("src/envie/decode.gleam", 196). ?DOC(" Split a string by a separator and parse each element as an integer.\n"). -spec int_list(binary()) -> decoder(list(integer())). int_list(Separator) -> _pipe = string_list(Separator), then(_pipe, fun(Strings) -> _pipe@1 = Strings, gleam@list:try_map( _pipe@1, fun(S) -> _pipe@2 = gleam_stdlib:parse_int(S), gleam@result:replace_error( _pipe@2, <<"Invalid integer in list: "/utf8, S/binary>> ) end ) end). -file("src/envie/decode.gleam", 208). ?DOC(" Parse a TCP/UDP port number (1–65 535).\n"). -spec port() -> decoder(integer()). port() -> int_range(1, 65535). -file("src/envie/decode.gleam", 213). ?DOC(" Accept only values that appear in `allowed` (case-sensitive).\n"). -spec one_of(list(binary())) -> decoder(binary()). one_of(Allowed) -> {decoder, fun(S) -> case gleam@list:contains(Allowed, S) of true -> {ok, S}; false -> {error, <<<<<<"Must be one of: "/utf8, (gleam@string:join(Allowed, <<", "/utf8>>))/binary>>/binary, "; got: "/utf8>>/binary, S/binary>>} end end}.