Packages
oaspec
0.26.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec@openapi@external_loader.erl
-module(oaspec@openapi@external_loader).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/openapi/external_loader.gleam").
-export([base_dir_of/1, resolve_external_component_refs/3]).
-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(
" Support for external `$ref` values that point at component definitions\n"
" in a sibling YAML/JSON file — `./other.yaml#/components/schemas/Foo`\n"
" style. Walks `components.schemas`, pulls referenced schemas from the\n"
" target file into the main spec, and rewrites the refs to local form.\n"
"\n"
" Supported shapes:\n"
" - top-level component schema entries (`components.schemas.Foo: $ref: ...`)\n"
" - ObjectSchema property values (`properties.field: $ref: ...`)\n"
" - ArraySchema item values (`items: $ref: ...`)\n"
" - ObjectSchema additionalProperties values (`additionalProperties: $ref: ...`)\n"
" - composition branches (`oneOf`, `anyOf`, `allOf` variant refs)\n"
" - `components.parameters.*.schema: $ref: ...` (parameter schema only)\n"
" - `components.parameters.*.content.*.schema: $ref: ...`\n"
" - `components.request_bodies.*.content.*.schema: $ref: ...`\n"
" - `components.responses.*.content.*.schema: $ref: ...`\n"
" - operation-level `parameters[*].schema` / `parameters[*].content.*.schema`\n"
" on both `paths.<path>.parameters` and `paths.<path>.<method>.parameters`\n"
" - operation-level `requestBody.content.*.schema`\n"
" - operation-level `responses.<code>.content.*.schema`\n"
" - `components.headers.*.schema` and every `Response.headers.*.schema`\n"
" (both under `components.responses` and operation-level responses)\n"
" - refs inside `components.path_items.*` (reusable PathItem\n"
" definitions, walked via the same `rewrite_path_item` helper\n"
" used at the top level)\n"
" - refs inside `operation.callbacks.*.entries.*` PathItems (recursive)\n"
" - whole-object external refs for `components.parameters`,\n"
" `components.requestBodies`, `components.responses`, and\n"
" `components.pathItems` (e.g., `$ref: './other.yaml#/components/parameters/Foo'`)\n"
" - one level of alias chaining inside the same external file\n"
" (`LegacyX: $ref: \"#/components/schemas/X\"` in the external file).\n"
" Cross-file chains collapse naturally because parse_file runs\n"
" the resolver on every loaded file before handing it back, so a\n"
" target that is itself an external ref is already inline by the\n"
" time we look it up.\n"
"\n"
" Out of scope (see issue #98 parent):\n"
" - alias chains longer than one hop inside the same file\n"
" - HTTP/HTTPS URLs\n"
"\n"
" Cyclic external refs (e.g., `A.yaml` → `B.yaml` → `A.yaml`) used\n"
" to loop forever, but are now detected: `parser.parse_file`\n"
" threads a visited-file stack through every recursive load and\n"
" emits a dedicated `invalid_value` diagnostic that shows the cycle\n"
" path instead of recursing indefinitely (issue #233).\n"
"\n"
" Name collisions — when an external ref would overwrite an existing local\n"
" schema, or when two external refs pull in the same fragment name from\n"
" different files — are surfaced as `Diagnostic` errors rather than\n"
" silently dropping one side.\n"
).
-file("src/oaspec/openapi/external_loader.gleam", 252).
?DOC(" Try each component prefix against a fragment, returning the first match.\n").
-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/openapi/external_loader.gleam", 233).
?DOC(
" Detect external refs like `./other.yaml#/components/parameters/Foo`.\n"
" Returns Some(#(file_path, component_prefix, name)) or None.\n"
" Supported prefixes: parameters, requestBodies, responses, pathItems.\n"
).
-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/openapi/external_loader.gleam", 330).
?DOC(
" Generic helper that walks a `Dict(String, RefOr(a))`, resolving any\n"
" `Ref(ref_str)` whose fragment matches `target_prefix` by loading the\n"
" external file and looking up the named object via `finder`.\n"
).
-spec resolve_ref_or_dict(
gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(RLY)),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
binary(),
fun((oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()), binary(), binary()) -> {ok,
RLY} |
{error, oaspec@openapi@diagnostic:diagnostic()})
) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(RLY))} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
resolve_ref_or_dict(Entries, Base_dir, Parse_file, Target_prefix, Finder) ->
Pairs = maps:to_list(Entries),
gleam@result:'try'(
gleam@list:try_fold(
Pairs,
[],
fun(Acc, Entry) ->
{Name, Ref_or_val} = Entry,
case Ref_or_val of
{ref, Ref_str} ->
case extract_external_component_ref(Ref_str) of
{some, {File_path, Prefix, Obj_name}} when Prefix =:= Target_prefix ->
Resolved_path = filepath:join(
Base_dir,
File_path
),
gleam@result:'try'(
Parse_file(Resolved_path),
fun(Loaded) ->
gleam@result:'try'(
Finder(
Loaded,
Obj_name,
Resolved_path
),
fun(Target) ->
{ok,
[{Name, {value, Target}} |
Acc]}
end
)
end
);
_ ->
{ok, [{Name, Ref_or_val} | Acc]}
end;
{value, _} ->
{ok, [{Name, Ref_or_val} | Acc]}
end
end
),
fun(New_pairs) ->
{ok,
gleam@list:fold(
New_pairs,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
)}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 364).
?DOC(" Look up a parameter by name in an external file's components.\n").
-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/openapi/external_loader.gleam", 415).
?DOC(" Look up a request body by name in an external file's components.\n").
-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/openapi/external_loader.gleam", 466).
?DOC(" Look up a response by name in an external file's components.\n").
-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/openapi/external_loader.gleam", 515).
?DOC(" Look up a path item by name in an external file's components.\n").
-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/openapi/external_loader.gleam", 279).
?DOC(
" Walk `components.parameters`, `request_bodies`, `responses`, and\n"
" `path_items`: for each `Ref(ref_str)` entry that is an external\n"
" component ref (e.g., `./other.yaml#/components/parameters/Foo`),\n"
" load the external file and replace the entry with `Value(loaded_object)`.\n"
" Runs after `process_components` and before `process_nested_property_refs`.\n"
).
-spec process_whole_object_refs(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()})
) -> {ok, oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_whole_object_refs(Components, Base_dir, Parse_file) ->
gleam@result:'try'(
resolve_ref_or_dict(
erlang:element(3, Components),
Base_dir,
Parse_file,
<<"/components/parameters/"/utf8>>,
fun find_external_parameter/3
),
fun(New_parameters) ->
gleam@result:'try'(
resolve_ref_or_dict(
erlang:element(4, Components),
Base_dir,
Parse_file,
<<"/components/requestBodies/"/utf8>>,
fun find_external_request_body/3
),
fun(New_request_bodies) ->
gleam@result:'try'(
resolve_ref_or_dict(
erlang:element(5, Components),
Base_dir,
Parse_file,
<<"/components/responses/"/utf8>>,
fun find_external_response/3
),
fun(New_responses) ->
gleam@result:'try'(
resolve_ref_or_dict(
erlang:element(7, Components),
Base_dir,
Parse_file,
<<"/components/pathItems/"/utf8>>,
fun find_external_path_item/3
),
fun(New_path_items) ->
{ok,
{components,
erlang:element(2, Components),
New_parameters,
New_request_bodies,
New_responses,
erlang:element(6, Components),
New_path_items,
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)}}
end
)
end
)
end
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 722).
?DOC(
" Placeholder target used to seed the nested-import tracker with top-level\n"
" imports whose schema was already merged. `Reference(\"\", \"\")` is never\n"
" emitted as a real value — the merge step filters it out by matching only\n"
" on `Inline(_)` targets.\n"
).
-spec no_target() -> oaspec@openapi@schema:schema_ref().
no_target() ->
{reference, <<""/utf8>>, <<""/utf8>>}.
-file("src/oaspec/openapi/external_loader.gleam", 1720).
?DOC(
" Reject a nested property ref whose fragment name collides with a schema\n"
" that was authored inline in the main spec. Without this guard the nested\n"
" import would silently rebind to the local schema — even if its shape is\n"
" unrelated — because the merged dict already holds that slot.\n"
).
-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/openapi/external_loader.gleam", 1747).
?DOC(
" Same shape as `check_cross_file_collision` but reads from the\n"
" `imports: Dict(fragment_name, #(source_path, target_schema))` dict used\n"
" by the nested-property phase.\n"
).
-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/openapi/external_loader.gleam", 1783).
?DOC(
" Reject an external ref whose fragment name would collide with a schema\n"
" already defined locally in the same spec. The case where the entry name\n"
" equals the fragment name (`Widget: $ref: './other.yaml#/.../Widget'`) is\n"
" intentionally allowed — we treat it as the user asking for that slot to\n"
" hold the imported schema.\n"
).
-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/openapi/external_loader.gleam", 1812).
?DOC(
" Reject two external refs that both pull the same fragment name from\n"
" different source files. Re-importing the same name from the same path is\n"
" allowed (idempotent) to keep error messages narrow.\n"
).
-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/openapi/external_loader.gleam", 1846).
?DOC(
" Detect a `./...#/components/schemas/Name` or `../...#/components/schemas/Name`\n"
" ref. Returns `Some(#(file_path, schema_name))` when it matches, `None`\n"
" otherwise.\n"
).
-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/openapi/external_loader.gleam", 221).
?DOC(
" Names in the current spec that are *not themselves* external refs.\n"
" These are the schemas the external loader must not silently overwrite.\n"
).
-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/openapi/external_loader.gleam", 1963).
?DOC(
" If `ref` is a local component-schemas ref inside the same file (no\n"
" leading file part), return the schema name. Otherwise return None\n"
" so the caller can surface a cross-file diagnostic.\n"
).
-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/openapi/external_loader.gleam", 1900).
?DOC(
" Look up `name` in the external file's `components.schemas`. If the\n"
" value is inline, return it directly. If it is a local alias\n"
" (`#/components/schemas/Other`) pointing at another schema *in the\n"
" same file*, follow the alias one level. Cross-file chained refs and\n"
" longer alias chains still surface a diagnostic.\n"
).
-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/openapi/external_loader.gleam", 1875).
-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/openapi/external_loader.gleam", 161).
-spec process_components(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), binary())}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_components(Components, Base_dir, Parse_file, Original_local_names) ->
Entries = maps:to_list(erlang:element(2, Components)),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], maps:new()},
fun(Acc, Entry) ->
{Pending, Imported} = Acc,
{Name, Schema_ref} = Entry,
case extract_external_ref(Schema_ref) of
{some, {Rel_path, Fragment_name}} ->
Resolved_path = filepath:join(Base_dir, Rel_path),
gleam@result:'try'(
check_local_collision(
Name,
Fragment_name,
Resolved_path,
Original_local_names
),
fun(_) ->
gleam@result:'try'(
check_cross_file_collision(
Fragment_name,
Resolved_path,
Imported
),
fun(_) ->
gleam@result:'try'(
Parse_file(Resolved_path),
fun(Loaded) ->
gleam@result:'try'(
find_external_schema(
Loaded,
Fragment_name,
Resolved_path
),
fun(Target) ->
Local_ref = {reference,
<<"#/components/schemas/"/utf8,
Fragment_name/binary>>,
Fragment_name},
Pending@1 = [{Name,
Local_ref},
{Fragment_name,
Target} |
Pending],
Imported@1 = gleam@dict:insert(
Imported,
Fragment_name,
Resolved_path
),
{ok,
{Pending@1,
Imported@1}}
end
)
end
)
end
)
end
);
none ->
{ok, {[{Name, Schema_ref} | Pending], Imported}}
end
end
),
fun(_use0) ->
{New_entries, Imported@2} = _use0,
Merged = gleam@list:fold(
New_entries,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok,
{{components,
Merged,
erlang:element(3, Components),
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
erlang:element(7, Components),
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Imported@2}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1677).
?DOC(
" Core external-ref hoisting step shared by the property-value and\n"
" array-items resolvers. If `schema_ref` is a relative-file external ref,\n"
" the referenced schema is staged for merging and the ref is rewritten to\n"
" a local `#/components/schemas/<fragment>` ref. Otherwise the ref passes\n"
" through unchanged.\n"
).
-spec maybe_hoist_ref(
oaspec@openapi@schema:schema_ref(),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@schema:schema_ref(),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
maybe_hoist_ref(Schema_ref, Base_dir, Parse_file, Imports, Original_local_names) ->
case extract_external_ref(Schema_ref) of
{some, {Rel_path, Fragment_name}} ->
Resolved_path = filepath:join(Base_dir, Rel_path),
gleam@result:'try'(
check_nested_local_collision(
Fragment_name,
Resolved_path,
Original_local_names
),
fun(_) ->
gleam@result:'try'(
check_nested_cross_file_collision(
Fragment_name,
Resolved_path,
Imports
),
fun(_) ->
gleam@result:'try'(
Parse_file(Resolved_path),
fun(Loaded) ->
gleam@result:'try'(
find_external_schema(
Loaded,
Fragment_name,
Resolved_path
),
fun(Target) ->
Local_ref = {reference,
<<"#/components/schemas/"/utf8,
Fragment_name/binary>>,
Fragment_name},
New_imports = gleam@dict:insert(
Imports,
Fragment_name,
{Resolved_path, Target}
),
{ok, {Local_ref, New_imports}}
end
)
end
)
end
)
end
);
none ->
{ok, {Schema_ref, Imports}}
end.
-file("src/oaspec/openapi/external_loader.gleam", 1408).
?DOC(
" Walk a `Dict(String, Header)` and hoist any external `$ref` found\n"
" on `Header.schema`. Headers are not `RefOr(Header)`, so no\n"
" placeholder handling — just iterate the dict and rewrite each\n"
" entry that has a schema.\n"
).
-spec rewrite_header_map(
gleam@dict:dict(binary(), oaspec@openapi@spec:header()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@spec:header()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_header_map(Headers, Base_dir, Parse_file, Imports, Original_local_names) ->
Entries = maps:to_list(Headers),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Imports},
fun(Acc, Entry) ->
{Collected, Imports@1} = Acc,
{Name, Header} = Entry,
case erlang:element(4, Header) of
{some, Ref} ->
gleam@result:'try'(
maybe_hoist_ref(
Ref,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_ref, New_imports} = _use0,
New_header = {header,
erlang:element(2, Header),
erlang:element(3, Header),
{some, New_ref}},
{ok,
{[{Name, New_header} | Collected],
New_imports}}
end
);
none ->
{ok, {[{Name, Header} | Collected], Imports@1}}
end
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
New_map = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_map, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1450).
?DOC(
" Walk `components.headers` (plain `Dict(String, Header)`, not\n"
" `RefOr`) and hoist any external `$ref` found on `Header.schema`.\n"
" Runs after the other components-side passes so imported schemas\n"
" continue to flow into `components.schemas`.\n"
).
-spec process_component_headers(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()})
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_component_headers(
Components,
Base_dir,
Parse_file,
Original_local_names,
Seeded_imports
) ->
gleam@result:'try'(
rewrite_header_map(
erlang:element(8, Components),
Base_dir,
Parse_file,
Seeded_imports,
Original_local_names
),
fun(_use0) ->
{New_headers, Final_imports} = _use0,
New_schemas = gleam@dict:fold(
Final_imports,
erlang:element(2, Components),
fun(D, Frag_name, Pair) ->
{_, Target_schema} = Pair,
case {gleam@dict:has_key(D, Frag_name), Target_schema} of
{true, _} ->
D;
{false, {inline, _}} ->
gleam@dict:insert(D, Frag_name, Target_schema);
{false, _} ->
D
end
end
),
{ok,
{{components,
New_schemas,
erlang:element(3, Components),
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
erlang:element(7, Components),
New_headers,
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Final_imports}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1539).
?DOC(
" Walk every MediaType in a content-type dict and hoist any external ref\n"
" found on `MediaType.schema`. MediaType values with no schema pass\n"
" through unchanged.\n"
).
-spec rewrite_media_type_map(
gleam@dict:dict(binary(), oaspec@openapi@spec:media_type()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@spec:media_type()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_media_type_map(
Content,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
Entries = maps:to_list(Content),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Imports},
fun(Acc, Entry) ->
{Collected, Imports@1} = Acc,
{Media_key, Media} = Entry,
case erlang:element(2, Media) of
{some, Ref} ->
gleam@result:'try'(
maybe_hoist_ref(
Ref,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_ref, New_imports} = _use0,
New_media = {media_type,
{some, New_ref},
erlang:element(3, Media),
erlang:element(4, Media),
erlang:element(5, Media)},
{ok,
{[{Media_key, New_media} | Collected],
New_imports}}
end
);
none ->
{ok, {[{Media_key, Media} | Collected], Imports@1}}
end
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
New_content = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_content, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1109).
-spec rewrite_optional_request_body(
gleam@option:option(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved()))),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@option:option(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved()))),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_optional_request_body(
Body,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
case Body of
{some, {value, Rb}} ->
gleam@result:'try'(
rewrite_media_type_map(
erlang:element(3, Rb),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_content, New_imports} = _use0,
New_rb = {request_body,
erlang:element(2, Rb),
New_content,
erlang:element(4, Rb)},
{ok, {{some, {value, New_rb}}, New_imports}}
end
);
{some, {ref, _}} ->
{ok, {Body, Imports}};
none ->
{ok, {none, Imports}}
end.
-file("src/oaspec/openapi/external_loader.gleam", 1323).
?DOC(
" Rewrite a single `RefOr(Parameter)` by hoisting external refs inside\n"
" either a `ParameterSchema` or a `ParameterContent` payload. `Ref`\n"
" entries (external parameter-object refs) pass through unchanged.\n"
).
-spec rewrite_ref_or_parameter(
oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved())),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved())),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_ref_or_parameter(
Ref_or_param,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
case Ref_or_param of
{value, P} ->
case erlang:element(6, P) of
{parameter_schema, Schema_ref} ->
gleam@result:'try'(
maybe_hoist_ref(
Schema_ref,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_ref, New_imports} = _use0,
New_param = {parameter,
erlang:element(2, P),
erlang:element(3, P),
erlang:element(4, P),
erlang:element(5, P),
{parameter_schema, New_ref},
erlang:element(7, P),
erlang:element(8, P),
erlang:element(9, P),
erlang:element(10, P),
erlang:element(11, P)},
{ok, {{value, New_param}, New_imports}}
end
);
{parameter_content, Content} ->
gleam@result:'try'(
rewrite_media_type_map(
Content,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0@1) ->
{New_content, New_imports@1} = _use0@1,
New_param@1 = {parameter,
erlang:element(2, P),
erlang:element(3, P),
erlang:element(4, P),
erlang:element(5, P),
{parameter_content, New_content},
erlang:element(7, P),
erlang:element(8, P),
erlang:element(9, P),
erlang:element(10, P),
erlang:element(11, P)},
{ok, {{value, New_param@1}, New_imports@1}}
end
)
end;
{ref, _} ->
{ok, {Ref_or_param, Imports}}
end.
-file("src/oaspec/openapi/external_loader.gleam", 787).
?DOC(
" Rewrite each `RefOr(Parameter)` in a parameter list, threading the\n"
" imports tracker so collisions across operation-level and components\n"
" refs remain visible.\n"
).
-spec rewrite_parameter_list(
list(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved()))),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{list(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved()))),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_parameter_list(
Parameters,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
gleam@list:try_fold(
Parameters,
{[], Imports},
fun(Acc, Item) ->
{Done, Imports@1} = Acc,
gleam@result:'try'(
rewrite_ref_or_parameter(
Item,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_item, New_imports} = _use0,
{ok, {[New_item | Done], New_imports}}
end
)
end
),
fun(_use0@1) ->
{Collected, New_imports@1} = _use0@1,
{ok, {lists:reverse(Collected), New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1187).
?DOC(
" Walk `components.parameters`: for each inline `Parameter` whose payload is\n"
" a `ParameterSchema(SchemaRef)` pointing at a relative-file external ref,\n"
" hoist the target schema into `components.schemas` and rewrite the inner\n"
" ref. Parameters expressed via `content` media type maps, `Ref` placeholders\n"
" pointing at other parameter objects, and local refs all pass through.\n"
).
-spec process_parameter_schemas(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()})
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_parameter_schemas(
Components,
Base_dir,
Parse_file,
Original_local_names,
Seeded_imports
) ->
Entries = maps:to_list(erlang:element(3, Components)),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Seeded_imports},
fun(Acc, Entry) ->
{Collected, Imports} = Acc,
{Name, Ref_or_param} = Entry,
gleam@result:'try'(
rewrite_ref_or_parameter(
Ref_or_param,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_param, New_imports} = _use0,
{ok, {[{Name, New_param} | Collected], New_imports}}
end
)
end
),
fun(_use0@1) ->
{Rewritten, Imports@1} = _use0@1,
New_parameters = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
New_schemas = gleam@dict:fold(
Imports@1,
erlang:element(2, Components),
fun(D@1, Frag_name, Pair@1) ->
{_, Target_schema} = Pair@1,
case {gleam@dict:has_key(D@1, Frag_name), Target_schema} of
{true, _} ->
D@1;
{false, {inline, _}} ->
gleam@dict:insert(D@1, Frag_name, Target_schema);
{false, _} ->
D@1
end
end
),
{ok,
{{components,
New_schemas,
New_parameters,
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
erlang:element(7, Components),
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1372).
?DOC(
" Rewrite both the `content` media map and the `headers` map of a\n"
" single Response value. Shared by the components-side and operation-\n"
" side response walkers so header schemas get the same external-ref\n"
" treatment as body schemas.\n"
).
-spec rewrite_response_value(
oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_response_value(
Response,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
rewrite_media_type_map(
erlang:element(3, Response),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_content, Imports_after_content} = _use0,
gleam@result:'try'(
rewrite_header_map(
erlang:element(4, Response),
Base_dir,
Parse_file,
Imports_after_content,
Original_local_names
),
fun(_use0@1) ->
{New_headers, New_imports} = _use0@1,
{ok,
{{response,
erlang:element(2, Response),
New_content,
New_headers,
erlang:element(5, Response)},
New_imports}}
end
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1139).
-spec rewrite_response_map(
gleam@dict:dict(oaspec@util@http:http_status_code(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved()))),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(oaspec@util@http:http_status_code(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved()))),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_response_map(
Responses,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
Entries = maps:to_list(Responses),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Imports},
fun(Acc, Entry) ->
{Collected, Imports@1} = Acc,
{Status, Ref_or_resp} = Entry,
case Ref_or_resp of
{value, Resp} ->
gleam@result:'try'(
rewrite_response_value(
Resp,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_resp, New_imports} = _use0,
{ok,
{[{Status, {value, New_resp}} | Collected],
New_imports}}
end
);
{ref, _} ->
{ok, {[{Status, Ref_or_resp} | Collected], Imports@1}}
end
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
New_map = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_map, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1241).
?DOC(
" Walk `components.request_bodies` and `components.responses`, hoisting\n"
" any external `$ref` found on a `MediaType.schema` field inside the\n"
" `content` dict. The imports tracker is shared with earlier passes so\n"
" cross-file collisions across every component kind stay honest.\n"
" Entries whose top-level value is a `Ref(...)` (reference to an\n"
" external body/response object) pass through untouched — handling those\n"
" requires hoisting the body/response itself, not just its schema.\n"
).
-spec process_body_response_schemas(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()})
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_body_response_schemas(
Components,
Base_dir,
Parse_file,
Original_local_names,
Seeded_imports
) ->
Body_entries = maps:to_list(erlang:element(4, Components)),
gleam@result:'try'(
gleam@list:try_fold(
Body_entries,
{[], Seeded_imports},
fun(Acc, Entry) ->
{Collected, Imports} = Acc,
{Name, Ref_or_body} = Entry,
case Ref_or_body of
{value, Body} ->
gleam@result:'try'(
rewrite_media_type_map(
erlang:element(3, Body),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_content, New_imports} = _use0,
New_body = {request_body,
erlang:element(2, Body),
New_content,
erlang:element(4, Body)},
{ok,
{[{Name, {value, New_body}} | Collected],
New_imports}}
end
);
{ref, _} ->
{ok, {[{Name, Ref_or_body} | Collected], Imports}}
end
end
),
fun(_use0@1) ->
{New_bodies, Imports_after_bodies} = _use0@1,
Response_entries = maps:to_list(erlang:element(5, Components)),
gleam@result:'try'(
gleam@list:try_fold(
Response_entries,
{[], Imports_after_bodies},
fun(Acc@1, Entry@1) ->
{Collected@1, Imports@1} = Acc@1,
{Name@1, Ref_or_resp} = Entry@1,
case Ref_or_resp of
{value, Resp} ->
gleam@result:'try'(
rewrite_response_value(
Resp,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0@2) ->
{New_resp, New_imports@1} = _use0@2,
{ok,
{[{Name@1, {value, New_resp}} |
Collected@1],
New_imports@1}}
end
);
{ref, _} ->
{ok,
{[{Name@1, Ref_or_resp} | Collected@1],
Imports@1}}
end
end
),
fun(_use0@3) ->
{New_responses, Final_imports} = _use0@3,
New_request_bodies = gleam@list:fold(
New_bodies,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
New_responses_dict = gleam@list:fold(
New_responses,
maps:new(),
fun(D@1, Pair@1) ->
gleam@dict:insert(
D@1,
erlang:element(1, Pair@1),
erlang:element(2, Pair@1)
)
end
),
New_schemas = gleam@dict:fold(
Final_imports,
erlang:element(2, Components),
fun(D@2, Frag_name, Pair@2) ->
{_, Target_schema} = Pair@2,
case {gleam@dict:has_key(D@2, Frag_name),
Target_schema} of
{true, _} ->
D@2;
{false, {inline, _}} ->
gleam@dict:insert(
D@2,
Frag_name,
Target_schema
);
{false, _} ->
D@2
end
end
),
{ok,
{{components,
New_schemas,
erlang:element(3, Components),
New_request_bodies,
New_responses_dict,
erlang:element(6, Components),
erlang:element(7, Components),
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Final_imports}}
end
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1581).
?DOC(
" Walk the properties dict of an ObjectSchema; for each property that is a\n"
" relative-file `$ref`, resolve it, stage the target schema for merging,\n"
" and rewrite the property to a local ref. Non-external property refs pass\n"
" through unchanged.\n"
).
-spec rewrite_object_properties(
gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_object_properties(
Properties,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
Entries = maps:to_list(Properties),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Imports},
fun(Acc, Entry) ->
{Prop_acc, Imports@1} = Acc,
{Prop_name, Prop_ref} = Entry,
gleam@result:'try'(
maybe_hoist_ref(
Prop_ref,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_ref, New_imports} = _use0,
{ok, {[{Prop_name, New_ref} | Prop_acc], New_imports}}
end
)
end
),
fun(_use0@1) ->
{New_entries, New_imports@1} = _use0@1,
New_properties = gleam@list:fold(
New_entries,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_properties, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1617).
?DOC(
" Walk an ObjectSchema's `additionalProperties` value; when it is a\n"
" `Typed(SchemaRef)` whose ref is external, hoist the target schema and\n"
" rewrite the inner ref to a local reference. `Forbidden` and `Untyped`\n"
" pass through untouched.\n"
).
-spec rewrite_additional_properties(
oaspec@openapi@schema:additional_properties(),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@schema:additional_properties(),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_additional_properties(
Additional,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
case Additional of
{typed, Ref} ->
gleam@result:'try'(
maybe_hoist_ref(
Ref,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_ref, New_imports} = _use0,
{ok, {{typed, New_ref}, New_imports}}
end
);
_ ->
{ok, {Additional, Imports}}
end.
-file("src/oaspec/openapi/external_loader.gleam", 1646).
?DOC(
" Walk a `List(SchemaRef)` produced by an allOf/oneOf/anyOf composition,\n"
" hoisting any relative-file external ref the same way property values\n"
" and array items are handled. Branches that are inline or local refs\n"
" pass through unchanged.\n"
).
-spec rewrite_schema_list(
list(oaspec@openapi@schema:schema_ref()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{list(oaspec@openapi@schema:schema_ref()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_schema_list(
Branches,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
gleam@list:try_fold(
Branches,
{[], Imports},
fun(Acc, Branch) ->
{Collected, Imports@1} = Acc,
gleam@result:'try'(
maybe_hoist_ref(
Branch,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_branch, New_imports} = _use0,
{ok, {[New_branch | Collected], New_imports}}
end
)
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
{ok, {lists:reverse(Rewritten), New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 575).
?DOC(
" Walk each `components.schemas` entry that is an `Inline(ObjectSchema)` and\n"
" hoist any property whose value is a relative-file `$ref`. The referenced\n"
" schema is added to `components.schemas` under its fragment name, and the\n"
" property is rewritten to a local `#/components/schemas/<fragment>` ref.\n"
"\n"
" Runs after `process_components` so top-level external refs are already\n"
" merged in. Collisions are surfaced rather than silently resolved:\n"
" - if the nested fragment name matches a schema that was originally\n"
" authored inline in the main spec, error (silent-shadowing guard);\n"
" - if two refs pull the same fragment name from different source files\n"
" (whether nested or top-level), error;\n"
" - same-file re-imports remain idempotent.\n"
).
-spec process_nested_property_refs(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), binary())
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_nested_property_refs(
Components,
Base_dir,
Parse_file,
Original_local_names,
Top_imported
) ->
Entries = maps:to_list(erlang:element(2, Components)),
Seeded_imports = gleam@dict:fold(
Top_imported,
maps:new(),
fun(D, Frag_name, Source_path) ->
gleam@dict:insert(D, Frag_name, {Source_path, no_target()})
end
),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Seeded_imports},
fun(Acc, Entry) ->
{Rewritten_acc, Imports} = Acc,
{Name, Schema_ref} = Entry,
case Schema_ref of
{inline,
{object_schema,
Metadata,
Properties,
Required,
Additional_properties,
Min_properties,
Max_properties}} ->
gleam@result:'try'(
rewrite_object_properties(
Properties,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_properties, Props_imports} = _use0,
gleam@result:'try'(
rewrite_additional_properties(
Additional_properties,
Base_dir,
Parse_file,
Props_imports,
Original_local_names
),
fun(_use0@1) ->
{New_additional_properties, New_imports} = _use0@1,
New_obj = {object_schema,
Metadata,
New_properties,
Required,
New_additional_properties,
Min_properties,
Max_properties},
{ok,
{[{Name, {inline, New_obj}} |
Rewritten_acc],
New_imports}}
end
)
end
);
{inline,
{array_schema,
Metadata@1,
Items,
Min_items,
Max_items,
Unique_items}} ->
gleam@result:'try'(
maybe_hoist_ref(
Items,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0@2) ->
{New_items, New_imports@1} = _use0@2,
New_arr = {array_schema,
Metadata@1,
New_items,
Min_items,
Max_items,
Unique_items},
{ok,
{[{Name, {inline, New_arr}} | Rewritten_acc],
New_imports@1}}
end
);
{inline, {all_of_schema, Metadata@2, Branches}} ->
gleam@result:'try'(
rewrite_schema_list(
Branches,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0@3) ->
{New_branches, New_imports@2} = _use0@3,
New_all = {all_of_schema,
Metadata@2,
New_branches},
{ok,
{[{Name, {inline, New_all}} | Rewritten_acc],
New_imports@2}}
end
);
{inline,
{one_of_schema, Metadata@3, Branches@1, Discriminator}} ->
gleam@result:'try'(
rewrite_schema_list(
Branches@1,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0@4) ->
{New_branches@1, New_imports@3} = _use0@4,
New_one = {one_of_schema,
Metadata@3,
New_branches@1,
Discriminator},
{ok,
{[{Name, {inline, New_one}} | Rewritten_acc],
New_imports@3}}
end
);
{inline,
{any_of_schema, Metadata@4, Branches@2, Discriminator@1}} ->
gleam@result:'try'(
rewrite_schema_list(
Branches@2,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0@5) ->
{New_branches@2, New_imports@4} = _use0@5,
New_any = {any_of_schema,
Metadata@4,
New_branches@2,
Discriminator@1},
{ok,
{[{Name, {inline, New_any}} | Rewritten_acc],
New_imports@4}}
end
);
_ ->
{ok, {[{Name, Schema_ref} | Rewritten_acc], Imports}}
end
end
),
fun(_use0@6) ->
{Rewritten, Imports@1} = _use0@6,
Merged = gleam@list:fold(
Rewritten,
maps:new(),
fun(D@1, Pair) ->
gleam@dict:insert(
D@1,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
Merged@1 = gleam@dict:fold(
Imports@1,
Merged,
fun(D@2, Frag_name@1, Pair@1) ->
{_, Target_schema} = Pair@1,
case {gleam@dict:has_key(D@2, Frag_name@1), Target_schema} of
{true, _} ->
D@2;
{false, {inline, _}} ->
gleam@dict:insert(D@2, Frag_name@1, Target_schema);
{false, _} ->
D@2
end
end
),
{ok,
{{components,
Merged@1,
erlang:element(3, Components),
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
erlang:element(7, Components),
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1982).
?DOC(
" Helper used by `parser.parse_file` to compute a spec's base directory.\n"
" Empty-string (current working directory) is returned when the filepath\n"
" module can't extract a parent — callers can then pass `Some(\"\")` which\n"
" resolves relative refs against CWD.\n"
).
-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.
-file("src/oaspec/openapi/external_loader.gleam", 1066).
?DOC(
" Rewrite each PathItem inside a Callback.entries dict. The entries\n"
" map URL-expression strings to `RefOr(PathItem)`; inline PathItems\n"
" recurse via `rewrite_path_item`, Ref entries pass through.\n"
).
-spec rewrite_callback_entries(
gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()))),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()))),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_callback_entries(
Entries,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
Pairs = maps:to_list(Entries),
gleam@result:'try'(
gleam@list:try_fold(
Pairs,
{[], Imports},
fun(Acc, Entry) ->
{Collected, Imports@1} = Acc,
{Url_expr, Ref_or_item} = Entry,
case Ref_or_item of
{value, Path_item} ->
gleam@result:'try'(
rewrite_path_item(
Path_item,
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_path_item, New_imports} = _use0,
{ok,
{[{Url_expr, {value, New_path_item}} |
Collected],
New_imports}}
end
);
{ref, _} ->
{ok, {[{Url_expr, Ref_or_item} | Collected], Imports@1}}
end
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
New_map = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_map, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 819).
?DOC(
" Rewrite both the path-level `parameters` list and every populated\n"
" method slot on a `PathItem`. Shared by the top-level paths walker\n"
" and the callback walker so callbacks recurse into the same helper.\n"
).
-spec rewrite_path_item(
oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_path_item(
Path_item,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
rewrite_parameter_list(
erlang:element(12, Path_item),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_parameters, Imports_after_params} = _use0,
rewrite_path_item_methods(
{path_item,
erlang:element(2, Path_item),
erlang:element(3, Path_item),
erlang:element(4, Path_item),
erlang:element(5, Path_item),
erlang:element(6, Path_item),
erlang:element(7, Path_item),
erlang:element(8, Path_item),
erlang:element(9, Path_item),
erlang:element(10, Path_item),
erlang:element(11, Path_item),
New_parameters,
erlang:element(13, Path_item)},
Base_dir,
Parse_file,
Imports_after_params,
Original_local_names
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 850).
?DOC(
" Rewrite every populated HTTP-method slot on a `PathItem`. Each inline\n"
" `Operation` has its own `parameters`, `request_body`, and `responses`\n"
" dicts rewritten.\n"
).
-spec rewrite_path_item_methods(
oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_path_item_methods(
Path_item,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(4, Path_item),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{Get_op, Imports1} = _use0,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(5, Path_item),
Base_dir,
Parse_file,
Imports1,
Original_local_names
),
fun(_use0@1) ->
{Post_op, Imports2} = _use0@1,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(6, Path_item),
Base_dir,
Parse_file,
Imports2,
Original_local_names
),
fun(_use0@2) ->
{Put_op, Imports3} = _use0@2,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(7, Path_item),
Base_dir,
Parse_file,
Imports3,
Original_local_names
),
fun(_use0@3) ->
{Delete_op, Imports4} = _use0@3,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(8, Path_item),
Base_dir,
Parse_file,
Imports4,
Original_local_names
),
fun(_use0@4) ->
{Patch_op, Imports5} = _use0@4,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(9, Path_item),
Base_dir,
Parse_file,
Imports5,
Original_local_names
),
fun(_use0@5) ->
{Head_op, Imports6} = _use0@5,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(
10,
Path_item
),
Base_dir,
Parse_file,
Imports6,
Original_local_names
),
fun(_use0@6) ->
{Options_op,
Imports7} = _use0@6,
gleam@result:'try'(
rewrite_optional_operation(
erlang:element(
11,
Path_item
),
Base_dir,
Parse_file,
Imports7,
Original_local_names
),
fun(_use0@7) ->
{Trace_op,
Final_imports} = _use0@7,
{ok,
{{path_item,
erlang:element(
2,
Path_item
),
erlang:element(
3,
Path_item
),
Get_op,
Post_op,
Put_op,
Delete_op,
Patch_op,
Head_op,
Options_op,
Trace_op,
erlang:element(
12,
Path_item
),
erlang:element(
13,
Path_item
)},
Final_imports}}
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 932).
-spec rewrite_optional_operation(
gleam@option:option(oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved())),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@option:option(oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved())),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_optional_operation(
Op,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
case Op of
{some, Operation} ->
gleam@result:'try'(
rewrite_operation(
Operation,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_op, New_imports} = _use0,
{ok, {{some, New_op}, New_imports}}
end
);
none ->
{ok, {none, Imports}}
end.
-file("src/oaspec/openapi/external_loader.gleam", 960).
-spec rewrite_operation(
oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_operation(
Operation,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
gleam@result:'try'(
rewrite_parameter_list(
erlang:element(6, Operation),
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_params, Imports_after_params} = _use0,
gleam@result:'try'(
rewrite_optional_request_body(
erlang:element(7, Operation),
Base_dir,
Parse_file,
Imports_after_params,
Original_local_names
),
fun(_use0@1) ->
{New_body, Imports_after_body} = _use0@1,
gleam@result:'try'(
rewrite_response_map(
erlang:element(8, Operation),
Base_dir,
Parse_file,
Imports_after_body,
Original_local_names
),
fun(_use0@2) ->
{New_responses, Imports_after_responses} = _use0@2,
gleam@result:'try'(
rewrite_callback_map(
erlang:element(11, Operation),
Base_dir,
Parse_file,
Imports_after_responses,
Original_local_names
),
fun(_use0@3) ->
{New_callbacks, Final_imports} = _use0@3,
{ok,
{{operation,
erlang:element(2, Operation),
erlang:element(3, Operation),
erlang:element(4, Operation),
erlang:element(5, Operation),
New_params,
New_body,
New_responses,
erlang:element(9, Operation),
erlang:element(10, Operation),
New_callbacks,
erlang:element(12, Operation),
erlang:element(13, Operation)},
Final_imports}}
end
)
end
)
end
)
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1020).
?DOC(
" Walk `operation.callbacks`: for each callback, rewrite every inline\n"
" PathItem in its `entries` dict via the same `rewrite_path_item`\n"
" helper used at the top level. `Ref` entries pointing at external\n"
" PathItem objects pass through unchanged, and now so do top-level\n"
" `Ref` callback entries (e.g. `myEvent: { $ref: '#/components/callbacks/foo' }`),\n"
" which we keep as refs rather than inlining.\n"
).
-spec rewrite_callback_map(
gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:callback(oaspec@openapi@spec:unresolved()))),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()}),
list(binary())
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:callback(oaspec@openapi@spec:unresolved()))),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
rewrite_callback_map(
Callbacks,
Base_dir,
Parse_file,
Imports,
Original_local_names
) ->
Entries = maps:to_list(Callbacks),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Imports},
fun(Acc, Entry) ->
{Collected, Imports@1} = Acc,
{Name, Ref_or_callback} = Entry,
case Ref_or_callback of
{ref, _} = R ->
{ok, {[{Name, R} | Collected], Imports@1}};
{value, Callback} ->
gleam@result:'try'(
rewrite_callback_entries(
erlang:element(2, Callback),
Base_dir,
Parse_file,
Imports@1,
Original_local_names
),
fun(_use0) ->
{New_entries, New_imports} = _use0,
New_callback = {value, {callback, New_entries}},
{ok,
{[{Name, New_callback} | Collected],
New_imports}}
end
)
end
end
),
fun(_use0@1) ->
{Rewritten, New_imports@1} = _use0@1,
New_callbacks = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
{ok, {New_callbacks, New_imports@1}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 731).
?DOC(
" Walk `spec.paths`: for each inline `PathItem`, rewrite its path-level\n"
" `parameters` list, every populated HTTP method `Operation` (via\n"
" `rewrite_operation`), and feed any newly imported schemas into\n"
" `components.schemas`. `RefOr.Ref` path items passing pointers to\n"
" external files are left untouched.\n"
).
-spec process_operation_schemas(
gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()))),
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()})
) -> {ok,
{gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved()))),
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_operation_schemas(
Paths,
Components,
Base_dir,
Parse_file,
Original_local_names,
Seeded_imports
) ->
Entries = maps:to_list(Paths),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Seeded_imports},
fun(Acc, Entry) ->
{Collected, Imports} = Acc,
{Path_key, Ref_or_item} = Entry,
case Ref_or_item of
{value, Path_item} ->
gleam@result:'try'(
rewrite_path_item(
Path_item,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_path_item, New_imports} = _use0,
{ok,
{[{Path_key, {value, New_path_item}} |
Collected],
New_imports}}
end
);
{ref, _} ->
{ok, {[{Path_key, Ref_or_item} | Collected], Imports}}
end
end
),
fun(_use0@1) ->
{Rewritten, Final_imports} = _use0@1,
New_paths = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
New_schemas = gleam@dict:fold(
Final_imports,
erlang:element(2, Components),
fun(D@1, Frag_name, Pair@1) ->
{_, Target_schema} = Pair@1,
case {gleam@dict:has_key(D@1, Frag_name), Target_schema} of
{true, _} ->
D@1;
{false, {inline, _}} ->
gleam@dict:insert(D@1, Frag_name, Target_schema);
{false, _} ->
D@1
end
end
),
{ok,
{New_paths,
{components,
New_schemas,
erlang:element(3, Components),
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
erlang:element(7, Components),
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)}}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 1487).
?DOC(
" Walk `components.path_items`: for each inline `PathItem`, rewrite\n"
" its parameters, method operations, and callbacks via the shared\n"
" `rewrite_path_item` helper — the same one used for top-level\n"
" `spec.paths` and callback PathItems. `Ref` entries pointing at\n"
" external PathItem objects pass through unchanged.\n"
).
-spec process_component_path_items(
oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
binary(),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}),
list(binary()),
gleam@dict:dict(binary(), {binary(), oaspec@openapi@schema:schema_ref()})
) -> {ok,
{oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()),
gleam@dict:dict(binary(), {binary(),
oaspec@openapi@schema:schema_ref()})}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
process_component_path_items(
Components,
Base_dir,
Parse_file,
Original_local_names,
Seeded_imports
) ->
Entries = maps:to_list(erlang:element(7, Components)),
gleam@result:'try'(
gleam@list:try_fold(
Entries,
{[], Seeded_imports},
fun(Acc, Entry) ->
{Collected, Imports} = Acc,
{Name, Ref_or_item} = Entry,
case Ref_or_item of
{value, Path_item} ->
gleam@result:'try'(
rewrite_path_item(
Path_item,
Base_dir,
Parse_file,
Imports,
Original_local_names
),
fun(_use0) ->
{New_path_item, New_imports} = _use0,
{ok,
{[{Name, {value, New_path_item}} |
Collected],
New_imports}}
end
);
{ref, _} ->
{ok, {[{Name, Ref_or_item} | Collected], Imports}}
end
end
),
fun(_use0@1) ->
{Rewritten, Final_imports} = _use0@1,
New_path_items = gleam@list:fold(
Rewritten,
maps:new(),
fun(D, Pair) ->
gleam@dict:insert(
D,
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
),
New_schemas = gleam@dict:fold(
Final_imports,
erlang:element(2, Components),
fun(D@1, Frag_name, Pair@1) ->
{_, Target_schema} = Pair@1,
case {gleam@dict:has_key(D@1, Frag_name), Target_schema} of
{true, _} ->
D@1;
{false, {inline, _}} ->
gleam@dict:insert(D@1, Frag_name, Target_schema);
{false, _} ->
D@1
end
end
),
{ok,
{{components,
New_schemas,
erlang:element(3, Components),
erlang:element(4, Components),
erlang:element(5, Components),
erlang:element(6, Components),
New_path_items,
erlang:element(8, Components),
erlang:element(9, Components),
erlang:element(10, Components),
erlang:element(11, Components)},
Final_imports}}
end
).
-file("src/oaspec/openapi/external_loader.gleam", 74).
?DOC(
" Load every `components.schemas` entry whose value is an external\n"
" filesystem ref, merge the referenced schema into the main spec, and\n"
" rewrite the entry to a local ref. `base_dir` is the directory of the\n"
" file this spec was loaded from (used to resolve relative paths).\n"
"\n"
" If `base_dir` is None (spec loaded from string), external refs are\n"
" treated as unresolvable and passed through unchanged — downstream\n"
" validation still rejects them.\n"
).
-spec resolve_external_component_refs(
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
gleam@option:option(binary()),
fun((binary()) -> {ok,
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()})
) -> {ok, oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
resolve_external_component_refs(Spec, Base_dir, Parse_file) ->
case {erlang:element(5, Spec), Base_dir} of
{{some, Components}, {some, Dir}} ->
Original_local_names = local_schema_names(
maps:to_list(erlang:element(2, Components))
),
gleam@result:'try'(
process_components(
Components,
Dir,
Parse_file,
Original_local_names
),
fun(_use0) ->
{Top_resolved, Top_imported} = _use0,
gleam@result:'try'(
process_whole_object_refs(Top_resolved, Dir, Parse_file),
fun(Whole_resolved) ->
gleam@result:'try'(
process_nested_property_refs(
Whole_resolved,
Dir,
Parse_file,
Original_local_names,
Top_imported
),
fun(_use0@1) ->
{Nested_resolved, Nested_imports} = _use0@1,
gleam@result:'try'(
process_parameter_schemas(
Nested_resolved,
Dir,
Parse_file,
Original_local_names,
Nested_imports
),
fun(_use0@2) ->
{Param_resolved, Param_imports} = _use0@2,
gleam@result:'try'(
process_body_response_schemas(
Param_resolved,
Dir,
Parse_file,
Original_local_names,
Param_imports
),
fun(_use0@3) ->
{Body_resolved,
Body_imports} = _use0@3,
gleam@result:'try'(
process_component_headers(
Body_resolved,
Dir,
Parse_file,
Original_local_names,
Body_imports
),
fun(_use0@4) ->
{Header_resolved,
Header_imports} = _use0@4,
gleam@result:'try'(
process_component_path_items(
Header_resolved,
Dir,
Parse_file,
Original_local_names,
Header_imports
),
fun(_use0@5) ->
{Path_items_resolved,
Path_items_imports} = _use0@5,
gleam@result:'try'(
process_operation_schemas(
erlang:element(
4,
Spec
),
Path_items_resolved,
Dir,
Parse_file,
Original_local_names,
Path_items_imports
),
fun(
_use0@6
) ->
{New_paths,
Op_final_components} = _use0@6,
{ok,
{open_api_spec,
erlang:element(
2,
Spec
),
erlang:element(
3,
Spec
),
New_paths,
{some,
Op_final_components},
erlang:element(
6,
Spec
),
erlang:element(
7,
Spec
),
erlang:element(
8,
Spec
),
erlang:element(
9,
Spec
),
erlang:element(
10,
Spec
),
erlang:element(
11,
Spec
)}}
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
);
{_, _} ->
{ok, Spec}
end.