1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! YAMD - Yet Another Markdown Document (flavour)
//!
//! Simplified version of [CommonMark](https://spec.commonmark.org/).
//!
//! For formatting check [`YAMD`](nodes::Yamd) struct documentation.
//!
//! # Quick start
//!
//! ```rust
//! 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`](nodes::Yamd) document — a tree of typed nodes,
//! suitable for walking, pattern-matching, or round-tripping back to markdown via
//! [`Display`](std::fmt::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`](op::Op)`>` of Start/End/Value events, where
//! [`Content`](op::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`](nodes::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](lexer::TokenKind::Literal).
//!
//! Example:
//!
//! | YAMD | HTML equivalent |
//! |-----------|-----------------|
//! | `\**foo**`|`<p>**foo**</p>` |
//!
//! ## Precedence
//!
//! [CommonMark](https://spec.commonmark.org/0.31.2/#precedence) 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 [ListItem](nodes::ListItem)s, 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](nodes::Yamd).
//!
//! # MSRV
//!
//! YAMD minimal supported Rust version is 1.87.
pub use Yamd;
pub use parse;
pub use to_yamd;
/// Deserialize a string into a Yamd struct
/// # Example
/// ```
/// use yamd::deserialize;
/// let input = "# header";
/// let yamd = deserialize(input);
/// ```