28 releases (18 breaking)

Uses new Rust 2024

new 0.19.0 Apr 22, 2026
0.17.0 Feb 8, 2026
0.16.2 Sep 4, 2025
0.16.1 Jun 9, 2025
0.4.0 Jul 10, 2023

#26 in #markdown-parser

Download history 157/week @ 2025-12-25 135/week @ 2026-01-01 2/week @ 2026-01-08 17/week @ 2026-01-15 76/week @ 2026-01-22 27/week @ 2026-01-29 65/week @ 2026-02-05 28/week @ 2026-02-12 27/week @ 2026-02-19 6/week @ 2026-02-26 65/week @ 2026-03-05 15/week @ 2026-03-12 52/week @ 2026-03-19 22/week @ 2026-03-26 22/week @ 2026-04-02 53/week @ 2026-04-09

150 downloads per month

MIT/Apache

720KB
6.5K SLoC

yamd

codecov crates.io Released API docs

YAMD - Yet Another Markdown Document (flavour)

Simplified version of CommonMark.

For formatting check YAMD struct documentation.

Quick start

use yamd::deserialize;

let input = "# Hello\n\nA paragraph with **bold** text.";
let yamd = deserialize(input);

// Access the AST
assert_eq!(yamd.body.len(), 2);

// Round-trip back to markdown
assert_eq!(yamd.to_string(), input);

Two APIs

  • deserialize returns a nested Yamd document — a tree of typed nodes, suitable for walking, pattern-matching, or round-tripping back to markdown via Display. The AST makes invalid nestings unrepresentable, and deserialize is fuzz-tested for panic-freedom and property-tested for round-trip fidelity.
  • parse returns a flat Vec<Op> of Start/End/Value events, where Content borrows from the source when possible. Reach for it when you want streaming rendering or zero-copy text processing without materializing the full tree. to_yamd promotes an event stream to the tree form. Fuzz-tested for panic-freedom (transitively, via deserialize); the AST's type-level invariants and round-trip property do not apply at this layer.

Reasoning

YAMD exchanges CommonMark's context-dependent rules for a uniform set: every node is treated the same, and escaping is resolved at the lexer. The goal is a parser that's easier to reason about locally, with fewer special cases to remember.

Rendering is out of scope; Yamd is an AST you walk and render however you like. With the serde feature enabled, the AST is also serde-serializable.

Difference from CommonMark

YAMD reuses most of CommonMark's syntax but diverges in a few places.

Escaping

Escaping is handled at the [lexer] level: any character following \ is treated as a literal.

Example:

YAMD HTML equivalent
\**foo** <p>**foo**</p>

Precedence

CommonMark distinguishes container blocks from leaf blocks and gives container-block markers higher precedence. YAMD does not distinguish block types — every node is treated the same, so there are no precedence rules to remember.

Example:

YAMD HTML equivalent
- `one\n- two` <ol><li><code>one\n- two</code></li></ol>

To get two separate ListItems, escape the backticks:

YAMD HTML equivalent
- \`one\n- two\` <ol><li>`one</li><li>two`</li><ol>

The reasoning: issues like this should be caught by tooling such as linters or language servers — that tooling doesn't exist yet.

Nodes

See [nodes] for the full list of supported nodes and their formatting. Start with YAMD.

MSRV

YAMD minimal supported Rust version is 1.87.

Dependencies