Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(transformer): TS transform generate do not copy statements #3832

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,17 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_method_definition(def, ctx);
self.x0_typescript.transform_method_definition(def);
}

fn exit_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_method_definition_on_exit(def);
self.x0_typescript.transform_method_definition_on_exit(def, ctx);
}

fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, _ctx: &mut TraverseCtx<'a>) {
Expand All @@ -238,8 +238,8 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x3_es2015.enter_statements(stmts);
}

fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statements_on_exit(stmts);
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statements_on_exit(stmts, ctx);
self.x3_es2015.exit_statements(stmts);
}

Expand Down
111 changes: 65 additions & 46 deletions crates/oxc_transformer/src/typescript/annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

use std::rc::Rc;

use oxc_allocator::Vec;
use oxc_allocator::Vec as ArenaVec;
use oxc_ast::ast::*;
use oxc_span::{Atom, GetSpan, SPAN};
use oxc_syntax::{operator::AssignmentOperator, reference::ReferenceFlag};
use oxc_span::{Atom, GetSpan, Span, SPAN};
use oxc_syntax::{operator::AssignmentOperator, reference::ReferenceFlag, symbol::SymbolId};
use oxc_traverse::TraverseCtx;
use rustc_hash::FxHashSet;

Expand All @@ -16,7 +16,7 @@ pub struct TypeScriptAnnotations<'a> {
options: Rc<TypeScriptOptions>,
ctx: Ctx<'a>,
/// Assignments to be added to the constructor body
assignments: Vec<'a, Statement<'a>>,
assignments: Vec<Assignment<'a>>,
has_super_call: bool,

