Packages
oaspec
0.56.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec@openapi@parser.erl
-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_with_locations/1, parse_string/1, parse_file/1, parse_file_with_progress_and_locations/2, parse_json_string/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", 146).
-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", 162).
?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", 173).
-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", 242).
?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", 280).
?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", 306).
-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", 388).
-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", 374).
?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", 891).
?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", 912).
?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", 936).
?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", 1270).
?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", 1382).
?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", 1548).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Flow_node,
<<"authorizationUrl"/utf8>>
),
Token_url = oaspec@internal@openapi@parser_value:optional_string(
Flow_node,
<<"tokenUrl"/utf8>>
),
Refresh_url = oaspec@internal@openapi@parser_value:optional_string(
Flow_node,
<<"refreshUrl"/utf8>>
),
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", 1451).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"bearerFormat"/utf8>>
),
{ok, {http_scheme, Scheme, Bearer_format}}
end
);
<<"oauth2"/utf8>> ->
Description = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
Flows = parse_oauth2_flows(Node),
{ok, {o_auth2_scheme, Description, Flows}};
<<"openIdConnect"/utf8>> ->
Description@1 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
gleam@result:'try'(
begin
_pipe@4 = yay:extract_string(
Node,
<<"openIdConnectUrl"/utf8>>
),
gleam@result:map_error(
_pipe@4,
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", 1389).
?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", 1632).
?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(
<<<<Context/binary,
".security."/utf8>>/binary,
Scheme_name/binary>>,
<<"Scope must be a string"/utf8>>,
oaspec@internal@openapi@location_index:lookup(
Index,
<<<<Context/binary,
".security."/utf8>>/binary,
Scheme_name/binary>>
)
)}
end end
);
node_nil ->
{ok, []};
_ ->
{error,
oaspec@openapi@diagnostic:invalid_value(
<<<<Context/binary,
".security."/utf8>>/binary,
Scheme_name/binary>>,
<<"Scopes must be an array of strings"/utf8>>,
oaspec@internal@openapi@location_index:lookup(
Index,
<<<<Context/binary,
".security."/utf8>>/binary,
Scheme_name/binary>>
)
)}
end, fun(Scopes) ->
{ok,
{security_scheme_ref,
Scheme_name,
Scopes}}
end);
_ ->
{error,
oaspec@openapi@diagnostic:invalid_value(
<<Context/binary, ".security"/utf8>>,
<<"Security requirement key must be a string"/utf8>>,
oaspec@internal@openapi@location_index:lookup(
Index,
<<Context/binary, ".security"/utf8>>
)
)}
end
end
),
fun(Scheme_refs) ->
{ok, {security_requirement, Scheme_refs}}
end
);
_ ->
{error,
oaspec@openapi@diagnostic:invalid_value(
<<Context/binary, ".security"/utf8>>,
<<"Security requirement must be an object"/utf8>>,
oaspec@internal@openapi@location_index:lookup(
Index,
<<Context/binary, ".security"/utf8>>
)
)}
end.
-file("src/oaspec/openapi/parser.gleam", 1594).
?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", 1611).
?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", 1806).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Contact_node,
<<"name"/utf8>>
),
Url = oaspec@internal@openapi@parser_value:optional_string(
Contact_node,
<<"url"/utf8>>
),
Email = oaspec@internal@openapi@parser_value:optional_string(
Contact_node,
<<"email"/utf8>>
),
{some, {contact, Name, Url, Email}};
_ ->
none
end.
-file("src/oaspec/openapi/parser.gleam", 1819).
?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 = oaspec@internal@openapi@parser_value:optional_string(
License_node,
<<"url"/utf8>>
),
{some, {license, Name, Url}};
_ ->
none
end;
_ ->
none
end.
-file("src/oaspec/openapi/parser.gleam", 419).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Info_node,
<<"description"/utf8>>
),
Summary = oaspec@internal@openapi@parser_value:optional_string(
Info_node,
<<"summary"/utf8>>
),
Terms_of_service = oaspec@internal@openapi@parser_value:optional_string(
Info_node,
<<"termsOfService"/utf8>>
),
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", 1835).
?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 = oaspec@internal@openapi@parser_value:string_default(
Value_node,
<<"default"/utf8>>,
<<""/utf8>>
),
Enum_values = case yay:extract_string_list(
Value_node,
<<"enum"/utf8>>
) of
{ok, Values} ->
Values;
_ ->
[]
end,
Description = oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"description"/utf8>>
),
gleam@dict:insert(
Acc,
Var_name,
{server_variable,
Default,
Enum_values,
Description}
);
_ ->
Acc
end
end
);
_ ->
maps:new()
end.
-file("src/oaspec/openapi/parser.gleam", 484).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
Variables = parse_server_variables(Node),
{ok, {server, Url, Description, Variables}}
end
).
-file("src/oaspec/openapi/parser.gleam", 472).
?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", 1863).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Doc_node,
<<"description"/utf8>>
),
{some, {external_doc, Url, Description}};
_ ->
none
end;
_ ->
none
end.
-file("src/oaspec/openapi/parser.gleam", 1880).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Tag_node,
<<"description"/utf8>>
),
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", 1979).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"contentType"/utf8>>
),
gleam@result:'try'(
case oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"style"/utf8>>
) of
{some, S} ->
gleam@result:'try'(
parse_parameter_style(S, Index),
fun(Parsed) ->
{ok, {some, Parsed}}
end
);
none ->
{ok, none}
end,
fun(Style) ->
Explode = oaspec@internal@openapi@parser_value:optional_bool(
Value_node,
<<"explode"/utf8>>
),
{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", 999).
?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,
<<Context/binary,
".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
);
_ ->
{error,
oaspec@openapi@diagnostic:missing_field(
<<Context/binary, ".requestBody"/utf8>>,
<<"content"/utf8>>,
oaspec@internal@openapi@location_index:lookup_field(
Index,
<<Context/binary, ".requestBody"/utf8>>,
<<"content"/utf8>>
)
)}
end.
-file("src/oaspec/openapi/parser.gleam", 983).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
Required = oaspec@internal@openapi@parser_value:bool_default(
Node,
<<"required"/utf8>>,
false
),
gleam@result:'try'(
parse_required_content(Node, Context, Index),
fun(Content) -> {ok, {request_body, Description, Content, Required}} end
).
-file("src/oaspec/openapi/parser.gleam", 956).
?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", 742).
?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", 1056).
?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,
<<Context/binary,
".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", 1323).
?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", 1933).
?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", 784).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
Explicit_required = oaspec@internal@openapi@parser_value:optional_bool(
Node,
<<"required"/utf8>>
),
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 = oaspec@internal@openapi@parser_value:bool_default(
Node,
<<"deprecated"/utf8>>,
false
),
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 oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"style"/utf8>>
) of
{some, S} ->
gleam@result:'try'(
parse_parameter_style(
S,
Index
),
fun(Parsed) ->
{ok,
{some,
Parsed}}
end
);
none ->
{ok, none}
end,
fun(Style) ->
Explode = oaspec@internal@openapi@parser_value:optional_bool(
Node,
<<"explode"/utf8>>
),
Allow_reserved = oaspec@internal@openapi@parser_value:bool_default(
Node,
<<"allowReserved"/utf8>>,
false
),
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", 771).
?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", 1296).
?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", 2015).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"description"/utf8>>
),
Required = oaspec@internal@openapi@parser_value:bool_default(
Value_node,
<<"required"/utf8>>,
false
),
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", 2056).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"operationId"/utf8>>
),
Description = oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"description"/utf8>>
),
{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", 1145).
?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", 1104).
?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", 758).
?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", 1354).
?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", 1747).
?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 oaspec@internal@openapi@parser_value:optional_string(
Path_item_node,
<<"$ref"/utf8>>
) of
{some, Ref_str} ->
{ok,
[{Url_expression, {ref, Ref_str}} |
Acc]};
none ->
gleam@result:'try'(
parse_path_item(
Path_item_node,
<<<<Context/binary,
".callbacks."/utf8>>/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(
<<Context/binary, ".callbacks"/utf8>>,
<<"url expression"/utf8>>,
oaspec@internal@openapi@location_index:lookup_field(
Index,
<<Context/binary, ".callbacks"/utf8>>,
<<"url expression"/utf8>>
)
)};
_ ->
{ok, {callback, maps:from_list(Parsed_entries)}}
end end
);
_ ->
{error,
oaspec@openapi@diagnostic:missing_field(
<<Context/binary, ".callbacks"/utf8>>,
<<"url expression"/utf8>>,
oaspec@internal@openapi@location_index:lookup_field(
Index,
<<Context/binary, ".callbacks"/utf8>>,
<<"url expression"/utf8>>
)
)}
end.
-file("src/oaspec/openapi/parser.gleam", 547).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"summary"/utf8>>
),
Description = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
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", 636).
?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", 656).
?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,
<<<<Path/binary, "."/utf8>>/binary, Method_key/binary>>,
Components,
Index
)
end
).
-file("src/oaspec/openapi/parser.gleam", 677).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"operationId"/utf8>>
),
Summary = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"summary"/utf8>>
),
Description = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"description"/utf8>>
),
Tags = case yay:extract_string_list(Node, <<"tags"/utf8>>) of
{ok, T} ->
T;
_ ->
[]
end,
Deprecated = oaspec@internal@openapi@parser_value:bool_default(
Node,
<<"deprecated"/utf8>>,
false
),
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", 1699).
?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(
<<<<<<Context/binary,
".callbacks."/utf8>>/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,
<<<<Context/binary,
".callbacks."/utf8>>/binary,
Callback_name/binary>>,
<<"$ref"/utf8>>
)
)}
end;
_ ->
{ok, Acc}
end
end
);
_ ->
{ok, maps:new()}
end.
-file("src/oaspec/openapi/parser.gleam", 506).
?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 oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"$ref"/utf8>>
) 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", 1228).
?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", 1419).
?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", 1176).
?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", 407).
?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", 1899).
?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 oaspec@internal@openapi@parser_value:optional_string(
Value_node,
<<"$ref"/utf8>>
) 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", 312).
?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 = oaspec@internal@openapi@parser_value:optional_string(
Node,
<<"jsonSchemaDialect"/utf8>>
),
{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", 203).
?DOC(
" Same as `parse_string` but also returns the YAML `LocationIndex`\n"
" built from the input. Caller-side companion to\n"
" `parse_file_with_locations` (Issue #411).\n"
).
-spec parse_string_with_locations(binary()) -> {ok,
{oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()),
oaspec@internal@openapi@location_index:location_index()}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
parse_string_with_locations(Content) ->
gleam@result:'try'(
parse_to_node(Content),
fun(_use0) ->
{Root, Index} = _use0,
gleam@result:map(
parse_root(Root, Index),
fun(Spec) -> {Spec, Index} end
)
end
).
-file("src/oaspec/openapi/parser.gleam", 193).
?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) ->
_pipe = parse_string_with_locations(Content),
gleam@result:map(_pipe, fun(Pair) -> erlang:element(1, Pair) end).
-file("src/oaspec/openapi/parser.gleam", 231).
?DOC(
" JSON variant of `parse_string_with_locations`. OTP's `json:decode/3`\n"
" does not expose token positions so the returned `LocationIndex` is\n"
" always empty; capability-check diagnostics from a JSON-only spec\n"
" keep `NoSourceLoc`.\n"
).
-spec parse_json_string_with_locations(binary()) -> {ok,
{oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()),
oaspec@internal@openapi@location_index:location_index()}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
parse_json_string_with_locations(Content) ->
gleam@result:'try'(
decode_json_to_node(Content),
fun(Root) ->
gleam@result:map(
parse_root(Root, oaspec@internal@openapi@location_index:empty()),
fun(Spec) ->
{Spec, oaspec@internal@openapi@location_index:empty()}
end
)
end
).
-file("src/oaspec/openapi/parser.gleam", 70).
?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"
"\n"
" Returns both the parsed spec and the YAML `LocationIndex` built from\n"
" the file's content. Recursive external-ref resolution discards\n"
" nested files' indices — only the top-level file's index is surfaced\n"
" (capability-check needs *one* canonical index, and external refs\n"
" land back at their `$ref` site in the main file anyway).\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()),
oaspec@internal@openapi@location_index:location_index()}} |
{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_with_locations(Content);
false ->
parse_string_with_locations(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(_use0) ->
{Spec, Index} = _use0,
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_planner:base_dir_of(
Path
),
fun(Sub_path) ->
_pipe@1 = parse_file_internal(
Sub_path,
New_visited,
Reporter
),
gleam@result:map(
_pipe@1,
fun(Pair) ->
erlang:element(1, Pair)
end
)
end
)
end
),
oaspec@internal@progress:report(
Reporter,
<<<<"resolve relative-file $ref components (took "/utf8,
(oaspec@internal@progress:format_ms(
Elapsed@2
))/binary>>/binary,
")"/utf8>>
),
_pipe@2 = Resolved,
gleam@result:map(_pipe@2, fun(S) -> {S, Index} end)
end
)
end
)
end
).
-file("src/oaspec/openapi/parser.gleam", 42).
?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 across schemas,\n"
" parameters, request bodies, responses, and path items — including\n"
" nested object/array properties and composition branches — by loading\n"
" the referenced files from disk and merging their definitions into the\n"
" main spec. Cyclic external ref graphs (`A.yaml → B.yaml → A.yaml`)\n"
" fail fast with a dedicated diagnostic. HTTP/HTTPS URLs are not\n"
" followed.\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) ->
_pipe = parse_file_internal(Path, [], oaspec@internal@progress:noop()),
gleam@result:map(_pipe, fun(Pair) -> erlang:element(1, Pair) end).
-file("src/oaspec/openapi/parser.gleam", 54).
?DOC(
" Combined `parse_file` entry point that accepts a `Reporter` and\n"
" also returns the top-level YAML `LocationIndex`. Issue #411 +\n"
" #352. The CLI uses this so capability-check diagnostics surface\n"
" `path:line:column:` and progress lines on big specs at the same\n"
" time. Library callers that don't need progress should pass\n"
" `progress.noop()`; callers that don't need locations can discard\n"
" the second tuple element.\n"
).
-spec parse_file_with_progress_and_locations(
binary(),
oaspec@internal@progress:reporter()
) -> {ok,
{oaspec@internal@openapi@spec:open_api_spec(oaspec@internal@openapi@spec:unresolved()),
oaspec@internal@openapi@location_index:location_index()}} |
{error, oaspec@openapi@diagnostic:diagnostic()}.
parse_file_with_progress_and_locations(Path, Reporter) ->
parse_file_internal(Path, [], Reporter).
-file("src/oaspec/openapi/parser.gleam", 220).
?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) ->
_pipe = parse_json_string_with_locations(Content),
gleam@result:map(_pipe, fun(Pair) -> erlang:element(1, Pair) end).