Skip to main content

dmc_parser/ast/
node.rs

1use duck_diagnostic::Span;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub enum Node {
6  Document(Document),
7  Frontmatter(Frontmatter),
8  Import(Import),
9  Export(Export),
10  Heading(Heading),
11  Paragraph(Paragraph),
12  Text(Text),
13  Bold(Inline),
14  Italic(Inline),
15  Strikethrough(Inline),
16  InlineCode(InlineCode),
17  CodeBlock(CodeBlock),
18  Link(Link),
19  Image(Image),
20  HorizontalRule(HorizontalRule),
21  Blockquote(Blockquote),
22  List(List),
23  ListItem(ListItem),
24  TaskListItem(TaskListItem),
25  Table(Table),
26  TableRow(TableRow),
27  TableCell(TableCell),
28  JsxElement(JsxElement),
29  JsxSelfClosing(JsxSelfClosing),
30  JsxFragment(JsxFragment),
31  JsxExpression(JsxExpression),
32  HardBreak(BreakNode),
33  SoftBreak(BreakNode),
34}
35
36impl Node {
37  pub fn children_of(node: &Node) -> &[Node] {
38    match node {
39      Node::Document(n) => &n.children,
40      Node::Heading(n) => &n.children,
41      Node::Paragraph(n) => &n.children,
42      Node::Bold(n) | Node::Italic(n) | Node::Strikethrough(n) => &n.children,
43      Node::Link(n) => &n.children,
44      Node::Blockquote(n) => &n.children,
45      Node::List(n) => &n.children,
46      Node::ListItem(n) => &n.children,
47      Node::TaskListItem(n) => &n.children,
48      Node::TableCell(n) => &n.children,
49      Node::JsxElement(n) => &n.children,
50      Node::JsxFragment(n) => &n.children,
51      _ => &[],
52    }
53  }
54
55  pub fn children_of_mut(node: &mut Node) -> Option<&mut Vec<Node>> {
56    match node {
57      Node::Document(n) => Some(&mut n.children),
58      Node::Heading(n) => Some(&mut n.children),
59      Node::Paragraph(n) => Some(&mut n.children),
60      Node::Bold(n) | Node::Italic(n) | Node::Strikethrough(n) => Some(&mut n.children),
61      Node::Link(n) => Some(&mut n.children),
62      Node::Blockquote(n) => Some(&mut n.children),
63      Node::List(n) => Some(&mut n.children),
64      Node::ListItem(n) => Some(&mut n.children),
65      Node::TaskListItem(n) => Some(&mut n.children),
66      Node::TableCell(n) => Some(&mut n.children),
67      Node::JsxElement(n) => Some(&mut n.children),
68      Node::JsxFragment(n) => Some(&mut n.children),
69      _ => None,
70    }
71  }
72}
73
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75pub struct Document {
76  pub children: Vec<Node>,
77  pub span: Span,
78}
79
80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
81pub struct Frontmatter {
82  pub raw: String,
83  pub span: Span,
84}
85
86#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
87pub struct Import {
88  pub raw: String,
89  pub span: Span,
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct Export {
94  pub raw: String,
95  pub span: Span,
96}
97
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub struct Heading {
100  pub level: u8,
101  pub children: Vec<Node>,
102  pub span: Span,
103}
104
105impl Heading {
106  /// URL-anchor slug from the heading's plain-text content. Recomputed each
107  /// call; the heading owns no derived state.
108  pub fn slug(&self) -> String {
109    slug::slugify(Self::plain_text(&self.children))
110  }
111
112  /// Flatten inline nodes to bare text. Recurses through emphasis and link
113  /// wrappers but skips JSX and images.
114  fn plain_text(nodes: &[Node]) -> String {
115    let mut s = String::new();
116    for n in nodes {
117      match n {
118        Node::Text(t) => s.push_str(&t.value),
119        Node::Bold(i) | Node::Italic(i) | Node::Strikethrough(i) => s.push_str(&Self::plain_text(&i.children)),
120        Node::Link(l) => s.push_str(&Self::plain_text(&l.children)),
121        Node::InlineCode(c) => s.push_str(&c.value),
122        _ => {},
123      }
124    }
125    s.trim().to_string()
126  }
127}
128
129#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
130pub struct Paragraph {
131  pub children: Vec<Node>,
132  pub span: Span,
133}
134
135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct Text {
137  pub value: String,
138  pub span: Span,
139}
140
141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
142pub struct Inline {
143  pub children: Vec<Node>,
144  pub span: Span,
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub struct InlineCode {
149  pub value: String,
150  pub span: Span,
151}
152
153#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
154pub struct CodeBlock {
155  pub lang: Option<String>,
156  pub meta: Option<String>,
157  pub value: String,
158  pub span: Span,
159}
160
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
162pub struct Link {
163  pub href: String,
164  pub title: Option<String>,
165  pub children: Vec<Node>,
166  pub span: Span,
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct Image {
171  pub src: String,
172  pub alt: String,
173  pub title: Option<String>,
174  pub span: Span,
175}
176
177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
178pub struct HorizontalRule {
179  pub span: Span,
180}
181
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct Blockquote {
184  pub children: Vec<Node>,
185  pub span: Span,
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
189pub struct List {
190  pub ordered: bool,
191  pub start: Option<u32>,
192  /// Children are `ListItem` or `TaskListItem` `Node` variants.
193  pub children: Vec<Node>,
194  pub span: Span,
195}
196
197#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
198pub struct ListItem {
199  pub children: Vec<Node>,
200  pub span: Span,
201}
202
203#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204pub struct TaskListItem {
205  pub checked: bool,
206  pub children: Vec<Node>,
207  pub span: Span,
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
211pub enum TableAlign {
212  None,
213  Left,
214  Right,
215  Center,
216}
217
218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
219pub struct Table {
220  pub align: Vec<TableAlign>,
221  pub children: Vec<TableRow>,
222  pub span: Span,
223}
224
225#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
226pub struct TableRow {
227  pub cells: Vec<TableCell>,
228  pub span: Span,
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
232pub struct TableCell {
233  pub children: Vec<Node>,
234  pub span: Span,
235}
236
237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
238pub struct JsxElement {
239  pub name: String,
240  pub attrs: Vec<crate::ast::JsxAttr>,
241  pub children: Vec<Node>,
242  pub span: Span,
243}
244
245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
246pub struct JsxSelfClosing {
247  pub name: String,
248  pub attrs: Vec<crate::ast::JsxAttr>,
249  pub span: Span,
250}
251
252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
253pub struct JsxFragment {
254  pub children: Vec<Node>,
255  pub span: Span,
256}
257
258#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
259pub struct JsxExpression {
260  pub value: String,
261  pub span: Span,
262}
263
264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
265pub struct BreakNode {
266  pub span: Span,
267}