Packages
oaspec
0.58.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.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.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec@internal@codegen@guards.erl
-module(oaspec@internal@codegen@guards).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/internal/codegen/guards.gleam").
-export([schema_has_validator/2, build_module/1, generate/1]).
-export_type([guard_function_kind/0, guard_function/0, guard_module/0, constraint_types/0, range_bound/0, range_guard_spec/0, guard_call_kind/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(false).
-type guard_function_kind() :: field_validator |
{delegating_field_validator, binary()} |
composite_validator.
-type guard_function() :: {guard_function,
binary(),
list(binary()),
binary(),
binary(),
binary(),
guard_function_kind()}.
-type guard_module() :: {guard_module, list(binary()), list(guard_function())}.
-type constraint_types() :: {constraint_types,
boolean(),
boolean(),
boolean(),
boolean(),
boolean(),
boolean(),
boolean()}.
-type range_bound() :: {range_bound, binary(), binary(), binary(), binary()}.
-type range_guard_spec() :: {range_guard_spec,
binary(),
binary(),
binary(),
binary(),
list(binary()),
binary(),
gleam@option:option(range_bound()),
gleam@option:option(range_bound())}.
-type guard_call_kind() :: direct | composite | composite_list.
-file("src/oaspec/internal/codegen/guards.gleam", 225).
?DOC(false).
-spec render_guard_function(gleam@string_tree:string_tree(), guard_function()) -> gleam@string_tree:string_tree().
render_guard_function(Sb, Function) ->
Sb@2 = gleam@list:fold(
erlang:element(3, Function),
Sb,
fun(Sb@1, Doc) -> _pipe = Sb@1,
oaspec@internal@util@string_extra:line(
_pipe,
<<"/// "/utf8, Doc/binary>>
) end
),
Sb@3 = begin
_pipe@1 = Sb@2,
oaspec@internal@util@string_extra:line(
_pipe@1,
<<<<<<<<<<<<"pub fn "/utf8, (erlang:element(2, Function))/binary>>/binary,
"("/utf8>>/binary,
(erlang:element(4, Function))/binary>>/binary,
") -> "/utf8>>/binary,
(erlang:element(5, Function))/binary>>/binary,
" {"/utf8>>
)
end,
Sb@5 = begin
_pipe@2 = erlang:element(6, Function),
_pipe@3 = gleam@string:split(_pipe@2, <<"\n"/utf8>>),
gleam@list:fold(_pipe@3, Sb@3, fun(Sb@4, Line) -> _pipe@4 = Sb@4,
oaspec@internal@util@string_extra:line(_pipe@4, Line) end)
end,
_pipe@5 = Sb@5,
_pipe@6 = oaspec@internal@util@string_extra:line(_pipe@5, <<"}"/utf8>>),
oaspec@internal@util@string_extra:blank_line(_pipe@6).
-file("src/oaspec/internal/codegen/guards.gleam", 285).
?DOC(false).
-spec dedupe_key(guard_function()) -> binary().
dedupe_key(Function) ->
<<<<<<<<(erlang:element(4, Function))/binary, "->"/utf8>>/binary,
(erlang:element(5, Function))/binary>>/binary,
"{\n"/utf8>>/binary,
(erlang:element(6, Function))/binary>>.
-file("src/oaspec/internal/codegen/guards.gleam", 289).
?DOC(false).
-spec emit_guard_delegator(guard_function(), binary()) -> guard_function().
emit_guard_delegator(Function, Canonical_name) ->
{guard_function,
erlang:element(2, Function),
erlang:element(3, Function),
erlang:element(4, Function),
erlang:element(5, Function),
<<<<" "/utf8, Canonical_name/binary>>/binary, "(value)"/utf8>>,
{delegating_field_validator, Canonical_name}}.
-file("src/oaspec/internal/codegen/guards.gleam", 251).
?DOC(false).
-spec dedupe_guard_functions(list(guard_function())) -> list(guard_function()).
dedupe_guard_functions(Functions) ->
Canonical_by_key = gleam@list:fold(
Functions,
maps:new(),
fun(Acc, Function) -> case erlang:element(7, Function) of
field_validator ->
case gleam_stdlib:map_get(Acc, dedupe_key(Function)) of
{error, nil} ->
gleam@dict:insert(
Acc,
dedupe_key(Function),
erlang:element(2, Function)
);
{ok, Existing} ->
case gleam@string:compare(
erlang:element(2, Function),
Existing
) of
lt ->
gleam@dict:insert(
Acc,
dedupe_key(Function),
erlang:element(2, Function)
);
_ ->
Acc
end
end;
_ ->
Acc
end end
),
gleam@list:map(
Functions,
fun(Function@1) -> case erlang:element(7, Function@1) of
field_validator ->
case gleam_stdlib:map_get(
Canonical_by_key,
dedupe_key(Function@1)
) of
{ok, Canonical_name} ->
case Canonical_name =:= erlang:element(
2,
Function@1
) of
true ->
Function@1;
false ->
emit_guard_delegator(
Function@1,
Canonical_name
)
end;
{error, nil} ->
Function@1
end;
_ ->
Function@1
end end
).
-file("src/oaspec/internal/codegen/guards.gleam", 506).
?DOC(false).
-spec maybe_one(gleam@option:option(JUD)) -> list(JUD).
maybe_one(Value) ->
case Value of
{some, V} ->
[V];
none ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 643).
?DOC(false).
-spec guard_function_name(binary(), binary(), binary()) -> binary().
guard_function_name(Schema_name, Prop_name, Constraint) ->
Base = oaspec@internal@util@naming:to_snake_case(Schema_name),
case Prop_name of
<<""/utf8>> ->
<<<<<<"validate_"/utf8, Base/binary>>/binary, "_"/utf8>>/binary,
Constraint/binary>>;
_ ->
<<<<<<<<<<"validate_"/utf8, Base/binary>>/binary, "_"/utf8>>/binary,
(oaspec@internal@util@naming:to_snake_case(Prop_name))/binary>>/binary,
"_"/utf8>>/binary,
Constraint/binary>>
end.
-file("src/oaspec/internal/codegen/guards.gleam", 662).
?DOC(false).
-spec field_label(binary()) -> binary().
field_label(Prop_name) ->
case Prop_name of
<<""/utf8>> ->
<<""/utf8>>;
_ ->
<<"."/utf8, Prop_name/binary>>
end.
-file("src/oaspec/internal/codegen/guards.gleam", 670).
?DOC(false).
-spec gleam_string_literal(binary()) -> binary().
gleam_string_literal(Value) ->
Escaped = begin
_pipe = Value,
_pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"\""/utf8>>, <<"\\\""/utf8>>),
_pipe@3 = gleam@string:replace(_pipe@2, <<"\n"/utf8>>, <<"\\n"/utf8>>),
_pipe@4 = gleam@string:replace(_pipe@3, <<"\r"/utf8>>, <<"\\r"/utf8>>),
gleam@string:replace(_pipe@4, <<"\t"/utf8>>, <<"\\t"/utf8>>)
end,
<<<<"\""/utf8, Escaped/binary>>/binary, "\""/utf8>>.
-file("src/oaspec/internal/codegen/guards.gleam", 685).
?DOC(false).
-spec emit_validation_failure_type(gleam@string_tree:string_tree()) -> gleam@string_tree:string_tree().
emit_validation_failure_type(Sb) ->
_pipe = Sb,
_pipe@1 = oaspec@internal@util@string_extra:doc_comment(
_pipe,
<<"A single field-level validation failure."/utf8>>
),
_pipe@2 = oaspec@internal@util@string_extra:doc_comment(
_pipe@1,
<<"Composite validators return `List(ValidationFailure)` so callers can build structured 422 bodies and clients can branch per-field instead of parsing prose messages. `field` is the JSON property name (empty for top-level constraints), `code` is a JSON Schema keyword like `minLength` / `maximum` / `pattern`, and `message` is human-readable."/utf8>>
),
_pipe@3 = oaspec@internal@util@string_extra:line(
_pipe@2,
<<"pub type ValidationFailure {"/utf8>>
),
_pipe@4 = oaspec@internal@util@string_extra:indent(
_pipe@3,
1,
<<"ValidationFailure(field: String, code: String, message: String)"/utf8>>
),
_pipe@5 = oaspec@internal@util@string_extra:line(_pipe@4, <<"}"/utf8>>),
_pipe@6 = oaspec@internal@util@string_extra:blank_line(_pipe@5),
_pipe@7 = oaspec@internal@util@string_extra:doc_comment(
_pipe@6,
<<"Encode a `ValidationFailure` as JSON for emitting 422 response bodies."/utf8>>
),
_pipe@8 = oaspec@internal@util@string_extra:line(
_pipe@7,
<<"pub fn validation_failure_to_json(failure: ValidationFailure) -> json.Json {"/utf8>>
),
_pipe@9 = oaspec@internal@util@string_extra:indent(
_pipe@8,
1,
<<"json.object(["/utf8>>
),
_pipe@10 = oaspec@internal@util@string_extra:indent(
_pipe@9,
2,
<<"#(\"field\", json.string(failure.field)),"/utf8>>
),
_pipe@11 = oaspec@internal@util@string_extra:indent(
_pipe@10,
2,
<<"#(\"code\", json.string(failure.code)),"/utf8>>
),
_pipe@12 = oaspec@internal@util@string_extra:indent(
_pipe@11,
2,
<<"#(\"message\", json.string(failure.message)),"/utf8>>
),
_pipe@13 = oaspec@internal@util@string_extra:indent(
_pipe@12,
1,
<<"])"/utf8>>
),
_pipe@14 = oaspec@internal@util@string_extra:line(_pipe@13, <<"}"/utf8>>),
oaspec@internal@util@string_extra:blank_line(_pipe@14).
-file("src/oaspec/internal/codegen/guards.gleam", 215).
?DOC(false).
-spec render_module(guard_module()) -> binary().
render_module(Module) ->
Sb = begin
_pipe = oaspec@internal@util@string_extra:file_header(<<"0.58.0"/utf8>>),
_pipe@1 = oaspec@internal@util@string_extra:imports(
_pipe,
erlang:element(2, Module)
),
emit_validation_failure_type(_pipe@1)
end,
_pipe@2 = gleam@list:fold(
erlang:element(3, Module),
Sb,
fun render_guard_function/2
),
oaspec@internal@util@string_extra:to_string(_pipe@2).
-file("src/oaspec/internal/codegen/guards.gleam", 715).
?DOC(false).
-spec validation_failure_literal(binary(), binary(), binary()) -> binary().
validation_failure_literal(Field, Code, Message) ->
<<<<<<<<<<<<"Error(ValidationFailure(field: "/utf8,
(gleam_string_literal(Field))/binary>>/binary,
", code: "/utf8>>/binary,
(gleam_string_literal(Code))/binary>>/binary,
", message: "/utf8>>/binary,
(gleam_string_literal(Message))/binary>>/binary,
"))"/utf8>>.
-file("src/oaspec/internal/codegen/guards.gleam", 733).
?DOC(false).
-spec validation_failure_dynamic(binary(), binary(), binary()) -> binary().
validation_failure_dynamic(Field, Code, Message_expr) ->
<<<<<<<<<<<<"Error(ValidationFailure(field: "/utf8,
(gleam_string_literal(Field))/binary>>/binary,
", code: "/utf8>>/binary,
(gleam_string_literal(Code))/binary>>/binary,
", message: "/utf8>>/binary,
Message_expr/binary>>/binary,
"))"/utf8>>.
-file("src/oaspec/internal/codegen/guards.gleam", 848).
?DOC(false).
-spec build_string_pattern_guard_function(
binary(),
binary(),
gleam@option:option(binary())
) -> gleam@option:option(guard_function()).
build_string_pattern_guard_function(Schema_name, Prop_name, Pattern) ->
case Pattern of
none ->
none;
{some, Pattern@1} ->
Fn_name = guard_function_name(
Schema_name,
Prop_name,
<<"pattern"/utf8>>
),
Pattern_literal = gleam_string_literal(Pattern@1),
Invalid_pattern_prefix = gleam_string_literal(
<<<<"invalid pattern: "/utf8, Pattern@1/binary>>/binary,
": "/utf8>>
),
Mismatch_failure = validation_failure_literal(
Prop_name,
<<"pattern"/utf8>>,
<<"must match pattern: "/utf8, Pattern@1/binary>>
),
Invalid_pattern_failure = validation_failure_dynamic(
Prop_name,
<<"invalidPattern"/utf8>>,
<<Invalid_pattern_prefix/binary, " <> error"/utf8>>
),
{some,
{guard_function,
Fn_name,
[<<<<<<"Validate string pattern for "/utf8,
Schema_name/binary>>/binary,
(field_label(Prop_name))/binary>>/binary,
"."/utf8>>],
<<"value: String"/utf8>>,
<<"Result(String, ValidationFailure)"/utf8>>,
gleam@string:join(
[<<<<" case regexp.from_string("/utf8,
Pattern_literal/binary>>/binary,
") {"/utf8>>,
<<" Ok(re) -> case regexp.check(re, value) {"/utf8>>,
<<" True -> Ok(value)"/utf8>>,
<<" False -> "/utf8, Mismatch_failure/binary>>,
<<" }"/utf8>>,
<<" Error(regexp.CompileError(error:, ..)) -> "/utf8,
Invalid_pattern_failure/binary>>,
<<" }"/utf8>>],
<<"\n"/utf8>>
),
field_validator}}
end.
-file("src/oaspec/internal/codegen/guards.gleam", 901).
?DOC(false).
-spec character_word(integer()) -> binary().
character_word(N) ->
case N of
1 ->
<<"character"/utf8>>;
_ ->
<<"characters"/utf8>>
end.
-file("src/oaspec/internal/codegen/guards.gleam", 980).
?DOC(false).
-spec range_check_lines(
binary(),
binary(),
gleam@option:option(range_bound()),
gleam@option:option(range_bound())
) -> list(binary()).
range_check_lines(Compare_var, Prop_name, Min, Max) ->
case {Min, Max} of
{{some, Lo}, {some, Hi}} ->
[<<<<<<<<<<<<" case "/utf8, Compare_var/binary>>/binary, " "/utf8>>/binary,
(erlang:element(2, Lo))/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(3, Lo))/binary>>/binary,
" {"/utf8>>,
<<" True -> "/utf8,
(validation_failure_literal(
Prop_name,
erlang:element(4, Lo),
erlang:element(5, Lo)
))/binary>>,
<<" False ->"/utf8>>,
<<<<<<<<<<<<" case "/utf8, Compare_var/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(2, Hi))/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(3, Hi))/binary>>/binary,
" {"/utf8>>,
<<" True -> "/utf8,
(validation_failure_literal(
Prop_name,
erlang:element(4, Hi),
erlang:element(5, Hi)
))/binary>>,
<<" False -> Ok(value)"/utf8>>,
<<" }"/utf8>>,
<<" }"/utf8>>];
{{some, Lo@1}, none} ->
[<<<<<<<<<<<<" case "/utf8, Compare_var/binary>>/binary, " "/utf8>>/binary,
(erlang:element(2, Lo@1))/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(3, Lo@1))/binary>>/binary,
" {"/utf8>>,
<<" True -> "/utf8,
(validation_failure_literal(
Prop_name,
erlang:element(4, Lo@1),
erlang:element(5, Lo@1)
))/binary>>,
<<" False -> Ok(value)"/utf8>>,
<<" }"/utf8>>];
{none, {some, Hi@1}} ->
[<<<<<<<<<<<<" case "/utf8, Compare_var/binary>>/binary, " "/utf8>>/binary,
(erlang:element(2, Hi@1))/binary>>/binary,
" "/utf8>>/binary,
(erlang:element(3, Hi@1))/binary>>/binary,
" {"/utf8>>,
<<" True -> "/utf8,
(validation_failure_literal(
Prop_name,
erlang:element(4, Hi@1),
erlang:element(5, Hi@1)
))/binary>>,
<<" False -> Ok(value)"/utf8>>,
<<" }"/utf8>>];
{none, none} ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 946).
?DOC(false).
-spec build_range_guard(binary(), binary(), range_guard_spec()) -> gleam@option:option(guard_function()).
build_range_guard(Schema_name, Prop_name, Spec) ->
case {erlang:element(8, Spec), erlang:element(9, Spec)} of
{none, none} ->
none;
{_, _} ->
Fn_name = guard_function_name(
Schema_name,
Prop_name,
erlang:element(2, Spec)
),
Lines = lists:append(
erlang:element(6, Spec),
range_check_lines(
erlang:element(7, Spec),
Prop_name,
erlang:element(8, Spec),
erlang:element(9, Spec)
)
),
{some,
{guard_function,
Fn_name,
[<<<<<<<<<<"Validate "/utf8,
(erlang:element(3, Spec))/binary>>/binary,
" for "/utf8>>/binary,
Schema_name/binary>>/binary,
(field_label(Prop_name))/binary>>/binary,
"."/utf8>>],
erlang:element(4, Spec),
erlang:element(5, Spec),
gleam@string:join(Lines, <<"\n"/utf8>>),
field_validator}}
end.
-file("src/oaspec/internal/codegen/guards.gleam", 1041).
?DOC(false).
-spec build_string_guard_function(
binary(),
binary(),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_string_guard_function(Schema_name, Prop_name, Min_length, Max_length) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"length"/utf8>>,
<<"string length"/utf8>>,
<<"value: String"/utf8>>,
<<"Result(String, ValidationFailure)"/utf8>>,
[<<" let len = string.length(value)"/utf8>>],
<<"len"/utf8>>,
gleam@option:map(
Min_length,
fun(N) ->
{range_bound,
<<"<"/utf8>>,
erlang:integer_to_binary(N),
<<"minLength"/utf8>>,
<<<<<<"must be at least "/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" "/utf8>>/binary,
(character_word(N))/binary>>}
end
),
gleam@option:map(
Max_length,
fun(N@1) ->
{range_bound,
<<">"/utf8>>,
erlang:integer_to_binary(N@1),
<<"maxLength"/utf8>>,
<<<<<<"must be at most "/utf8,
(erlang:integer_to_binary(N@1))/binary>>/binary,
" "/utf8>>/binary,
(character_word(N@1))/binary>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1083).
?DOC(false).
-spec build_integer_guard_function(
binary(),
binary(),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_integer_guard_function(Schema_name, Prop_name, Minimum, Maximum) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"range"/utf8>>,
<<"integer range"/utf8>>,
<<"value: Int"/utf8>>,
<<"Result(Int, ValidationFailure)"/utf8>>,
[],
<<"value"/utf8>>,
gleam@option:map(
Minimum,
fun(N) ->
{range_bound,
<<"<"/utf8>>,
erlang:integer_to_binary(N),
<<"minimum"/utf8>>,
<<"must be at least "/utf8,
(erlang:integer_to_binary(N))/binary>>}
end
),
gleam@option:map(
Maximum,
fun(N@1) ->
{range_bound,
<<">"/utf8>>,
erlang:integer_to_binary(N@1),
<<"maximum"/utf8>>,
<<"must be at most "/utf8,
(erlang:integer_to_binary(N@1))/binary>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1119).
?DOC(false).
-spec build_float_guard_function(
binary(),
binary(),
gleam@option:option(float()),
gleam@option:option(float())
) -> gleam@option:option(guard_function()).
build_float_guard_function(Schema_name, Prop_name, Minimum, Maximum) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"range"/utf8>>,
<<"float range"/utf8>>,
<<"value: Float"/utf8>>,
<<"Result(Float, ValidationFailure)"/utf8>>,
[],
<<"value"/utf8>>,
gleam@option:map(
Minimum,
fun(N) ->
{range_bound,
<<"<."/utf8>>,
gleam_stdlib:float_to_string(N),
<<"minimum"/utf8>>,
<<"must be at least "/utf8,
(gleam_stdlib:float_to_string(N))/binary>>}
end
),
gleam@option:map(
Maximum,
fun(N@1) ->
{range_bound,
<<">."/utf8>>,
gleam_stdlib:float_to_string(N@1),
<<"maximum"/utf8>>,
<<"must be at most "/utf8,
(gleam_stdlib:float_to_string(N@1))/binary>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1155).
?DOC(false).
-spec build_integer_exclusive_guard_function(
binary(),
binary(),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_integer_exclusive_guard_function(
Schema_name,
Prop_name,
Exclusive_minimum,
Exclusive_maximum
) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"exclusive_range"/utf8>>,
<<"integer exclusive range"/utf8>>,
<<"value: Int"/utf8>>,
<<"Result(Int, ValidationFailure)"/utf8>>,
[],
<<"value"/utf8>>,
gleam@option:map(
Exclusive_minimum,
fun(N) ->
{range_bound,
<<"<="/utf8>>,
erlang:integer_to_binary(N),
<<"exclusiveMinimum"/utf8>>,
<<"must be greater than "/utf8,
(erlang:integer_to_binary(N))/binary>>}
end
),
gleam@option:map(
Exclusive_maximum,
fun(N@1) ->
{range_bound,
<<">="/utf8>>,
erlang:integer_to_binary(N@1),
<<"exclusiveMaximum"/utf8>>,
<<"must be less than "/utf8,
(erlang:integer_to_binary(N@1))/binary>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1193).
?DOC(false).
-spec build_integer_multiple_of_guard_function(
binary(),
binary(),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_integer_multiple_of_guard_function(Schema_name, Prop_name, Multiple_of) ->
case Multiple_of of
none ->
none;
{some, M} ->
{some,
{guard_function,
guard_function_name(
Schema_name,
Prop_name,
<<"multiple_of"/utf8>>
),
[<<<<<<"Validate integer multipleOf for "/utf8,
Schema_name/binary>>/binary,
(field_label(Prop_name))/binary>>/binary,
"."/utf8>>],
<<"value: Int"/utf8>>,
<<"Result(Int, ValidationFailure)"/utf8>>,
gleam@string:join(
[<<<<" case value % "/utf8,
(erlang:integer_to_binary(M))/binary>>/binary,
" == 0 {"/utf8>>,
<<" False -> "/utf8,
(validation_failure_literal(
Prop_name,
<<"multipleOf"/utf8>>,
<<"must be a multiple of "/utf8,
(erlang:integer_to_binary(M))/binary>>
))/binary>>,
<<" True -> Ok(value)"/utf8>>,
<<" }"/utf8>>],
<<"\n"/utf8>>
),
field_validator}}
end.
-file("src/oaspec/internal/codegen/guards.gleam", 1230).
?DOC(false).
-spec build_float_exclusive_guard_function(
binary(),
binary(),
gleam@option:option(float()),
gleam@option:option(float())
) -> gleam@option:option(guard_function()).
build_float_exclusive_guard_function(
Schema_name,
Prop_name,
Exclusive_minimum,
Exclusive_maximum
) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"exclusive_range"/utf8>>,
<<"float exclusive range"/utf8>>,
<<"value: Float"/utf8>>,
<<"Result(Float, ValidationFailure)"/utf8>>,
[],
<<"value"/utf8>>,
gleam@option:map(
Exclusive_minimum,
fun(N) ->
{range_bound,
<<"<=."/utf8>>,
gleam_stdlib:float_to_string(N),
<<"exclusiveMinimum"/utf8>>,
<<"must be greater than "/utf8,
(gleam_stdlib:float_to_string(N))/binary>>}
end
),
gleam@option:map(
Exclusive_maximum,
fun(N@1) ->
{range_bound,
<<">=."/utf8>>,
gleam_stdlib:float_to_string(N@1),
<<"exclusiveMaximum"/utf8>>,
<<"must be less than "/utf8,
(gleam_stdlib:float_to_string(N@1))/binary>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1266).
?DOC(false).
-spec build_float_multiple_of_guard_function(
binary(),
binary(),
gleam@option:option(float())
) -> gleam@option:option(guard_function()).
build_float_multiple_of_guard_function(Schema_name, Prop_name, Multiple_of) ->
case Multiple_of of
none ->
none;
{some, M} ->
{some,
{guard_function,
guard_function_name(
Schema_name,
Prop_name,
<<"multiple_of"/utf8>>
),
[<<<<<<"Validate float multipleOf for "/utf8,
Schema_name/binary>>/binary,
(field_label(Prop_name))/binary>>/binary,
"."/utf8>>],
<<"value: Float"/utf8>>,
<<"Result(Float, ValidationFailure)"/utf8>>,
gleam@string:join(
[<<<<<<" let remainder = value -. int.to_float(float.truncate(value /. "/utf8,
(gleam_stdlib:float_to_string(M))/binary>>/binary,
")) *. "/utf8>>/binary,
(gleam_stdlib:float_to_string(M))/binary>>,
<<" case remainder == 0.0 || remainder == -0.0 {"/utf8>>,
<<" False -> "/utf8,
(validation_failure_literal(
Prop_name,
<<"multipleOf"/utf8>>,
<<"must be a multiple of "/utf8,
(gleam_stdlib:float_to_string(M))/binary>>
))/binary>>,
<<" True -> Ok(value)"/utf8>>,
<<" }"/utf8>>],
<<"\n"/utf8>>
),
field_validator}}
end.
-file("src/oaspec/internal/codegen/guards.gleam", 1317).
?DOC(false).
-spec build_list_guard_function(
binary(),
binary(),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_list_guard_function(Schema_name, Prop_name, Min_items, Max_items) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"length"/utf8>>,
<<"list length"/utf8>>,
<<"value: List(a)"/utf8>>,
<<"Result(List(a), ValidationFailure)"/utf8>>,
[<<" let len = list.length(value)"/utf8>>],
<<"len"/utf8>>,
gleam@option:map(
Min_items,
fun(N) ->
{range_bound,
<<"<"/utf8>>,
erlang:integer_to_binary(N),
<<"minItems"/utf8>>,
<<<<"must have at least "/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" items"/utf8>>}
end
),
gleam@option:map(
Max_items,
fun(N@1) ->
{range_bound,
<<">"/utf8>>,
erlang:integer_to_binary(N@1),
<<"maxItems"/utf8>>,
<<<<"must have at most "/utf8,
(erlang:integer_to_binary(N@1))/binary>>/binary,
" items"/utf8>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 1353).
?DOC(false).
-spec build_unique_items_guard_function(binary(), binary(), boolean()) -> gleam@option:option(guard_function()).
build_unique_items_guard_function(Schema_name, Prop_name, Unique_items) ->
gleam@bool:guard(
not Unique_items,
none,
fun() ->
{some,
{guard_function,
guard_function_name(
Schema_name,
Prop_name,
<<"unique"/utf8>>
),
[<<<<<<"Validate unique items for "/utf8,
Schema_name/binary>>/binary,
(field_label(Prop_name))/binary>>/binary,
"."/utf8>>],
<<"value: List(a)"/utf8>>,
<<"Result(List(a), ValidationFailure)"/utf8>>,
gleam@string:join(
[<<" case list.length(value) == list.length(list.unique(value)) {"/utf8>>,
<<" True -> Ok(value)"/utf8>>,
<<" False -> "/utf8,
(validation_failure_literal(
Prop_name,
<<"uniqueItems"/utf8>>,
<<"items must be unique"/utf8>>
))/binary>>,
<<" }"/utf8>>],
<<"\n"/utf8>>
),
field_validator}}
end
).
-file("src/oaspec/internal/codegen/guards.gleam", 408).
?DOC(false).
-spec collect_field_guard_functions(
binary(),
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> list(guard_function()).
collect_field_guard_functions(Schema_name, Prop_name, Prop_ref, Ctx) ->
Resolved = oaspec@internal@codegen@context:resolve_schema_ref(Prop_ref, Ctx),
case Resolved of
{ok, {string_schema, _, _, _, Min_length, Max_length, Pattern}} ->
lists:append(
[maybe_one(
build_string_guard_function(
Schema_name,
Prop_name,
Min_length,
Max_length
)
),
maybe_one(
build_string_pattern_guard_function(
Schema_name,
Prop_name,
Pattern
)
)]
);
{ok,
{integer_schema,
_,
_,
Minimum,
Maximum,
Exclusive_minimum,
Exclusive_maximum,
Multiple_of}} ->
lists:append(
[maybe_one(
build_integer_guard_function(
Schema_name,
Prop_name,
Minimum,
Maximum
)
),
maybe_one(
build_integer_exclusive_guard_function(
Schema_name,
Prop_name,
Exclusive_minimum,
Exclusive_maximum
)
),
maybe_one(
build_integer_multiple_of_guard_function(
Schema_name,
Prop_name,
Multiple_of
)
)]
);
{ok,
{number_schema,
_,
_,
Minimum@1,
Maximum@1,
Exclusive_minimum@1,
Exclusive_maximum@1,
Multiple_of@1}} ->
lists:append(
[maybe_one(
build_float_guard_function(
Schema_name,
Prop_name,
Minimum@1,
Maximum@1
)
),
maybe_one(
build_float_exclusive_guard_function(
Schema_name,
Prop_name,
Exclusive_minimum@1,
Exclusive_maximum@1
)
),
maybe_one(
build_float_multiple_of_guard_function(
Schema_name,
Prop_name,
Multiple_of@1
)
)]
);
{ok, {array_schema, _, _, Min_items, Max_items, Unique_items}} ->
lists:append(
[maybe_one(
build_list_guard_function(
Schema_name,
Prop_name,
Min_items,
Max_items
)
),
maybe_one(
build_unique_items_guard_function(
Schema_name,
Prop_name,
Unique_items
)
)]
);
_ ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 1387).
?DOC(false).
-spec build_properties_count_guard_function(
binary(),
binary(),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> gleam@option:option(guard_function()).
build_properties_count_guard_function(
Schema_name,
Prop_name,
Min_properties,
Max_properties
) ->
build_range_guard(
Schema_name,
Prop_name,
{range_guard_spec,
<<"properties"/utf8>>,
<<"property count"/utf8>>,
<<"value: Dict(k, v)"/utf8>>,
<<"Result(Dict(k, v), ValidationFailure)"/utf8>>,
[<<" let count = dict.size(value)"/utf8>>],
<<"count"/utf8>>,
gleam@option:map(
Min_properties,
fun(N) ->
{range_bound,
<<"<"/utf8>>,
erlang:integer_to_binary(N),
<<"minProperties"/utf8>>,
<<<<"must have at least "/utf8,
(erlang:integer_to_binary(N))/binary>>/binary,
" properties"/utf8>>}
end
),
gleam@option:map(
Max_properties,
fun(N@1) ->
{range_bound,
<<">"/utf8>>,
erlang:integer_to_binary(N@1),
<<"maxProperties"/utf8>>,
<<<<"must have at most "/utf8,
(erlang:integer_to_binary(N@1))/binary>>/binary,
" properties"/utf8>>}
end
)}
).
-file("src/oaspec/internal/codegen/guards.gleam", 317).
?DOC(false).
-spec collect_guard_functions_for_schema_object(
binary(),
oaspec@internal@openapi@schema:schema_object(),
oaspec@internal@codegen@context:context()
) -> list(guard_function()).
collect_guard_functions_for_schema_object(Name, Schema, Ctx) ->
case Schema of
{object_schema, _, Properties, _, _, Min_properties, Max_properties} ->
lists:append(
maybe_one(
build_properties_count_guard_function(
Name,
<<""/utf8>>,
Min_properties,
Max_properties
)
),
begin
_pipe = oaspec@internal@codegen@ir_build:sorted_entries(
Properties
),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Prop_name, Prop_ref} = Entry,
collect_field_guard_functions(
Name,
Prop_name,
Prop_ref,
Ctx
)
end
)
end
);
{all_of_schema, _, Schemas} ->
lists:append(
[],
begin
_pipe@1 = oaspec@internal@codegen@ir_build:sorted_entries(
erlang:element(
2,
oaspec@internal@codegen@allof_merge:merge_allof_schemas(
Schemas,
Ctx
)
)
),
gleam@list:flat_map(
_pipe@1,
fun(Entry@1) ->
{Prop_name@1, Prop_ref@1} = Entry@1,
collect_field_guard_functions(
Name,
Prop_name@1,
Prop_ref@1,
Ctx
)
end
)
end
);
{string_schema, _, _, _, Min_length, Max_length, Pattern} ->
lists:append(
[maybe_one(
build_string_guard_function(
Name,
<<""/utf8>>,
Min_length,
Max_length
)
),
maybe_one(
build_string_pattern_guard_function(
Name,
<<""/utf8>>,
Pattern
)
)]
);
{integer_schema,
_,
_,
Minimum,
Maximum,
Exclusive_minimum,
Exclusive_maximum,
Multiple_of} ->
lists:append(
[maybe_one(
build_integer_guard_function(
Name,
<<""/utf8>>,
Minimum,
Maximum
)
),
maybe_one(
build_integer_exclusive_guard_function(
Name,
<<""/utf8>>,
Exclusive_minimum,
Exclusive_maximum
)
),
maybe_one(
build_integer_multiple_of_guard_function(
Name,
<<""/utf8>>,
Multiple_of
)
)]
);
{number_schema,
_,
_,
Minimum@1,
Maximum@1,
Exclusive_minimum@1,
Exclusive_maximum@1,
Multiple_of@1} ->
lists:append(
[maybe_one(
build_float_guard_function(
Name,
<<""/utf8>>,
Minimum@1,
Maximum@1
)
),
maybe_one(
build_float_exclusive_guard_function(
Name,
<<""/utf8>>,
Exclusive_minimum@1,
Exclusive_maximum@1
)
),
maybe_one(
build_float_multiple_of_guard_function(
Name,
<<""/utf8>>,
Multiple_of@1
)
)]
);
{array_schema, _, _, Min_items, Max_items, Unique_items} ->
lists:append(
[maybe_one(
build_list_guard_function(
Name,
<<""/utf8>>,
Min_items,
Max_items
)
),
maybe_one(
build_unique_items_guard_function(
Name,
<<""/utf8>>,
Unique_items
)
)]
);
_ ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 300).
?DOC(false).
-spec collect_guard_functions_for_schema(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> list(guard_function()).
collect_guard_functions_for_schema(Name, Schema_ref, Ctx) ->
case Schema_ref of
{inline, Schema} ->
collect_guard_functions_for_schema_object(Name, Schema, Ctx);
{reference, _, Name@1} ->
case oaspec@internal@codegen@context:resolve_schema_ref(
Schema_ref,
Ctx
) of
{ok, Schema@1} ->
collect_guard_functions_for_schema_object(
Name@1,
Schema@1,
Ctx
);
_ ->
[]
end
end.
-file("src/oaspec/internal/codegen/guards.gleam", 1424).
?DOC(false).
-spec composite_validator_type(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> binary().
composite_validator_type(Name, Schema_ref, Ctx) ->
Schema = oaspec@internal@codegen@context:resolve_schema_ref(Schema_ref, Ctx),
case Schema of
{ok, {object_schema, _, _, _, _, _, _}} ->
<<"types."/utf8,
(oaspec@internal@util@naming:schema_to_type_name(Name))/binary>>;
{ok, {all_of_schema, _, _}} ->
<<"types."/utf8,
(oaspec@internal@util@naming:schema_to_type_name(Name))/binary>>;
{ok, S} ->
oaspec@internal@codegen@schema_dispatch:schema_type(S);
_ ->
<<"types."/utf8,
(oaspec@internal@util@naming:schema_to_type_name(Name))/binary>>
end.
-file("src/oaspec/internal/codegen/guards.gleam", 578).
?DOC(false).
-spec collect_schema_constraint_types_inner(
constraint_types(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context(),
gleam@set:set(binary())
) -> constraint_types().
collect_schema_constraint_types_inner(Acc, Schema_ref, Ctx, Seen) ->
Schema = oaspec@internal@codegen@context:resolve_schema_ref(Schema_ref, Ctx),
case Schema of
{ok, {string_schema, _, _, _, Min_length, Max_length, Pattern}} ->
Acc@1 = case {Min_length, Max_length} of
{none, none} ->
Acc;
{_, _} ->
{constraint_types,
true,
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)}
end,
case Pattern of
{some, _} ->
{constraint_types,
erlang:element(2, Acc@1),
true,
erlang:element(4, Acc@1),
erlang:element(5, Acc@1),
erlang:element(6, Acc@1),
erlang:element(7, Acc@1),
erlang:element(8, Acc@1)};
none ->
Acc@1
end;
{ok, {integer_schema, _, _, {some, _}, _, _, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {integer_schema, _, _, _, {some, _}, _, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {integer_schema, _, _, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {integer_schema, _, _, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {integer_schema, _, _, _, _, _, _, {some, _}}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {number_schema, _, _, _, _, _, _, {some, _}}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true,
erlang:element(6, Acc),
true,
erlang:element(8, Acc)};
{ok, {number_schema, _, _, {some, _}, _, _, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true,
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {number_schema, _, _, _, {some, _}, _, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true,
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {number_schema, _, _, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true,
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {number_schema, _, _, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true,
erlang:element(6, Acc),
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {array_schema, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc),
true,
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {array_schema, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc),
true,
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok, {array_schema, _, _, _, _, true}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc),
true,
erlang:element(7, Acc),
erlang:element(8, Acc)};
{ok,
{object_schema, _, Properties, _, _, Min_properties, Max_properties}} ->
Acc@2 = case {Min_properties, Max_properties} of
{none, none} ->
Acc;
{_, _} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc),
erlang:element(6, Acc),
erlang:element(7, Acc),
true}
end,
_pipe = maps:to_list(Properties),
gleam@list:fold(
_pipe,
Acc@2,
fun(A, Prop) ->
{_, Prop_ref} = Prop,
collect_schema_constraint_types(A, Prop_ref, Ctx, Seen)
end
);
{ok, {all_of_schema, _, Schemas}} ->
gleam@list:fold(
Schemas,
Acc,
fun(A@1, S) ->
collect_schema_constraint_types(A@1, S, Ctx, Seen)
end
);
_ ->
Acc
end.
-file("src/oaspec/internal/codegen/guards.gleam", 555).
?DOC(false).
-spec collect_schema_constraint_types(
constraint_types(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context(),
gleam@set:set(binary())
) -> constraint_types().
collect_schema_constraint_types(Acc, Schema_ref, Ctx, Seen) ->
case Schema_ref of
{reference, _, Name} ->
case gleam@set:contains(Seen, Name) of
true ->
Acc;
false ->
collect_schema_constraint_types_inner(
Acc,
Schema_ref,
Ctx,
gleam@set:insert(Seen, Name)
)
end;
_ ->
collect_schema_constraint_types_inner(Acc, Schema_ref, Ctx, Seen)
end.
-file("src/oaspec/internal/codegen/guards.gleam", 539).
?DOC(false).
-spec collect_constraint_types(
list({binary(), oaspec@internal@openapi@schema:schema_ref()}),
oaspec@internal@codegen@context:context()
) -> constraint_types().
collect_constraint_types(Schemas, Ctx) ->
gleam@list:fold(
Schemas,
{constraint_types, false, false, false, false, false, false, false},
fun(Acc, Entry) ->
{_, Schema_ref} = Entry,
collect_schema_constraint_types(
Acc,
Schema_ref,
Ctx,
gleam@set:new()
)
end
).
-file("src/oaspec/internal/codegen/guards.gleam", 1641).
?DOC(false).
-spec collect_field_guard_calls(
binary(),
binary(),
oaspec@internal@openapi@schema:schema_ref(),
boolean(),
oaspec@internal@codegen@context:context(),
list(binary())
) -> list({binary(), binary(), boolean(), guard_call_kind()}).
collect_field_guard_calls(
Schema_name,
Prop_name,
Prop_ref,
Is_required,
Ctx,
Visiting
) ->
Resolved = oaspec@internal@codegen@context:resolve_schema_ref(Prop_ref, Ctx),
Accessor = <<"value."/utf8,
(oaspec@internal@util@naming:to_snake_case(Prop_name))/binary>>,
case Resolved of
{ok, {string_schema, _, _, _, Min_length, Max_length, Pattern}} ->
Calls = case {Min_length, Max_length} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(
Schema_name,
Prop_name,
<<"length"/utf8>>
),
Accessor,
Is_required,
direct}]
end,
case Pattern of
none ->
Calls;
{some, _} ->
lists:append(
Calls,
[{guard_function_name(
Schema_name,
Prop_name,
<<"pattern"/utf8>>
),
Accessor,
Is_required,
direct}]
)
end;
{ok,
{integer_schema,
_,
_,
Minimum,
Maximum,
Exclusive_minimum,
Exclusive_maximum,
Multiple_of}} ->
Calls@1 = case {Minimum, Maximum} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(
Schema_name,
Prop_name,
<<"range"/utf8>>
),
Accessor,
Is_required,
direct}]
end,
Calls@2 = case {Exclusive_minimum, Exclusive_maximum} of
{none, none} ->
Calls@1;
{_, _} ->
lists:append(
Calls@1,
[{guard_function_name(
Schema_name,
Prop_name,
<<"exclusive_range"/utf8>>
),
Accessor,
Is_required,
direct}]
)
end,
case Multiple_of of
none ->
Calls@2;
{some, _} ->
lists:append(
Calls@2,
[{guard_function_name(
Schema_name,
Prop_name,
<<"multiple_of"/utf8>>
),
Accessor,
Is_required,
direct}]
)
end;
{ok,
{number_schema,
_,
_,
Minimum@1,
Maximum@1,
Exclusive_minimum@1,
Exclusive_maximum@1,
Multiple_of@1}} ->
Calls@3 = case {Minimum@1, Maximum@1} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(
Schema_name,
Prop_name,
<<"range"/utf8>>
),
Accessor,
Is_required,
direct}]
end,
Calls@4 = case {Exclusive_minimum@1, Exclusive_maximum@1} of
{none, none} ->
Calls@3;
{_, _} ->
lists:append(
Calls@3,
[{guard_function_name(
Schema_name,
Prop_name,
<<"exclusive_range"/utf8>>
),
Accessor,
Is_required,
direct}]
)
end,
case Multiple_of@1 of
none ->
Calls@4;
{some, _} ->
lists:append(
Calls@4,
[{guard_function_name(
Schema_name,
Prop_name,
<<"multiple_of"/utf8>>
),
Accessor,
Is_required,
direct}]
)
end;
{ok, {array_schema, _, Items, Min_items, Max_items, Unique_items}} ->
Length_calls = case {Min_items, Max_items} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(
Schema_name,
Prop_name,
<<"length"/utf8>>
),
Accessor,
Is_required,
direct}]
end,
Unique_calls = case Unique_items of
true ->
[{guard_function_name(
Schema_name,
Prop_name,
<<"unique"/utf8>>
),
Accessor,
Is_required,
direct}];
false ->
[]
end,
Item_calls = case Items of
{reference, _, Item_name} ->
case schema_has_validator_visiting(Item_name, Ctx, Visiting) of
true ->
[{<<"validate_"/utf8,
(oaspec@internal@util@naming:to_snake_case(
Item_name
))/binary>>,
Accessor,
Is_required,
composite_list}];
false ->
[]
end;
_ ->
[]
end,
lists:append([Length_calls, Unique_calls, Item_calls]);
{ok, {object_schema, _, _, _, _, _, _}} ->
case Prop_ref of
{reference, _, Ref_name} ->
case schema_has_validator_visiting(Ref_name, Ctx, Visiting) of
true ->
[{<<"validate_"/utf8,
(oaspec@internal@util@naming:to_snake_case(
Ref_name
))/binary>>,
Accessor,
Is_required,
composite}];
false ->
[]
end;
_ ->
[]
end;
_ ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 58).
?DOC(false).
-spec schema_has_validator_visiting(
binary(),
oaspec@internal@codegen@context:context(),
list(binary())
) -> boolean().
schema_has_validator_visiting(Name, Ctx, Visiting) ->
gleam@bool:guard(
gleam@list:contains(Visiting, Name),
false,
fun() ->
case erlang:element(5, oaspec@internal@codegen@context:spec(Ctx)) of
{some, Components} ->
case gleam_stdlib:map_get(
erlang:element(2, Components),
Name
) of
{ok, Schema_ref} ->
not oaspec@internal@codegen@ir_build:is_internal_schema(
Schema_ref
)
andalso not gleam@list:is_empty(
collect_guard_calls_visiting(
Name,
Schema_ref,
Ctx,
[Name | Visiting]
)
);
{error, _} ->
false
end;
none ->
false
end
end
).
-file("src/oaspec/internal/codegen/guards.gleam", 1471).
?DOC(false).
-spec collect_guard_calls_visiting(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context(),
list(binary())
) -> list({binary(), binary(), boolean(), guard_call_kind()}).
collect_guard_calls_visiting(Name, Schema_ref, Ctx, Visiting) ->
Schema = oaspec@internal@codegen@context:resolve_schema_ref(Schema_ref, Ctx),
case Schema of
{ok,
{object_schema,
_,
Properties,
Required,
_,
Min_properties,
Max_properties}} ->
Prop_calls = begin
_pipe = oaspec@internal@codegen@ir_build:sorted_entries(
Properties
),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Prop_name, Prop_ref} = Entry,
Is_required = gleam@list:contains(Required, Prop_name),
collect_field_guard_calls(
Name,
Prop_name,
Prop_ref,
Is_required,
Ctx,
Visiting
)
end
)
end,
Size_calls = case {Min_properties, Max_properties} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(
Name,
<<""/utf8>>,
<<"properties"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
end,
lists:append(Prop_calls, Size_calls);
{ok, {all_of_schema, _, Schemas}} ->
Merged = oaspec@internal@codegen@allof_merge:merge_allof_schemas(
Schemas,
Ctx
),
_pipe@1 = oaspec@internal@codegen@ir_build:sorted_entries(
erlang:element(2, Merged)
),
gleam@list:flat_map(
_pipe@1,
fun(Entry@1) ->
{Prop_name@1, Prop_ref@1} = Entry@1,
Is_required@1 = gleam@list:contains(
erlang:element(3, Merged),
Prop_name@1
),
collect_field_guard_calls(
Name,
Prop_name@1,
Prop_ref@1,
Is_required@1,
Ctx,
Visiting
)
end
);
{ok, {string_schema, _, _, _, Min_length, Max_length, Pattern}} ->
Calls = case {Min_length, Max_length} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(Name, <<""/utf8>>, <<"length"/utf8>>),
<<"value"/utf8>>,
true,
direct}]
end,
case Pattern of
none ->
Calls;
{some, _} ->
lists:append(
Calls,
[{guard_function_name(
Name,
<<""/utf8>>,
<<"pattern"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
)
end;
{ok,
{integer_schema,
_,
_,
Minimum,
Maximum,
Exclusive_minimum,
Exclusive_maximum,
Multiple_of}} ->
Calls@1 = case {Minimum, Maximum} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(Name, <<""/utf8>>, <<"range"/utf8>>),
<<"value"/utf8>>,
true,
direct}]
end,
Calls@2 = case {Exclusive_minimum, Exclusive_maximum} of
{none, none} ->
Calls@1;
{_, _} ->
lists:append(
Calls@1,
[{guard_function_name(
Name,
<<""/utf8>>,
<<"exclusive_range"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
)
end,
case Multiple_of of
none ->
Calls@2;
{some, _} ->
lists:append(
Calls@2,
[{guard_function_name(
Name,
<<""/utf8>>,
<<"multiple_of"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
)
end;
{ok,
{number_schema,
_,
_,
Minimum@1,
Maximum@1,
Exclusive_minimum@1,
Exclusive_maximum@1,
Multiple_of@1}} ->
Calls@3 = case {Minimum@1, Maximum@1} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(Name, <<""/utf8>>, <<"range"/utf8>>),
<<"value"/utf8>>,
true,
direct}]
end,
Calls@4 = case {Exclusive_minimum@1, Exclusive_maximum@1} of
{none, none} ->
Calls@3;
{_, _} ->
lists:append(
Calls@3,
[{guard_function_name(
Name,
<<""/utf8>>,
<<"exclusive_range"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
)
end,
case Multiple_of@1 of
none ->
Calls@4;
{some, _} ->
lists:append(
Calls@4,
[{guard_function_name(
Name,
<<""/utf8>>,
<<"multiple_of"/utf8>>
),
<<"value"/utf8>>,
true,
direct}]
)
end;
{ok, {array_schema, _, _, Min_items, Max_items, Unique_items}} ->
Length_calls = case {Min_items, Max_items} of
{none, none} ->
[];
{_, _} ->
[{guard_function_name(Name, <<""/utf8>>, <<"length"/utf8>>),
<<"value"/utf8>>,
true,
direct}]
end,
Unique_calls = case Unique_items of
true ->
[{guard_function_name(Name, <<""/utf8>>, <<"unique"/utf8>>),
<<"value"/utf8>>,
true,
direct}];
false ->
[]
end,
lists:append(Length_calls, Unique_calls);
_ ->
[]
end.
-file("src/oaspec/internal/codegen/guards.gleam", 47).
?DOC(false).
-spec schema_has_validator(binary(), oaspec@internal@codegen@context:context()) -> boolean().
schema_has_validator(Name, Ctx) ->
schema_has_validator_visiting(Name, Ctx, []).
-file("src/oaspec/internal/codegen/guards.gleam", 1463).
?DOC(false).
-spec collect_guard_calls(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> list({binary(), binary(), boolean(), guard_call_kind()}).
collect_guard_calls(Name, Schema_ref, Ctx) ->
collect_guard_calls_visiting(Name, Schema_ref, Ctx, []).
-file("src/oaspec/internal/codegen/guards.gleam", 747).
?DOC(false).
-spec build_composite_guard_function(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> gleam@option:option(guard_function()).
build_composite_guard_function(Name, Schema_ref, Ctx) ->
Guard_calls = collect_guard_calls(Name, Schema_ref, Ctx),
case gleam@list:is_empty(Guard_calls) of
true ->
none;
false ->
Fn_name = <<"validate_"/utf8,
(oaspec@internal@util@naming:to_snake_case(Name))/binary>>,
Type_name = oaspec@internal@util@naming:schema_to_type_name(Name),
Gleam_type = composite_validator_type(Name, Schema_ref, Ctx),
Call_lines = gleam@list:flat_map(
Guard_calls,
fun(Call) ->
{Guard_fn, Accessor, Is_required, Kind} = Call,
case {Kind, Is_required} of
{direct, true} ->
[<<<<<<<<" let errors = case "/utf8,
Guard_fn/binary>>/binary,
"("/utf8>>/binary,
Accessor/binary>>/binary,
") {"/utf8>>,
<<" Ok(_) -> errors"/utf8>>,
<<" Error(failure) -> [failure, ..errors]"/utf8>>,
<<" }"/utf8>>];
{direct, false} ->
[<<<<" let errors = case "/utf8, Accessor/binary>>/binary,
" {"/utf8>>,
<<<<" option.Some(v) -> case "/utf8,
Guard_fn/binary>>/binary,
"(v) {"/utf8>>,
<<" Ok(_) -> errors"/utf8>>,
<<" Error(failure) -> [failure, ..errors]"/utf8>>,
<<" }"/utf8>>,
<<" option.None -> errors"/utf8>>,
<<" }"/utf8>>];
{composite, true} ->
[<<<<<<<<" let errors = case "/utf8,
Guard_fn/binary>>/binary,
"("/utf8>>/binary,
Accessor/binary>>/binary,
") {"/utf8>>,
<<" Ok(_) -> errors"/utf8>>,
<<" Error(failures) -> list.append(list.reverse(failures), errors)"/utf8>>,
<<" }"/utf8>>];
{composite, false} ->
[<<<<" let errors = case "/utf8, Accessor/binary>>/binary,
" {"/utf8>>,
<<<<" option.Some(v) -> case "/utf8,
Guard_fn/binary>>/binary,
"(v) {"/utf8>>,
<<" Ok(_) -> errors"/utf8>>,
<<" Error(failures) -> list.append(list.reverse(failures), errors)"/utf8>>,
<<" }"/utf8>>,
<<" option.None -> errors"/utf8>>,
<<" }"/utf8>>];
{composite_list, true} ->
[<<<<" let errors = list.fold("/utf8,
Accessor/binary>>/binary,
", errors, fn(errs, item) {"/utf8>>,
<<<<" case "/utf8, Guard_fn/binary>>/binary,
"(item) {"/utf8>>,
<<" Ok(_) -> errs"/utf8>>,
<<" Error(failures) -> list.append(list.reverse(failures), errs)"/utf8>>,
<<" }"/utf8>>,
<<" })"/utf8>>];
{composite_list, false} ->
[<<<<" let errors = case "/utf8, Accessor/binary>>/binary,
" {"/utf8>>,
<<" option.Some(items) -> list.fold(items, errors, fn(errs, item) {"/utf8>>,
<<<<" case "/utf8, Guard_fn/binary>>/binary,
"(item) {"/utf8>>,
<<" Ok(_) -> errs"/utf8>>,
<<" Error(failures) -> list.append(list.reverse(failures), errs)"/utf8>>,
<<" }"/utf8>>,
<<" })"/utf8>>,
<<" option.None -> errors"/utf8>>,
<<" }"/utf8>>]
end
end
),
{some,
{guard_function,
Fn_name,
[<<<<"Validate all constraints for "/utf8,
Type_name/binary>>/binary,
"."/utf8>>,
<<"Auto-calls all field validators and collects failures."/utf8>>],
<<"value: "/utf8, Gleam_type/binary>>,
<<<<"Result("/utf8, Gleam_type/binary>>/binary,
", List(ValidationFailure))"/utf8>>,
gleam@string:join(
lists:append(
[[<<" let errors = []"/utf8>>],
Call_lines,
[<<" case errors {"/utf8>>,
<<" [] -> Ok(value)"/utf8>>,
<<" _ -> Error(errors)"/utf8>>,
<<" }"/utf8>>]]
),
<<"\n"/utf8>>
),
composite_validator}}
end.
-file("src/oaspec/internal/codegen/guards.gleam", 99).
?DOC(false).
-spec build_module(oaspec@internal@codegen@context:context()) -> guard_module().
build_module(Ctx) ->
Schemas = case erlang:element(5, oaspec@internal@codegen@context:spec(Ctx)) of
{some, Components} ->
_pipe = gleam@list:sort(
maps:to_list(erlang:element(2, Components)),
fun(A, B) ->
gleam@string:compare(
erlang:element(1, A),
erlang:element(1, B)
)
end
),
gleam@list:filter(
_pipe,
fun(Entry) ->
not oaspec@internal@codegen@ir_build:is_internal_schema(
erlang:element(2, Entry)
)
end
);
none ->
[]
end,
Constraint_types = collect_constraint_types(Schemas, Ctx),
Imports = [<<"gleam/json"/utf8>>],
Imports@1 = case erlang:element(2, Constraint_types) of
true ->
[<<"gleam/string"/utf8>> | Imports];
false ->
Imports
end,
Imports@2 = case erlang:element(3, Constraint_types) of
true ->
[<<"gleam/regexp"/utf8>> | Imports@1];
false ->
Imports@1
end,
Imports@3 = case erlang:element(6, Constraint_types) of
true ->
[<<"gleam/list"/utf8>> | Imports@2];
false ->
Imports@2
end,
Imports@4 = case erlang:element(8, Constraint_types) of
true ->
[<<"gleam/dict.{type Dict}"/utf8>> | Imports@3];
false ->
Imports@3
end,
Imports@5 = case erlang:element(7, Constraint_types) of
true ->
[<<"gleam/int"/utf8>>, <<"gleam/float"/utf8>> | Imports@4];
false ->
Imports@4
end,
Needs_types = gleam@list:any(
Schemas,
fun(Entry@1) ->
{Name, Schema_ref} = Entry@1,
Guard_calls = collect_guard_calls(Name, Schema_ref, Ctx),
case gleam@list:is_empty(Guard_calls) of
true ->
false;
false ->
Resolved = oaspec@internal@codegen@context:resolve_schema_ref(
Schema_ref,
Ctx
),
case Resolved of
{ok, {object_schema, _, _, _, _, _, _}} ->
true;
{ok, {all_of_schema, _, _}} ->
true;
_ ->
false
end
end
end
),
Imports@6 = case Needs_types of
true ->
[<<(oaspec@config:package(
oaspec@internal@codegen@context:config(Ctx)
))/binary,
"/types"/utf8>> |
Imports@5];
false ->
Imports@5
end,
Needs_option = gleam@list:any(
Schemas,
fun(Entry@2) ->
{Name@1, Schema_ref@1} = Entry@2,
Guard_calls@1 = collect_guard_calls(Name@1, Schema_ref@1, Ctx),
gleam@list:any(
Guard_calls@1,
fun(Call) ->
{_, _, Is_required, _} = Call,
not Is_required
end
)
end
),
Imports@7 = case Needs_option of
true ->
[<<"gleam/option"/utf8>> | Imports@6];
false ->
Imports@6
end,
Needs_list_for_composites = gleam@list:any(
Schemas,
fun(Entry@3) ->
{Name@2, Schema_ref@2} = Entry@3,
Guard_calls@2 = collect_guard_calls(Name@2, Schema_ref@2, Ctx),
gleam@list:any(
Guard_calls@2,
fun(Call@1) ->
{_, _, _, Kind} = Call@1,
case Kind of
composite ->
true;
composite_list ->
true;
direct ->
false
end
end
)
end
),
Imports@8 = case Needs_list_for_composites andalso not erlang:element(
6,
Constraint_types
) of
true ->
[<<"gleam/list"/utf8>> | Imports@7];
false ->
Imports@7
end,
Field_validators = begin
_pipe@1 = gleam@list:flat_map(
Schemas,
fun(Entry@4) ->
{Name@3, Schema_ref@3} = Entry@4,
collect_guard_functions_for_schema(Name@3, Schema_ref@3, Ctx)
end
),
dedupe_guard_functions(_pipe@1)
end,
Composite_validators = gleam@list:flat_map(
Schemas,
fun(Entry@5) ->
{Name@4, Schema_ref@4} = Entry@5,
maybe_one(build_composite_guard_function(Name@4, Schema_ref@4, Ctx))
end
),
{guard_module,
Imports@8,
lists:append(Field_validators, Composite_validators)}.
-file("src/oaspec/internal/codegen/guards.gleam", 83).
?DOC(false).
-spec generate(oaspec@internal@codegen@context:context()) -> list(oaspec@internal@codegen@context:generated_file()).
generate(Ctx) ->
Module = build_module(Ctx),
case gleam@list:is_empty(erlang:element(3, Module)) of
true ->
[];
false ->
[{generated_file,
<<"guards.gleam"/utf8>>,
render_module(Module),
shared_target,
overwrite}]
end.