This commit is contained in:
Josh Thomas 2025-01-05 23:04:24 -06:00
parent 0fe4a328ae
commit 9bd2ab98fd
6 changed files with 779 additions and 9 deletions

View file

@ -214,39 +214,57 @@ impl Parser {
let start_pos = start_token.start().unwrap_or(0);
let mut total_length = start_token.length().unwrap_or(0);
// Handle newlines by returning next node
if matches!(start_token.token_type(), TokenType::Newline) {
self.consume()?;
let (next_node, _) = self.next_node()?;
return Ok(next_node);
}
let mut content = match start_token.token_type() {
TokenType::Text(text) => text.to_string(),
TokenType::Whitespace(count) => " ".repeat(*count),
TokenType::Newline => "\n".to_string(),
_ => {
return Err(ParserError::Ast(AstError::InvalidTag(
"Expected text, whitespace, or newline token".to_string(),
"Expected text or whitespace token".to_string(),
)))
}
};
self.consume()?;
// Look ahead for more text/whitespace tokens
// Look ahead for more tokens until newline
while let Ok(next_token) = self.peek() {
match next_token.token_type() {
TokenType::Text(text) => {
content.push_str(text);
total_length = total_length.checked_add(text.len() as u32).unwrap_or(0);
total_length += next_token.length().unwrap_or(0);
self.consume()?;
}
TokenType::Whitespace(count) => {
content.push_str(&" ".repeat(*count));
total_length = total_length.checked_add(*count as u32).unwrap_or(0);
total_length += next_token.length().unwrap_or(0);
self.consume()?;
}
TokenType::Newline => {
// Include newline in span but not content
total_length += next_token.length().unwrap_or(0);
self.consume()?;
break;
}
_ => break,
}
}
Ok(Node::Text {
content,
span: Span::new(start_pos, total_length),
})
// Skip empty text nodes
if content.trim().is_empty() {
let (next_node, _) = self.next_node()?;
Ok(next_node)
} else {
Ok(Node::Text {
content,
span: Span::new(start_pos, total_length),
})
}
}
fn parse_comment(

View file

@ -0,0 +1,258 @@
---
source: crates/djls-template-ast/src/parser.rs
assertion_line: 487
expression: ast
snapshot_kind: text
---
nodes:
- Text:
content: "Welcome, "
span:
start: 0
length: 9
- Block:
Block:
tag:
name: if
bits:
- if
- user.is_authenticated
span:
start: 9
length: 24
tag_span:
start: 9
length: 24
assignment: ~
nodes:
- Variable:
bits:
- user
- name
filters:
- name: title
args: []
span:
start: 48
length: 31
- name: default
args:
- "'Guest'"
span:
start: 48
length: 31
span:
start: 47
length: 31
- Block:
Block:
tag:
name: for
bits:
- for
- group
- in
- user.groups
span:
start: 86
length: 24
tag_span:
start: 86
length: 24
assignment: ~
nodes:
- Block:
Block:
tag:
name: if
bits:
- if
- forloop.first
span:
start: 125
length: 16
tag_span:
start: 125
length: 16
assignment: ~
nodes:
- Text:
content: (
span:
start: 147
length: 1
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 148
length: 5
tag_span:
start: 148
length: 5
assignment: ~
assignments: []
- Variable:
bits:
- group
- name
filters: []
span:
start: 171
length: 10
- Block:
Block:
tag:
name: if
bits:
- if
- not
- forloop.last
span:
start: 193
length: 19
tag_span:
start: 193
length: 19
assignment: ~
nodes:
- Text:
content: ", "
span:
start: 218
length: 2
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 220
length: 5
tag_span:
start: 220
length: 5
assignment: ~
assignments: []
- Block:
Block:
tag:
name: if
bits:
- if
- forloop.last
span:
start: 240
length: 15
tag_span:
start: 240
length: 15
assignment: ~
nodes:
- Text:
content: )
span:
start: 261
length: 1
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 262
length: 5
tag_span:
start: 262
length: 5
assignment: ~
assignments: []
- Block:
Tag:
tag:
name: empty
bits:
- empty
span:
start: 278
length: 5
tag_span:
start: 278
length: 5
assignment: ~
- Text:
content: " (no groups)"
span:
start: 290
length: 20
closing:
Closing:
tag:
name: endfor
bits:
- endfor
span:
start: 314
length: 6
tag_span:
start: 314
length: 6
assignment: ~
assignments: []
- Block:
Tag:
tag:
name: else
bits:
- else
span:
start: 327
length: 4
tag_span:
start: 327
length: 4
assignment: ~
- Text:
content: " Guest"
span:
start: 338
length: 10
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 348
length: 5
tag_span:
start: 348
length: 5
assignment: ~
assignments: []
- Text:
content: "!"
span:
start: 359
length: 1
line_offsets:
- 0
- 40
- 82
- 117
- 160
- 185
- 232
- 274
- 290
- 310
- 327
- 338
- 348
errors: []

View file

@ -0,0 +1,139 @@
---
source: crates/djls-template-ast/src/parser.rs
assertion_line: 604
expression: ast
snapshot_kind: text
---
nodes:
- Text:
content: "<div class=\"container\">"
span:
start: 0
length: 24
- Text:
content: " <h1>Header</h1>"
span:
start: 24
length: 20
- Block:
Block:
tag:
name: if
bits:
- if
- user.is_authenticated
span:
start: 48
length: 24
tag_span:
start: 48
length: 24
assignment: ~
nodes:
- Comment:
content: This if is unclosed which does matter
span:
start: 87
length: 41
- Text:
content: " <p>Welcome "
span:
start: 131
length: 19
- Variable:
bits:
- user
- name
filters: []
span:
start: 153
length: 9
- Text:
content: "</p>"
span:
start: 165
length: 5
- Text:
content: " <div>"
span:
start: 170
length: 14
- Comment:
content: "This div is unclosed which doesn't matter"
span:
start: 196
length: 45
- Block:
Block:
tag:
name: for
bits:
- for
- item
- in
- items
span:
start: 252
length: 17
tag_span:
start: 252
length: 17
assignment: ~
nodes:
- Text:
content: " <span>"
span:
start: 276
length: 18
- Variable:
bits:
- item
filters: []
span:
start: 297
length: 4
- Text:
content: "</span>"
span:
start: 304
length: 8
closing:
Closing:
tag:
name: endfor
bits:
- endfor
span:
start: 320
length: 6
tag_span:
start: 320
length: 6
assignment: ~
assignments: []
- Text:
content: " <footer>Page Footer</footer>"
span:
start: 333
length: 33
- Text:
content: "</div>"
span:
start: 366
length: 6
closing: ~
assignments: []
line_offsets:
- 0
- 24
- 44
- 79
- 131
- 170
- 184
- 244
- 276
- 312
- 333
- 366
errors: []

View file

@ -0,0 +1,259 @@
---
source: crates/djls-template-ast/src/parser.rs
assertion_line: 647
expression: ast
snapshot_kind: text
---
nodes:
- Text:
content: "<!DOCTYPE html>"
span:
start: 0
length: 16
- Text:
content: "<html>"
span:
start: 16
length: 7
- Text:
content: " <head>"
span:
start: 23
length: 11
- Text:
content: " <style type=\"text/css\">"
span:
start: 34
length: 32
- Text:
content: " /* Style header */"
span:
start: 66
length: 31
- Text:
content: " .header { color: blue; }"
span:
start: 97
length: 37
- Text:
content: " </style>"
span:
start: 134
length: 17
- Text:
content: " <script type=\"text/javascript\">"
span:
start: 151
length: 40
- Text:
content: " // Init app"
span:
start: 191
length: 24
- Text:
content: " const app = {"
span:
start: 215
length: 26
- Text:
content: " /* Config */"
span:
start: 241
length: 29
- Text:
content: " debug: true"
span:
start: 270
length: 28
- Text:
content: " };"
span:
start: 298
length: 15
- Text:
content: " </script>"
span:
start: 313
length: 18
- Text:
content: " </head>"
span:
start: 331
length: 12
- Text:
content: " <body>"
span:
start: 343
length: 11
- Text:
content: " <!-- Header section -->"
span:
start: 354
length: 32
- Text:
content: " <div class=\"header\" id=\"main\" data-value=\"123\" disabled>"
span:
start: 386
length: 65
- Block:
Block:
tag:
name: if
bits:
- if
- user.is_authenticated
span:
start: 463
length: 24
tag_span:
start: 463
length: 24
assignment: ~
nodes:
- Comment:
content: Welcome message
span:
start: 510
length: 19
- Text:
content: " <h1>Welcome, "
span:
start: 532
length: 29
- Variable:
bits:
- user
- name
filters:
- name: title
args: []
span:
start: 565
length: 31
- name: default
args:
- "'Guest'"
span:
start: 565
length: 31
span:
start: 564
length: 31
- Text:
content: "!</h1>"
span:
start: 598
length: 7
- Block:
Block:
tag:
name: if
bits:
- if
- user.is_staff
span:
start: 621
length: 16
tag_span:
start: 621
length: 16
assignment: ~
nodes:
- Text:
content: " <span>Admin</span>"
span:
start: 644
length: 39
- Block:
Tag:
tag:
name: else
bits:
- else
span:
start: 699
length: 4
tag_span:
start: 699
length: 4
assignment: ~
- Text:
content: " <span>User</span>"
span:
start: 710
length: 38
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 764
length: 5
tag_span:
start: 764
length: 5
assignment: ~
assignments: []
closing:
Closing:
tag:
name: endif
bits:
- endif
span:
start: 788
length: 5
tag_span:
start: 788
length: 5
assignment: ~
assignments: []
- Text:
content: " </div>"
span:
start: 800
length: 15
- Text:
content: " </body>"
span:
start: 815
length: 12
- Text:
content: "</html>"
span:
start: 827
length: 7
line_offsets:
- 0
- 16
- 23
- 34
- 66
- 97
- 134
- 151
- 191
- 215
- 241
- 270
- 298
- 313
- 331
- 343
- 354
- 386
- 451
- 494
- 532
- 605
- 644
- 683
- 710
- 748
- 776
- 800
- 815
- 827
errors: []

View file

@ -0,0 +1,51 @@
---
source: crates/djls-template-ast/src/parser.rs
assertion_line: 505
expression: ast
snapshot_kind: text
---
nodes:
- Text:
content: "<script type=\"text/javascript\">"
span:
start: 0
length: 32
- Text:
content: " // Single line comment"
span:
start: 32
length: 27
- Text:
content: " const x = 1;"
span:
start: 59
length: 17
- Text:
content: " /* Multi-line"
span:
start: 76
length: 18
- Text:
content: " comment */"
span:
start: 94
length: 19
- Text:
content: " console.log(x);"
span:
start: 113
length: 20
- Text:
content: "</script>"
span:
start: 133
length: 9
line_offsets:
- 0
- 32
- 59
- 76
- 94
- 113
- 133
errors: []

View file

@ -0,0 +1,45 @@
---
source: crates/djls-template-ast/src/parser.rs
assertion_line: 522
expression: ast
snapshot_kind: text
---
nodes:
- Text:
content: "<style type=\"text/css\">"
span:
start: 0
length: 24
- Text:
content: " /* Header styles */"
span:
start: 24
length: 24
- Text:
content: " .header {"
span:
start: 48
length: 14
- Text:
content: " color: blue;"
span:
start: 62
length: 21
- Text:
content: " }"
span:
start: 83
length: 6
- Text:
content: "</style>"
span:
start: 89
length: 8
line_offsets:
- 0
- 24
- 48
- 62
- 83
- 89
errors: []