-module(yum@yaml).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/yum/yaml.gleam").
-export([parse_stream/1, parse/1, from_node/1, resolve/1, root/1, directives/1, diagnostics/1, get/2, get_keys/1, get_values/1, decode/2, to_string/1]).
-export_type([decode_error/0, directive/0, yaml/0, yaml_internal/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Parse, resolve, query, decode, and emit YAML documents.\n"
"\n"
" This is the main public module. It parses strings into opaque YAML\n"
" documents, resolves YAML-level metadata such as aliases and tags, retrieves\n"
" nested nodes by path, decodes documents with `gleam/dynamic/decode`, and\n"
" emits YAML strings from parsed or built documents.\n"
"\n"
" ```gleam\n"
" import gleam/option\n"
" import yum/yaml\n"
" import yum/yaml/node\n"
"\n"
" pub fn example() {\n"
" let assert Ok(document) = yaml.parse(\"name: yum\")\n"
"\n"
" let name =\n"
" document\n"
" |> yaml.get([node.Key(\"name\")])\n"
" |> option.map(node.as_string)\n"
"\n"
" assert name == option.Some(Ok(\"yum\"))\n"
" }\n"
" ```\n"
"\n"
" Use [`parse`](#parse) when you want a single YAML document value. Use\n"
" [`parse_stream`](#parse_stream) for YAML streams containing zero or more\n"
" explicit documents.\n"
"\n"
" Parsed YAML is raw syntax. Pipe it into [`resolve`](#resolve) to run the\n"
" semantic YAML phase that validates anchors, aliases, directives, and tags.\n"
"\n"
).
-type decode_error() :: {parse_error, yum@yaml@error:yaml_error()} |
{resolve_error, list(yum@yaml@diagnostic:diagnostic())} |
{unable_to_decode, list(gleam@dynamic@decode:decode_error())}.
-type directive() :: {directive, binary(), list(binary()), yum@yaml@node:span()}.
-opaque yaml() :: {raw, yaml_internal()} |
{resolved, yaml_internal(), list(yum@yaml@diagnostic:diagnostic())}.
-type yaml_internal() :: {yaml_internal,
yum@yaml@node:node_(),
list(yum@yaml@document:directive())}.
-file("src/yum/yaml.gleam", 280).
-spec raw_from_document(yum@yaml@document:document()) -> yaml().
raw_from_document(Document) ->
{raw,
{yaml_internal,
yum@yaml@document:root(Document),
yum@yaml@document:directives(Document)}}.
-file("src/yum/yaml.gleam", 273).
-spec count_indents(binary()) -> integer().
count_indents(Input) ->
case Input of
<<" "/utf8, Rest/binary>> ->
1 + count_indents(Rest);
_ ->
0
end.
-file("src/yum/yaml.gleam", 265).
-spec find_min_indent(list(binary())) -> {ok, integer()} |
{error, yum@yaml@error:yaml_error()}.
find_min_indent(Lines) ->
_pipe = Lines,
_pipe@1 = gleam@list:map(_pipe, fun count_indents/1),
_pipe@2 = gleam@list:map(_pipe@1, fun gleam@int:negate/1),
_pipe@3 = gleam@list:max(_pipe@2, fun gleam@int:compare/2),
gleam@result:replace_error(
_pipe@3,
yum@yaml@error:indent_normalization_error()
).
-file("src/yum/yaml.gleam", 254).
?DOC(
" Normalizes the indentation of the YAML file.\n"
" If all lines have <X leading whitespace, all lines will be trimmed X spaces\n"
" going forward.\n"
).
-spec normalize_indents(binary()) -> {ok, binary()} |
{error, yum@yaml@error:yaml_error()}.
normalize_indents(Input) ->
Lines = gleam@string:split(Input, <<"\n"/utf8>>),
gleam@result:'try'(
find_min_indent(Lines),
fun(X) ->
Min_indent = gleam@int:absolute_value(X),
_pipe = Lines,
_pipe@1 = gleam@list:map(
_pipe,
fun(_capture) ->
gleam@string:drop_start(_capture, Min_indent)
end
),
_pipe@2 = gleam@string:join(_pipe@1, <<"\n"/utf8>>),
{ok, _pipe@2}
end
).
-file("src/yum/yaml.gleam", 240).
?DOC(
" Normalizes whitespace in the YAML file.\n"
" By default, turns every un-escaped tab (`\\t`) into the given amount of\n"
" whitespaces.\n"
).
-spec normalize_whitespace(binary(), integer()) -> {ok, binary()} |
{error, yum@yaml@error:yaml_error()}.
normalize_whitespace(Input, Tab_equivalent) ->
gleam@bool:guard(Tab_equivalent =:= 0, {ok, Input}, fun() -> _pipe = Input,
_pipe@1 = gleam@string:replace(
_pipe,
<<"\t"/utf8>>,
gleam@string:repeat(<<" "/utf8>>, Tab_equivalent)
),
{ok, _pipe@1} end).
-file("src/yum/yaml.gleam", 111).
-spec parse_document_stream(binary()) -> {ok,
list(yum@yaml@document:document())} |
{error, yum@yaml@error:yaml_error()}.
parse_document_stream(Input) ->
gleam@result:'try'(
normalize_whitespace(Input, 0),
fun(Input@1) ->
gleam@result:'try'(
normalize_indents(Input@1),
fun(Input@2) ->
gleam@result:'try'(
yum@yaml@lexer:lex(Input@2),
fun(Tokens) ->
gleam@result:'try'(
yum@yaml@parser:parse_document_stream(Tokens),
fun(Parsed) -> {ok, Parsed} end
)
end
)
end
)
end
).
-file("src/yum/yaml.gleam", 105).
?DOC(" Parses a YAML stream into a list of YAML documents.\n").
-spec parse_stream(binary()) -> {ok, list(yaml())} |
{error, yum@yaml@error:yaml_error()}.
parse_stream(Input) ->
_pipe = Input,
_pipe@1 = parse_document_stream(_pipe),
gleam@result:map(
_pipe@1,
fun(_capture) -> gleam@list:map(_capture, fun raw_from_document/1) end
).
-file("src/yum/yaml.gleam", 93).
?DOC(
" Parses a YAML file into a YAML document.\n"
"\n"
" Follows the [YAML 1.2 specification](https://yaml.org/spec/1.2.2/)\n"
).
-spec parse(binary()) -> {ok, yaml()} | {error, yum@yaml@error:yaml_error()}.
parse(Input) ->
gleam@result:'try'(parse_stream(Input), fun(Documents) -> case Documents of
[Document] ->
{ok, Document};
[_, _ | _] ->
{error, yum@yaml@error:multiple_documents()};
[] ->
{error, yum@yaml@error:unexpected_end_of_input()}
end end).
-file("src/yum/yaml.gleam", 125).
?DOC(
" Creates a raw YAML document from a node.\n"
"\n"
" This is useful with [`yum/yaml/builder`](./yaml/builder.html), which builds\n"
" node trees.\n"
).
-spec from_node(yum@yaml@node:node_()) -> yaml().
from_node(Node) ->
{raw, {yaml_internal, Node, []}}.
-file("src/yum/yaml.gleam", 192).
-spec resolve_internal(yaml_internal()) -> {ok, yaml()} |
{error, list(yum@yaml@diagnostic:diagnostic())}.
resolve_internal(Internal) ->
{yaml_internal, Root, Directives} = Internal,
case yum@yaml@resolver:resolve(Root, Directives) of
{ok, {Root@1, Diagnostics}} ->
{ok, {resolved, {yaml_internal, Root@1, Directives}, Diagnostics}};
{error, Diagnostics@1} ->
{error, Diagnostics@1}
end.
-file("src/yum/yaml.gleam", 133).
?DOC(
" Resolves raw YAML into composed YAML.\n"
"\n"
" Calling this on already-resolved YAML is a no-op.\n"
).
-spec resolve(yaml()) -> {ok, yaml()} |
{error, list(yum@yaml@diagnostic:diagnostic())}.
resolve(Yaml) ->
case Yaml of
{resolved, _, _} ->
{ok, Yaml};
{raw, Internal} ->
resolve_internal(Internal)
end.
-file("src/yum/yaml.gleam", 292).
-spec internal(yaml()) -> yaml_internal().
internal(Yaml) ->
case Yaml of
{raw, Internal} ->
Internal;
{resolved, Internal, _} ->
Internal
end.
-file("src/yum/yaml.gleam", 142).
?DOC(" Returns the document root node.\n").
-spec root(yaml()) -> yum@yaml@node:node_().
root(Yaml) ->
{yaml_internal, Root, _} = internal(Yaml),
Root.
-file("src/yum/yaml.gleam", 287).
-spec public_directive(yum@yaml@document:directive()) -> directive().
public_directive(Directive) ->
{directive, Name, Parameters, Span} = Directive,
{directive, Name, Parameters, Span}.
-file("src/yum/yaml.gleam", 149).
?DOC(" Returns the document directives.\n").
-spec directives(yaml()) -> list(directive()).
directives(Yaml) ->
{yaml_internal, _, Directives} = internal(Yaml),
gleam@list:map(Directives, fun public_directive/1).
-file("src/yum/yaml.gleam", 156).
?DOC(" Returns non-fatal diagnostics collected while resolving the document.\n").
-spec diagnostics(yaml()) -> list(yum@yaml@diagnostic:diagnostic()).
diagnostics(Yaml) ->
case Yaml of
{raw, _} ->
[];
{resolved, _, Diagnostics} ->
Diagnostics
end.
-file("src/yum/yaml.gleam", 165).
?DOC(" Returns a nested node by mapping key or sequence index.\n").
-spec get(yaml(), list(yum@yaml@node:path_segment())) -> gleam@option:option(yum@yaml@node:node_()).
get(Yaml, Path) ->
_pipe = Yaml,
_pipe@1 = root(_pipe),
yum@yaml@node:get(_pipe@1, Path).
-file("src/yum/yaml.gleam", 176).
?DOC(
" Returns all keys from the root mapping.\n"
"\n"
" The keys are returned as nodes because YAML mappings can use scalar,\n"
" sequence, or mapping nodes as keys. Returns [`ExpectedKind`](./yaml/node.html#AccessError)\n"
" when the document root is not a mapping.\n"
).
-spec get_keys(yaml()) -> {ok, list(yum@yaml@node:node_())} |
{error, yum@yaml@node:access_error()}.
get_keys(Yaml) ->
_pipe = Yaml,
_pipe@1 = root(_pipe),
yum@yaml@node:get_keys(_pipe@1).
-file("src/yum/yaml.gleam", 186).
?DOC(
" Returns all values from the root mapping.\n"
"\n"
" Values are returned in source order. Returns [`ExpectedKind`](./yaml/node.html#AccessError)\n"
" when the document root is not a mapping.\n"
).
-spec get_values(yaml()) -> {ok, list(yum@yaml@node:node_())} |
{error, yum@yaml@node:access_error()}.
get_values(Yaml) ->
_pipe = Yaml,
_pipe@1 = root(_pipe),
yum@yaml@node:get_values(_pipe@1).
-file("src/yum/yaml.gleam", 207).
?DOC(
" Parses YAML and decodes it using a\n"
" [`gleam/dynamic/decode`](https://hexdocs.pm/gleam_stdlib/gleam/dynamic/decode.html)\n"
" decoder.\n"
).
-spec decode(binary(), gleam@dynamic@decode:decoder(PNQ)) -> {ok, PNQ} |
{error, decode_error()}.
decode(Input, Decoder) ->
gleam@result:'try'(
begin
_pipe = parse(Input),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {parse_error, Field@0} end
)
end,
fun(Document) ->
gleam@result:'try'(
begin
_pipe@1 = Document,
_pipe@2 = resolve(_pipe@1),
gleam@result:map_error(
_pipe@2,
fun(Field@0) -> {resolve_error, Field@0} end
)
end,
fun(Document@1) -> _pipe@3 = Document@1,
_pipe@4 = root(_pipe@3),
_pipe@5 = yum@yaml@dynamic:from_node(_pipe@4),
_pipe@6 = gleam@dynamic@decode:run(_pipe@5, Decoder),
gleam@result:map_error(
_pipe@6,
fun(Field@0) -> {unable_to_decode, Field@0} end
) end
)
end
).
-file("src/yum/yaml.gleam", 230).
?DOC(" Emits a deterministic YAML string from a YAML document.\n").
-spec to_string(yaml()) -> binary().
to_string(Yaml) ->
_pipe = Yaml,
_pipe@1 = root(_pipe),
yum@yaml@emitter:to_string(_pipe@1).