Current section

Files

Jump to
oaspec src oaspec@codegen@guards.erl
Raw

src/oaspec@codegen@guards.erl

-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([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()}.
-file("src/oaspec/codegen/guards.gleam", 89).
?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,
erlang:element(2, Ctx)
)
end,
case Schema of
{ok, {string_schema, _, _, _, {some, _}, _, _, _}} ->
{constraint_types,
true,
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc)};
{ok, {string_schema, _, _, _, _, {some, _}, _, _}} ->
{constraint_types,
true,
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc)};
{ok, {integer_schema, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
true,
erlang:element(4, Acc),
erlang:element(5, Acc)};
{ok, {integer_schema, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
true,
erlang:element(4, Acc),
erlang:element(5, Acc)};
{ok, {number_schema, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc)};
{ok, {number_schema, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
true,
erlang:element(5, Acc)};
{ok, {array_schema, _, _, {some, _}, _, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true};
{ok, {array_schema, _, _, _, {some, _}, _}} ->
{constraint_types,
erlang:element(2, Acc),
erlang:element(3, Acc),
erlang:element(4, Acc),
true};
{ok, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:fold(
_pipe,
Acc,
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", 74).
?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},
fun(Acc, Entry) ->
{_, Schema_ref} = Entry,
collect_schema_constraint_types(Acc, Schema_ref, Ctx)
end
).
-file("src/oaspec/codegen/guards.gleam", 516).
?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", 535).
?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", 218).
?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,
" characters\")"/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,
" characters\")"/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,
" characters\")"/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,
" characters\")"/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", 296).
?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", 365).
?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", 434).
?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", 193).
?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,
erlang:element(2, Ctx)
)
end,
case Resolved of
{ok, {string_schema, _, _, _, Min_length, Max_length, _, _}} ->
generate_string_guard(
Sb,
Schema_name,
Prop_name,
Min_length,
Max_length
);
{ok, {integer_schema, _, _, Minimum, Maximum, _}} ->
generate_integer_guard(Sb, Schema_name, Prop_name, Minimum, Maximum);
{ok, {number_schema, _, _, Minimum@1, Maximum@1, _}} ->
generate_float_guard(
Sb,
Schema_name,
Prop_name,
Minimum@1,
Maximum@1
);
{ok, {array_schema, _, _, Min_items, Max_items, _}} ->
generate_list_guard(
Sb,
Schema_name,
Prop_name,
Min_items,
Max_items
);
_ ->
Sb
end.
-file("src/oaspec/codegen/guards.gleam", 146).
?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, _, _, _, _} ->
Props = maps:to_list(Properties),
gleam@list:fold(
Props,
Sb,
fun(Sb@1, Entry) ->
{Prop_name, Prop_ref} = Entry,
generate_field_guard(Sb@1, Name, Prop_name, Prop_ref, Ctx)
end
);
{all_of_schema, _, Schemas} ->
Merged_props = gleam@list:fold(
Schemas,
maps:new(),
fun(Acc, S_ref) -> case S_ref of
{inline, {object_schema, _, Properties@1, _, _, _, _}} ->
maps:merge(Acc, Properties@1);
{reference, _} ->
case oaspec@openapi@resolver:resolve_schema_ref(
S_ref,
erlang:element(2, Ctx)
) of
{ok,
{object_schema, _, Properties@2, _, _, _, _}} ->
maps:merge(Acc, Properties@2);
_ ->
Acc
end;
_ ->
Acc
end end
),
Props@1 = maps:to_list(Merged_props),
gleam@list:fold(
Props@1,
Sb,
fun(Sb@2, Entry@1) ->
{Prop_name@1, Prop_ref@1} = Entry@1,
generate_field_guard(
Sb@2,
Name,
Prop_name@1,
Prop_ref@1,
Ctx
)
end
);
{string_schema, _, _, _, Min_length, Max_length, _, _} ->
generate_string_guard(Sb, Name, <<""/utf8>>, Min_length, Max_length);
{integer_schema, _, _, Minimum, Maximum, _} ->
generate_integer_guard(Sb, Name, <<""/utf8>>, Minimum, Maximum);
{number_schema, _, _, Minimum@1, Maximum@1, _} ->
generate_float_guard(Sb, Name, <<""/utf8>>, Minimum@1, Maximum@1);
{array_schema, _, _, Min_items, Max_items, _} ->
generate_list_guard(Sb, Name, <<""/utf8>>, Min_items, Max_items);
_ ->
Sb
end.
-file("src/oaspec/codegen/guards.gleam", 126).
?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, Ref} ->
Resolved_name = oaspec@openapi@resolver:ref_to_name(Ref),
case oaspec@openapi@resolver:resolve_schema_ref(
Schema_ref,
erlang:element(2, 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", 26).
?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, erlang:element(2, Ctx)) of
{some, Components} ->
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
);
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(5, Constraint_types) of
true ->
[<<"gleam/list"/utf8>> | Imports@1];
false ->
Imports@1
end,
Sb = begin
_pipe = oaspec@util@string_extra:file_header(<<"0.4.0"/utf8>>),
oaspec@util@string_extra:imports(_pipe, Imports@2)
end,
Sb@2 = gleam@list:fold(
Schemas,
Sb,
fun(Sb@1, Entry) ->
{Name, Schema_ref} = Entry,
generate_guards_for_schema(Sb@1, Name, Schema_ref, Ctx)
end
),
oaspec@util@string_extra:to_string(Sb@2).
-file("src/oaspec/codegen/guards.gleam", 17).
?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}];
false ->
[]
end.