feat(transformer/typescript): support transform namespace (#2075)

This commit is contained in:
Dunqing 2024-01-18 23:15:28 +08:00 committed by GitHub
parent 2e78b918d1
commit 56ca8b6dfe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 369 additions and 4 deletions

View file

@ -891,6 +891,10 @@ impl<'a> Modifiers<'a> {
.as_ref()
.map_or(false, |modifiers| modifiers.iter().any(|modifier| modifier.kind == target))
}
pub fn is_contains_declare(&self) -> bool {
self.contains(ModifierKind::Declare)
}
}
/// Export Assignment in non-module files

View file

@ -181,6 +181,8 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
}
fn visit_statements(&mut self, stmts: &mut oxc_allocator::Vec<'a, Statement<'a>>) {
self.typescript.as_mut().map(|t| t.transform_statements(stmts));
for stmt in stmts.iter_mut() {
self.visit_statement(stmt);
}

View file

@ -49,6 +49,10 @@ impl<'a> TypeScript<'a> {
}
}
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
self.insert_let_decl_for_ts_module_block(stmts);
}
pub fn transform_statement(&mut self, stmt: &mut Statement<'a>) {
let new_stmt = match stmt {
Statement::ModuleDeclaration(module_decl) => {
@ -58,6 +62,13 @@ impl<'a> TypeScript<'a> {
None
}
}
Statement::Declaration(Declaration::TSModuleDeclaration(ts_module_decl)) => {
if ts_module_decl.modifiers.is_contains_declare() {
None
} else {
Some(self.transform_ts_module_block(ts_module_decl))
}
}
_ => None,
};
@ -562,4 +573,128 @@ impl<'a> TypeScript<'a> {
Some(Statement::Declaration(self.ast.move_declaration(declaration)))
}
/// Insert let declaration for ts module block
fn insert_let_decl_for_ts_module_block(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
let mut insert_var_decl = vec![];
for (index, stmt) in stmts.iter().enumerate() {
if let Statement::Declaration(Declaration::TSModuleDeclaration(decl)) = stmt {
if !decl.modifiers.is_contains_declare() {
insert_var_decl.push((index, decl.id.name().clone()));
}
}
}
for (index, name) in insert_var_decl.into_iter().rev() {
let kind = VariableDeclarationKind::Let;
let decls = {
let binding_identifier = BindingIdentifier::new(SPAN, name.clone());
let binding_pattern_kind = self.ast.binding_pattern_identifier(binding_identifier);
let binding = self.ast.binding_pattern(binding_pattern_kind, None, false);
let decl = self.ast.variable_declarator(SPAN, kind, binding, None, false);
self.ast.new_vec_single(decl)
};
let variable_declaration =
self.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty());
let stmt =
Statement::Declaration(Declaration::VariableDeclaration(variable_declaration));
stmts.insert(index, stmt);
}
}
/// ```TypeScript
/// // transform ts module block
/// namespace Foo {
/// }
/// // to
/// let Foo; // this line added in `insert_let_decl_for_ts_module_block`
/// (function (_Foo) {
/// })(Foo || (Foo = {}));
/// ```
fn transform_ts_module_block(
&mut self,
block: &mut Box<'a, TSModuleDeclaration<'a>>,
) -> Statement<'a> {
let body_statements = match &mut block.body {
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
let transformed_module_block = self.transform_ts_module_block(decl);
self.ast.new_vec_single(transformed_module_block)
}
TSModuleDeclarationBody::TSModuleBlock(ts_module_block) => {
self.ast.move_statement_vec(&mut ts_module_block.body)
}
};
let name = block.id.name();
let callee = {
let body = self.ast.function_body(SPAN, self.ast.new_vec(), body_statements);
let params = self.ast.formal_parameters(
SPAN,
FormalParameterKind::FormalParameter,
self.ast.new_vec_single(self.ast.formal_parameter(
SPAN,
self.ast.binding_pattern(
self.ast.binding_pattern_identifier(BindingIdentifier::new(
SPAN,
format!("_{}", name.clone()).into(),
)),
None,
false,
),
None,
false,
self.ast.new_vec(),
)),
None,
);
let function = self.ast.function(
FunctionType::FunctionExpression,
SPAN,
None,
false,
false,
false,
None,
params,
Some(body),
None,
None,
Modifiers::empty(),
);
let function_expr = self.ast.function_expression(function);
self.ast.parenthesized_expression(SPAN, function_expr)
};
let arguments = {
let right = {
let left = AssignmentTarget::SimpleAssignmentTarget(
self.ast.simple_assignment_target_identifier(IdentifierReference::new(
SPAN,
name.clone(),
)),
);
let right = self.ast.object_expression(SPAN, self.ast.new_vec(), None);
self.ast.parenthesized_expression(
SPAN,
self.ast.assignment_expression(SPAN, AssignmentOperator::Assign, left, right),
)
};
self.ast.new_vec_single(Argument::Expression(
self.ast.logical_expression(
SPAN,
self.ast.identifier_reference_expression(IdentifierReference::new(
SPAN,
name.clone(),
)),
LogicalOperator::Or,
right,
),
))
};
let expr = self.ast.call_expression(SPAN, callee, arguments, false, None);
self.ast.expression_statement(SPAN, expr)
}
}

