-module(oaspec@openapi@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/openapi/parser.gleam"). -export([parse_error_to_string/1, parse_string/1, parse_json_string/1, parse_file_with_progress/2, parse_file/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/parser.gleam", 127). -spec format_size(integer()) -> binary(). format_size(Bytes) -> case Bytes < 1024 of true -> <<(erlang:integer_to_binary(Bytes))/binary, " B"/utf8>>; false -> case Bytes < (1024 * 1024) of true -> <<(erlang:integer_to_binary(Bytes div 1024))/binary, " KiB"/utf8>>; false -> <<(erlang:integer_to_binary(case (1024 * 1024) of 0 -> 0; Gleam@denominator -> Bytes div Gleam@denominator end))/binary, " MiB"/utf8>> end end. -file("src/oaspec/openapi/parser.gleam", 143). ?DOC( " Normalize a path string for cycle detection. This is not a full\n" " canonicalization (no symlink resolution, no realpath call); it just\n" " collapses the `./` and duplicate-slash noise that `filepath.join`\n" " can leave behind so the same file reached via two equivalent\n" " relative paths compares equal.\n" ). -spec canonicalize_ref_path(binary()) -> binary(). canonicalize_ref_path(Path) -> Segments = begin _pipe = Path, _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), gleam@list:filter( _pipe@1, fun(Seg) -> (Seg /= <<""/utf8>>) andalso (Seg /= <<"."/utf8>>) end ) end, case gleam_stdlib:string_starts_with(Path, <<"/"/utf8>>) of true -> <<"/"/utf8, (gleam@string:join(Segments, <<"/"/utf8>>))/binary>>; false -> gleam@string:join(Segments, <<"/"/utf8>>) end. -file("src/oaspec/openapi/parser.gleam", 154). -spec cyclic_external_ref_diagnostic(binary(), list(binary())) -> oaspec@openapi@diagnostic:diagnostic(). cyclic_external_ref_diagnostic(Current, Visited) -> Chain = lists:reverse([Current | Visited]), oaspec@openapi@diagnostic:invalid_value( <<"external_ref"/utf8>>, <<<<"Cyclic external $ref graph detected: "/utf8, (gleam@string:join(Chain, <<" -> "/utf8>>))/binary>>/binary, ". oaspec requires external ref graphs to be acyclic."/utf8>>, no_source_loc ). -file("src/oaspec/openapi/parser.gleam", 200). ?DOC( " Run yamerl on `content` and return the root node plus a\n" " location index built from the same content. Both pieces are\n" " consumed by `parse_root` to produce the OpenApiSpec.\n" ). -spec parse_to_node(binary()) -> {ok, {yay:node_(), oaspec@internal@openapi@location_index:location_index()}} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_to_node(Content) -> gleam@result:'try'( begin _pipe = yaml_ffi:parse_string(Content), gleam@result:map_error(_pipe, fun(E) -> case E of {parsing_error, Msg, Loc} -> oaspec@openapi@diagnostic:yaml_error( Msg, {source_loc, erlang:element(2, Loc), erlang:element(3, Loc)} ); unexpected_parsing_error -> oaspec@openapi@diagnostic:yaml_error( <<"Unexpected parsing error"/utf8>>, no_source_loc ) end end) end, fun(Docs) -> gleam@result:'try'(case Docs of [First | _] -> {ok, First}; [] -> {error, oaspec@openapi@diagnostic:yaml_error( <<"Empty document"/utf8>>, no_source_loc )} end, fun(Doc) -> Root = yay:document_root(Doc), Index = oaspec@internal@openapi@location_index:build( Content ), {ok, {Root, Index}} end) end ). -file("src/oaspec/openapi/parser.gleam", 238). ?DOC( " Decode a JSON string into a yay.Node via the OTP `json` module.\n" " Wraps the FFI's `Result(List(Document), YamlError)` shape into a\n" " `Diagnostic` so it lines up with `parse_to_node`'s contract.\n" ). -spec decode_json_to_node(binary()) -> {ok, yay:node_()} | {error, oaspec@openapi@diagnostic:diagnostic()}. decode_json_to_node(Content) -> gleam@result:'try'( begin _pipe = oaspec_json_ffi:parse_string(Content), gleam@result:map_error(_pipe, fun(E) -> case E of {parsing_error, Msg, Loc} -> oaspec@openapi@diagnostic:yaml_error( Msg, case {erlang:element(2, Loc), erlang:element(3, Loc)} of {0, 0} -> no_source_loc; {_, _} -> {source_loc, erlang:element(2, Loc), erlang:element(3, Loc)} end ); unexpected_parsing_error -> oaspec@openapi@diagnostic:yaml_error( <<"Unexpected JSON parsing error"/utf8>>, no_source_loc ) end end) end, fun(Docs) -> case Docs of [First | _] -> {ok, yay:document_root(First)}; [] -> {error, oaspec@openapi@diagnostic:yaml_error( <<"Empty document"/utf8>>, no_source_loc )} end end ). -file("src/oaspec/openapi/parser.gleam", 264). -spec looks_like_json_path(binary()) -> boolean(). looks_like_json_path(Path) -> Lower = string:lowercase(Path), gleam_stdlib:string_ends_with(Lower, <<".json"/utf8>>). -file("src/oaspec/openapi/parser.gleam", 347). -spec is_supported_openapi_version(binary()) -> boolean(). is_supported_openapi_version(Version) -> case gleam@string:split(Version, <<"."/utf8>>) of [<<"3"/utf8>>, <<"0"/utf8>>, Patch] -> case gleam_stdlib:parse_int(Patch) of {ok, N} when N >= 0 -> true; _ -> false end; [<<"3"/utf8>>, <<"1"/utf8>>, Patch] -> case gleam_stdlib:parse_int(Patch) of {ok, N} when N >= 0 -> true; _ -> false end; [<<"3"/utf8>>, <<"0"/utf8>>] -> true; [<<"3"/utf8>>, <<"1"/utf8>>] -> true; _ -> false end. -file("src/oaspec/openapi/parser.gleam", 333). ?DOC( " Reject spec files whose `openapi` field is not in the supported 3.0.x /\n" " 3.1.x range. OpenAPI 3.x is what oaspec claims to generate from, so\n" " accepting 2.0 or 4.0.0 would let users feed specs that are either\n" " subtly or grossly incompatible with the generator.\n" ). -spec validate_openapi_version(binary(), oaspec@openapi@diagnostic:source_loc()) -> {ok, nil} | {error, oaspec@openapi@diagnostic:diagnostic()}. validate_openapi_version(Version, Loc) -> gleam@bool:guard( is_supported_openapi_version(Version), {ok, nil}, fun() -> {error, oaspec@openapi@diagnostic:invalid_value( <<"openapi"/utf8>>, <<<<"Unsupported OpenAPI version: '"/utf8, Version/binary>>/binary, "'. oaspec only supports OpenAPI 3.0.x and 3.1.x."/utf8>>, Loc )} end ). -file("src/oaspec/openapi/parser.gleam", 889). ?DOC(" Parse parameter location string.\n"). -spec parse_parameter_in( binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:parameter_in()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter_in(Value, Index) -> case Value of <<"path"/utf8>> -> {ok, in_path}; <<"query"/utf8>> -> {ok, in_query}; <<"header"/utf8>> -> {ok, in_header}; <<"cookie"/utf8>> -> {ok, in_cookie}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<"parameter.in"/utf8>>, <<<<"Unknown parameter location: "/utf8, Value/binary>>/binary, ". Must be one of: path, query, header, cookie"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<"parameter.in"/utf8>> ) )} end. -file("src/oaspec/openapi/parser.gleam", 910). ?DOC(" Map a style string to a ParameterStyle ADT value.\n"). -spec parse_parameter_style( binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:parameter_style()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter_style(Value, Index) -> case Value of <<"form"/utf8>> -> {ok, form_style}; <<"simple"/utf8>> -> {ok, simple_style}; <<"deepObject"/utf8>> -> {ok, deep_object_style}; <<"matrix"/utf8>> -> {ok, matrix_style}; <<"label"/utf8>> -> {ok, label_style}; <<"spaceDelimited"/utf8>> -> {ok, space_delimited_style}; <<"pipeDelimited"/utf8>> -> {ok, pipe_delimited_style}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<"parameter.style"/utf8>>, <<<<"Unknown parameter style: '"/utf8, Value/binary>>/binary, "'. Must be one of: form, simple, deepObject, matrix, label, spaceDelimited, pipeDelimited"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<"parameter.style"/utf8>> ) )} end. -file("src/oaspec/openapi/parser.gleam", 934). ?DOC(" Map an apiKey \"in\" string to a SecuritySchemeIn ADT value.\n"). -spec parse_security_scheme_in( binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:security_scheme_in()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_scheme_in(Value, Index) -> case Value of <<"header"/utf8>> -> {ok, scheme_in_header}; <<"query"/utf8>> -> {ok, scheme_in_query}; <<"cookie"/utf8>> -> {ok, scheme_in_cookie}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<"securityScheme.in"/utf8>>, <<<<"Unknown apiKey location: "/utf8, Value/binary>>/binary, ". Must be one of: header, query, cookie"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<"securityScheme.in"/utf8>> ) )} end. -file("src/oaspec/openapi/parser.gleam", 1273). ?DOC(" Parse the schemas map from components.\n"). -spec parse_schemas_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@schema:schema_ref())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_schemas_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"schemas"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Value_node, <<"components.schemas."/utf8, Name/binary>>, Index ), fun(Schema_ref) -> {ok, gleam@dict:insert(Acc, Name, Schema_ref)} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1385). ?DOC( " Parse a schema reference (either $ref or inline schema).\n" " Convert a parse error to a human-readable string.\n" ). -spec parse_error_to_string(oaspec@openapi@diagnostic:diagnostic()) -> binary(). parse_error_to_string(Error) -> oaspec@openapi@diagnostic:to_short_string(Error). -file("src/oaspec/openapi/parser.gleam", 1557). ?DOC(" Parse OAuth2 flows from a security scheme node.\n"). -spec parse_oauth2_flows(yay:node_()) -> gleam@dict:dict(binary(), oaspec@internal@openapi@spec:o_auth2_flow()). parse_oauth2_flows(Node) -> case yay:select_sugar(Node, <<"flows"/utf8>>) of {ok, {node_map, Flow_entries}} -> gleam@list:fold( Flow_entries, maps:new(), fun(Acc, Entry) -> {Key_node, Flow_node} = Entry, case Key_node of {node_str, Flow_name} -> Authorization_url = begin _pipe = yay:extract_optional_string( Flow_node, <<"authorizationUrl"/utf8>> ), gleam@result:unwrap(_pipe, none) end, Token_url = begin _pipe@1 = yay:extract_optional_string( Flow_node, <<"tokenUrl"/utf8>> ), gleam@result:unwrap(_pipe@1, none) end, Refresh_url = begin _pipe@2 = yay:extract_optional_string( Flow_node, <<"refreshUrl"/utf8>> ), gleam@result:unwrap(_pipe@2, none) end, Scopes = case yay:select_sugar( Flow_node, <<"scopes"/utf8>> ) of {ok, {node_map, Scope_entries}} -> gleam@list:fold( Scope_entries, maps:new(), fun(Sacc, Sentry) -> {Sk, Sv} = Sentry, case {Sk, Sv} of {{node_str, Scope_name}, {node_str, Scope_desc}} -> gleam@dict:insert( Sacc, Scope_name, Scope_desc ); {_, _} -> Sacc end end ); _ -> maps:new() end, gleam@dict:insert( Acc, Flow_name, {o_auth2_flow, Authorization_url, Token_url, Refresh_url, Scopes} ); _ -> Acc end end ); _ -> maps:new() end. -file("src/oaspec/openapi/parser.gleam", 1454). ?DOC(" Parse a single security scheme.\n"). -spec parse_security_scheme( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:security_scheme()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_scheme(Node, Index) -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"type"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture, <<"securityScheme"/utf8>>, <<"type"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"securityScheme"/utf8>>, <<"type"/utf8>> ) ) end ) end, fun(Type_str) -> case Type_str of <<"apiKey"/utf8>> -> gleam@result:'try'( begin _pipe@1 = yay:extract_string(Node, <<"name"/utf8>>), gleam@result:map_error( _pipe@1, fun(_capture@1) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@1, <<"securityScheme.apiKey"/utf8>>, <<"name"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"securityScheme.apiKey"/utf8>>, <<"name"/utf8>> ) ) end ) end, fun(Name) -> gleam@result:'try'( begin _pipe@2 = yay:extract_string( Node, <<"in"/utf8>> ), gleam@result:map_error( _pipe@2, fun(_capture@2) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@2, <<"securityScheme.apiKey"/utf8>>, <<"in"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"securityScheme.apiKey"/utf8>>, <<"in"/utf8>> ) ) end ) end, fun(In_str) -> case parse_security_scheme_in(In_str, Index) of {ok, In_} -> {ok, {api_key_scheme, Name, In_}}; {error, _} -> {error, oaspec@openapi@diagnostic:invalid_value( <<"securityScheme.apiKey.in"/utf8>>, <<<<"Only 'header', 'query' and 'cookie' are supported for apiKey. Got: '"/utf8, In_str/binary>>/binary, "'"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<"securityScheme.apiKey.in"/utf8>> ) )} end end ) end ); <<"http"/utf8>> -> gleam@result:'try'( begin _pipe@3 = yay:extract_string( Node, <<"scheme"/utf8>> ), gleam@result:map_error( _pipe@3, fun(_capture@3) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@3, <<"securityScheme.http"/utf8>>, <<"scheme"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"securityScheme.http"/utf8>>, <<"scheme"/utf8>> ) ) end ) end, fun(Scheme) -> Bearer_format = begin _pipe@4 = yay:extract_optional_string( Node, <<"bearerFormat"/utf8>> ), gleam@result:unwrap(_pipe@4, none) end, {ok, {http_scheme, Scheme, Bearer_format}} end ); <<"oauth2"/utf8>> -> Description = begin _pipe@5 = yay:extract_optional_string( Node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@5, none) end, Flows = parse_oauth2_flows(Node), {ok, {o_auth2_scheme, Description, Flows}}; <<"openIdConnect"/utf8>> -> Description@1 = begin _pipe@6 = yay:extract_optional_string( Node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@6, none) end, gleam@result:'try'( begin _pipe@7 = yay:extract_string( Node, <<"openIdConnectUrl"/utf8>> ), gleam@result:map_error( _pipe@7, fun(_capture@4) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@4, <<"securityScheme.openIdConnect"/utf8>>, <<"openIdConnectUrl"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"securityScheme.openIdConnect"/utf8>>, <<"openIdConnectUrl"/utf8>> ) ) end ) end, fun(Open_id_connect_url) -> {ok, {open_id_connect_scheme, Open_id_connect_url, Description@1}} end ); _ -> {ok, {unsupported_scheme, Type_str}} end end ). -file("src/oaspec/openapi/parser.gleam", 1392). ?DOC( " Parse security schemes from components.\n" " Returns Ok(empty dict) if the section is absent, Error if present but\n" " malformed.\n" ). -spec parse_security_schemes_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:security_scheme()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_schemes_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"securitySchemes"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; _ -> gleam@result:'try'( parse_security_scheme(Value_node, Index), fun(Scheme) -> {ok, gleam@dict:insert( Acc, Name, {value, Scheme} )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1645). ?DOC( " Parse a single security requirement object.\n" " Returns one SecurityRequirement whose schemes list contains all AND-ed\n" " scheme refs. The outer list (caller) represents OR alternatives.\n" ). -spec parse_security_requirement_object( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:security_requirement()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_requirement_object(Node, Context, Index) -> case Node of {node_map, Entries} -> gleam@result:'try'( gleam@list:try_map( Entries, fun(Entry) -> {Key_node, Scopes_node} = Entry, case Key_node of {node_str, Scheme_name} -> gleam@result:'try'(case Scopes_node of {node_seq, Scope_items} -> gleam@list:try_map( Scope_items, fun(S) -> case S of {node_str, V} -> {ok, V}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<<>/binary, Scheme_name/binary>>, <<"Scope must be a string"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<<>/binary, Scheme_name/binary>> ) )} end end ); node_nil -> {ok, []}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<<>/binary, Scheme_name/binary>>, <<"Scopes must be an array of strings"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<<>/binary, Scheme_name/binary>> ) )} end, fun(Scopes) -> {ok, {security_scheme_ref, Scheme_name, Scopes}} end); _ -> {error, oaspec@openapi@diagnostic:invalid_value( <>, <<"Security requirement key must be a string"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <> ) )} end end ), fun(Scheme_refs) -> {ok, {security_requirement, Scheme_refs}} end ); _ -> {error, oaspec@openapi@diagnostic:invalid_value( <>, <<"Security requirement must be an object"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <> ) )} end. -file("src/oaspec/openapi/parser.gleam", 1607). ?DOC( " Parse top-level security requirements.\n" " Returns Ok([]) if absent, Error if present but malformed.\n" ). -spec parse_security_requirements( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, list(oaspec@internal@openapi@spec:security_requirement())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_requirements(Node, Context, Index) -> case yay:select_sugar(Node, <<"security"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:try_map( Items, fun(Item) -> parse_security_requirement_object(Item, Context, Index) end ); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 1624). ?DOC( " Parse operation-level security requirements.\n" " Returns Ok(None) if absent (inherits top-level), Ok(Some([])) if explicitly\n" " empty (opts out), Ok(Some([...])) if specified.\n" ). -spec parse_optional_security_requirements( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@option:option(list(oaspec@internal@openapi@spec:security_requirement()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_security_requirements(Node, Context, Index) -> case yay:select_sugar(Node, <<"security"/utf8>>) of {ok, {node_seq, Items}} -> gleam@result:'try'( gleam@list:try_map( Items, fun(Item) -> parse_security_requirement_object(Item, Context, Index) end ), fun(Reqs) -> {ok, {some, Reqs}} end ); _ -> {ok, none} end. -file("src/oaspec/openapi/parser.gleam", 1822). ?DOC(" Parse optional contact from an info node.\n"). -spec parse_optional_contact(yay:node_()) -> gleam@option:option(oaspec@internal@openapi@spec:contact()). parse_optional_contact(Info_node) -> case yay:select_sugar(Info_node, <<"contact"/utf8>>) of {ok, Contact_node} -> Name = begin _pipe = yay:extract_optional_string( Contact_node, <<"name"/utf8>> ), gleam@result:unwrap(_pipe, none) end, Url = begin _pipe@1 = yay:extract_optional_string( Contact_node, <<"url"/utf8>> ), gleam@result:unwrap(_pipe@1, none) end, Email = begin _pipe@2 = yay:extract_optional_string( Contact_node, <<"email"/utf8>> ), gleam@result:unwrap(_pipe@2, none) end, {some, {contact, Name, Url, Email}}; _ -> none end. -file("src/oaspec/openapi/parser.gleam", 1841). ?DOC(" Parse optional license from an info node.\n"). -spec parse_optional_license(yay:node_()) -> gleam@option:option(oaspec@internal@openapi@spec:license()). parse_optional_license(Info_node) -> case yay:select_sugar(Info_node, <<"license"/utf8>>) of {ok, License_node} -> case yay:extract_string(License_node, <<"name"/utf8>>) of {ok, Name} -> Url = begin _pipe = yay:extract_optional_string( License_node, <<"url"/utf8>> ), gleam@result:unwrap(_pipe, none) end, {some, {license, Name, Url}}; _ -> none end; _ -> none end. -file("src/oaspec/openapi/parser.gleam", 378). ?DOC(" Parse the info object.\n"). -spec parse_info( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:info()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_info(Root, Index) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Root, <<"info"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_selector( _capture, <<""/utf8>>, <<"info"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<""/utf8>>, <<"info"/utf8>> ) ) end ) end, fun(Info_node) -> gleam@result:'try'( begin _pipe@1 = yay:extract_string(Info_node, <<"title"/utf8>>), gleam@result:map_error( _pipe@1, fun(_capture@1) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@1, <<"info"/utf8>>, <<"title"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"info"/utf8>>, <<"title"/utf8>> ) ) end ) end, fun(Title) -> gleam@result:'try'( begin _pipe@2 = yay:extract_string( Info_node, <<"version"/utf8>> ), gleam@result:map_error( _pipe@2, fun(_capture@2) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@2, <<"info"/utf8>>, <<"version"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"info"/utf8>>, <<"version"/utf8>> ) ) end ) end, fun(Version) -> Description = begin _pipe@3 = yay:extract_optional_string( Info_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@3, none) end, Summary = begin _pipe@4 = yay:extract_optional_string( Info_node, <<"summary"/utf8>> ), gleam@result:unwrap(_pipe@4, none) end, Terms_of_service = begin _pipe@5 = yay:extract_optional_string( Info_node, <<"termsOfService"/utf8>> ), gleam@result:unwrap(_pipe@5, none) end, Contact = parse_optional_contact(Info_node), License = parse_optional_license(Info_node), {ok, {info, Title, Description, Version, Summary, Terms_of_service, Contact, License}} end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 1859). ?DOC(" Parse server variables from a server node.\n"). -spec parse_server_variables(yay:node_()) -> gleam@dict:dict(binary(), oaspec@internal@openapi@spec:server_variable()). parse_server_variables(Node) -> case yay:select_sugar(Node, <<"variables"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Var_name} -> Default = begin _pipe = yay:extract_optional_string( Value_node, <<"default"/utf8>> ), _pipe@1 = gleam@result:unwrap(_pipe, none), gleam@option:unwrap(_pipe@1, <<""/utf8>>) end, Enum_values = case yay:extract_string_list( Value_node, <<"enum"/utf8>> ) of {ok, Values} -> Values; _ -> [] end, Description = begin _pipe@2 = yay:extract_optional_string( Value_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@2, none) end, gleam@dict:insert( Acc, Var_name, {server_variable, Default, Enum_values, Description} ); _ -> Acc end end ); _ -> maps:new() end. -file("src/oaspec/openapi/parser.gleam", 448). ?DOC(" Parse a single server object.\n"). -spec parse_server( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:server()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_server(Node, Index) -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"url"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture, <<"servers"/utf8>>, <<"url"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"servers"/utf8>>, <<"url"/utf8>> ) ) end ) end, fun(Url) -> Description = begin _pipe@1 = yay:extract_optional_string( Node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@1, none) end, Variables = parse_server_variables(Node), {ok, {server, Url, Description, Variables}} end ). -file("src/oaspec/openapi/parser.gleam", 436). ?DOC(" Parse servers array.\n"). -spec parse_servers( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, list(oaspec@internal@openapi@spec:server())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_servers(Root, Index) -> case yay:select_sugar(Root, <<"servers"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:try_map( Items, fun(Item) -> parse_server(Item, Index) end ); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 1891). ?DOC(" Parse optional external docs from a node.\n"). -spec parse_optional_external_docs(yay:node_()) -> gleam@option:option(oaspec@internal@openapi@spec:external_doc()). parse_optional_external_docs(Node) -> case yay:select_sugar(Node, <<"externalDocs"/utf8>>) of {ok, Doc_node} -> case yay:extract_string(Doc_node, <<"url"/utf8>>) of {ok, Url} -> Description = begin _pipe = yay:extract_optional_string( Doc_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe, none) end, {some, {external_doc, Url, Description}}; _ -> none end; _ -> none end. -file("src/oaspec/openapi/parser.gleam", 1909). ?DOC(" Parse tags array from root.\n"). -spec parse_tags(yay:node_()) -> list(oaspec@internal@openapi@spec:tag()). parse_tags(Node) -> case yay:select_sugar(Node, <<"tags"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:filter_map( Items, fun(Tag_node) -> case yay:extract_string(Tag_node, <<"name"/utf8>>) of {ok, Name} -> Description = begin _pipe = yay:extract_optional_string( Tag_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe, none) end, External_docs = parse_optional_external_docs( Tag_node ), {ok, {tag, Name, Description, External_docs}}; _ -> {error, nil} end end ); _ -> [] end. -file("src/oaspec/openapi/parser.gleam", 2012). ?DOC(" Parse encoding map from a media type node.\n"). -spec parse_encoding_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:encoding())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_encoding_map(Node, Index) -> case yay:select_sugar(Node, <<"encoding"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Prop_name} -> Content_type = begin _pipe = yay:extract_optional_string( Value_node, <<"contentType"/utf8>> ), gleam@result:unwrap(_pipe, none) end, gleam@result:'try'( case begin _pipe@1 = yay:extract_optional_string( Value_node, <<"style"/utf8>> ), gleam@result:unwrap(_pipe@1, none) end of {some, S} -> gleam@result:'try'( parse_parameter_style(S, Index), fun(Parsed) -> {ok, {some, Parsed}} end ); none -> {ok, none} end, fun(Style) -> Explode = begin _pipe@2 = yay:extract_optional_bool( Value_node, <<"explode"/utf8>> ), gleam@result:unwrap(_pipe@2, none) end, {ok, gleam@dict:insert( Acc, Prop_name, {encoding, Content_type, Style, Explode} )} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1002). ?DOC(" Parse content map, requiring at least one entry for request bodies.\n"). -spec parse_required_content( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_required_content(Node, Context, Index) -> case yay:select_sugar(Node, <<"content"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Media_type_name} -> gleam@result:'try'( case yay:select_sugar( Value_node, <<"schema"/utf8>> ) of {ok, Schema_node} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Schema_node, <>, Index ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@internal@openapi@parser_value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@internal@openapi@parser_value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node, Index), fun(Mt_encoding) -> {ok, gleam@dict:insert( Acc, Media_type_name, {media_type, Mt_schema, Mt_example, Mt_examples, Mt_encoding} )} end ) end ); _ -> {ok, Acc} end end ); _ -> {error, oaspec@openapi@diagnostic:missing_field( <>, <<"content"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <>, <<"content"/utf8>> ) )} end. -file("src/oaspec/openapi/parser.gleam", 981). ?DOC(" Parse a request body object.\n"). -spec parse_request_body( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_body(Node, Context, Index) -> Description = begin _pipe = yay:extract_optional_string(Node, <<"description"/utf8>>), gleam@result:unwrap(_pipe, none) end, Required = begin _pipe@1 = yay:extract_optional_bool(Node, <<"required"/utf8>>), _pipe@2 = gleam@result:unwrap(_pipe@1, none), gleam@option:unwrap(_pipe@2, false) end, gleam@result:'try'( parse_required_content(Node, Context, Index), fun(Content) -> {ok, {request_body, Description, Content, Required}} end ). -file("src/oaspec/openapi/parser.gleam", 954). ?DOC(" Parse requestBody from a node.\n"). -spec parse_request_body_at( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_body_at(Node, Context, _, Index) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Node, <<"requestBody"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_selector( _capture, Context, <<"requestBody"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, Context, <<"requestBody"/utf8>> ) ) end ) end, fun(Rb_node) -> case yay:extract_optional_string(Rb_node, <<"$ref"/utf8>>) of {ok, {some, Ref_str}} -> {ok, {ref, Ref_str}}; _ -> gleam@result:'try'( parse_request_body(Rb_node, Context, Index), fun(Rb) -> {ok, {value, Rb}} end ) end end ). -file("src/oaspec/openapi/parser.gleam", 724). ?DOC( " Parse optional requestBody: Ok(None) if absent, Ok(Some(..)) if valid,\n" " Error if present but malformed.\n" ). -spec parse_optional_request_body( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@option:option(oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_request_body(Node, Context, Components, Index) -> Present = gleam@result:is_ok(yay:select_sugar(Node, <<"requestBody"/utf8>>)), gleam@bool:guard( not Present, {ok, none}, fun() -> gleam@result:'try'( parse_request_body_at(Node, Context, Components, Index), fun(Rb) -> {ok, {some, Rb}} end ) end ). -file("src/oaspec/openapi/parser.gleam", 1059). ?DOC(" Parse content map (media type -> schema).\n"). -spec parse_content( yay:node_(), binary(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_content(Node, Context, Index) -> case yay:select_sugar(Node, <<"content"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Media_type_name} -> gleam@result:'try'( case yay:select_sugar( Value_node, <<"schema"/utf8>> ) of {ok, Schema_node} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Schema_node, <>, Index ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@internal@openapi@parser_value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@internal@openapi@parser_value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node, Index), fun(Mt_encoding) -> {ok, gleam@dict:insert( Acc, Media_type_name, {media_type, Mt_schema, Mt_example, Mt_examples, Mt_encoding} )} end ) end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1326). ?DOC(" Parse the requestBodies map from components.\n"). -spec parse_request_bodies_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:request_body(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_bodies_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"requestBodies"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; _ -> gleam@result:'try'( parse_request_body( Value_node, <<"components.requestBodies."/utf8, Name/binary>>, Index ), fun(Rb) -> {ok, gleam@dict:insert( Acc, Name, {value, Rb} )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1966). ?DOC(" Parse a content map (non-result version for use in Parameter).\n"). -spec parse_content_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_content_map(Node, Index) -> case yay:select_sugar(Node, <<"content"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Media_type_name} -> gleam@result:'try'( case yay:select_sugar( Value_node, <<"schema"/utf8>> ) of {ok, Schema_node} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Schema_node, <<"content.schema"/utf8>>, Index ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@internal@openapi@parser_value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@internal@openapi@parser_value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node, Index), fun(Mt_encoding) -> {ok, gleam@dict:insert( Acc, Media_type_name, {media_type, Mt_schema, Mt_example, Mt_examples, Mt_encoding} )} end ) end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 766). ?DOC(" Parse a single parameter.\n"). -spec parse_parameter( yay:node_(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter(Node, _, Index) -> case yay:extract_optional_string(Node, <<"$ref"/utf8>>) of {ok, {some, Ref_str}} -> {ok, {ref, Ref_str}}; _ -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"name"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture, <<"parameter"/utf8>>, <<"name"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"parameter"/utf8>>, <<"name"/utf8>> ) ) end ) end, fun(Name) -> gleam@result:'try'( begin _pipe@1 = yay:extract_string(Node, <<"in"/utf8>>), gleam@result:map_error( _pipe@1, fun(_capture@1) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture@1, <<"parameter."/utf8, Name/binary>>, <<"in"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"parameter."/utf8, Name/binary>>, <<"in"/utf8>> ) ) end ) end, fun(In_str) -> gleam@result:'try'( parse_parameter_in(In_str, Index), fun(In_) -> Description = begin _pipe@2 = yay:extract_optional_string( Node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@2, none) end, Explicit_required = begin _pipe@3 = yay:extract_optional_bool( Node, <<"required"/utf8>> ), gleam@result:unwrap(_pipe@3, none) end, gleam@result:'try'( case {In_, Explicit_required} of {in_path, {some, false}} -> {error, oaspec@openapi@diagnostic:invalid_value( <<"parameter."/utf8, Name/binary>>, <<"Path parameters must have required: true"/utf8>>, oaspec@internal@openapi@location_index:lookup( Index, <<"parameter."/utf8, Name/binary>> ) )}; {in_path, _} -> {ok, true}; {_, {some, V}} -> {ok, V}; {_, none} -> {ok, false} end, fun(Required) -> Deprecated = begin _pipe@4 = yay:extract_optional_bool( Node, <<"deprecated"/utf8>> ), _pipe@5 = gleam@result:unwrap( _pipe@4, none ), gleam@option:unwrap( _pipe@5, false ) end, gleam@result:'try'( case yay:select_sugar( Node, <<"schema"/utf8>> ) of {ok, Schema_node} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Schema_node, <<"parameter.schema"/utf8>>, Index ), fun(Sr) -> {ok, {ok, Sr}} end ); _ -> {ok, {error, nil}} end, fun(Param_schema) -> gleam@result:'try'( case begin _pipe@6 = yay:extract_optional_string( Node, <<"style"/utf8>> ), gleam@result:unwrap( _pipe@6, none ) end of {some, S} -> gleam@result:'try'( parse_parameter_style( S, Index ), fun(Parsed) -> {ok, {some, Parsed}} end ); none -> {ok, none} end, fun(Style) -> Explode = begin _pipe@7 = yay:extract_optional_bool( Node, <<"explode"/utf8>> ), gleam@result:unwrap( _pipe@7, none ) end, Allow_reserved = begin _pipe@8 = yay:extract_optional_bool( Node, <<"allowReserved"/utf8>> ), _pipe@9 = gleam@result:unwrap( _pipe@8, none ), gleam@option:unwrap( _pipe@9, false ) end, gleam@result:'try'( parse_content_map( Node, Index ), fun(Content) -> Examples = oaspec@internal@openapi@parser_value:extract_map( Node, <<"examples"/utf8>> ), Payload = case Param_schema of {ok, Sr@1} -> {parameter_schema, Sr@1}; {error, _} -> {parameter_content, Content} end, {ok, {value, {parameter, Name, In_, Description, Required, Payload, Style, Explode, Deprecated, Allow_reserved, Examples}}} end ) end ) end ) end ) end ) end ) end ) end. -file("src/oaspec/openapi/parser.gleam", 753). ?DOC(" Parse parameters list from a node.\n"). -spec parse_parameters_list( yay:node_(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, list(oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameters_list(Node, Components, Index) -> case yay:select_sugar(Node, <<"parameters"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:try_map( Items, fun(Item) -> parse_parameter(Item, Components, Index) end ); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 1299). ?DOC(" Parse the parameters map from components.\n"). -spec parse_parameters_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:parameter(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameters_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"parameters"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; _ -> gleam@result:'try'( parse_parameter(Value_node, none, Index), fun(Param) -> {ok, gleam@dict:insert( Acc, Name, Param )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 2054). ?DOC(" Parse headers map from a node.\n"). -spec parse_headers_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:header())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_headers_map(Node, Index) -> case yay:select_sugar(Node, <<"headers"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Header_name} -> Description = begin _pipe = yay:extract_optional_string( Value_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe, none) end, Required = begin _pipe@1 = yay:extract_optional_bool( Value_node, <<"required"/utf8>> ), _pipe@2 = gleam@result:unwrap(_pipe@1, none), gleam@option:unwrap(_pipe@2, false) end, gleam@result:'try'( case yay:select_sugar( Value_node, <<"schema"/utf8>> ) of {ok, Schema_node} -> gleam@result:'try'( oaspec@internal@openapi@parser_schema:parse_schema_ref( Schema_node, <<<<"header."/utf8, Header_name/binary>>/binary, ".schema"/utf8>>, Index ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Hdr_schema) -> {ok, gleam@dict:insert( Acc, Header_name, {header, Description, Required, Hdr_schema} )} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 2098). ?DOC(" Parse links map from a node.\n"). -spec parse_links_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:link())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_links_map(Node) -> case yay:select_sugar(Node, <<"links"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Link_name} -> Operation_id = begin _pipe = yay:extract_optional_string( Value_node, <<"operationId"/utf8>> ), gleam@result:unwrap(_pipe, none) end, Description = begin _pipe@1 = yay:extract_optional_string( Value_node, <<"description"/utf8>> ), gleam@result:unwrap(_pipe@1, none) end, {ok, gleam@dict:insert( Acc, Link_name, {link, Operation_id, Description} )}; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1148). ?DOC(" Parse a single response object.\n"). -spec parse_response( yay:node_(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_response(Node, _, Index) -> case yay:extract_optional_string(Node, <<"$ref"/utf8>>) of {ok, {some, Ref_str}} -> {ok, {ref, Ref_str}}; _ -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"description"/utf8>>), _pipe@1 = gleam@result:map( _pipe, fun(Field@0) -> {some, Field@0} end ), gleam@result:map_error( _pipe@1, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture, <<"response"/utf8>>, <<"description"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"response"/utf8>>, <<"description"/utf8>> ) ) end ) end, fun(Description) -> gleam@result:'try'( parse_content(Node, <<"response"/utf8>>, Index), fun(Content) -> gleam@result:'try'( parse_headers_map(Node, Index), fun(Headers) -> gleam@result:'try'( parse_links_map(Node), fun(Links) -> {ok, {value, {response, Description, Content, Headers, Links}}} end ) end ) end ) end ) end. -file("src/oaspec/openapi/parser.gleam", 1107). ?DOC(" Parse responses object.\n"). -spec parse_responses( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(oaspec@internal@util@http:http_status_code(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses(Node, _, Components, Index) -> case yay:select_sugar(Node, <<"responses"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Status_code} -> case gleam_stdlib:string_starts_with( Status_code, <<"x-"/utf8>> ) of true -> {ok, Acc}; false -> case oaspec@internal@util@http:parse_status_code( Status_code ) of {ok, Code} -> gleam@result:'try'( parse_response( Value_node, Components, Index ), fun(Resp) -> {ok, gleam@dict:insert( Acc, Code, Resp )} end ); {error, _} -> {ok, Acc} end end; {node_int, Code@1} -> gleam@result:'try'( parse_response(Value_node, Components, Index), fun(Resp@1) -> {ok, gleam@dict:insert( Acc, {status, Code@1}, Resp@1 )} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 740). ?DOC( " Parse responses, treating the field as optional.\n" " OpenAPI 3.x requires responses on operations, but webhook operations\n" " in the wild often omit them. Validation can catch missing responses.\n" ). -spec parse_responses_required( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(oaspec@internal@util@http:http_status_code(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses_required(Node, Context, Components, Index) -> parse_responses(Node, Context, Components, Index). -file("src/oaspec/openapi/parser.gleam", 1357). ?DOC(" Parse the responses map from components.\n"). -spec parse_responses_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:response(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"responses"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; _ -> gleam@result:'try'( parse_response(Value_node, none, Index), fun(Resp) -> {ok, gleam@dict:insert( Acc, Name, Resp )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1760). ?DOC( " Parse a single callback object (maps URL expressions -> PathItems).\n" " Propagates parse errors from individual URL expression path items.\n" ). -spec parse_callback_object( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:callback(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_callback_object(Node, Context, Components, Index) -> case Node of {node_map, Entries} -> gleam@result:'try'( gleam@list:try_fold( Entries, [], fun(Acc, Entry) -> {Key_node, Path_item_node} = Entry, case Key_node of {node_str, Url_expression} -> case begin _pipe = yay:extract_optional_string( Path_item_node, <<"$ref"/utf8>> ), gleam@result:unwrap(_pipe, none) end of {some, Ref_str} -> {ok, [{Url_expression, {ref, Ref_str}} | Acc]}; none -> gleam@result:'try'( parse_path_item( Path_item_node, <<<>/binary, Url_expression/binary>>, Components, Index ), fun(Path_item) -> {ok, [{Url_expression, {value, Path_item}} | Acc]} end ) end; _ -> {ok, Acc} end end ), fun(Parsed_entries) -> case Parsed_entries of [] -> {error, oaspec@openapi@diagnostic:missing_field( <>, <<"url expression"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <>, <<"url expression"/utf8>> ) )}; _ -> {ok, {callback, maps:from_list(Parsed_entries)}} end end ); _ -> {error, oaspec@openapi@diagnostic:missing_field( <>, <<"url expression"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <>, <<"url expression"/utf8>> ) )} end. -file("src/oaspec/openapi/parser.gleam", 516). ?DOC(" Parse a single path item.\n"). -spec parse_path_item( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_path_item(Node, Path, Components, Index) -> Summary = begin _pipe = yay:extract_optional_string(Node, <<"summary"/utf8>>), gleam@result:unwrap(_pipe, none) end, Description = begin _pipe@1 = yay:extract_optional_string(Node, <<"description"/utf8>>), gleam@result:unwrap(_pipe@1, none) end, gleam@result:'try'( parse_optional_operation(Node, <<"get"/utf8>>, Path, Components, Index), fun(Get) -> gleam@result:'try'( parse_optional_operation( Node, <<"post"/utf8>>, Path, Components, Index ), fun(Post) -> gleam@result:'try'( parse_optional_operation( Node, <<"put"/utf8>>, Path, Components, Index ), fun(Put) -> gleam@result:'try'( parse_optional_operation( Node, <<"delete"/utf8>>, Path, Components, Index ), fun(Delete) -> gleam@result:'try'( parse_optional_operation( Node, <<"patch"/utf8>>, Path, Components, Index ), fun(Patch) -> gleam@result:'try'( parse_optional_operation( Node, <<"head"/utf8>>, Path, Components, Index ), fun(Head) -> gleam@result:'try'( parse_optional_operation( Node, <<"options"/utf8>>, Path, Components, Index ), fun(Options) -> gleam@result:'try'( parse_optional_operation( Node, <<"trace"/utf8>>, Path, Components, Index ), fun(Trace) -> gleam@result:'try'( parse_parameters_list( Node, Components, Index ), fun( Parameters ) -> gleam@result:'try'( parse_servers( Node, Index ), fun( Servers ) -> {ok, {path_item, Summary, Description, Get, Post, Put, Delete, Patch, Head, Options, Trace, Parameters, Servers}} end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 609). ?DOC( " Parse an optional operation: Ok(None) if key absent, Ok(Some(..)) if valid,\n" " Error if present but malformed.\n" ). -spec parse_optional_operation( yay:node_(), binary(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@option:option(oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_operation(Node, Method_key, Path, Components, Index) -> Present = gleam@result:is_ok(yay:select_sugar(Node, Method_key)), gleam@bool:guard( not Present, {ok, none}, fun() -> gleam@result:'try'( parse_operation_at(Node, Method_key, Path, Components, Index), fun(Op) -> {ok, {some, Op}} end ) end ). -file("src/oaspec/openapi/parser.gleam", 629). ?DOC(" Parse an operation at a specific HTTP method key.\n"). -spec parse_operation_at( yay:node_(), binary(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_operation_at(Node, Method_key, Path, Components, Index) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Node, Method_key), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_selector( _capture, Path, Method_key, oaspec@internal@openapi@location_index:lookup_field( Index, Path, Method_key ) ) end ) end, fun(Op_node) -> parse_operation( Op_node, <<<>/binary, Method_key/binary>>, Components, Index ) end ). -file("src/oaspec/openapi/parser.gleam", 650). ?DOC(" Parse a single operation.\n"). -spec parse_operation( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:operation(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_operation(Node, Context, Components, Index) -> Operation_id = begin _pipe = yay:extract_optional_string(Node, <<"operationId"/utf8>>), gleam@result:unwrap(_pipe, none) end, Summary = begin _pipe@1 = yay:extract_optional_string(Node, <<"summary"/utf8>>), gleam@result:unwrap(_pipe@1, none) end, Description = begin _pipe@2 = yay:extract_optional_string(Node, <<"description"/utf8>>), gleam@result:unwrap(_pipe@2, none) end, Tags = case yay:extract_string_list(Node, <<"tags"/utf8>>) of {ok, T} -> T; _ -> [] end, Deprecated = begin _pipe@3 = yay:extract_optional_bool(Node, <<"deprecated"/utf8>>), _pipe@4 = gleam@result:unwrap(_pipe@3, none), gleam@option:unwrap(_pipe@4, false) end, gleam@result:'try'( parse_parameters_list(Node, Components, Index), fun(Parameters) -> gleam@result:'try'( parse_optional_request_body(Node, Context, Components, Index), fun(Request_body) -> gleam@result:'try'( parse_responses_required( Node, Context, Components, Index ), fun(Responses) -> gleam@result:'try'( parse_optional_security_requirements( Node, Context, Index ), fun(Security) -> gleam@result:'try'( parse_callbacks( Node, Context, Components, Index ), fun(Callbacks) -> gleam@result:'try'( parse_servers(Node, Index), fun(Op_servers) -> External_docs = parse_optional_external_docs( Node ), {ok, {operation, Operation_id, Summary, Description, Tags, Parameters, Request_body, Responses, Deprecated, Security, Callbacks, Op_servers, External_docs}} end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 1712). ?DOC( " Parse callbacks from an operation node.\n" " Returns an empty dict if no callbacks are present.\n" " Each entry is a `RefOr(Callback)`: a top-level `$ref` pointing at\n" " `#/components/callbacks/foo` is preserved as-is (so the reusable\n" " callback reference survives into the resolved AST), while inline\n" " definitions are parsed into their URL-expression→PathItem shape.\n" ). -spec parse_callbacks( yay:node_(), binary(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:callback(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_callbacks(Node, Context, Components, Index) -> case yay:select_sugar(Node, <<"callbacks"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Callback_name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Callback_name, {ref, Ref_str} )}; {ok, none} -> gleam@result:'try'( parse_callback_object( Value_node, Context, Components, Index ), fun(Callback) -> {ok, gleam@dict:insert( Acc, Callback_name, {value, Callback} )} end ); {error, _} -> {error, oaspec@openapi@diagnostic:invalid_value( <<<<<>/binary, Callback_name/binary>>/binary, ".$ref"/utf8>>, <<"`$ref` under a callback entry must be a string pointing at '#/components/callbacks/...'."/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<<>/binary, Callback_name/binary>>, <<"$ref"/utf8>> ) )} end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 472). ?DOC(" Parse the paths object.\n"). -spec parse_paths( yay:node_(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_paths(Root, Components, Index) -> case yay:select_sugar(Root, <<"paths"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Path} -> case gleam_stdlib:string_starts_with( Path, <<"x-"/utf8>> ) of true -> {ok, Acc}; false -> gleam@result:'try'( case begin _pipe = yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ), gleam@result:unwrap(_pipe, none) end of {some, Ref_str} -> {ok, {ref, Ref_str}}; none -> gleam@result:'try'( parse_path_item( Value_node, Path, Components, Index ), fun(Pi) -> {ok, {value, Pi}} end ) end, fun(Ref_or_path_item) -> {ok, gleam@dict:insert( Acc, Path, Ref_or_path_item )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1231). ?DOC( " Parse `components.callbacks`: each entry is a named reusable callback\n" " object. Returns an empty dict if the section is missing. `$ref` values\n" " are preserved so chains like `components.callbacks.foo.$ref: ...`\n" " stay as references.\n" ). -spec parse_components_callbacks_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:callback(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_components_callbacks_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"callbacks"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; {ok, none} -> gleam@result:'try'( parse_callback_object( Value_node, <<"components.callbacks."/utf8, Name/binary>>, none, Index ), fun(Callback) -> {ok, gleam@dict:insert( Acc, Name, {value, Callback} )} end ); {error, _} -> {error, oaspec@openapi@diagnostic:invalid_value( <<<<"components.callbacks."/utf8, Name/binary>>/binary, ".$ref"/utf8>>, <<"`$ref` under a reusable callback must be a string pointing at '#/components/callbacks/...'."/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<"components.callbacks."/utf8, Name/binary>>, <<"$ref"/utf8>> ) )} end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1422). ?DOC(" Parse the pathItems map from components.\n"). -spec parse_path_items_map( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_path_items_map(Components_node, Index) -> case yay:select_sugar(Components_node, <<"pathItems"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ) of {ok, {some, Ref_str}} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; _ -> gleam@result:'try'( parse_path_item( Value_node, <<"components.pathItems."/utf8, Name/binary>>, none, Index ), fun(Path_item) -> {ok, gleam@dict:insert( Acc, Name, {value, Path_item} )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 1179). ?DOC(" Parse the components section.\n"). -spec parse_components( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_components(Root, Index) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Root, <<"components"/utf8>>), gleam@result:map_error( _pipe, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_selector( _capture, <<""/utf8>>, <<"components"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<""/utf8>>, <<"components"/utf8>> ) ) end ) end, fun(Components_node) -> gleam@result:'try'( parse_schemas_map(Components_node, Index), fun(Schemas) -> gleam@result:'try'( parse_parameters_map(Components_node, Index), fun(Parameters) -> gleam@result:'try'( parse_request_bodies_map(Components_node, Index), fun(Request_bodies) -> gleam@result:'try'( parse_responses_map( Components_node, Index ), fun(Responses) -> gleam@result:'try'( parse_security_schemes_map( Components_node, Index ), fun(Security_schemes) -> gleam@result:'try'( parse_path_items_map( Components_node, Index ), fun(Path_items) -> gleam@result:'try'( parse_headers_map( Components_node, Index ), fun(Headers) -> Examples = oaspec@internal@openapi@parser_value:extract_map( Components_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_links_map( Components_node ), fun( Links ) -> gleam@result:'try'( parse_components_callbacks_map( Components_node, Index ), fun( Callbacks ) -> {ok, {components, Schemas, Parameters, Request_bodies, Responses, Security_schemes, Path_items, Headers, Examples, Links, Callbacks}} end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 366). ?DOC( " Parse optional components section.\n" " Returns Ok(None) if not present, Ok(Some(..)) if valid, Error if malformed.\n" ). -spec parse_optional_components( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_components(Root, Index) -> Present = gleam@result:is_ok(yay:select_sugar(Root, <<"components"/utf8>>)), gleam@bool:guard( not Present, {ok, none}, fun() -> gleam@result:'try'( parse_components(Root, Index), fun(Comps) -> {ok, {some, Comps}} end ) end ). -file("src/oaspec/openapi/parser.gleam", 1929). ?DOC(" Parse webhooks from root.\n"). -spec parse_webhooks( yay:node_(), gleam@option:option(oaspec@internal@openapi@spec:components(oaspec@internal@openapi@spec:unresolved())), oaspec@internal@openapi@location_index:location_index() ) -> {ok, gleam@dict:dict(binary(), oaspec@internal@openapi@spec:ref_or(oaspec@internal@openapi@spec:path_item(oaspec@internal@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_webhooks(Node, Components, Index) -> case yay:select_sugar(Node, <<"webhooks"/utf8>>) of {ok, {node_map, Entries}} -> gleam@list:try_fold( Entries, maps:new(), fun(Acc, Entry) -> {Key_node, Value_node} = Entry, case Key_node of {node_str, Name} -> case begin _pipe = yay:extract_optional_string( Value_node, <<"$ref"/utf8>> ), gleam@result:unwrap(_pipe, none) end of {some, Ref_str} -> {ok, gleam@dict:insert( Acc, Name, {ref, Ref_str} )}; none -> gleam@result:'try'( parse_path_item( Value_node, <<"webhooks."/utf8, Name/binary>>, Components, Index ), fun(Path_item) -> {ok, gleam@dict:insert( Acc, Name, {value, Path_item} )} end ) end; _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 270). ?DOC(" Parse the root OpenAPI object.\n"). -spec parse_root( yay:node_(), oaspec@internal@openapi@location_index:location_index() ) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_root(Node, Index) -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"openapi"/utf8>>), _pipe@2 = gleam@result:lazy_or( _pipe, fun() -> _pipe@1 = yay:extract_float(Node, <<"openapi"/utf8>>), gleam@result:map( _pipe@1, fun(F) -> case F =:= erlang:float(erlang:trunc(F)) of true -> <<(erlang:integer_to_binary(erlang:trunc(F)))/binary, ".0"/utf8>>; false -> gleam_stdlib:float_to_string(F) end end ) end ), gleam@result:map_error( _pipe@2, fun(_capture) -> oaspec@internal@openapi@parser_yay_error:missing_field_from_extraction( _capture, <<""/utf8>>, <<"openapi"/utf8>>, oaspec@internal@openapi@location_index:lookup_field( Index, <<""/utf8>>, <<"openapi"/utf8>> ) ) end ) end, fun(Openapi) -> gleam@result:'try'( validate_openapi_version( Openapi, oaspec@internal@openapi@location_index:lookup_field( Index, <<""/utf8>>, <<"openapi"/utf8>> ) ), fun(_) -> gleam@result:'try'( parse_info(Node, Index), fun(Info) -> gleam@result:'try'( parse_optional_components(Node, Index), fun(Components) -> gleam@result:'try'( parse_paths(Node, Components, Index), fun(Paths) -> gleam@result:'try'( parse_servers(Node, Index), fun(Servers) -> gleam@result:'try'( parse_security_requirements( Node, <<""/utf8>>, Index ), fun(Security) -> gleam@result:'try'( parse_webhooks( Node, Components, Index ), fun(Webhooks) -> Tags = parse_tags( Node ), External_docs = parse_optional_external_docs( Node ), Json_schema_dialect = begin _pipe@3 = yay:extract_optional_string( Node, <<"jsonSchemaDialect"/utf8>> ), gleam@result:unwrap( _pipe@3, none ) end, {ok, {open_api_spec, Openapi, Info, Paths, Components, Servers, Security, Webhooks, Tags, External_docs, Json_schema_dialect}} end ) end ) end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 174). ?DOC( " Parse an OpenAPI spec from a YAML/JSON string. The default path\n" " runs the input through yamerl, which preserves YAML semantics and\n" " source locations but is too slow on large JSON specs (the GitHub\n" " REST OpenAPI is ~12 MB and yamerl effectively hangs — see issue\n" " #352). Use `parse_json_string` directly when the content is known\n" " to be JSON.\n" ). -spec parse_string(binary()) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_string(Content) -> gleam@result:'try'( parse_to_node(Content), fun(_use0) -> {Root, Index} = _use0, parse_root(Root, Index) end ). -file("src/oaspec/openapi/parser.gleam", 190). ?DOC( " Parse an OpenAPI spec from a JSON string using OTP's native JSON\n" " decoder instead of yamerl. Roughly two orders of magnitude faster\n" " than `parse_string` on large specs because the YAML pre-processing\n" " and constructor passes are skipped (issue #352). Behaves like\n" " `parse_string` once the tree is built — same `OpenApiSpec` shape,\n" " same downstream pipeline. Diagnostics from this path do not carry\n" " source line/column info because OTP `json:decode/3` does not\n" " expose decoder positions; the caller still gets the path-prefixed\n" " error message that downstream tooling relies on.\n" ). -spec parse_json_string(binary()) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_json_string(Content) -> gleam@result:'try'( decode_json_to_node(Content), fun(Root) -> parse_root(Root, oaspec@internal@openapi@location_index:empty()) end ). -file("src/oaspec/openapi/parser.gleam", 55). ?DOC( " Internal parse entry that threads the `visited` stack through every\n" " external-ref recursion so `A.yaml -> B.yaml -> A.yaml` cycles fail\n" " fast with a dedicated diagnostic instead of spinning forever.\n" ). -spec parse_file_internal( binary(), list(binary()), oaspec@internal@progress:reporter() ) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_file_internal(Path, Visited, Reporter) -> Canonical = canonicalize_ref_path(Path), gleam@bool:guard( gleam@list:contains(Visited, Canonical), {error, cyclic_external_ref_diagnostic(Canonical, Visited)}, fun() -> {Elapsed, Read_result} = oaspec@internal@progress:timed( fun() -> simplifile:read(Path) end ), gleam@result:'try'( begin _pipe = Read_result, gleam@result:map_error( _pipe, fun(Err) -> oaspec@openapi@diagnostic:file_error( <<<<<<<<"Cannot read file: "/utf8, Path/binary>>/binary, " ("/utf8>>/binary, (simplifile:describe_error(Err))/binary>>/binary, ")"/utf8>> ) end ) end, fun(Content) -> oaspec@internal@progress:report( Reporter, <<<<<<<<<<<<"read "/utf8, Path/binary>>/binary, " ("/utf8>>/binary, (format_size(erlang:byte_size(Content)))/binary>>/binary, ", took "/utf8>>/binary, (oaspec@internal@progress:format_ms(Elapsed))/binary>>/binary, ")"/utf8>> ), Is_json = looks_like_json_path(Path), {Elapsed@1, Parsed} = oaspec@internal@progress:timed( fun() -> case Is_json of true -> parse_json_string(Content); false -> parse_string(Content) end end ), oaspec@internal@progress:report(Reporter, case Is_json of true -> <<<<"parse JSON document via OTP json (took "/utf8, (oaspec@internal@progress:format_ms( Elapsed@1 ))/binary>>/binary, ")"/utf8>>; false -> <<<<"parse YAML document via yamerl (took "/utf8, (oaspec@internal@progress:format_ms( Elapsed@1 ))/binary>>/binary, ")"/utf8>> end), gleam@result:'try'( Parsed, fun(Spec) -> New_visited = [Canonical | Visited], {Elapsed@2, Resolved} = oaspec@internal@progress:timed( fun() -> oaspec@internal@openapi@external_loader:resolve_external_component_refs( Spec, oaspec@internal@openapi@external_loader:base_dir_of( Path ), fun(Sub_path) -> parse_file_internal( Sub_path, New_visited, Reporter ) end ) end ), oaspec@internal@progress:report( Reporter, <<<<"resolve relative-file $ref components (took "/utf8, (oaspec@internal@progress:format_ms( Elapsed@2 ))/binary>>/binary, ")"/utf8>> ), Resolved end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 45). ?DOC( " Same as `parse_file`, with a `Reporter` that receives a line per\n" " stage (read, parse, resolve external refs). Used by the CLI to\n" " give the user feedback on big specs (issue #352).\n" ). -spec parse_file_with_progress(binary(), oaspec@internal@progress:reporter()) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_file_with_progress(Path, Reporter) -> parse_file_internal(Path, [], Reporter). -file("src/oaspec/openapi/parser.gleam", 38). ?DOC( " Parse an OpenAPI spec from a file path.\n" " Supports both YAML (.yaml, .yml) and JSON (.json) files.\n" " After parsing, resolves relative-file `$ref` values in\n" " `components.schemas` by loading the referenced files from disk and\n" " merging their schemas. Nested or parameter/response external refs are\n" " left to downstream validation.\n" ). -spec parse_file(binary()) -> {ok, oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_file(Path) -> parse_file_with_progress(Path, oaspec@internal@progress:noop()).