Packages
oaspec
0.59.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec@internal@codegen@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([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", 95).
?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) ->
Reversed = 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, [Site | Existing]);
{error, _} ->
gleam@dict:insert(Acc, Key, [Site])
end
end
),
gleam@dict:map_values(Reversed, fun(_, Sites) -> lists:reverse(Sites) end).
-file("src/oaspec/internal/codegen/validate.gleam", 118).
?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", 134).
?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", 55).
?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", 151).
?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", 245).
?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 => 247,
value => _assert_fail,
start => 9115,
'end' => 9170,
pattern_start => 9126,
pattern_end => 9132})
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", 205).
?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_error_both(
<<Op_id/binary, ".path"/utf8>>,
<<<<<<<<"Path template parameter '{"/utf8,
Name/binary>>/binary,
"}' in '"/utf8>>/binary,
Path/binary>>/binary,
"' has no corresponding parameter definition."/utf8>>,
{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", 441).
?DOC(false).
-spec array_items_resolve_primitive(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
array_items_resolve_primitive(Items, Ctx) ->
case Items of
{inline, {string_schema, _, _, _, _, _, _}} ->
true;
{inline, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{inline, {number_schema, _, _, _, _, _, _, _}} ->
true;
{inline, {boolean_schema, _}} ->
true;
{reference, _, _} ->
case oaspec@internal@codegen@context:resolve_schema_ref(Items, Ctx) of
{ok, {string_schema, _, _, _, _, _, _}} ->
true;
{ok, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{ok, {number_schema, _, _, _, _, _, _, _}} ->
true;
{ok, {boolean_schema, _}} ->
true;
{ok, _} ->
false;
{error, _} ->
false
end;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 529).
?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", 645).
?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@codegen@context:resolve_schema_ref(
Schema_ref@1,
Ctx
) of
{ok, Schema_obj@1} ->
{some, Schema_obj@1};
{error, _} ->
none
end;
none ->
none
end.
-file("src/oaspec/internal/codegen/validate.gleam", 317).
?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_error_both(
Path,
<<<<"Parameter style '"/utf8, Style_name/binary>>/binary,
"' is only supported for 'in: query'."/utf8>>,
{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_error_both(
Path,
<<<<"Parameter style '"/utf8, Style_name/binary>>/binary,
"' requires an array schema."/utf8>>,
{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", 495).
?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", 461).
?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_error_server(
<<<<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>>,
{some,
<<"Simplify deepObject properties to primitive scalars or primitive arrays."/utf8>>}
)]
end
end
);
{_, _, _} ->
[]
end.
-file("src/oaspec/internal/codegen/validate.gleam", 356).
?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) ->
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, _, Items, _, _, _}}} ->
case array_items_resolve_primitive(Items, Ctx) of
true ->
[];
false ->
case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
[oaspec@openapi@diagnostic:validation_error_server(
Path,
<<"Query array parameters are only supported for primitive items (string, integer, number, boolean), whether inline or via $ref, in server code generation."/utf8>>,
{some,
<<"Switch to mode: client to use the JSON escape hatch, or replace the item schema with a primitive type."/utf8>>}
)]
end
end;
{in_header, {some, {array_schema, _, Items@1, _, _, _}}} ->
case array_items_resolve_primitive(Items@1, Ctx) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation_error_both(
Path,
<<"Header array parameters are only supported for primitive items (string, integer, number, boolean), whether inline or via $ref."/utf8>>,
{some,
<<"Replace the item schema with a primitive type (string, integer, number, boolean)."/utf8>>}
)]
end;
{in_cookie, {some, {array_schema, _, Items@2, _, _, _}}} ->
case array_items_resolve_primitive(Items@2, Ctx) of
true ->
[];
false ->
[oaspec@openapi@diagnostic:validation_error_both(
Path,
<<"Cookie array parameters are only supported for primitive items (string, integer, number, boolean), whether inline or via $ref."/utf8>>,
{some,
<<"Replace the item schema with a primitive type (string, integer, number, boolean)."/utf8>>}
)]
end;
{_, _} ->
[]
end,
Deep_object_errors = case oaspec@config:mode(
oaspec@internal@codegen@context:config(Ctx)
) of
client ->
[];
_ ->
validate_server_deep_object_param(Path, Param, Ctx)
end,
lists:append([Array_errors, Deep_object_errors]).
-file("src/oaspec/internal/codegen/validate.gleam", 613).
?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 oaspec@config:mode(oaspec@internal@codegen@context:config(Ctx)) of
client ->
[];
_ ->
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, _, _, _, _, _, _}} ->
[];
{some, {all_of_schema, _, _}} ->
[];
{some, {one_of_schema, _, _, _}} ->
[oaspec@openapi@diagnostic:validation_error_server(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested oneOf/anyOf properties in deepObject parameters are not supported in server code generation. Only primitive scalars, primitive arrays, and single-level nested objects (Dict(String, String)) are supported."/utf8>>,
{some,
<<"Switch to mode: client to use the JSON escape hatch, or flatten the property structure."/utf8>>}
)];
{some, {any_of_schema, _, _, _}} ->
[oaspec@openapi@diagnostic:validation_error_server(
<<<<Path/binary, "."/utf8>>/binary,
Prop_name/binary>>,
<<"Nested oneOf/anyOf properties in deepObject parameters are not supported in server code generation. Only primitive scalars, primitive arrays, and single-level nested objects (Dict(String, String)) are supported."/utf8>>,
{some,
<<"Switch to mode: client to use the JSON escape hatch, or flatten the property structure."/utf8>>}
)];
_ ->
[]
end
end
);
_ ->
[]
end
end.
-file("src/oaspec/internal/codegen/validate.gleam", 558).
?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_error_server(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation_warning_both(
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>>,
{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_error_server(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation_warning_both(
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>>,
{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_error_server(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation_warning_both(
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>>,
{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_error_server(
Path,
<<"Complex path parameters are not supported for server code generation."/utf8>>,
{some,
<<"Use a simple scalar type (string, integer, number, boolean) for path parameters."/utf8>>}
)]
end;
_ ->
[oaspec@openapi@diagnostic:validation_warning_both(
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>>,
{some,
<<"Declare 'style: deepObject' explicitly if the parameter encodes a structured object."/utf8>>}
)]
end;
_ ->
[]
end
end.
-file("src/oaspec/internal/codegen/validate.gleam", 261).
?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_error_both(
Path,
<<"Parameter style is not supported. Supported styles: form, simple, deepObject, pipeDelimited, spaceDelimited."/utf8>>,
{some,
<<"Use style 'form', 'simple', 'deepObject', 'pipeDelimited', or 'spaceDelimited' instead."/utf8>>}
)];
{some, label_style} ->
[oaspec@openapi@diagnostic:validation_error_both(
Path,
<<"Parameter style is not supported. Supported styles: form, simple, deepObject, pipeDelimited, spaceDelimited."/utf8>>,
{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_error_both(
Path,
<<"Parameters using 'content' instead of 'schema' are not supported."/utf8>>,
{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", 784).
?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_error_both(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"application/x-www-form-urlencoded request bodies must use an object schema."/utf8>>,
{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", 909).
?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, _, _, _}} ->
case resolve_schema_object({some, Items}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
_ ->
false
end;
{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", 1011).
?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 (Key /= <<"*/*"/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_error_server(
<<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>>,
{some,
<<"Use application/json for typed server request bodies, or multipart/form-data, application/x-www-form-urlencoded, application/octet-stream, text/plain, or */* for non-JSON payloads."/utf8>>}
)
end
)
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1112).
?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", 1100).
?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", 1047).
?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_error_server(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"multipart/form-data request bodies are only supported as the sole request content type for server code generation."/utf8>>,
{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_error_server(
<<<<Op_id/binary,
".requestBody.multipart."/utf8>>/binary,
Field_name/binary>>,
<<"multipart/form-data server request bodies only support primitive scalar fields."/utf8>>,
{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", 1144).
?DOC(false).
-spec multipart_field_array_item_supported(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
multipart_field_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;
{some, {object_schema, _, _, _, _, _, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 1125).
?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;
{some, {array_schema, _, Items, _, _, _}} ->
multipart_field_array_item_supported(Items, Ctx);
{some, {object_schema, _, _, _, _, _, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 741).
?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_error_both(
<<<<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>>,
{some,
<<"Use a primitive scalar type, binary, or string enum for multipart fields."/utf8>>}
)]
end
end
);
{some, _} ->
[oaspec@openapi@diagnostic:validation_error_both(
<<Op_id/binary, ".requestBody"/utf8>>,
<<"multipart/form-data request bodies must use an object schema."/utf8>>,
{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", 1202).
?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", 1256).
?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", 1374).
?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_error_both(
<<"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>>,
{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_error_both(
<<<<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>>,
{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", 988).
?DOC(false).
-spec form_urlencoded_array_items_codegen_safe(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context()
) -> boolean().
form_urlencoded_array_items_codegen_safe(Items, Ctx) ->
case resolve_schema_object({some, Items}, Ctx) of
{some, {string_schema, _, _, _, _, _, _}} ->
true;
{some, {integer_schema, _, _, _, _, _, _, _}} ->
true;
{some, {number_schema, _, _, _, _, _, _, _}} ->
true;
{some, {boolean_schema, _}} ->
true;
{some, {array_schema, _, Inner_items, _, _, _}} ->
form_urlencoded_array_items_codegen_safe(Inner_items, Ctx);
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:all(
_pipe,
fun(Entry) ->
{_, Child_schema} = Entry,
form_urlencoded_field_codegen_safe(Child_schema, Ctx, 0)
end
);
{some, {one_of_schema, _, _, _}} ->
true;
{some, {any_of_schema, _, _, _}} ->
true;
{some, {all_of_schema, _, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 952).
?DOC(false).
-spec form_urlencoded_field_codegen_safe(
oaspec@internal@openapi@schema:schema_ref(),
oaspec@internal@codegen@context:context(),
integer()
) -> boolean().
form_urlencoded_field_codegen_safe(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, _, _, _}} ->
form_urlencoded_array_items_codegen_safe(Items, Ctx);
{some, {object_schema, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:all(
_pipe,
fun(Entry) ->
{_, Child_schema} = Entry,
form_urlencoded_field_codegen_safe(Child_schema, Ctx, 0)
end
);
{some, {one_of_schema, _, _, _}} ->
true;
{some, {any_of_schema, _, _, _}} ->
true;
{some, {all_of_schema, _, _}} ->
true;
_ ->
false
end.
-file("src/oaspec/internal/codegen/validate.gleam", 814).
?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) ->
Server_mode_errors = 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, _} ->
case erlang:length(Content_keys) > 1 of
true ->
[oaspec@openapi@diagnostic:validation_error_server(
<<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>>,
{some,
<<"Remove other content type definitions from this operation's request body."/utf8>>}
)];
false ->
[]
end;
{error, _} ->
[]
end
end,
Field_errors = 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, _, Properties, _, _, _, _}} ->
_pipe = maps:to_list(Properties),
gleam@list:flat_map(
_pipe,
fun(Entry) ->
{Field_name, Field_schema} = Entry,
Client_safe = form_urlencoded_field_codegen_safe(
Field_schema,
Ctx,
0
),
Server_safe = form_urlencoded_server_field_supported(
Field_schema,
Ctx,
0
),
case {Client_safe, Server_safe} of
{true, true} ->
[];
{true, false} ->
[oaspec@openapi@diagnostic:validation_error_server(
<<<<Op_id/binary,
".requestBody.form."/utf8>>/binary,
Field_name/binary>>,
<<"application/x-www-form-urlencoded server request bodies only support primitive scalars, primitive arrays at the top level, and nested objects with primitive leaves (max 5 levels). Nested arrays-within-objects, oneOf, anyOf, and allOf properties are not yet supported on the server side."/utf8>>,
{some,
<<"Switch to mode: client for now, or simplify to primitive scalars, primitive arrays at the top level, or shallow nested objects with primitive leaves."/utf8>>}
)];
{false, _} ->
[oaspec@openapi@diagnostic:validation_error_both(
<<<<Op_id/binary,
".requestBody.form."/utf8>>/binary,
Field_name/binary>>,
<<"application/x-www-form-urlencoded request body field has a shape the codegen does not yet know how to serialise."/utf8>>,
{some,
<<<<"Switch this field to a concrete primitive, object, array, or composite schema, or set encoding."/utf8,
Field_name/binary>>/binary,
".contentType: application/json to opt the field into the JSON escape hatch."/utf8>>}
)]
end
end
);
_ ->
[]
end;
{error, _} ->
[]
end,
lists:append(Server_mode_errors, Field_errors).
-file("src/oaspec/internal/codegen/validate.gleam", 1316).
?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", 1261).
?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_error_both(
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>>,
{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_error_both(
Path,
<<<<"External $ref '"/utf8, Ref/binary>>/binary,
"' is not supported. Only local references (#/components/...) are supported."/utf8>>,
{some,
<<"Inline the external schema or copy it into #/components/schemas/ and use a local $ref."/utf8>>}
)
end];
true ->
case oaspec@internal@codegen@context:resolve_schema_ref(
Schema_ref,
Ctx
) of
{ok, _} ->
[];
{error, _} ->
[oaspec@openapi@diagnostic:validation_error_both(
Path,
<<<<"Unresolved schema reference: '"/utf8,
Ref/binary>>/binary,
"'. The referenced schema does not exist in components."/utf8>>,
{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", 662).
?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_error_both(
<<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>>,
{some,
<<"Use application/json (or a +json suffix type like application/problem+json), text/plain, multipart/form-data, application/x-www-form-urlencoded, application/octet-stream, or */*."/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", 1159).
?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_error_both(
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>>,
{some,
<<"Use application/json (or a +json suffix type), text/plain, application/x-ndjson, application/octet-stream, application/xml (or a +xml suffix type), text/xml, or */*."/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", 156).
?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_error_both(
Op_id,
<<"Operation has no responses defined. OpenAPI 3.x requires at least one response."/utf8>>,
{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", 1236).
?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", 25).
?DOC(false).
-spec validate(oaspec@internal@codegen@context:context()) -> list(oaspec@openapi@diagnostic:diagnostic()).
validate(Ctx) ->
Operations = oaspec@internal@codegen@context: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),
lists:append(
[Op_errors,
Opid_errors,
Schema_errors,
Schema_collision_errors,
Security_errors]
).