leading whitespace

This commit is contained in:
Josh Thomas 2025-01-06 11:22:26 -06:00
parent ad9d6e56b0
commit 55b2b92fc1
6 changed files with 136 additions and 128 deletions

View file

@ -54,6 +54,11 @@ impl Parser {
fn next_node(&mut self) -> Result<Node, ParserError> { fn next_node(&mut self) -> Result<Node, ParserError> {
let token = self.peek()?; let token = self.peek()?;
match token.token_type() { match token.token_type() {
TokenType::Comment(content, start, end) => {
self.consume()?;
self.parse_comment(content, start, end.as_deref())
}
TokenType::Eof => Err(ParserError::Ast(AstError::StreamError("AtEnd".to_string()))),
TokenType::DjangoBlock(content) => { TokenType::DjangoBlock(content) => {
self.consume()?; self.consume()?;
self.parse_django_block(content) self.parse_django_block(content)
@ -62,24 +67,39 @@ impl Parser {
self.consume()?; self.consume()?;
self.parse_django_variable(content) self.parse_django_variable(content)
} }
TokenType::Comment(content, start, end) => { TokenType::HtmlTagClose(_)
self.consume()?;
self.parse_comment(content, start, end.as_deref())
}
TokenType::Text(_)
| TokenType::Whitespace(_)
| TokenType::Newline
| TokenType::HtmlTagOpen(_) | TokenType::HtmlTagOpen(_)
| TokenType::HtmlTagClose(_)
| TokenType::HtmlTagVoid(_) | TokenType::HtmlTagVoid(_)
| TokenType::ScriptTagOpen(_) | TokenType::Newline
| TokenType::ScriptTagClose(_) | TokenType::ScriptTagClose(_)
| TokenType::ScriptTagOpen(_)
| TokenType::StyleTagClose(_)
| TokenType::StyleTagOpen(_) | TokenType::StyleTagOpen(_)
| TokenType::StyleTagClose(_) => { | TokenType::Text(_)
| TokenType::Whitespace(_) => {
self.consume()?; self.consume()?;
self.parse_text() self.parse_text()
} }
TokenType::Eof => Err(ParserError::Ast(AstError::StreamError("AtEnd".to_string()))), }
}
fn parse_comment(
&mut self,
content: &str,
start: &str,
end: Option<&str>,
) -> Result<Node, ParserError> {
let token = self.peek_previous()?;
let start_pos = token.start().unwrap_or(0);
// Only treat Django comments as Comment nodes
if start == "{#" && end == Some("#}") {
Ok(Node::Comment {
content: content.to_string(),
span: Span::new(start_pos, token.token_type().len().unwrap_or(0) as u32),
})
} else {
self.parse_text()
} }
} }
@ -209,7 +229,7 @@ impl Parser {
.. ..
} = &block } = &block
{ {
if let Some(expected_closing) = &spec.closing { if let Some(_expected_closing) = &spec.closing {
self.errors.push(ParserError::Ast(AstError::UnclosedTag( self.errors.push(ParserError::Ast(AstError::UnclosedTag(
tag_ref.name.clone(), tag_ref.name.clone(),
))); )));
@ -245,7 +265,7 @@ impl Parser {
filters.push(DjangoFilter { filters.push(DjangoFilter {
name: filter_name.to_string(), name: filter_name.to_string(),
args: filter_args, args: filter_args,
span: Span::new(start + 4, content.len() as u32), // Account for {{ and space span: Span::new(start + 4, content.len() as u32),
}); });
} }
} }
@ -253,7 +273,7 @@ impl Parser {
Ok(Node::Variable { Ok(Node::Variable {
bits, bits,
filters, filters,
span: Span::new(start + 3, content.len() as u32), // Account for {{ and space span: Span::new(start + 3, content.len() as u32),
}) })
} }
@ -261,8 +281,16 @@ impl Parser {
let start_token = self.peek_previous()?; let start_token = self.peek_previous()?;
let start_pos = start_token.start().unwrap_or(0); let start_pos = start_token.start().unwrap_or(0);
if matches!(start_token.token_type(), TokenType::Newline) { match start_token.token_type() {
return self.next_node(); TokenType::Newline => return self.next_node(),
TokenType::Whitespace(_)
if self
.peek_at(-2)
.map_or(false, |t| matches!(t.token_type(), TokenType::Newline)) =>
{
return self.next_node()
}
_ => {}
} }
let mut text = start_token.token_type().to_string(); let mut text = start_token.token_type().to_string();
@ -294,26 +322,6 @@ impl Parser {
} }
} }
fn parse_comment(
&mut self,
content: &str,
start: &str,
end: Option<&str>,
) -> Result<Node, ParserError> {
let token = self.peek_previous()?;
let start_pos = token.start().unwrap_or(0);
// Only treat Django comments as Comment nodes
if start == "{#" && end == Some("#}") {
Ok(Node::Comment {
content: content.to_string(),
span: Span::new(start_pos, token.token_type().len().unwrap_or(0) as u32),
})
} else {
self.parse_text()
}
}
fn peek(&self) -> Result<Token, ParserError> { fn peek(&self) -> Result<Token, ParserError> {
self.peek_at(0) self.peek_at(0)
} }

