From b3f80eaeb38ae94b9e70d56a50cff1fddbce3efe Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 5 Jan 2025 01:38:30 -0600 Subject: [PATCH] wip --- crates/djls-template-ast/src/ast.rs | 31 +- crates/djls-template-ast/src/lexer.rs | 5 +- crates/djls-template-ast/src/parser.rs | 72 +++-- ...rser__tests__comments__parse_comments.snap | 1 + ...__tests__comments__parse_comments.snap.new | 20 ++ ..._tests__django__parse_complex_if_elif.snap | 1 + ...ts__django__parse_complex_if_elif.snap.new | 76 +++++ ...tests__django__parse_django_for_block.snap | 3 +- ...s__django__parse_django_for_block.snap.new | 59 ++++ ..._tests__django__parse_django_if_block.snap | 1 + ...ts__django__parse_django_if_block.snap.new | 39 +++ ..._tests__django__parse_django_variable.snap | 5 +- ...ts__django__parse_django_variable.snap.new | 23 ++ ...r__tests__django__parse_filter_chains.snap | 9 +- ...ests__django__parse_filter_chains.snap.new | 33 +++ ...r__tests__django__parse_mixed_content.snap | 33 +-- ...ests__django__parse_mixed_content.snap.new | 269 ++++++++++++++++++ ...r__tests__django__parse_nested_for_if.snap | 3 +- ...ests__django__parse_nested_for_if.snap.new | 68 +++++ ...__tests__errors__parse_error_recovery.snap | 21 +- ...sts__errors__parse_error_recovery.snap.new | 126 ++++++++ ...ts__errors__parse_unclosed_django_for.snap | 3 +- ...errors__parse_unclosed_django_for.snap.new | 34 +++ ...sts__errors__parse_unclosed_django_if.snap | 1 + ..._errors__parse_unclosed_django_if.snap.new | 29 ++ ...ests__errors__parse_unclosed_html_tag.snap | 1 + ...__errors__parse_unclosed_html_tag.snap.new | 15 + ..._tests__errors__parse_unclosed_script.snap | 1 + ...ts__errors__parse_unclosed_script.snap.new | 15 + ...__tests__errors__parse_unclosed_style.snap | 1 + ...sts__errors__parse_unclosed_style.snap.new | 15 + ...er__tests__full_templates__parse_full.snap | 29 +- ...tests__full_templates__parse_full.snap.new | 162 +++++++++++ ...rser__tests__html__parse_html_doctype.snap | 1 + ...__tests__html__parse_html_doctype.snap.new | 15 + ...__parser__tests__html__parse_html_tag.snap | 1 + ...rser__tests__html__parse_html_tag.snap.new | 15 + ..._parser__tests__html__parse_html_void.snap | 1 + ...ser__tests__html__parse_html_void.snap.new | 15 + ...__parser__tests__script__parse_script.snap | 1 + ...rser__tests__script__parse_script.snap.new | 21 ++ ...st__parser__tests__style__parse_style.snap | 1 + ...parser__tests__style__parse_style.snap.new | 20 ++ 43 files changed, 1220 insertions(+), 75 deletions(-) create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_style.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__full_templates__parse_full.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap.new create mode 100644 crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap.new diff --git a/crates/djls-template-ast/src/ast.rs b/crates/djls-template-ast/src/ast.rs index 1c5c789..c524a38 100644 --- a/crates/djls-template-ast/src/ast.rs +++ b/crates/djls-template-ast/src/ast.rs @@ -42,7 +42,7 @@ impl Ast { } #[derive(Clone, Default, Debug, Serialize)] -pub struct LineOffsets(Vec); +pub struct LineOffsets(pub Vec); impl LineOffsets { pub fn new() -> Self { @@ -55,11 +55,33 @@ impl LineOffsets { } pub fn position_to_line_col(&self, offset: u32) -> (u32, u32) { + eprintln!("LineOffsets: Converting position {} to line/col. Offsets: {:?}", offset, self.0); + + // Find which line contains this offset by looking for the first line start + // that's greater than our position let line = match self.0.binary_search(&offset) { - Ok(line) => line, - Err(line) => if line > 0 { line - 1 } else { line }, + Ok(exact_line) => exact_line, // We're exactly at a line start, so we're on that line + Err(next_line) => { + if next_line == 0 { + 0 // Before first line start, so we're on line 0 + } else { + let prev_line = next_line - 1; + // If we're at the start of the next line, we're on that line + if offset == self.0[next_line] - 1 { + prev_line + } else { + // Otherwise we're on the previous line + prev_line + } + } + } }; + + // Calculate column as offset from line start let col = offset - self.0[line]; + + eprintln!("LineOffsets: Found line {} starting at offset {}", line, self.0[line]); + eprintln!("LineOffsets: Calculated col {} as {} - {}", col, offset, self.0[line]); (line as u32, col) } @@ -185,6 +207,7 @@ mod tests { fn test_variable_spans() { let template = "Hello\n{{ user.name }}\nWorld"; let tokens = Lexer::new(template).tokenize().unwrap(); + println!("Tokens: {:#?}", tokens); // Add debug print let mut parser = Parser::new(tokens); let ast = parser.parse().unwrap(); @@ -236,6 +259,8 @@ mod tests { // Check content span if let Some(content) = children { if let Node::Text { span, .. } = &content[0] { + eprintln!("content {:?}", content); + eprintln!("span start {:?}", span.start()); let (content_line, content_col) = ast.line_offsets.position_to_line_col(*span.start()); assert_eq!( diff --git a/crates/djls-template-ast/src/lexer.rs b/crates/djls-template-ast/src/lexer.rs index b88a830..d1975e8 100644 --- a/crates/djls-template-ast/src/lexer.rs +++ b/crates/djls-template-ast/src/lexer.rs @@ -60,8 +60,11 @@ impl Lexer { }, '\n' => { self.consume()?; + let token = TokenType::Newline; + eprintln!("Lexer: Found newline at position {}, incrementing line from {} to {}", + self.start, self.line, self.line + 1); self.line += 1; - TokenType::Newline + token } ' ' | '\t' | '\r' => { let mut count = 1; diff --git a/crates/djls-template-ast/src/parser.rs b/crates/djls-template-ast/src/parser.rs index 4cf1c9a..db5d4f5 100644 --- a/crates/djls-template-ast/src/parser.rs +++ b/crates/djls-template-ast/src/parser.rs @@ -15,21 +15,25 @@ impl Parser { pub fn parse(&mut self) -> Result { let mut ast = Ast::default(); - let mut line_offsets = LineOffsets::new(); + let mut line_offsets = LineOffsets::new(); // Already contains [0] // First pass: collect line offsets - let mut current_offset = 0; for token in self.tokens.tokens() { match token.token_type() { TokenType::Newline => { - current_offset += 1; // Add 1 for the newline character - line_offsets.add_line(current_offset as u32); - } - _ => { - if let Some(len) = token.token_type().len() { - current_offset += len; + if let Some(start) = token.start() { + eprintln!("Parser: Found newline at position {}", start); + // Add line offset at the start of the next line + line_offsets.add_line(*start as u32 + 1); + eprintln!("Parser: Added line offset {} at position {}", line_offsets.0.len(), start + 1); } } + TokenType::Whitespace(count) => { + if let Some(start) = token.start() { + eprintln!("Parser: Found whitespace of length {} at position {}", count, start); + } + } + _ => {} } } @@ -189,20 +193,21 @@ impl Parser { } let closing_token = self.peek_previous()?; let closing_content = match closing_token.token_type() { - TokenType::DjangoBlock(content) => content.len(), + TokenType::DjangoBlock(content) => content.len() + 5, // Add 5 for {% and %} _ => 0, }; - total_length = (closing_token.start().unwrap_or(0) + closing_content) - - start_pos as usize; + let closing_start = closing_token.start().unwrap_or(0); + total_length = (closing_start + closing_content) - start_pos as usize; + let closing_span = Span::new( + closing_start as u32, + closing_content as u16, + ); children.push(Node::Block { block_type: BlockType::Closing, name: tag, bits: vec![], children: None, - span: Span::new( - closing_token.start().unwrap_or(0) as u32, - closing_content as u16, - ), + span: closing_span, tag_span, }); found_closing_tag = true; @@ -210,7 +215,7 @@ impl Parser { } // Check if intermediate tag if let Some(branches) = &spec.branches { - if let Some(branch) = branches.iter().find(|i| i.name == tag) { + if let Some(branch) = branches.iter().find(|b| b.name == tag) { // If we have a current branch, add it to children if let Some((name, bits, branch_children)) = current_branch { let branch_span = Span::new(start_pos, total_length as u16); @@ -281,10 +286,11 @@ impl Parser { } fn parse_django_variable(&mut self, s: &str) -> Result { - let start_token = self.peek_previous()?; - let start_pos = start_token.start().unwrap_or(0) as u32; + let token = self.peek_previous()?; + let start_pos = token.start().unwrap_or(0) as u32; + let s = s.trim(); // Trim whitespace let length = s.len() as u16; - let span = Span::new(start_pos, length); + let span = Span::new(start_pos + 3, length); // Add 3 to skip "{{ " let parts: Vec<&str> = s.split('|').collect(); let bits: Vec = parts[0].trim().split('.').map(String::from).collect(); @@ -324,10 +330,30 @@ impl Parser { } fn parse_text(&mut self) -> Result { - let start_token = self.peek()?; - let start_pos = start_token.start().unwrap_or(0) as u32; + let mut start_pos = self.peek()?.start().unwrap_or(0) as u32; let mut text = String::new(); + // Skip any leading newlines and whitespace + while let Ok(token) = self.peek() { + match token.token_type() { + TokenType::Newline => { + self.consume()?; + text.push('\n'); + if let Ok(next) = self.peek() { + start_pos = next.start().unwrap_or(0) as u32; + } + } + TokenType::Whitespace(len) => { + self.consume()?; + text.push_str(&" ".repeat(*len)); + if let Ok(next) = self.peek() { + start_pos = next.start().unwrap_or(0) as u32; + } + } + _ => break, + } + } + while let Ok(token) = self.peek() { match token.token_type() { TokenType::DjangoBlock(_) @@ -530,7 +556,8 @@ mod tests { } #[test] fn test_parse_complex_if_elif() { - let source = "{% if x > 0 %}Positive{% elif x < 0 %}Negative{% else %}Zero{% endif %}"; + let source = + "{% if x > 0 %}Positive{% elif x < 0 %}Negative{% else %}Zero{% endif %}"; let tokens = Lexer::new(source).tokenize().unwrap(); let mut parser = Parser::new(tokens); let ast = parser.parse().unwrap(); @@ -734,6 +761,7 @@ mod tests { let ast = parser.parse().unwrap(); let offsets = ast.line_offsets(); + eprintln!("{:?}", offsets); assert_eq!(offsets.position_to_line_col(0), (0, 0)); // Start of line 1 assert_eq!(offsets.position_to_line_col(6), (1, 0)); // Start of line 2 } diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap index f0bd382..ba19092 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap @@ -15,4 +15,5 @@ nodes: length: 18 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap.new new file mode 100644 index 0000000..20b4d11 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__comments__parse_comments.snap.new @@ -0,0 +1,20 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 608 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "" + span: + start: 0 + length: 21 + - Comment: + content: Django comment + span: + start: 21 + length: 18 +line_offsets: + - 0 +errors: [] 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 dc1ea7b..39f2f54 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 @@ -71,4 +71,5 @@ nodes: length: 8 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap.new new file mode 100644 index 0000000..b13760e --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_complex_if_elif.snap.new @@ -0,0 +1,76 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 535 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: if + bits: + - if + - x + - ">" + - "0" + children: + - Text: + content: Positive + span: + start: 14 + length: 8 + - Block: + block_type: Branch + name: elif + bits: + - x + - "<" + - "0" + children: + - Text: + content: Negative + span: + start: 38 + length: 8 + span: + start: 0 + length: 8 + tag_span: + start: 0 + length: 8 + - Block: + block_type: Branch + name: else + bits: [] + children: + - Text: + content: Zero + span: + start: 56 + length: 4 + span: + start: 0 + length: 8 + tag_span: + start: 0 + length: 8 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 60 + length: 5 + tag_span: + start: 0 + length: 8 + span: + start: 0 + length: 65 + tag_span: + start: 0 + length: 8 +line_offsets: + - 0 +errors: [] 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 c0b743a..13feb69 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 @@ -17,7 +17,7 @@ nodes: - item filters: [] span: - start: 23 + start: 25 length: 4 - Block: block_type: Branch @@ -54,4 +54,5 @@ nodes: length: 17 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap.new new file mode 100644 index 0000000..9c37553 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_for_block.snap.new @@ -0,0 +1,59 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 527 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: for + bits: + - for + - item + - in + - items + children: + - Variable: + bits: + - item + filters: [] + span: + start: 26 + length: 4 + - Block: + block_type: Branch + name: empty + bits: [] + children: + - Text: + content: No items + span: + start: 44 + length: 8 + span: + start: 0 + length: 17 + tag_span: + start: 0 + length: 17 + - Block: + block_type: Closing + name: endfor + bits: [] + children: ~ + span: + start: 52 + length: 6 + tag_span: + start: 0 + length: 17 + span: + start: 0 + length: 58 + tag_span: + start: 0 + length: 17 +line_offsets: + - 0 +errors: [] 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 a3fd5f7..a890b84 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 @@ -34,4 +34,5 @@ nodes: length: 24 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap.new new file mode 100644 index 0000000..2f1ae42 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_if_block.snap.new @@ -0,0 +1,39 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 519 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_authenticated + children: + - Text: + content: Welcome + span: + start: 30 + length: 7 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 37 + length: 5 + tag_span: + start: 0 + length: 24 + span: + start: 0 + length: 42 + tag_span: + start: 0 + length: 24 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap index 0a4dfbb..11a6477 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap @@ -11,11 +11,12 @@ nodes: - name: title arguments: [] span: - start: 10 + start: 12 length: 5 span: - start: 0 + start: 2 length: 15 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap.new new file mode 100644 index 0000000..471a049 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_django_variable.snap.new @@ -0,0 +1,23 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 503 +expression: ast +snapshot_kind: text +--- +nodes: + - Variable: + bits: + - user + - name + filters: + - name: title + arguments: [] + span: + start: 10 + length: 5 + span: + start: 3 + length: 15 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap index 23c7895..b19bc54 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap @@ -11,21 +11,22 @@ nodes: arguments: - "'nothing'" span: - start: 6 + start: 8 length: 17 - name: title arguments: [] span: - start: 24 + start: 26 length: 5 - name: upper arguments: [] span: - start: 30 + start: 32 length: 5 span: - start: 0 + start: 2 length: 35 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap.new new file mode 100644 index 0000000..c42904a --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_filter_chains.snap.new @@ -0,0 +1,33 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 511 +expression: ast +snapshot_kind: text +--- +nodes: + - Variable: + bits: + - value + filters: + - name: default + arguments: + - "'nothing'" + span: + start: 6 + length: 17 + - name: title + arguments: [] + span: + start: 24 + length: 5 + - name: upper + arguments: [] + span: + start: 30 + length: 5 + span: + start: 3 + length: 35 +line_offsets: + - 0 +errors: [] 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 cdde84b..fe5e876 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 @@ -28,16 +28,16 @@ nodes: - name: title arguments: [] span: - start: 54 + start: 56 length: 5 - name: default arguments: - "'Guest'" span: - start: 60 + start: 62 length: 15 span: - start: 44 + start: 46 length: 31 - Text: content: "\n " @@ -98,7 +98,7 @@ nodes: - name filters: [] span: - start: 168 + start: 170 length: 10 - Text: content: "\n " @@ -252,16 +252,17 @@ nodes: length: 1 line_offsets: - 0 - - 34 - - 70 - - 99 - - 130 - - 149 - - 184 - - 214 - - 224 - - 244 - - 255 - - 260 - - 270 + - 0 + - 40 + - 82 + - 117 + - 160 + - 185 + - 232 + - 274 + - 290 + - 310 + - 327 + - 338 + - 348 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap.new new file mode 100644 index 0000000..703a0f7 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_mixed_content.snap.new @@ -0,0 +1,269 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 564 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "Welcome, " + span: + start: 0 + length: 9 + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_authenticated + children: + - Text: + content: "\n " + span: + start: 39 + length: 5 + - Variable: + bits: + - user + - name + filters: + - name: title + arguments: [] + span: + start: 54 + length: 5 + - name: default + arguments: + - "'Guest'" + span: + start: 60 + length: 15 + span: + start: 47 + length: 31 + - Text: + content: "\n " + span: + start: 81 + length: 5 + - Block: + block_type: Standard + name: for + bits: + - for + - group + - in + - user.groups + children: + - Text: + content: "\n " + span: + start: 116 + length: 9 + - Block: + block_type: Standard + name: if + bits: + - if + - forloop.first + children: + - Text: + content: ( + span: + start: 147 + length: 1 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 148 + length: 5 + tag_span: + start: 125 + length: 16 + span: + start: 125 + length: 28 + tag_span: + start: 125 + length: 16 + - Text: + content: "\n " + span: + start: 159 + length: 9 + - Variable: + bits: + - group + - name + filters: [] + span: + start: 171 + length: 10 + - Text: + content: "\n " + span: + start: 184 + length: 9 + - Block: + block_type: Standard + name: if + bits: + - if + - not + - forloop.last + children: + - Text: + content: ", " + span: + start: 218 + length: 2 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 220 + length: 5 + tag_span: + start: 193 + length: 19 + span: + start: 193 + length: 32 + tag_span: + start: 193 + length: 19 + - Text: + content: "\n " + span: + start: 231 + length: 9 + - Block: + block_type: Standard + name: if + bits: + - if + - forloop.last + children: + - Text: + content: ) + span: + start: 261 + length: 1 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 262 + length: 5 + tag_span: + start: 240 + length: 15 + span: + start: 240 + length: 27 + tag_span: + start: 240 + length: 15 + - Text: + content: "\n " + span: + start: 273 + length: 5 + - Block: + block_type: Branch + name: empty + bits: [] + children: + - Text: + content: "\n (no groups)\n " + span: + start: 289 + length: 25 + span: + start: 86 + length: 24 + tag_span: + start: 86 + length: 24 + - Block: + block_type: Closing + name: endfor + bits: [] + children: ~ + span: + start: 314 + length: 6 + tag_span: + start: 86 + length: 24 + span: + start: 86 + length: 234 + tag_span: + start: 86 + length: 24 + - Text: + content: "\n" + span: + start: 326 + length: 1 + - Block: + block_type: Branch + name: else + bits: [] + children: + - Text: + content: "\n Guest\n" + span: + start: 337 + length: 11 + span: + start: 9 + length: 24 + tag_span: + start: 9 + length: 24 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 348 + length: 5 + tag_span: + start: 9 + length: 24 + span: + start: 9 + length: 344 + tag_span: + start: 9 + length: 24 + - Text: + content: "!" + span: + start: 359 + length: 1 +line_offsets: + - 0 + - 40 + - 82 + - 117 + - 160 + - 185 + - 232 + - 274 + - 290 + - 310 + - 327 + - 338 + - 348 +errors: [] 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 081a6ab..8aa150d 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 @@ -25,7 +25,7 @@ nodes: - name filters: [] span: - start: 43 + start: 45 length: 9 - Block: block_type: Closing @@ -63,4 +63,5 @@ nodes: length: 17 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap.new new file mode 100644 index 0000000..f07854c --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__django__parse_nested_for_if.snap.new @@ -0,0 +1,68 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 544 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: for + bits: + - for + - item + - in + - items + children: + - Block: + block_type: Standard + name: if + bits: + - if + - item.active + children: + - Variable: + bits: + - item + - name + filters: [] + span: + start: 46 + length: 9 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 58 + length: 5 + tag_span: + start: 23 + length: 14 + span: + start: 23 + length: 40 + tag_span: + start: 23 + length: 14 + - Block: + block_type: Closing + name: endfor + bits: [] + children: ~ + span: + start: 69 + length: 6 + tag_span: + start: 0 + length: 17 + span: + start: 0 + length: 75 + tag_span: + start: 0 + length: 17 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap index 6567480..dd67046 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap @@ -36,7 +36,7 @@ nodes: - name filters: [] span: - start: 150 + start: 152 length: 9 - Text: content: "

