-module(oaspec@internal@openapi@capability_check). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/internal/openapi/capability_check.gleam"). -export([check_preserved/2, check/2]). -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/capability_check.gleam", 246). ?DOC(false). -spec check_security_schemes( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_security_schemes(Spec, Index) -> case erlang:element(5, Spec) of none -> []; {some, Components} -> _pipe = maps:to_list(erlang:element(6, Components)), gleam@list:filter_map( _pipe, fun(Entry) -> {Name, Ref_or} = Entry, case Ref_or of {value, {unsupported_scheme, Scheme_type}} -> Path = <<"components.securitySchemes."/utf8, Name/binary>>, {ok, oaspec@openapi@diagnostic:capability( Path, <<<<"Unsupported security scheme type: '"/utf8, Scheme_type/binary>>/binary, "'. Supported types: apiKey, http, oauth2, openIdConnect."/utf8>>, severity_error, target_both, {some, <<"Use apiKey, http (bearer), oauth2, or openIdConnect instead."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, Path ) )}; _ -> {error, nil} end end ) end. -file("src/oaspec/internal/openapi/capability_check.gleam", 283). ?DOC(false). -spec operation_yaml_prefix( binary(), oaspec@internal@openapi@spec:http_method() ) -> binary(). operation_yaml_prefix(Url, Method) -> <<<<<<"paths."/utf8, Url/binary>>/binary, "."/utf8>>/binary, (string:lowercase(oaspec@internal@openapi@spec:method_to_string(Method)))/binary>>. -file("src/oaspec/internal/openapi/capability_check.gleam", 290). ?DOC(false). -spec capability_path_to_yaml( binary(), list({binary(), oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()), binary(), oaspec@internal@openapi@spec:http_method()}) ) -> binary(). capability_path_to_yaml(Path, Operations) -> case gleam@string:split(Path, <<"."/utf8>>) of [First | Rest] -> case gleam@list:find_map( Operations, fun(Op) -> {Op_id, _, Url, Method} = Op, case Op_id =:= First of true -> {ok, operation_yaml_prefix(Url, Method)}; false -> {error, nil} end end ) of {ok, Prefix} -> case Rest of [] -> Prefix; _ -> <<<>/binary, (gleam@string:join(Rest, <<"."/utf8>>))/binary>> end; {error, _} -> Path end; [] -> Path end. -file("src/oaspec/internal/openapi/capability_check.gleam", 321). ?DOC(false). -spec lookup_loc( oaspec@internal@codegen@context:context(), oaspec@internal@openapi@location_index:location_index(), binary() ) -> oaspec@openapi@diagnostic:source_loc(). lookup_loc(Ctx, Index, Path) -> Yaml_path = capability_path_to_yaml( Path, oaspec@internal@codegen@context:operations(Ctx) ), oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, Yaml_path ). -file("src/oaspec/internal/openapi/capability_check.gleam", 329). ?DOC(false). -spec check_preserved( oaspec@internal@codegen@context:context(), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_preserved(Ctx, Index) -> Webhook_warnings = case gleam@dict:is_empty( erlang:element(8, oaspec@internal@codegen@context:spec(Ctx)) ) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"webhooks"/utf8>>, <<"Webhooks are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Webhooks will not appear in generated code. No action needed unless you expected them."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"webhooks"/utf8>> ) )] end, Ops = oaspec@internal@codegen@context:operations(Ctx), Response_warnings = gleam@list:flat_map( Ops, fun(Op) -> {Op_id, Operation, _, _} = Op, Entries = maps:to_list(erlang:element(8, Operation)), gleam@list:flat_map( Entries, fun(Entry) -> {Status_code, Ref_or} = Entry, case Ref_or of {value, Response} -> Base_path = <<<>/binary, (oaspec@internal@util@http:status_code_to_string( Status_code ))/binary>>, Multi_content_warnings = case {oaspec@config:mode( oaspec@internal@codegen@context:config(Ctx) ), erlang:length( maps:to_list(erlang:element(3, Response)) )} of {client, _} -> []; {_, N} when N > 1 -> Path = <>, [oaspec@openapi@diagnostic:capability( Path, <<"Multiple response content types are not fully supported for server code generation. Generated server responses lose the content-type header."/utf8>>, severity_warning, target_server, {some, <<"Use a single content type per response for full server code generation support."/utf8>>}, lookup_loc(Ctx, Index, Path) )]; {_, _} -> [] end, Header_warnings = [], Link_warnings = case gleam@dict:is_empty( erlang:element(5, Response) ) of true -> []; false -> Path@1 = <>, [oaspec@openapi@diagnostic:capability( Path@1, <<"Response links are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Response links will not appear in generated code. No action needed."/utf8>>}, lookup_loc(Ctx, Index, Path@1) )] end, Content_entries = maps:to_list( erlang:element(3, Response) ), Encoding_warnings = gleam@list:flat_map( Content_entries, fun(Ce) -> {Media_type_name, Media_type} = Ce, case gleam@dict:is_empty( erlang:element(5, Media_type) ) of true -> []; false -> Path@2 = <<<<<>/binary, Media_type_name/binary>>/binary, ".encoding"/utf8>>, [oaspec@openapi@diagnostic:capability( Path@2, <<"MediaType encoding is parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Encoding settings will not affect generated code. No action needed."/utf8>>}, lookup_loc( Ctx, Index, Path@2 ) )] end end ), lists:append( [Multi_content_warnings, Header_warnings, Link_warnings, Encoding_warnings] ); _ -> [] end end ) end ), Request_body_encoding_warnings = gleam@list:flat_map( Ops, fun(Op@1) -> {Op_id@1, Operation@1, _, _} = Op@1, case erlang:element(7, Operation@1) of {some, {value, Rb}} -> Base_path@1 = <>, Content_entries@1 = maps:to_list(erlang:element(3, Rb)), gleam@list:flat_map( Content_entries@1, fun(Ce@1) -> {Media_type_name@1, Media_type@1} = Ce@1, case gleam@dict:is_empty( erlang:element(5, Media_type@1) ) of true -> []; false -> Path@3 = <<<<<>/binary, Media_type_name@1/binary>>/binary, ".encoding"/utf8>>, [oaspec@openapi@diagnostic:capability( Path@3, <<"Request-body encoding is parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Encoding settings (contentType, style, explode) will not affect generated code. No action needed."/utf8>>}, lookup_loc(Ctx, Index, Path@3) )] end end ); _ -> [] end end ), External_docs_warnings = case erlang:element( 10, oaspec@internal@codegen@context:spec(Ctx) ) of {some, _} -> [oaspec@openapi@diagnostic:capability( <<"externalDocs"/utf8>>, <<"External docs are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"External docs will not appear in generated code. Include documentation in descriptions instead."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"externalDocs"/utf8>> ) )]; none -> [] end, Tag_warnings = case gleam@list:is_empty( erlang:element(9, oaspec@internal@codegen@context:spec(Ctx)) ) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"tags"/utf8>>, <<"Top-level tags are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Tags will not appear in generated code. No action needed."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"tags"/utf8>> ) )] end, Operation_server_warnings = [], Path_server_warnings = [], Component_warnings = case erlang:element( 5, oaspec@internal@codegen@context:spec(Ctx) ) of {some, Components} -> Header_w = case gleam@dict:is_empty(erlang:element(8, Components)) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"components.headers"/utf8>>, <<"Component headers are wired into generated code only when referenced from a response.headers entry; standalone definitions are not surfaced."/utf8>>, severity_warning, target_both, {some, <<"If a component header should reach a client, reference it from the relevant response.headers entry."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"components.headers"/utf8>> ) )] end, Example_w = case gleam@dict:is_empty(erlang:element(9, Components)) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"components.examples"/utf8>>, <<"Component examples are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Component examples will not appear in generated code. Include examples in descriptions instead."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"components.examples"/utf8>> ) )] end, Link_w = case gleam@dict:is_empty(erlang:element(10, Components)) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"components.links"/utf8>>, <<"Component links are parsed but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Component links will not appear in generated code. No action needed."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"components.links"/utf8>> ) )] end, Callback_w = case gleam@dict:is_empty( erlang:element(11, Components) ) of true -> []; false -> [oaspec@openapi@diagnostic:capability( <<"components.callbacks"/utf8>>, <<"Component callbacks are parsed and preserved but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"Callback endpoints will not appear in generated code. No action needed unless you expected handler stubs for them."/utf8>>}, oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<"components.callbacks"/utf8>> ) )] end, lists:append([Header_w, Example_w, Link_w, Callback_w]); none -> [] end, Operation_callback_warnings = gleam@list:filter_map( Ops, fun(Op@2) -> {Op_id@2, Operation@2, _, _} = Op@2, case gleam@dict:is_empty(erlang:element(11, Operation@2)) of true -> {error, nil}; false -> Path@4 = <>, {ok, oaspec@openapi@diagnostic:capability( Path@4, <<"Operation-level callbacks are parsed and preserved but not used by code generation."/utf8>>, severity_warning, target_both, {some, <<"The callback endpoints listed here will not appear in generated server/client code. No action needed unless you expected handler stubs."/utf8>>}, lookup_loc(Ctx, Index, Path@4) )} end end ), lists:append( [Webhook_warnings, Response_warnings, Request_body_encoding_warnings, External_docs_warnings, Tag_warnings, Operation_server_warnings, Path_server_warnings, Component_warnings, Operation_callback_warnings] ). -file("src/oaspec/internal/openapi/capability_check.gleam", 166). ?DOC(false). -spec check_schema( binary(), oaspec@internal@openapi@schema:schema_object(), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_schema(Path, Schema_obj, Index) -> Metadata = oaspec@internal@openapi@schema:get_metadata(Schema_obj), Keyword_errors = case erlang:element(12, Metadata) of [] -> []; Keywords -> Keyword_list = gleam@string:join(Keywords, <<"', '"/utf8>>), Loc = case Keywords of [First | _] -> oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, <<<>/binary, First/binary>> ); [] -> oaspec@internal@openapi@location_index:lookup_with_ancestor( Index, Path ) end, [oaspec@openapi@diagnostic:capability( Path, <<<<<<"Unsupported JSON Schema keyword '"/utf8, Keyword_list/binary>>/binary, "' found. Remove or model differently. See: "/utf8>>/binary, (gleam@string:join( gleam@list:filter_map( Keywords, fun(K) -> _pipe = gleam@list:find( oaspec@internal@capability:registry(), fun(C) -> erlang:element(2, C) =:= K end ), gleam@result:map( _pipe, fun(C@1) -> erlang:element(5, C@1) end ) end ), <<"; "/utf8>> ))/binary>>, severity_error, target_both, {some, <<"Remove the keyword or restructure the schema using supported constructs."/utf8>>}, Loc )] end, Child_errors = case Schema_obj of {object_schema, _, Properties, _, Additional_properties, _, _} -> Prop_errors = begin _pipe@1 = maps:to_list(Properties), gleam@list:flat_map( _pipe@1, fun(E) -> check_schema_ref( <<<>/binary, (erlang:element(1, E))/binary>>, erlang:element(2, E), Index ) end ) end, Ap_errors = case Additional_properties of {typed, Ap} -> check_schema_ref( <>, Ap, Index ); _ -> [] end, lists:append(Prop_errors, Ap_errors); {array_schema, _, Items, _, _, _} -> check_schema_ref(<>, Items, Index); {all_of_schema, _, Schemas} -> gleam@list:flat_map( Schemas, fun(S) -> check_schema_ref(<>, S, Index) end ); {one_of_schema, _, Schemas@1, _} -> gleam@list:flat_map( Schemas@1, fun(S@1) -> check_schema_ref(<>, S@1, Index) end ); {any_of_schema, _, Schemas@2, _} -> gleam@list:flat_map( Schemas@2, fun(S@2) -> check_schema_ref(<>, S@2, Index) end ); _ -> [] end, lists:append(Keyword_errors, Child_errors). -file("src/oaspec/internal/openapi/capability_check.gleam", 154). ?DOC(false). -spec check_schema_ref( binary(), oaspec@internal@openapi@schema:schema_ref(), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_schema_ref(Path, Ref, Index) -> case Ref of {reference, _, _} -> []; {inline, Schema_obj} -> check_schema(Path, Schema_obj, Index) end. -file("src/oaspec/internal/openapi/capability_check.gleam", 99). ?DOC(false). -spec check_operation_schemas( binary(), oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_operation_schemas(Base_path, Op, Index) -> Rb_errors = case erlang:element(7, Op) of {some, {value, Rb}} -> _pipe = maps:to_list(erlang:element(3, Rb)), gleam@list:flat_map( _pipe, fun(Entry) -> {Ct, Mt} = Entry, case erlang:element(2, Mt) of {some, Sr} -> check_schema_ref( <<<<<>/binary, Ct/binary>>/binary, ".schema"/utf8>>, Sr, Index ); none -> [] end end ); _ -> [] end, Resp_errors = begin _pipe@1 = maps:to_list(erlang:element(8, Op)), gleam@list:flat_map( _pipe@1, fun(Entry@1) -> {Code, Ref_or} = Entry@1, case Ref_or of {value, Resp} -> _pipe@2 = maps:to_list(erlang:element(3, Resp)), gleam@list:flat_map( _pipe@2, fun(Ct_entry) -> {Ct@1, Mt@1} = Ct_entry, case erlang:element(2, Mt@1) of {some, Sr@1} -> check_schema_ref( <<<<<<<<<>/binary, (oaspec@internal@util@http:status_code_to_string( Code ))/binary>>/binary, ".content."/utf8>>/binary, Ct@1/binary>>/binary, ".schema"/utf8>>, Sr@1, Index ); none -> [] end end ); _ -> [] end end ) end, lists:append(Rb_errors, Resp_errors). -file("src/oaspec/internal/openapi/capability_check.gleam", 75). ?DOC(false). -spec check_path_item_schemas( binary(), oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_path_item_schemas(Base_path, Pi, Index) -> Method_ops = [{<<"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:flat_map( Method_ops, fun(Entry) -> {Method, Maybe_op} = Entry, case Maybe_op of {some, Op} -> check_operation_schemas( <<<>/binary, Method/binary>>, Op, Index ); none -> [] end end ). -file("src/oaspec/internal/openapi/capability_check.gleam", 60). ?DOC(false). -spec check_inline_schemas( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_inline_schemas(Spec, Index) -> _pipe = maps:to_list(erlang:element(4, Spec)), gleam@list:flat_map( _pipe, fun(Path_entry) -> {Path, Ref_or} = Path_entry, case Ref_or of {value, Path_item} -> check_path_item_schemas( <<"paths."/utf8, Path/binary>>, Path_item, Index ); _ -> [] end end ). -file("src/oaspec/internal/openapi/capability_check.gleam", 42). ?DOC(false). -spec check_schemas( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check_schemas(Spec, Index) -> Component_errors = 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, check_schema_ref( <<"components.schemas."/utf8, Name/binary>>, Schema_ref, Index ) end ) end, Inline_errors = check_inline_schemas(Spec, Index), lists:append(Component_errors, Inline_errors). -file("src/oaspec/internal/openapi/capability_check.gleam", 31). ?DOC(false). -spec check( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:resolved()), oaspec@internal@openapi@location_index:location_index() ) -> list(oaspec@openapi@diagnostic:diagnostic()). check(Spec, Index) -> Schema_errors = check_schemas(Spec, Index), Security_errors = check_security_schemes(Spec, Index), lists:append([Schema_errors, Security_errors]).