diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 8785bf686047d..438f29066686e 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -810,17 +810,9 @@ impl<'a> MemberExpression<'a> { pub fn static_property_name(&self) -> Option<&str> { match self { - MemberExpression::ComputedMemberExpression(expr) => match &expr.expression { - Expression::StringLiteral(lit) => Some(&lit.value), - Expression::TemplateLiteral(lit) => { - if lit.expressions.is_empty() && lit.quasis.len() == 1 { - Some(&lit.quasis[0].value.raw) - } else { - None - } - } - _ => None, - }, + MemberExpression::ComputedMemberExpression(expr) => { + expr.static_property_name().map(|name| name.as_str()) + } MemberExpression::StaticMemberExpression(expr) => Some(expr.property.name.as_str()), MemberExpression::PrivateFieldExpression(_) => None, } @@ -883,6 +875,20 @@ pub struct ComputedMemberExpression<'a> { pub optional: bool, // for optional chaining } +impl<'a> ComputedMemberExpression<'a> { + pub fn static_property_name(&self) -> Option> { + match &self.expression { + Expression::StringLiteral(lit) => Some(lit.value.clone()), + Expression::TemplateLiteral(lit) + if lit.expressions.is_empty() && lit.quasis.len() == 1 => + { + Some(lit.quasis[0].value.raw.clone()) + } + _ => None, + } + } +} + /// `MemberExpression[?Yield, ?Await] . IdentifierName` #[visited_node] #[derive(Debug, Hash)] diff --git a/crates/oxc_transformer/src/react/display_name.rs b/crates/oxc_transformer/src/react/display_name.rs index 299ca3a26bc19..8433efe9d3567 100644 --- a/crates/oxc_transformer/src/react/display_name.rs +++ b/crates/oxc_transformer/src/react/display_name.rs @@ -37,21 +37,22 @@ impl<'a> ReactDisplayName<'a> { let name = ctx.find_ancestor(|ancestor| { match ancestor { // `foo = React.createClass({})` - Ancestor::AssignmentExpressionRight(assign_expr) => match &assign_expr.left() { + Ancestor::AssignmentExpressionRight(assign_expr) => match assign_expr.left() { AssignmentTarget::AssignmentTargetIdentifier(ident) => { FinderRet::Found(ident.name.clone()) } - target => { - if let Some(target) = target.as_member_expression() { - if let Some(name) = target.static_property_name() { - FinderRet::Found(ctx.ast.new_atom(name)) - } else { - FinderRet::Stop - } - } else { - FinderRet::Stop + AssignmentTarget::StaticMemberExpression(expr) => { + FinderRet::Found(expr.property.name.clone()) + } + // Babel does not handle computed member expressions e.g. `foo["bar"]`, + // so we diverge from Babel here, but that's probably an improvement + AssignmentTarget::ComputedMemberExpression(expr) => { + match expr.static_property_name() { + Some(name) => FinderRet::Found(name), + None => FinderRet::Stop, } } + _ => FinderRet::Stop, }, // `let foo = React.createClass({})` Ancestor::VariableDeclaratorInit(declarator) => match &declarator.id().kind { @@ -62,6 +63,9 @@ impl<'a> ReactDisplayName<'a> { }, // `{foo: React.createClass({})}` Ancestor::ObjectPropertyValue(prop) => { + // Babel only handles static identifiers e.g. `{foo: React.createClass({})}`, + // whereas we also handle e.g. `{"foo-bar": React.createClass({})}`, + // so we diverge from Babel here, but that's probably an improvement if let Some(name) = prop.key().static_name() { FinderRet::Found(ctx.ast.new_atom(&name)) } else {