-module(oaspec@internal@openapi@ref_validation). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/internal/openapi/ref_validation.gleam"). -export([validate_schema_refs/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/openapi/ref_validation.gleam", 330). ?DOC(false). -spec lookup_component_schema( oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()), binary() ) -> {ok, oaspec@openapi@schema:schema_ref()} | {error, nil}. lookup_component_schema(Spec, Name) -> case erlang:element(5, Spec) of none -> {error, nil}; {some, Components} -> gleam_stdlib:map_get(erlang:element(2, Components), Name) end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 135). ?DOC(false). -spec validate_operation( oaspec@openapi@spec:operation(oaspec@openapi@spec:resolved()), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_operation(Op, Context, Spec) -> Param_diags = validate_parameters( erlang:element(6, Op), <>, Spec ), Request_body_diags = case erlang:element(7, Op) of none -> []; {some, Rb} -> validate_request_body_refor( Rb, <>, Spec ) end, Response_diags = begin _pipe = maps:to_list(erlang:element(8, Op)), gleam@list:flat_map( _pipe, fun(Entry) -> {_, Response_refor} = Entry, validate_response_refor( Response_refor, <>, Spec ) end ) end, Callback_diags = begin _pipe@1 = maps:to_list(erlang:element(11, Op)), gleam@list:flat_map( _pipe@1, fun(Entry@1) -> {Name, Cb_refor} = Entry@1, Callback_path = <<<>/binary, Name/binary>>, case Cb_refor of {ref, _} -> []; {value, Callback} -> _pipe@2 = maps:to_list(erlang:element(2, Callback)), gleam@list:flat_map( _pipe@2, fun(Cb_entry) -> {Url, Pi_refor} = Cb_entry, Cb_path = <<<>/binary, Url/binary>>, case Pi_refor of {ref, _} -> []; {value, Pi} -> validate_path_item(Pi, Cb_path, Spec) end end ) end end ) end, lists:append( [Param_diags, Request_body_diags, Response_diags, Callback_diags] ). -file("src/oaspec/internal/openapi/ref_validation.gleam", 102). ?DOC(false). -spec validate_path_item( oaspec@openapi@spec:path_item(oaspec@openapi@spec:resolved()), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_path_item(Pi, Context, Spec) -> Operations = begin _pipe = [{<<"get"/utf8>>, erlang:element(4, Pi)}, {<<"post"/utf8>>, erlang:element(5, Pi)}, {<<"put"/utf8>>, erlang:element(6, Pi)}, {<<"delete"/utf8>>, erlang:element(7, Pi)}, {<<"patch"/utf8>>, erlang:element(8, Pi)}, {<<"head"/utf8>>, erlang:element(9, Pi)}, {<<"options"/utf8>>, erlang:element(10, Pi)}, {<<"trace"/utf8>>, erlang:element(11, Pi)}], gleam@list:filter_map( _pipe, fun(Pair) -> {Method, Op} = Pair, case Op of {some, O} -> {ok, {Method, O}}; none -> {error, nil} end end ) end, Op_diags = gleam@list:flat_map( Operations, fun(Pair@1) -> {Method@1, Op@1} = Pair@1, validate_operation( Op@1, <<<>/binary, Method@1/binary>>, Spec ) end ), Path_param_diags = validate_parameters( erlang:element(12, Pi), <>, Spec ), lists:append(Path_param_diags, Op_diags). -file("src/oaspec/internal/openapi/ref_validation.gleam", 81). ?DOC(false). -spec validate_paths( gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:resolved()))), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_paths(Paths, Prefix, Spec) -> _pipe = maps:to_list(Paths), gleam@list:flat_map( _pipe, fun(Entry) -> {Path, Ref_or} = Entry, Context = <<<>/binary, Path/binary>>, case Ref_or of {ref, _} -> []; {value, Pi} -> validate_path_item(Pi, Context, Spec) end end ). -file("src/oaspec/internal/openapi/ref_validation.gleam", 340). ?DOC(false). -spec validate_inline_schema( binary(), oaspec@openapi@schema:schema_object(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()), gleam@set:set(binary()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_inline_schema(Path, Schema_obj, Spec, Expanding) -> case Schema_obj of {object_schema, _, Properties, _, Additional_properties, _, _} -> Prop_diags = begin _pipe = maps:to_list(Properties), gleam@list:flat_map( _pipe, fun(Entry) -> {Prop_name, Prop_ref} = Entry, validate_schema_ref( <<<>/binary, Prop_name/binary>>, Prop_ref, Spec, Expanding ) end ) end, Ap_diags = validate_additional_properties( Additional_properties, <>, Spec, Expanding ), lists:append(Prop_diags, Ap_diags); {array_schema, _, Items, _, _, _} -> validate_schema_ref( <>, Items, Spec, Expanding ); {all_of_schema, _, Schemas} -> gleam@list:flat_map( Schemas, fun(S) -> validate_schema_ref( <>, S, Spec, Expanding ) end ); {one_of_schema, _, Schemas@1, _} -> gleam@list:flat_map( Schemas@1, fun(S@1) -> validate_schema_ref( <>, S@1, Spec, Expanding ) end ); {any_of_schema, _, Schemas@2, _} -> gleam@list:flat_map( Schemas@2, fun(S@2) -> validate_schema_ref( <>, S@2, Spec, Expanding ) end ); _ -> [] end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 387). ?DOC(false). -spec validate_additional_properties( oaspec@openapi@schema:additional_properties(), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()), gleam@set:set(binary()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_additional_properties(Ap, Path, Spec, Expanding) -> case Ap of {typed, Ref} -> validate_schema_ref(Path, Ref, Spec, Expanding); forbidden -> []; untyped -> []; unspecified -> [] end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 279). ?DOC(false). -spec validate_schema_ref( binary(), oaspec@openapi@schema:schema_ref(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()), gleam@set:set(binary()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_schema_ref(Path, Schema_ref, Spec, Expanding) -> case Schema_ref of {inline, Schema_obj} -> validate_inline_schema(Path, Schema_obj, Spec, Expanding); {reference, Ref, Name} -> case gleam@set:contains(Expanding, Name) of true -> [oaspec@openapi@diagnostic:resolve_error( Path, <<<<<<<<"Circular schema reference detected at '"/utf8, Ref/binary>>/binary, "'. The $ref chain re-enters '"/utf8>>/binary, Name/binary>>/binary, "' before reaching a concrete schema."/utf8>>, {some, <<"Break the cycle by replacing one $ref in the chain with an inline schema or restructuring the components."/utf8>>}, no_source_loc )]; false -> case lookup_component_schema(Spec, Name) of {error, nil} -> [oaspec@openapi@diagnostic:resolve_error( Path, <<<<"Unresolved schema reference: '"/utf8, Ref/binary>>/binary, "'. The referenced schema does not exist in components.schemas."/utf8>>, {some, <<"Verify the schema is defined in components.schemas and the $ref path is spelled correctly."/utf8>>}, no_source_loc )]; {ok, Target} -> validate_schema_ref( Path, Target, Spec, gleam@set:insert(Expanding, Name) ) end end end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 64). ?DOC(false). -spec validate_components_schemas( oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_components_schemas(Spec) -> case erlang:element(5, Spec) of none -> []; {some, Components} -> _pipe = maps:to_list(erlang:element(2, Components)), gleam@list:flat_map( _pipe, fun(Entry) -> {Name, Schema_ref} = Entry, validate_schema_ref( <<"components.schemas."/utf8, Name/binary>>, Schema_ref, Spec, gleam@set:new() ) end ) end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 49). ?DOC(false). -spec validate_schema_refs( oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> {ok, nil} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. validate_schema_refs(Spec) -> Diags = lists:append( [validate_components_schemas(Spec), validate_paths(erlang:element(4, Spec), <<"paths"/utf8>>, Spec), validate_paths(erlang:element(8, Spec), <<"webhooks"/utf8>>, Spec)] ), case Diags of [] -> {ok, nil}; _ -> {error, Diags} end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 242). ?DOC(false). -spec validate_header( oaspec@openapi@spec:header(), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_header(Header, Context, Spec) -> case erlang:element(4, Header) of none -> []; {some, Schema_ref} -> validate_schema_ref( <>, Schema_ref, Spec, gleam@set:new() ) end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 254). ?DOC(false). -spec validate_media_type_map( gleam@dict:dict(binary(), oaspec@openapi@spec:media_type()), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_media_type_map(Media_types, Context, Spec) -> _pipe = maps:to_list(Media_types), gleam@list:flat_map( _pipe, fun(Entry) -> {Media_type_name, Media_type} = Entry, Mt_path = <<<>/binary, Media_type_name/binary>>, case erlang:element(2, Media_type) of none -> []; {some, Schema_ref} -> validate_schema_ref( <>, Schema_ref, Spec, gleam@set:new() ) end end ). -file("src/oaspec/internal/openapi/ref_validation.gleam", 189). ?DOC(false). -spec validate_parameter( oaspec@openapi@spec:parameter(oaspec@openapi@spec:resolved()), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_parameter(Param, Context, Spec) -> Param_path = <<<>/binary, (erlang:element(2, Param))/binary>>, case erlang:element(6, Param) of {parameter_schema, Schema_ref} -> validate_schema_ref( <>, Schema_ref, Spec, gleam@set:new() ); {parameter_content, Content} -> validate_media_type_map( Content, <>, Spec ) end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 176). ?DOC(false). -spec validate_parameters( list(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:resolved()))), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_parameters(Parameters, Context, Spec) -> gleam@list:flat_map(Parameters, fun(P) -> case P of {ref, _} -> []; {value, Param} -> validate_parameter(Param, Context, Spec) end end). -file("src/oaspec/internal/openapi/ref_validation.gleam", 203). ?DOC(false). -spec validate_request_body_refor( oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:resolved())), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_request_body_refor(Rb_refor, Context, Spec) -> case Rb_refor of {ref, _} -> []; {value, Rb} -> validate_media_type_map( erlang:element(3, Rb), <>, Spec ) end. -file("src/oaspec/internal/openapi/ref_validation.gleam", 226). ?DOC(false). -spec validate_response( oaspec@openapi@spec:response(oaspec@openapi@spec:resolved()), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_response(Response, Context, Spec) -> Content_diags = validate_media_type_map( erlang:element(3, Response), <>, Spec ), Header_diags = begin _pipe = maps:to_list(erlang:element(4, Response)), gleam@list:flat_map( _pipe, fun(Entry) -> {Name, Header} = Entry, validate_header( Header, <<<>/binary, Name/binary>>, Spec ) end ) end, lists:append(Content_diags, Header_diags). -file("src/oaspec/internal/openapi/ref_validation.gleam", 215). ?DOC(false). -spec validate_response_refor( oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:resolved())), binary(), oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved()) ) -> list(oaspec@openapi@diagnostic:diagnostic()). validate_response_refor(Response_refor, Context, Spec) -> case Response_refor of {ref, _} -> []; {value, Response} -> validate_response(Response, Context, Spec) end.