fix parseing of django tags with potential intermediates

This commit is contained in:
Josh Thomas 2024-12-13 01:13:04 -06:00
parent a5e42fe7a4
commit 134f3fea54
2 changed files with 141 additions and 4 deletions

View file

@ -155,8 +155,18 @@ impl Parser {
if tag == end_tag {
self.consume()?;
break;
} else if !tag.starts_with("end") {
// For intermediate tags (else, elif, empty, etc.)
self.consume()?;
// Create a new Tag node for the intermediate tag
children.push(Node::Django(DjangoNode::Tag {
kind: DjangoTagKind::from_str(&tag)?,
bits: vec![tag.clone()],
children: Vec::new(),
}));
} else {
return Err(ParserError::ErrorSignal(Signal::ClosingTagFound(tag)));
}
// If it's not our end tag, keep collecting children
}
Err(e) => return Err(e),
}
@ -453,16 +463,37 @@ impl Parser {
const SYNC_TYPES: &[TokenType] = &[
TokenType::DjangoBlock(String::new()),
TokenType::HtmlTagOpen(String::new()),
TokenType::HtmlTagClose(String::new()), // Added
TokenType::HtmlTagVoid(String::new()),
TokenType::ScriptTagOpen(String::new()),
TokenType::ScriptTagClose(String::new()), // Added
TokenType::StyleTagOpen(String::new()),
TokenType::StyleTagClose(String::new()), // Added
TokenType::Newline,
TokenType::Eof,
];
let mut nesting = 0;
while !self.is_at_end() {
if SYNC_TYPES.contains(self.peek()?.token_type()) {
return Ok(());
let token = self.peek()?;
match token.token_type() {
TokenType::HtmlTagOpen(_)
| TokenType::ScriptTagOpen(_)
| TokenType::StyleTagOpen(_) => {
nesting += 1;
}
TokenType::HtmlTagClose(_)
| TokenType::ScriptTagClose(_)
| TokenType::StyleTagClose(_) => {
nesting -= 1;
if nesting < 0 {
return Ok(());
}
}
_ if SYNC_TYPES.contains(token.token_type()) && nesting == 0 => {
return Ok(());
}
_ => {}
}
self.consume()?;
}
@ -609,7 +640,7 @@ mod tests {
}
// hangs for some reason
// #[test]
#[test]
fn test_parse_full() {
let source = r#"<!DOCTYPE html>
<html>

View file

@ -0,0 +1,106 @@
---
source: crates/djls-ast/src/parser.rs
expression: ast
---
nodes:
- Html:
Doctype: "!DOCTYPE"
- Html:
Element:
tag_name: html
attributes: {}
children:
- Html:
Element:
tag_name: head
attributes: {}
children:
- Style:
Element:
attributes:
type:
Value: text/css
children:
- Style:
Comment: Style header
- Text: ".header "
- Text: "{"
- Text: "color: blue; }"
- Script:
Element:
attributes:
script: Boolean
type:
Value: text/javascript
children:
- Script:
Comment:
content: Init app
kind: SingleLine
- Text: "const app = "
- Text: "{"
- Script:
Comment:
content: Config
kind: MultiLine
- Text: "debug: true"
- Text: "};"
- Html:
Element:
tag_name: body
attributes: {}
children:
- Html:
Comment: Header section
- Html:
Element:
tag_name: div
attributes:
class:
Value: header
data-value:
Value: "123"
disabled: Boolean
id:
Value: main
children:
- Django:
Tag:
kind: If
bits:
- if
- user.is_authenticated
children:
- Django:
Comment: Welcome message
- Html:
Element:
tag_name: h1
attributes: {}
children:
- Text: "Welcome, "
- Django:
Variable:
bits:
- user
- name
filters:
- name: default
arguments:
- Guest
- name: title
arguments: []
- Text: "!"
- Django:
Tag:
kind: If
bits:
- if
- user.is_staff
children:
- Html:
Element:
tag_name: span
attributes: {}
children:
- Text: Admin