panache_parser/syntax/
alerts.rs1use super::ast::support;
4use super::{AstChildren, AstNode, PanacheLanguage, Paragraph, SyntaxKind, SyntaxNode};
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct Alert(SyntaxNode);
8
9impl AstNode for Alert {
10 type Language = PanacheLanguage;
11
12 fn can_cast(kind: SyntaxKind) -> bool {
13 kind == SyntaxKind::ALERT
14 }
15
16 fn cast(syntax: SyntaxNode) -> Option<Self> {
17 Self::can_cast(syntax.kind()).then(|| Self(syntax))
18 }
19
20 fn syntax(&self) -> &SyntaxNode {
21 &self.0
22 }
23}
24
25impl Alert {
26 pub fn marker(&self) -> Option<String> {
27 self.0
28 .children_with_tokens()
29 .filter_map(|child| child.into_token())
30 .find(|token| token.kind() == SyntaxKind::ALERT_MARKER)
31 .map(|token| token.text().to_string())
32 }
33
34 pub fn paragraphs(&self) -> AstChildren<Paragraph> {
35 support::children(&self.0)
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use crate::options::{Extensions, Flavor, ParserOptions};
43 use crate::parse;
44
45 #[test]
46 fn alert_wrapper_extracts_marker_and_paragraphs() {
47 let mut extensions = Extensions::for_flavor(Flavor::Gfm);
48 extensions.alerts = true;
49 let config = ParserOptions {
50 flavor: Flavor::Gfm,
51 extensions,
52 ..Default::default()
53 };
54 let tree = parse("> [!NOTE]\n> Heads up\n> More context\n", Some(config));
55
56 let alert = tree.descendants().find_map(Alert::cast).expect("alert");
57 assert_eq!(alert.marker().as_deref(), Some("[!NOTE]"));
58 let paragraphs = alert.paragraphs().collect::<Vec<_>>();
59 assert_eq!(paragraphs.len(), 1);
60 let text = paragraphs[0].syntax().text().to_string();
61 assert!(text.contains("Heads up"));
62 assert!(text.contains("More context"));
63 }
64}