Current section
Files
Jump to
Current section
Files
src/gloo@validate.erl
-module(gloo@validate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gloo/validate.gleam").
-export([struct/1, field/3, required/2, max_length/1, length/1, format/1, gte/1, lte/1]).
-export_type([error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Input validation combinators. `validate.struct` collects ALL field errors\n"
" before returning — it never short-circuits.\n"
"\n"
" ```gleam\n"
" validate.struct([\n"
" validate.field(\"email\", email, [validate.format(\"^[^@]+@[^@]+$\")]),\n"
" validate.field(\"name\", name, [validate.max_length(100)]),\n"
" ])\n"
" // -> Result(List(value), List(validate.Error))\n"
" ```\n"
).
-type error() :: {field_error, binary(), binary()}.
-file("src/gloo/validate.gleam", 26).
?DOC(
" Returns Ok(values) when every field passes, Error(all_errors) otherwise.\n"
" Processes every field even after a failure — never short-circuits.\n"
).
-spec struct(list({ok, KVS} | {error, list(error())})) -> {ok, list(KVS)} |
{error, list(error())}.
struct(Fields) ->
Errors = gleam@list:flat_map(Fields, fun(R) -> case R of
{ok, _} ->
[];
{error, Errs} ->
Errs
end end),
case Errors of
[] ->
{ok, gleam@list:filter_map(Fields, fun(R@1) -> case R@1 of
{ok, V} ->
{ok, V};
{error, _} ->
{error, nil}
end end)};
_ ->
{error, Errors}
end.
-file("src/gloo/validate.gleam", 52).
?DOC(
" Validate a single field against a list of rules.\n"
" Runs every rule regardless of prior failures.\n"
).
-spec field(binary(), KWB, list(fun((KWB) -> {ok, nil} | {error, binary()}))) -> {ok,
KWB} |
{error, list(error())}.
field(Name, Value, Rules) ->
Errs = gleam@list:filter_map(Rules, fun(Rule) -> case Rule(Value) of
{ok, _} ->
{error, nil};
{error, Msg} ->
{ok, {field_error, Name, Msg}}
end end),
case Errs of
[] ->
{ok, Value};
_ ->
{error, Errs}
end.
-file("src/gloo/validate.gleam", 72).
-spec required(binary(), gleam@option:option(KWI)) -> {ok, KWI} |
{error, list(error())}.
required(Field_name, Value) ->
case Value of
{some, V} ->
{ok, V};
none ->
{error, [{field_error, Field_name, <<"is required"/utf8>>}]}
end.
-file("src/gloo/validate.gleam", 82).
-spec max_length(integer()) -> fun((binary()) -> {ok, nil} | {error, binary()}).
max_length(N) ->
fun(S) -> case string:length(S) =< N of
true ->
{ok, nil};
false ->
{error,
<<<<"must be at most "/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" characters long"/utf8>>}
end end.
-file("src/gloo/validate.gleam", 92).
-spec length(integer()) -> fun((binary()) -> {ok, nil} | {error, binary()}).
length(N) ->
fun(S) -> case string:length(S) =:= N of
true ->
{ok, nil};
false ->
{error,
<<<<"must be exactly "/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" characters long"/utf8>>}
end end.
-file("src/gloo/validate.gleam", 102).
-spec format(binary()) -> fun((binary()) -> {ok, nil} | {error, binary()}).
format(Pattern) ->
fun(S) -> case gleam@regexp:from_string(Pattern) of
{error, _} ->
{error, <<"invalid format pattern"/utf8>>};
{ok, Re} ->
case gleam@regexp:check(Re, S) of
true ->
{ok, nil};
false ->
{error, <<"has invalid format"/utf8>>}
end
end end.
-file("src/gloo/validate.gleam", 117).
-spec gte(integer()) -> fun((integer()) -> {ok, nil} | {error, binary()}).
gte(Minimum) ->
fun(V) -> case V >= Minimum of
true ->
{ok, nil};
false ->
{error,
<<"must be >= "/utf8,
(erlang:integer_to_binary(Minimum))/binary>>}
end end.
-file("src/gloo/validate.gleam", 126).
-spec lte(integer()) -> fun((integer()) -> {ok, nil} | {error, binary()}).
lte(Maximum) ->
fun(V) -> case V =< Maximum of
true ->
{ok, nil};
false ->
{error,
<<"must be <= "/utf8,
(erlang:integer_to_binary(Maximum))/binary>>}
end end.