View file

@ -1,4 +1,4 @@
Passed: 314/1179
Passed: 316/1179
# All Passed:
* babel-plugin-transform-numeric-separator
@ -832,7 +832,7 @@ Passed: 314/1179
* general/function-duplicate-name/input.js
* general/object/input.js
# babel-plugin-transform-typescript (83/158)
# babel-plugin-transform-typescript (85/158)
* class/abstract-class-decorated/input.ts
* class/abstract-class-decorated-method/input.ts
* class/abstract-class-decorated-parameter/input.ts
@ -875,7 +875,6 @@ Passed: 314/1179
* namespace/clobber-import/input.ts
* namespace/contentious-names/input.ts
* namespace/declare/input.ts
* namespace/declare-global-nested-namespace/input.ts
* namespace/empty-removed/input.ts
* namespace/export/input.ts
* namespace/export-type-only/input.ts
@ -891,7 +890,6 @@ Passed: 314/1179
* namespace/nested-shorthand/input.ts
* namespace/nested-shorthand-export/input.ts
* namespace/same-name/input.ts
* namespace/undeclared/input.ts
* optimize-const-enums/custom-values/input.ts
* optimize-const-enums/custom-values-exported/input.ts
* optimize-const-enums/declare/input.ts

View file

@ -511,11 +511,237 @@ var Animals = (Animals => {
# typescript/tests/cases/conformance/enums/enumMerging.ts
```typescript
let M1;
(function(_M1) {
var EImpl1 = (EImpl1 => {
const A = 0;
EImpl1[EImpl1['A'] = A] = 'A';
const B = 1 + A;
EImpl1[EImpl1['B'] = B] = 'B';
const C = 1 + B;
EImpl1[EImpl1['C'] = C] = 'C';
return EImpl1;
})(EImpl1 || {});
var EImpl1 = (EImpl1 => {
const D = 1;
EImpl1[EImpl1['D'] = D] = 'D';
const E = 1 + D;
EImpl1[EImpl1['E'] = E] = 'E';
const F = 1 + E;
EImpl1[EImpl1['F'] = F] = 'F';
return EImpl1;
})(EImpl1 || {});
export var EConst1 = (EConst1 => {
const A = 3;
EConst1[EConst1['A'] = A] = 'A';
const B = 2;
EConst1[EConst1['B'] = B] = 'B';
const C = 1;
EConst1[EConst1['C'] = C] = 'C';
return EConst1;
})(EConst1 || {});
var EConst1 = (EConst1 => {
const D = 7;
EConst1[EConst1['D'] = D] = 'D';
const E = 9;
EConst1[EConst1['E'] = E] = 'E';
const F = 8;
EConst1[EConst1['F'] = F] = 'F';
return EConst1;
})(EConst1 || {});
var x = [EConst1.A, EConst1.B, EConst1.C, EConst1.D, EConst1.E, EConst1.F];
})(M1 || (M1 = {}));
let M2;
(function(_M2) {
export var EComp2 = (EComp2 => {
const A = 'foo'.length;
EComp2[EComp2['A'] = A] = 'A';
const B = 'foo'.length;
EComp2[EComp2['B'] = B] = 'B';
const C = 'foo'.length;
EComp2[EComp2['C'] = C] = 'C';
return EComp2;
})(EComp2 || {});
var EComp2 = (EComp2 => {
const D = 'foo'.length;
EComp2[EComp2['D'] = D] = 'D';
const E = 'foo'.length;
EComp2[EComp2['E'] = E] = 'E';
const F = 'foo'.length;
EComp2[EComp2['F'] = F] = 'F';
return EComp2;
})(EComp2 || {});
var x = [EComp2.A, EComp2.B, EComp2.C, EComp2.D, EComp2.E, EComp2.F];
})(M2 || (M2 = {}));
let M3;
(function(_M3) {
var EInit = (EInit => {
const A = 0;
EInit[EInit['A'] = A] = 'A';
const B = 1 + A;
EInit[EInit['B'] = B] = 'B';
return EInit;
})(EInit || {});
var EInit = (EInit => {
const C = 1;
EInit[EInit['C'] = C] = 'C';
const D = 1 + C;
EInit[EInit['D'] = D] = 'D';
const E = 1 + D;
EInit[EInit['E'] = E] = 'E';
return EInit;
})(EInit || {});
})(M3 || (M3 = {}));
let M4;
(function(_M4) {
export var Color = (Color => {
const Red = 0;
Color[Color['Red'] = Red] = 'Red';
const Green = 1 + Red;
Color[Color['Green'] = Green] = 'Green';
const Blue = 1 + Green;
Color[Color['Blue'] = Blue] = 'Blue';
return Color;
})(Color || {});
})(M4 || (M4 = {}));
let M5;
(function(_M5) {
var Color = (Color => {
const Red = 0;
Color[Color['Red'] = Red] = 'Red';
const Green = 1 + Red;
Color[Color['Green'] = Green] = 'Green';
const Blue = 1 + Green;
Color[Color['Blue'] = Blue] = 'Blue';
return Color;
})(Color || {});
})(M5 || (M5 = {}));
let M6;
(function(_M6) {
(function(_A) {
var Color = (Color => {
const Red = 0;
Color[Color['Red'] = Red] = 'Red';
const Green = 1 + Red;
Color[Color['Green'] = Green] = 'Green';
const Blue = 1 + Green;
Color[Color['Blue'] = Blue] = 'Blue';
return Color;
})(Color || {});
})(A || (A = {}));
})(M6 || (M6 = {}));
let M6;
(function(_M6) {
var t = A.Color.Yellow;
t = A.Color.Red;
})(M6 || (M6 = {}));
```
# typescript/tests/cases/conformance/enums/enumMergingErrors.ts
```typescript
let M;
(function(_M) {
export var E1 = (E1 => {
const A = 0;
E1[E1['A'] = A] = 'A';
return E1;
})(E1 || {});
export var E2 = (E2 => {
const C = 0;
E2[E2['C'] = C] = 'C';
return E2;
})(E2 || {});
export var E3 = (E3 => {
const A = 0;
E3[E3['A'] = A] = 'A';
return E3;
})(E3 || {});
})(M || (M = {}));
let M;
(function(_M) {
var E1 = (E1 => {
const B = 'foo'.length;
E1[E1['B'] = B] = 'B';
return E1;
})(E1 || {});
var E2 = (E2 => {
const B = 'foo'.length;
E2[E2['B'] = B] = 'B';
return E2;
})(E2 || {});
var E3 = (E3 => {
const C = 0;
E3[E3['C'] = C] = 'C';
return E3;
})(E3 || {});
})(M || (M = {}));
let M;
(function(_M) {
var E1 = (E1 => {
const C = 0;
E1[E1['C'] = C] = 'C';
return E1;
})(E1 || {});
var E2 = (E2 => {
const A = 0;
E2[E2['A'] = A] = 'A';
return E2;
})(E2 || {});
var E3 = (E3 => {
const B = 'foo'.length;
E3[E3['B'] = B] = 'B';
return E3;
})(E3 || {});
})(M || (M = {}));
let M1;
(function(_M1) {
var E1 = (E1 => {
const A = 0;
E1[E1['A'] = A] = 'A';
return E1;
})(E1 || {});
})(M1 || (M1 = {}));
let M1;
(function(_M1) {
var E1 = (E1 => {
const B = 0;
E1[E1['B'] = B] = 'B';
return E1;
})(E1 || {});
})(M1 || (M1 = {}));
let M1;
(function(_M1) {
var E1 = (E1 => {
const C = 0;
E1[E1['C'] = C] = 'C';
return E1;
})(E1 || {});
})(M1 || (M1 = {}));
let M2;
(function(_M2) {
var E1 = (E1 => {
const A = 0;
E1[E1['A'] = A] = 'A';
return E1;
})(E1 || {});
})(M2 || (M2 = {}));
let M2;
(function(_M2) {
var E1 = (E1 => {
const B = 0;
E1[E1['B'] = B] = 'B';
return E1;
})(E1 || {});
})(M2 || (M2 = {}));
let M2;
(function(_M2) {
var E1 = (E1 => {
const C = 0;
E1[E1['C'] = C] = 'C';
return E1;
})(E1 || {});
})(M2 || (M2 = {}));
```