-module(oaspec@codegen@guards). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/codegen/guards.gleam"). -export([schema_has_validator/2, generate/1]). -export_type([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. -type constraint_types() :: {constraint_types, boolean(), boolean(), boolean(), boolean(), boolean(), boolean(), boolean()}. -file("src/oaspec/codegen/guards.gleam", 178). ?DOC(" Collect constraint types from a single schema ref.\n"). -spec collect_schema_constraint_types( constraint_types(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> constraint_types(). collect_schema_constraint_types(Acc, Schema_ref, Ctx) -> Schema = case Schema_ref of {inline, S} -> {ok, S}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, oaspec@codegen@context:spec(Ctx) ) end, 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) end ); {ok, {all_of_schema, _, Schemas}} -> gleam@list:fold( Schemas, Acc, fun(A@1, S@1) -> collect_schema_constraint_types(A@1, S@1, Ctx) end ); _ -> Acc end. -file("src/oaspec/codegen/guards.gleam", 163). ?DOC(" Scan all schemas to find which constraint types are present.\n"). -spec collect_constraint_types( list({binary(), oaspec@openapi@schema:schema_ref()}), oaspec@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) end ). -file("src/oaspec/codegen/guards.gleam", 463). ?DOC( " Word used in minLength/maxLength error messages.\n" " Singular when the bound is exactly one; plural otherwise.\n" ). -spec character_word(integer()) -> binary(). character_word(N) -> case N of 1 -> <<"character"/utf8>>; _ -> <<"characters"/utf8>> end. -file("src/oaspec/codegen/guards.gleam", 1112). ?DOC(" Build the guard function name from schema name, property name, and constraint type.\n"). -spec guard_function_name(binary(), binary(), binary()) -> binary(). guard_function_name(Schema_name, Prop_name, Constraint) -> Base = oaspec@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@util@naming:to_snake_case(Prop_name))/binary>>/binary, "_"/utf8>>/binary, Constraint/binary>> end. -file("src/oaspec/codegen/guards.gleam", 1131). ?DOC(" Format a field label for documentation.\n"). -spec field_label(binary()) -> binary(). field_label(Prop_name) -> case Prop_name of <<""/utf8>> -> <<""/utf8>>; _ -> <<"."/utf8, Prop_name/binary>> end. -file("src/oaspec/codegen/guards.gleam", 471). ?DOC(" Generate a string length validation guard.\n"). -spec generate_string_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_string_guard(Sb, Schema_name, Prop_name, Min_length, Max_length) -> case {Min_length, Max_length} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"length"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate string length for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: String) -> Result(String, String) {"/utf8>> ) end, Sb@3 = begin _pipe@2 = Sb@2, oaspec@util@string_extra:indent( _pipe@2, 1, <<"let len = string.length(value)"/utf8>> ) end, Sb@4 = case {Min_length, Max_length} of {{some, Min}, {some, Max}} -> _pipe@3 = Sb@3, _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 1, <<<<"case len < "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " {"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<<<<<<<"True -> Error(\"must be at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " "/utf8>>/binary, (character_word(Min))/binary>>/binary, "\")"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 2, <<"False ->"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 3, <<<<"case len > "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " {"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<<<<<<<"True -> Error(\"must be at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " "/utf8>>/binary, (character_word(Max))/binary>>/binary, "\")"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 4, <<"False -> Ok(value)"/utf8>> ), _pipe@10 = oaspec@util@string_extra:indent( _pipe@9, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@10, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@11 = Sb@3, _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 1, <<<<"case len < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<<<<<<<"True -> Error(\"must be at least "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " "/utf8>>/binary, (character_word(Min@1))/binary>>/binary, "\")"/utf8>> ), _pipe@14 = oaspec@util@string_extra:indent( _pipe@13, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@14, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@15 = Sb@3, _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 1, <<<<"case len > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<<<<<<<"True -> Error(\"must be at most "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " "/utf8>>/binary, (character_word(Max@1))/binary>>/binary, "\")"/utf8>> ), _pipe@18 = oaspec@util@string_extra:indent( _pipe@17, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@18, 1, <<"}"/utf8>>); {none, none} -> Sb@3 end, _pipe@19 = Sb@4, _pipe@20 = oaspec@util@string_extra:line(_pipe@19, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@20) end. -file("src/oaspec/codegen/guards.gleam", 557). ?DOC(" Generate an integer range validation guard.\n"). -spec generate_integer_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_integer_guard(Sb, Schema_name, Prop_name, Minimum, Maximum) -> case {Minimum, Maximum} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"range"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate integer range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Int) -> Result(Int, String) {"/utf8>> ) end, Sb@3 = case {Minimum, Maximum} of {{some, Min}, {some, Max}} -> _pipe@2 = Sb@2, _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case value < "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<<<"True -> Error(\"must be at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, "\")"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"False ->"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 3, <<<<"case value > "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " {"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 4, <<<<"True -> Error(\"must be at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, "\")"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<"False -> Ok(value)"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@9, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@10 = Sb@2, _pipe@11 = oaspec@util@string_extra:indent( _pipe@10, 1, <<<<"case value < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 2, <<<<"True -> Error(\"must be at least "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, "\")"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@13, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@14 = Sb@2, _pipe@15 = oaspec@util@string_extra:indent( _pipe@14, 1, <<<<"case value > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 2, <<<<"True -> Error(\"must be at most "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, "\")"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@17, 1, <<"}"/utf8>>); {none, none} -> Sb@2 end, _pipe@18 = Sb@3, _pipe@19 = oaspec@util@string_extra:line(_pipe@18, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@19) end. -file("src/oaspec/codegen/guards.gleam", 626). ?DOC(" Generate a float range validation guard.\n"). -spec generate_float_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(float()), gleam@option:option(float()) ) -> gleam@string_tree:string_tree(). generate_float_guard(Sb, Schema_name, Prop_name, Minimum, Maximum) -> case {Minimum, Maximum} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"range"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate float range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Float) -> Result(Float, String) {"/utf8>> ) end, Sb@3 = case {Minimum, Maximum} of {{some, Min}, {some, Max}} -> _pipe@2 = Sb@2, _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case value <. "/utf8, (gleam_stdlib:float_to_string(Min))/binary>>/binary, " {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<<<"True -> Error(\"must be at least "/utf8, (gleam_stdlib:float_to_string(Min))/binary>>/binary, "\")"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"False ->"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 3, <<<<"case value >. "/utf8, (gleam_stdlib:float_to_string(Max))/binary>>/binary, " {"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 4, <<<<"True -> Error(\"must be at most "/utf8, (gleam_stdlib:float_to_string(Max))/binary>>/binary, "\")"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<"False -> Ok(value)"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@9, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@10 = Sb@2, _pipe@11 = oaspec@util@string_extra:indent( _pipe@10, 1, <<<<"case value <. "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 2, <<<<"True -> Error(\"must be at least "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, "\")"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@13, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@14 = Sb@2, _pipe@15 = oaspec@util@string_extra:indent( _pipe@14, 1, <<<<"case value >. "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 2, <<<<"True -> Error(\"must be at most "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, "\")"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@17, 1, <<"}"/utf8>>); {none, none} -> Sb@2 end, _pipe@18 = Sb@3, _pipe@19 = oaspec@util@string_extra:line(_pipe@18, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@19) end. -file("src/oaspec/codegen/guards.gleam", 695). ?DOC(" Generate an integer exclusive range validation guard.\n"). -spec generate_integer_exclusive_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_integer_exclusive_guard( Sb, Schema_name, Prop_name, Exclusive_minimum, Exclusive_maximum ) -> case {Exclusive_minimum, Exclusive_maximum} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"exclusive_range"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate integer exclusive range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Int) -> Result(Int, String) {"/utf8>> ) end, Sb@3 = case {Exclusive_minimum, Exclusive_maximum} of {{some, Min}, {some, Max}} -> _pipe@2 = Sb@2, _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case value > "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<<<"False -> Error(\"must be greater than "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, "\")"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"True ->"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 3, <<<<"case value < "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " {"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 4, <<<<"False -> Error(\"must be less than "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, "\")"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<"True -> Ok(value)"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@9, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@10 = Sb@2, _pipe@11 = oaspec@util@string_extra:indent( _pipe@10, 1, <<<<"case value > "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 2, <<<<"False -> Error(\"must be greater than "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, "\")"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<"True -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@13, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@14 = Sb@2, _pipe@15 = oaspec@util@string_extra:indent( _pipe@14, 1, <<<<"case value < "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 2, <<<<"False -> Error(\"must be less than "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, "\")"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<"True -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@17, 1, <<"}"/utf8>>); {none, none} -> Sb@2 end, _pipe@18 = Sb@3, _pipe@19 = oaspec@util@string_extra:line(_pipe@18, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@19) end. -file("src/oaspec/codegen/guards.gleam", 769). ?DOC(" Generate an integer multipleOf validation guard.\n"). -spec generate_integer_multiple_of_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_integer_multiple_of_guard(Sb, Schema_name, Prop_name, Multiple_of) -> case Multiple_of of none -> Sb; {some, M} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"multiple_of"/utf8>> ), _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate integer multipleOf for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Int) -> Result(Int, String) {"/utf8>> ), _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case value % "/utf8, (erlang:integer_to_binary(M))/binary>>/binary, " == 0 {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<<<"False -> Error(\"must be a multiple of "/utf8, (erlang:integer_to_binary(M))/binary>>/binary, "\")"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"True -> Ok(value)"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent(_pipe@5, 1, <<"}"/utf8>>), _pipe@7 = oaspec@util@string_extra:line(_pipe@6, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@7) end. -file("src/oaspec/codegen/guards.gleam", 803). ?DOC(" Generate a float exclusive range validation guard.\n"). -spec generate_float_exclusive_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(float()), gleam@option:option(float()) ) -> gleam@string_tree:string_tree(). generate_float_exclusive_guard( Sb, Schema_name, Prop_name, Exclusive_minimum, Exclusive_maximum ) -> case {Exclusive_minimum, Exclusive_maximum} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"exclusive_range"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate float exclusive range for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Float) -> Result(Float, String) {"/utf8>> ) end, Sb@3 = case {Exclusive_minimum, Exclusive_maximum} of {{some, Min}, {some, Max}} -> _pipe@2 = Sb@2, _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case value >. "/utf8, (gleam_stdlib:float_to_string(Min))/binary>>/binary, " {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<<<"False -> Error(\"must be greater than "/utf8, (gleam_stdlib:float_to_string(Min))/binary>>/binary, "\")"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"True ->"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 3, <<<<"case value <. "/utf8, (gleam_stdlib:float_to_string(Max))/binary>>/binary, " {"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 4, <<<<"False -> Error(\"must be less than "/utf8, (gleam_stdlib:float_to_string(Max))/binary>>/binary, "\")"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<"True -> Ok(value)"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@9, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@10 = Sb@2, _pipe@11 = oaspec@util@string_extra:indent( _pipe@10, 1, <<<<"case value >. "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 2, <<<<"False -> Error(\"must be greater than "/utf8, (gleam_stdlib:float_to_string(Min@1))/binary>>/binary, "\")"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<"True -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@13, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@14 = Sb@2, _pipe@15 = oaspec@util@string_extra:indent( _pipe@14, 1, <<<<"case value <. "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 2, <<<<"False -> Error(\"must be less than "/utf8, (gleam_stdlib:float_to_string(Max@1))/binary>>/binary, "\")"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<"True -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@17, 1, <<"}"/utf8>>); {none, none} -> Sb@2 end, _pipe@18 = Sb@3, _pipe@19 = oaspec@util@string_extra:line(_pipe@18, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@19) end. -file("src/oaspec/codegen/guards.gleam", 881). ?DOC(" Generate a float multipleOf validation guard.\n"). -spec generate_float_multiple_of_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(float()) ) -> gleam@string_tree:string_tree(). generate_float_multiple_of_guard(Sb, Schema_name, Prop_name, Multiple_of) -> case Multiple_of of none -> Sb; {some, M} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"multiple_of"/utf8>> ), _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate float multipleOf for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Float) -> Result(Float, String) {"/utf8>> ), _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<<<"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>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 1, <<"case remainder == 0.0 || remainder == -0.0 {"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<<<"False -> Error(\"must be a multiple of "/utf8, (gleam_stdlib:float_to_string(M))/binary>>/binary, "\")"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 2, <<"True -> Ok(value)"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent(_pipe@6, 1, <<"}"/utf8>>), _pipe@8 = oaspec@util@string_extra:line(_pipe@7, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@8) end. -file("src/oaspec/codegen/guards.gleam", 922). ?DOC(" Generate a list length validation guard.\n"). -spec generate_list_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_list_guard(Sb, Schema_name, Prop_name, Min_items, Max_items) -> case {Min_items, Max_items} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"length"/utf8>> ), Sb@1 = begin _pipe = Sb, oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate list length for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ) end, Sb@2 = begin _pipe@1 = Sb@1, oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: List(a)) -> Result(List(a), String) {"/utf8>> ) end, Sb@3 = begin _pipe@2 = Sb@2, oaspec@util@string_extra:indent( _pipe@2, 1, <<"let len = list.length(value)"/utf8>> ) end, Sb@4 = case {Min_items, Max_items} of {{some, Min}, {some, Max}} -> _pipe@3 = Sb@3, _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 1, <<<<"case len < "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " {"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<<<"True -> Error(\"must have at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " items\")"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 2, <<"False ->"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 3, <<<<"case len > "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " {"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<<<"True -> Error(\"must have at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " items\")"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 4, <<"False -> Ok(value)"/utf8>> ), _pipe@10 = oaspec@util@string_extra:indent( _pipe@9, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@10, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@11 = Sb@3, _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 1, <<<<"case len < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<<<"True -> Error(\"must have at least "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " items\")"/utf8>> ), _pipe@14 = oaspec@util@string_extra:indent( _pipe@13, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@14, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@15 = Sb@3, _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 1, <<<<"case len > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<<<"True -> Error(\"must have at most "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " items\")"/utf8>> ), _pipe@18 = oaspec@util@string_extra:indent( _pipe@17, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@18, 1, <<"}"/utf8>>); {none, none} -> Sb@3 end, _pipe@19 = Sb@4, _pipe@20 = oaspec@util@string_extra:line(_pipe@19, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@20) end. -file("src/oaspec/codegen/guards.gleam", 1004). ?DOC(" Generate a uniqueItems validation guard.\n"). -spec generate_unique_items_guard( gleam@string_tree:string_tree(), binary(), binary(), boolean() ) -> gleam@string_tree:string_tree(). generate_unique_items_guard(Sb, Schema_name, Prop_name, Unique_items) -> gleam@bool:guard( not Unique_items, Sb, fun() -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"unique"/utf8>> ), _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate unique items for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: List(a)) -> Result(List(a), String) {"/utf8>> ), _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<"case list.length(value) == list.length(list.unique(value)) {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<"True -> Ok(value)"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<"False -> Error(\"items must be unique\")"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent(_pipe@5, 1, <<"}"/utf8>>), _pipe@7 = oaspec@util@string_extra:line(_pipe@6, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@7) end ). -file("src/oaspec/codegen/guards.gleam", 1034). ?DOC(" Generate a minProperties/maxProperties validation guard for objects.\n"). -spec generate_properties_count_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> gleam@string_tree:string_tree(). generate_properties_count_guard( Sb, Schema_name, Prop_name, Min_properties, Max_properties ) -> case {Min_properties, Max_properties} of {none, none} -> Sb; {_, _} -> Fn_name = guard_function_name( Schema_name, Prop_name, <<"properties"/utf8>> ), Sb@1 = begin _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate property count for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: Dict(k, v)) -> Result(Dict(k, v), String) {"/utf8>> ), oaspec@util@string_extra:indent( _pipe@2, 1, <<"let count = dict.size(value)"/utf8>> ) end, Sb@2 = case {Min_properties, Max_properties} of {{some, Min}, {some, Max}} -> _pipe@3 = Sb@1, _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 1, <<<<"case count < "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " {"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 2, <<<<"True -> Error(\"must have at least "/utf8, (erlang:integer_to_binary(Min))/binary>>/binary, " properties\")"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 2, <<"False ->"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 3, <<<<"case count > "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " {"/utf8>> ), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 4, <<<<"True -> Error(\"must have at most "/utf8, (erlang:integer_to_binary(Max))/binary>>/binary, " properties\")"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 4, <<"False -> Ok(value)"/utf8>> ), _pipe@10 = oaspec@util@string_extra:indent( _pipe@9, 3, <<"}"/utf8>> ), oaspec@util@string_extra:indent(_pipe@10, 1, <<"}"/utf8>>); {{some, Min@1}, none} -> _pipe@11 = Sb@1, _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 1, <<<<"case count < "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " {"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<<<"True -> Error(\"must have at least "/utf8, (erlang:integer_to_binary(Min@1))/binary>>/binary, " properties\")"/utf8>> ), _pipe@14 = oaspec@util@string_extra:indent( _pipe@13, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@14, 1, <<"}"/utf8>>); {none, {some, Max@1}} -> _pipe@15 = Sb@1, _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 1, <<<<"case count > "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " {"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<<<"True -> Error(\"must have at most "/utf8, (erlang:integer_to_binary(Max@1))/binary>>/binary, " properties\")"/utf8>> ), _pipe@18 = oaspec@util@string_extra:indent( _pipe@17, 2, <<"False -> Ok(value)"/utf8>> ), oaspec@util@string_extra:indent(_pipe@18, 1, <<"}"/utf8>>); {none, none} -> Sb@1 end, _pipe@19 = Sb@2, _pipe@20 = oaspec@util@string_extra:line(_pipe@19, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@20) end. -file("src/oaspec/codegen/guards.gleam", 1139). ?DOC(" Render a runtime string literal for generated Gleam source.\n"). -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/codegen/guards.gleam", 418). ?DOC(" Generate a string pattern validation guard.\n"). -spec generate_string_pattern_guard( gleam@string_tree:string_tree(), binary(), binary(), gleam@option:option(binary()) ) -> gleam@string_tree:string_tree(). generate_string_pattern_guard(Sb, Schema_name, Prop_name, Pattern) -> case Pattern of none -> Sb; {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_message = gleam_string_literal( <<"must match pattern: "/utf8, Pattern@1/binary>> ), _pipe = Sb, _pipe@1 = oaspec@util@string_extra:line( _pipe, <<<<<<"/// Validate string pattern for "/utf8, Schema_name/binary>>/binary, (field_label(Prop_name))/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:line( _pipe@1, <<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: String) -> Result(String, String) {"/utf8>> ), _pipe@3 = oaspec@util@string_extra:indent( _pipe@2, 1, <<<<"case regexp.from_string("/utf8, Pattern_literal/binary>>/binary, ") {"/utf8>> ), _pipe@4 = oaspec@util@string_extra:indent( _pipe@3, 2, <<"Ok(re) -> case regexp.check(re, value) {"/utf8>> ), _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 3, <<"True -> Ok(value)"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 3, <<<<"False -> Error("/utf8, Mismatch_message/binary>>/binary, ")"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent(_pipe@6, 2, <<"}"/utf8>>), _pipe@8 = oaspec@util@string_extra:indent( _pipe@7, 2, <<<<"Error(regexp.CompileError(error:, ..)) -> Error("/utf8, Invalid_pattern_prefix/binary>>/binary, " <> error)"/utf8>> ), _pipe@9 = oaspec@util@string_extra:indent(_pipe@8, 1, <<"}"/utf8>>), _pipe@10 = oaspec@util@string_extra:line(_pipe@9, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@10) end. -file("src/oaspec/codegen/guards.gleam", 340). ?DOC(" Generate a guard for a specific field based on its schema type and constraints.\n"). -spec generate_field_guard( gleam@string_tree:string_tree(), binary(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_field_guard(Sb, Schema_name, Prop_name, Prop_ref, Ctx) -> Resolved = case Prop_ref of {inline, Schema} -> {ok, Schema}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Prop_ref, oaspec@codegen@context:spec(Ctx) ) end, case Resolved of {ok, {string_schema, _, _, _, Min_length, Max_length, Pattern}} -> Sb@1 = generate_string_guard( Sb, Schema_name, Prop_name, Min_length, Max_length ), generate_string_pattern_guard(Sb@1, Schema_name, Prop_name, Pattern); {ok, {integer_schema, _, _, Minimum, Maximum, Exclusive_minimum, Exclusive_maximum, Multiple_of}} -> Sb@2 = generate_integer_guard( Sb, Schema_name, Prop_name, Minimum, Maximum ), Sb@3 = generate_integer_exclusive_guard( Sb@2, Schema_name, Prop_name, Exclusive_minimum, Exclusive_maximum ), generate_integer_multiple_of_guard( Sb@3, Schema_name, Prop_name, Multiple_of ); {ok, {number_schema, _, _, Minimum@1, Maximum@1, Exclusive_minimum@1, Exclusive_maximum@1, Multiple_of@1}} -> Sb@4 = generate_float_guard( Sb, Schema_name, Prop_name, Minimum@1, Maximum@1 ), Sb@5 = generate_float_exclusive_guard( Sb@4, Schema_name, Prop_name, Exclusive_minimum@1, Exclusive_maximum@1 ), generate_float_multiple_of_guard( Sb@5, Schema_name, Prop_name, Multiple_of@1 ); {ok, {array_schema, _, _, Min_items, Max_items, Unique_items}} -> Sb@6 = generate_list_guard( Sb, Schema_name, Prop_name, Min_items, Max_items ), generate_unique_items_guard( Sb@6, Schema_name, Prop_name, Unique_items ); _ -> Sb end. -file("src/oaspec/codegen/guards.gleam", 256). ?DOC(" Generate guard functions for fields within a schema object.\n"). -spec generate_guards_for_schema_object( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_object(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_guards_for_schema_object(Sb, Name, Schema, Ctx) -> case Schema of {object_schema, _, Properties, _, _, Min_properties, Max_properties} -> Sb@1 = generate_properties_count_guard( Sb, Name, <<""/utf8>>, Min_properties, Max_properties ), Props = oaspec@codegen@ir_build:sorted_entries(Properties), gleam@list:fold( Props, Sb@1, fun(Sb@2, Entry) -> {Prop_name, Prop_ref} = Entry, generate_field_guard(Sb@2, Name, Prop_name, Prop_ref, Ctx) end ); {all_of_schema, _, Schemas} -> Props@1 = oaspec@codegen@ir_build:sorted_entries( erlang:element( 2, oaspec@codegen@allof_merge:merge_allof_schemas(Schemas, Ctx) ) ), gleam@list:fold( Props@1, Sb, fun(Sb@3, Entry@1) -> {Prop_name@1, Prop_ref@1} = Entry@1, generate_field_guard( Sb@3, Name, Prop_name@1, Prop_ref@1, Ctx ) end ); {string_schema, _, _, _, Min_length, Max_length, Pattern} -> Sb@4 = generate_string_guard( Sb, Name, <<""/utf8>>, Min_length, Max_length ), generate_string_pattern_guard(Sb@4, Name, <<""/utf8>>, Pattern); {integer_schema, _, _, Minimum, Maximum, Exclusive_minimum, Exclusive_maximum, Multiple_of} -> Sb@5 = generate_integer_guard( Sb, Name, <<""/utf8>>, Minimum, Maximum ), Sb@6 = generate_integer_exclusive_guard( Sb@5, Name, <<""/utf8>>, Exclusive_minimum, Exclusive_maximum ), generate_integer_multiple_of_guard( Sb@6, Name, <<""/utf8>>, Multiple_of ); {number_schema, _, _, Minimum@1, Maximum@1, Exclusive_minimum@1, Exclusive_maximum@1, Multiple_of@1} -> Sb@7 = generate_float_guard( Sb, Name, <<""/utf8>>, Minimum@1, Maximum@1 ), Sb@8 = generate_float_exclusive_guard( Sb@7, Name, <<""/utf8>>, Exclusive_minimum@1, Exclusive_maximum@1 ), generate_float_multiple_of_guard( Sb@8, Name, <<""/utf8>>, Multiple_of@1 ); {array_schema, _, _, Min_items, Max_items, Unique_items} -> Sb@9 = generate_list_guard( Sb, Name, <<""/utf8>>, Min_items, Max_items ), generate_unique_items_guard(Sb@9, Name, <<""/utf8>>, Unique_items); _ -> Sb end. -file("src/oaspec/codegen/guards.gleam", 236). ?DOC(" Generate guard functions for a single schema's constrained fields.\n"). -spec generate_guards_for_schema( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_guards_for_schema(Sb, Name, Schema_ref, Ctx) -> case Schema_ref of {inline, Schema} -> generate_guards_for_schema_object(Sb, Name, Schema, Ctx); {reference, _, Name@1} -> Resolved_name = Name@1, case oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, oaspec@codegen@context:spec(Ctx) ) of {ok, Schema@1} -> generate_guards_for_schema_object( Sb, Resolved_name, Schema@1, Ctx ); _ -> Sb end end. -file("src/oaspec/codegen/guards.gleam", 1218). ?DOC(" Determine the Gleam type for the composite validator parameter.\n"). -spec composite_validator_type( binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> binary(). composite_validator_type(Name, Schema_ref, Ctx) -> Schema = case Schema_ref of {inline, S} -> {ok, S}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, oaspec@codegen@context:spec(Ctx) ) end, case Schema of {ok, {object_schema, _, _, _, _, _, _}} -> <<"types."/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>>; {ok, {all_of_schema, _, _}} -> <<"types."/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>>; {ok, S@1} -> oaspec@codegen@types:schema_to_gleam_type(S@1, Ctx); _ -> <<"types."/utf8, (oaspec@util@naming:schema_to_type_name(Name))/binary>> end. -file("src/oaspec/codegen/guards.gleam", 1377). ?DOC(" Collect guard calls for a single field.\n"). -spec collect_field_guard_calls( binary(), binary(), oaspec@openapi@schema:schema_ref(), boolean(), oaspec@codegen@context:context() ) -> list({binary(), binary(), boolean()}). collect_field_guard_calls(Schema_name, Prop_name, Prop_ref, Is_required, Ctx) -> Resolved = case Prop_ref of {inline, Schema} -> {ok, Schema}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Prop_ref, oaspec@codegen@context:spec(Ctx) ) end, Accessor = <<"value."/utf8, (oaspec@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/codegen/guards.gleam", 1243). ?DOC(" Collect all guard function calls for a schema's constrained fields.\n"). -spec collect_guard_calls( binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> list({binary(), binary(), boolean()}). collect_guard_calls(Name, Schema_ref, Ctx) -> Schema = case Schema_ref of {inline, S} -> {ok, S}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, oaspec@codegen@context:spec(Ctx) ) end, case Schema of {ok, {object_schema, _, Properties, Required, _, Min_properties, Max_properties}} -> Prop_calls = begin _pipe = oaspec@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@codegen@allof_merge:merge_allof_schemas( Schemas, Ctx ), _pipe@1 = oaspec@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/codegen/guards.gleam", 23). ?DOC( " Check whether a named component schema has a composite validator.\n" " Used by server/client generators to decide whether to emit guard calls.\n" ). -spec schema_has_validator(binary(), oaspec@codegen@context:context()) -> boolean(). schema_has_validator(Name, Ctx) -> case erlang:element(5, oaspec@codegen@context:spec(Ctx)) of {some, Components} -> case gleam_stdlib:map_get(erlang:element(2, Components), Name) of {ok, Schema_ref} -> not oaspec@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/codegen/guards.gleam", 1153). ?DOC( " Generate a composite validate function for a schema that calls all\n" " individual field validators. This enables auto-validation by calling\n" " a single function rather than individual field guards.\n" ). -spec generate_composite_validator( gleam@string_tree:string_tree(), binary(), oaspec@openapi@schema:schema_ref(), oaspec@codegen@context:context() ) -> gleam@string_tree:string_tree(). generate_composite_validator(Sb, Name, Schema_ref, Ctx) -> Guard_calls = collect_guard_calls(Name, Schema_ref, Ctx), case gleam@list:is_empty(Guard_calls) of true -> Sb; false -> Fn_name = <<"validate_"/utf8, (oaspec@util@naming:to_snake_case(Name))/binary>>, Type_name = oaspec@util@naming:schema_to_type_name(Name), Gleam_type = composite_validator_type(Name, Schema_ref, Ctx), Sb@1 = begin _pipe = Sb, _pipe@1 = oaspec@util@string_extra:doc_comment( _pipe, <<<<"Validate all constraints for "/utf8, Type_name/binary>>/binary, "."/utf8>> ), _pipe@2 = oaspec@util@string_extra:doc_comment( _pipe@1, <<"Auto-calls all field validators and collects errors."/utf8>> ), _pipe@3 = oaspec@util@string_extra:line( _pipe@2, <<<<<<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(value: "/utf8>>/binary, Gleam_type/binary>>/binary, ") -> Result("/utf8>>/binary, Gleam_type/binary>>/binary, ", List(String)) {"/utf8>> ), oaspec@util@string_extra:indent( _pipe@3, 1, <<"let errors = []"/utf8>> ) end, Sb@3 = gleam@list:fold( Guard_calls, Sb@1, fun(Sb@2, Call) -> {Guard_fn, Accessor, Is_required} = Call, case Is_required of true -> _pipe@4 = Sb@2, _pipe@5 = oaspec@util@string_extra:indent( _pipe@4, 1, <<<<<<<<"let errors = case "/utf8, Guard_fn/binary>>/binary, "("/utf8>>/binary, Accessor/binary>>/binary, ") {"/utf8>> ), _pipe@6 = oaspec@util@string_extra:indent( _pipe@5, 2, <<"Ok(_) -> errors"/utf8>> ), _pipe@7 = oaspec@util@string_extra:indent( _pipe@6, 2, <<"Error(msg) -> [msg, ..errors]"/utf8>> ), oaspec@util@string_extra:indent( _pipe@7, 1, <<"}"/utf8>> ); false -> _pipe@8 = Sb@2, _pipe@9 = oaspec@util@string_extra:indent( _pipe@8, 1, <<<<"let errors = case "/utf8, Accessor/binary>>/binary, " {"/utf8>> ), _pipe@10 = oaspec@util@string_extra:indent( _pipe@9, 2, <<<<"option.Some(v) -> case "/utf8, Guard_fn/binary>>/binary, "(v) {"/utf8>> ), _pipe@11 = oaspec@util@string_extra:indent( _pipe@10, 3, <<"Ok(_) -> errors"/utf8>> ), _pipe@12 = oaspec@util@string_extra:indent( _pipe@11, 3, <<"Error(msg) -> [msg, ..errors]"/utf8>> ), _pipe@13 = oaspec@util@string_extra:indent( _pipe@12, 2, <<"}"/utf8>> ), _pipe@14 = oaspec@util@string_extra:indent( _pipe@13, 2, <<"option.None -> errors"/utf8>> ), oaspec@util@string_extra:indent( _pipe@14, 1, <<"}"/utf8>> ) end end ), _pipe@15 = Sb@3, _pipe@16 = oaspec@util@string_extra:indent( _pipe@15, 1, <<"case errors {"/utf8>> ), _pipe@17 = oaspec@util@string_extra:indent( _pipe@16, 2, <<"[] -> Ok(value)"/utf8>> ), _pipe@18 = oaspec@util@string_extra:indent( _pipe@17, 2, <<"_ -> Error(errors)"/utf8>> ), _pipe@19 = oaspec@util@string_extra:indent( _pipe@18, 1, <<"}"/utf8>> ), _pipe@20 = oaspec@util@string_extra:line(_pipe@19, <<"}"/utf8>>), oaspec@util@string_extra:blank_line(_pipe@20) end. -file("src/oaspec/codegen/guards.gleam", 54). ?DOC(" Generate validation guard functions for schemas with constraints.\n"). -spec generate_guards(oaspec@codegen@context:context()) -> binary(). generate_guards(Ctx) -> Schemas = case erlang:element(5, oaspec@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@codegen@ir_build:is_internal_schema( erlang:element(2, Entry) ) end ); none -> [] end, Constraint_types = collect_constraint_types(Schemas, Ctx), Imports = [], 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 = case Schema_ref of {inline, S} -> {ok, S}; {reference, _, _} -> oaspec@openapi@resolver:resolve_schema_ref( Schema_ref, oaspec@codegen@context:spec(Ctx) ) end, 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@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, Sb = begin _pipe@1 = oaspec@util@string_extra:file_header(<<"0.20.0"/utf8>>), oaspec@util@string_extra:imports(_pipe@1, Imports@7) end, Sb@2 = gleam@list:fold( Schemas, Sb, fun(Sb@1, Entry@3) -> {Name@2, Schema_ref@2} = Entry@3, generate_guards_for_schema(Sb@1, Name@2, Schema_ref@2, Ctx) end ), Sb@4 = gleam@list:fold( Schemas, Sb@2, fun(Sb@3, Entry@4) -> {Name@3, Schema_ref@3} = Entry@4, generate_composite_validator(Sb@3, Name@3, Schema_ref@3, Ctx) end ), oaspec@util@string_extra:to_string(Sb@4). -file("src/oaspec/codegen/guards.gleam", 38). ?DOC(" Generate guard/validation functions from OpenAPI schemas that have constraints.\n"). -spec generate(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()). generate(Ctx) -> Content = generate_guards(Ctx), case gleam_stdlib:contains_string(Content, <<"pub fn validate_"/utf8>>) of true -> [{generated_file, <<"guards.gleam"/utf8>>, Content, shared_target, overwrite}]; false -> [] end.