Skip to main content

textlane_core/models/
hast.rs

1use crate::ArenaVec;
2use crate::models::data::Data;
3use crate::models::mdx::{MdxExpression, MdxJsxElement, MdxjsEsm};
4use crate::models::position::Position;
5
6/// A hast node.
7#[derive(Debug, PartialEq)]
8pub enum Node<'a> {
9    Root(Root<'a>),
10    Element(Element<'a>),
11    Text(Text<'a>),
12    Comment(Comment<'a>),
13    Doctype(Doctype<'a>),
14    Raw(Raw<'a>),
15    Unknown(Unknown<'a>),
16    MdxJsxFlowElement(MdxJsxElement<'a, Node<'a>>),
17    MdxJsxTextElement(MdxJsxElement<'a, Node<'a>>),
18    MdxFlowExpression(MdxExpression<'a>),
19    MdxTextExpression(MdxExpression<'a>),
20    MdxjsEsm(MdxjsEsm<'a>),
21}
22
23/// The document or fragment.
24#[derive(Debug, PartialEq)]
25pub struct Root<'a> {
26    pub children: ArenaVec<'a, Node<'a>>,
27    pub position: Option<Position<'a>>,
28    /// unist's `data`, when the node carries any.
29    pub data: Option<&'a Data<'a>>,
30    /// `data.quirksMode`, set by the HTML parser: whether the document is in quirks mode.
31    pub quirks_mode: Option<bool>,
32}
33
34/// An element.
35#[derive(Debug, PartialEq)]
36pub struct Element<'a> {
37    pub tag_name: &'a str,
38    pub properties: ArenaVec<'a, Property<'a>>,
39    pub children: ArenaVec<'a, Node<'a>>,
40    pub position: Option<Position<'a>>,
41    /// unist's `data`, when the node carries any.
42    pub data: Option<&'a Data<'a>>,
43    /// A `template`'s contents, which hast keeps out of its children.
44    pub content: Option<&'a Root<'a>>,
45}
46
47/// One property of an element, by its hast name (`className`, not `class`).
48#[derive(Debug, PartialEq)]
49pub struct Property<'a> {
50    pub name: &'a str,
51    pub value: PropertyValue<'a>,
52}
53
54/// A property value as hast allows it.
55#[derive(Debug, PartialEq)]
56pub enum PropertyValue<'a> {
57    Null,
58    Boolean(bool),
59    Number(f64),
60    String(&'a str),
61    List(ArenaVec<'a, PropertyItem<'a>>),
62}
63
64/// One item of a list property value, such as one class name.
65#[derive(Debug, PartialEq)]
66pub enum PropertyItem<'a> {
67    Number(f64),
68    String(&'a str),
69}
70
71/// Text.
72#[derive(Debug, PartialEq)]
73pub struct Text<'a> {
74    pub value: &'a str,
75    pub position: Option<Position<'a>>,
76    /// unist's `data`, when the node carries any.
77    pub data: Option<&'a Data<'a>>,
78}
79
80/// A comment.
81#[derive(Debug, PartialEq)]
82pub struct Comment<'a> {
83    pub value: &'a str,
84    pub position: Option<Position<'a>>,
85    /// unist's `data`, when the node carries any.
86    pub data: Option<&'a Data<'a>>,
87}
88
89/// Raw HTML, written as it is only when dangerous HTML is allowed.
90#[derive(Debug, PartialEq)]
91pub struct Raw<'a> {
92    pub value: &'a str,
93    pub position: Option<Position<'a>>,
94    /// unist's `data`, when the node carries any.
95    pub data: Option<&'a Data<'a>>,
96}
97
98/// A doctype.
99#[derive(Debug, PartialEq)]
100pub struct Doctype<'a> {
101    pub position: Option<Position<'a>>,
102    /// unist's `data`, when the node carries any.
103    pub data: Option<&'a Data<'a>>,
104}
105
106/// A node of a type hast does not define, such as one `md.toHtml` passes through.
107#[derive(Debug, PartialEq)]
108pub struct Unknown<'a> {
109    /// The node's `type`.
110    pub kind: &'a str,
111    /// Its fields besides `type`, `children`, `position` and `data`, in order.
112    pub fields: &'a [(&'a str, Data<'a>)],
113    /// Its children, when it is a parent.
114    pub children: Option<ArenaVec<'a, Node<'a>>>,
115    pub position: Option<Position<'a>>,
116    /// unist's `data`, when the node carries any.
117    pub data: Option<&'a Data<'a>>,
118}
119
120impl<'a> Node<'a> {
121    /// The node's unist `data`, when it carries any.
122    pub fn data(&self) -> Option<&'a Data<'a>> {
123        match self {
124            Node::Root(node) => node.data,
125            Node::Element(node) => node.data,
126            Node::Text(node) => node.data,
127            Node::Comment(node) => node.data,
128            Node::Doctype(node) => node.data,
129            Node::Raw(node) => node.data,
130            Node::Unknown(node) => node.data,
131            Node::MdxJsxFlowElement(node) | Node::MdxJsxTextElement(node) => node.data,
132            Node::MdxFlowExpression(node) | Node::MdxTextExpression(node) => node.data,
133            Node::MdxjsEsm(node) => node.data,
134        }
135    }
136
137    pub fn position(&self) -> Option<&Position<'a>> {
138        match self {
139            Node::Root(node) => node.position.as_ref(),
140            Node::Element(node) => node.position.as_ref(),
141            Node::Text(node) => node.position.as_ref(),
142            Node::Comment(node) => node.position.as_ref(),
143            Node::Doctype(node) => node.position.as_ref(),
144            Node::Raw(node) => node.position.as_ref(),
145            Node::Unknown(node) => node.position.as_ref(),
146            Node::MdxJsxFlowElement(node) | Node::MdxJsxTextElement(node) => {
147                node.position.as_ref()
148            }
149            Node::MdxFlowExpression(node) | Node::MdxTextExpression(node) => {
150                node.position.as_ref()
151            }
152            Node::MdxjsEsm(node) => node.position.as_ref(),
153        }
154    }
155}