From ec05c62c2a930bd8d131f46d8657a0296ccaf91b Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 4 Jan 2025 15:32:04 -0600 Subject: [PATCH] add closing tag and adjust branching strat --- crates/djls-template-ast/src/ast.rs | 4 +- crates/djls-template-ast/src/parser.rs | 68 ++++---- ..._tests__django__parse_complex_if_elif.snap | 37 ++-- ...tests__django__parse_django_for_block.snap | 29 ++-- ..._tests__django__parse_django_if_block.snap | 5 + ...r__tests__django__parse_mixed_content.snap | 163 ++++++++++-------- ...r__tests__django__parse_nested_for_if.snap | 10 ++ ...er__tests__full_templates__parse_full.snap | 36 ++-- ...mplate_ast__parser__tests__parse_full.snap | 53 ------ ...er__tests__script_tests__parse_script.snap | 10 -- ...rser__tests__style_tests__parse_style.snap | 13 -- 11 files changed, 213 insertions(+), 215 deletions(-) delete mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__parse_full.snap delete mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script_tests__parse_script.snap delete mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style_tests__parse_style.snap diff --git a/crates/djls-template-ast/src/ast.rs b/crates/djls-template-ast/src/ast.rs index 2072520..ea85e55 100644 --- a/crates/djls-template-ast/src/ast.rs +++ b/crates/djls-template-ast/src/ast.rs @@ -63,8 +63,8 @@ pub enum TagNode { #[derive(Clone, Debug, Serialize)] pub struct DjangoFilter { - pub name: String, - pub arguments: Vec, + name: String, + arguments: Vec, } impl DjangoFilter { diff --git a/crates/djls-template-ast/src/parser.rs b/crates/djls-template-ast/src/parser.rs index 230f38c..2f31a48 100644 --- a/crates/djls-template-ast/src/parser.rs +++ b/crates/djls-template-ast/src/parser.rs @@ -155,22 +155,28 @@ impl Parser { let specs = TagSpec::load_builtin_specs().unwrap_or_default(); - // Check if closing or intermediate tag according to any spec + // Check if this is a closing tag for (_, spec) in specs.iter() { if Some(&tag_name) == spec.closing.as_ref() { + let node = Node::Django(DjangoNode::Tag(TagNode::Closing { + name: tag_name.clone(), + bits: bits[1..].to_vec(), + })); return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name))); } + } + + // Check if this is a branch tag according to any spec + for (_, spec) in specs.iter() { if let Some(intermediates) = &spec.intermediates { - if intermediates.contains(&tag_name) { + if intermediates.iter().any(|i| i.name == tag_name) { return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name))); } } } let tag_spec = specs.get(tag_name.as_str()).cloned(); - let mut children = Vec::new(); - let mut branches = Vec::new(); while !self.is_at_end() { match self.next_node() { @@ -181,40 +187,44 @@ impl Parser { if let Some(spec) = &tag_spec { // Check if closing tag if Some(&tag) == spec.closing.as_ref() { - let tag_node = if !branches.is_empty() { - TagNode::Branching { - name: tag_name, - bits, - children, - branches, - } - } else { - TagNode::Block { - name: tag_name, - bits, - children, - } - }; - return Ok(Node::Django(DjangoNode::Tag(tag_node))); + children.push(Node::Django(DjangoNode::Tag(TagNode::Closing { + name: tag, + bits: vec![], + }))); + return Ok(Node::Django(DjangoNode::Tag(TagNode::Block { + name: tag_name, + bits, + children, + }))); } // Check if intermediate tag if let Some(intermediates) = &spec.intermediates { - if intermediates.contains(&tag) { - branches.push(TagNode::Block { - name: tag.clone(), - bits: vec![tag.clone()], - children, - }); - children = Vec::new(); + if let Some(intermediate) = intermediates.iter().find(|i| i.name == tag) { + // Create branch node with the current children + let branch_bits = if intermediate.args { + match &self.tokens[self.current - 1].token_type() { + TokenType::DjangoBlock(content) => content + .split_whitespace() + .skip(1) // Skip the tag name + .map(|s| s.to_string()) + .collect(), + _ => vec![tag.clone()], + } + } else { + vec![] + }; + children.push(Node::Django(DjangoNode::Tag(TagNode::Branch { + name: tag, + bits: branch_bits, + children: Vec::new(), + }))); continue; } } } return Err(ParserError::UnexpectedTag(tag)); } - Err(e) => { - return Err(e); - } + Err(e) => return Err(e), } } diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap index 02414f5..9d80d99 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap @@ -5,7 +5,7 @@ expression: ast nodes: - Django: Tag: - Branching: + Block: name: if bits: - if @@ -13,17 +13,26 @@ nodes: - ">" - "0" children: + - Text: Positive + - Django: + Tag: + Branch: + name: elif + bits: + - x + - "<" + - "0" + children: [] + - Text: Negative + - Django: + Tag: + Branch: + name: else + bits: [] + children: [] - Text: Zero - branches: - - Block: - name: elif - bits: - - elif - children: - - Text: Positive - - Block: - name: else - bits: - - else - children: - - Text: Negative + - Django: + Tag: + Closing: + name: endif + bits: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap index ba68416..824d841 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap @@ -5,7 +5,7 @@ expression: ast nodes: - Django: Tag: - Branching: + Block: name: for bits: - for @@ -13,15 +13,20 @@ nodes: - in - items children: + - Django: + Variable: + bits: + - item + filters: [] + - Django: + Tag: + Branch: + name: empty + bits: [] + children: [] - Text: No items - branches: - - Block: - name: empty - bits: - - empty - children: - - Django: - Variable: - bits: - - item - filters: [] + - Django: + Tag: + Closing: + name: endfor + bits: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap index 166f1f3..ff753ba 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap @@ -12,3 +12,8 @@ nodes: - user.is_authenticated children: - Text: Welcome + - Django: + Tag: + Closing: + name: endif + bits: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap index ac86f42..ec96adb 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap @@ -6,79 +6,104 @@ nodes: - Text: "Welcome, " - Django: Tag: - Branching: + Block: name: if bits: - if - user.is_authenticated children: + - Django: + Variable: + bits: + - user + - name + filters: + - name: title + arguments: [] + - name: default + arguments: + - "'Guest'" + - Django: + Tag: + Block: + name: for + bits: + - for + - group + - in + - user.groups + children: + - Django: + Tag: + Block: + name: if + bits: + - if + - forloop.first + children: + - Text: ( + - Django: + Tag: + Closing: + name: endif + bits: [] + - Django: + Variable: + bits: + - group + - name + filters: [] + - Django: + Tag: + Block: + name: if + bits: + - if + - not + - forloop.last + children: + - Text: ", " + - Django: + Tag: + Closing: + name: endif + bits: [] + - Django: + Tag: + Block: + name: if + bits: + - if + - forloop.last + children: + - Text: ) + - Django: + Tag: + Closing: + name: endif + bits: [] + - Django: + Tag: + Branch: + name: empty + bits: [] + children: [] + - Text: (no groups) + - Django: + Tag: + Closing: + name: endfor + bits: [] + - Django: + Tag: + Branch: + name: else + bits: [] + children: [] - Text: Guest - branches: - - Block: - name: else - bits: - - else - children: - - Django: - Variable: - bits: - - user - - name - filters: - - name: title - arguments: [] - - name: default - arguments: - - "'Guest'" - - Django: - Tag: - Branching: - name: for - bits: - - for - - group - - in - - user.groups - children: - - Text: (no groups) - branches: - - Block: - name: empty - bits: - - empty - children: - - Django: - Tag: - Block: - name: if - bits: - - if - - forloop.first - children: - - Text: ( - - Django: - Variable: - bits: - - group - - name - filters: [] - - Django: - Tag: - Block: - name: if - bits: - - if - - not - - forloop.last - children: - - Text: ", " - - Django: - Tag: - Block: - name: if - bits: - - if - - forloop.last - children: - - Text: ) + - Django: + Tag: + Closing: + name: endif + bits: [] - Text: "!" diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap index 8e4ac15..2b6ba47 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap @@ -27,3 +27,13 @@ nodes: - item - name filters: [] + - Django: + Tag: + Closing: + name: endif + bits: [] + - Django: + Tag: + Closing: + name: endfor + bits: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__full_templates__parse_full.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__full_templates__parse_full.snap index aacc26d..0688237 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__full_templates__parse_full.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__full_templates__parse_full.snap @@ -94,27 +94,37 @@ nodes: - Text: "!" - Django: Tag: - Branching: + Block: name: if bits: - if - user.is_staff children: + - Html: + Element: + tag_name: span + attributes: {} + children: + - Text: Admin + - Django: + Tag: + Branch: + name: else + bits: [] + children: [] - Html: Element: tag_name: span attributes: {} children: - Text: User - branches: - - Block: - name: else - bits: - - else - children: - - Html: - Element: - tag_name: span - attributes: {} - children: - - Text: Admin + - Django: + Tag: + Closing: + name: endif + bits: [] + - Django: + Tag: + Closing: + name: endif + bits: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__parse_full.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__parse_full.snap deleted file mode 100644 index 1e55b09..0000000 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__parse_full.snap +++ /dev/null @@ -1,53 +0,0 @@ ---- -source: crates/djls-template-ast/src/parser.rs -expression: ast ---- -nodes: - - Html: - Doctype: "!DOCTYPE" - - Html: - Element: - tag_name: html - attributes: {} - children: - - Html: - Element: - tag_name: head - attributes: {} - children: - - Html: - Element: - tag_name: title - attributes: {} - children: - - Text: Test - - Html: - Element: - tag_name: body - attributes: {} - children: - - Html: - Element: - tag_name: h1 - attributes: {} - children: - - Text: Hello World - - Html: - Element: - tag_name: p - attributes: {} - children: - - Text: This is a test - - Script: - Element: - attributes: {} - children: - - Text: "console.log(\"Hello World\");" - - Style: - Element: - attributes: - style: Boolean - children: - - Text: "h1 " - - Text: "{" - - Text: "color: red; }" diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script_tests__parse_script.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script_tests__parse_script.snap deleted file mode 100644 index 62f7cc0..0000000 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script_tests__parse_script.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: crates/djls-template-ast/src/parser.rs -expression: ast ---- -nodes: - - Script: - Element: - attributes: {} - children: - - Text: "console.log(\"Hello World\");" diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style_tests__parse_style.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style_tests__parse_style.snap deleted file mode 100644 index 7a9cca0..0000000 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style_tests__parse_style.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: crates/djls-template-ast/src/parser.rs -expression: ast ---- -nodes: - - Style: - Element: - attributes: - style: Boolean - children: - - Text: "h1 " - - Text: "{" - - Text: "color: red; }"