-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_schema_object/2, parse_schema_ref/2, parse_string/1, 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", 599). ?DOC(" Parse parameter location string.\n"). -spec parse_parameter_in(binary()) -> {ok, oaspec@openapi@spec:parameter_in()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter_in(Value) -> 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>> )} end. -file("src/oaspec/openapi/parser.gleam", 616). ?DOC(" Map a style string to a ParameterStyle ADT value.\n"). -spec parse_parameter_style(binary()) -> {ok, oaspec@openapi@spec:parameter_style()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter_style(Value) -> 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>> )} end. -file("src/oaspec/openapi/parser.gleam", 638). ?DOC(" Map an apiKey \"in\" string to a SecuritySchemeIn ADT value.\n"). -spec parse_security_scheme_in(binary()) -> {ok, oaspec@openapi@spec:security_scheme_in()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_scheme_in(Value) -> 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>> )} end. -file("src/oaspec/openapi/parser.gleam", 1119). ?DOC( " Detect unsupported JSON Schema 2020-12 keywords present in a schema node.\n" " Returns a list of keyword names found (does NOT fail — stores them for later).\n" " Note: `const` is NOT in this list because it is parsed into `const_value`.\n" ). -spec detect_unsupported_keywords(yay:node_()) -> list(binary()). detect_unsupported_keywords(Node) -> Keywords = [<<"$defs"/utf8>>, <<"prefixItems"/utf8>>, <<"if"/utf8>>, <<"then"/utf8>>, <<"else"/utf8>>, <<"dependentSchemas"/utf8>>, <<"unevaluatedProperties"/utf8>>, <<"unevaluatedItems"/utf8>>, <<"contentEncoding"/utf8>>, <<"contentMediaType"/utf8>>, <<"contentSchema"/utf8>>, <<"not"/utf8>>], gleam@list:filter( Keywords, fun(Keyword) -> case yay:select_sugar(Node, Keyword) of {ok, _} -> true; {error, _} -> false end end ). -file("src/oaspec/openapi/parser.gleam", 1371). ?DOC(" Parse discriminator from a node.\n"). -spec parse_discriminator(yay:node_()) -> {ok, oaspec@openapi@schema:discriminator()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_discriminator(Node) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Node, <<"discriminator"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<"schema"/utf8>>, <<"discriminator"/utf8>> ) end ) end, fun(Disc_node) -> gleam@result:'try'( begin _pipe@1 = yay:extract_string( Disc_node, <<"propertyName"/utf8>> ), gleam@result:map_error( _pipe@1, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<"discriminator"/utf8>>, <<"propertyName"/utf8>> ) end ) end, fun(Property_name) -> Mapping = case yay:extract_string_map( Disc_node, <<"mapping"/utf8>> ) of {ok, M} -> M; _ -> maps:new() end, {ok, {discriminator, Property_name, Mapping}} end ) end ). -file("src/oaspec/openapi/parser.gleam", 1395). ?DOC(" 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", 1535). ?DOC(" Parse OAuth2 flows from a security scheme node.\n"). -spec parse_oauth2_flows(yay:node_()) -> gleam@dict:dict(binary(), oaspec@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", 1458). ?DOC(" Parse a single security scheme.\n"). -spec parse_security_scheme(yay:node_()) -> {ok, oaspec@openapi@spec:security_scheme()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_scheme(Node) -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"type"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<"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(_) -> oaspec@openapi@diagnostic:missing_field( <<"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(_) -> oaspec@openapi@diagnostic:missing_field( <<"securityScheme.apiKey"/utf8>>, <<"in"/utf8>> ) end ) end, fun(In_str) -> case parse_security_scheme_in(In_str) 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>> )} end end ) end ); <<"http"/utf8>> -> gleam@result:'try'( begin _pipe@3 = yay:extract_string( Node, <<"scheme"/utf8>> ), gleam@result:map_error( _pipe@3, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<"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(_) -> oaspec@openapi@diagnostic:missing_field( <<"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", 1402). ?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_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:security_scheme()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_schemes_map(Components_node) -> 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), 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", 1621). ?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()) -> {ok, oaspec@openapi@spec:security_requirement()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_requirement_object(Node, Context) -> 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>> )} end end ); node_nil -> {ok, []}; _ -> {error, oaspec@openapi@diagnostic:invalid_value( <<<>/binary, Scheme_name/binary>>, <<"Scopes must be an array of strings"/utf8>> )} 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>> )} end end ), fun(Scheme_refs) -> {ok, {security_requirement, Scheme_refs}} end ); _ -> {error, oaspec@openapi@diagnostic:invalid_value( <>, <<"Security requirement must be an object"/utf8>> )} end. -file("src/oaspec/openapi/parser.gleam", 1585). ?DOC( " Parse top-level security requirements.\n" " Returns Ok([]) if absent, Error if present but malformed.\n" ). -spec parse_security_requirements(yay:node_(), binary()) -> {ok, list(oaspec@openapi@spec:security_requirement())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_security_requirements(Node, Context) -> 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) end ); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 1601). ?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()) -> {ok, gleam@option:option(list(oaspec@openapi@spec:security_requirement()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_security_requirements(Node, Context) -> 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) end ), fun(Reqs) -> {ok, {some, Reqs}} end ); _ -> {ok, none} end. -file("src/oaspec/openapi/parser.gleam", 1752). ?DOC(" Parse optional contact from an info node.\n"). -spec parse_optional_contact(yay:node_()) -> gleam@option:option(oaspec@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", 1771). ?DOC(" Parse optional license from an info node.\n"). -spec parse_optional_license(yay:node_()) -> gleam@option:option(oaspec@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", 149). ?DOC(" Parse the info object.\n"). -spec parse_info(yay:node_()) -> {ok, oaspec@openapi@spec:info()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_info(Root) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Root, <<"info"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<""/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(_) -> oaspec@openapi@diagnostic:missing_field( <<"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(_) -> oaspec@openapi@diagnostic:missing_field( <<"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", 1789). ?DOC(" Parse server variables from a server node.\n"). -spec parse_server_variables(yay:node_()) -> gleam@dict:dict(binary(), oaspec@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", 206). ?DOC(" Parse a single server object.\n"). -spec parse_server(yay:node_()) -> {ok, oaspec@openapi@spec:server()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_server(Node) -> gleam@result:'try'( begin _pipe = yay:extract_string(Node, <<"url"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<"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", 198). ?DOC(" Parse servers array.\n"). -spec parse_servers(yay:node_()) -> {ok, list(oaspec@openapi@spec:server())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_servers(Root) -> case yay:select_sugar(Root, <<"servers"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:try_map(Items, fun parse_server/1); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 1821). ?DOC(" Parse optional external docs from a node.\n"). -spec parse_optional_external_docs(yay:node_()) -> gleam@option:option(oaspec@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", 1839). ?DOC(" Parse tags array from root.\n"). -spec parse_tags(yay:node_()) -> list(oaspec@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", 1937). ?DOC(" Parse encoding map from a media type node.\n"). -spec parse_encoding_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:encoding())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_encoding_map(Node) -> 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), 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", 2018). ?DOC(" Parse links map from a node.\n"). -spec parse_links_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@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", 1702). ?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@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:callback(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_callback_object(Node, Context, Components) -> 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 ), 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>> )}; _ -> {ok, {callback, maps:from_list(Parsed_entries)}} end end ); _ -> {error, oaspec@openapi@diagnostic:missing_field( <>, <<"url expression"/utf8>> )} end. -file("src/oaspec/openapi/parser.gleam", 266). ?DOC(" Parse a single path item.\n"). -spec parse_path_item( yay:node_(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_path_item(Node, Path, Components) -> 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), fun(Get) -> gleam@result:'try'( parse_optional_operation( Node, <<"post"/utf8>>, Path, Components ), fun(Post) -> gleam@result:'try'( parse_optional_operation( Node, <<"put"/utf8>>, Path, Components ), fun(Put) -> gleam@result:'try'( parse_optional_operation( Node, <<"delete"/utf8>>, Path, Components ), fun(Delete) -> gleam@result:'try'( parse_optional_operation( Node, <<"patch"/utf8>>, Path, Components ), fun(Patch) -> gleam@result:'try'( parse_optional_operation( Node, <<"head"/utf8>>, Path, Components ), fun(Head) -> gleam@result:'try'( parse_optional_operation( Node, <<"options"/utf8>>, Path, Components ), fun(Options) -> gleam@result:'try'( parse_optional_operation( Node, <<"trace"/utf8>>, Path, Components ), fun(Trace) -> gleam@result:'try'( parse_parameters_list( Node, Components ), fun( Parameters ) -> gleam@result:'try'( parse_servers( Node ), 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", 340). ?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@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@option:option(oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_operation(Node, Method_key, Path, Components) -> case yay:select_sugar(Node, Method_key) of {ok, _} -> gleam@result:'try'( parse_operation_at(Node, Method_key, Path, Components), fun(Op) -> {ok, {some, Op}} end ); {error, _} -> {ok, none} end. -file("src/oaspec/openapi/parser.gleam", 361). ?DOC(" Parse an operation at a specific HTTP method key.\n"). -spec parse_operation_at( yay:node_(), binary(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_operation_at(Node, Method_key, Path, Components) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Node, Method_key), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field(Path, Method_key) end ) end, fun(Op_node) -> parse_operation( Op_node, <<<>/binary, Method_key/binary>>, Components ) end ). -file("src/oaspec/openapi/parser.gleam", 378). ?DOC(" Parse a single operation.\n"). -spec parse_operation( yay:node_(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:operation(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_operation(Node, Context, Components) -> 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), fun(Parameters) -> gleam@result:'try'( parse_optional_request_body(Node, Context, Components), fun(Request_body) -> gleam@result:'try'( parse_responses_required(Node, Context, Components), fun(Responses) -> gleam@result:'try'( parse_optional_security_requirements( Node, Context ), fun(Security) -> gleam@result:'try'( parse_callbacks( Node, Context, Components ), fun(Callbacks) -> gleam@result:'try'( parse_servers(Node), 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", 1674). ?DOC( " Parse callbacks from an operation node.\n" " Returns an empty dict if no callbacks are present.\n" " Propagates parse errors instead of silently dropping invalid callbacks.\n" ). -spec parse_callbacks( yay:node_(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:callback(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_callbacks(Node, Context, Components) -> 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} -> gleam@result:'try'( parse_callback_object( Value_node, Context, Components ), fun(Callback) -> {ok, gleam@dict:insert( Acc, Callback_name, Callback )} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 224). ?DOC(" Parse the paths object.\n"). -spec parse_paths( yay:node_(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_paths(Root, Components) -> 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 ), 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", 1428). ?DOC(" Parse the pathItems map from components.\n"). -spec parse_path_items_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_path_items_map(Components_node) -> 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 ), 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", 1859). ?DOC(" Parse webhooks from root.\n"). -spec parse_webhooks( yay:node_(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:path_item(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_webhooks(Node, Components) -> 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 ), 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", 1011). ?DOC(" Parse a schema object.\n"). -spec parse_schema_object(yay:node_(), binary()) -> {ok, oaspec@openapi@schema:schema_object()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_schema_object(Node, Path) -> Nullable = begin _pipe = yay:extract_optional_bool(Node, <<"nullable"/utf8>>), _pipe@1 = gleam@result:unwrap(_pipe, none), gleam@option:unwrap(_pipe@1, false) end, Description = begin _pipe@2 = yay:extract_optional_string(Node, <<"description"/utf8>>), gleam@result:unwrap(_pipe@2, none) 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, Title = begin _pipe@5 = yay:extract_optional_string(Node, <<"title"/utf8>>), gleam@result:unwrap(_pipe@5, none) end, Read_only = begin _pipe@6 = yay:extract_optional_bool(Node, <<"readOnly"/utf8>>), _pipe@7 = gleam@result:unwrap(_pipe@6, none), gleam@option:unwrap(_pipe@7, false) end, Write_only = begin _pipe@8 = yay:extract_optional_bool(Node, <<"writeOnly"/utf8>>), _pipe@9 = gleam@result:unwrap(_pipe@8, none), gleam@option:unwrap(_pipe@9, false) end, Default = oaspec@openapi@value:extract_optional(Node, <<"default"/utf8>>), Example = oaspec@openapi@value:extract_optional(Node, <<"example"/utf8>>), Const_value = oaspec@openapi@value:extract_optional(Node, <<"const"/utf8>>), Unsupported_keywords = detect_unsupported_keywords(Node), Metadata = {schema_metadata, Description, Nullable, Deprecated, Title, Read_only, Write_only, Default, Example, Const_value, none, Unsupported_keywords, false, user_authored}, case yay:select_sugar(Node, <<"allOf"/utf8>>) of {ok, {node_seq, Items}} -> gleam@result:'try'( gleam@list:try_map( Items, fun(_capture) -> parse_schema_ref( _capture, <> ) end ), fun(Schemas) -> {ok, {all_of_schema, Metadata, Schemas}} end ); _ -> case yay:select_sugar(Node, <<"oneOf"/utf8>>) of {ok, {node_seq, Items@1}} -> gleam@result:'try'( gleam@list:try_map( Items@1, fun(_capture@1) -> parse_schema_ref( _capture@1, <> ) end ), fun(Schemas@1) -> gleam@result:'try'( case yay:select_sugar( Node, <<"discriminator"/utf8>> ) of {ok, _} -> gleam@result:'try'( parse_discriminator(Node), fun(D) -> {ok, {some, D}} end ); {error, _} -> {ok, none} end, fun(Discriminator) -> {ok, {one_of_schema, Metadata, Schemas@1, Discriminator}} end ) end ); _ -> case yay:select_sugar(Node, <<"anyOf"/utf8>>) of {ok, {node_seq, Items@2}} -> gleam@result:'try'( gleam@list:try_map( Items@2, fun(_capture@2) -> parse_schema_ref( _capture@2, <> ) end ), fun(Schemas@2) -> gleam@result:'try'( case yay:select_sugar( Node, <<"discriminator"/utf8>> ) of {ok, _} -> gleam@result:'try'( parse_discriminator(Node), fun(D@1) -> {ok, {some, D@1}} end ); {error, _} -> {ok, none} end, fun(Discriminator@1) -> {ok, {any_of_schema, Metadata, Schemas@2, Discriminator@1}} end ) end ); _ -> parse_typed_schema(Node, Metadata, Path) end end end. -file("src/oaspec/openapi/parser.gleam", 1134). ?DOC(" Parse a typed schema (string, integer, number, boolean, array, object).\n"). -spec parse_typed_schema( yay:node_(), oaspec@openapi@schema:schema_metadata(), binary() ) -> {ok, oaspec@openapi@schema:schema_object()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_typed_schema(Node, Metadata, Path) -> gleam@result:'try'(case yay:select_sugar(Node, <<"type"/utf8>>) of {ok, {node_seq, Type_nodes}} -> Type_strs = gleam@list:filter_map( Type_nodes, fun(N) -> case N of {node_str, S} -> {ok, S}; _ -> {error, nil} end end ), Has_null = gleam@list:contains(Type_strs, <<"null"/utf8>>), Non_null_types = gleam@list:filter( Type_strs, fun(S@1) -> S@1 /= <<"null"/utf8>> end ), case Non_null_types of [Single] -> {ok, {Single, {schema_metadata, erlang:element(2, Metadata), erlang:element(3, Metadata) orelse Has_null, erlang:element(4, Metadata), erlang:element(5, Metadata), erlang:element(6, Metadata), erlang:element(7, Metadata), erlang:element(8, Metadata), erlang:element(9, Metadata), erlang:element(10, Metadata), erlang:element(11, Metadata), erlang:element(12, Metadata), erlang:element(13, Metadata), erlang:element(14, Metadata)}}}; [] -> {ok, {<<"object"/utf8>>, {schema_metadata, erlang:element(2, Metadata), erlang:element(3, Metadata) orelse Has_null, erlang:element(4, Metadata), erlang:element(5, Metadata), erlang:element(6, Metadata), erlang:element(7, Metadata), erlang:element(8, Metadata), erlang:element(9, Metadata), erlang:element(10, Metadata), erlang:element(11, Metadata), erlang:element(12, Metadata), erlang:element(13, Metadata), erlang:element(14, Metadata)}}}; _ -> Updated_meta = {schema_metadata, erlang:element(2, Metadata), erlang:element(3, Metadata) orelse Has_null, erlang:element(4, Metadata), erlang:element(5, Metadata), erlang:element(6, Metadata), erlang:element(7, Metadata), erlang:element(8, Metadata), erlang:element(9, Metadata), erlang:element(10, Metadata), {some, Non_null_types}, erlang:element(12, Metadata), erlang:element(13, Metadata), erlang:element(14, Metadata)}, Primary = case Non_null_types of [First | _] -> First; [] -> <<"object"/utf8>> end, {ok, {Primary, Updated_meta}} end; {ok, {node_str, S@2}} -> {ok, {S@2, Metadata}}; _ -> S@3 = begin _pipe = yay:extract_optional_string(Node, <<"type"/utf8>>), _pipe@1 = gleam@result:unwrap(_pipe, none), gleam@option:unwrap(_pipe@1, <<"object"/utf8>>) end, {ok, {S@3, Metadata}} end, fun(_use0) -> {Type_str, Metadata@1} = _use0, Format = begin _pipe@2 = yay:extract_optional_string(Node, <<"format"/utf8>>), gleam@result:unwrap(_pipe@2, none) end, case Type_str of <<"string"/utf8>> -> Enum_values = case yay:extract_string_list( Node, <<"enum"/utf8>> ) of {ok, Values} -> Values; _ -> [] end, Min_length = begin _pipe@3 = yay:extract_optional_int( Node, <<"minLength"/utf8>> ), gleam@result:unwrap(_pipe@3, none) end, Max_length = begin _pipe@4 = yay:extract_optional_int( Node, <<"maxLength"/utf8>> ), gleam@result:unwrap(_pipe@4, none) end, Pattern = begin _pipe@5 = yay:extract_optional_string( Node, <<"pattern"/utf8>> ), gleam@result:unwrap(_pipe@5, none) end, {ok, {string_schema, Metadata@1, Format, Enum_values, Min_length, Max_length, Pattern}}; <<"integer"/utf8>> -> Minimum = begin _pipe@6 = yay:extract_optional_int( Node, <<"minimum"/utf8>> ), gleam@result:unwrap(_pipe@6, none) end, Maximum = begin _pipe@7 = yay:extract_optional_int( Node, <<"maximum"/utf8>> ), gleam@result:unwrap(_pipe@7, none) end, Exclusive_minimum = begin _pipe@8 = yay:extract_optional_int( Node, <<"exclusiveMinimum"/utf8>> ), gleam@result:unwrap(_pipe@8, none) end, Exclusive_maximum = begin _pipe@9 = yay:extract_optional_int( Node, <<"exclusiveMaximum"/utf8>> ), gleam@result:unwrap(_pipe@9, none) end, Multiple_of = begin _pipe@10 = yay:extract_optional_int( Node, <<"multipleOf"/utf8>> ), gleam@result:unwrap(_pipe@10, none) end, {ok, {integer_schema, Metadata@1, Format, Minimum, Maximum, Exclusive_minimum, Exclusive_maximum, Multiple_of}}; <<"number"/utf8>> -> Minimum@1 = begin _pipe@11 = yay:extract_optional_float( Node, <<"minimum"/utf8>> ), gleam@result:unwrap(_pipe@11, none) end, Maximum@1 = begin _pipe@12 = yay:extract_optional_float( Node, <<"maximum"/utf8>> ), gleam@result:unwrap(_pipe@12, none) end, Exclusive_minimum@1 = begin _pipe@13 = yay:extract_optional_float( Node, <<"exclusiveMinimum"/utf8>> ), gleam@result:unwrap(_pipe@13, none) end, Exclusive_maximum@1 = begin _pipe@14 = yay:extract_optional_float( Node, <<"exclusiveMaximum"/utf8>> ), gleam@result:unwrap(_pipe@14, none) end, Multiple_of@1 = begin _pipe@15 = yay:extract_optional_float( Node, <<"multipleOf"/utf8>> ), gleam@result:unwrap(_pipe@15, none) end, {ok, {number_schema, Metadata@1, Format, Minimum@1, Maximum@1, Exclusive_minimum@1, Exclusive_maximum@1, Multiple_of@1}}; <<"boolean"/utf8>> -> {ok, {boolean_schema, Metadata@1}}; <<"array"/utf8>> -> gleam@result:'try'( case yay:select_sugar(Node, <<"items"/utf8>>) of {ok, Items_node} -> parse_schema_ref( Items_node, <> ); _ -> {error, oaspec@openapi@diagnostic:missing_field( Path, <<"items"/utf8>> )} end, fun(Items) -> Min_items = begin _pipe@16 = yay:extract_optional_int( Node, <<"minItems"/utf8>> ), gleam@result:unwrap(_pipe@16, none) end, Max_items = begin _pipe@17 = yay:extract_optional_int( Node, <<"maxItems"/utf8>> ), gleam@result:unwrap(_pipe@17, none) end, Unique_items = begin _pipe@18 = yay:extract_optional_bool( Node, <<"uniqueItems"/utf8>> ), _pipe@19 = gleam@result:unwrap(_pipe@18, none), gleam@option:unwrap(_pipe@19, false) end, {ok, {array_schema, Metadata@1, Items, Min_items, Max_items, Unique_items}} end ); <<"object"/utf8>> -> gleam@result:'try'( parse_properties(Node, Path), fun(Properties) -> Required = case yay:extract_string_list( Node, <<"required"/utf8>> ) of {ok, R} -> R; _ -> [] end, gleam@result:'try'( case yay:select_sugar( Node, <<"additionalProperties"/utf8>> ) of {ok, {node_bool, true}} -> {ok, untyped}; {ok, {node_bool, false}} -> {ok, forbidden}; {ok, Ap_node} -> gleam@result:'try'( parse_schema_ref( Ap_node, <> ), fun(Sr) -> {ok, {typed, Sr}} end ); _ -> {ok, untyped} end, fun(Additional_properties) -> Min_properties = begin _pipe@20 = yay:extract_optional_int( Node, <<"minProperties"/utf8>> ), gleam@result:unwrap(_pipe@20, none) end, Max_properties = begin _pipe@21 = yay:extract_optional_int( Node, <<"maxProperties"/utf8>> ), gleam@result:unwrap(_pipe@21, none) end, {ok, {object_schema, Metadata@1, Properties, Required, Additional_properties, Min_properties, Max_properties}} end ) end ); Unrecognized -> {error, oaspec@openapi@diagnostic:invalid_value( <>, <<<<"Unrecognized schema type '"/utf8, Unrecognized/binary>>/binary, "'. Supported types: string, integer, number, boolean, array, object."/utf8>> )} end end). -file("src/oaspec/openapi/parser.gleam", 1346). ?DOC(" Parse properties map from an object schema.\n"). -spec parse_properties(yay:node_(), binary()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_properties(Node, Path) -> case yay:select_sugar(Node, <<"properties"/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} -> gleam@result:'try'( parse_schema_ref( Value_node, <<<>/binary, Prop_name/binary>> ), fun(Schema_ref) -> {ok, gleam@dict:insert( Acc, Prop_name, Schema_ref )} end ); _ -> {ok, Acc} end end ); _ -> {ok, maps:new()} end. -file("src/oaspec/openapi/parser.gleam", 997). ?DOC(" Parse a schema reference (either $ref or inline schema).\n"). -spec parse_schema_ref(yay:node_(), binary()) -> {ok, oaspec@openapi@schema:schema_ref()} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_schema_ref(Node, Path) -> case yay:extract_optional_string(Node, <<"$ref"/utf8>>) of {ok, {some, Ref}} -> {ok, oaspec@openapi@schema:make_reference(Ref)}; _ -> gleam@result:'try'( parse_schema_object(Node, Path), fun(Schema_obj) -> {ok, {inline, Schema_obj}} end ) end. -file("src/oaspec/openapi/parser.gleam", 699). ?DOC(" Parse content map, requiring at least one entry for request bodies.\n"). -spec parse_required_content(yay:node_(), binary()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_required_content(Node, Context) -> 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'( parse_schema_ref( Schema_node, <> ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@openapi@value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@openapi@value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node), 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>> )} end. -file("src/oaspec/openapi/parser.gleam", 679). ?DOC(" Parse a request body object.\n"). -spec parse_request_body(yay:node_(), binary()) -> {ok, oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_body(Node, Context) -> 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), fun(Content) -> {ok, {request_body, Description, Content, Required}} end ). -file("src/oaspec/openapi/parser.gleam", 656). ?DOC(" Parse requestBody from a node.\n"). -spec parse_request_body_at( yay:node_(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_body_at(Node, Context, _) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Node, <<"requestBody"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( 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), fun(Rb) -> {ok, {value, Rb}} end ) end end ). -file("src/oaspec/openapi/parser.gleam", 445). ?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@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@option:option(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_request_body(Node, Context, Components) -> case yay:select_sugar(Node, <<"requestBody"/utf8>>) of {ok, _} -> gleam@result:'try'( parse_request_body_at(Node, Context, Components), fun(Rb) -> {ok, {some, Rb}} end ); {error, _} -> {ok, none} end. -file("src/oaspec/openapi/parser.gleam", 748). ?DOC(" Parse content map (media type -> schema).\n"). -spec parse_content(yay:node_(), binary()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_content(Node, Context) -> 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'( parse_schema_ref( Schema_node, <> ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@openapi@value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@openapi@value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node), 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", 892). ?DOC(" Parse the schemas map from components.\n"). -spec parse_schemas_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@schema:schema_ref())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_schemas_map(Components_node) -> 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'( parse_schema_ref( Value_node, <<"components.schemas."/utf8, Name/binary>> ), 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", 942). ?DOC(" Parse the requestBodies map from components.\n"). -spec parse_request_bodies_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:request_body(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_request_bodies_map(Components_node) -> 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>> ), 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", 1894). ?DOC(" Parse a content map (non-result version for use in Parameter).\n"). -spec parse_content_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:media_type())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_content_map(Node) -> 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'( parse_schema_ref( Schema_node, <<"content.schema"/utf8>> ), fun(Sr) -> {ok, {some, Sr}} end ); _ -> {ok, none} end, fun(Mt_schema) -> Mt_example = oaspec@openapi@value:extract_optional( Value_node, <<"example"/utf8>> ), Mt_examples = oaspec@openapi@value:extract_map( Value_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_encoding_map(Value_node), 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", 486). ?DOC(" Parse a single parameter.\n"). -spec parse_parameter( yay:node_(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameter(Node, _) -> 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(_) -> oaspec@openapi@diagnostic:missing_field( <<"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(_) -> oaspec@openapi@diagnostic:missing_field( <<"parameter."/utf8, Name/binary>>, <<"in"/utf8>> ) end ) end, fun(In_str) -> gleam@result:'try'( parse_parameter_in(In_str), 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>> )}; {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'( parse_schema_ref( Schema_node, <<"parameter.schema"/utf8>> ), 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 ), 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 ), fun(Content) -> Examples = oaspec@openapi@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", 474). ?DOC(" Parse parameters list from a node.\n"). -spec parse_parameters_list( yay:node_(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, list(oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameters_list(Node, Components) -> case yay:select_sugar(Node, <<"parameters"/utf8>>) of {ok, {node_seq, Items}} -> gleam@list:try_map( Items, fun(Item) -> parse_parameter(Item, Components) end ); _ -> {ok, []} end. -file("src/oaspec/openapi/parser.gleam", 916). ?DOC(" Parse the parameters map from components.\n"). -spec parse_parameters_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:parameter(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_parameters_map(Components_node) -> 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), 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", 1978). ?DOC(" Parse headers map from a node.\n"). -spec parse_headers_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:header())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_headers_map(Node) -> 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'( parse_schema_ref( Schema_node, <<<<"header."/utf8, Header_name/binary>>/binary, ".schema"/utf8>> ), 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", 831). ?DOC(" Parse a single response object.\n"). -spec parse_response( yay:node_(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_response(Node, _) -> 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(_) -> oaspec@openapi@diagnostic:missing_field( <<"response"/utf8>>, <<"description"/utf8>> ) end ) end, fun(Description) -> gleam@result:'try'( parse_content(Node, <<"response"/utf8>>), fun(Content) -> gleam@result:'try'( parse_headers_map(Node), 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", 793). ?DOC(" Parse responses object.\n"). -spec parse_responses( yay:node_(), binary(), gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@dict:dict(oaspec@util@http:http_status_code(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses(Node, _, Components) -> 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@util@http:parse_status_code( Status_code ) of {ok, Code} -> gleam@result:'try'( parse_response( Value_node, Components ), 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), 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", 462). ?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@openapi@spec:components(oaspec@openapi@spec:unresolved())) ) -> {ok, gleam@dict:dict(oaspec@util@http:http_status_code(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses_required(Node, Context, Components) -> parse_responses(Node, Context, Components). -file("src/oaspec/openapi/parser.gleam", 971). ?DOC(" Parse the responses map from components.\n"). -spec parse_responses_map(yay:node_()) -> {ok, gleam@dict:dict(binary(), oaspec@openapi@spec:ref_or(oaspec@openapi@spec:response(oaspec@openapi@spec:unresolved())))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_responses_map(Components_node) -> 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), 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", 858). ?DOC(" Parse the components section.\n"). -spec parse_components(yay:node_()) -> {ok, oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_components(Root) -> gleam@result:'try'( begin _pipe = yay:select_sugar(Root, <<"components"/utf8>>), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:missing_field( <<""/utf8>>, <<"components"/utf8>> ) end ) end, fun(Components_node) -> gleam@result:'try'( parse_schemas_map(Components_node), fun(Schemas) -> gleam@result:'try'( parse_parameters_map(Components_node), fun(Parameters) -> gleam@result:'try'( parse_request_bodies_map(Components_node), fun(Request_bodies) -> gleam@result:'try'( parse_responses_map(Components_node), fun(Responses) -> gleam@result:'try'( parse_security_schemes_map( Components_node ), fun(Security_schemes) -> gleam@result:'try'( parse_path_items_map( Components_node ), fun(Path_items) -> gleam@result:'try'( parse_headers_map( Components_node ), fun(Headers) -> Examples = oaspec@openapi@value:extract_map( Components_node, <<"examples"/utf8>> ), gleam@result:'try'( parse_links_map( Components_node ), fun( Links ) -> {ok, {components, Schemas, Parameters, Request_bodies, Responses, Security_schemes, Path_items, Headers, Examples, Links}} end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/oaspec/openapi/parser.gleam", 136). ?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_()) -> {ok, gleam@option:option(oaspec@openapi@spec:components(oaspec@openapi@spec:unresolved()))} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_optional_components(Root) -> case yay:select_sugar(Root, <<"components"/utf8>>) of {ok, _} -> gleam@result:'try'( parse_components(Root), fun(Comps) -> {ok, {some, Comps}} end ); {error, _} -> {ok, none} end. -file("src/oaspec/openapi/parser.gleam", 86). ?DOC(" Parse the root OpenAPI object.\n"). -spec parse_root(yay:node_()) -> {ok, oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_root(Node) -> 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(_) -> oaspec@openapi@diagnostic:missing_field( <<""/utf8>>, <<"openapi"/utf8>> ) end ) end, fun(Openapi) -> gleam@result:'try'( parse_info(Node), fun(Info) -> gleam@result:'try'( parse_optional_components(Node), fun(Components) -> gleam@result:'try'( parse_paths(Node, Components), fun(Paths) -> gleam@result:'try'( parse_servers(Node), fun(Servers) -> gleam@result:'try'( parse_security_requirements( Node, <<""/utf8>> ), fun(Security) -> gleam@result:'try'( parse_webhooks( Node, Components ), 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 ). -file("src/oaspec/openapi/parser.gleam", 54). ?DOC(" Parse an OpenAPI spec from a YAML/JSON string.\n"). -spec parse_string(binary()) -> {ok, oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_string(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), parse_root(Root) end) end ). -file("src/oaspec/openapi/parser.gleam", 37). ?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@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved())} | {error, oaspec@openapi@diagnostic:diagnostic()}. parse_file(Path) -> gleam@result:'try'( begin _pipe = simplifile:read(Path), gleam@result:map_error( _pipe, fun(_) -> oaspec@openapi@diagnostic:file_error( <<"Cannot read file: "/utf8, Path/binary>> ) end ) end, fun(Content) -> gleam@result:'try'( parse_string(Content), fun(Spec) -> oaspec@openapi@external_loader:resolve_external_component_refs( Spec, oaspec@openapi@external_loader:base_dir_of(Path), fun parse_file/1 ) end ) end ).