mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(transformer): implement typescript namespace (#3025)
Co-authored-by: Dunqing <dengqing0821@gmail.com>
This commit is contained in:
parent
ac72d08592
commit
78875b79fe
9 changed files with 519 additions and 179 deletions
|
|
@ -1318,6 +1318,18 @@ impl<'a> Declaration<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> Option<&BindingIdentifier<'a>> {
|
||||||
|
match self {
|
||||||
|
Declaration::FunctionDeclaration(decl) => decl.id.as_ref(),
|
||||||
|
Declaration::ClassDeclaration(decl) => decl.id.as_ref(),
|
||||||
|
Declaration::TSTypeAliasDeclaration(decl) => Some(&decl.id),
|
||||||
|
Declaration::TSInterfaceDeclaration(decl) => Some(&decl.id),
|
||||||
|
Declaration::TSEnumDeclaration(decl) => Some(&decl.id),
|
||||||
|
Declaration::TSImportEqualsDeclaration(decl) => Some(&decl.id),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn modifiers(&self) -> Option<&Modifiers<'a>> {
|
pub fn modifiers(&self) -> Option<&Modifiers<'a>> {
|
||||||
match self {
|
match self {
|
||||||
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers),
|
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers),
|
||||||
|
|
|
||||||
|
|
@ -1216,6 +1216,21 @@ impl<'a> AstBuilder<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn plain_export_named_declaration_declaration(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
declaration: Declaration<'a>,
|
||||||
|
) -> Box<'a, ExportNamedDeclaration<'a>> {
|
||||||
|
self.export_named_declaration(
|
||||||
|
span,
|
||||||
|
Some(declaration),
|
||||||
|
self.new_vec(),
|
||||||
|
None,
|
||||||
|
ImportOrExportKind::Value,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn plain_export_named_declaration(
|
pub fn plain_export_named_declaration(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,10 @@ impl<'a> BoundNames<'a> for FormalParameter<'a> {
|
||||||
|
|
||||||
impl<'a> BoundNames<'a> for ModuleDeclaration<'a> {
|
impl<'a> BoundNames<'a> for ModuleDeclaration<'a> {
|
||||||
fn bound_names<F: FnMut(&BindingIdentifier<'a>)>(&self, f: &mut F) {
|
fn bound_names<F: FnMut(&BindingIdentifier<'a>)>(&self, f: &mut F) {
|
||||||
if let ModuleDeclaration::ImportDeclaration(decl) = &self {
|
match self {
|
||||||
decl.bound_names(f);
|
ModuleDeclaration::ImportDeclaration(decl) => decl.bound_names(f),
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(decl) => decl.bound_names(f),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,10 @@ impl<'a> Transformer<'a> {
|
||||||
|
|
||||||
impl<'a> VisitMut<'a> for Transformer<'a> {
|
impl<'a> VisitMut<'a> for Transformer<'a> {
|
||||||
fn visit_program(&mut self, program: &mut Program<'a>) {
|
fn visit_program(&mut self, program: &mut Program<'a>) {
|
||||||
|
self.x0_typescript.transform_program(program);
|
||||||
|
|
||||||
walk_mut::walk_program_mut(self, program);
|
walk_mut::walk_program_mut(self, program);
|
||||||
|
|
||||||
self.x1_react.transform_program_on_exit(program);
|
self.x1_react.transform_program_on_exit(program);
|
||||||
self.x0_typescript.transform_program_on_exit(program);
|
self.x0_typescript.transform_program_on_exit(program);
|
||||||
}
|
}
|
||||||
|
|
@ -186,8 +189,6 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
self.x0_typescript.transform_statements(stmts);
|
|
||||||
|
|
||||||
walk_mut::walk_statements_mut(self, stmts);
|
walk_mut::walk_statements_mut(self, stmts);
|
||||||
|
|
||||||
self.x0_typescript.transform_statements_on_exit(stmts);
|
self.x0_typescript.transform_statements_on_exit(stmts);
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,18 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
program: &mut Program<'a>,
|
program: &mut Program<'a>,
|
||||||
references: &TypeScriptReferenceCollector,
|
references: &TypeScriptReferenceCollector,
|
||||||
) {
|
) {
|
||||||
let mut import_type_names = FxHashSet::default();
|
let mut type_names = FxHashSet::default();
|
||||||
let mut module_count = 0;
|
let mut module_count = 0;
|
||||||
let mut removed_count = 0;
|
let mut removed_count = 0;
|
||||||
|
|
||||||
program.body.retain_mut(|stmt| {
|
program.body.retain_mut(|stmt| {
|
||||||
|
// fix namespace/export-type-only/input.ts
|
||||||
|
// The namespace is type only. So if its name appear in the ExportNamedDeclaration, we should remove it.
|
||||||
|
if let Statement::Declaration(Declaration::TSModuleDeclaration(decl)) = stmt {
|
||||||
|
type_names.insert(decl.id.name().clone());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let Statement::ModuleDeclaration(module_decl) = stmt else {
|
let Statement::ModuleDeclaration(module_decl) = stmt else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
@ -71,7 +78,7 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
||||||
decl.specifiers.retain(|specifier| {
|
decl.specifiers.retain(|specifier| {
|
||||||
!(specifier.export_kind.is_type()
|
!(specifier.export_kind.is_type()
|
||||||
|| import_type_names.contains(specifier.exported.name()))
|
|| type_names.contains(specifier.exported.name()))
|
||||||
});
|
});
|
||||||
|
|
||||||
decl.export_kind.is_type()
|
decl.export_kind.is_type()
|
||||||
|
|
@ -92,7 +99,7 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
specifiers.retain(|specifier| match specifier {
|
specifiers.retain(|specifier| match specifier {
|
||||||
ImportDeclarationSpecifier::ImportSpecifier(s) => {
|
ImportDeclarationSpecifier::ImportSpecifier(s) => {
|
||||||
if is_type || s.import_kind.is_type() {
|
if is_type || s.import_kind.is_type() {
|
||||||
import_type_names.insert(s.local.name.clone());
|
type_names.insert(s.local.name.clone());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +111,7 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
}
|
}
|
||||||
ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
|
ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
|
||||||
if is_type {
|
if is_type {
|
||||||
import_type_names.insert(s.local.name.clone());
|
type_names.insert(s.local.name.clone());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +122,7 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
}
|
}
|
||||||
ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
|
ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
|
||||||
if is_type {
|
if is_type {
|
||||||
import_type_names.insert(s.local.name.clone());
|
type_names.insert(s.local.name.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.only_remove_type_imports {
|
if self.options.only_remove_type_imports {
|
||||||
|
|
@ -295,6 +302,14 @@ impl<'a> TypeScriptAnnotations<'a> {
|
||||||
// Remove TS specific statements
|
// Remove TS specific statements
|
||||||
stmts.retain(|stmt| match stmt {
|
stmts.retain(|stmt| match stmt {
|
||||||
Statement::ExpressionStatement(s) => !s.expression.is_typescript_syntax(),
|
Statement::ExpressionStatement(s) => !s.expression.is_typescript_syntax(),
|
||||||
|
Statement::Declaration(s) => {
|
||||||
|
// Removed in transform_program_on_exit
|
||||||
|
if matches!(s, Declaration::TSModuleDeclaration(_)) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
!s.is_typescript_syntax()
|
||||||
|
}
|
||||||
|
}
|
||||||
// Ignore ModuleDeclaration as it's handled in the program
|
// Ignore ModuleDeclaration as it's handled in the program
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ impl<'a> TypeScript<'a> {
|
||||||
|
|
||||||
// Transforms
|
// Transforms
|
||||||
impl<'a> TypeScript<'a> {
|
impl<'a> TypeScript<'a> {
|
||||||
|
pub fn transform_program(&self, program: &mut Program<'a>) {
|
||||||
|
self.transform_program_for_namespace(program);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transform_program_on_exit(&self, program: &mut Program<'a>) {
|
pub fn transform_program_on_exit(&self, program: &mut Program<'a>) {
|
||||||
self.annotations.transform_program_on_exit(program, &self.reference_collector);
|
self.annotations.transform_program_on_exit(program, &self.reference_collector);
|
||||||
}
|
}
|
||||||
|
|
@ -133,10 +137,6 @@ impl<'a> TypeScript<'a> {
|
||||||
self.annotations.transform_property_definition(def);
|
self.annotations.transform_property_definition(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
|
||||||
self.transform_statements_for_namespace(stmts);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
self.annotations.transform_statements_on_exit(stmts);
|
self.annotations.transform_statements_on_exit(stmts);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,169 +1,308 @@
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use super::TypeScript;
|
use super::TypeScript;
|
||||||
|
|
||||||
use oxc_allocator::{Box, Vec};
|
use oxc_allocator::{Box, Vec};
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::{ast::*, syntax_directed_operations::BoundNames};
|
||||||
use oxc_span::{Atom, SPAN};
|
use oxc_span::{Atom, SPAN};
|
||||||
use oxc_syntax::operator::{AssignmentOperator, LogicalOperator};
|
use oxc_syntax::operator::{AssignmentOperator, LogicalOperator};
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct State<'a> {
|
|
||||||
/// Deduplicate the `let` declarations` for namespace concatenation.
|
|
||||||
/// `namespace foo {}; namespace {}` creates a single `let foo;`.
|
|
||||||
names: FxHashSet<Atom<'a>>,
|
|
||||||
|
|
||||||
/// Increment the argument name to avoid name clashes.
|
|
||||||
arg_names: FxHashMap<Atom<'a>, usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_namespace(decl: &Declaration<'_>) -> bool {
|
|
||||||
matches!(decl, Declaration::TSModuleDeclaration(decl) if !decl.modifiers.is_contains_declare())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1. register scope for the newly created function: <https://github.com/babel/babel/blob/08b0472069cd207f043dd40a4d157addfdd36011/packages/babel-plugin-transform-typescript/src/namespace.ts#L38>
|
// 1. register scope for the newly created function: <https://github.com/babel/babel/blob/08b0472069cd207f043dd40a4d157addfdd36011/packages/babel-plugin-transform-typescript/src/namespace.ts#L38>
|
||||||
impl<'a> TypeScript<'a> {
|
impl<'a> TypeScript<'a> {
|
||||||
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
pub(super) fn transform_statements_for_namespace(&self, stmts: &mut Vec<'a, Statement<'a>>) {
|
pub(super) fn transform_program_for_namespace(&self, program: &mut Program<'a>) {
|
||||||
// Only do the transform if a namespace declaration is found.
|
// namespace declaration is only allowed at the top level
|
||||||
if !stmts.iter().any(|stmt| match stmt {
|
|
||||||
Statement::Declaration(decl) => is_namespace(decl),
|
if !has_namespace(program.body.as_slice()) {
|
||||||
Statement::ModuleDeclaration(decl) => match &**decl {
|
|
||||||
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
|
||||||
decl.declaration.as_ref().is_some_and(is_namespace)
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
_ => false,
|
|
||||||
}) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect all binding names. Such as function name and class name.
|
||||||
|
let mut names: FxHashSet<Atom<'a>> = FxHashSet::default();
|
||||||
|
|
||||||
// Recreate the statements vec for memory efficiency.
|
// Recreate the statements vec for memory efficiency.
|
||||||
// Inserting the `let` declaration multiple times will reallocate the whole statements vec
|
// Inserting the `let` declaration multiple times will reallocate the whole statements vec
|
||||||
// every time a namespace declaration is encountered.
|
// every time a namespace declaration is encountered.
|
||||||
let mut new_stmts = self.ctx.ast.new_vec();
|
let mut new_stmts = self.ctx.ast.new_vec();
|
||||||
|
|
||||||
let mut state = State::default();
|
for stmt in self.ctx.ast.move_statement_vec(&mut program.body) {
|
||||||
|
match stmt {
|
||||||
|
Statement::Declaration(Declaration::TSModuleDeclaration(decl)) => {
|
||||||
|
if !decl.modifiers.is_contains_declare() {
|
||||||
|
if let Some(transformed_stmt) =
|
||||||
|
self.handle_nested(self.ctx.ast.copy(&decl).unbox(), None)
|
||||||
|
{
|
||||||
|
let name = decl.id.name();
|
||||||
|
if names.insert(name.clone()) {
|
||||||
|
new_stmts.push(Statement::Declaration(
|
||||||
|
self.create_variable_declaration(name),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
new_stmts.push(transformed_stmt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_stmts.push(Statement::Declaration(Declaration::TSModuleDeclaration(decl)));
|
||||||
|
}
|
||||||
|
Statement::ModuleDeclaration(module_decl) => {
|
||||||
|
if let ModuleDeclaration::ExportNamedDeclaration(export_decl) =
|
||||||
|
self.ctx.ast.copy(&module_decl).unbox()
|
||||||
|
{
|
||||||
|
if let Some(Declaration::TSModuleDeclaration(decl)) =
|
||||||
|
&export_decl.declaration
|
||||||
|
{
|
||||||
|
if !decl.modifiers.is_contains_declare() {
|
||||||
|
if let Some(transformed_stmt) =
|
||||||
|
self.handle_nested(self.ctx.ast.copy(decl), None)
|
||||||
|
{
|
||||||
|
let name = decl.id.name();
|
||||||
|
if names.insert(name.clone()) {
|
||||||
|
let declaration = self.create_variable_declaration(name);
|
||||||
|
let export_named_decl = self
|
||||||
|
.ctx
|
||||||
|
.ast
|
||||||
|
.plain_export_named_declaration_declaration(
|
||||||
|
SPAN,
|
||||||
|
declaration,
|
||||||
|
);
|
||||||
|
let export_named_decl =
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(
|
||||||
|
export_named_decl,
|
||||||
|
);
|
||||||
|
let stmt =
|
||||||
|
self.ctx.ast.module_declaration(export_named_decl);
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
new_stmts.push(transformed_stmt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for mut stmt in self.ctx.ast.move_statement_vec(stmts) {
|
module_decl.bound_names(&mut |id| {
|
||||||
if !self.transform_statement_for_namespace(&mut state, &mut new_stmts, &mut stmt) {
|
names.insert(id.name.clone());
|
||||||
|
});
|
||||||
|
new_stmts.push(Statement::ModuleDeclaration(module_decl));
|
||||||
|
}
|
||||||
|
// Collect bindings from class, function, variable and enum declarations
|
||||||
|
Statement::Declaration(Declaration::FunctionDeclaration(ref decl)) => {
|
||||||
|
if let Some(ident) = &decl.id {
|
||||||
|
names.insert(ident.name.clone());
|
||||||
|
}
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
Statement::Declaration(Declaration::ClassDeclaration(ref decl)) => {
|
||||||
|
if let Some(ident) = &decl.id {
|
||||||
|
names.insert(ident.name.clone());
|
||||||
|
}
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
Statement::Declaration(Declaration::TSEnumDeclaration(ref decl)) => {
|
||||||
|
names.insert(decl.id.name.clone());
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
Statement::Declaration(Declaration::VariableDeclaration(ref decl)) => {
|
||||||
|
decl.bound_names(&mut |id| {
|
||||||
|
names.insert(id.name.clone());
|
||||||
|
});
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
new_stmts.push(stmt);
|
new_stmts.push(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*stmts = new_stmts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_statement_for_namespace(
|
program.body = new_stmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_nested(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State<'a>,
|
decl: TSModuleDeclaration<'a>,
|
||||||
new_stmts: &mut Vec<'a, Statement<'a>>,
|
parent_export: Option<Expression<'a>>,
|
||||||
stmt: &mut Statement<'a>,
|
) -> Option<Statement<'a>> {
|
||||||
) -> bool {
|
let mut names: FxHashSet<Atom<'a>> = FxHashSet::default();
|
||||||
let mut is_export = false;
|
let real_name = decl.id.name();
|
||||||
let ts_module_decl = match stmt {
|
|
||||||
Statement::Declaration(Declaration::TSModuleDeclaration(ts_module_decl)) => {
|
let name = self.ctx.ast.new_atom(&format!("_{}", real_name.clone())); // path.scope.generateUid(realName.name);
|
||||||
ts_module_decl
|
|
||||||
|
let namespace_top_level = if let Some(body) = decl.body {
|
||||||
|
match body {
|
||||||
|
TSModuleDeclarationBody::TSModuleBlock(mut block) => {
|
||||||
|
self.ctx.ast.move_statement_vec(&mut block.body)
|
||||||
|
}
|
||||||
|
// We handle `namespace X.Y {}` as if it was
|
||||||
|
// namespace X {
|
||||||
|
// export namespace Y {}
|
||||||
|
// }
|
||||||
|
TSModuleDeclarationBody::TSModuleDeclaration(declaration) => {
|
||||||
|
let declaration =
|
||||||
|
Declaration::TSModuleDeclaration(self.ctx.ast.copy(&declaration));
|
||||||
|
let export_named_decl =
|
||||||
|
self.ctx.ast.plain_export_named_declaration_declaration(SPAN, declaration);
|
||||||
|
let stmt = self.ctx.ast.module_declaration(
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(export_named_decl),
|
||||||
|
);
|
||||||
|
self.ctx.ast.new_vec_single(stmt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Statement::ModuleDeclaration(decl) => match &mut **decl {
|
|
||||||
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
|
||||||
if let Some(Declaration::TSModuleDeclaration(ts_module_decl)) =
|
|
||||||
decl.declaration.as_mut()
|
|
||||||
{
|
|
||||||
is_export = true;
|
|
||||||
ts_module_decl
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
self.ctx.ast.new_vec()
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return false,
|
|
||||||
},
|
|
||||||
_ => return false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ts_module_decl.modifiers.is_contains_declare() {
|
let mut is_empty = true;
|
||||||
return false;
|
let mut new_stmts = self.ctx.ast.new_vec();
|
||||||
|
|
||||||
|
for stmt in namespace_top_level {
|
||||||
|
match stmt {
|
||||||
|
Statement::Declaration(Declaration::TSModuleDeclaration(decl)) => {
|
||||||
|
let module_name = decl.id.name().clone();
|
||||||
|
if let Some(transformed) = self.handle_nested(decl.unbox(), None) {
|
||||||
|
is_empty = false;
|
||||||
|
if names.insert(module_name.clone()) {
|
||||||
|
new_stmts.push(Statement::Declaration(
|
||||||
|
self.create_variable_declaration(&module_name),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
new_stmts.push(transformed);
|
||||||
let name = ts_module_decl.id.name().clone();
|
}
|
||||||
|
}
|
||||||
if state.names.insert(name.clone()) {
|
Statement::Declaration(Declaration::ClassDeclaration(decl)) => {
|
||||||
let stmt = self.create_variable_declaration_statement(&name, is_export);
|
is_empty = false;
|
||||||
|
decl.bound_names(&mut |id| {
|
||||||
|
names.insert(id.name.clone());
|
||||||
|
});
|
||||||
|
new_stmts.push(Statement::Declaration(Declaration::ClassDeclaration(decl)));
|
||||||
|
}
|
||||||
|
Statement::Declaration(Declaration::TSEnumDeclaration(enum_decl)) => {
|
||||||
|
is_empty = false;
|
||||||
|
names.insert(enum_decl.id.name.clone());
|
||||||
|
new_stmts
|
||||||
|
.push(Statement::Declaration(Declaration::TSEnumDeclaration(enum_decl)));
|
||||||
|
}
|
||||||
|
Statement::ModuleDeclaration(decl) => {
|
||||||
|
if let ModuleDeclaration::ExportNamedDeclaration(export_decl) = decl.unbox() {
|
||||||
|
let export_decl = export_decl.unbox();
|
||||||
|
if let Some(decl) = export_decl.declaration {
|
||||||
|
if decl.modifiers().is_some_and(Modifiers::is_contains_declare) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match decl {
|
||||||
|
Declaration::TSEnumDeclaration(enum_decl) => {
|
||||||
|
is_empty = false;
|
||||||
|
self.add_declaration(
|
||||||
|
Declaration::TSEnumDeclaration(enum_decl),
|
||||||
|
&name,
|
||||||
|
&mut names,
|
||||||
|
&mut new_stmts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Declaration::FunctionDeclaration(func_decl) => {
|
||||||
|
is_empty = false;
|
||||||
|
self.add_declaration(
|
||||||
|
Declaration::FunctionDeclaration(func_decl),
|
||||||
|
&name,
|
||||||
|
&mut names,
|
||||||
|
&mut new_stmts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Declaration::ClassDeclaration(class_decl) => {
|
||||||
|
is_empty = false;
|
||||||
|
self.add_declaration(
|
||||||
|
Declaration::ClassDeclaration(class_decl),
|
||||||
|
&name,
|
||||||
|
&mut names,
|
||||||
|
&mut new_stmts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Declaration::VariableDeclaration(var_decl) => {
|
||||||
|
is_empty = false;
|
||||||
|
let stmts = self.handle_variable_declaration(var_decl, &name);
|
||||||
|
new_stmts.extend(stmts);
|
||||||
|
}
|
||||||
|
Declaration::TSModuleDeclaration(module_decl) => {
|
||||||
|
let module_name = module_decl.id.name().clone();
|
||||||
|
if let Some(transformed) = self.handle_nested(
|
||||||
|
module_decl.unbox(),
|
||||||
|
Some(self.ctx.ast.identifier_reference_expression(
|
||||||
|
IdentifierReference::new(SPAN, name.clone()),
|
||||||
|
)),
|
||||||
|
) {
|
||||||
|
is_empty = false;
|
||||||
|
if names.insert(module_name.clone()) {
|
||||||
|
new_stmts.push(Statement::Declaration(
|
||||||
|
self.create_variable_declaration(&module_name),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
new_stmts.push(transformed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let stmt = self.ctx.ast.module_declaration(
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(
|
||||||
|
self.ctx.ast.alloc(export_decl),
|
||||||
|
),
|
||||||
|
);
|
||||||
new_stmts.push(stmt);
|
new_stmts.push(stmt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Declaration(decl) if decl.is_typescript_syntax() => continue,
|
||||||
|
stmt => {
|
||||||
|
is_empty = false;
|
||||||
|
new_stmts.push(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let namespace = self.transform_namespace(state, ts_module_decl);
|
if is_empty {
|
||||||
new_stmts.push(namespace);
|
return None;
|
||||||
true
|
}
|
||||||
|
|
||||||
|
Some(self.transform_namespace(&name, real_name, new_stmts, parent_export))
|
||||||
}
|
}
|
||||||
|
|
||||||
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
// ^^^^^^^
|
// ^^^^^^^
|
||||||
fn create_variable_declaration_statement(
|
fn create_variable_declaration(&self, name: &Atom<'a>) -> Declaration<'a> {
|
||||||
&self,
|
|
||||||
name: &Atom<'a>,
|
|
||||||
is_export: bool,
|
|
||||||
) -> Statement<'a> {
|
|
||||||
let kind = VariableDeclarationKind::Let;
|
let kind = VariableDeclarationKind::Let;
|
||||||
let declarators = {
|
let declarator = {
|
||||||
let ident = BindingIdentifier::new(SPAN, name.clone());
|
let ident = BindingIdentifier::new(SPAN, name.clone());
|
||||||
let pattern_kind = self.ctx.ast.binding_pattern_identifier(ident);
|
let pattern_kind = self.ctx.ast.binding_pattern_identifier(ident);
|
||||||
let binding = self.ctx.ast.binding_pattern(pattern_kind, None, false);
|
let binding = self.ctx.ast.binding_pattern(pattern_kind, None, false);
|
||||||
let decl = self.ctx.ast.variable_declarator(SPAN, kind, binding, None, false);
|
let decl = self.ctx.ast.variable_declarator(SPAN, kind, binding, None, false);
|
||||||
self.ctx.ast.new_vec_single(decl)
|
self.ctx.ast.new_vec_single(decl)
|
||||||
};
|
};
|
||||||
let decl = Declaration::VariableDeclaration(self.ctx.ast.variable_declaration(
|
Declaration::VariableDeclaration(self.ctx.ast.variable_declaration(
|
||||||
SPAN,
|
SPAN,
|
||||||
kind,
|
kind,
|
||||||
declarators,
|
declarator,
|
||||||
Modifiers::empty(),
|
Modifiers::empty(),
|
||||||
));
|
|
||||||
if is_export {
|
|
||||||
self.ctx.ast.module_declaration(ModuleDeclaration::ExportNamedDeclaration(
|
|
||||||
self.ctx.ast.export_named_declaration(
|
|
||||||
SPAN,
|
|
||||||
Some(decl),
|
|
||||||
self.ctx.ast.new_vec(),
|
|
||||||
None,
|
|
||||||
ImportOrExportKind::Value,
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
} else {
|
|
||||||
Statement::Declaration(decl)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
fn transform_namespace(
|
fn transform_namespace(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State<'a>,
|
arg_name: &Atom<'a>,
|
||||||
block: &mut Box<'a, TSModuleDeclaration<'a>>,
|
real_name: &Atom<'a>,
|
||||||
|
stmts: Vec<'a, Statement<'a>>,
|
||||||
|
parent_export: Option<Expression<'a>>,
|
||||||
) -> Statement<'a> {
|
) -> Statement<'a> {
|
||||||
let body_statements = match &mut block.body {
|
|
||||||
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
|
|
||||||
let transformed_module_block = self.transform_namespace(state, decl);
|
|
||||||
self.ctx.ast.new_vec_single(transformed_module_block)
|
|
||||||
}
|
|
||||||
Some(TSModuleDeclarationBody::TSModuleBlock(ts_module_block)) => {
|
|
||||||
self.ctx.ast.move_statement_vec(&mut ts_module_block.body)
|
|
||||||
}
|
|
||||||
None => self.ctx.ast.new_vec(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = block.id.name();
|
|
||||||
|
|
||||||
// `(function (_N) { var x; })(N || (N = {}))`;
|
// `(function (_N) { var x; })(N || (N = {}))`;
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
let callee = {
|
let callee = {
|
||||||
let body = self.ctx.ast.function_body(SPAN, self.ctx.ast.new_vec(), body_statements);
|
let body = self.ctx.ast.function_body(SPAN, self.ctx.ast.new_vec(), stmts);
|
||||||
let arg_name = self.get_namespace_arg_name(state, name);
|
|
||||||
let params = {
|
let params = {
|
||||||
let ident =
|
let ident = self.ctx.ast.binding_pattern_identifier(BindingIdentifier::new(
|
||||||
self.ctx.ast.binding_pattern_identifier(BindingIdentifier::new(SPAN, arg_name));
|
SPAN,
|
||||||
|
self.ctx.ast.new_atom(arg_name),
|
||||||
|
));
|
||||||
let pattern = self.ctx.ast.binding_pattern(ident, None, false);
|
let pattern = self.ctx.ast.binding_pattern(ident, None, false);
|
||||||
let items =
|
let items =
|
||||||
self.ctx.ast.new_vec_single(self.ctx.ast.plain_formal_parameter(SPAN, pattern));
|
self.ctx.ast.new_vec_single(self.ctx.ast.plain_formal_parameter(SPAN, pattern));
|
||||||
|
|
@ -185,17 +324,36 @@ impl<'a> TypeScript<'a> {
|
||||||
self.ctx.ast.parenthesized_expression(SPAN, function_expr)
|
self.ctx.ast.parenthesized_expression(SPAN, function_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `(function (_N) { var x; })(N || (N = {}))`;
|
// (function (_N) { var M; (function (_M) { var x; })(M || (M = _N.M || (_N.M = {})));})(N || (N = {}));
|
||||||
// ^^^^^^^^^^^^^
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
|
||||||
|
// Nested namespace arguments Normal namespace arguments
|
||||||
let arguments = {
|
let arguments = {
|
||||||
|
// M
|
||||||
let logical_left = {
|
let logical_left = {
|
||||||
let ident = IdentifierReference::new(SPAN, name.clone());
|
let ident = IdentifierReference::new(SPAN, real_name.clone());
|
||||||
self.ctx.ast.identifier_reference_expression(ident)
|
self.ctx.ast.identifier_reference_expression(ident)
|
||||||
};
|
};
|
||||||
let logical_right = {
|
|
||||||
let assign_left = self.ctx.ast.simple_assignment_target_identifier(
|
// (_N.M = {}) or (N = {})
|
||||||
IdentifierReference::new(SPAN, name.clone()),
|
let mut logical_right = {
|
||||||
);
|
// _N.M
|
||||||
|
let assign_left = if let Some(parent_export) = self.ctx.ast.copy(&parent_export) {
|
||||||
|
self.ctx.ast.simple_assignment_target_member_expression(
|
||||||
|
self.ctx.ast.static_member(
|
||||||
|
SPAN,
|
||||||
|
parent_export,
|
||||||
|
self.ctx.ast.identifier_name(SPAN, real_name),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// _N
|
||||||
|
self.ctx.ast.simple_assignment_target_identifier(IdentifierReference::new(
|
||||||
|
SPAN,
|
||||||
|
real_name.clone(),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
let assign_right =
|
let assign_right =
|
||||||
self.ctx.ast.object_expression(SPAN, self.ctx.ast.new_vec(), None);
|
self.ctx.ast.object_expression(SPAN, self.ctx.ast.new_vec(), None);
|
||||||
let op = AssignmentOperator::Assign;
|
let op = AssignmentOperator::Assign;
|
||||||
|
|
@ -203,21 +361,138 @@ impl<'a> TypeScript<'a> {
|
||||||
self.ctx.ast.assignment_expression(SPAN, op, assign_left, assign_right);
|
self.ctx.ast.assignment_expression(SPAN, op, assign_left, assign_right);
|
||||||
self.ctx.ast.parenthesized_expression(SPAN, assign_expr)
|
self.ctx.ast.parenthesized_expression(SPAN, assign_expr)
|
||||||
};
|
};
|
||||||
self.ctx.ast.new_vec_single(Argument::Expression(self.ctx.ast.logical_expression(
|
|
||||||
SPAN,
|
// (M = _N.M || (_N.M = {}))
|
||||||
logical_left,
|
if let Some(parent_export) = parent_export {
|
||||||
LogicalOperator::Or,
|
let assign_left = self.ctx.ast.simple_assignment_target_identifier(
|
||||||
logical_right,
|
IdentifierReference::new(SPAN, real_name.clone()),
|
||||||
)))
|
);
|
||||||
|
let assign_right = {
|
||||||
|
let property = self.ctx.ast.identifier_name(SPAN, real_name);
|
||||||
|
let logical_left =
|
||||||
|
self.ctx.ast.static_member_expression(SPAN, parent_export, property, false);
|
||||||
|
let op = LogicalOperator::Or;
|
||||||
|
self.ctx.ast.logical_expression(SPAN, logical_left, op, logical_right)
|
||||||
};
|
};
|
||||||
|
let op = AssignmentOperator::Assign;
|
||||||
|
logical_right =
|
||||||
|
self.ctx.ast.assignment_expression(SPAN, op, assign_left, assign_right);
|
||||||
|
logical_right = self.ctx.ast.parenthesized_expression(SPAN, logical_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
let op = LogicalOperator::Or;
|
||||||
|
let expr = self.ctx.ast.logical_expression(SPAN, logical_left, op, logical_right);
|
||||||
|
self.ctx.ast.new_vec_single(Argument::Expression(expr))
|
||||||
|
};
|
||||||
|
|
||||||
let expr = self.ctx.ast.call_expression(SPAN, callee, arguments, false, None);
|
let expr = self.ctx.ast.call_expression(SPAN, callee, arguments, false, None);
|
||||||
self.ctx.ast.expression_statement(SPAN, expr)
|
self.ctx.ast.expression_statement(SPAN, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_namespace_arg_name(&self, state: &mut State<'a>, name: &Atom<'a>) -> Atom<'a> {
|
/// Add assignment statement for decl id
|
||||||
let count = state.arg_names.entry(name.clone()).or_insert(0);
|
/// function id() {} -> function id() {}; Name.id = id;
|
||||||
*count += 1;
|
fn add_declaration(
|
||||||
let name = if *count > 1 { format!("_{name}{count}") } else { format!("_{name}") };
|
&self,
|
||||||
self.ctx.ast.new_atom(&name)
|
decl: Declaration<'a>,
|
||||||
|
name: &Atom<'a>,
|
||||||
|
names: &mut FxHashSet<Atom<'a>>,
|
||||||
|
new_stmts: &mut Vec<'a, Statement<'a>>,
|
||||||
|
) {
|
||||||
|
if let Some(ident) = decl.id() {
|
||||||
|
let item_name = ident.name.clone();
|
||||||
|
let assignment_statement = self.create_assignment_statement(name, &item_name);
|
||||||
|
new_stmts.push(Statement::Declaration(decl));
|
||||||
|
let assignment_statement =
|
||||||
|
self.ctx.ast.expression_statement(SPAN, assignment_statement);
|
||||||
|
new_stmts.push(assignment_statement);
|
||||||
|
names.insert(item_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// name.item_name = item_name
|
||||||
|
fn create_assignment_statement(&self, name: &Atom<'a>, item_name: &Atom<'a>) -> Expression<'a> {
|
||||||
|
let ident = self.ctx.ast.identifier_reference(SPAN, name.as_str());
|
||||||
|
let object = self.ctx.ast.identifier_reference_expression(ident);
|
||||||
|
let property = IdentifierName::new(SPAN, item_name.clone());
|
||||||
|
let left = self.ctx.ast.static_member(SPAN, object, property, false);
|
||||||
|
let left = SimpleAssignmentTarget::MemberAssignmentTarget(self.ctx.ast.alloc(left));
|
||||||
|
let left = AssignmentTarget::SimpleAssignmentTarget(left);
|
||||||
|
let ident = self.ctx.ast.identifier_reference(SPAN, item_name.as_str());
|
||||||
|
let right = self.ctx.ast.identifier_reference_expression(ident);
|
||||||
|
let op = AssignmentOperator::Assign;
|
||||||
|
self.ctx.ast.assignment_expression(SPAN, op, left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert `export const foo = 1` to `Namespace.foo = 1`;
|
||||||
|
fn handle_variable_declaration(
|
||||||
|
&self,
|
||||||
|
mut var_decl: Box<'a, VariableDeclaration<'a>>,
|
||||||
|
name: &Atom<'a>,
|
||||||
|
) -> Vec<'a, Statement<'a>> {
|
||||||
|
let is_all_binding_identifier = var_decl
|
||||||
|
.declarations
|
||||||
|
.iter()
|
||||||
|
.all(|declaration| declaration.id.kind.is_binding_identifier());
|
||||||
|
|
||||||
|
// `export const a = 1` transforms to `const a = N.a = 1`, the output
|
||||||
|
// is smaller than `const a = 1; N.a = a`;
|
||||||
|
if is_all_binding_identifier {
|
||||||
|
var_decl.declarations.iter_mut().for_each(|declarator| {
|
||||||
|
let Some(property_name) = declarator.id.get_identifier() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Some(init) = &declarator.init {
|
||||||
|
declarator.init = Some(self.ctx.ast.assignment_expression(
|
||||||
|
SPAN,
|
||||||
|
AssignmentOperator::Assign,
|
||||||
|
self.ctx.ast.simple_assignment_target_member_expression(
|
||||||
|
self.ctx.ast.static_member(
|
||||||
|
SPAN,
|
||||||
|
self.ctx.ast.identifier_reference_expression(
|
||||||
|
IdentifierReference::new(SPAN, name.clone()),
|
||||||
|
),
|
||||||
|
IdentifierName::new(SPAN, property_name.clone()),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
self.ctx.ast.copy(init),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return self.ctx.ast.new_vec_single(Statement::Declaration(
|
||||||
|
Declaration::VariableDeclaration(var_decl),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have pattern in declarators
|
||||||
|
// `export const [a] = 1` transforms to `const [a] = 1; N.a = a`
|
||||||
|
let mut assignments = self.ctx.ast.new_vec();
|
||||||
|
var_decl.bound_names(&mut |id| {
|
||||||
|
assignments.push(self.create_assignment_statement(name, &id.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut stmts = self.ctx.ast.new_vec_with_capacity(2);
|
||||||
|
stmts.push(Statement::Declaration(Declaration::VariableDeclaration(var_decl)));
|
||||||
|
stmts.push(
|
||||||
|
self.ctx
|
||||||
|
.ast
|
||||||
|
.expression_statement(SPAN, self.ctx.ast.sequence_expression(SPAN, assignments)),
|
||||||
|
);
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the statements contain a namespace declaration
|
||||||
|
fn has_namespace(stmts: &[Statement]) -> bool {
|
||||||
|
stmts.iter().any(|stmt| match stmt {
|
||||||
|
Statement::Declaration(Declaration::TSModuleDeclaration(_)) => true,
|
||||||
|
Statement::ModuleDeclaration(module_decl) => {
|
||||||
|
if let ModuleDeclaration::ExportNamedDeclaration(decl) = &**module_decl {
|
||||||
|
matches!(decl.declaration, Some(Declaration::TSModuleDeclaration(_)))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Passed: 153/209
|
Passed: 157/209
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-react-jsx-source
|
* babel-plugin-transform-react-jsx-source
|
||||||
|
|
@ -17,7 +17,7 @@ Passed: 153/209
|
||||||
* opts/optimizeConstEnums/input.ts
|
* opts/optimizeConstEnums/input.ts
|
||||||
* opts/rewriteImportExtensions/input.ts
|
* opts/rewriteImportExtensions/input.ts
|
||||||
|
|
||||||
# babel-plugin-transform-typescript (97/139)
|
# babel-plugin-transform-typescript (101/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
|
||||||
* exports/declared-types/input.ts
|
* exports/declared-types/input.ts
|
||||||
|
|
@ -29,22 +29,18 @@ Passed: 153/209
|
||||||
* namespace/ambient-module-nested/input.ts
|
* namespace/ambient-module-nested/input.ts
|
||||||
* namespace/ambient-module-nested-exported/input.ts
|
* namespace/ambient-module-nested-exported/input.ts
|
||||||
* namespace/canonical/input.ts
|
* namespace/canonical/input.ts
|
||||||
* namespace/clobber-class/input.ts
|
|
||||||
* namespace/clobber-enum/input.ts
|
* namespace/clobber-enum/input.ts
|
||||||
* namespace/clobber-export/input.ts
|
|
||||||
* namespace/clobber-import/input.ts
|
|
||||||
* namespace/contentious-names/input.ts
|
* namespace/contentious-names/input.ts
|
||||||
* namespace/empty-removed/input.ts
|
* namespace/empty-removed/input.ts
|
||||||
* namespace/export-type-only/input.ts
|
|
||||||
* namespace/module-nested/input.ts
|
* namespace/module-nested/input.ts
|
||||||
* namespace/module-nested-export/input.ts
|
* namespace/module-nested-export/input.ts
|
||||||
|
* namespace/multiple/input.ts
|
||||||
* namespace/mutable-fail/input.ts
|
* namespace/mutable-fail/input.ts
|
||||||
* namespace/namespace-flag/input.ts
|
* namespace/namespace-flag/input.ts
|
||||||
* namespace/namespace-nested-module/input.ts
|
* namespace/namespace-nested-module/input.ts
|
||||||
* namespace/nested/input.ts
|
* namespace/nested/input.ts
|
||||||
* namespace/nested-destructuring/input.ts
|
* namespace/nested-destructuring/input.ts
|
||||||
* namespace/nested-namespace/input.ts
|
* namespace/nested-namespace/input.ts
|
||||||
* namespace/nested-shorthand/input.ts
|
|
||||||
* namespace/nested-shorthand-export/input.ts
|
* namespace/nested-shorthand-export/input.ts
|
||||||
* namespace/same-name/input.ts
|
* namespace/same-name/input.ts
|
||||||
* optimize-const-enums/custom-values/input.ts
|
* optimize-const-enums/custom-values/input.ts
|
||||||
|
|
|
||||||
|
|
@ -533,7 +533,7 @@ let M1;
|
||||||
EImpl1[EImpl1['F'] = F] = 'F';
|
EImpl1[EImpl1['F'] = F] = 'F';
|
||||||
return EImpl1;
|
return EImpl1;
|
||||||
})(EImpl1 || {});
|
})(EImpl1 || {});
|
||||||
export var EConst1 = (EConst1 => {
|
var EConst1 = (EConst1 => {
|
||||||
const A = 3;
|
const A = 3;
|
||||||
EConst1[EConst1['A'] = A] = 'A';
|
EConst1[EConst1['A'] = A] = 'A';
|
||||||
const B = 2;
|
const B = 2;
|
||||||
|
|
@ -542,7 +542,8 @@ export var EConst1 = (EConst1 => {
|
||||||
EConst1[EConst1['C'] = C] = 'C';
|
EConst1[EConst1['C'] = C] = 'C';
|
||||||
return EConst1;
|
return EConst1;
|
||||||
})(EConst1 || {});
|
})(EConst1 || {});
|
||||||
export var EConst1 = (EConst1 => {
|
_M1.EConst1 = EConst1;
|
||||||
|
var EConst1 = (EConst1 => {
|
||||||
const D = 7;
|
const D = 7;
|
||||||
EConst1[EConst1['D'] = D] = 'D';
|
EConst1[EConst1['D'] = D] = 'D';
|
||||||
const E = 9;
|
const E = 9;
|
||||||
|
|
@ -551,11 +552,12 @@ export var EConst1 = (EConst1 => {
|
||||||
EConst1[EConst1['F'] = F] = 'F';
|
EConst1[EConst1['F'] = F] = 'F';
|
||||||
return EConst1;
|
return EConst1;
|
||||||
})(EConst1 || {});
|
})(EConst1 || {});
|
||||||
|
_M1.EConst1 = EConst1;
|
||||||
var x = [EConst1.A, EConst1.B, EConst1.C, EConst1.D, EConst1.E, EConst1.F];
|
var x = [EConst1.A, EConst1.B, EConst1.C, EConst1.D, EConst1.E, EConst1.F];
|
||||||
})(M1 || (M1 = {}));
|
})(M1 || (M1 = {}));
|
||||||
let M2;
|
let M2;
|
||||||
(function(_M2) {
|
(function(_M2) {
|
||||||
export var EComp2 = (EComp2 => {
|
var EComp2 = (EComp2 => {
|
||||||
const A = 'foo'.length;
|
const A = 'foo'.length;
|
||||||
EComp2[EComp2['A'] = A] = 'A';
|
EComp2[EComp2['A'] = A] = 'A';
|
||||||
const B = 'foo'.length;
|
const B = 'foo'.length;
|
||||||
|
|
@ -564,7 +566,8 @@ export var EComp2 = (EComp2 => {
|
||||||
EComp2[EComp2['C'] = C] = 'C';
|
EComp2[EComp2['C'] = C] = 'C';
|
||||||
return EComp2;
|
return EComp2;
|
||||||
})(EComp2 || {});
|
})(EComp2 || {});
|
||||||
export var EComp2 = (EComp2 => {
|
_M2.EComp2 = EComp2;
|
||||||
|
var EComp2 = (EComp2 => {
|
||||||
const D = 'foo'.length;
|
const D = 'foo'.length;
|
||||||
EComp2[EComp2['D'] = D] = 'D';
|
EComp2[EComp2['D'] = D] = 'D';
|
||||||
const E = 'foo'.length;
|
const E = 'foo'.length;
|
||||||
|
|
@ -573,6 +576,7 @@ export var EComp2 = (EComp2 => {
|
||||||
EComp2[EComp2['F'] = F] = 'F';
|
EComp2[EComp2['F'] = F] = 'F';
|
||||||
return EComp2;
|
return EComp2;
|
||||||
})(EComp2 || {});
|
})(EComp2 || {});
|
||||||
|
_M2.EComp2 = EComp2;
|
||||||
var x = [EComp2.A, EComp2.B, EComp2.C, EComp2.D, EComp2.E, EComp2.F];
|
var x = [EComp2.A, EComp2.B, EComp2.C, EComp2.D, EComp2.E, EComp2.F];
|
||||||
})(M2 || (M2 = {}));
|
})(M2 || (M2 = {}));
|
||||||
let M3;
|
let M3;
|
||||||
|
|
@ -596,7 +600,7 @@ let M3;
|
||||||
})(M3 || (M3 = {}));
|
})(M3 || (M3 = {}));
|
||||||
let M4;
|
let M4;
|
||||||
(function(_M4) {
|
(function(_M4) {
|
||||||
export var Color = (Color => {
|
var Color = (Color => {
|
||||||
const Red = 0;
|
const Red = 0;
|
||||||
Color[Color['Red'] = Red] = 'Red';
|
Color[Color['Red'] = Red] = 'Red';
|
||||||
const Green = 1 + Red;
|
const Green = 1 + Red;
|
||||||
|
|
@ -605,10 +609,11 @@ export var Color = (Color => {
|
||||||
Color[Color['Blue'] = Blue] = 'Blue';
|
Color[Color['Blue'] = Blue] = 'Blue';
|
||||||
return Color;
|
return Color;
|
||||||
})(Color || {});
|
})(Color || {});
|
||||||
|
_M4.Color = Color;
|
||||||
})(M4 || (M4 = {}));
|
})(M4 || (M4 = {}));
|
||||||
let M5;
|
let M5;
|
||||||
(function(_M5) {
|
(function(_M5) {
|
||||||
export var Color = (Color => {
|
var Color = (Color => {
|
||||||
const Red = 0;
|
const Red = 0;
|
||||||
Color[Color['Red'] = Red] = 'Red';
|
Color[Color['Red'] = Red] = 'Red';
|
||||||
const Green = 1 + Red;
|
const Green = 1 + Red;
|
||||||
|
|
@ -617,11 +622,13 @@ export var Color = (Color => {
|
||||||
Color[Color['Blue'] = Blue] = 'Blue';
|
Color[Color['Blue'] = Blue] = 'Blue';
|
||||||
return Color;
|
return Color;
|
||||||
})(Color || {});
|
})(Color || {});
|
||||||
|
_M5.Color = Color;
|
||||||
})(M5 || (M5 = {}));
|
})(M5 || (M5 = {}));
|
||||||
let M6;
|
let M6;
|
||||||
(function(_M6) {
|
(function(_M6) {
|
||||||
|
let A;
|
||||||
(function(_A) {
|
(function(_A) {
|
||||||
export var Color = (Color => {
|
var Color = (Color => {
|
||||||
const Red = 0;
|
const Red = 0;
|
||||||
Color[Color['Red'] = Red] = 'Red';
|
Color[Color['Red'] = Red] = 'Red';
|
||||||
const Green = 1 + Red;
|
const Green = 1 + Red;
|
||||||
|
|
@ -630,17 +637,19 @@ export var Color = (Color => {
|
||||||
Color[Color['Blue'] = Blue] = 'Blue';
|
Color[Color['Blue'] = Blue] = 'Blue';
|
||||||
return Color;
|
return Color;
|
||||||
})(Color || {});
|
})(Color || {});
|
||||||
})(A || (A = {}));
|
_A.Color = Color;
|
||||||
|
})(A || (A = _M6.A || (_M6.A = {})));
|
||||||
})(M6 || (M6 = {}));
|
})(M6 || (M6 = {}));
|
||||||
(function(_M62) {
|
(function(_M6) {
|
||||||
export let A;
|
let A;
|
||||||
(function(_A) {
|
(function(_A) {
|
||||||
export var Color = (Color => {
|
var Color = (Color => {
|
||||||
const Yellow = 1;
|
const Yellow = 1;
|
||||||
Color[Color['Yellow'] = Yellow] = 'Yellow';
|
Color[Color['Yellow'] = Yellow] = 'Yellow';
|
||||||
return Color;
|
return Color;
|
||||||
})(Color || {});
|
})(Color || {});
|
||||||
})(A || (A = {}));
|
_A.Color = Color;
|
||||||
|
})(A || (A = _M6.A || (_M6.A = {})));
|
||||||
var t = A.Color.Yellow;
|
var t = A.Color.Yellow;
|
||||||
t = A.Color.Red;
|
t = A.Color.Red;
|
||||||
})(M6 || (M6 = {}));
|
})(M6 || (M6 = {}));
|
||||||
|
|
@ -651,99 +660,114 @@ export var Color = (Color => {
|
||||||
```typescript
|
```typescript
|
||||||
let M;
|
let M;
|
||||||
(function(_M) {
|
(function(_M) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const A = 0;
|
const A = 0;
|
||||||
E1[E1['A'] = A] = 'A';
|
E1[E1['A'] = A] = 'A';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
export var E2 = (E2 => {
|
_M.E1 = E1;
|
||||||
|
var E2 = (E2 => {
|
||||||
const C = 0;
|
const C = 0;
|
||||||
E2[E2['C'] = C] = 'C';
|
E2[E2['C'] = C] = 'C';
|
||||||
return E2;
|
return E2;
|
||||||
})(E2 || {});
|
})(E2 || {});
|
||||||
export var E3 = (E3 => {
|
_M.E2 = E2;
|
||||||
|
var E3 = (E3 => {
|
||||||
const A = 0;
|
const A = 0;
|
||||||
E3[E3['A'] = A] = 'A';
|
E3[E3['A'] = A] = 'A';
|
||||||
return E3;
|
return E3;
|
||||||
})(E3 || {});
|
})(E3 || {});
|
||||||
|
_M.E3 = E3;
|
||||||
})(M || (M = {}));
|
})(M || (M = {}));
|
||||||
(function(_M2) {
|
(function(_M) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const B = 'foo'.length;
|
const B = 'foo'.length;
|
||||||
E1[E1['B'] = B] = 'B';
|
E1[E1['B'] = B] = 'B';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
export var E2 = (E2 => {
|
_M.E1 = E1;
|
||||||
|
var E2 = (E2 => {
|
||||||
const B = 'foo'.length;
|
const B = 'foo'.length;
|
||||||
E2[E2['B'] = B] = 'B';
|
E2[E2['B'] = B] = 'B';
|
||||||
return E2;
|
return E2;
|
||||||
})(E2 || {});
|
})(E2 || {});
|
||||||
export var E3 = (E3 => {
|
_M.E2 = E2;
|
||||||
|
var E3 = (E3 => {
|
||||||
const C = 0;
|
const C = 0;
|
||||||
E3[E3['C'] = C] = 'C';
|
E3[E3['C'] = C] = 'C';
|
||||||
return E3;
|
return E3;
|
||||||
})(E3 || {});
|
})(E3 || {});
|
||||||
|
_M.E3 = E3;
|
||||||
})(M || (M = {}));
|
})(M || (M = {}));
|
||||||
(function(_M3) {
|
(function(_M) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const C = 0;
|
const C = 0;
|
||||||
E1[E1['C'] = C] = 'C';
|
E1[E1['C'] = C] = 'C';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
export var E2 = (E2 => {
|
_M.E1 = E1;
|
||||||
|
var E2 = (E2 => {
|
||||||
const A = 0;
|
const A = 0;
|
||||||
E2[E2['A'] = A] = 'A';
|
E2[E2['A'] = A] = 'A';
|
||||||
return E2;
|
return E2;
|
||||||
})(E2 || {});
|
})(E2 || {});
|
||||||
export var E3 = (E3 => {
|
_M.E2 = E2;
|
||||||
|
var E3 = (E3 => {
|
||||||
const B = 'foo'.length;
|
const B = 'foo'.length;
|
||||||
E3[E3['B'] = B] = 'B';
|
E3[E3['B'] = B] = 'B';
|
||||||
return E3;
|
return E3;
|
||||||
})(E3 || {});
|
})(E3 || {});
|
||||||
|
_M.E3 = E3;
|
||||||
})(M || (M = {}));
|
})(M || (M = {}));
|
||||||
let M1;
|
let M1;
|
||||||
(function(_M1) {
|
(function(_M1) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const A = 0;
|
const A = 0;
|
||||||
E1[E1['A'] = A] = 'A';
|
E1[E1['A'] = A] = 'A';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M1.E1 = E1;
|
||||||
})(M1 || (M1 = {}));
|
})(M1 || (M1 = {}));
|
||||||
(function(_M12) {
|
(function(_M1) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const B = 0;
|
const B = 0;
|
||||||
E1[E1['B'] = B] = 'B';
|
E1[E1['B'] = B] = 'B';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M1.E1 = E1;
|
||||||
})(M1 || (M1 = {}));
|
})(M1 || (M1 = {}));
|
||||||
(function(_M13) {
|
(function(_M1) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const C = 0;
|
const C = 0;
|
||||||
E1[E1['C'] = C] = 'C';
|
E1[E1['C'] = C] = 'C';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M1.E1 = E1;
|
||||||
})(M1 || (M1 = {}));
|
})(M1 || (M1 = {}));
|
||||||
let M2;
|
let M2;
|
||||||
(function(_M2) {
|
(function(_M2) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const A = 0;
|
const A = 0;
|
||||||
E1[E1['A'] = A] = 'A';
|
E1[E1['A'] = A] = 'A';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M2.E1 = E1;
|
||||||
})(M2 || (M2 = {}));
|
})(M2 || (M2 = {}));
|
||||||
(function(_M22) {
|
(function(_M2) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const B = 0;
|
const B = 0;
|
||||||
E1[E1['B'] = B] = 'B';
|
E1[E1['B'] = B] = 'B';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M2.E1 = E1;
|
||||||
})(M2 || (M2 = {}));
|
})(M2 || (M2 = {}));
|
||||||
(function(_M23) {
|
(function(_M2) {
|
||||||
export var E1 = (E1 => {
|
var E1 = (E1 => {
|
||||||
const C = 0;
|
const C = 0;
|
||||||
E1[E1['C'] = C] = 'C';
|
E1[E1['C'] = C] = 'C';
|
||||||
return E1;
|
return E1;
|
||||||
})(E1 || {});
|
})(E1 || {});
|
||||||
|
_M2.E1 = E1;
|
||||||
})(M2 || (M2 = {}));
|
})(M2 || (M2 = {}));
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue