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
150 downloads per month
720KB
6.5K
SLoC
yamd
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
deserializereturns a nestedYamddocument — a tree of typed nodes, suitable for walking, pattern-matching, or round-tripping back to markdown viaDisplay. The AST makes invalid nestings unrepresentable, anddeserializeis fuzz-tested for panic-freedom and property-tested for round-trip fidelity.parsereturns a flatVec<Op>of Start/End/Value events, whereContentborrows from the source when possible. Reach for it when you want streaming rendering or zero-copy text processing without materializing the full tree.to_yamdpromotes an event stream to the tree form. Fuzz-tested for panic-freedom (transitively, viadeserialize); 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.