Skip to main content

coil_template/model/
dom.rs

1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum AttributeValue {
5    Static(String),
6    DynamicText(String),
7    DynamicExpression(TemplateExpression),
8}
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct AttributeNode {
12    pub(crate) name: String,
13    pub(crate) value: AttributeValue,
14}
15
16impl AttributeNode {
17    pub fn static_value(
18        name: impl Into<String>,
19        value: impl Into<String>,
20    ) -> Result<Self, TemplateModelError> {
21        Ok(Self {
22            name: validate_attribute_name(name.into())?,
23            value: AttributeValue::Static(value.into()),
24        })
25    }
26
27    pub fn dynamic_text(
28        name: impl Into<String>,
29        key: impl Into<String>,
30    ) -> Result<Self, TemplateModelError> {
31        Ok(Self {
32            name: validate_attribute_name(name.into())?,
33            value: AttributeValue::DynamicExpression(TemplateExpression::ModelKey(validate_token(
34                "render_key",
35                key.into(),
36            )?)),
37        })
38    }
39
40    pub fn dynamic_expression(
41        name: impl Into<String>,
42        expression: TemplateExpression,
43    ) -> Result<Self, TemplateModelError> {
44        Ok(Self {
45            name: validate_attribute_name(name.into())?,
46            value: AttributeValue::DynamicExpression(expression),
47        })
48    }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct ElementNode {
53    pub(crate) tag: String,
54    pub(crate) attributes: Vec<AttributeNode>,
55    pub(crate) children: Vec<Node>,
56}
57
58impl ElementNode {
59    pub fn new(tag: impl Into<String>, children: Vec<Node>) -> Result<Self, TemplateModelError> {
60        Ok(Self {
61            tag: validate_element_name(tag.into())?,
62            attributes: Vec::new(),
63            children,
64        })
65    }
66
67    pub fn with_attribute(mut self, attribute: AttributeNode) -> Self {
68        self.attributes.push(attribute);
69        self
70    }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct SlotNode {
75    pub(crate) name: SlotName,
76    pub(crate) fallback: Option<Vec<Node>>,
77}
78
79impl SlotNode {
80    pub fn new(name: SlotName) -> Self {
81        Self {
82            name,
83            fallback: None,
84        }
85    }
86
87    pub fn with_fallback(mut self, fallback: Vec<Node>) -> Self {
88        self.fallback = Some(fallback);
89        self
90    }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub enum TemplateExpression {
95    ModelKey(String),
96    LiteralText(String),
97    LiteralBool(bool),
98    AssetPath(String),
99    TranslationKey(String),
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct TemplateBinding {
104    pub(crate) key: String,
105    pub(crate) expression: TemplateExpression,
106}
107
108impl TemplateBinding {
109    pub fn new(
110        key: impl Into<String>,
111        expression: TemplateExpression,
112    ) -> Result<Self, TemplateModelError> {
113        Ok(Self {
114            key: validate_token("render_key", key.into())?,
115            expression,
116        })
117    }
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub enum ConditionExpression {
122    Key(String),
123    Literal(bool),
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
127pub enum Node {
128    StaticText(String),
129    Value(String),
130    RawValue(String),
131    Expression(TemplateExpression),
132    RawExpression(TemplateExpression),
133    Element(ElementNode),
134    Slot(SlotNode),
135    Include(TemplateSelector),
136    With {
137        bindings: Vec<TemplateBinding>,
138        children: Vec<Node>,
139    },
140    Conditional {
141        condition: ConditionExpression,
142        negated: bool,
143        children: Vec<Node>,
144    },
145    Each {
146        item: String,
147        collection: String,
148        children: Vec<Node>,
149    },
150}
151
152impl Node {
153    pub fn static_text(value: impl Into<String>) -> Self {
154        Self::StaticText(value.into())
155    }
156
157    pub fn value(key: impl Into<String>) -> Result<Self, TemplateModelError> {
158        Ok(Self::Value(validate_token("render_key", key.into())?))
159    }
160
161    pub fn raw_value(key: impl Into<String>) -> Result<Self, TemplateModelError> {
162        Ok(Self::RawValue(validate_token("render_key", key.into())?))
163    }
164
165    pub fn expression(expression: TemplateExpression) -> Self {
166        Self::Expression(expression)
167    }
168
169    pub fn raw_expression(expression: TemplateExpression) -> Self {
170        Self::RawExpression(expression)
171    }
172
173    pub fn include(selector: TemplateSelector) -> Self {
174        Self::Include(selector)
175    }
176
177    pub fn with(bindings: Vec<TemplateBinding>, children: Vec<Node>) -> Self {
178        Self::With { bindings, children }
179    }
180
181    pub fn conditional(
182        condition: impl Into<String>,
183        children: Vec<Node>,
184    ) -> Result<Self, TemplateModelError> {
185        Ok(Self::Conditional {
186            condition: ConditionExpression::Key(validate_token("render_key", condition.into())?),
187            negated: false,
188            children,
189        })
190    }
191
192    pub fn conditional_literal(value: bool, children: Vec<Node>) -> Self {
193        Self::Conditional {
194            condition: ConditionExpression::Literal(value),
195            negated: false,
196            children,
197        }
198    }
199
200    pub fn conditional_not(
201        condition: impl Into<String>,
202        children: Vec<Node>,
203    ) -> Result<Self, TemplateModelError> {
204        Ok(Self::Conditional {
205            condition: ConditionExpression::Key(validate_token("render_key", condition.into())?),
206            negated: true,
207            children,
208        })
209    }
210
211    pub fn each(
212        item: impl Into<String>,
213        collection: impl Into<String>,
214        children: Vec<Node>,
215    ) -> Result<Self, TemplateModelError> {
216        Ok(Self::Each {
217            item: validate_token("render_key", item.into())?,
218            collection: validate_token("render_key", collection.into())?,
219            children,
220        })
221    }
222}