1#![warn(missing_docs)]
2
3use nargo_types::{Result, Span};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11use crate::expr::JsExpr;
12use crate::types::{MAX_ARRAY_LENGTH, MAX_RECURSION_DEPTH, MAX_STRING_LENGTH, IRError, Trivia};
13
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
16pub struct TestIR {
17 pub name: String,
19 pub body: crate::program::JsProgram,
21 pub span: Span,
23}
24
25impl TestIR {
26 pub fn validate(&self) -> Result<()> {
28 if self.name.len() > MAX_STRING_LENGTH {
29 return Err(IRError::SizeLimitExceeded("Test name length exceeded".to_string()).into());
30 }
31 self.body.validate()
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
37pub struct TemplateIR {
38 pub nodes: Vec<TemplateNodeIR>,
40 #[serde(default)]
42 pub span: Span,
43}
44
45impl TemplateIR {
46 pub fn validate(&self) -> Result<()> {
48 if self.nodes.len() > MAX_ARRAY_LENGTH {
49 return Err(IRError::SizeLimitExceeded("Template nodes length exceeded".to_string()).into());
50 }
51 for node in &self.nodes {
52 node.validate(0)?;
53 }
54 Ok(())
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
60pub enum TemplateNodeIR {
61 Element(ElementIR),
63 If(IfNodeIR),
65 For(ForNodeIR),
67 Text(String, #[serde(default)] Span, #[serde(default)] Trivia),
69 Interpolation(ExpressionIR),
71 Comment(String, #[serde(default)] Span, #[serde(default)] Trivia),
73 Hoisted(String),
75}
76
77impl TemplateNodeIR {
78 pub fn validate(&self, depth: usize) -> Result<()> {
80 if depth > MAX_RECURSION_DEPTH {
81 return Err(IRError::CircularReference("Template node recursion depth exceeded".to_string()).into());
82 }
83
84 match self {
85 TemplateNodeIR::Element(element) => element.validate(depth + 1),
86 TemplateNodeIR::If(if_node) => if_node.validate(depth + 1),
87 TemplateNodeIR::For(for_node) => for_node.validate(depth + 1),
88 TemplateNodeIR::Text(text, _, _) => {
89 if text.len() > MAX_STRING_LENGTH {
90 return Err(IRError::SizeLimitExceeded("Text length exceeded".to_string()).into());
91 }
92 Ok(())
93 }
94 TemplateNodeIR::Interpolation(expr) => expr.validate(depth + 1),
95 TemplateNodeIR::Comment(comment, _, _) => {
96 if comment.len() > MAX_STRING_LENGTH {
97 return Err(IRError::SizeLimitExceeded("Comment length exceeded".to_string()).into());
98 }
99 Ok(())
100 }
101 TemplateNodeIR::Hoisted(key) => {
102 if key.len() > MAX_STRING_LENGTH {
103 return Err(IRError::SizeLimitExceeded("Hoisted key length exceeded".to_string()).into());
104 }
105 Ok(())
106 }
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
113pub struct IfNodeIR {
114 pub condition: ExpressionIR,
116 pub consequent: Vec<TemplateNodeIR>,
118 pub alternate: Option<Vec<TemplateNodeIR>>,
120 pub else_ifs: Vec<(ExpressionIR, Vec<TemplateNodeIR>)>,
122 #[serde(default)]
124 pub span: Span,
125}
126
127impl IfNodeIR {
128 pub fn validate(&self, depth: usize) -> Result<()> {
130 if depth > MAX_RECURSION_DEPTH {
131 return Err(IRError::CircularReference("If node recursion depth exceeded".to_string()).into());
132 }
133
134 self.condition.validate(depth + 1)?;
135
136 if self.consequent.len() > MAX_ARRAY_LENGTH {
137 return Err(IRError::SizeLimitExceeded("If node consequent length exceeded".to_string()).into());
138 }
139 for node in &self.consequent {
140 node.validate(depth + 1)?;
141 }
142
143 if let Some(alternate) = &self.alternate {
144 if alternate.len() > MAX_ARRAY_LENGTH {
145 return Err(IRError::SizeLimitExceeded("If node alternate length exceeded".to_string()).into());
146 }
147 for node in alternate {
148 node.validate(depth + 1)?;
149 }
150 }
151
152 if self.else_ifs.len() > MAX_ARRAY_LENGTH {
153 return Err(IRError::SizeLimitExceeded("If node else ifs length exceeded".to_string()).into());
154 }
155 for (condition, body) in &self.else_ifs {
156 condition.validate(depth + 1)?;
157 if body.len() > MAX_ARRAY_LENGTH {
158 return Err(IRError::SizeLimitExceeded("If node else if body length exceeded".to_string()).into());
159 }
160 for node in body {
161 node.validate(depth + 1)?;
162 }
163 }
164
165 Ok(())
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
171pub struct ForNodeIR {
172 pub iterator: ForIteratorIR,
174 pub body: Vec<TemplateNodeIR>,
176 #[serde(default)]
178 pub span: Span,
179}
180
181impl ForNodeIR {
182 pub fn validate(&self, depth: usize) -> Result<()> {
184 if depth > MAX_RECURSION_DEPTH {
185 return Err(IRError::CircularReference("For node recursion depth exceeded".to_string()).into());
186 }
187
188 self.iterator.validate(depth + 1)?;
189
190 if self.body.len() > MAX_ARRAY_LENGTH {
191 return Err(IRError::SizeLimitExceeded("For node body length exceeded".to_string()).into());
192 }
193 for node in &self.body {
194 node.validate(depth + 1)?;
195 }
196
197 Ok(())
198 }
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
203pub struct ForIteratorIR {
204 pub item: String,
206 pub index: Option<String>,
208 pub collection: ExpressionIR,
210}
211
212impl ForIteratorIR {
213 pub fn validate(&self, depth: usize) -> Result<()> {
215 if depth > MAX_RECURSION_DEPTH {
216 return Err(IRError::CircularReference("For iterator recursion depth exceeded".to_string()).into());
217 }
218
219 if self.item.len() > MAX_STRING_LENGTH {
220 return Err(IRError::SizeLimitExceeded("For iterator item length exceeded".to_string()).into());
221 }
222
223 if let Some(index) = &self.index {
224 if index.len() > MAX_STRING_LENGTH {
225 return Err(IRError::SizeLimitExceeded("For iterator index length exceeded".to_string()).into());
226 }
227 }
228
229 self.collection.validate(depth + 1)
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
235pub struct ElementIR {
236 pub tag: String,
238 pub attributes: Vec<AttributeIR>,
240 pub children: Vec<TemplateNodeIR>,
242 pub is_static: bool,
244 #[serde(default)]
246 pub span: Span,
247 #[serde(default)]
249 pub trivia: Trivia,
250}
251
252impl ElementIR {
253 pub fn validate(&self, depth: usize) -> Result<()> {
255 if depth > MAX_RECURSION_DEPTH {
256 return Err(IRError::CircularReference("Element recursion depth exceeded".to_string()).into());
257 }
258
259 if self.tag.len() > MAX_STRING_LENGTH {
260 return Err(IRError::SizeLimitExceeded("Element tag length exceeded".to_string()).into());
261 }
262
263 if self.attributes.len() > MAX_ARRAY_LENGTH {
264 return Err(IRError::SizeLimitExceeded("Element attributes length exceeded".to_string()).into());
265 }
266 for attr in &self.attributes {
267 attr.validate(depth + 1)?;
268 }
269
270 if self.children.len() > MAX_ARRAY_LENGTH {
271 return Err(IRError::SizeLimitExceeded("Element children length exceeded".to_string()).into());
272 }
273 for child in &self.children {
274 child.validate(depth + 1)?;
275 }
276
277 Ok(())
278 }
279}
280
281#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
283pub struct AttributeIR {
284 pub name: String,
286 pub value: Option<String>,
288 pub value_ast: Option<JsExpr>,
290 pub argument: Option<String>,
292 pub modifiers: Vec<String>,
294 pub is_directive: bool,
296 pub is_dynamic: bool,
298 #[serde(default)]
300 pub span: Span,
301 #[serde(default)]
303 pub trivia: Trivia,
304}
305
306impl AttributeIR {
307 pub fn validate(&self, depth: usize) -> Result<()> {
309 if depth > MAX_RECURSION_DEPTH {
310 return Err(IRError::CircularReference("Attribute recursion depth exceeded".to_string()).into());
311 }
312
313 if self.name.len() > MAX_STRING_LENGTH {
314 return Err(IRError::SizeLimitExceeded("Attribute name length exceeded".to_string()).into());
315 }
316
317 if let Some(value) = &self.value {
318 if value.len() > MAX_STRING_LENGTH {
319 return Err(IRError::SizeLimitExceeded("Attribute value length exceeded".to_string()).into());
320 }
321 }
322
323 if let Some(value_ast) = &self.value_ast {
324 value_ast.validate(depth + 1)?;
325 }
326
327 if let Some(argument) = &self.argument {
328 if argument.len() > MAX_STRING_LENGTH {
329 return Err(IRError::SizeLimitExceeded("Attribute argument length exceeded".to_string()).into());
330 }
331 }
332
333 if self.modifiers.len() > MAX_ARRAY_LENGTH {
334 return Err(IRError::SizeLimitExceeded("Attribute modifiers length exceeded".to_string()).into());
335 }
336 for modifier in &self.modifiers {
337 if modifier.len() > MAX_STRING_LENGTH {
338 return Err(IRError::SizeLimitExceeded("Attribute modifier length exceeded".to_string()).into());
339 }
340 }
341
342 Ok(())
343 }
344}
345
346#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
348pub struct ExpressionIR {
349 pub code: String,
351 pub ast: Option<JsExpr>,
353 pub is_static: bool,
355 #[serde(default)]
357 pub span: Span,
358 #[serde(default)]
360 pub trivia: Trivia,
361}
362
363impl ExpressionIR {
364 pub fn validate(&self, depth: usize) -> Result<()> {
366 if depth > MAX_RECURSION_DEPTH {
367 return Err(IRError::CircularReference("Expression IR recursion depth exceeded".to_string()).into());
368 }
369
370 if self.code.len() > MAX_STRING_LENGTH {
371 return Err(IRError::SizeLimitExceeded("Expression code length exceeded".to_string()).into());
372 }
373
374 if let Some(ast) = &self.ast {
375 ast.validate(depth + 1)?;
376 }
377
378 Ok(())
379 }
380
381 pub fn is_empty(&self) -> bool {
383 self.code.is_empty() && self.ast.is_none() && self.trivia.is_empty()
384 }
385}
386
387#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
389pub struct CustomBlockIR {
390 pub name: String,
392 pub content: String,
394 pub attributes: HashMap<String, String>,
396 #[serde(default)]
398 pub span: Span,
399 #[serde(default)]
401 pub trivia: Trivia,
402}
403
404impl CustomBlockIR {
405 pub fn validate(&self) -> Result<()> {
407 if self.name.len() > MAX_STRING_LENGTH {
408 return Err(IRError::SizeLimitExceeded("Custom block name length exceeded".to_string()).into());
409 }
410
411 if self.content.len() > MAX_STRING_LENGTH {
412 return Err(IRError::SizeLimitExceeded("Custom block content length exceeded".to_string()).into());
413 }
414
415 if self.attributes.len() > MAX_ARRAY_LENGTH {
416 return Err(IRError::SizeLimitExceeded("Custom block attributes size exceeded".to_string()).into());
417 }
418 for (key, value) in &self.attributes {
419 if key.len() > MAX_STRING_LENGTH {
420 return Err(IRError::SizeLimitExceeded("Custom block attribute key length exceeded".to_string()).into());
421 }
422 if value.len() > MAX_STRING_LENGTH {
423 return Err(IRError::SizeLimitExceeded("Custom block attribute value length exceeded".to_string()).into());
424 }
425 }
426
427 Ok(())
428 }
429
430 pub fn is_empty(&self) -> bool {
432 self.name.is_empty() && self.content.is_empty() && self.attributes.is_empty() && self.trivia.is_empty()
433 }
434}
435
436#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
438pub struct StyleIR {
439 pub code: String,
441 pub lang: String,
443 pub scoped: bool,
445 #[serde(default)]
447 pub span: Span,
448 #[serde(default)]
450 pub trivia: Trivia,
451}
452
453impl StyleIR {
454 pub fn validate(&self) -> Result<()> {
456 if self.code.len() > MAX_STRING_LENGTH {
457 return Err(IRError::SizeLimitExceeded("Style code length exceeded".to_string()).into());
458 }
459
460 if self.lang.len() > MAX_STRING_LENGTH {
461 return Err(IRError::SizeLimitExceeded("Style lang length exceeded".to_string()).into());
462 }
463
464 Ok(())
465 }
466
467 pub fn is_empty(&self) -> bool {
469 self.code.is_empty() && self.lang.is_empty() && self.trivia.is_empty()
470 }
471}
472
473pub trait TemplateNodeVisitor<R> {
475 fn visit_element(&mut self, element: &ElementIR, depth: usize) -> R;
477 fn visit_if(&mut self, if_node: &IfNodeIR, depth: usize) -> R;
479 fn visit_for(&mut self, for_node: &ForNodeIR, depth: usize) -> R;
481 fn visit_text(&mut self, text: &String, span: &Span, trivia: &Trivia, depth: usize) -> R;
483 fn visit_interpolation(&mut self, expr: &ExpressionIR, depth: usize) -> R;
485 fn visit_comment(&mut self, comment: &String, span: &Span, trivia: &Trivia, depth: usize) -> R;
487 fn visit_hoisted(&mut self, key: &String, depth: usize) -> R;
489}
490
491impl TemplateNodeIR {
492 pub fn accept<R>(&self, visitor: &mut dyn TemplateNodeVisitor<R>, depth: usize) -> R {
494 match self {
495 TemplateNodeIR::Element(element) => visitor.visit_element(element, depth),
496 TemplateNodeIR::If(if_node) => visitor.visit_if(if_node, depth),
497 TemplateNodeIR::For(for_node) => visitor.visit_for(for_node, depth),
498 TemplateNodeIR::Text(text, span, trivia) => visitor.visit_text(text, span, trivia, depth),
499 TemplateNodeIR::Interpolation(expr) => visitor.visit_interpolation(expr, depth),
500 TemplateNodeIR::Comment(comment, span, trivia) => visitor.visit_comment(comment, span, trivia, depth),
501 TemplateNodeIR::Hoisted(key) => visitor.visit_hoisted(key, depth),
502 }
503 }
504}