@@ -153,6 +153,8 @@ fn inside_tag_context(p: &HtmlParser) -> HtmlLexContext {
153153 HtmlLexContext :: InsideTagWithDirectives { svelte : false }
154154 } else if Svelte . is_supported ( p) {
155155 HtmlLexContext :: InsideTagSvelte
156+ } else if Astro . is_supported ( p) {
157+ HtmlLexContext :: InsideTagAstro
156158 } else {
157159 HtmlLexContext :: InsideTag
158160 }
@@ -190,11 +192,14 @@ fn parse_any_tag_name(p: &mut HtmlParser) -> ParsedSyntax {
190192 if !is_at_start_literal ( p) {
191193 return Absent ;
192194 }
193-
194195 let tag_text = p. cur_text ( ) ;
195196
196- // Step 1: Parse base name (either component or regular tag)
197- let name = if is_possible_component ( p, tag_text) {
197+ // Check if this could be a component or has member expression
198+ let is_component = is_possible_component ( p, tag_text) ;
199+ let has_member_expression = !p. options ( ) . is_html ( ) && p. nth_at ( 1 , T ! [ . ] ) ;
200+
201+ // Step 1: Parse base name
202+ let name = if is_component || has_member_expression {
198203 // Parse as component name - use component_name_context to allow `.` for member expressions
199204 let m = p. start ( ) ;
200205 p. bump_with_context ( HTML_LITERAL , component_name_context ( p) ) ;
@@ -203,14 +208,18 @@ fn parse_any_tag_name(p: &mut HtmlParser) -> ParsedSyntax {
203208 // Parse as regular HTML tag
204209 parse_literal ( p, HTML_TAG_NAME )
205210 } ;
206-
207211 // Step 2: Extend with member access if present (using .map() pattern from JSX parser)
208212 name. map ( |mut name| {
209- while p. at ( T ! [ . ] ) {
210- let m = name. precede ( p) ; // Create marker BEFORE already-parsed name
211- p. bump_with_context ( T ! [ . ] , component_name_context ( p) ) ; // Use component context for `.`
213+ // Check kind BEFORE moving name with precede()
214+ let is_lowercase_tag = name. kind ( p) == HTML_TAG_NAME ;
212215
213- // Parse member name - must use component_name_context to maintain `.` lexing
216+ while p. at ( T ! [ . ] ) {
217+ // Convert BEFORE precede takes ownership of name
218+ if is_lowercase_tag {
219+ name. change_kind ( p, HTML_COMPONENT_NAME ) ;
220+ }
221+ let m = name. precede ( p) ;
222+ p. bump_with_context ( T ! [ . ] , component_name_context ( p) ) ;
214223 if is_at_start_literal ( p) {
215224 let member_m = p. start ( ) ;
216225 p. bump_with_context ( HTML_LITERAL , component_name_context ( p) ) ;
@@ -219,7 +228,7 @@ fn parse_any_tag_name(p: &mut HtmlParser) -> ParsedSyntax {
219228 p. error ( expected_element_name ( p, p. cur_range ( ) ) ) ;
220229 }
221230
222- name = m. complete ( p, HTML_MEMBER_NAME ) ; // Wrap previous name
231+ name = m. complete ( p, HTML_MEMBER_NAME ) ;
223232 }
224233 name
225234 } )
@@ -243,8 +252,15 @@ fn parse_element(p: &mut HtmlParser) -> ParsedSyntax {
243252
244253 parse_any_tag_name ( p) . or_add_diagnostic ( p, expected_element_name) ;
245254
246- if Astro . is_supported ( p) {
247- p. re_lex ( HtmlReLexContext :: InsideTagAstro ) ;
255+ let context = inside_tag_context ( p) ;
256+ match context {
257+ HtmlLexContext :: InsideTagSvelte => {
258+ p. re_lex ( HtmlReLexContext :: InsideTagSvelte ) ;
259+ }
260+ HtmlLexContext :: InsideTagAstro => {
261+ p. re_lex ( HtmlReLexContext :: InsideTagAstro ) ;
262+ }
263+ _ => { }
248264 }
249265
250266 AttributeList . parse_list ( p) ;
@@ -318,8 +334,8 @@ fn parse_closing_tag(p: &mut HtmlParser) -> ParsedSyntax {
318334 return Absent ;
319335 }
320336 let m = p. start ( ) ;
321- p. bump_with_context ( T ! [ <] , HtmlLexContext :: InsideTag ) ;
322- p. bump_with_context ( T ! [ /] , HtmlLexContext :: InsideTag ) ;
337+ p. bump_with_context ( T ! [ <] , inside_tag_context ( p ) ) ;
338+ p. bump_with_context ( T ! [ /] , inside_tag_context ( p ) ) ;
323339 let should_be_self_closing = VOID_ELEMENTS
324340 . iter ( )
325341 . any ( |tag| tag. eq_ignore_ascii_case ( p. cur_text ( ) ) )
0 commit comments