1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum NodeKind {
8 Document,
10 Section,
11 Paragraph,
12 Heading { level: u8 },
13 FencedCodeBlock,
14 IndentedCodeBlock,
15 BlockQuote,
16 BulletList,
17 OrderedList,
18 ListItem,
19 ThematicBreak,
20 HtmlBlock,
21 Table,
22 TableRow,
23 TableHeader,
24 TableDelimiterRow,
25 LinkReferenceDefinition,
26 FrontMatter,
27
28 Emphasis, StrongEmphasis, InlineCode, Link, Image, Strikethrough, HardLineBreak,
36 SoftLineBreak,
37
38 InfoString, CodeFenceContent, Inline, Text, Unknown,
46}
47
48impl NodeKind {
49 pub fn from_ts_kind(kind: &str) -> Self {
51 match kind {
52 "document" => NodeKind::Document,
53 "section" => NodeKind::Section,
54 "paragraph" => NodeKind::Paragraph,
55 "atx_heading" | "setext_heading" => NodeKind::Heading { level: 0 }, "fenced_code_block" => NodeKind::FencedCodeBlock,
57 "indented_code_block" => NodeKind::IndentedCodeBlock,
58 "block_quote" => NodeKind::BlockQuote,
59 "thematic_break" => NodeKind::ThematicBreak,
60 "html_block" => NodeKind::HtmlBlock,
61 "list" => NodeKind::BulletList, "list_item" => NodeKind::ListItem,
63 "pipe_table" => NodeKind::Table,
64 "pipe_table_row" => NodeKind::TableRow,
65 "pipe_table_header" => NodeKind::TableHeader,
66 "pipe_table_delimiter_row" => NodeKind::TableDelimiterRow,
67 "link_reference_definition" => NodeKind::LinkReferenceDefinition,
68 "minus_metadata" | "plus_metadata" => NodeKind::FrontMatter,
69
70 "emphasis" => NodeKind::Emphasis,
71 "strong_emphasis" => NodeKind::StrongEmphasis,
72 "code_span" => NodeKind::InlineCode,
73 "link" | "full_reference_link" | "collapsed_reference_link"
74 | "shortcut_link" | "autolink" | "uri_autolink" => NodeKind::Link,
75 "image" => NodeKind::Image,
76 "strikethrough" => NodeKind::Strikethrough,
77 "hard_line_break" => NodeKind::HardLineBreak,
78 "soft_line_break" => NodeKind::SoftLineBreak,
79
80 "info_string" => NodeKind::InfoString,
81 "code_fence_content" => NodeKind::CodeFenceContent,
82
83 "inline" => NodeKind::Inline,
84
85 _ => NodeKind::Unknown,
86 }
87 }
88
89 pub fn is_block(&self) -> bool {
91 matches!(
92 self,
93 NodeKind::Document
94 | NodeKind::Section
95 | NodeKind::Paragraph
96 | NodeKind::Heading { .. }
97 | NodeKind::FencedCodeBlock
98 | NodeKind::IndentedCodeBlock
99 | NodeKind::BlockQuote
100 | NodeKind::BulletList
101 | NodeKind::OrderedList
102 | NodeKind::ListItem
103 | NodeKind::ThematicBreak
104 | NodeKind::HtmlBlock
105 | NodeKind::Table
106 | NodeKind::LinkReferenceDefinition
107 | NodeKind::FrontMatter
108 )
109 }
110
111 pub fn is_inline(&self) -> bool {
113 matches!(
114 self,
115 NodeKind::Emphasis
116 | NodeKind::StrongEmphasis
117 | NodeKind::InlineCode
118 | NodeKind::Link
119 | NodeKind::Image
120 | NodeKind::Strikethrough
121 | NodeKind::HardLineBreak
122 | NodeKind::SoftLineBreak
123 | NodeKind::Inline
124 | NodeKind::Text
125 )
126 }
127
128 pub fn is_container(&self) -> bool {
130 matches!(
131 self,
132 NodeKind::Document
133 | NodeKind::Section
134 | NodeKind::BlockQuote
135 | NodeKind::BulletList
136 | NodeKind::OrderedList
137 | NodeKind::ListItem
138 )
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn classify_block_nodes() {
148 assert!(NodeKind::from_ts_kind("paragraph").is_block());
149 assert!(NodeKind::from_ts_kind("atx_heading").is_block());
150 assert!(NodeKind::from_ts_kind("fenced_code_block").is_block());
151 assert!(NodeKind::from_ts_kind("list").is_block());
152 }
153
154 #[test]
155 fn classify_inline_nodes() {
156 assert!(NodeKind::from_ts_kind("emphasis").is_inline());
157 assert!(NodeKind::from_ts_kind("strong_emphasis").is_inline());
158 assert!(NodeKind::from_ts_kind("code_span").is_inline());
159 assert!(NodeKind::from_ts_kind("link").is_inline());
160 }
161
162 #[test]
163 fn containers() {
164 assert!(NodeKind::from_ts_kind("block_quote").is_container());
165 assert!(NodeKind::from_ts_kind("list").is_container());
166 assert!(!NodeKind::from_ts_kind("paragraph").is_container());
167 }
168}