taffy
A pure-Gleam YAML 1.2 parser. Passes 351/351 of the official YAML test
suite. Works on both Erlang and JavaScript targets; an optional native
backend (taffy/native, Erlang only) wraps fast_yaml for ~3-7×
speedup on large documents.
Quick start
import taffy
pub fn main() {
let assert Ok(value) =
taffy.parse("name: John\nage: 30\ntags:\n - gleam\n - erlang")
let assert Ok(name) = taffy.get(value, "name")
let json = taffy.to_json_string(value)
}
Supported YAML features
- Scalars: strings, numbers (incl.
0x,0o,.inf,.nan), booleans, null - Block + flow collections:
- item,key: value,[a, b],{k: v} - Multi-line strings:
|(literal) and>(folded) - Anchors and aliases:
&anchorand*alias - Merge keys:
<<: *anchorand<<: [*a, *b], resolved automatically - Multi-document streams via
parse_all - Comments, document markers (
---,...), tag directives
Output
to_json/to_json_string— convert togleam_jsonvaluesto_yaml— emit block-style YAML, round-trips throughparsevalidate_unique_keys— opt-in YAML 1.2 strict duplicate-key check
Types
pub type Value =
value.YamlValue
Values
pub fn as_bool(val: value.YamlValue) -> option.Option(Bool)
Pull out a bool scalar; None for any other variant.
pub fn as_dict(
val: value.YamlValue,
) -> option.Option(dict.Dict(String, value.YamlValue))
Pull out a mapping as a Dict. Note: this loses YAML’s insertion order;
use as_pairs if order matters.
pub fn as_float(val: value.YamlValue) -> option.Option(Float)
Pull out a float scalar. Coerces Int(n) to Float(n) so numeric callers
don’t have to branch on the parse-time tag.
pub fn as_int(val: value.YamlValue) -> option.Option(Int)
Pull out an int scalar; None for any other variant (no float coercion).
pub fn as_list(
val: value.YamlValue,
) -> option.Option(List(value.YamlValue))
Pull out a sequence as a list. Order is preserved.
pub fn as_pairs(
val: value.YamlValue,
) -> option.Option(List(#(String, value.YamlValue)))
Pull out a mapping as ordered #(key, value) pairs, preserving YAML
insertion order.
pub fn as_string(val: value.YamlValue) -> option.Option(String)
Pull out a string scalar; None for any other variant.
pub fn error_location(input: String, pos: Int) -> #(Int, Int)
Compute #(line, column) (both 1-indexed) for a grapheme position
inside input. Out-of-range positions clamp to the last line/column.
Useful for turning error.pos into a user-facing location:
case taffy.parse(input) {
Ok(_) -> ...
Error(err) -> {
let #(line, col) = taffy.error_location(input, err.pos)
io.println(err.message <> " at " <> int.to_string(line) <>
":" <> int.to_string(col))
}
}
pub fn get(
val: value.YamlValue,
key: String,
) -> Result(value.YamlValue, Nil)
Look up a key in a mapping. Returns Error(Nil) when val is not a
mapping or the key is absent.
pub fn get_or(
val: value.YamlValue,
key: String,
default: value.YamlValue,
) -> value.YamlValue
Like get, but returns default instead of an error when the key is
missing or val is not a mapping.
pub fn get_path(
val: value.YamlValue,
path: List(String),
) -> Result(value.YamlValue, Nil)
Walk a chain of keys through nested mappings. An empty path returns
val unchanged; any missing key short-circuits to Error(Nil).
pub fn index(
val: value.YamlValue,
idx: Int,
) -> Result(value.YamlValue, Nil)
Get the idx-th item of a sequence (0-indexed). Returns Error(Nil) if
val is not a sequence or idx is out of range.
pub fn is_null(val: value.YamlValue) -> Bool
True only for Null. Bool/Int/zero values all return False.
pub fn parse(input: String) -> Result(value.YamlValue, Error)
Parse a single YAML document. For multi-document streams use parse_all.
On error the position points at the grapheme where parsing gave up.
<< merge keys are resolved automatically. Duplicate mapping keys are
allowed (with first-wins access) — the YAML 1.2 spec mandates uniqueness
but the official test suite expects parsers to accept them; use
validate_unique_keys to enforce strict uniqueness yourself.
pub fn parse_all(
input: String,
) -> Result(List(value.YamlValue), Error)
Parse a YAML stream as a list of documents. Empty input yields [].
Same merge-key + duplicate semantics as parse.
pub fn to_json(val: value.YamlValue) -> json.Json
Convert a parsed YAML value into a gleam_json Json. Whole-valued
floats serialize as ints to round-trip nicely with the YAML test suite.
pub fn to_json_string(val: value.YamlValue) -> String
Convenience wrapper around to_json + json.to_string.
pub fn to_string(val: value.YamlValue) -> String
Render a value as a JSON-shaped debug string. Useful for snapshot tests;
for round-trippable YAML output use to_yaml.
pub fn to_yaml(val: value.YamlValue) -> String
Emit a value as block-style YAML with a trailing newline. The output
round-trips through parse for all values that are themselves
round-trippable (taffy is lossy on tag, anchor, and comment metadata).
pub fn validate_unique_keys(
val: value.YamlValue,
) -> Result(value.YamlValue, Error)
Reject any mapping (recursively) that contains duplicate keys. The error
message names the first offending key. Run after parse if your
application requires YAML 1.2’s key-uniqueness invariant.