Current section

Files

Jump to
oaspec src oaspec@internal@openapi@external_loader_planner.erl
Raw

src/oaspec@internal@openapi@external_loader_planner.erl

-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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@openapi@spec:parameter(oaspec@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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@openapi@spec:request_body(oaspec@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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@openapi@spec:response(oaspec@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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@openapi@spec:path_item(oaspec@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@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@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@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@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
binary(),
binary()
) -> {ok, oaspec@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.