diff --git a/crates/oxc_transformer/src/react/refresh.rs b/crates/oxc_transformer/src/react/refresh.rs index bb85901e0b4ac..a576a4e110ceb 100644 --- a/crates/oxc_transformer/src/react/refresh.rs +++ b/crates/oxc_transformer/src/react/refresh.rs @@ -2,7 +2,7 @@ use std::{cell::Cell, iter::once}; use base64::prelude::{Engine, BASE64_STANDARD}; use oxc_allocator::CloneIn; -use oxc_ast::{ast::*, match_expression, match_member_expression, AstBuilder}; +use oxc_ast::{ast::*, match_expression, AstBuilder}; use oxc_semantic::{Reference, ReferenceFlags, ScopeId, SymbolFlags, SymbolId}; use oxc_span::{Atom, GetSpan, SPAN}; use oxc_syntax::operator::AssignmentOperator; @@ -384,14 +384,10 @@ impl<'a> Traverse<'a> for ReactRefresh<'a> { return; } - let name = match &call_expr.callee { - Expression::Identifier(ident) => Some(ident.name.clone()), - Expression::StaticMemberExpression(ref member) => Some(member.property.name.clone()), - _ => None, - }; - - let Some(hook_name) = name else { - return; + let hook_name = match &call_expr.callee { + Expression::Identifier(ident) => ident.name.clone(), + Expression::StaticMemberExpression(ref member) => member.property.name.clone(), + _ => return, }; if !is_use_hook_name(&hook_name) { @@ -399,50 +395,47 @@ impl<'a> Traverse<'a> for ReactRefresh<'a> { } if !is_builtin_hook(&hook_name) { - let (binding_name, hook_name) = match &call_expr.callee { - Expression::Identifier(ident) => (ident.name.clone(), None), - callee @ match_member_expression!(Expression) => { - let member_expr = callee.to_member_expression(); - match member_expr.object() { - Expression::Identifier(ident) => { - (ident.name.clone(), Some(hook_name.clone())) - } - _ => unreachable!(), + let (binding_name, is_member_expression) = match &call_expr.callee { + Expression::Identifier(ident) => (Some(ident.name.clone()), false), + Expression::StaticMemberExpression(member) => { + if let Expression::Identifier(object) = member.get_first_object() { + (Some(object.name.clone()), true) + } else { + (None, false) } } _ => unreachable!(), }; - let callees = self.non_builtin_hooks_callee.entry(current_scope_id).or_default(); - - callees.push( - ctx.scopes() - .find_binding( - ctx.scopes().get_parent_id(ctx.current_scope_id()).unwrap(), - binding_name.as_str(), - ) - .map(|symbol_id| { - let ident = ctx.create_reference_id( - SPAN, - binding_name.clone(), - Some(symbol_id), - ReferenceFlags::Read, - ); - - let mut expr = self.ctx.ast.expression_from_identifier_reference(ident); - - if let Some(hook_name) = hook_name { - // binding_name.hook_name - expr = Expression::from(self.ctx.ast.member_expression_static( + if let Some(binding_name) = binding_name { + self.non_builtin_hooks_callee.entry(current_scope_id).or_default().push( + ctx.scopes() + .find_binding( + ctx.scopes().get_parent_id(ctx.current_scope_id()).unwrap(), + binding_name.as_str(), + ) + .map(|symbol_id| { + let ident = ctx.create_reference_id( SPAN, - expr, - self.ctx.ast.identifier_name(SPAN, hook_name), - false, - )); - } - expr - }), - ); + binding_name, + Some(symbol_id), + ReferenceFlags::Read, + ); + let mut expr = self.ctx.ast.expression_from_identifier_reference(ident); + + if is_member_expression { + // binding_name.hook_name + expr = Expression::from(self.ctx.ast.member_expression_static( + SPAN, + expr, + self.ctx.ast.identifier_name(SPAN, hook_name.clone()), + false, + )); + } + expr + }), + ); + } } let key = if let Ancestor::VariableDeclaratorInit(declarator) = ctx.parent() { diff --git a/tasks/transform_conformance/oxc.snap.md b/tasks/transform_conformance/oxc.snap.md index b433fdb20feb4..f05bdfdc64cd0 100644 --- a/tasks/transform_conformance/oxc.snap.md +++ b/tasks/transform_conformance/oxc.snap.md @@ -1,6 +1,6 @@ commit: 3bcfee23 -Passed: 18/51 +Passed: 19/52 # All Passed: * babel-plugin-transform-nullish-coalescing-operator @@ -167,7 +167,7 @@ rebuilt : SymbolId(2): [] x Output mismatch -# babel-plugin-transform-react-jsx (4/29) +# babel-plugin-transform-react-jsx (5/30) * refresh/can-handle-implicit-arrow-returns/input.jsx Reference flags mismatch: after transform: ReferenceId(18): ReferenceFlags(Write) diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/input.jsx b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/input.jsx new file mode 100644 index 0000000000000..a90555cc1a58c --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/input.jsx @@ -0,0 +1,3 @@ +export function Bar () { + A.B.C.useHook() +} \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/output.js new file mode 100644 index 0000000000000..43f61f030a1ce --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/refresh/nested-member-expression-with-hooks/output.js @@ -0,0 +1,9 @@ +var _s = $RefreshSig$(); +export function Bar() { + _s(); + A.B.C.useHook(); +} +_s(Bar, "useHook{}", true); +_c = Bar; +var _c; +$RefreshReg$(_c, "Bar");