has_jsx_element: bool,
Expand All @@ -42,7 +42,7 @@ impl<'a> TypeScriptAnnotations<'a> {

Self {
has_super_call: false,
assignments: ctx.ast.new_vec(),
assignments: vec![],
options,
ctx,
has_jsx_element: false,
Expand All @@ -60,35 +60,6 @@ impl<'a> TypeScriptAnnotations<'a> {
|| self.has_jsx_fragment && name == self.jsx_fragment_import_name
}

// Creates `this.name = name`
fn create_this_property_assignment(
&self,
id: &BindingIdentifier<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Statement<'a> {
let ast = self.ctx.ast;

let symbol_id = id.symbol_id.get().unwrap();
let reference_id =
ctx.create_bound_reference(id.name.to_compact_str(), symbol_id, ReferenceFlag::Read);
let id = IdentifierReference::new_read(id.span, id.name.clone(), Some(reference_id));

ast.expression_statement(
SPAN,
ast.assignment_expression(
SPAN,
AssignmentOperator::Assign,
ast.simple_assignment_target_member_expression(ast.static_member(
SPAN,
ast.this_expression(SPAN),
IdentifierName::new(id.span, id.name.clone()),
false,
)),
ast.identifier_reference_expression(id),
),
)
}

// Remove type only imports/exports
pub fn transform_program_on_exit(
&mut self,
Expand Down Expand Up @@ -306,19 +277,18 @@ impl<'a> TypeScriptAnnotations<'a> {
elem.type_parameters = None;
}

pub fn transform_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
// Collects parameter properties so that we can add an assignment
// for each of them in the constructor body.
if def.kind == MethodDefinitionKind::Constructor {
for param in def.value.params.items.as_mut_slice() {
if param.is_public() {
if let Some(id) = param.pattern.get_binding_identifier() {
let assignment = self.create_this_property_assignment(id, ctx);
self.assignments.push(assignment);
self.assignments.push(Assignment {
span: id.span,
name: id.name.clone(),
symbol_id: id.symbol_id.get().unwrap(),
});
}
}

Expand All @@ -333,7 +303,11 @@ impl<'a> TypeScriptAnnotations<'a> {
def.r#override = false;
}

pub fn transform_method_definition_on_exit(&mut self, def: &mut MethodDefinition<'a>) {
pub fn transform_method_definition_on_exit(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'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
Expand All @@ -350,7 +324,11 @@ impl<'a> TypeScriptAnnotations<'a> {
)
})
.statements
.extend(self.assignments.drain(..));
.extend(
self.assignments
.drain(..)
.map(|assignment| assignment.create_this_property_assignment(ctx)),
);
}
}
}
Expand Down Expand Up @@ -379,7 +357,7 @@ impl<'a> TypeScriptAnnotations<'a> {
def.type_annotation = None;
}

pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
pub fn transform_statements(&mut self, stmts: &mut ArenaVec<'a, Statement<'a>>) {
// Remove declare declaration
stmts.retain(|stmt| match stmt {
match_declaration!(Statement) => {
Expand All @@ -389,7 +367,11 @@ impl<'a> TypeScriptAnnotations<'a> {
});
}

pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
pub fn transform_statements_on_exit(
&mut self,
stmts: &mut ArenaVec<'a, Statement<'a>>,
ctx: &mut TraverseCtx<'a>,
) {
// Remove TS specific statements
stmts.retain(|stmt| match stmt {
Statement::ExpressionStatement(s) => !s.expression.is_typescript_syntax(),
Expand All @@ -410,7 +392,11 @@ impl<'a> TypeScriptAnnotations<'a> {
let is_super_call = matches!(stmt, Statement::ExpressionStatement(ref stmt) if stmt.expression.is_super_call_expression());
new_stmts.push(stmt);
if is_super_call {
new_stmts.extend(self.ctx.ast.copy(&self.assignments));
new_stmts.extend(
self.assignments
.iter()
.map(|assignment| assignment.create_this_property_assignment(ctx)),
);
}
}
self.has_super_call = true;
Expand Down Expand Up @@ -528,3 +514,36 @@ impl<'a> TypeScriptAnnotations<'a> {
self.is_jsx_imports(name)
}
}

struct Assignment<'a> {
span: Span,
name: Atom<'a>,
symbol_id: SymbolId,
}

impl<'a> Assignment<'a> {
// Creates `this.name = name`
fn create_this_property_assignment(&self, ctx: &mut TraverseCtx<'a>) -> Statement<'a> {
let reference_id = ctx.create_bound_reference(
self.name.to_compact_str(),
self.symbol_id,
ReferenceFlag::Read,
);
let id = IdentifierReference::new_read(self.span, self.name.clone(), Some(reference_id));

ctx.ast.expression_statement(
SPAN,
ctx.ast.assignment_expression(
SPAN,
AssignmentOperator::Assign,
ctx.ast.simple_assignment_target_member_expression(ctx.ast.static_member(
SPAN,
ctx.ast.this_expression(SPAN),
IdentifierName::new(self.span, self.name.clone()),
false,
)),
ctx.ast.identifier_reference_expression(id),
),
)
}
}
20 changes: 12 additions & 8 deletions crates/oxc_transformer/src/typescript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,16 @@ impl<'a> TypeScript<'a> {
self.annotations.transform_jsx_opening_element(elem);
}

pub fn transform_method_definition(
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
self.annotations.transform_method_definition(def);
}

pub fn transform_method_definition_on_exit(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_method_definition(def, ctx);
}

pub fn transform_method_definition_on_exit(&mut self, def: &mut MethodDefinition<'a>) {
self.annotations.transform_method_definition_on_exit(def);
self.annotations.transform_method_definition_on_exit(def, ctx);
}

pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
Expand All @@ -151,8 +151,12 @@ impl<'a> TypeScript<'a> {
self.annotations.transform_statements(stmts);
}

pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
self.annotations.transform_statements_on_exit(stmts);
pub fn transform_statements_on_exit(
&mut self,
stmts: &mut Vec<'a, Statement<'a>>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_statements_on_exit(stmts, ctx);
}

pub fn transform_statement(&mut self, stmt: &mut Statement<'a>, ctx: &TraverseCtx<'a>) {
Expand Down
Loading