View file

@ -185,10 +185,10 @@ nodes:
assignment: ~ assignment: ~
nodes: nodes:
- Text: - Text:
content: " (no groups)" content: (no groups)
span: span:
start: 290 start: 298
length: 19 length: 11
closing: closing:
Closing: Closing:
tag: tag:
@ -218,10 +218,10 @@ nodes:
assignment: ~ assignment: ~
nodes: nodes:
- Text: - Text:
content: " Guest" content: Guest
span: span:
start: 338 start: 342
length: 9 length: 5
closing: closing:
Closing: Closing:
tag: tag:

View file

@ -9,10 +9,10 @@ nodes:
start: 0 start: 0
length: 23 length: 23
- Text: - Text:
content: " <h1>Header</h1>" content: "<h1>Header</h1>"
span: span:
start: 24 start: 28
length: 19 length: 15
- Block: - Block:
Block: Block:
tag: tag:
@ -34,10 +34,10 @@ nodes:
start: 87 start: 87
length: 43 length: 43
- Text: - Text:
content: " <p>Welcome " content: "<p>Welcome "
span: span:
start: 131 start: 139
length: 19 length: 11
- Variable: - Variable:
bits: bits:
- user - user
@ -52,10 +52,10 @@ nodes:
start: 165 start: 165
length: 4 length: 4
- Text: - Text:
content: " <div>" content: "<div>"
span: span:
start: 170 start: 178
length: 13 length: 5
- Comment: - Comment:
content: "This div is unclosed which doesn't matter" content: "This div is unclosed which doesn't matter"
span: span:
@ -79,10 +79,10 @@ nodes:
assignment: ~ assignment: ~
nodes: nodes:
- Text: - Text:
content: " <span>" content: "<span>"
span: span:
start: 276 start: 288
length: 18 length: 6
- Variable: - Variable:
bits: bits:
- item - item
@ -110,10 +110,10 @@ nodes:
assignment: ~ assignment: ~
assignments: ~ assignments: ~
- Text: - Text:
content: " <footer>Page Footer</footer>" content: "<footer>Page Footer</footer>"
span: span:
start: 333 start: 337
length: 32 length: 28
- Text: - Text:
content: "</div>" content: "</div>"
span: span:

View file

