mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(transformer/typescript): insert this assignment after the super call (#3018)
This commit is contained in:
parent
5d89e75e48
commit
e14ac17c72
5 changed files with 106 additions and 21 deletions
|
|
@ -275,6 +275,10 @@ impl<'a> Expression<'a> {
|
|||
matches!(self, Expression::CallExpression(_))
|
||||
}
|
||||
|
||||
pub fn is_super_call_expression(&self) -> bool {
|
||||
matches!(self, Expression::CallExpression(expr) if matches!(&expr.callee, Expression::Super(_)))
|
||||
}
|
||||
|
||||
pub fn is_call_like_expression(&self) -> bool {
|
||||
self.is_call_expression()
|
||||
&& matches!(self, Expression::NewExpression(_) | Expression::ImportExpression(_))
|
||||
|
|
@ -1910,6 +1914,12 @@ pub struct FormalParameter<'a> {
|
|||
pub decorators: Vec<'a, Decorator<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> FormalParameter<'a> {
|
||||
pub fn is_public(&self) -> bool {
|
||||
matches!(self.accessibility, Some(TSAccessibility::Public))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||
pub enum FormalParameterKind {
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
|||
self.x0_typescript.transform_method_definition(def);
|
||||
|
||||
walk_mut::walk_method_definition_mut(self, def);
|
||||
|
||||
self.x0_typescript.transform_method_definition_on_exit(def);
|
||||
}
|
||||
|
||||
fn visit_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||
|
|
@ -216,4 +218,9 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
|||
self.x0_typescript.transform_declaration(decl);
|
||||
walk_mut::walk_declaration_mut(self, decl);
|
||||
}
|
||||
|
||||
fn visit_if_statement(&mut self, stmt: &mut IfStatement<'a>) {
|
||||
self.x0_typescript.transform_if_statement(stmt);
|
||||
walk_mut::walk_if_statement_mut(self, stmt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,19 @@ pub struct TypeScriptAnnotations<'a> {
|
|||
#[allow(dead_code)]
|
||||
options: Rc<TypeScriptOptions>,
|
||||
ctx: Ctx<'a>,
|
||||
/// Assignments to be added to the constructor body
|
||||
assignments: Vec<'a, Statement<'a>>,
|
||||
has_super_call: bool,
|
||||
}
|
||||
|
||||
impl<'a> TypeScriptAnnotations<'a> {
|
||||
pub fn new(options: &Rc<TypeScriptOptions>, ctx: &Ctx<'a>) -> Self {
|
||||
Self { options: Rc::clone(options), ctx: Rc::clone(ctx) }
|
||||
Self {
|
||||
has_super_call: false,
|
||||
assignments: ctx.ast.new_vec(),
|
||||
options: Rc::clone(options),
|
||||
ctx: Rc::clone(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
// Convert `export = expr` into `module.exports = expr`
|
||||
|
|
@ -237,35 +245,44 @@ impl<'a> TypeScriptAnnotations<'a> {
|
|||
}
|
||||
|
||||
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
|
||||
def.accessibility = None;
|
||||
def.optional = false;
|
||||
def.r#override = false;
|
||||
|
||||
// Collects parameter properties so that we can add an assignment
|
||||
// for each of them in the constructor body.
|
||||
if def.kind == MethodDefinitionKind::Constructor {
|
||||
let mut assigns = self.ctx.ast.new_vec();
|
||||
|
||||
for param in &def.value.params.items {
|
||||
if param.pattern.type_annotation.is_none() {
|
||||
if !param.is_public() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(id) = param.pattern.get_identifier() {
|
||||
assigns.push(self.create_this_property_assignment(id));
|
||||
let assignment = self.create_this_property_assignment(id);
|
||||
self.assignments.push(assignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !assigns.is_empty() {
|
||||
def.accessibility = None;
|
||||
def.optional = false;
|
||||
def.r#override = false;
|
||||
}
|
||||
|
||||
pub fn transform_method_definition_on_exit(&mut self, def: &mut MethodDefinition<'a>) {
|
||||
if def.kind == MethodDefinitionKind::Constructor && !self.assignments.is_empty() {
|
||||
// When the constructor doesn't have a super call,
|
||||
// we simply add assignments to the bottom of the function body
|
||||
if self.has_super_call {
|
||||
self.assignments.clear();
|
||||
} else {
|
||||
def.value
|
||||
.body
|
||||
.get_or_insert(self.ctx.ast.function_body(
|
||||
SPAN,
|
||||
self.ctx.ast.new_vec(),
|
||||
self.ctx.ast.new_vec(),
|
||||
))
|
||||
.get_or_insert_with(|| {
|
||||
self.ctx.ast.function_body(
|
||||
SPAN,
|
||||
self.ctx.ast.new_vec(),
|
||||
self.ctx.ast.new_vec(),
|
||||
)
|
||||
})
|
||||
.statements
|
||||
.extend(assigns);
|
||||
.extend(self.assignments.drain(..));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -302,6 +319,52 @@ impl<'a> TypeScriptAnnotations<'a> {
|
|||
// Ignore ModuleDeclaration as it's handled in the program
|
||||
_ => true,
|
||||
});
|
||||
|
||||
// Add assignments after super calls
|
||||
if !self.assignments.is_empty() {
|
||||
let mut super_indexes = vec![];
|
||||
for (index, stmt) in stmts.iter().rev().enumerate() {
|
||||
if matches!(stmt, Statement::ExpressionStatement(stmt) if stmt.expression.is_super_call_expression())
|
||||
{
|
||||
super_indexes.push(index);
|
||||
}
|
||||
}
|
||||
if !super_indexes.is_empty() {
|
||||
self.has_super_call = true;
|
||||
for index in super_indexes.iter().rev() {
|
||||
stmts.splice((index + 1)..=*index, self.ctx.ast.copy(&self.assignments));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform if statement's consequent and alternate to block statements if they are super calls
|
||||
/// ```ts
|
||||
/// if (true) super() else super();
|
||||
/// // to
|
||||
/// if (true) { super() } else { super() }
|
||||
/// ```
|
||||
pub fn transform_if_statement(&mut self, stmt: &mut IfStatement<'a>) {
|
||||
if !self.assignments.is_empty() {
|
||||
if matches!(&stmt.consequent, Statement::ExpressionStatement(expr) if expr.expression.is_super_call_expression())
|
||||
{
|
||||
stmt.consequent =
|
||||
self.ctx.ast.block_statement(self.ctx.ast.block(
|
||||
SPAN,
|
||||
self.ctx.ast.new_vec_single(self.ctx.ast.copy(&stmt.consequent)),
|
||||
));
|
||||
}
|
||||
if let Some(alternate) = &stmt.alternate {
|
||||
if matches!(alternate, Statement::ExpressionStatement(expr) if expr.expression.is_super_call_expression())
|
||||
{
|
||||
stmt.alternate =
|
||||
Some(self.ctx.ast.block_statement(self.ctx.ast.block(
|
||||
SPAN,
|
||||
self.ctx.ast.new_vec_single(self.ctx.ast.copy(alternate)),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_tagged_template_expression(
|
||||
|
|
|
|||
|
|
@ -120,6 +120,10 @@ impl<'a> TypeScript<'a> {
|
|||
self.annotations.transform_method_definition(def);
|
||||
}
|
||||
|
||||
pub fn transform_method_definition_on_exit(&mut self, def: &mut MethodDefinition<'a>) {
|
||||
self.annotations.transform_method_definition_on_exit(def);
|
||||
}
|
||||
|
||||
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||
self.annotations.transform_new_expression(expr);
|
||||
}
|
||||
|
|
@ -136,6 +140,10 @@ impl<'a> TypeScript<'a> {
|
|||
self.annotations.transform_statements_on_exit(stmts);
|
||||
}
|
||||
|
||||
pub fn transform_if_statement(&mut self, stmt: &mut IfStatement<'a>) {
|
||||
self.annotations.transform_if_statement(stmt);
|
||||
}
|
||||
|
||||
pub fn transform_tagged_template_expression(
|
||||
&mut self,
|
||||
expr: &mut TaggedTemplateExpression<'a>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Passed: 148/209
|
||||
Passed: 151/209
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-react-jsx-source
|
||||
|
|
@ -17,12 +17,9 @@ Passed: 148/209
|
|||
* opts/optimizeConstEnums/input.ts
|
||||
* opts/rewriteImportExtensions/input.ts
|
||||
|
||||
# babel-plugin-transform-typescript (92/139)
|
||||
# babel-plugin-transform-typescript (95/139)
|
||||
* class/accessor-allowDeclareFields-false/input.ts
|
||||
* class/accessor-allowDeclareFields-true/input.ts
|
||||
* class/parameter-properties/input.ts
|
||||
* class/parameter-properties-late-super/input.ts
|
||||
* class/parameter-properties-with-super/input.ts
|
||||
* exports/declared-types/input.ts
|
||||
* exports/export-const-enums/input.ts
|
||||
* exports/export-type-star-from/input.ts
|
||||
|
|
|
|||
Loading…
Reference in a new issue