-module(oaspec@internal@openapi@external_loader_planner). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/internal/openapi/external_loader_planner.gleam"). -export([extract_external_component_ref/1, find_external_parameter/3, find_external_request_body/3, find_external_response/3, find_external_path_item/3, check_nested_local_collision/3, check_nested_cross_file_collision/3, check_local_collision/4, check_cross_file_collision/3, extract_external_ref/1, local_schema_names/1, local_schema_name_from_ref/1, find_schema_follow_alias/3, find_external_schema/3, base_dir_of/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/external_loader_planner.gleam", 59). ?DOC(false). -spec try_component_prefix(binary(), binary(), list(binary())) -> gleam@option:option({binary(), binary(), binary()}). try_component_prefix(File_path, Fragment, Prefixes) -> case Prefixes of [] -> none; [Prefix | Rest] -> case gleam_stdlib:string_starts_with(Fragment, Prefix) of true -> Name = gleam@string:replace(Fragment, Prefix, <<""/utf8>>), case {gleam_stdlib:contains_string(Name, <<"/"/utf8>>), Name} of {false, <<""/utf8>>} -> none; {false, _} -> {some, {File_path, Prefix, Name}}; {true, _} -> none end; false -> try_component_prefix(File_path, Fragment, Rest) end end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 40). ?DOC(false). -spec extract_external_component_ref(binary()) -> gleam@option:option({binary(), binary(), binary()}). extract_external_component_ref(Ref_str) -> Is_relative = gleam_stdlib:string_starts_with(Ref_str, <<"./"/utf8>>) orelse gleam_stdlib:string_starts_with( Ref_str, <<"../"/utf8>> ), gleam@bool:guard( not Is_relative, none, fun() -> case gleam@string:split_once(Ref_str, <<"#"/utf8>>) of {ok, {File_path, Fragment}} -> try_component_prefix( File_path, Fragment, [<<"/components/parameters/"/utf8>>, <<"/components/requestBodies/"/utf8>>, <<"/components/responses/"/utf8>>, <<"/components/pathItems/"/utf8>>] ); _ -> none end end ). -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 82). ?DOC(false). -spec find_external_parameter( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_external_parameter(Loaded, Name, Source_path) -> case erlang:element(5, Loaded) of {some, Components} -> case gleam_stdlib:map_get(erlang:element(3, Components), Name) of {ok, {value, P}} -> {ok, P}; {ok, {ref, _}} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External parameter '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' is itself a $ref; chained external refs are not supported."/utf8>>, severity_error, target_both, {some, <<"Inline the parameter in the external file or flatten the ref chain."/utf8>>} )}; {error, nil} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components.parameters."/utf8>>/binary, Name/binary>>, severity_error, target_both, {some, <<"Verify the ref path and that the referenced file defines the parameter."/utf8>>} )} end; none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components block."/utf8>>, severity_error, target_both, {some, <<"Add a components.parameters section to the referenced file."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 133). ?DOC(false). -spec find_external_request_body( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_external_request_body(Loaded, Name, Source_path) -> case erlang:element(5, Loaded) of {some, Components} -> case gleam_stdlib:map_get(erlang:element(4, Components), Name) of {ok, {value, Rb}} -> {ok, Rb}; {ok, {ref, _}} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External request body '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' is itself a $ref; chained external refs are not supported."/utf8>>, severity_error, target_both, {some, <<"Inline the request body in the external file or flatten the ref chain."/utf8>>} )}; {error, nil} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components.requestBodies."/utf8>>/binary, Name/binary>>, severity_error, target_both, {some, <<"Verify the ref path and that the referenced file defines the request body."/utf8>>} )} end; none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components block."/utf8>>, severity_error, target_both, {some, <<"Add a components.requestBodies section to the referenced file."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 184). ?DOC(false). -spec find_external_response( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_external_response(Loaded, Name, Source_path) -> case erlang:element(5, Loaded) of {some, Components} -> case gleam_stdlib:map_get(erlang:element(5, Components), Name) of {ok, {value, R}} -> {ok, R}; {ok, {ref, _}} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External response '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' is itself a $ref; chained external refs are not supported."/utf8>>, severity_error, target_both, {some, <<"Inline the response in the external file or flatten the ref chain."/utf8>>} )}; {error, nil} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components.responses."/utf8>>/binary, Name/binary>>, severity_error, target_both, {some, <<"Verify the ref path and that the referenced file defines the response."/utf8>>} )} end; none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components block."/utf8>>, severity_error, target_both, {some, <<"Add a components.responses section to the referenced file."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 233). ?DOC(false). -spec find_external_path_item( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_external_path_item(Loaded, Name, Source_path) -> case erlang:element(5, Loaded) of {some, Components} -> case gleam_stdlib:map_get(erlang:element(7, Components), Name) of {ok, {value, Pi}} -> {ok, Pi}; {ok, {ref, _}} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External path item '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' is itself a $ref; chained external refs are not supported."/utf8>>, severity_error, target_both, {some, <<"Inline the path item in the external file or flatten the ref chain."/utf8>>} )}; {error, nil} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components.pathItems."/utf8>>/binary, Name/binary>>, severity_error, target_both, {some, <<"Verify the ref path and that the referenced file defines the path item."/utf8>>} )} end; none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components block."/utf8>>, severity_error, target_both, {some, <<"Add a components.pathItems section to the referenced file."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 285). ?DOC(false). -spec check_nested_local_collision(binary(), binary(), list(binary())) -> {ok, nil} | {error, oaspec@openapi@diagnostic:diagnostic()}. check_nested_local_collision(Fragment_name, Source_path, Original_local_names) -> gleam@bool:guard( not gleam@list:contains(Original_local_names, Fragment_name), {ok, nil}, fun() -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"Nested property $ref imports schema '"/utf8, Fragment_name/binary>>/binary, "' from '"/utf8>>/binary, Source_path/binary>>/binary, "', but a local schema with the same name is already defined."/utf8>>, severity_error, target_both, {some, <<"Rename one of the colliding schemas, or point the external ref at a file whose fragment name is unique."/utf8>>} )} end ). -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 312). ?DOC(false). -spec check_nested_cross_file_collision( binary(), binary(), gleam@dict:dict(binary(), {binary(), oaspec@internal@openapi@schema:schema_ref()}) ) -> {ok, nil} | {error, oaspec@openapi@diagnostic:diagnostic()}. check_nested_cross_file_collision(Fragment_name, Resolved_path, Imports) -> case gleam_stdlib:map_get(Imports, Fragment_name) of {error, _} -> {ok, nil}; {ok, {Prev_path, _}} -> case Prev_path =:= Resolved_path of true -> {ok, nil}; false -> {error, oaspec@openapi@diagnostic:validation( Resolved_path, <<<<<<<<<<<<"Nested property $ref imports schema '"/utf8, Fragment_name/binary>>/binary, "' from '"/utf8>>/binary, Resolved_path/binary>>/binary, "', but the same name was already imported from '"/utf8>>/binary, Prev_path/binary>>/binary, "'."/utf8>>, severity_error, target_both, {some, <<"Rename one of the schemas in the source files so imports do not collide."/utf8>>} )} end end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 348). ?DOC(false). -spec check_local_collision(binary(), binary(), binary(), list(binary())) -> {ok, nil} | {error, oaspec@openapi@diagnostic:diagnostic()}. check_local_collision( Entry_name, Fragment_name, Source_path, Original_local_names ) -> gleam@bool:guard( Entry_name =:= Fragment_name, {ok, nil}, fun() -> gleam@bool:guard( not gleam@list:contains(Original_local_names, Fragment_name), {ok, nil}, fun() -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External $ref imports schema '"/utf8, Fragment_name/binary>>/binary, "' from '"/utf8>>/binary, Source_path/binary>>/binary, "', but a local schema with the same name is already defined."/utf8>>, severity_error, target_both, {some, <<"Rename one of the colliding schemas, or point the external ref at a file whose fragment name is unique."/utf8>>} )} end ) end ). -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 377). ?DOC(false). -spec check_cross_file_collision( binary(), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, nil} | {error, oaspec@openapi@diagnostic:diagnostic()}. check_cross_file_collision(Fragment_name, Resolved_path, Imported) -> case gleam_stdlib:map_get(Imported, Fragment_name) of {error, _} -> {ok, nil}; {ok, Prev_path} -> case Prev_path =:= Resolved_path of true -> {ok, nil}; false -> {error, oaspec@openapi@diagnostic:validation( Resolved_path, <<<<<<<<<<<<"External $ref imports schema '"/utf8, Fragment_name/binary>>/binary, "' from '"/utf8>>/binary, Resolved_path/binary>>/binary, "', but the same name was already imported from '"/utf8>>/binary, Prev_path/binary>>/binary, "'."/utf8>>, severity_error, target_both, {some, <<"Rename one of the schemas in the source files so imports do not collide."/utf8>>} )} end end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 411). ?DOC(false). -spec extract_external_ref(oaspec@internal@openapi@schema:schema_ref()) -> gleam@option:option({binary(), binary()}). extract_external_ref(Schema_ref) -> case Schema_ref of {reference, Ref, _} -> case gleam_stdlib:string_starts_with(Ref, <<"./"/utf8>>) orelse gleam_stdlib:string_starts_with( Ref, <<"../"/utf8>> ) of true -> case gleam@string:split_once(Ref, <<"#"/utf8>>) of {ok, {File_path, Fragment}} -> case gleam_stdlib:string_starts_with( Fragment, <<"/components/schemas/"/utf8>> ) of true -> Name = gleam@string:replace( Fragment, <<"/components/schemas/"/utf8>>, <<""/utf8>> ), case {gleam_stdlib:contains_string( Name, <<"/"/utf8>> ), Name} of {false, <<""/utf8>>} -> none; {false, _} -> {some, {File_path, Name}}; {true, _} -> none end; false -> none end; _ -> none end; false -> none end; _ -> none end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 28). ?DOC(false). -spec local_schema_names( list({binary(), oaspec@internal@openapi@schema:schema_ref()}) ) -> list(binary()). local_schema_names(Entries) -> gleam@list:filter_map( Entries, fun(Entry) -> case extract_external_ref(erlang:element(2, Entry)) of {some, _} -> {error, nil}; none -> {ok, erlang:element(1, Entry)} end end ). -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 530). ?DOC(false). -spec local_schema_name_from_ref(binary()) -> gleam@option:option(binary()). local_schema_name_from_ref(Ref) -> Prefix = <<"#/components/schemas/"/utf8>>, case gleam_stdlib:string_starts_with(Ref, Prefix) of true -> Name = gleam@string:replace(Ref, Prefix, <<""/utf8>>), case {gleam_stdlib:contains_string(Name, <<"/"/utf8>>), Name} of {false, <<""/utf8>>} -> none; {false, _} -> {some, Name}; {true, _} -> none end; false -> none end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 467). ?DOC(false). -spec find_schema_follow_alias( oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@schema:schema_ref()} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_schema_follow_alias(Components, Name, Source_path) -> case gleam_stdlib:map_get(erlang:element(2, Components), Name) of {ok, {inline, _} = S} -> {ok, S}; {ok, {reference, Ref, _}} -> case local_schema_name_from_ref(Ref) of {some, Aliased} -> case gleam_stdlib:map_get( erlang:element(2, Components), Aliased ) of {ok, {inline, _} = S@1} -> {ok, S@1}; _ -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<<<<<"External schema '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' aliases '"/utf8>>/binary, Aliased/binary>>/binary, "', but the target is itself a $ref or missing; only a single level of aliasing inside the same file is supported."/utf8>>, severity_error, target_both, {some, <<"Flatten the alias chain in the external file so the target resolves to an inline schema."/utf8>>} )} end; none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<<<"External schema '"/utf8, Name/binary>>/binary, "' in '"/utf8>>/binary, Source_path/binary>>/binary, "' is itself a $ref pointing outside this file; chained external refs are not supported yet."/utf8>>, severity_error, target_both, {some, <<"Inline the external schema or flatten the ref to live inside the same file."/utf8>>} )} end; {error, nil} -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components.schemas."/utf8>>/binary, Name/binary>>, severity_error, target_both, {some, <<"Verify the ref path and that the referenced file defines the schema."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 442). ?DOC(false). -spec find_external_schema( oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()), binary(), binary() ) -> {ok, oaspec@internal@openapi@schema:schema_ref()} | {error, oaspec@openapi@diagnostic:diagnostic()}. find_external_schema(Loaded, Name, Source_path) -> case erlang:element(5, Loaded) of {some, Components} -> find_schema_follow_alias(Components, Name, Source_path); none -> {error, oaspec@openapi@diagnostic:validation( Source_path, <<<<"External file '"/utf8, Source_path/binary>>/binary, "' has no components block."/utf8>>, severity_error, target_both, {some, <<"Add a components.schemas section to the referenced file or inline the schema."/utf8>>} )} end. -file("src/oaspec/internal/openapi/external_loader_planner.gleam", 549). ?DOC(false). -spec base_dir_of(binary()) -> gleam@option:option(binary()). base_dir_of(Path) -> case filepath:directory_name(Path) of <<""/utf8>> -> {some, <<"."/utf8>>}; Dir -> {some, Dir} end.