mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(transformer/typescript): support transform namespace (#2075)
This commit is contained in:
parent
2e78b918d1
commit
56ca8b6dfe
5 changed files with 369 additions and 4 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {}));
|
||||
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue