Current section

Files

Jump to
oaspec src oaspec@openapi@normalize.erl
Raw

src/oaspec@openapi@normalize.erl

-module(oaspec@openapi@normalize).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/openapi/normalize.gleam").
-export([normalize/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.
-file("src/oaspec/openapi/normalize.gleam", 256).
?DOC(
" Add `keyword` to the schema's `unsupported_keywords` list so the\n"
" downstream capability_check rejects the schema with a targeted error\n"
" instead of silently dropping the constraint.\n"
).
-spec mark_unsupported(oaspec@openapi@schema:schema_object(), binary()) -> oaspec@openapi@schema:schema_object().
mark_unsupported(Schema_obj, Keyword) ->
Meta = oaspec@openapi@schema:get_metadata(Schema_obj),
New_meta = {schema_metadata,
erlang:element(2, Meta),
erlang:element(3, Meta),
erlang:element(4, Meta),
erlang:element(5, Meta),
erlang:element(6, Meta),
erlang:element(7, Meta),
erlang:element(8, Meta),
erlang:element(9, Meta),
erlang:element(10, Meta),
erlang:element(11, Meta),
[Keyword | erlang:element(12, Meta)],
erlang:element(13, Meta),
erlang:element(14, Meta)},
oaspec@openapi@schema:set_metadata(Schema_obj, New_meta).
-file("src/oaspec/openapi/normalize.gleam", 270).
?DOC(
" Does this primitive-typed schema carry any constraint that the\n"
" multi-type `oneOf` rewrite would drop? Only type-specific constraints\n"
" count — generic metadata like `nullable` or `description` is already\n"
" preserved by the rewrite.\n"
).
-spec has_type_specific_constraints(oaspec@openapi@schema:schema_object()) -> boolean().
has_type_specific_constraints(Schema_obj) ->
case Schema_obj of
{string_schema, _, Format, Enum_values, Min_length, Max_length, Pattern} ->
(((gleam@option:is_some(Format) orelse (Enum_values /= [])) orelse gleam@option:is_some(
Min_length
))
orelse gleam@option:is_some(Max_length))
orelse gleam@option:is_some(Pattern);
{integer_schema,
_,
Format@1,
Minimum,
Maximum,
Exclusive_minimum,
Exclusive_maximum,
Multiple_of} ->
((((gleam@option:is_some(Format@1) orelse gleam@option:is_some(
Minimum
))
orelse gleam@option:is_some(Maximum))
orelse gleam@option:is_some(Exclusive_minimum))
orelse gleam@option:is_some(Exclusive_maximum))
orelse gleam@option:is_some(Multiple_of);
{number_schema,
_,
Format@2,
Minimum@1,
Maximum@1,
Exclusive_minimum@1,
Exclusive_maximum@1,
Multiple_of@1} ->
((((gleam@option:is_some(Format@2) orelse gleam@option:is_some(
Minimum@1
))
orelse gleam@option:is_some(Maximum@1))
orelse gleam@option:is_some(Exclusive_minimum@1))
orelse gleam@option:is_some(Exclusive_maximum@1))
orelse gleam@option:is_some(Multiple_of@1);
_ ->
false
end.
-file("src/oaspec/openapi/normalize.gleam", 312).
-spec make_typed_schema(binary(), oaspec@openapi@schema:schema_metadata()) -> oaspec@openapi@schema:schema_object().
make_typed_schema(Type_str, Metadata) ->
case Type_str of
<<"string"/utf8>> ->
{string_schema, Metadata, none, [], none, none, none};
<<"integer"/utf8>> ->
{integer_schema, Metadata, none, none, none, none, none, none};
<<"number"/utf8>> ->
{number_schema, Metadata, none, none, none, none, none, none};
<<"boolean"/utf8>> ->
{boolean_schema, Metadata};
_ ->
{object_schema, Metadata, maps:new(), [], forbidden, none, none}
end.
-file("src/oaspec/openapi/normalize.gleam", 137).
-spec normalize_callback(oaspec@openapi@spec:callback(PIE)) -> oaspec@openapi@spec:callback(PIE).
normalize_callback(Cb) ->
{callback,
gleam@dict:map_values(
erlang:element(2, Cb),
fun(_, Ref_or) -> normalize_ref_or_path_item(Ref_or) end
)}.
-file("src/oaspec/openapi/normalize.gleam", 39).
-spec normalize_ref_or_path_item(
oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(PHL))
) -> oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(PHL)).
normalize_ref_or_path_item(Ref_or) ->
case Ref_or of
{ref, R} ->
{ref, R};
{value, Item} ->
{value, normalize_path_item(Item)}
end.
-file("src/oaspec/openapi/normalize.gleam", 88).
-spec normalize_path_item(oaspec@openapi@spec:path_item(PHT)) -> oaspec@openapi@spec:path_item(PHT).
normalize_path_item(Item) ->
{path_item,
erlang:element(2, Item),
erlang:element(3, Item),
gleam@option:map(erlang:element(4, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(5, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(6, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(7, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(8, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(9, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(10, Item), fun normalize_operation/1),
gleam@option:map(erlang:element(11, Item), fun normalize_operation/1),
gleam@list:map(
erlang:element(12, Item),
fun normalize_ref_or_parameter/1
),
erlang:element(13, Item)}.
-file("src/oaspec/openapi/normalize.gleam", 112).
-spec normalize_operation(oaspec@openapi@spec:operation(PIB)) -> oaspec@openapi@spec:operation(PIB).
normalize_operation(Op) ->
{operation,
erlang:element(2, Op),
erlang:element(3, Op),
erlang:element(4, Op),
erlang:element(5, Op),
gleam@list:map(erlang:element(6, Op), fun normalize_ref_or_parameter/1),
gleam@option:map(erlang:element(7, Op), fun(Ref_or) -> case Ref_or of
{ref, R} ->
{ref, R};
{value, Rb} ->
{value, normalize_request_body(Rb)}
end end),
gleam@dict:map_values(
erlang:element(8, Op),
fun(_, Ref_or@1) -> case Ref_or@1 of
{ref, R@1} ->
{ref, R@1};
{value, R@2} ->
{value, normalize_response(R@2)}
end end
),
erlang:element(9, Op),
erlang:element(10, Op),
gleam@dict:map_values(
erlang:element(11, Op),
fun(_, Ref_or@2) -> case Ref_or@2 of
{ref, R@3} ->
{ref, R@3};
{value, Cb} ->
{value, normalize_callback(Cb)}
end end
),
erlang:element(12, Op),
erlang:element(13, Op)}.
-file("src/oaspec/openapi/normalize.gleam", 356).
-spec normalize_schema_children(oaspec@openapi@schema:schema_object()) -> oaspec@openapi@schema:schema_object().
normalize_schema_children(S) ->
case S of
{object_schema,
Metadata,
Properties,
Required,
Additional_properties,
Min_properties,
Max_properties} ->
Properties@1 = gleam@dict:map_values(
Properties,
fun(_, V) -> normalize_schema_ref(V) end
),
Additional_properties@1 = case Additional_properties of
{typed, Sr} ->
{typed, normalize_schema_ref(Sr)};
Other ->
Other
end,
{object_schema,
Metadata,
Properties@1,
Required,
Additional_properties@1,
Min_properties,
Max_properties};
{array_schema, Metadata@1, Items, Min_items, Max_items, Unique_items} ->
{array_schema,
Metadata@1,
normalize_schema_ref(Items),
Min_items,
Max_items,
Unique_items};
{all_of_schema, Metadata@2, Schemas} ->
{all_of_schema,
Metadata@2,
gleam@list:map(Schemas, fun normalize_schema_ref/1)};
{one_of_schema, Metadata@3, Schemas@1, Discriminator} ->
{one_of_schema,
Metadata@3,
gleam@list:map(Schemas@1, fun normalize_schema_ref/1),
Discriminator};
{any_of_schema, Metadata@4, Schemas@2, Discriminator@1} ->
{any_of_schema,
Metadata@4,
gleam@list:map(Schemas@2, fun normalize_schema_ref/1),
Discriminator@1};
_ ->
S
end.
-file("src/oaspec/openapi/normalize.gleam", 179).
-spec normalize_schema_ref(oaspec@openapi@schema:schema_ref()) -> oaspec@openapi@schema:schema_ref().
normalize_schema_ref(Ref) ->
case Ref of
{inline, S} ->
{inline, normalize_schema(S)};
{reference, _, _} ->
Ref
end.
-file("src/oaspec/openapi/normalize.gleam", 186).
-spec normalize_schema(oaspec@openapi@schema:schema_object()) -> oaspec@openapi@schema:schema_object().
normalize_schema(Schema_obj) ->
Schema_obj@1 = case Schema_obj of
{string_schema, Meta, _, _, _, _, _} ->
case erlang:element(10, Meta) of
{some, {json_string, Str_val}} ->
{string_schema,
{schema_metadata,
erlang:element(2, Meta),
erlang:element(3, Meta),
erlang:element(4, Meta),
erlang:element(5, Meta),
erlang:element(6, Meta),
erlang:element(7, Meta),
erlang:element(8, Meta),
erlang:element(9, Meta),
none,
erlang:element(11, Meta),
erlang:element(12, Meta),
erlang:element(13, Meta),
erlang:element(14, Meta)},
erlang:element(3, Schema_obj),
[Str_val],
erlang:element(5, Schema_obj),
erlang:element(6, Schema_obj),
erlang:element(7, Schema_obj)};
_ ->
Schema_obj
end;
_ ->
case erlang:element(
10,
oaspec@openapi@schema:get_metadata(Schema_obj)
) of
{some, _} ->
mark_unsupported(Schema_obj, <<"const (non-string)"/utf8>>);
none ->
Schema_obj
end
end,
Schema_obj@2 = case erlang:element(
11,
oaspec@openapi@schema:get_metadata(Schema_obj@1)
) of
{some, Types} ->
case erlang:length(Types) > 1 of
true ->
Meta@1 = oaspec@openapi@schema:get_metadata(Schema_obj@1),
case has_type_specific_constraints(Schema_obj@1) of
true ->
mark_unsupported(
Schema_obj@1,
<<"type: [T1, T2] with type-specific constraints"/utf8>>
);
false ->
Type_schemas = gleam@list:map(
Types,
fun(T) ->
{inline,
make_typed_schema(
T,
begin
_record = oaspec@openapi@schema:default_metadata(
),
{schema_metadata,
erlang:element(2, _record),
erlang:element(3, Meta@1),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record),
erlang:element(12, _record),
erlang:element(13, _record),
erlang:element(14, _record)}
end
)}
end
),
{one_of_schema,
{schema_metadata,
erlang:element(2, Meta@1),
erlang:element(3, Meta@1),
erlang:element(4, Meta@1),
erlang:element(5, Meta@1),
erlang:element(6, Meta@1),
erlang:element(7, Meta@1),
erlang:element(8, Meta@1),
erlang:element(9, Meta@1),
erlang:element(10, Meta@1),
none,
erlang:element(12, Meta@1),
erlang:element(13, Meta@1),
erlang:element(14, Meta@1)},
Type_schemas,
none}
end;
false ->
Schema_obj@1
end;
none ->
Schema_obj@1
end,
normalize_schema_children(Schema_obj@2).
-file("src/oaspec/openapi/normalize.gleam", 171).
-spec normalize_header(oaspec@openapi@spec:header()) -> oaspec@openapi@spec:header().
normalize_header(H) ->
{header,
erlang:element(2, H),
erlang:element(3, H),
gleam@option:map(erlang:element(4, H), fun normalize_schema_ref/1)}.
-file("src/oaspec/openapi/normalize.gleam", 175).
-spec normalize_media_type(oaspec@openapi@spec:media_type()) -> oaspec@openapi@spec:media_type().
normalize_media_type(Mt) ->
{media_type,
gleam@option:map(erlang:element(2, Mt), fun normalize_schema_ref/1),
erlang:element(3, Mt),
erlang:element(4, Mt),
erlang:element(5, Mt)}.
-file("src/oaspec/openapi/normalize.gleam", 145).
-spec normalize_parameter(oaspec@openapi@spec:parameter(PIH)) -> oaspec@openapi@spec:parameter(PIH).
normalize_parameter(P) ->
Payload = case erlang:element(6, P) of
{parameter_schema, S} ->
{parameter_schema, normalize_schema_ref(S)};
{parameter_content, C} ->
{parameter_content,
gleam@dict:map_values(
C,
fun(_, Mt) -> normalize_media_type(Mt) end
)}
end,
{parameter,
erlang:element(2, P),
erlang:element(3, P),
erlang:element(4, P),
erlang:element(5, P),
Payload,
erlang:element(7, P),
erlang:element(8, P),
erlang:element(9, P),
erlang:element(10, P),
erlang:element(11, P)}.
-file("src/oaspec/openapi/normalize.gleam", 103).
-spec normalize_ref_or_parameter(
oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(PHW))
) -> oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(PHW)).
normalize_ref_or_parameter(Ref_or) ->
case Ref_or of
{ref, R} ->
{ref, R};
{value, P} ->
{value, normalize_parameter(P)}
end.
-file("src/oaspec/openapi/normalize.gleam", 156).
-spec normalize_request_body(oaspec@openapi@spec:request_body(PIK)) -> oaspec@openapi@spec:request_body(PIK).
normalize_request_body(Rb) ->
{request_body,
erlang:element(2, Rb),
gleam@dict:map_values(
erlang:element(3, Rb),
fun(_, Mt) -> normalize_media_type(Mt) end
),
erlang:element(4, Rb)}.
-file("src/oaspec/openapi/normalize.gleam", 163).
-spec normalize_response(oaspec@openapi@spec:response(PIN)) -> oaspec@openapi@spec:response(PIN).
normalize_response(R) ->
{response,
erlang:element(2, R),
gleam@dict:map_values(
erlang:element(3, R),
fun(_, Mt) -> normalize_media_type(Mt) end
),
gleam@dict:map_values(
erlang:element(4, R),
fun(_, H) -> normalize_header(H) end
),
erlang:element(5, R)}.
-file("src/oaspec/openapi/normalize.gleam", 48).
-spec normalize_components(oaspec@openapi@spec:components(PHQ)) -> oaspec@openapi@spec:components(PHQ).
normalize_components(C) ->
Schemas = gleam@dict:map_values(
erlang:element(2, C),
fun(_, V) -> normalize_schema_ref(V) end
),
Parameters = gleam@dict:map_values(
erlang:element(3, C),
fun(_, Entry) -> case Entry of
{value, P} ->
{value, normalize_parameter(P)};
{ref, R} ->
{ref, R}
end end
),
Request_bodies = gleam@dict:map_values(
erlang:element(4, C),
fun(_, Entry@1) -> case Entry@1 of
{value, Rb} ->
{value, normalize_request_body(Rb)};
{ref, R@1} ->
{ref, R@1}
end end
),
Responses = gleam@dict:map_values(
erlang:element(5, C),
fun(_, Entry@2) -> case Entry@2 of
{value, R@2} ->
{value, normalize_response(R@2)};
{ref, Ref} ->
{ref, Ref}
end end
),
Path_items = gleam@dict:map_values(
erlang:element(7, C),
fun(_, Entry@3) -> normalize_ref_or_path_item(Entry@3) end
),
Headers = gleam@dict:map_values(
erlang:element(8, C),
fun(_, H) -> normalize_header(H) end
),
{components,
Schemas,
Parameters,
Request_bodies,
Responses,
erlang:element(6, C),
Path_items,
Headers,
erlang:element(9, C),
erlang:element(10, C),
erlang:element(11, C)}.
-file("src/oaspec/openapi/normalize.gleam", 23).
?DOC(
" Normalize an OpenApiSpec after parsing.\n"
" Converts OAS 3.1 patterns to 3.0-compatible representations:\n"
" - raw_type with multiple types becomes oneOf\n"
" - const_value becomes a single-value enum\n"
).
-spec normalize(oaspec@openapi@spec:open_api_spec(PHI)) -> oaspec@openapi@spec:open_api_spec(PHI).
normalize(Spec) ->
Components = case erlang:element(5, Spec) of
{some, C} ->
{some, normalize_components(C)};
none ->
none
end,
Paths = gleam@dict:map_values(
erlang:element(4, Spec),
fun(_, Ref_or) -> normalize_ref_or_path_item(Ref_or) end
),
Webhooks = gleam@dict:map_values(
erlang:element(8, Spec),
fun(_, Ref_or@1) -> normalize_ref_or_path_item(Ref_or@1) end
),
{open_api_spec,
erlang:element(2, Spec),
erlang:element(3, Spec),
Paths,
Components,
erlang:element(6, Spec),
erlang:element(7, Spec),
Webhooks,
erlang:element(9, Spec),
erlang:element(10, Spec),
erlang:element(11, Spec)}.