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

Output

Types

pub type Error =
  @internal ParseError

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.

Search Document