-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]). -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()}. -file("src/oaspec/internal/codegen/guards.gleam", 181). ?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", 241). ?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", 245). ?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", 207). ?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", 462). ?DOC(false). -spec maybe_one(gleam@option:option(JLD)) -> list(JLD). maybe_one(Value) -> case Value of {some, V} -> [V]; none -> [] end. -file("src/oaspec/internal/codegen/guards.gleam", 590). ?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", 609). ?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", 617). ?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", 632). ?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", 171). ?DOC(false). -spec render_module(guard_module()) -> binary(). render_module(Module) -> Sb = begin _pipe = oaspec@internal@util@string_extra:file_header(<<"0.41.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", 662). ?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", 680). ?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", 754). ?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>>, < 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", 807). ?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", 814). ?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) -> case {Min_length, Max_length} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"length"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"minLength"/utf8>>, <<<<<<"must be at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " "/utf8>>/binary, (character_word(Min))/binary>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"maxLength"/utf8>>, <<<<<<"must be at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " "/utf8>>/binary, (character_word(Max))/binary>> ) end, Lines = case {Min_length, Max_length} of {{some, Min@1}, {some, Max@1}} -> [<<" let len = string.length(value)"/utf8>>, <<<<" case len < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@1))/binary>>, <<" False ->"/utf8>>, <<<<" case len > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@1))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<" let len = string.length(value)"/utf8>>, <<<<" case len < "/utf8, (erlang:integer_to_binary(Min@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<" let len = string.length(value)"/utf8>>, <<<<" case len > "/utf8, (erlang:integer_to_binary(Max@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate string length for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: String"/utf8>>, <<"Result(String, ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 886). ?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) -> case {Minimum, Maximum} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"range"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"minimum"/utf8>>, <<"must be at least "/utf8, (erlang:integer_to_binary(Min))/binary>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"maximum"/utf8>>, <<"must be at most "/utf8, (erlang:integer_to_binary(Max))/binary>> ) end, Lines = case {Minimum, Maximum} of {{some, Min@1}, {some, Max@1}} -> [<<<<" case value < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@1))/binary>>, <<" False ->"/utf8>>, <<<<" case value > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@1))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<<<" case value < "/utf8, (erlang:integer_to_binary(Min@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<<<" case value > "/utf8, (erlang:integer_to_binary(Max@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate integer range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: Int"/utf8>>, <<"Result(Int, ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 952). ?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) -> case {Minimum, Maximum} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"range"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"minimum"/utf8>>, <<"must be at least "/utf8, (gleam_stdlib:float_to_string(Min))/binary>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"maximum"/utf8>>, <<"must be at most "/utf8, (gleam_stdlib:float_to_string(Max))/binary>> ) end, Lines = case {Minimum, Maximum} of {{some, Min@1}, {some, Max@1}} -> [<<<<" case value <. "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@1))/binary>>, <<" False ->"/utf8>>, <<<<" case value >. "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@1))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<<<" case value <. "/utf8, (gleam_stdlib:float_to_string(Min@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<<<" case value >. "/utf8, (gleam_stdlib:float_to_string(Max@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate float range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: Float"/utf8>>, <<"Result(Float, ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 1018). ?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 ) -> case {Exclusive_minimum, Exclusive_maximum} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"exclusive_range"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"exclusiveMinimum"/utf8>>, <<"must be greater than "/utf8, (erlang:integer_to_binary(Min))/binary>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"exclusiveMaximum"/utf8>>, <<"must be less than "/utf8, (erlang:integer_to_binary(Max))/binary>> ) end, Lines = case {Exclusive_minimum, Exclusive_maximum} of {{some, Min@1}, {some, Max@1}} -> [<<<<" case value > "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Min_failure(Min@1))/binary>>, <<" True ->"/utf8>>, <<<<" case value < "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Max_failure(Max@1))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<<<" case value > "/utf8, (erlang:integer_to_binary(Min@2))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Min_failure(Min@2))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<<<" case value < "/utf8, (erlang:integer_to_binary(Max@2))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Max_failure(Max@2))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate integer exclusive range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: Int"/utf8>>, <<"Result(Int, ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 1085). ?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", 1122). ?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 ) -> case {Exclusive_minimum, Exclusive_maximum} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"exclusive_range"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"exclusiveMinimum"/utf8>>, <<"must be greater than "/utf8, (gleam_stdlib:float_to_string(Min))/binary>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"exclusiveMaximum"/utf8>>, <<"must be less than "/utf8, (gleam_stdlib:float_to_string(Max))/binary>> ) end, Lines = case {Exclusive_minimum, Exclusive_maximum} of {{some, Min@1}, {some, Max@1}} -> [<<<<" case value >. "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Min_failure(Min@1))/binary>>, <<" True ->"/utf8>>, <<<<" case value <. "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Max_failure(Max@1))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<<<" case value >. "/utf8, (gleam_stdlib:float_to_string(Min@2))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Min_failure(Min@2))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<<<" case value <. "/utf8, (gleam_stdlib:float_to_string(Max@2))/binary>>/binary, " {"/utf8>>, <<" False -> "/utf8, (Max_failure(Max@2))/binary>>, <<" True -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate float exclusive range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: Float"/utf8>>, <<"Result(Float, ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 1189). ?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 -. float.truncate(value /. "/utf8, (gleam_stdlib:float_to_string(M))/binary>>/binary, " |> int.to_float) *. "/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", 1230). ?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) -> case {Min_items, Max_items} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"length"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"minItems"/utf8>>, <<<<"must have at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " items"/utf8>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"maxItems"/utf8>>, <<<<"must have at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " items"/utf8>> ) end, Lines = case {Min_items, Max_items} of {{some, Min@1}, {some, Max@1}} -> [<<" let len = list.length(value)"/utf8>>, <<<<" case len < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@1))/binary>>, <<" False ->"/utf8>>, <<<<" case len > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@1))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<" let len = list.length(value)"/utf8>>, <<<<" case len < "/utf8, (erlang:integer_to_binary(Min@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<" let len = list.length(value)"/utf8>>, <<<<" case len > "/utf8, (erlang:integer_to_binary(Max@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate list length 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(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 1299). ?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", 364). ?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", 1333). ?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 ) -> case {Min_properties, Max_properties} of {none, none} -> none; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"properties"/utf8>> ), Min_failure = fun(Min) -> validation_failure_literal( Prop_name, <<"minProperties"/utf8>>, <<<<"must have at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " properties"/utf8>> ) end, Max_failure = fun(Max) -> validation_failure_literal( Prop_name, <<"maxProperties"/utf8>>, <<<<"must have at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " properties"/utf8>> ) end, Lines = case {Min_properties, Max_properties} of {{some, Min@1}, {some, Max@1}} -> [<<" let count = dict.size(value)"/utf8>>, <<<<" case count < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@1))/binary>>, <<" False ->"/utf8>>, <<<<" case count > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@1))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>, <<" }"/utf8>>]; {{some, Min@2}, none} -> [<<" let count = dict.size(value)"/utf8>>, <<<<" case count < "/utf8, (erlang:integer_to_binary(Min@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Min_failure(Min@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, {some, Max@2}} -> [<<" let count = dict.size(value)"/utf8>>, <<<<" case count > "/utf8, (erlang:integer_to_binary(Max@2))/binary>>/binary, " {"/utf8>>, <<" True -> "/utf8, (Max_failure(Max@2))/binary>>, <<" False -> Ok(value)"/utf8>>, <<" }"/utf8>>]; {none, none} -> [] end, {some, {guard_function, Fn_name, [<<<<<<"Validate property count for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>>], <<"value: Dict(k, v)"/utf8>>, <<"Result(Dict(k, v), ValidationFailure)"/utf8>>, gleam@string:join(Lines, <<"\n"/utf8>>), field_validator}} end. -file("src/oaspec/internal/codegen/guards.gleam", 273). ?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", 256). ?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", 1403). ?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@types:schema_to_gleam_type(S, Ctx); _ -> <<"types."/utf8, (oaspec@internal@util@naming:schema_to_type_name(Name))/binary>> end. -file("src/oaspec/internal/codegen/guards.gleam", 1556). ?DOC(false). -spec collect_field_guard_calls( binary(), binary(), oaspec@internal@openapi@schema:schema_ref(), boolean(), oaspec@internal@codegen@context:context() ) -> list({binary(), binary(), boolean()}). collect_field_guard_calls(Schema_name, Prop_name, Prop_ref, Is_required, Ctx) -> 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}] end, case Pattern of none -> Calls; {some, _} -> lists:append( Calls, [{guard_function_name( Schema_name, Prop_name, <<"pattern"/utf8>> ), Accessor, Is_required}] ) 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}] 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}] ) 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}] ) 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}] 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}] ) 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}] ) end; {ok, {array_schema, _, _, 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}] end, Unique_calls = case Unique_items of true -> [{guard_function_name( Schema_name, Prop_name, <<"unique"/utf8>> ), Accessor, Is_required}]; false -> [] end, lists:append(Length_calls, Unique_calls); _ -> [] end. -file("src/oaspec/internal/codegen/guards.gleam", 1425). ?DOC(false). -spec collect_guard_calls( binary(), oaspec@internal@openapi@schema:schema_ref(), oaspec@internal@codegen@context:context() ) -> list({binary(), binary(), boolean()}). collect_guard_calls(Name, Schema_ref, Ctx) -> 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 ) end ) end, Size_calls = case {Min_properties, Max_properties} of {none, none} -> []; {_, _} -> [{guard_function_name( Name, <<""/utf8>>, <<"properties"/utf8>> ), <<"value"/utf8>>, true}] 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 ) 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}] end, case Pattern of none -> Calls; {some, _} -> lists:append( Calls, [{guard_function_name( Name, <<""/utf8>>, <<"pattern"/utf8>> ), <<"value"/utf8>>, true}] ) 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}] 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}] ) end, case Multiple_of of none -> Calls@2; {some, _} -> lists:append( Calls@2, [{guard_function_name( Name, <<""/utf8>>, <<"multiple_of"/utf8>> ), <<"value"/utf8>>, true}] ) 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}] 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}] ) 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}] ) 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}] end, Unique_calls = case Unique_items of true -> [{guard_function_name(Name, <<""/utf8>>, <<"unique"/utf8>>), <<"value"/utf8>>, true}]; 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) -> 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(Name, Schema_ref, Ctx) ); {error, _} -> false end; none -> false end. -file("src/oaspec/internal/codegen/guards.gleam", 694). ?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} = Call, case Is_required of true -> [<<<<<<<<" let errors = case "/utf8, Guard_fn/binary>>/binary, "("/utf8>>/binary, Accessor/binary>>/binary, ") {"/utf8>>, <<" Ok(_) -> errors"/utf8>>, <<" Error(failure) -> [failure, ..errors]"/utf8>>, <<" }"/utf8>>]; 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>>] 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", 534). ?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), 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, {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, {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", 511). ?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", 495). ?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", 78). ?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, Field_validators = begin _pipe@1 = gleam@list:flat_map( Schemas, fun(Entry@3) -> {Name@2, Schema_ref@2} = Entry@3, collect_guard_functions_for_schema(Name@2, Schema_ref@2, Ctx) end ), dedupe_guard_functions(_pipe@1) end, Composite_validators = gleam@list:flat_map( Schemas, fun(Entry@4) -> {Name@3, Schema_ref@3} = Entry@4, maybe_one(build_composite_guard_function(Name@3, Schema_ref@3, Ctx)) end ), {guard_module, Imports@7, lists:append(Field_validators, Composite_validators)}. -file("src/oaspec/internal/codegen/guards.gleam", 62). ?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.