From 3c55da6e015963ac6d04c32f22e7495d7efdd8b3 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Thu, 23 May 2024 12:06:45 +0800 Subject: [PATCH] feat(transformer/typescript): if the binding exists, the identifier reference is not renamed --- crates/oxc_transformer/src/lib.rs | 4 +-- crates/oxc_transformer/src/typescript/enum.rs | 29 ++++++++++++++----- crates/oxc_transformer/src/typescript/mod.rs | 8 ++--- tasks/transform_conformance/babel.snap.md | 5 ++-- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index d0a0f3ba8114c3..f3ca7ed6df3ab2 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -234,8 +234,8 @@ impl<'a> Traverse<'a> for Transformer<'a> { self.x0_typescript.transform_identifier_reference(ident, ctx); } - fn enter_statement(&mut self, stmt: &mut Statement<'a>, _ctx: &mut TraverseCtx<'a>) { - self.x0_typescript.transform_statement(stmt); + fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) { + self.x0_typescript.transform_statement(stmt, ctx); } fn enter_declaration(&mut self, decl: &mut Declaration<'a>, _ctx: &mut TraverseCtx<'a>) { diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs index bf409c2f802375..bc2cd5e5fcafe1 100644 --- a/crates/oxc_transformer/src/typescript/enum.rs +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -7,6 +7,7 @@ use oxc_syntax::{ number::{NumberBase, ToJsInt32, ToJsString}, operator::{AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator}, }; +use oxc_traverse::TraverseCtx; use rustc_hash::FxHashMap; use crate::context::Ctx; @@ -37,6 +38,7 @@ impl<'a> TypeScriptEnum<'a> { &mut self, decl: &Box<'a, TSEnumDeclaration<'a>>, is_export: bool, + ctx: &TraverseCtx<'a>, ) -> Option> { if decl.modifiers.contains(ModifierKind::Declare) { return None; @@ -61,7 +63,7 @@ impl<'a> TypeScriptEnum<'a> { // Foo[Foo["X"] = 0] = "X"; let enum_name = decl.id.name.clone(); let is_already_declared = self.enums.contains_key(&enum_name); - let statements = self.transform_ts_enum_members(&decl.members, &enum_name); + let statements = self.transform_ts_enum_members(&decl.members, &enum_name, ctx); let body = self.ctx.ast.function_body(decl.span, self.ctx.ast.new_vec(), statements); let r#type = FunctionType::FunctionExpression; let callee = self.ctx.ast.plain_function(r#type, SPAN, None, params, Some(body)); @@ -128,6 +130,7 @@ impl<'a> TypeScriptEnum<'a> { &mut self, members: &Vec<'a, TSEnumMember<'a>>, enum_name: &Atom<'a>, + ctx: &TraverseCtx<'a>, ) -> Vec<'a, Statement<'a>> { let mut statements = self.ctx.ast.new_vec(); let mut prev_constant_value = Some(ConstantValue::Number(-1.0)); @@ -153,12 +156,24 @@ impl<'a> TypeScriptEnum<'a> { None => { prev_constant_value = None; let mut new_initializer = self.ctx.ast.copy(initializer); - IdentifierReferenceRename::new( - enum_name.clone(), - previous_enum_members.clone(), - &self.ctx, - ) - .visit_expression(&mut new_initializer); + + // If the initializer is a binding identifier, + // and it is not a binding in the current scope and parent scopes, + // we need to rename it to the enum name. e.g. `d = c` to `d = A.c` + // same behavior in https://github.com/babel/babel/blob/610897a9a96c5e344e77ca9665df7613d2f88358/packages/babel-plugin-transform-typescript/src/enum.ts#L145-L150 + let has_binding = matches!( + &new_initializer, + Expression::Identifier(ident) if ctx.scopes().has_binding(ctx.current_scope_id(), &ident.name) + ); + if !has_binding { + IdentifierReferenceRename::new( + enum_name.clone(), + previous_enum_members.clone(), + &self.ctx, + ) + .visit_expression(&mut new_initializer); + } + new_initializer } Some(constant_value) => { diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index 776f35ac519043..d9835497855aa7 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -136,11 +136,11 @@ impl<'a> TypeScript<'a> { self.annotations.transform_statements_on_exit(stmts); } - pub fn transform_statement(&mut self, stmt: &mut Statement<'a>) { + pub fn transform_statement(&mut self, stmt: &mut Statement<'a>, ctx: &TraverseCtx<'a>) { let new_stmt = match stmt { match_declaration!(Statement) => { if let Declaration::TSEnumDeclaration(ts_enum_decl) = &stmt.to_declaration() { - self.r#enum.transform_ts_enum(ts_enum_decl, false) + self.r#enum.transform_ts_enum(ts_enum_decl, false, ctx) } else { None } @@ -150,7 +150,7 @@ impl<'a> TypeScript<'a> { stmt.to_module_declaration_mut() { if let Some(Declaration::TSEnumDeclaration(ts_enum_decl)) = &decl.declaration { - self.r#enum.transform_ts_enum(ts_enum_decl, true) + self.r#enum.transform_ts_enum(ts_enum_decl, true, ctx) } else { None } @@ -180,7 +180,7 @@ impl<'a> TypeScript<'a> { pub fn transform_identifier_reference( &mut self, ident: &mut IdentifierReference<'a>, - ctx: &TraverseCtx, + ctx: &TraverseCtx<'a>, ) { if !ctx.parent().is_ts_interface_heritage() && !ctx.parent().is_ts_type_reference() { self.reference_collector.visit_identifier_reference(ident); diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 9f9096a3701cfe..d39d02c684956f 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,6 +1,6 @@ commit: 4bd1b2c2 -Passed: 309/351 +Passed: 310/351 # All Passed: * babel-preset-react @@ -21,12 +21,11 @@ Passed: 309/351 * opts/optimizeConstEnums/input.ts * opts/rewriteImportExtensions/input.ts -# babel-plugin-transform-typescript (123/154) +# babel-plugin-transform-typescript (124/154) * enum/mix-references/input.ts * enum/scoped/input.ts * enum/ts5.0-const-foldable/input.ts * exports/declared-types/input.ts -* imports/enum-value/input.ts * imports/type-only-export-specifier-2/input.ts * namespace/contentious-names/input.ts * namespace/empty-removed/input.ts