Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

AD-0005 — YAML via pretty_yaml

Context

FR-1.4 requires canonical YAML formatting that preserves comments, anchors/aliases, and multi-line (block) scalar styles, without reordering keys or sequence entries (FR-3.4) or changing the data model (FR-6.2). Unparseable input must be left unchanged and reported (FR-6.3). YAML is the hardest format to round-trip, and the Rust ecosystem has few formatter-grade options.

Options

pretty_yaml (chosen). A configurable YAML formatter by g-plane, the YAML member of the same CST-formatter family (tiny_pretty + yaml_parser, a rowan CST) that backs several dprint plugins. format_text(input, &FormatOptions) -> Result<String, SyntaxError> returns a parse error directly on invalid YAML — so no separate parse step is needed. It preserves comments, anchors/aliases, and block (literal | / folded >) scalar styles, and never reorders. Pure Rust.

yaml-rust2 / saphyr / yaml-peg. YAML 1.2 parsers without a canonical, comment-preserving printer. Using one would mean writing prim’s own YAML printer — anchors, aliases, flow vs block, multi-line scalars — far too much surface. Rejected.

serde_yaml. Deprecated, and its value model strips comments and styles. Rejected.

Hand-rolled formatter. Rejected on minimum-code grounds; YAML’s round-trip fidelity is exactly what pretty_yaml already solves.

Decision: pretty_yaml as a library, in a prim-fmt yaml module

pretty_yaml = "0.6" is added to prim-fmt. The integration lives in a yaml module (mirroring json/toml). prim_fmt::format dispatches FileKind::Yaml to it.

Options mapping from Style. LayoutOptions.print_width from max_line_length (default 80); LayoutOptions.indent_width from Style::indent; LayoutOptions.line_break = Lf (the existing hygiene pass owns end-of-line and final-newline, keeping one source of truth across formats). LanguageOptions defaults are used.

Tab indentation. YAML forbids tabs for indentation and pretty_yaml has no tab option, so Indent::Tab falls back to a two-space indent.

Parse errors. format_text returns Err(SyntaxError) on invalid YAML, mapped to FormatError::Parse. CLI handling is identical to JSON/TOML (explicit → exit 2, discovered → warning, stdin → echo original + exit 2).

Consequences

pretty_yaml (and its transitive yaml_parser, rowan, tiny_pretty) become prim-fmt dependencies — all pure Rust, no FFI. With YAML done, only Markdown (#12, FR-1.1) remains among the per-format passes. A pre-existing .editorconfig behavioural test that used a .yaml file as a hygiene-only vehicle was retargeted to a .txt orphan, which stays hygiene-only regardless of future per-format passes.


Satisfies: FR-1.4 (YAML canonical; comments, anchors/aliases, block scalar styles preserved), FR-3.4 (no reorder), FR-6.2 (data model unchanged), FR-6.3 (unparseable files unchanged and reported).
Related: AD-0003 (the fallible format API), AD-0004 (TOML via taplo), docs/design/system.md, crates/prim-fmt/src/yaml.rs.