\n
\n " @@ -72,7 +72,7 @@ nodes: - item filters: [] span: - start: 294 + start: 296 length: 4 - Text: content: "\n " @@ -108,17 +108,18 @@ nodes: start: 48 length: 24 line_offsets: + - 0 - 0 - 24 - 44 - - 73 - - 123 - - 156 + - 79 + - 131 - 170 - - 228 - - 254 - - 284 - - 299 - - 332 + - 184 + - 244 + - 276 + - 312 + - 333 + - 366 errors: - UnclosedTag: if diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap.new new file mode 100644 index 0000000..01b9918 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_error_recovery.snap.new @@ -0,0 +1,126 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 677 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "
\n

Header

\n " + span: + start: 0 + length: 48 + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_authenticated + children: + - Text: + content: "\n " + span: + start: 78 + length: 9 + - Comment: + content: This if is unclosed which does matter + span: + start: 87 + length: 41 + - Text: + content: "\n

Welcome " + span: + start: 130 + length: 20 + - Variable: + bits: + - user + - name + filters: [] + span: + start: 153 + length: 9 + - Text: + content: "

\n
\n " + span: + start: 165 + length: 31 + - Comment: + content: "This div is unclosed which doesn't matter" + span: + start: 196 + length: 45 + - Text: + content: "\n " + span: + start: 243 + length: 9 + - Block: + block_type: Standard + name: for + bits: + - for + - item + - in + - items + children: + - Text: + content: "\n " + span: + start: 275 + length: 19 + - Variable: + bits: + - item + filters: [] + span: + start: 297 + length: 4 + - Text: + content: "\n " + span: + start: 304 + length: 16 + - Block: + block_type: Closing + name: endfor + bits: [] + children: ~ + span: + start: 320 + length: 6 + tag_span: + start: 252 + length: 17 + span: + start: 252 + length: 74 + tag_span: + start: 252 + length: 17 + - Text: + content: "\n
Page Footer
\n
" + span: + start: 332 + length: 40 + span: + start: 48 + length: 24 + tag_span: + start: 48 + length: 24 +line_offsets: + - 0 + - 24 + - 44 + - 79 + - 131 + - 170 + - 184 + - 244 + - 276 + - 312 + - 333 + - 366 +errors: + - UnclosedTag: if diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap index d9352d2..68ef466 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap @@ -18,7 +18,7 @@ nodes: - name filters: [] span: - start: 23 + start: 25 length: 9 span: start: 0 @@ -28,5 +28,6 @@ nodes: length: 17 line_offsets: - 0 + - 0 errors: - UnclosedTag: for diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap.new new file mode 100644 index 0000000..b94c595 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_for.snap.new @@ -0,0 +1,34 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 638 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: for + bits: + - for + - item + - in + - items + children: + - Variable: + bits: + - item + - name + filters: [] + span: + start: 26 + length: 9 + span: + start: 0 + length: 17 + tag_span: + start: 0 + length: 17 +line_offsets: + - 0 +errors: + - UnclosedTag: for diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap index 1fb1dfd..92ef3e9 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap @@ -23,5 +23,6 @@ nodes: length: 24 line_offsets: - 0 + - 0 errors: - UnclosedTag: if diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap.new new file mode 100644 index 0000000..532510a --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_django_if.snap.new @@ -0,0 +1,29 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 628 +expression: ast +snapshot_kind: text +--- +nodes: + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_authenticated + children: + - Text: + content: Welcome + span: + start: 30 + length: 7 + span: + start: 0 + length: 24 + tag_span: + start: 0 + length: 24 +line_offsets: + - 0 +errors: + - UnclosedTag: if diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap index 6b42432..ab2ce91 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap @@ -10,4 +10,5 @@ nodes: length: 5 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap.new new file mode 100644 index 0000000..e924744 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_html_tag.snap.new @@ -0,0 +1,15 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 619 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "
" + span: + start: 0 + length: 5 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap index 1e35fbd..457c0f6 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap @@ -10,4 +10,5 @@ nodes: length: 28 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap.new new file mode 100644 index 0000000..ae9d2b5 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__errors__parse_unclosed_script.snap.new @@ -0,0 +1,15 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 648 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "\n \n \n \n
\n " + span: + start: 0 + length: 463 + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_authenticated + children: + - Text: + content: "\n " + span: + start: 493 + length: 17 + - Comment: + content: Welcome message + span: + start: 510 + length: 19 + - Text: + content: "\n

