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)]
113 pub id: Option<String>,
114}
115
116impl Heading {
117 pub fn slug(&self) -> String {
121 if let Some(id) = &self.id {
122 return id.clone();
123 }
124 crate::slugger::github_slugify(&Self::plain_text(&self.children))
125 }
126
127 pub fn plain_text(nodes: &[Node]) -> String {
130 let mut s = String::new();
131 for n in nodes {
132 match n {
133 Node::Text(t) => s.push_str(&t.value),
134 Node::Bold(i) | Node::Italic(i) | Node::Strikethrough(i) => s.push_str(&Self::plain_text(&i.children)),
135 Node::Link(l) => s.push_str(&Self::plain_text(&l.children)),
136 Node::InlineCode(c) => s.push_str(&c.value),
137 _ => {},
138 }
139 }
140 s.trim().to_string()
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub struct Paragraph {
146 pub children: Vec<Node>,
147 pub span: Span,
148}
149
150#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151pub struct Text {
152 pub value: String,
153 pub span: Span,
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157pub struct Inline {
158 pub children: Vec<Node>,
159 pub span: Span,
160}
161
162#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
163pub struct InlineCode {
164 pub value: String,
165 pub span: Span,
166}
167
168#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
169pub struct CodeBlock {
170 pub lang: Option<String>,
171 pub meta: Option<String>,
172 pub value: String,
173 pub span: Span,
174}
175
176#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
177pub struct Link {
178 pub href: String,
179 pub title: Option<String>,
180 pub children: Vec<Node>,
181 pub span: Span,
182}
183
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub struct Image {
186 pub src: String,
187 pub alt: String,
188 pub title: Option<String>,
189 pub span: Span,
190}
191
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193pub struct HorizontalRule {
194 pub span: Span,
195}
196
197#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
198pub struct Blockquote {
199 pub children: Vec<Node>,
200 pub span: Span,
201}
202
203#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204pub struct List {
205 pub ordered: bool,
206 pub start: Option<u32>,
207 pub children: Vec<Node>,
209 pub span: Span,
210}
211
212#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213pub struct ListItem {
214 pub children: Vec<Node>,
215 pub span: Span,
216}
217
218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
219pub struct TaskListItem {
220 pub checked: bool,
221 pub children: Vec<Node>,
222 pub span: Span,
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
226pub enum TableAlign {
227 None,
228 Left,
229 Right,
230 Center,
231}
232
233#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234pub struct Table {
235 pub align: Vec<TableAlign>,
236 pub children: Vec<TableRow>,
237 pub span: Span,
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
241pub struct TableRow {
242 pub cells: Vec<TableCell>,
243 pub span: Span,
244}
245
246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
247pub struct TableCell {
248 pub children: Vec<Node>,
249 pub span: Span,
250}
251
252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
253pub struct JsxElement {
254 pub name: String,
255 pub attrs: Vec<crate::ast::JsxAttr>,
256 pub children: Vec<Node>,
257 pub span: Span,
258}
259
260#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
261pub struct JsxSelfClosing {
262 pub name: String,
263 pub attrs: Vec<crate::ast::JsxAttr>,
264 pub span: Span,
265}
266
267#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
268pub struct JsxFragment {
269 pub children: Vec<Node>,
270 pub span: Span,
271}
272
273#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274pub struct JsxExpression {
275 pub value: String,
276 pub span: Span,
277}
278
279#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
280pub struct BreakNode {
281 pub span: Span,
282}
283
284#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
288pub struct Html {
289 pub value: String,
290 pub span: Span,
291}
292
293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
295pub struct FootnoteRef {
296 pub id: String,
297 pub span: Span,
298}
299
300#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
303pub struct FootnoteDef {
304 pub id: String,
305 pub children: Vec<Node>,
306 pub span: Span,
307}