-module(oaspec@openapi@resolve). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/openapi/resolve.gleam"). -export([resolve/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/oaspec/openapi/resolve.gleam", 186). ?DOC(" Extract the last segment of a $ref path.\n"). -spec extract_ref_name(binary()) -> binary(). extract_ref_name(Ref) -> _pipe = Ref, _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), _pipe@2 = gleam@list:last(_pipe@1), gleam@result:unwrap(_pipe@2, <<"unknown"/utf8>>). -file("src/oaspec/openapi/resolve.gleam", 147). ?DOC(" Follow a $ref chain to find the concrete value.\n"). -spec resolve_alias( gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(PBJ)), binary(), binary(), gleam@set:set(binary()) ) -> {ok, PBJ} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_alias(Entries, Ref, Context, Seen) -> case gleam@set:contains(Seen, Ref) of true -> {error, oaspec@openapi@diagnostic:resolve_error( Context, <<"Circular component alias detected: "/utf8, Ref/binary>>, {some, <<"Check that component $ref chains don't form a cycle. Each $ref must eventually point to a concrete definition."/utf8>>} )}; false -> New_seen = gleam@set:insert(Seen, Ref), Ref_name = extract_ref_name(Ref), case gleam_stdlib:map_get(Entries, Ref_name) of {ok, {value, Value}} -> {ok, Value}; {ok, {ref, Next_ref}} -> resolve_alias(Entries, Next_ref, Context, New_seen); {error, _} -> {error, oaspec@openapi@diagnostic:resolve_error( Context, <<<<<<<<"Unresolved component alias: "/utf8, Ref/binary>>/binary, " — target '"/utf8>>/binary, Ref_name/binary>>/binary, "' not found."/utf8>>, {some, <<"Verify the target component exists and the $ref path is spelled correctly."/utf8>>} )} end end. -file("src/oaspec/openapi/resolve.gleam", 124). ?DOC( " Resolve all aliases in a component dict.\n" " After resolution, all entries are Value.\n" ). -spec resolve_component_dict( gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(PBA)), binary() ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(PBA))} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_component_dict(Entries, Context) -> _pipe = maps:to_list(Entries), gleam@list:try_fold( _pipe, Entries, fun(Acc, Entry) -> {Name, Value} = Entry, case Value of {value, _} -> {ok, Acc}; {ref, Ref} -> gleam@result:'try'( resolve_alias( Entries, Ref, <<<>/binary, Name/binary>>, gleam@set:new() ), fun(Resolved) -> {ok, gleam@dict:insert(Acc, Name, {value, Resolved})} end ) end end ). -file("src/oaspec/openapi/resolve.gleam", 195). ?DOC( " Validate that a $ref string points to the expected component kind.\n" " Returns Ok(name) if valid, Error(diagnostic) if wrong kind or external.\n" ). -spec validate_ref_kind(binary(), binary(), binary()) -> {ok, binary()} | {error, oaspec@openapi@diagnostic:diagnostic()}. validate_ref_kind(Ref_str, Expected_prefix, Context_path) -> case gleam_stdlib:string_starts_with(Ref_str, Expected_prefix) of true -> {ok, extract_ref_name(Ref_str)}; false -> {error, oaspec@openapi@diagnostic:resolve_error( Context_path, <<<<<<<<"$ref '"/utf8, Ref_str/binary>>/binary, "' points to wrong component kind; expected prefix '"/utf8>>/binary, Expected_prefix/binary>>/binary, "'"/utf8>>, {some, <<"Use the correct $ref prefix for the component type (e.g., #/components/schemas/ for schemas)."/utf8>>} )} end. -file("src/oaspec/openapi/resolve.gleam", 415). ?DOC(" Resolve a parameter Ref by looking it up in components.parameters.\n"). -spec resolve_param_ref( oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(PDG)), binary(), oaspec@openapi@spec:components(PDG) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(PDG))} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_param_ref(Ref_or, Path, Components) -> case Ref_or of {value, _} -> {ok, Ref_or}; {ref, Ref_str} -> gleam@result:'try'( validate_ref_kind( Ref_str, <<"#/components/parameters/"/utf8>>, <<"paths."/utf8, Path/binary>> ), fun(Ref_name) -> case gleam_stdlib:map_get( erlang:element(3, Components), Ref_name ) of {ok, {value, P}} -> {ok, {value, P}}; _ -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components.parameters"/utf8>>, {some, <<"Verify the parameter exists in components.parameters."/utf8>>} )} end end ) end. -file("src/oaspec/openapi/resolve.gleam", 444). ?DOC(" Resolve a request body Ref by looking it up in components.request_bodies.\n"). -spec resolve_request_body_ref( oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(PDO)), binary(), oaspec@openapi@spec:components(PDO) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(PDO))} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_request_body_ref(Ref_or, Path, Components) -> case Ref_or of {value, _} -> {ok, Ref_or}; {ref, Ref_str} -> gleam@result:'try'( validate_ref_kind( Ref_str, <<"#/components/requestBodies/"/utf8>>, <<"paths."/utf8, Path/binary>> ), fun(Ref_name) -> case gleam_stdlib:map_get( erlang:element(4, Components), Ref_name ) of {ok, {value, Rb}} -> {ok, {value, Rb}}; _ -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components.requestBodies"/utf8>>, {some, <<"Verify the request body exists in components.requestBodies."/utf8>>} )} end end ) end. -file("src/oaspec/openapi/resolve.gleam", 475). ?DOC(" Resolve a response Ref by looking it up in components.responses.\n"). -spec resolve_response_ref( oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(PDW)), binary(), oaspec@openapi@spec:components(PDW) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(PDW))} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_response_ref(Ref_or, Path, Components) -> case Ref_or of {value, _} -> {ok, Ref_or}; {ref, Ref_str} -> gleam@result:'try'( validate_ref_kind( Ref_str, <<"#/components/responses/"/utf8>>, <<"paths."/utf8, Path/binary>> ), fun(Ref_name) -> case gleam_stdlib:map_get( erlang:element(5, Components), Ref_name ) of {ok, {value, R}} -> {ok, {value, R}}; _ -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components.responses"/utf8>>, {some, <<"Verify the response exists in components.responses."/utf8>>} )} end end ) end. -file("src/oaspec/openapi/resolve.gleam", 504). ?DOC(" Map over an Option value with a fallible function.\n"). -spec option_try( gleam@option:option(PEE), fun((PEE) -> {ok, PEE} | {error, list(oaspec@openapi@diagnostic:diagnostic())}) ) -> {ok, gleam@option:option(PEE)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. option_try(Opt, F) -> case Opt of {some, V} -> gleam@result:map(F(V), fun(Field@0) -> {some, Field@0} end); none -> {ok, none} end. -file("src/oaspec/openapi/resolve.gleam", 515). ?DOC(" Map over dict values with a fallible function, collecting first error.\n"). -spec try_map_values( gleam@dict:dict(PEN, PEO), fun((PEN, PEO) -> {ok, PEO} | {error, list(oaspec@openapi@diagnostic:diagnostic())}) ) -> {ok, gleam@dict:dict(PEN, PEO)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. try_map_values(D, F) -> _pipe = maps:to_list(D), gleam@list:try_fold( _pipe, maps:new(), fun(Acc, Entry) -> {Key, Value} = Entry, gleam@result:'try'( F(Key, Value), fun(New_value) -> {ok, gleam@dict:insert(Acc, Key, New_value)} end ) end ). -file("src/oaspec/openapi/resolve.gleam", 392). ?DOC(" Resolve inline refs within a callback.\n"). -spec resolve_inline_callback( oaspec@openapi@spec:callback(PCZ), binary(), oaspec@openapi@spec:components(PCZ) ) -> {ok, oaspec@openapi@spec:callback(PCZ)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve_inline_callback(Cb, Path, Components) -> gleam@result:'try'( try_map_values(erlang:element(2, Cb), fun(_, Ref_or) -> case Ref_or of {ref, Ref_str} -> _pipe = resolve_path_item_ref(Ref_str, Path, Components), gleam@result:map_error(_pipe, fun(E) -> [E] end); {value, Pi} -> case resolve_inline_path_item(Pi, Path, Components) of {ok, Resolved_pi} -> {ok, {value, Resolved_pi}}; {error, Errs} -> {error, Errs} end end end), fun(Entries) -> {ok, {callback, Entries}} end ). -file("src/oaspec/openapi/resolve.gleam", 245). ?DOC(" Resolve a path-level $ref by looking it up in components.pathItems.\n"). -spec resolve_path_item_ref( binary(), binary(), oaspec@openapi@spec:components(PCF) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(PCF))} | {error, oaspec@openapi@diagnostic:diagnostic()}. resolve_path_item_ref(Ref_str, Path, Components) -> gleam@result:'try'( validate_ref_kind( Ref_str, <<"#/components/pathItems/"/utf8>>, <<"paths."/utf8, Path/binary>> ), fun(Ref_name) -> case gleam_stdlib:map_get(erlang:element(7, Components), Ref_name) of {ok, {value, Pi}} -> case resolve_inline_path_item(Pi, Path, Components) of {ok, Resolved_pi} -> {ok, {value, Resolved_pi}}; {error, Errs} -> case Errs of [First | _] -> {error, First}; [] -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components"/utf8>>, {some, <<"Verify the referenced component exists and the $ref path is spelled correctly."/utf8>>} )} end end; {ok, {ref, _}} -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components"/utf8>>, {some, <<"Verify the referenced component exists and the $ref path is spelled correctly."/utf8>>} )}; {error, _} -> {error, oaspec@openapi@diagnostic:resolve_error( <<"paths."/utf8, Path/binary>>, <<<<"Unresolved $ref: "/utf8, Ref_str/binary>>/binary, " — target not found in components"/utf8>>, {some, <<"Verify the referenced component exists and the $ref path is spelled correctly."/utf8>>} )} end end ). -file("src/oaspec/openapi/resolve.gleam", 300). ?DOC(" Resolve inline refs within a path item.\n"). -spec resolve_inline_path_item( oaspec@openapi@spec:path_item(PCL), binary(), oaspec@openapi@spec:components(PCL) ) -> {ok, oaspec@openapi@spec:path_item(PCL)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve_inline_path_item(Pi, Path, Components) -> gleam@result:'try'( option_try( erlang:element(4, Pi), fun(_capture) -> resolve_inline_operation(_capture, Path, Components) end ), fun(Get) -> gleam@result:'try'( option_try( erlang:element(5, Pi), fun(_capture@1) -> resolve_inline_operation(_capture@1, Path, Components) end ), fun(Post) -> gleam@result:'try'( option_try( erlang:element(6, Pi), fun(_capture@2) -> resolve_inline_operation( _capture@2, Path, Components ) end ), fun(Put) -> gleam@result:'try'( option_try( erlang:element(7, Pi), fun(_capture@3) -> resolve_inline_operation( _capture@3, Path, Components ) end ), fun(Delete) -> gleam@result:'try'( option_try( erlang:element(8, Pi), fun(_capture@4) -> resolve_inline_operation( _capture@4, Path, Components ) end ), fun(Patch) -> gleam@result:'try'( option_try( erlang:element(9, Pi), fun(_capture@5) -> resolve_inline_operation( _capture@5, Path, Components ) end ), fun(Head) -> gleam@result:'try'( option_try( erlang:element( 10, Pi ), fun(_capture@6) -> resolve_inline_operation( _capture@6, Path, Components ) end ), fun(Options) -> gleam@result:'try'( option_try( erlang:element( 11, Pi ), fun( _capture@7 ) -> resolve_inline_operation( _capture@7, Path, Components ) end ), fun(Trace) -> gleam@result:'try'( gleam@list:try_map( erlang:element( 12, Pi ), fun( P ) -> _pipe = resolve_param_ref( P, Path, Components ), gleam@result:map_error( _pipe, fun( E ) -> [E] end ) end ), fun( Parameters ) -> {ok, {path_item, erlang:element( 2, Pi ), erlang:element( 3, Pi ), Get, Post, Put, Delete, Patch, Head, Options, Trace, Parameters, erlang:element( 13, Pi )}} end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/resolve.gleam", 352). ?DOC(" Resolve inline refs within an operation.\n"). -spec resolve_inline_operation( oaspec@openapi@spec:operation(PCS), binary(), oaspec@openapi@spec:components(PCS) ) -> {ok, oaspec@openapi@spec:operation(PCS)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve_inline_operation(Op, Path, Components) -> gleam@result:'try'( gleam@list:try_map( erlang:element(6, Op), fun(P) -> _pipe = resolve_param_ref(P, Path, Components), gleam@result:map_error(_pipe, fun(E) -> [E] end) end ), fun(Parameters) -> gleam@result:'try'( option_try( erlang:element(7, Op), fun(Rb) -> _pipe@1 = resolve_request_body_ref(Rb, Path, Components), gleam@result:map_error(_pipe@1, fun(E@1) -> [E@1] end) end ), fun(Request_body) -> gleam@result:'try'( try_map_values( erlang:element(8, Op), fun(_, Ref_or) -> _pipe@2 = resolve_response_ref( Ref_or, Path, Components ), gleam@result:map_error( _pipe@2, fun(E@2) -> [E@2] end ) end ), fun(Responses) -> gleam@result:'try'( try_map_values( erlang:element(11, Op), fun(_, Cb) -> resolve_inline_callback( Cb, Path, Components ) end ), fun(Callbacks) -> {ok, {operation, erlang:element(2, Op), erlang:element(3, Op), erlang:element(4, Op), erlang:element(5, Op), Parameters, Request_body, Responses, erlang:element(9, Op), erlang:element(10, Op), Callbacks, erlang:element(12, Op), erlang:element(13, Op)}} end ) end ) end ) end ). -file("src/oaspec/openapi/resolve.gleam", 222). ?DOC(" Resolve inline refs in a paths dict by looking up components.\n"). -spec resolve_inline_paths( gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(PBS))), oaspec@openapi@spec:components(PBS) ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(PBS)))} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve_inline_paths(Paths, Components) -> _pipe = maps:to_list(Paths), gleam@list:try_fold( _pipe, maps:new(), fun(Acc, Entry) -> {Path, Ref_or} = Entry, case Ref_or of {ref, Ref_str} -> case resolve_path_item_ref(Ref_str, Path, Components) of {ok, Resolved} -> {ok, gleam@dict:insert(Acc, Path, Resolved)}; {error, E} -> {error, [E]} end; {value, Pi} -> case resolve_inline_path_item(Pi, Path, Components) of {ok, Resolved_pi} -> {ok, gleam@dict:insert( Acc, Path, {value, Resolved_pi} )}; {error, Errs} -> {error, Errs} end end end ). -file("src/oaspec/openapi/resolve.gleam", 30). ?DOC(" Internal resolve that preserves the input stage parameter.\n"). -spec resolve_internal(oaspec@openapi@spec:open_api_spec(PAU)) -> {ok, oaspec@openapi@spec:open_api_spec(PAU)} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve_internal(Spec) -> Empty_components = {components, maps:new(), maps:new(), maps:new(), maps:new(), maps:new(), maps:new(), maps:new(), maps:new(), maps:new()}, case erlang:element(5, Spec) of none -> gleam@result:'try'( resolve_inline_paths(erlang:element(4, Spec), Empty_components), fun(Resolved_paths) -> gleam@result:'try'( resolve_inline_paths( erlang:element(8, Spec), Empty_components ), fun(Resolved_webhooks) -> {ok, {open_api_spec, erlang:element(2, Spec), erlang:element(3, Spec), Resolved_paths, erlang:element(5, Spec), erlang:element(6, Spec), erlang:element(7, Spec), Resolved_webhooks, erlang:element(9, Spec), erlang:element(10, Spec), erlang:element(11, Spec)}} end ) end ); {some, Components} -> gleam@result:'try'( begin _pipe = resolve_component_dict( erlang:element(3, Components), <<"components.parameters"/utf8>> ), gleam@result:map_error(_pipe, fun(E) -> [E] end) end, fun(Parameters) -> gleam@result:'try'( begin _pipe@1 = resolve_component_dict( erlang:element(4, Components), <<"components.requestBodies"/utf8>> ), gleam@result:map_error( _pipe@1, fun(E@1) -> [E@1] end ) end, fun(Request_bodies) -> gleam@result:'try'( begin _pipe@2 = resolve_component_dict( erlang:element(5, Components), <<"components.responses"/utf8>> ), gleam@result:map_error( _pipe@2, fun(E@2) -> [E@2] end ) end, fun(Responses) -> gleam@result:'try'( begin _pipe@3 = resolve_component_dict( erlang:element(6, Components), <<"components.securitySchemes"/utf8>> ), gleam@result:map_error( _pipe@3, fun(E@3) -> [E@3] end ) end, fun(Security_schemes) -> gleam@result:'try'( begin _pipe@4 = resolve_component_dict( erlang:element( 7, Components ), <<"components.pathItems"/utf8>> ), gleam@result:map_error( _pipe@4, fun(E@4) -> [E@4] end ) end, fun(Path_items) -> Resolved_components = {components, erlang:element( 2, Components ), Parameters, Request_bodies, Responses, Security_schemes, Path_items, erlang:element( 8, Components ), erlang:element( 9, Components ), erlang:element( 10, Components )}, gleam@result:'try'( resolve_inline_paths( erlang:element( 4, Spec ), Resolved_components ), fun(Resolved_paths@1) -> gleam@result:'try'( resolve_inline_paths( erlang:element( 8, Spec ), Resolved_components ), fun( Resolved_webhooks@1 ) -> {ok, {open_api_spec, erlang:element( 2, Spec ), erlang:element( 3, Spec ), Resolved_paths@1, {some, Resolved_components}, erlang:element( 6, Spec ), erlang:element( 7, Spec ), Resolved_webhooks@1, erlang:element( 9, Spec ), erlang:element( 10, Spec ), erlang:element( 11, Spec )}} end ) end ) end ) end ) end ) end ) end ) end. -file("src/oaspec/openapi/resolve.gleam", 18). ?DOC( " Resolve all RefOr aliases in the spec.\n" " Call after parse and normalize, before capability_check and codegen.\n" " Resolves both component-level aliases and inline $ref within operations.\n" ). -spec resolve( oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()) ) -> {ok, oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:resolved())} | {error, list(oaspec@openapi@diagnostic:diagnostic())}. resolve(Spec) -> gleam@result:'try'( resolve_internal(Spec), fun(Resolved) -> {ok, gleam_stdlib:identity(Resolved)} end ).