Welcome, " + span: + start: 531 + length: 30 + - Variable: + bits: + - user + - name + filters: + - name: title + arguments: [] + span: + start: 571 + length: 5 + - name: default + arguments: + - "'Guest'" + span: + start: 577 + length: 15 + span: + start: 564 + length: 31 + - Text: + content: "!

\n " + span: + start: 598 + length: 23 + - Block: + block_type: Standard + name: if + bits: + - if + - user.is_staff + children: + - Text: + content: "\n Admin\n " + span: + start: 643 + length: 56 + - Block: + block_type: Branch + name: else + bits: [] + children: + - Text: + content: "\n User\n " + span: + start: 709 + length: 55 + span: + start: 621 + length: 16 + tag_span: + start: 621 + length: 16 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 764 + length: 5 + tag_span: + start: 621 + length: 16 + span: + start: 621 + length: 148 + tag_span: + start: 621 + length: 16 + - Text: + content: "\n " + span: + start: 775 + length: 13 + - Block: + block_type: Closing + name: endif + bits: [] + children: ~ + span: + start: 788 + length: 5 + tag_span: + start: 463 + length: 24 + span: + start: 463 + length: 330 + tag_span: + start: 463 + length: 24 + - Text: + content: "\n
\n \n" + span: + start: 799 + length: 35 +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: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap index 75261ea..4f12506 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap @@ -10,4 +10,5 @@ nodes: length: 15 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap.new new file mode 100644 index 0000000..9a0c869 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_doctype.snap.new @@ -0,0 +1,15 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 476 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "" + span: + start: 0 + length: 15 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap index 57b00d3..edad717 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap @@ -10,4 +10,5 @@ nodes: length: 34 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap.new new file mode 100644 index 0000000..745d6a6 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_tag.snap.new @@ -0,0 +1,15 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 484 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "
Hello
" + span: + start: 0 + length: 34 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap index 76523ff..59b9455 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap @@ -10,4 +10,5 @@ nodes: length: 21 line_offsets: - 0 + - 0 errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap.new new file mode 100644 index 0000000..02b6907 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__html__parse_html_void.snap.new @@ -0,0 +1,15 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 492 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "" + span: + start: 0 + length: 21 +line_offsets: + - 0 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap index 3927d68..34f1dcc 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap @@ -9,6 +9,7 @@ nodes: start: 0 length: 142 line_offsets: + - 0 - 0 - 32 - 59 diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap.new new file mode 100644 index 0000000..bef0f63 --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__script__parse_script.snap.new @@ -0,0 +1,21 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 581 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "" + span: + start: 0 + length: 142 +line_offsets: + - 0 + - 32 + - 59 + - 76 + - 94 + - 113 + - 133 +errors: [] diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap index fc8b64f..b767351 100644 --- a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap @@ -9,6 +9,7 @@ nodes: start: 0 length: 97 line_offsets: + - 0 - 0 - 24 - 48 diff --git a/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap.new b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap.new new file mode 100644 index 0000000..d71036a --- /dev/null +++ b/crates/djls-template-ast/src/snapshots/djls_template_ast__parser__tests__style__parse_style.snap.new @@ -0,0 +1,20 @@ +--- +source: crates/djls-template-ast/src/parser.rs +assertion_line: 597 +expression: ast +snapshot_kind: text +--- +nodes: + - Text: + content: "" + span: + start: 0 + length: 97 +line_offsets: + - 0 + - 24 + - 48 + - 62 + - 83 + - 89 +errors: []