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 Html(Html),
35 FootnoteRef(FootnoteRef),
36 FootnoteDef(FootnoteDef),
37}
38
39impl Node {
40 pub fn children_of(node: &Node) -> &[Node] {
41 match node {
42 Node::Document(n) => &n.children,
43 Node::Heading(n) => &n.children,
44 Node::Paragraph(n) => &n.children,
45 Node::Bold(n) | Node::Italic(n) | Node::Strikethrough(n) => &n.children,
46 Node::Link(n) => &n.children,
47 Node::Blockquote(n) => &n.children,
48 Node::List(n) => &n.children,
49 Node::ListItem(n) => &n.children,
50 Node::TaskListItem(n) => &n.children,
51 Node::TableCell(n) => &n.children,
52 Node::JsxElement(n) => &n.children,
53 Node::JsxFragment(n) => &n.children,
54 Node::FootnoteDef(n) => &n.children,
55 _ => &[],
56 }
57 }
58
59 pub fn children_of_mut(node: &mut Node) -> Option<&mut Vec<Node>> {
60 match node {
61 Node::Document(n) => Some(&mut n.children),
62 Node::Heading(n) => Some(&mut n.children),
63 Node::Paragraph(n) => Some(&mut n.children),
64 Node::Bold(n) | Node::Italic(n) | Node::Strikethrough(n) => Some(&mut n.children),
65 Node::Link(n) => Some(&mut n.children),
66 Node::Blockquote(n) => Some(&mut n.children),
67 Node::List(n) => Some(&mut n.children),
68 Node::ListItem(n) => Some(&mut n.children),
69 Node::TaskListItem(n) => Some(&mut n.children),
70 Node::TableCell(n) => Some(&mut n.children),
71 Node::JsxElement(n) => Some(&mut n.children),
72 Node::JsxFragment(n) => Some(&mut n.children),
73 Node::FootnoteDef(n) => Some(&mut n.children),
74 _ => None,
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
80pub struct Document {
81 pub children: Vec<Node>,
82 pub span: Span,
83}
84
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct Frontmatter {
87 pub raw: String,
88 pub span: Span,
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
92pub struct Import {
93 pub raw: String,
94 pub span: Span,
95}
96
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
98pub struct Export {
99 pub raw: String,
100 pub span: Span,
101}
102
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104pub struct Heading {
105 pub level: u8,
106 pub children: Vec<Node>,
107 pub span: Span,
108 #[serde(default)]
111 pub id: Option<String>,
112}
113
114impl Heading {
115 pub fn slug(&self) -> String {
118 if let Some(id) = &self.id {
119 return id.clone();
120 }
121 crate::slugger::github_slugify(&Self::plain_text(&self.children))
122 }
123
124 pub fn plain_text(nodes: &[Node]) -> String {
127 let mut s = String::new();
128 for n in nodes {
129 match n {
130 Node::Text(t) => s.push_str(&t.value),
131 Node::Bold(i) | Node::Italic(i) | Node::Strikethrough(i) => s.push_str(&Self::plain_text(&i.children)),
132 Node::Link(l) => s.push_str(&Self::plain_text(&l.children)),
133 Node::InlineCode(c) => s.push_str(&c.value),
134 _ => {},
135 }
136 }
137 s.trim().to_string()
138 }
139}
140
141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
142pub struct Paragraph {
143 pub children: Vec<Node>,
144 pub span: Span,
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub struct Text {
149 pub value: String,
150 pub span: Span,
151}
152
153#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
154pub struct Inline {
155 pub children: Vec<Node>,
156 pub span: Span,
157}
158
159#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
160pub struct InlineCode {
161 pub value: String,
162 pub span: Span,
163}
164
165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
166pub struct CodeBlock {
167 pub lang: Option<String>,
168 pub meta: Option<String>,
169 pub value: String,
170 pub span: Span,
171}
172
173#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
174pub struct Link {
175 pub href: String,
176 pub title: Option<String>,
177 pub children: Vec<Node>,
178 pub span: Span,
179}
180
181#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
182pub struct Image {
183 pub src: String,
184 pub alt: String,
185 pub title: Option<String>,
186 pub span: Span,
187}
188
189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct HorizontalRule {
191 pub span: Span,
192}
193
194#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
195pub struct Blockquote {
196 pub children: Vec<Node>,
197 pub span: Span,
198}
199
200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub struct List {
202 pub ordered: bool,
203 pub start: Option<u32>,
204 pub children: Vec<Node>,
206 pub span: Span,
207}
208
209#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
210pub struct ListItem {
211 pub children: Vec<Node>,
212 pub span: Span,
213}
214
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
216pub struct TaskListItem {
217 pub checked: bool,
218 pub children: Vec<Node>,
219 pub span: Span,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
223pub enum TableAlign {
224 None,
225 Left,
226 Right,
227 Center,
228}
229
230#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
231pub struct Table {
232 pub align: Vec<TableAlign>,
233 pub children: Vec<TableRow>,
234 pub span: Span,
235}
236
237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
238pub struct TableRow {
239 pub cells: Vec<TableCell>,
240 pub span: Span,
241}
242
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244pub struct TableCell {
245 pub children: Vec<Node>,
246 pub span: Span,
247}
248
249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
250pub struct JsxElement {
251 pub name: String,
252 pub attrs: Vec<crate::ast::JsxAttr>,
253 pub children: Vec<Node>,
254 pub span: Span,
255}
256
257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
258pub struct JsxSelfClosing {
259 pub name: String,
260 pub attrs: Vec<crate::ast::JsxAttr>,
261 pub span: Span,
262}
263
264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
265pub struct JsxFragment {
266 pub children: Vec<Node>,
267 pub span: Span,
268}
269
270#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
271pub struct JsxExpression {
272 pub value: String,
273 pub span: Span,
274}
275
276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
277pub struct BreakNode {
278 pub span: Span,
279}
280
281#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
283pub struct Html {
284 pub value: String,
285 pub span: Span,
286}
287
288#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
290pub struct FootnoteRef {
291 pub id: String,
292 pub span: Span,
293}
294
295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
298pub struct FootnoteDef {
299 pub id: String,
300 pub children: Vec<Node>,
301 pub span: Span,
302}