mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(transformer/class-properties): transform super call expression that is inside static prop initializer (#7831)
This commit is contained in:
parent
c039a5ae4f
commit
6bc530d2e2
6 changed files with 88 additions and 16 deletions
|
|
@ -244,6 +244,11 @@ impl<'a> Expression<'a> {
|
|||
matches!(self, Expression::CallExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_super(&self) -> bool {
|
||||
matches!(self, Expression::Super(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_super_call_expression(&self) -> bool {
|
||||
matches!(self, Expression::CallExpression(expr) if matches!(&expr.callee, Expression::Super(_)))
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ impl<'a, 'ctx, 'v> VisitMut<'a> for StaticInitializerVisitor<'a, 'ctx, 'v> {
|
|||
}
|
||||
// `object.#prop()`
|
||||
Expression::CallExpression(_) => {
|
||||
self.class_properties.transform_super_call_expression(expr, self.ctx);
|
||||
self.class_properties.transform_call_expression(expr, self.ctx);
|
||||
}
|
||||
// `object.#prop = value`, `object.#prop += value`, `object.#prop ??= value` etc
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//! ES2022: Class Properties
|
||||
//! Transform of `super` expressions.
|
||||
|
||||
use oxc_allocator::Vec as ArenaVec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_span::SPAN;
|
||||
use oxc_traverse::TraverseCtx;
|
||||
|
||||
use crate::Helper;
|
||||
|
|
@ -21,20 +23,21 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
|||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let Expression::StaticMemberExpression(member) = expr else { unreachable!() };
|
||||
if matches!(member.object, Expression::Super(_)) {
|
||||
*expr = self.transform_static_member_expression_impl(member, ctx);
|
||||
if member.object.is_super() {
|
||||
*expr = self.transform_static_member_expression_impl(member, false, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_static_member_expression_impl(
|
||||
&mut self,
|
||||
member: &mut StaticMemberExpression<'a>,
|
||||
is_callee: bool,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Expression<'a> {
|
||||
let property = &member.property;
|
||||
let property =
|
||||
ctx.ast.expression_string_literal(property.span, property.name.clone(), None);
|
||||
self.create_super_prop_get(member.span, property, ctx)
|
||||
self.create_super_prop_get(member.span, property, is_callee, ctx)
|
||||
}
|
||||
|
||||
/// Transform computed member expression where object is `super`.
|
||||
|
|
@ -49,35 +52,87 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
|||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let Expression::ComputedMemberExpression(member) = expr else { unreachable!() };
|
||||
if matches!(member.object, Expression::Super(_)) {
|
||||
*expr = self.transform_computed_member_expression_impl(member, ctx);
|
||||
if member.object.is_super() {
|
||||
*expr = self.transform_computed_member_expression_impl(member, false, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_computed_member_expression_impl(
|
||||
&mut self,
|
||||
member: &mut ComputedMemberExpression<'a>,
|
||||
is_callee: bool,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Expression<'a> {
|
||||
let property = ctx.ast.move_expression(&mut member.expression);
|
||||
self.create_super_prop_get(member.span, property, ctx)
|
||||
self.create_super_prop_get(member.span, property, is_callee, ctx)
|
||||
}
|
||||
|
||||
/// `_superPropGet(_Class, prop, _Class)`
|
||||
/// Transform call expression where callee contains `super`.
|
||||
///
|
||||
/// `super.method()` -> `_superPropGet(_Class, "method", _Class, 2)([])`
|
||||
/// `super.method(1)` -> `_superPropGet(_Class, "method", _Class, 2)([1])`
|
||||
//
|
||||
// `#[inline]` so that compiler sees that `expr` is an `Expression::CallExpression`.
|
||||
#[inline]
|
||||
pub(super) fn transform_super_call_expression(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let Expression::CallExpression(call) = expr else { unreachable!() };
|
||||
let callee = &mut call.callee;
|
||||
match callee {
|
||||
Expression::StaticMemberExpression(member) if member.object.is_super() => {
|
||||
*callee = self.transform_static_member_expression_impl(member, true, ctx);
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) if member.object.is_super() => {
|
||||
*callee = self.transform_computed_member_expression_impl(member, true, ctx);
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
Self::transform_super_call_expression_arguments(&mut call.arguments, ctx);
|
||||
}
|
||||
|
||||
/// [A, B, C] -> [[A, B, C]]
|
||||
pub(super) fn transform_super_call_expression_arguments(
|
||||
arguments: &mut ArenaVec<'a, Argument<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let owned_arguments = ctx.ast.move_vec(arguments);
|
||||
let elements =
|
||||
ctx.ast.vec_from_iter(owned_arguments.into_iter().map(ArrayExpressionElement::from));
|
||||
let array = ctx.ast.expression_array(SPAN, elements, None);
|
||||
arguments.push(Argument::from(array));
|
||||
}
|
||||
|
||||
/// Member:
|
||||
/// `_superPropGet(_Class, prop, _Class)`
|
||||
///
|
||||
/// Callee:
|
||||
/// `_superPropGet(_Class, prop, _Class, 2)`
|
||||
fn create_super_prop_get(
|
||||
&mut self,
|
||||
span: Span,
|
||||
property: Expression<'a>,
|
||||
is_callee: bool,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Expression<'a> {
|
||||
let class_binding = self.get_temp_binding(ctx);
|
||||
// `(_Class, prop, _Class)`
|
||||
let arguments = ctx.ast.vec_from_array([
|
||||
Argument::from(class_binding.create_read_expression(ctx)),
|
||||
Argument::from(property),
|
||||
Argument::from(class_binding.create_read_expression(ctx)),
|
||||
]);
|
||||
// `_superPropGet(_Class, prop, _Class)`
|
||||
|
||||
let ident1 = Argument::from(class_binding.create_read_expression(ctx));
|
||||
let ident2 = Argument::from(class_binding.create_read_expression(ctx));
|
||||
let property = Argument::from(property);
|
||||
|
||||
let arguments = if is_callee {
|
||||
// `(_Class, prop, _Class, 2)`
|
||||
let two = ctx.ast.expression_numeric_literal(SPAN, 2.0, None, NumberBase::Decimal);
|
||||
ctx.ast.vec_from_array([ident1, property, ident2, Argument::from(two)])
|
||||
} else {
|
||||
// `(_Class, prop, _Class)`
|
||||
ctx.ast.vec_from_array([ident1, property, ident2])
|
||||
};
|
||||
|
||||
// `_superPropGet(_Class, prop, _Class)` or `_superPropGet(_Class, prop, _Class, 2)`
|
||||
self.ctx.helper_call_expr(Helper::SuperPropGet, span, arguments, ctx)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
commit: 54a8389f
|
||||
|
||||
Passed: 108/122
|
||||
Passed: 109/123
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-class-static-block
|
||||
|
|
@ -16,7 +16,7 @@ Passed: 108/122
|
|||
* regexp
|
||||
|
||||
|
||||
# babel-plugin-transform-class-properties (9/11)
|
||||
# babel-plugin-transform-class-properties (10/12)
|
||||
* typescript/optional-call/input.ts
|
||||
Symbol reference IDs mismatch for "X":
|
||||
after transform: SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), ReferenceId(11), ReferenceId(16)]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
class C {
|
||||
static foo = super.method();
|
||||
static bar = super.method(1);
|
||||
static bar = super.method(1, 2, 3);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
var _C;
|
||||
class C {}
|
||||
_C = C;
|
||||
babelHelpers.defineProperty(C, "foo", babelHelpers.superPropGet(_C, "method", _C, 2)([]));
|
||||
babelHelpers.defineProperty(C, "bar", babelHelpers.superPropGet(_C, "method", _C, 2)([1]));
|
||||
babelHelpers.defineProperty(C, "bar", babelHelpers.superPropGet(_C, "method", _C, 2)([1, 2, 3]));
|
||||
Loading…
Reference in a new issue