Skip to main content

typst_batch/html/
node.rs

1//! HTML node wrapper.
2
3use super::{HtmlElement, HtmlFrame};
4
5/// An HTML node (element, text, or frame).
6///
7/// Use `kind()` to determine the node type and access its data.
8#[derive(Debug, Clone, Copy)]
9pub struct HtmlNode<'a>(pub(crate) &'a typst_html::HtmlNode);
10
11/// The kind of an HTML node.
12#[derive(Debug, Clone, Copy)]
13pub enum NodeKind<'a> {
14    /// An HTML element with tag, attributes, and children.
15    Element(HtmlElement<'a>),
16    /// Plain text content.
17    Text(&'a str),
18    /// A frame that should be rendered as SVG.
19    Frame(HtmlFrame<'a>),
20    /// An introspection tag (usually ignored during conversion).
21    Tag,
22}
23
24impl<'a> HtmlNode<'a> {
25    /// Get the kind of this node.
26    ///
27    /// # Example
28    ///
29    /// ```ignore
30    /// match node.kind() {
31    ///     NodeKind::Element(elem) => {
32    ///         println!("Element: {}", elem.tag());
33    ///     }
34    ///     NodeKind::Text(text) => {
35    ///         println!("Text: {}", text);
36    ///     }
37    ///     NodeKind::Frame(frame) => {
38    ///         #[cfg(feature = "svg")]
39    ///         let svg = frame.to_svg(&doc);
40    ///     }
41    ///     NodeKind::Tag => {
42    ///         // Introspection tag, usually ignored
43    ///     }
44    /// }
45    /// ```
46    #[inline]
47    pub fn kind(&self) -> NodeKind<'a> {
48        match self.0 {
49            typst_html::HtmlNode::Tag(_) => NodeKind::Tag,
50            typst_html::HtmlNode::Text(text, _span) => NodeKind::Text(text.as_str()),
51            typst_html::HtmlNode::Element(elem) => NodeKind::Element(HtmlElement(elem)),
52            typst_html::HtmlNode::Frame(frame) => NodeKind::Frame(HtmlFrame(frame)),
53        }
54    }
55
56    /// Try to get this node as an element.
57    #[inline]
58    pub fn as_element(&self) -> Option<HtmlElement<'a>> {
59        match self.0 {
60            typst_html::HtmlNode::Element(elem) => Some(HtmlElement(elem)),
61            _ => None,
62        }
63    }
64
65    /// Try to get this node as text.
66    #[inline]
67    pub fn as_text(&self) -> Option<&'a str> {
68        match self.0 {
69            typst_html::HtmlNode::Text(text, _) => Some(text.as_str()),
70            _ => None,
71        }
72    }
73
74    /// Try to get this node as a frame.
75    #[inline]
76    pub fn as_frame(&self) -> Option<HtmlFrame<'a>> {
77        match self.0 {
78            typst_html::HtmlNode::Frame(frame) => Some(HtmlFrame(frame)),
79            _ => None,
80        }
81    }
82
83    /// Check if this is an element node.
84    #[inline]
85    pub fn is_element(&self) -> bool {
86        matches!(self.0, typst_html::HtmlNode::Element(_))
87    }
88
89    /// Check if this is a text node.
90    #[inline]
91    pub fn is_text(&self) -> bool {
92        matches!(self.0, typst_html::HtmlNode::Text(_, _))
93    }
94
95    /// Check if this is a frame node.
96    #[inline]
97    pub fn is_frame(&self) -> bool {
98        matches!(self.0, typst_html::HtmlNode::Frame(_))
99    }
100
101    /// Check if this is a tag node (introspection).
102    #[inline]
103    pub fn is_tag(&self) -> bool {
104        matches!(self.0, typst_html::HtmlNode::Tag(_))
105    }
106}