@ -14,85 +14,85 @@ nodes:
start: 16 start: 16
length: 6 length: 6
- Text: - Text:
content: " <head>" content: "<head>"
span: span:
start: 23 start: 27
length: 10 length: 6
- Text: - Text:
content: " <style type=\"text/css\">" content: "<style type=\"text/css\">"
span: span:
start: 34 start: 42
length: 31 length: 23
- Text: - Text:
content: /* Style header */ content: /* Style header */
span: span:
start: 78 start: 78
length: 18 length: 18
- Text: - Text:
content: " .header { color: blue; }" content: ".header { color: blue; }"
span: span:
start: 97 start: 109
length: 36 length: 24
- Text: - Text:
content: " </style>" content: "</style>"
span: span:
start: 134 start: 142
length: 16 length: 8
- Text: - Text:
content: " <script type=\"text/javascript\">" content: "<script type=\"text/javascript\">"
span: span:
start: 151 start: 159
length: 39 length: 31
- Text: - Text:
content: // Init app content: // Init app
span: span:
start: 203 start: 203
length: 11 length: 11
- Text: - Text:
content: " const app = {" content: "const app = {"
span: span:
start: 215 start: 227
length: 25 length: 13
- Text: - Text:
content: /* Config */ content: /* Config */
span: span:
start: 257 start: 257
length: 12 length: 12
- Text: - Text:
content: " debug: true" content: "debug: true"
span: span:
start: 270 start: 286
length: 27
- Text:
content: " };"
span:
start: 298
length: 14
- Text:
content: " </script>"
span:
start: 313
length: 17
- Text:
content: " </head>"
span:
start: 331
length: 11 length: 11
- Text: - Text:
content: " <body>" content: "};"
span: span:
start: 343 start: 310
length: 10 length: 2
- Text:
content: "</script>"
span:
start: 321
length: 9
- Text:
content: "</head>"
span:
start: 335
length: 7
- Text:
content: "<body>"
span:
start: 347
length: 6
- Text: - Text:
content: "<!-- Header section -->" content: "<!-- Header section -->"
span: span:
start: 362 start: 362
length: 23 length: 23
- Text: - Text:
content: " <div class=\"header\" id=\"main\" data-value=\"123\" disabled>" content: "<div class=\"header\" id=\"main\" data-value=\"123\" disabled>"
span: span:
start: 386 start: 394
length: 64 length: 56
- Block: - Block:
Block: Block:
tag: tag:
@ -114,10 +114,10 @@ nodes:
start: 510 start: 510
length: 21 length: 21
- Text: - Text:
content: " <h1>Welcome, " content: "<h1>Welcome, "
span: span:
start: 532 start: 548
length: 29 length: 13
- Variable: - Variable:
bits: bits:
- user - user
@ -158,10 +158,10 @@ nodes:
assignment: ~ assignment: ~
nodes: nodes:
- Text: - Text:
content: " <span>Admin</span>" content: "<span>Admin</span>"
span: span:
start: 644 start: 664
length: 38 length: 18
- Block: - Block:
Branch: Branch:
tag: tag:
@ -177,10 +177,10 @@ nodes:
assignment: ~ assignment: ~
nodes: nodes:
- Text: - Text:
content: " <span>User</span>" content: "<span>User</span>"
span: span:
start: 710 start: 730
length: 37 length: 17
closing: closing:
Closing: Closing:
tag: tag:
@ -210,15 +210,15 @@ nodes:
assignment: ~ assignment: ~
assignments: ~ assignments: ~
- Text: - Text:
content: " </div>" content: "</div>"
span: span:
start: 800 start: 808
length: 14 length: 6
- Text: - Text:
content: " </body>" content: "</body>"
span: span:
start: 815 start: 819
length: 11 length: 7
- Text: - Text:
content: "</html>" content: "</html>"
span: span:

View file

@ -14,20 +14,20 @@ nodes:
start: 36 start: 36
length: 22 length: 22
- Text: - Text:
content: " const x = 1;" content: const x = 1;
span: span:
start: 59 start: 63
length: 16 length: 12
- Text: - Text:
content: "/* Multi-line\n comment */" content: "/* Multi-line\n comment */"
span: span:
start: 80 start: 80
length: 32 length: 32
- Text: - Text:
content: " console.log(x);" content: console.log(x);
span: span:
start: 113 start: 117
length: 19 length: 15
- Text: - Text:
content: "</script>" content: "</script>"
span: span:

View file

@ -14,20 +14,20 @@ nodes:
start: 28 start: 28
length: 19 length: 19
- Text: - Text:
content: " .header {" content: ".header {"
span: span:
start: 48 start: 52
length: 13 length: 9
- Text: - Text:
content: " color: blue;" content: "color: blue;"
span: span:
start: 62 start: 70
length: 20 length: 12
- Text: - Text:
content: " }" content: "}"
span: span:
start: 83 start: 87
length: 5 length: 1
- Text: - Text:
content: "</style>" content: "</style>"
span: span: