@@ -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