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}