@@ -149,19 +149,21 @@ impl<'a> ParserImpl<'a> {
149149 return JSXElementName :: dummy ( self . ast . allocator ) ;
150150 }
151151
152- // References begin with a capital letter, `_` or `$` e.g. `<Foo>`, `<_foo>`, `<$foo>`.
152+ // Determine if this JSX element name is a reference (component) or an intrinsic element.
153+ // References (components) are:
154+ // - ASCII names that start with uppercase letter, `_` or `$`: `<Foo>`, `<_foo>`, `<$foo>`
155+ // - All non-ASCII names (e.g., Unicode identifiers like `<테스트>`)
156+ // - Names without hyphens (hyphenated names like `<my-element>` are custom elements)
153157 // https://babeljs.io/repl#?code_lz=DwMQ9mAED0B8DcAoYAzCMHIPpqnJwAJLhkkA&presets=react
154- // The identifier has already been checked to be valid, so when first char is ASCII, it can only
155- // be `a-z`, `A-Z`, `_` or `$`. But compiler doesn't know that, so we can help it create faster
156- // code by taking that invariant into account.
157- // `b < b'a'` matches `A-Z`, `_` and `$`.
158- // Use a fast path for common case of ASCII characters, to avoid the more expensive
159- // `char::is_uppercase` in most cases.
158+ //
159+ // The identifier has already been validated by the parser, so for ASCII characters
160+ // we know it can only be `a-z`, `A-Z`, `_` or `$`.
161+ // Use a fast path for ASCII to avoid expensive Unicode operations in the common case.
160162 let name = identifier. name . as_str ( ) ;
161163 let is_reference = match name. as_bytes ( ) [ 0 ] {
162- b if b. is_ascii ( ) => b < b'a' ,
163- _ => name . chars ( ) . next ( ) . unwrap ( ) . is_uppercase ( ) ,
164- } ;
164+ b if b. is_ascii ( ) => !b . is_ascii_lowercase ( ) , // Matches A-Z, _, $
165+ _ => true , // Non-ASCII characters are always treated as references
166+ } && !name . contains ( '-' ) ; // Exclude hyphenated custom elements
165167
166168 if is_reference {
167169 let identifier = self . ast . alloc_identifier_reference ( identifier. span , identifier. name ) ;
0 commit comments