Skip to content

Commit e0143ef

Browse files
committed
align r3 transformer
1 parent 9daf614 commit e0143ef

File tree

55 files changed

+6503
-982
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+6503
-982
lines changed

crates/oxc_angular_compiler/src/parser/expression/mod.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,55 @@ pub struct TemplateBindingParseResult<'a> {
3434
pub warnings: std::vec::Vec<String>,
3535
}
3636

37+
/// Result of stripping comments from an expression.
38+
pub struct StripCommentsResult<'a> {
39+
/// The stripped expression (without comment).
40+
pub stripped: &'a str,
41+
/// Whether a comment was found.
42+
pub has_comments: bool,
43+
/// The position where the comment starts (if any).
44+
pub comment_start: Option<usize>,
45+
}
46+
47+
/// Finds the start of a `//` comment, respecting string quotes.
48+
///
49+
/// Returns `None` if no comment is found, or the byte position of `//`.
50+
pub fn find_comment_start(input: &str) -> Option<usize> {
51+
let bytes = input.as_bytes();
52+
let mut outer_quote: Option<u8> = None;
53+
54+
for i in 0..bytes.len().saturating_sub(1) {
55+
let ch = bytes[i];
56+
let next_ch = bytes[i + 1];
57+
58+
// Check for // outside of quotes
59+
if ch == b'/' && next_ch == b'/' && outer_quote.is_none() {
60+
return Some(i);
61+
}
62+
63+
// Track quote state
64+
if outer_quote == Some(ch) {
65+
outer_quote = None;
66+
} else if outer_quote.is_none() && (ch == b'\'' || ch == b'"' || ch == b'`') {
67+
outer_quote = Some(ch);
68+
}
69+
}
70+
71+
None
72+
}
73+
74+
/// Strips `//` comments from an expression, respecting string quotes.
75+
pub fn strip_comments(input: &str) -> StripCommentsResult<'_> {
76+
match find_comment_start(input) {
77+
Some(pos) => StripCommentsResult {
78+
stripped: &input[..pos],
79+
has_comments: true,
80+
comment_start: Some(pos),
81+
},
82+
None => StripCommentsResult { stripped: input, has_comments: false, comment_start: None },
83+
}
84+
}
85+
3786
/// A piece of text with start and end positions.
3887
#[derive(Debug, Clone)]
3988
pub struct InterpolationPiece {

crates/oxc_angular_compiler/src/parser/html/parser.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,39 @@ impl<'a> HtmlParser<'a> {
160160
self.parse_and_add_node();
161161
}
162162

163-
// Report unclosed blocks and elements
164-
// Components (uppercase first letter) are implicitly closed without error
165-
for container in &self.container_stack {
163+
// Close all remaining containers at EOF (error recovery)
164+
// This ensures we still produce AST nodes even for unclosed elements
165+
// Process from top of stack (innermost) to bottom (outermost)
166+
while let Some(container) = self.container_stack.pop() {
166167
match container {
167168
ContainerIndex::Block(idx) => {
168-
let block = &self.blocks[*idx];
169+
let block = &self.blocks[idx];
169170
let err = self.make_error(
170171
block.span.start,
171172
format!("Unclosed block \"@{}\"", block.name),
172173
);
173174
self.errors.push(err);
175+
176+
// Convert block to node and add to parent
177+
let block = std::mem::replace(
178+
&mut self.blocks[idx],
179+
HtmlBlock {
180+
block_type: BlockType::If,
181+
name: Atom::from(""),
182+
parameters: Vec::new_in(self.allocator),
183+
children: Vec::new_in(self.allocator),
184+
span: Span::new(0, 0),
185+
name_span: Span::new(0, 0),
186+
start_span: Span::new(0, 0),
187+
end_span: None,
188+
},
189+
);
190+
let node = HtmlNode::Block(Box::new_in(block, self.allocator));
191+
self.add_to_parent(node);
174192
}
175193
ContainerIndex::Element(idx) => {
176-
let element = &self.elements[*idx];
177-
// Components (first char is uppercase or underscore) are implicitly closed
194+
let element = &self.elements[idx];
195+
// Components (first char is uppercase or underscore) are implicitly closed without error
178196
let first_char = element.name.chars().next().unwrap_or('a');
179197
if !first_char.is_ascii_uppercase() && first_char != '_' {
180198
let err = self.make_error(
@@ -183,6 +201,23 @@ impl<'a> HtmlParser<'a> {
183201
);
184202
self.errors.push(err);
185203
}
204+
205+
// Convert element to node and add to parent
206+
let element = std::mem::replace(
207+
&mut self.elements[idx],
208+
HtmlElement {
209+
name: Atom::from(""),
210+
attrs: Vec::new_in(self.allocator),
211+
directives: Vec::new_in(self.allocator),
212+
children: Vec::new_in(self.allocator),
213+
span: Span::new(0, 0),
214+
start_span: Span::new(0, 0),
215+
end_span: None,
216+
is_self_closing: false,
217+
},
218+
);
219+
let node = HtmlNode::Element(Box::new_in(element, self.allocator));
220+
self.add_to_parent(node);
186221
}
187222
}
188223
}

0 commit comments

Comments
 (0)