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(_))
|
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 {
|
pub fn is_call_like_expression(&self) -> bool {
|
||||||
self.is_call_expression()
|
self.is_call_expression()
|
||||||
&& matches!(self, Expression::NewExpression(_) | Expression::ImportExpression(_))
|
&& matches!(self, Expression::NewExpression(_) | Expression::ImportExpression(_))
|
||||||
|
|
@ -1910,6 +1914,12 @@ pub struct FormalParameter<'a> {
|
||||||
pub decorators: Vec<'a, Decorator<'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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||||
pub enum FormalParameterKind {
|
pub enum FormalParameterKind {
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,8 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
||||||
self.x0_typescript.transform_method_definition(def);
|
self.x0_typescript.transform_method_definition(def);
|
||||||
|
|
||||||
walk_mut::walk_method_definition_mut(self, 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>) {
|
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);
|
self.x0_typescript.transform_declaration(decl);
|
||||||
walk_mut::walk_declaration_mut(self, 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)]
|
#[allow(dead_code)]
|
||||||
options: Rc<TypeScriptOptions>,
|
options: Rc<TypeScriptOptions>,
|
||||||
ctx: Ctx<'a>,
|
ctx: Ctx<'a>,
|
||||||
|
/// Assignments to be added to the constructor body
|
||||||
|
assignments: Vec<'a, Statement<'a>>,
|
||||||
|
has_super_call: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TypeScriptAnnotations<'a> {
|
impl<'a> TypeScriptAnnotations<'a> {
|
||||||
pub fn new(options: &Rc<TypeScriptOptions>, ctx: &Ctx<'a>) -> Self {
|
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`
|
// 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>) {
|
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
|
// Collects parameter properties so that we can add an assignment
|
||||||
// for each of them in the constructor body.
|
// for each of them in the constructor body.
|
||||||
if def.kind == MethodDefinitionKind::Constructor {
|
if def.kind == MethodDefinitionKind::Constructor {
|
||||||
let mut assigns = self.ctx.ast.new_vec();
|
|
||||||
|
|
||||||
for param in &def.value.params.items {
|
for param in &def.value.params.items {
|
||||||
if param.pattern.type_annotation.is_none() {
|
if !param.is_public() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = param.pattern.get_identifier() {
|
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
|
def.value
|
||||||
.body
|
.body
|
||||||
.get_or_insert(self.ctx.ast.function_body(
|
.get_or_insert_with(|| {
|
||||||
SPAN,
|
self.ctx.ast.function_body(
|
||||||
self.ctx.ast.new_vec(),
|
SPAN,
|
||||||
self.ctx.ast.new_vec(),
|
self.ctx.ast.new_vec(),
|
||||||
))
|
self.ctx.ast.new_vec(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.statements
|
.statements
|
||||||
.extend(assigns);
|
.extend(self.assignments.drain(..));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,6 +319,52 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
// Ignore ModuleDeclaration as it's handled in the program
|
// Ignore ModuleDeclaration as it's handled in the program
|
||||||
_ => true,
|
_ => 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(
|
pub fn transform_tagged_template_expression(
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,10 @@ impl<'a> TypeScript<'a> {
|
||||||
self.annotations.transform_method_definition(def);
|
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>) {
|
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||||
self.annotations.transform_new_expression(expr);
|
self.annotations.transform_new_expression(expr);
|
||||||
}
|
}
|
||||||
|
|
@ -136,6 +140,10 @@ impl<'a> TypeScript<'a> {
|
||||||
self.annotations.transform_statements_on_exit(stmts);
|
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(
|
pub fn transform_tagged_template_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: &mut TaggedTemplateExpression<'a>,
|
expr: &mut TaggedTemplateExpression<'a>,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Passed: 148/209
|
Passed: 151/209
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-react-jsx-source
|
* babel-plugin-transform-react-jsx-source
|
||||||
|
|
@ -17,12 +17,9 @@ Passed: 148/209
|
||||||
* opts/optimizeConstEnums/input.ts
|
* opts/optimizeConstEnums/input.ts
|
||||||
* opts/rewriteImportExtensions/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-false/input.ts
|
||||||
* class/accessor-allowDeclareFields-true/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/declared-types/input.ts
|
||||||
* exports/export-const-enums/input.ts
|
* exports/export-const-enums/input.ts
|
||||||
* exports/export-type-star-from/input.ts
|
* exports/export-type-star-from/input.ts
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue