Current section

Files

Jump to
oaspec src oaspec@internal@codegen@validate.erl
Raw

src/oaspec@internal@codegen@validate.erl

-module(oaspec@internal@codegen@validate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/internal/codegen/validate.gleam").
-export([errors_only/1, warnings_only/1, filter_by_mode/2, error_to_string/1, validate/1]).
-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).
-file("src/oaspec/internal/codegen/validate.gleam", 55).
?DOC(false).
-spec validate_decode_list_collisions(oaspec@internal@codegen@context:context()) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_decode_list_collisions(Ctx) ->
Schema_names = case erlang:element(
5,
oaspec@internal@codegen@context:spec(Ctx)
) of
{some, Components} ->
_pipe = maps:to_list(erlang:element(2, Components)),
gleam@list:map(_pipe, fun(Entry) -> erlang:element(1, Entry) end);
none ->
[]
end,
gleam@list:filter_map(
Schema_names,
fun(Base_name) ->
Collider_name = <<Base_name/binary, "List"/utf8>>,
case gleam@list:contains(Schema_names, Collider_name) of
false ->
{error, nil};
true ->
Snake = oaspec@internal@util@naming:to_snake_case(Base_name),
{ok,
oaspec@openapi@diagnostic:validation(
<<"components.schemas."/utf8, Collider_name/binary>>,
<<<<<<<<<<<<<<<<<<<<"Schema name '"/utf8,
Collider_name/binary>>/binary,
"' would generate decode_"/utf8>>/binary,
Snake/binary>>/binary,
"_list, which collides with the synthetic list decoder for '"/utf8>>/binary,
Base_name/binary>>/binary,
"' (a JSON array of "/utf8>>/binary,
Base_name/binary>>/binary,
"). gleam build will fail with `Duplicate definition: decode_"/utf8>>/binary,
Snake/binary>>/binary,
"_list`."/utf8>>,
severity_error,
target_both,
{some,
<<<<<<<<<<<<<<<<"Rename one of the schemas. Example: rename '"/utf8,
Collider_name/binary>>/binary,
"' to '"/utf8>>/binary,
Base_name/binary>>/binary,
"Collection', '"/utf8>>/binary,
Base_name/binary>>/binary,
"Page', or '"/utf8>>/binary,
Base_name/binary>>/binary,
"Items'."/utf8>>}
)}
end
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 143).
?DOC(false).
-spec group_operations_by_id(
list({binary(),
oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()),
binary(),
oaspec@internal@openapi@spec:http_method()}),
fun((binary()) -> binary())
) -> gleam@dict:dict(binary(), list(binary())).
group_operations_by_id(Operations, Key_fn) ->
gleam@list:fold(
Operations,
maps:new(),
fun(Acc, Entry) ->
{Op_id, _, Path, Method} = Entry,
Key = Key_fn(Op_id),
Site = <<<<(string:uppercase(
oaspec@internal@openapi@spec:method_to_string(Method)
))/binary,
" "/utf8>>/binary,
Path/binary>>,
case gleam_stdlib:map_get(Acc, Key) of
{ok, Existing} ->
gleam@dict:insert(Acc, Key, lists:append(Existing, [Site]));
{error, _} ->
gleam@dict:insert(Acc, Key, [Site])
end
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 159).
?DOC(false).
-spec duplicate_operation_id_diagnostic(binary(), list(binary())) -> oaspec@openapi@diagnostic:diagnostic().
duplicate_operation_id_diagnostic(Op_id, Sites) ->
oaspec@openapi@diagnostic:invalid_value(
<<"paths.*.operationId"/utf8>>,
<<<<<<<<<<"Duplicate operationId '"/utf8, Op_id/binary>>/binary,
"' found on: "/utf8>>/binary,
(gleam@string:join(Sites, <<", "/utf8>>))/binary>>/binary,
". operationId must be unique across the entire spec; "/utf8>>/binary,
"rename one of the operations to keep the generated API stable."/utf8>>,
no_source_loc
).
-file("src/oaspec/internal/codegen/validate.gleam", 175).
?DOC(false).
-spec duplicate_function_name_diagnostic(binary(), list(binary())) -> oaspec@openapi@diagnostic:diagnostic().
duplicate_function_name_diagnostic(Fn_name, Sites) ->
oaspec@openapi@diagnostic:invalid_value(
<<"paths.*.operationId"/utf8>>,
<<<<<<<<<<"operationIds that normalize to the same generated function name '"/utf8,
Fn_name/binary>>/binary,
"' found on: "/utf8>>/binary,
(gleam@string:join(Sites, <<", "/utf8>>))/binary>>/binary,
". oaspec converts operationIds to snake_case, so values like "/utf8>>/binary,
"'listItems' and 'list_items' collide; rename one of them."/utf8>>,
no_source_loc
).
-file("src/oaspec/internal/codegen/validate.gleam", 103).
?DOC(false).
-spec validate_unique_operation_ids(
list({binary(),
oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()),
binary(),
oaspec@internal@openapi@spec:http_method()})
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_unique_operation_ids(Operations) ->
Literal = group_operations_by_id(Operations, fun(Op_id) -> Op_id end),
By_function = group_operations_by_id(
Operations,
fun oaspec@internal@util@naming:operation_to_function_name/1
),
Literal_errors = begin
_pipe = maps:to_list(Literal),
gleam@list:filter_map(
_pipe,
fun(Entry) ->
{Op_id@1, Sites} = Entry,
case Sites of
[_, _ | _] ->
{ok, duplicate_operation_id_diagnostic(Op_id@1, Sites)};
_ ->
{error, nil}
end
end
)
end,
Function_errors = begin
_pipe@1 = maps:to_list(By_function),
gleam@list:filter_map(
_pipe@1,
fun(Entry@1) ->
{Fn_name, Sites@1} = Entry@1,
case Sites@1 of
[_, _ | _] ->
case gleam_stdlib:map_get(Literal, Fn_name) of
{ok, Literal_sites} when Literal_sites =:= Sites@1 ->
{error, nil};
_ ->
{ok,
duplicate_function_name_diagnostic(
Fn_name,
Sites@1
)}
end;
_ ->
{error, nil}
end
end
)
end,
lists:append(Literal_errors, Function_errors).
-file("src/oaspec/internal/codegen/validate.gleam", 192).
?DOC(false).
-spec errors_only(list(oaspec@openapi@diagnostic:diagnostic())) -> list(oaspec@openapi@diagnostic:diagnostic()).
errors_only(Issues) ->
oaspec@openapi@diagnostic:errors_only(Issues).
-file("src/oaspec/internal/codegen/validate.gleam", 197).
?DOC(false).
-spec warnings_only(list(oaspec@openapi@diagnostic:diagnostic())) -> list(oaspec@openapi@diagnostic:diagnostic()).
warnings_only(Issues) ->
oaspec@openapi@diagnostic:warnings_only(Issues).
-file("src/oaspec/internal/codegen/validate.gleam", 202).
?DOC(false).
-spec filter_by_mode(
list(oaspec@openapi@diagnostic:diagnostic()),
oaspec@config:generate_mode()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
filter_by_mode(Issues, Mode) ->
oaspec@openapi@diagnostic:filter_by_mode(Issues, Mode).
-file("src/oaspec/internal/codegen/validate.gleam", 210).
?DOC(false).
-spec error_to_string(oaspec@openapi@diagnostic:diagnostic()) -> binary().
error_to_string(Error) ->
oaspec@openapi@diagnostic:to_string(Error).
-file("src/oaspec/internal/codegen/validate.gleam", 308).
?DOC(false).
-spec extract_path_template_names(binary()) -> list(binary()).
extract_path_template_names(Path) ->
Re@1 = case gleam@regexp:from_string(<<"\\{([^}]+)\\}"/utf8>>) of
{ok, Re} -> Re;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/validate"/utf8>>,
function => <<"extract_path_template_names"/utf8>>,
line => 310,
value => _assert_fail,
start => 10970,
'end' => 11025,
pattern_start => 10981,
pattern_end => 10987})
end,
_pipe = gleam@regexp:scan(Re@1, Path),
gleam@list:filter_map(_pipe, fun(Match) -> case erlang:element(3, Match) of
[{some, Name}] ->
{ok, Name};
_ ->
{error, nil}
end end).
-file("src/oaspec/internal/codegen/validate.gleam", 266).
?DOC(false).
-spec validate_path_template_params(
binary(),
binary(),
list(oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()))
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_path_template_params(Op_id, Path, Params) ->
Template_names = extract_path_template_names(Path),
Path_param_names = gleam@list:filter_map(
Params,
fun(P) -> case erlang:element(3, P) of
in_path ->
{ok, erlang:element(2, P)};
_ ->
{error, nil}
end end
),
gleam@list:filter_map(
Template_names,
fun(Name) -> case gleam@list:contains(Path_param_names, Name) of
true ->
{error, nil};
false ->
Defined = case Path_param_names of
[] ->
<<""/utf8>>;
Names ->
<<<<" Defined path parameters: "/utf8,
(gleam@string:join(Names, <<", "/utf8>>))/binary>>/binary,
"."/utf8>>
end,
{ok,
oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".path"/utf8>>,
<<<<<<<<"Path template parameter '{"/utf8,
Name/binary>>/binary,
"}' in '"/utf8>>/binary,
Path/binary>>/binary,
"' has no corresponding parameter definition."/utf8>>,
severity_error,
target_both,
{some,
<<"Add a parameter definition with 'in: path' for this variable, or remove it from the path template."/utf8,
Defined/binary>>}
)}
end end
).
-file("src/oaspec/internal/codegen/validate.gleam", 543).
?DOC(false).
-spec validate_server_cookie_param(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_cookie_param(_, _, _) ->
[].
-file("src/oaspec/internal/codegen/validate.gleam", 655).
?DOC(false).
-spec resolve_schema_object(
gleam@option:option(oaspec@internal@openapi@schema:schema_ref()),
oaspec@internal@codegen@context:context()
) -> gleam@option:option(oaspec@internal@openapi@schema:schema_object()).
resolve_schema_object(Schema_ref, Ctx) ->
case Schema_ref of
{some, {inline, Schema_obj}} ->
{some, Schema_obj};
{some, Schema_ref@1} ->
case oaspec@internal@openapi@resolver:resolve_schema_ref(
Schema_ref@1,
oaspec@internal@codegen@context:spec(Ctx)
) of
{ok, Schema_obj@1} ->
{some, Schema_obj@1};
{error, _} ->
none
end;
none ->
none
end.
-file("src/oaspec/internal/codegen/validate.gleam", 384).
?DOC(false).
-spec validate_delimited_style(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
binary(),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_delimited_style(Path, Param, Style_name, Ctx) ->
Location_errors = case erlang:element(3, Param) of
in_query ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<<<"Parameter style '"/utf8, Style_name/binary>>/binary,
"' is only supported for 'in: query'."/utf8>>,
severity_error,
target_both,
{some,
<<"Move this parameter to 'in: query' or switch to a style valid for its location."/utf8>>}
)]
end,
Schema_errors = case resolve_schema_object(
oaspec@internal@openapi@spec:parameter_schema(Param),
Ctx
) of
{some, {array_schema, _, _, _, _, _}} ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<<<"Parameter style '"/utf8, Style_name/binary>>/binary,
"' requires an array schema."/utf8>>,
severity_error,
target_both,
{some,
<<"Change the schema to 'type: array' or switch to style 'form'."/utf8>>}
)]
end,
lists:append([Location_errors, Schema_errors]).
-file("src/oaspec/internal/codegen/validate.gleam", 514).
?DOC(false).
-spec deep_object_server_leaf_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
deep_object_server_leaf_supported(Schema_ref, Ctx) ->
case Schema_ref of
{inline, {string_schema, _, _, _, _, _, _}} ->
true;
{inline, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{inline, {number_schema, _, _, _, _, _, _, _}} ->
true;
{inline, {boolean_schema, _}} ->
true;
{inline,
{array_schema,
_,
{inline, {string_schema, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{inline,
{array_schema,
_,
{inline, {integer_schema, _, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{inline,
{array_schema,
_,
{inline, {number_schema, _, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{inline, {array_schema, _, {inline, {boolean_schema, _}}, _, _, _}} ->
true;
{reference, _, _} ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
{some,
{array_schema,
_,
{inline, {string_schema, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{some,
{array_schema,
_,
{inline, {integer_schema, _, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{some,
{array_schema,
_,
{inline, {number_schema, _, _, _, _, _, _, _}},
_,
_,
_}} ->
true;
{some,
{array_schema, _, {inline, {boolean_schema, _}}, _, _, _}} ->
true;
_ ->
false
end;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 478).
?DOC(false).
-spec validate_server_deep_object_param(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_deep_object_param(Path, Param, Ctx) ->
case {erlang:element(3, Param),
erlang:element(7, Param),
resolve_schema_object(
oaspec@internal@openapi@spec:parameter_schema(Param),
Ctx
)} of
{in_query,
{some, deep_object_style},
{some, {object_schema, _, Properties, _, _, _, _}}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Prop_name, Prop_ref} = Entry,
case deep_object_server_leaf_supported(Prop_ref, Ctx) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"deepObject properties are only supported for inline primitive scalars and inline primitive array leaves in server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Simplify deepObject properties to primitive scalars or primitive arrays."/utf8>>}
)]
end
end
);
{_, _, _} ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 427).
?DOC(false).
-spec validate_server_structured_param(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_structured_param(Path, Param, Ctx) ->
case oaspec@config:mode(oaspec@internal@codegen@context:config(Ctx)) of
client ->
[];
_ ->
Schema_obj = resolve_schema_object(
oaspec@internal@openapi@spec:parameter_schema(Param),
Ctx
),
Array_errors = case {erlang:element(3, Param), Schema_obj} of
{in_query,
{some,
{array_schema,
_,
{inline, {string_schema, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_query,
{some,
{array_schema,
_,
{inline, {integer_schema, _, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_query,
{some,
{array_schema,
_,
{inline, {number_schema, _, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_query,
{some,
{array_schema,
_,
{inline, {boolean_schema, _}},
_,
_,
_}}} ->
[];
{in_query, {some, {array_schema, _, _, _, _, _}}} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Query array parameters are only supported for inline primitive items in server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use inline primitive items (string, integer, number, boolean) for array query parameters."/utf8>>}
)];
{in_header,
{some,
{array_schema,
_,
{inline, {string_schema, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_header,
{some,
{array_schema,
_,
{inline, {integer_schema, _, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_header,
{some,
{array_schema,
_,
{inline, {number_schema, _, _, _, _, _, _, _}},
_,
_,
_}}} ->
[];
{in_header,
{some,
{array_schema,
_,
{inline, {boolean_schema, _}},
_,
_,
_}}} ->
[];
{in_header, {some, {array_schema, _, _, _, _, _}}} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Header array parameters are only supported for inline primitive items in server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use inline primitive items (string, integer, number, boolean) for array header parameters."/utf8>>}
)];
{_, _} ->
[]
end,
Deep_object_errors = validate_server_deep_object_param(
Path,
Param,
Ctx
),
lists:append([Array_errors, Deep_object_errors])
end.
-file("src/oaspec/internal/codegen/validate.gleam", 623).
?DOC(false).
-spec validate_deep_object_no_nested_objects(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_deep_object_no_nested_objects(Path, Param, Ctx) ->
case resolve_schema_object(
oaspec@internal@openapi@spec:parameter_schema(Param),
Ctx
) of
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Prop_name, Prop_ref} = Entry,
case resolve_schema_object({some, Prop_ref}, Ctx) of
{some, {object_schema, _, _, _, _, _, _}} ->
[oaspec@openapi@diagnostic:validation(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested object properties in deepObject parameters are not supported. Only one level of object nesting is supported (e.g., filter[name]=value)."/utf8>>,
severity_error,
target_both,
{some,
<<"Flatten the property structure to a single level of nesting."/utf8>>}
)];
{some, {all_of_schema, _, _}} ->
[oaspec@openapi@diagnostic:validation(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested object properties in deepObject parameters are not supported. Only one level of object nesting is supported (e.g., filter[name]=value)."/utf8>>,
severity_error,
target_both,
{some,
<<"Flatten the property structure to a single level of nesting."/utf8>>}
)];
{some, {one_of_schema, _, _, _}} ->
[oaspec@openapi@diagnostic:validation(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested object properties in deepObject parameters are not supported. Only one level of object nesting is supported (e.g., filter[name]=value)."/utf8>>,
severity_error,
target_both,
{some,
<<"Flatten the property structure to a single level of nesting."/utf8>>}
)];
{some, {any_of_schema, _, _, _}} ->
[oaspec@openapi@diagnostic:validation(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested object properties in deepObject parameters are not supported. Only one level of object nesting is supported (e.g., filter[name]=value)."/utf8>>,
severity_error,
target_both,
{some,
<<"Flatten the property structure to a single level of nesting."/utf8>>}
)];
_ ->
[]
end
end
);
_ ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 572).
?DOC(false).
-spec validate_complex_param_schema(
binary(),
oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_complex_param_schema(Path, Param, Ctx) ->
case erlang:element(7, Param) of
{some, deep_object_style} ->
validate_deep_object_no_nested_objects(Path, Param, Ctx);
_ ->
case resolve_schema_object(
oaspec@internal@openapi@spec:parameter_schema(Param),
Ctx
) of
{some, {object_schema, _, _, _, _, _, _}} ->
case erlang:element(3, Param) of
in_path ->
case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex schema (object/oneOf/allOf/anyOf) parameter has no explicit 'style'; falling back to form-style serialization. This works for oneOf-of-primitives and shallow objects but may not match the spec author's intent for deeply nested objects."/utf8>>,
severity_warning,
target_both,
{some,
<<"Declare 'style: deepObject' explicitly if the parameter encodes a structured object."/utf8>>}
)]
end;
{some, {all_of_schema, _, _}} ->
case erlang:element(3, Param) of
in_path ->
case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex schema (object/oneOf/allOf/anyOf) parameter has no explicit 'style'; falling back to form-style serialization. This works for oneOf-of-primitives and shallow objects but may not match the spec author's intent for deeply nested objects."/utf8>>,
severity_warning,
target_both,
{some,
<<"Declare 'style: deepObject' explicitly if the parameter encodes a structured object."/utf8>>}
)]
end;
{some, {one_of_schema, _, _, _}} ->
case erlang:element(3, Param) of
in_path ->
case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex schema (object/oneOf/allOf/anyOf) parameter has no explicit 'style'; falling back to form-style serialization. This works for oneOf-of-primitives and shallow objects but may not match the spec author's intent for deeply nested objects."/utf8>>,
severity_warning,
target_both,
{some,
<<"Declare 'style: deepObject' explicitly if the parameter encodes a structured object."/utf8>>}
)]
end;
{some, {any_of_schema, _, _, _}} ->
case erlang:element(3, Param) of
in_path ->
case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Complex schema (object/oneOf/allOf/anyOf) parameter has no explicit 'style'; falling back to form-style serialization. This works for oneOf-of-primitives and shallow objects but may not match the spec author's intent for deeply nested objects."/utf8>>,
severity_warning,
target_both,
{some,
<<"Declare 'style: deepObject' explicitly if the parameter encodes a structured object."/utf8>>}
)]
end;
_ ->
[]
end
end.
-file("src/oaspec/internal/codegen/validate.gleam", 324).
?DOC(false).
-spec validate_parameters(
binary(),
list(oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:resolved())),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_parameters(Op_id, Params, Ctx) ->
gleam@list:flat_map(
Params,
fun(P) ->
Path = <<<<Op_id/binary, ".parameters."/utf8>>/binary,
(erlang:element(2, P))/binary>>,
Style_errors = case erlang:element(7, P) of
{some, matrix_style} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Parameter style is not supported. Supported styles: form, simple, deepObject, pipeDelimited, spaceDelimited."/utf8>>,
severity_error,
target_both,
{some,
<<"Use style 'form', 'simple', 'deepObject', 'pipeDelimited', or 'spaceDelimited' instead."/utf8>>}
)];
{some, label_style} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Parameter style is not supported. Supported styles: form, simple, deepObject, pipeDelimited, spaceDelimited."/utf8>>,
severity_error,
target_both,
{some,
<<"Use style 'form', 'simple', 'deepObject', 'pipeDelimited', or 'spaceDelimited' instead."/utf8>>}
)];
{some, pipe_delimited_style} ->
validate_delimited_style(
Path,
P,
<<"pipeDelimited"/utf8>>,
Ctx
);
{some, space_delimited_style} ->
validate_delimited_style(
Path,
P,
<<"spaceDelimited"/utf8>>,
Ctx
);
_ ->
[]
end,
Content_errors = case erlang:element(6, P) of
{parameter_content, _} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<"Parameters using 'content' instead of 'schema' are not supported."/utf8>>,
severity_error,
target_both,
{some,
<<"Replace the 'content' field with a 'schema' field in the parameter definition."/utf8>>}
)];
{parameter_schema, _} ->
[]
end,
Complex_schema_errors = validate_complex_param_schema(Path, P, Ctx),
Server_structured_param_errors = validate_server_structured_param(
Path,
P,
Ctx
),
Cookie_errors = validate_server_cookie_param(Path, P, Ctx),
lists:append(
[Style_errors,
Content_errors,
Complex_schema_errors,
Server_structured_param_errors,
Cookie_errors]
)
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 800).
?DOC(false).
-spec validate_form_urlencoded_schema(
binary(),
gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_form_urlencoded_schema(Op_id, Content, Ctx) ->
case gleam_stdlib:map_get(
Content,
<<"application/x-www-form-urlencoded"/utf8>>
) of
{ok, Media_type} ->
case resolve_schema_object(erlang:element(2, Media_type), Ctx) of
{some, {object_schema, _, _, _, _, _, _}} ->
[];
{some, _} ->
[oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"application/x-www-form-urlencoded request bodies must use an object schema."/utf8>>,
severity_error,
target_both,
{some,
<<"Wrap fields in an object schema with properties for each form field."/utf8>>}
)];
none ->
[]
end;
{error, _} ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 891).
?DOC(false).
-spec validate_server_request_body_content_types(
binary(),
list(binary()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_request_body_content_types(Op_id, Content_keys, Ctx) ->
case oaspec@config:mode(oaspec@internal@codegen@context:config(Ctx)) of
client ->
[];
_ ->
Non_json_but_supported = gleam@list:filter(
Content_keys,
fun(Key) ->
(((((Key /= <<"application/json"/utf8>>) andalso (Key /= <<"application/x-www-form-urlencoded"/utf8>>))
andalso (Key /= <<"multipart/form-data"/utf8>>))
andalso (Key /= <<"application/octet-stream"/utf8>>))
andalso (Key /= <<"text/plain"/utf8>>))
andalso oaspec@internal@util@content_type:is_supported_request(
oaspec@internal@util@content_type:from_string(Key)
)
end
),
gleam@list:map(
Non_json_but_supported,
fun(Media_type) ->
oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<<<"Content type '"/utf8, Media_type/binary>>/binary,
"' is not supported for server code generation. Server router only supports application/json request bodies with typed decoding."/utf8>>,
severity_error,
target_server,
{some,
<<"Use application/json for typed server request bodies, or multipart/form-data, application/x-www-form-urlencoded, or application/octet-stream for non-JSON payloads."/utf8>>}
)
end
)
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1004).
?DOC(false).
-spec form_urlencoded_server_array_item_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
form_urlencoded_server_array_item_supported(Schema_ref, Ctx) ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 982).
?DOC(false).
-spec form_urlencoded_server_field_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context(),
integer()
) -> boolean().
form_urlencoded_server_field_supported(Schema_ref, Ctx, Depth) ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
{some, {array_schema, _, Items, _, _, _}} ->
form_urlencoded_server_array_item_supported(Items, Ctx);
{some, {object_schema, _, Properties, _, _, _, _}} when Depth < 5 ->
_pipe = maps:to_list(Properties),
gleam@list:all(
_pipe,
fun(Entry) ->
{_, Child_schema} = Entry,
form_urlencoded_server_field_supported(
Child_schema,
Ctx,
Depth + 1
)
end
);
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 832).
?DOC(false).
-spec validate_server_form_urlencoded_request_body(
binary(),
gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type()),
list(binary()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_form_urlencoded_request_body(Op_id, Content, Content_keys, Ctx) ->
case oaspec@config:mode(oaspec@internal@codegen@context:config(Ctx)) of
client ->
[];
_ ->
case gleam_stdlib:map_get(
Content,
<<"application/x-www-form-urlencoded"/utf8>>
) of
{ok, Media_type} ->
Content_type_errors = case erlang:length(Content_keys) > 1 of
true ->
[oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"application/x-www-form-urlencoded request bodies are only supported as the sole request content type for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Remove other content type definitions from this operation's request body."/utf8>>}
)];
false ->
[]
end,
Field_errors = case resolve_schema_object(
erlang:element(2, Media_type),
Ctx
) of
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Field_name, Field_schema} = Entry,
case form_urlencoded_server_field_supported(
Field_schema,
Ctx,
0
) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation(
<<<<Op_id/binary,
".requestBody.form."/utf8>>/binary,
Field_name/binary>>,
<<"application/x-www-form-urlencoded server request bodies only support primitive scalars, primitive arrays, and nested objects with primitive leaves (max 5 levels)."/utf8>>,
severity_error,
target_server,
{some,
<<"Simplify to primitive scalars, primitive arrays, or shallow nested objects."/utf8>>}
)]
end
end
);
_ ->
[]
end,
lists:append(Content_type_errors, Field_errors);
{error, _} ->
[]
end
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1029).
?DOC(false).
-spec multipart_server_array_item_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
multipart_server_array_item_supported(Schema_ref, Ctx) ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1017).
?DOC(false).
-spec multipart_server_field_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
multipart_server_field_supported(Schema_ref, Ctx) ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
{some, {array_schema, _, Items, _, _, _}} ->
multipart_server_array_item_supported(Items, Ctx);
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 925).
?DOC(false).
-spec validate_server_multipart_request_body(
binary(),
gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type()),
list(binary()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_server_multipart_request_body(Op_id, Content, Content_keys, Ctx) ->
case oaspec@config:mode(oaspec@internal@codegen@context:config(Ctx)) of
client ->
[];
_ ->
case gleam_stdlib:map_get(Content, <<"multipart/form-data"/utf8>>) of
{ok, Media_type} ->
Content_type_errors = case erlang:length(Content_keys) > 1 of
true ->
[oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"multipart/form-data request bodies are only supported as the sole request content type for server code generation."/utf8>>,
severity_error,
target_server,
{some,
<<"Remove other content type definitions from this operation's request body."/utf8>>}
)];
false ->
[]
end,
Field_errors = case resolve_schema_object(
erlang:element(2, Media_type),
Ctx
) of
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Field_name, Field_schema} = Entry,
case multipart_server_field_supported(
Field_schema,
Ctx
) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation(
<<<<Op_id/binary,
".requestBody.multipart."/utf8>>/binary,
Field_name/binary>>,
<<"multipart/form-data server request bodies only support primitive scalar fields."/utf8>>,
severity_error,
target_server,
{some,
<<"Use primitive scalar types or arrays of primitive scalars (string, integer, number, boolean) for multipart form fields."/utf8>>}
)]
end
end
);
_ ->
[]
end,
lists:append(Content_type_errors, Field_errors);
{error, _} ->
[]
end
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1042).
?DOC(false).
-spec multipart_field_is_stringifiable(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
multipart_field_is_stringifiable(Schema_ref, Ctx) ->
case resolve_schema_object({some, Schema_ref}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 753).
?DOC(false).
-spec validate_multipart_request_body_fields(
binary(),
gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type()),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_multipart_request_body_fields(Op_id, Content, Ctx) ->
case gleam_stdlib:map_get(Content, <<"multipart/form-data"/utf8>>) of
{ok, Media_type} ->
case resolve_schema_object(erlang:element(2, Media_type), Ctx) of
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Field_name, Field_schema} = Entry,
case multipart_field_is_stringifiable(
Field_schema,
Ctx
) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation(
<<<<Op_id/binary,
".requestBody.multipart."/utf8>>/binary,
Field_name/binary>>,
<<"multipart/form-data fields must be string, integer, number, boolean, binary, or string enums."/utf8>>,
severity_error,
target_both,
{some,
<<"Use a primitive scalar type, binary, or string enum for multipart fields."/utf8>>}
)]
end
end
);
{some, _} ->
[oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"multipart/form-data request bodies must use an object schema."/utf8>>,
severity_error,
target_both,
{some,
<<"Wrap fields in an object schema with properties for each form field."/utf8>>}
)];
none ->
[]
end;
{error, _} ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1098).
?DOC(false).
-spec validate_unique_schema_names(oaspec@internal@codegen@context:context()) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_unique_schema_names(Ctx) ->
Schemas = case erlang:element(5, oaspec@internal@codegen@context:spec(Ctx)) of
{some, Components} ->
maps:keys(erlang:element(2, Components));
none ->
[]
end,
By_type_name = gleam@list:fold(
Schemas,
maps:new(),
fun(Acc, Name) ->
Key = oaspec@internal@util@naming:schema_to_type_name(Name),
case gleam_stdlib:map_get(Acc, Key) of
{ok, Existing} ->
gleam@dict:insert(Acc, Key, [Name | Existing]);
{error, _} ->
gleam@dict:insert(Acc, Key, [Name])
end
end
),
_pipe = maps:to_list(By_type_name),
gleam@list:filter_map(
_pipe,
fun(Entry) ->
{Type_name, Names} = Entry,
case Names of
[_, _ | _] ->
{ok,
oaspec@openapi@diagnostic:invalid_value(
<<"components.schemas"/utf8>>,
<<<<<<<<"Schema names "/utf8,
(gleam@string:join(
gleam@list:map(
Names,
fun(N) ->
<<<<"\""/utf8,
N/binary>>/binary,
"\""/utf8>>
end
),
<<", "/utf8>>
))/binary>>/binary,
" all map to Gleam type `"/utf8>>/binary,
Type_name/binary>>/binary,
"` — rename one to avoid the collision"/utf8>>,
no_source_loc
)};
_ ->
{error, nil}
end
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 1152).
?DOC(false).
-spec is_url_style_ref(binary()) -> boolean().
is_url_style_ref(Ref) ->
gleam_stdlib:string_starts_with(Ref, <<"http://"/utf8>>) orelse gleam_stdlib:string_starts_with(
Ref,
<<"https://"/utf8>>
).
-file("src/oaspec/internal/codegen/validate.gleam", 1276).
?DOC(false).
-spec validate_security_schemes(
oaspec@internal@codegen@context:context(),
list({binary(),
oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()),
binary(),
oaspec@internal@openapi@spec:http_method()})
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_security_schemes(Ctx, Operations) ->
Scheme_names = case erlang:element(
5,
oaspec@internal@codegen@context:spec(Ctx)
) of
{some, Components} ->
maps:keys(erlang:element(6, Components));
none ->
[]
end,
Global_errors = gleam@list:flat_map(
erlang:element(7, oaspec@internal@codegen@context:spec(Ctx)),
fun(Req) ->
gleam@list:filter_map(
erlang:element(2, Req),
fun(Scheme_ref) ->
case gleam@list:contains(
Scheme_names,
erlang:element(2, Scheme_ref)
) of
true ->
{error, nil};
false ->
{ok,
oaspec@openapi@diagnostic:validation(
<<"security."/utf8,
(erlang:element(2, Scheme_ref))/binary>>,
<<<<"Security requirement references scheme '"/utf8,
(erlang:element(2, Scheme_ref))/binary>>/binary,
"' which is not defined in components.securitySchemes."/utf8>>,
severity_error,
target_both,
{some,
<<"Add the security scheme definition to components.securitySchemes or fix the scheme name."/utf8>>}
)}
end
end
)
end
),
Operation_errors = gleam@list:flat_map(
Operations,
fun(Op) ->
{Op_id, Operation, _, _} = Op,
case erlang:element(10, Operation) of
{some, Reqs} ->
gleam@list:flat_map(
Reqs,
fun(Req@1) ->
gleam@list:filter_map(
erlang:element(2, Req@1),
fun(Scheme_ref@1) ->
case gleam@list:contains(
Scheme_names,
erlang:element(2, Scheme_ref@1)
) of
true ->
{error, nil};
false ->
{ok,
oaspec@openapi@diagnostic:validation(
<<<<Op_id/binary,
".security."/utf8>>/binary,
(erlang:element(
2,
Scheme_ref@1
))/binary>>,
<<<<"Security requirement references scheme '"/utf8,
(erlang:element(
2,
Scheme_ref@1
))/binary>>/binary,
"' which is not defined in components.securitySchemes."/utf8>>,
severity_error,
target_both,
{some,
<<"Add the security scheme definition to components.securitySchemes or fix the scheme name."/utf8>>}
)}
end
end
)
end
);
none ->
[]
end
end
),
lists:append(Global_errors, Operation_errors).
-file("src/oaspec/internal/codegen/validate.gleam", 1218).
?DOC(false).
-spec validate_schema_recursive(
binary(),
oaspec@internal@openapi@schema:schema_object(),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_schema_recursive(Path, Schema_obj, Ctx) ->
case Schema_obj of
{object_schema, _, Properties, _, Additional_properties, _, _} ->
Ap_errors = [],
Typed_ap_errors = case Additional_properties of
{typed, Ap_ref} ->
validate_schema_ref_recursive(
<<Path/binary, ".additionalProperties"/utf8>>,
Ap_ref,
Ctx
);
forbidden ->
[];
untyped ->
[];
unspecified ->
[]
end,
Prop_errors = begin
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Prop_name, Prop_ref} = Entry,
Prop_path = <<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
validate_schema_ref_recursive(Prop_path, Prop_ref, Ctx)
end
)
end,
lists:append([Ap_errors, Typed_ap_errors, Prop_errors]);
{array_schema, _, Items, _, _, _} ->
validate_schema_ref_recursive(
<<Path/binary, ".items"/utf8>>,
Items,
Ctx
);
{one_of_schema, _, Schemas, _} ->
gleam@list:flat_map(
Schemas,
fun(S_ref) ->
validate_schema_ref_recursive(
<<Path/binary, ".oneOf"/utf8>>,
S_ref,
Ctx
)
end
);
{any_of_schema, _, Schemas@1, _} ->
gleam@list:flat_map(
Schemas@1,
fun(S_ref@1) ->
validate_schema_ref_recursive(
<<Path/binary, ".anyOf"/utf8>>,
S_ref@1,
Ctx
)
end
);
{all_of_schema, _, Schemas@2} ->
gleam@list:flat_map(
Schemas@2,
fun(S_ref@2) ->
validate_schema_ref_recursive(
<<Path/binary, ".allOf"/utf8>>,
S_ref@2,
Ctx
)
end
);
_ ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1157).
?DOC(false).
-spec validate_schema_ref_recursive(
binary(),
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_schema_ref_recursive(Path, Schema_ref, Ctx) ->
case Schema_ref of
{reference, Ref, _} ->
case gleam_stdlib:string_starts_with(Ref, <<"#/"/utf8>>) of
false ->
[case is_url_style_ref(Ref) of
true ->
oaspec@openapi@diagnostic:validation(
Path,
<<<<"URL-style $ref '"/utf8, Ref/binary>>/binary,
"' is not supported. oaspec does not resolve OpenAPI 3.1 / JSON Schema `$id`-backed identifiers — those refs are an explicit boundary."/utf8>>,
severity_error,
target_both,
{some,
<<"Rewrite the schema to a local $ref (`#/components/schemas/...`) and drop the `$id` URL, or inline the schema at the use site."/utf8>>}
);
false ->
oaspec@openapi@diagnostic:validation(
Path,
<<<<"External $ref '"/utf8, Ref/binary>>/binary,
"' is not supported. Only local references (#/components/...) are supported."/utf8>>,
severity_error,
target_both,
{some,
<<"Inline the external schema or copy it into #/components/schemas/ and use a local $ref."/utf8>>}
)
end];
true ->
case oaspec@internal@openapi@resolver:resolve_schema_ref(
Schema_ref,
oaspec@internal@codegen@context:spec(Ctx)
) of
{ok, _} ->
[];
{error, _} ->
[oaspec@openapi@diagnostic:validation(
Path,
<<<<"Unresolved schema reference: '"/utf8,
Ref/binary>>/binary,
"'. The referenced schema does not exist in components."/utf8>>,
severity_error,
target_both,
{some,
<<"Verify the schema is defined in components.schemas and the $ref path is spelled correctly."/utf8>>}
)]
end
end;
{inline, Schema_obj} ->
validate_schema_recursive(Path, Schema_obj, Ctx)
end.
-file("src/oaspec/internal/codegen/validate.gleam", 672).
?DOC(false).
-spec validate_request_body(
binary(),
gleam@option:option(oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:resolved())),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_request_body(Op_id, Request_body, Ctx) ->
case Request_body of
none ->
[];
{some, Rb} ->
Content_keys = maps:keys(erlang:element(3, Rb)),
Unsupported = gleam@list:filter(
Content_keys,
fun(Key) ->
not oaspec@internal@util@content_type:is_supported_request(
oaspec@internal@util@content_type:from_string(Key)
)
end
),
Content_type_errors = case Unsupported of
[] ->
[];
[Media_type | _] ->
[oaspec@openapi@diagnostic:validation(
<<Op_id/binary, ".requestBody"/utf8>>,
<<<<"Content type '"/utf8, Media_type/binary>>/binary,
"' is not supported. Supported request content types: application/json (and +json suffix types), text/plain, multipart/form-data, application/x-www-form-urlencoded, application/octet-stream."/utf8>>,
severity_error,
target_both,
{some,
<<"Use application/json (or a +json suffix type like application/problem+json), text/plain, multipart/form-data, application/x-www-form-urlencoded, or application/octet-stream."/utf8>>}
)]
end,
Schema_errors = begin
_pipe = maps:to_list(erlang:element(3, Rb)),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{_, Media_type@1} = Entry,
case erlang:element(2, Media_type@1) of
{some, Schema_ref} ->
validate_schema_ref_recursive(
<<Op_id/binary, ".requestBody"/utf8>>,
Schema_ref,
Ctx
);
none ->
[]
end
end
)
end,
Multipart_field_errors = validate_multipart_request_body_fields(
Op_id,
erlang:element(3, Rb),
Ctx
),
Form_urlencoded_errors = validate_form_urlencoded_schema(
Op_id,
erlang:element(3, Rb),
Ctx
),
Server_form_urlencoded_errors = validate_server_form_urlencoded_request_body(
Op_id,
erlang:element(3, Rb),
Content_keys,
Ctx
),
Server_multipart_errors = validate_server_multipart_request_body(
Op_id,
erlang:element(3, Rb),
Content_keys,
Ctx
),
Server_body_errors = validate_server_request_body_content_types(
Op_id,
Content_keys,
Ctx
),
lists:append(
[Content_type_errors,
Schema_errors,
Multipart_field_errors,
Form_urlencoded_errors,
Server_form_urlencoded_errors,
Server_multipart_errors,
Server_body_errors]
)
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1053).
?DOC(false).
-spec validate_responses(
binary(),
gleam@dict:dict(oaspec@internal@util@http:http_status_code(), oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:resolved())),
oaspec@internal@codegen@context:context()
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_responses(Op_id, Responses, Ctx) ->
Entries = maps:to_list(Responses),
gleam@list:flat_map(
Entries,
fun(Entry) ->
{Status_code, Response} = Entry,
Content_entries = maps:to_list(erlang:element(3, Response)),
gleam@list:flat_map(
Content_entries,
fun(Ce) ->
{Media_type_name, Media_type} = Ce,
Path = <<<<Op_id/binary, ".responses."/utf8>>/binary,
(oaspec@internal@util@http:status_code_to_string(
Status_code
))/binary>>,
Content_type_errors = case oaspec@internal@util@content_type:is_supported_response(
oaspec@internal@util@content_type:from_string(
Media_type_name
)
) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation(
Path,
<<<<"Response content type '"/utf8,
Media_type_name/binary>>/binary,
"' is not supported. Supported response content types: application/json (and +json suffix types), text/plain, application/x-ndjson, application/octet-stream, application/xml (and +xml suffix types), text/xml."/utf8>>,
severity_error,
target_both,
{some,
<<"Use application/json (or a +json suffix type), text/plain, application/x-ndjson, application/octet-stream, application/xml (or a +xml suffix type), or text/xml."/utf8>>}
)]
end,
Schema_errors = case erlang:element(2, Media_type) of
{some, Schema_ref} ->
validate_schema_ref_recursive(Path, Schema_ref, Ctx);
none ->
[]
end,
lists:append(Content_type_errors, Schema_errors)
end
)
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 215).
?DOC(false).
-spec validate_operations(
oaspec@internal@codegen@context:context(),
list({binary(),
oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()),
binary(),
oaspec@internal@openapi@spec:http_method()})
) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_operations(Ctx, Operations) ->
gleam@list:flat_map(
Operations,
fun(Op) ->
{Op_id, Operation, Path, _} = Op,
Resolved_params = gleam@list:map(
erlang:element(6, Operation),
fun oaspec@internal@openapi@spec:unwrap_ref/1
),
Resolved_request_body = case erlang:element(7, Operation) of
{some, Ref_or} ->
{some, oaspec@internal@openapi@spec:unwrap_ref(Ref_or)};
none ->
none
end,
Resolved_responses = begin
_pipe = maps:to_list(erlang:element(8, Operation)),
_pipe@1 = gleam@list:map(
_pipe,
fun(Entry) ->
{Status_code, Ref_or@1} = Entry,
{Status_code,
oaspec@internal@openapi@spec:unwrap_ref(Ref_or@1)}
end
),
maps:from_list(_pipe@1)
end,
Path_errors = validate_path_template_params(
Op_id,
Path,
Resolved_params
),
Param_errors = validate_parameters(Op_id, Resolved_params, Ctx),
Body_errors = validate_request_body(
Op_id,
Resolved_request_body,
Ctx
),
Response_errors = validate_responses(Op_id, Resolved_responses, Ctx),
Missing_responses_errors = case gleam@dict:is_empty(
Resolved_responses
) of
true ->
[oaspec@openapi@diagnostic:validation(
Op_id,
<<"Operation has no responses defined. OpenAPI 3.x requires at least one response."/utf8>>,
severity_error,
target_both,
{some,
<<"Add at least one response (e.g., '200': { description: ok }) to this operation."/utf8>>}
)];
false ->
[]
end,
lists:append(
[Path_errors,
Param_errors,
Body_errors,
Response_errors,
Missing_responses_errors]
)
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 1132).
?DOC(false).
-spec validate_component_schemas(oaspec@internal@codegen@context:context()) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate_component_schemas(Ctx) ->
Schemas = case erlang:element(5, oaspec@internal@codegen@context:spec(Ctx)) of
{some, Components} ->
maps:to_list(erlang:element(2, Components));
none ->
[]
end,
gleam@list:flat_map(
Schemas,
fun(Entry) ->
{Name, Schema_ref} = Entry,
validate_schema_ref_recursive(
<<"components.schemas."/utf8, Name/binary>>,
Schema_ref,
Ctx
)
end
).
-file("src/oaspec/internal/codegen/validate.gleam", 29).
?DOC(false).
-spec validate(oaspec@internal@codegen@context:context()) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate(Ctx) ->
Operations = oaspec@internal@openapi@operations:collect_operations(Ctx),
Op_errors = validate_operations(Ctx, Operations),
Opid_errors = validate_unique_operation_ids(Operations),
Schema_errors = validate_component_schemas(Ctx),
Schema_collision_errors = validate_unique_schema_names(Ctx),
Security_errors = validate_security_schemes(Ctx, Operations),
List_decoder_errors = validate_decode_list_collisions(Ctx),
lists:append(
[Op_errors,
Opid_errors,
Schema_errors,
Schema_collision_errors,
Security_errors,
List_decoder_errors]
).