cmark_writer/
ast.rs

1//! Abstract Syntax Tree for CommonMark document structure.
2//!
3//! This module defines various node types for representing CommonMark documents,
4//! including headings, paragraphs, lists, code blocks, etc.
5
6/// Main node type, representing an element in a CommonMark document
7#[derive(Debug, Clone, PartialEq)]
8pub enum Node {
9    // Block-level nodes
10    /// Root document node, contains child nodes
11    Document(Vec<Node>),
12
13    /// Heading, contains level (1-6) and inline content
14    Heading {
15        /// Heading level, 1-6
16        level: u8,
17        /// Heading content, containing inline elements
18        content: Vec<Node>,
19    },
20
21    /// Paragraph node, containing inline elements
22    Paragraph(Vec<Node>),
23
24    /// Block quote, containing any block-level elements
25    BlockQuote(Vec<Node>),
26
27    /// Code block, containing optional language identifier and content
28    CodeBlock {
29        /// Optional language identifier
30        language: Option<String>,
31        /// Code content
32        content: String,
33    },
34
35    /// Unordered list, containing list items
36    UnorderedList(Vec<ListItem>),
37
38    /// Ordered list, containing starting number and list items
39    OrderedList {
40        /// List starting number
41        start: u32,
42        /// List items
43        items: Vec<ListItem>,
44    },
45
46    /// Thematic break (horizontal rule)
47    ThematicBreak,
48
49    /// Table
50    Table {
51        /// Header cells
52        headers: Vec<Node>,
53        /// Table rows, each row containing multiple cells
54        rows: Vec<Vec<Node>>,
55        /// Column alignments
56        alignments: Vec<Alignment>,
57    },
58
59    /// HTML block
60    HtmlBlock(String),
61
62    // Inline nodes
63    /// Plain text
64    Text(String),
65
66    /// Emphasis (italic)
67    Emphasis(Vec<Node>),
68
69    /// Strong emphasis (bold)
70    Strong(Vec<Node>),
71
72    /// Strikethrough
73    Strike(Vec<Node>),
74
75    /// Inline code
76    InlineCode(String),
77
78    /// Link
79    Link {
80        /// Link URL
81        url: String,
82        /// Optional link title
83        title: Option<String>,
84        /// Link text
85        content: Vec<Node>,
86    },
87
88    /// Image
89    Image {
90        /// Image URL
91        url: String,
92        /// Optional image title
93        title: Option<String>,
94        /// Alternative text, containing inline elements
95        alt: Vec<Node>,
96    },
97
98    /// Inline element collection, without formatting and line breaks
99    InlineContainer(Vec<Node>),
100
101    /// HTML inline element
102    HtmlElement(HtmlElement),
103
104    /// Soft break (single line break)
105    SoftBreak,
106
107    /// Hard break (two spaces followed by a line break, or backslash followed by a line break)
108    HardBreak,
109}
110
111/// List item type
112#[derive(Debug, Clone, PartialEq)]
113pub enum ListItem {
114    /// Unordered list item
115    Unordered {
116        /// List item content, containing one or more block-level elements
117        content: Vec<Node>,
118    },
119    /// Ordered list item
120    Ordered {
121        /// Optional item number for ordered lists, allowing manual numbering
122        number: Option<u32>,
123        /// List item content, containing one or more block-level elements
124        content: Vec<Node>,
125    },
126}
127
128/// Table column alignment
129#[derive(Debug, Clone, Copy, PartialEq)]
130pub enum Alignment {
131    /// No specific alignment
132    None,
133    /// Left alignment
134    Left,
135    /// Center alignment
136    Center,
137    /// Right alignment
138    Right,
139}
140
141/// Represents an HTML attribute, containing name and value
142#[derive(Debug, Clone, PartialEq)]
143pub struct HtmlAttribute {
144    /// Attribute name
145    pub name: String,
146    /// Attribute value
147    pub value: String,
148}
149
150/// Represents an HTML element, containing tag name, attributes, and child nodes
151#[derive(Debug, Clone, PartialEq)]
152pub struct HtmlElement {
153    /// Element tag name
154    pub tag: String,
155    /// Element attributes
156    pub attributes: Vec<HtmlAttribute>,
157    /// Element child nodes (can only contain inline nodes)
158    pub children: Vec<Node>,
159    /// Whether it's a self-closing tag (e.g. <img />)
160    pub self_closing: bool,
161}
162
163impl Node {
164    /// Check if a node is a block-level node
165    pub fn is_block(&self) -> bool {
166        matches!(
167            self,
168            Node::Document(_)
169                | Node::Heading { .. }
170                | Node::Paragraph(_)
171                | Node::BlockQuote(_)
172                | Node::CodeBlock { .. }
173                | Node::UnorderedList(_)
174                | Node::OrderedList { .. }
175                | Node::ThematicBreak
176                | Node::Table { .. }
177                | Node::HtmlBlock(_)
178        )
179    }
180
181    /// Check if a node is an inline node
182    pub fn is_inline(&self) -> bool {
183        matches!(
184            self,
185            Node::Text(_)
186                | Node::Emphasis(_)
187                | Node::Strong(_)
188                | Node::Strike(_)
189                | Node::InlineCode(_)
190                | Node::Link { .. }
191                | Node::Image { .. }
192                | Node::InlineContainer(_)
193                | Node::HtmlElement(_)
194                | Node::SoftBreak
195                | Node::HardBreak
196        )
197    }
198}