-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, read_file/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..parameters` and `paths...parameters`\n" " - operation-level `requestBody.content.*.schema`\n" " - operation-level `responses..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" " - cyclic external refs (e.g., `A.yaml` → `B.yaml` → `A.yaml`)\n" " would loop forever; callers are expected to maintain acyclic\n" " file graphs.\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", 250). ?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", 230). ?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) -> case gleam_stdlib:string_starts_with(Ref_str, <<"./"/utf8>>) orelse gleam_stdlib:string_starts_with( Ref_str, <<"../"/utf8>> ) of true -> 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; false -> none end. -file("src/oaspec/openapi/external_loader.gleam", 328). ?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(QPR)), 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, QPR} | {error, oaspec@openapi@diagnostic:diagnostic()}) ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(QPR))} | {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", 362). ?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", 413). ?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", 464). ?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", 513). ?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", 277). ?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)}} end ) end ) end ) end ). -file("src/oaspec/openapi/external_loader.gleam", 720). ?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", 1709). ?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) -> case gleam@list:contains(Original_local_names, Fragment_name) of false -> {ok, nil}; true -> {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", 1736). ?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", 1771). ?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 ) -> case Entry_name =:= Fragment_name of true -> {ok, nil}; false -> case gleam@list:contains(Original_local_names, Fragment_name) of false -> {ok, nil}; true -> {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", 1803). ?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", 1836). ?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", 218). ?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", 1953). ?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", 1890). ?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", 1865). -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", 158). -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)}, Imported@2}} end ). -file("src/oaspec/openapi/external_loader.gleam", 1666). ?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/` 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", 1397). ?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", 1439). ?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)}, Final_imports}} end ). -file("src/oaspec/openapi/external_loader.gleam", 1528). ?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", 1098). -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", 1312). ?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", 785). ?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", 1176). ?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)}, Imports@1}} end ). -file("src/oaspec/openapi/external_loader.gleam", 1361). ?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", 1128). -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", 1230). ?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)}, Final_imports}} end ) end ). -file("src/oaspec/openapi/external_loader.gleam", 1570). ?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", 1606). ?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", 1635). ?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", 573). ?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/` 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)}, Imports@1}} end ). -file("src/oaspec/openapi/external_loader.gleam", 1972). ?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", 1981). ?DOC( " Read a file from disk. Extracted so tests can stub file I/O by passing\n" " their own `parse_file` callback.\n" ). -spec read_file(binary()) -> {ok, binary()} | {error, oaspec@openapi@diagnostic:diagnostic()}. read_file(Path) -> _pipe = simplifile:read(Path), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:file_error( <<"Cannot read external file: "/utf8, Path/binary>> ) end ). -file("src/oaspec/openapi/external_loader.gleam", 1055). ?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", 817). ?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", 848). ?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", 930). -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", 958). -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", 1016). ?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.\n" ). -spec rewrite_callback_map( gleam@dict:dict(binary(), 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: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, Callback} = Entry, 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 = {callback, New_entries}, {ok, {[{Name, New_callback} | Collected], New_imports}} 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", 729). ?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)}}} end ). -file("src/oaspec/openapi/external_loader.gleam", 1476). ?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)}, Final_imports}} end ). -file("src/oaspec/openapi/external_loader.gleam", 71). ?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.