yamd/lib.rs
1//! YAMD - Yet Another Markdown Document (flavour)
2//!
3//! Simplified version of [CommonMark](https://spec.commonmark.org/).
4//!
5//! For formatting check [`YAMD`](nodes::Yamd) struct documentation.
6//!
7//! # Reasoning
8//!
9//! Simplified set of rules allows to have simpler, more efficient, parser and renderer.
10//! [YAMD](nodes::Yamd) does not provide render functionality, instead it is a [serde]
11//! serializable structure that allows you to write any renderer for that structure. All HTML
12//! equivalents in this doc are provided as an example to what it can be rendered.
13//!
14//! # Difference from CommonMark
15//!
16//! While YAMD tries to utilize as much CommonMark syntax as possible, there are differences.
17//!
18//! ## Escaping
19//!
20//! Escaping done on a [lexer] level. Every symbol following the `\` symbol will be treated as a
21//! [literal](lexer::TokenKind::Literal).
22//!
23//! Example:
24//!
25//! | YAMD | HTML equivalent |
26//! |-----------|-----------------|
27//! | `\**foo**`|`<p>**foo**</p>` |
28//!
29//! ## Precedence
30//!
31//! [CommonMark](https://spec.commonmark.org/0.31.2/#precedence) defines container blocks and leaf
32//! blocks. And that container block indicator has higher precedence. YAMD does not discriminate by
33//! block type, every node (block) is the same. In practice, there are no additional rules to encode
34//! and remember.
35//!
36//! Example:
37//!
38//! | YAMD | HTML equivalent |
39//! |-----------------------|-----------------------------------------------|
40//! | ``- `one\n- two` `` | `<ol><li><code>one\n- two</code></li></ol>` |
41//!
42//!
43//! If you want to have two [ListItem](nodes::ListItem)'s use escaping:
44//!
45//! | YAMD | HTML equivalent |
46//! |---------------------------|-------------------------------------------|
47//! | ``- \`one\n- two\` `` | ``<ol><li>`one</li><li>two`</li><ol>`` |
48//!
49//! The reasoning is that those kind issues can be caught with tooling like linters/lsp. That tooling
50//! does not exist yet.
51//!
52//! ## Nodes
53//!
54//! List of supported [nodes] and their formatting. The best starting point is [YAMD](nodes::Yamd).
55//!
56//! # MSRV
57//!
58//! YAMD minimal supported Rust version is 1.80.0 due to [Option::take_if] usage
59
60#[deny(missing_docs, rustdoc::broken_intra_doc_links)]
61pub mod lexer;
62pub mod nodes;
63mod parser;
64
65#[doc(inline)]
66pub use nodes::Yamd;
67use parser::{yamd, Parser};
68
69/// Deserialize a string into a Yamd struct
70/// # Example
71/// ```
72/// use yamd::deserialize;
73/// let input = "# header";
74/// let yamd = deserialize(input);
75/// ```
76pub fn deserialize(str: &str) -> Yamd {
77 let mut p = Parser::new(str);
78 yamd(&mut p, |_| false)
79}
80
81#[cfg(test)]
82mod tests {
83 use pretty_assertions::assert_eq;
84
85 use crate::{
86 deserialize,
87 nodes::{Anchor, Heading, Paragraph, Yamd},
88 };
89
90 #[test]
91 fn test_deserialize() {
92 let input = "# header";
93 let expected = Yamd::new(
94 None,
95 vec![Heading::new(1, vec![String::from("header").into()]).into()],
96 );
97 let actual = deserialize(input);
98 assert_eq!(expected, actual);
99 }
100
101 #[test]
102 fn deserialize_text_containing_utf8() {
103 let input = "## 🤔\n\n[link 😉](url)";
104 let expected = Yamd::new(
105 None,
106 vec![
107 Heading::new(2, vec![String::from("🤔").into()]).into(),
108 Paragraph::new(vec![Anchor::new("link 😉", "url").into()]).into(),
109 ],
110 );
111 let actual = deserialize(input);
112 assert_eq!(expected, actual);
113 }
114}