Skip to content

Commit

Permalink
draft: namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
magic-akari committed Jun 26, 2023
1 parent 0d93b04 commit 9d72649
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 40 deletions.
206 changes: 169 additions & 37 deletions crates/swc_ecma_transforms_typescript/src/transform.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::mem;
use std::{mem, vec};

use swc_common::{collections::AHashSet, util::take::Take, Mark, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::constructor::inject_after_super;
use swc_ecma_utils::{constructor::inject_after_super, ExprFactory};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};

use crate::{
import_export_assign::import_export_assign,
utils::{make_assign_to_this, MerageableDecl},
utils::{make_assign_to_this, AsDecl, AsEnumOrModule},
TsImportExportAssignConfig,
};

Expand Down Expand Up @@ -42,7 +42,6 @@ pub(crate) struct Transform {
unresolved_mark: Mark,
import_export_assign_config: TsImportExportAssignConfig,

scope_depth: u16,
namespace_id: Option<Id>,
}

Expand Down Expand Up @@ -162,42 +161,43 @@ impl VisitMut for Transform {
}

fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
self.scope_depth += 1;
n.visit_mut_children_with(self);
self.scope_depth -= 1;

self.transform_stmts(n);
}

fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
self.scope_depth += 1;
n.visit_mut_children_with(self);
self.scope_depth -= 1;

self.transform_module_items(n);
}

fn visit_mut_ts_namespace_decl(&mut self, n: &mut TsNamespaceDecl) {
let id = n.id.to_id();
self.namespace_id = Some(id);
let old_id = self.namespace_id.replace(id);

n.body.visit_mut_with(self);

self.namespace_id = old_id;
}

fn visit_mut_ts_module_decl(&mut self, n: &mut TsModuleDecl) {
if let Some(id) = n.id.as_ident().map(Ident::to_id) {
self.namespace_id = Some(id);
}
let id =
n.id.as_ident()
.map(Ident::to_id)
.expect("Only ambient modules can use quoted names.");

let old_id = self.namespace_id.replace(id);

n.body.visit_mut_with(self);

self.namespace_id = old_id;
}
}

impl Transform {
fn transform_stmts(&mut self, n: &mut Vec<Stmt>) {
let found = (**n)
.iter()
.any(|stmt| matches!(stmt, Stmt::Decl(Decl::TsModule(..) | Decl::TsEnum(..))));
let found = (**n).iter().any(|stmt| stmt.is_enum_or_module());

if !found {
return;
Expand All @@ -206,16 +206,15 @@ impl Transform {
let mut decl_id = AHashSet::<Id>::default();

for mut stmt in n.take().drain(..) {
let id = stmt.get_decl_id();

if let Some(id) = &id {
if let Some(id) = stmt.get_enum_or_module_id() {
let var_stmt = self
.add_var_for_enum_or_module_declaration(id, &decl_id)
.add_var_for_enum_or_module_declaration(&id, &decl_id)
.map(Into::into);

n.extend(var_stmt);
}

let id = stmt.get_decl_id();
stmt = self.fold_stmt(stmt);
decl_id.extend(id);
n.push(stmt);
Expand All @@ -224,22 +223,16 @@ impl Transform {

fn fold_stmt(&self, n: Stmt) -> Stmt {
match n {
Stmt::Decl(Decl::TsModule(ts_module)) => self.transform_ts_module(*ts_module),
Stmt::Decl(Decl::TsModule(ts_module)) => self.transform_ts_module(*ts_module, false),
Stmt::Decl(Decl::TsEnum(ts_enum)) => self.transform_ts_enum(*ts_enum),
stmt => stmt,
}
}

fn transform_module_items(&mut self, n: &mut Vec<ModuleItem>) {
let found = (**n).iter().any(|module_item| {
matches!(
module_item,
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::TsModule(..) | Decl::TsEnum(..),
..
})) | ModuleItem::Stmt(Stmt::Decl(Decl::TsModule(..) | Decl::TsEnum(..)))
)
});
let found = (**n)
.iter()
.any(|module_item| module_item.is_enum_or_module());

if !found {
return;
Expand All @@ -248,12 +241,14 @@ impl Transform {
let mut decl_id = AHashSet::<Id>::default();

for mut module_item in n.take().drain(..) {
let id = module_item.get_decl_id();

if let Some(id) = &id {
if let Some(id) = &module_item.get_enum_or_module_id() {
let var_decl = self.add_var_for_enum_or_module_declaration(id, &decl_id);

let var_stmt = if self.scope_depth == 0 {
let var_stmt = if self.namespace_id.is_none()
&& matches!(
module_item,
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(..))
) {
// export var foo;
var_decl
.map(Box::new)
Expand All @@ -272,6 +267,7 @@ impl Transform {
n.extend(var_stmt);
}

let id = module_item.get_decl_id();
module_item = self.fold_module_item(module_item);
decl_id.extend(id);
n.push(module_item);
Expand All @@ -283,7 +279,7 @@ impl Transform {
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::TsModule(ts_module),
..
})) => self.transform_ts_module(*ts_module).into(),
})) => self.transform_ts_module(*ts_module, true).into(),
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::TsEnum(ts_enum),
..
Expand All @@ -302,7 +298,7 @@ impl Transform {
return None;
}

let kind = if self.scope_depth == 0 {
let kind = if self.namespace_id.is_none() {
VarDeclKind::Var
} else {
VarDeclKind::Let
Expand All @@ -323,11 +319,147 @@ impl Transform {
Some(var_decl)
}

fn transform_ts_module(&self, _ts_module: TsModuleDecl) -> Stmt {
todo!()
fn transform_ts_module(&self, ts_module: TsModuleDecl, is_export: bool) -> Stmt {
debug_assert!(!ts_module.declare);
debug_assert!(!ts_module.global);

let TsModuleDecl {
span,
id: TsModuleName::Ident(ident),
body: Some(body),
..
} = ts_module else { unreachable!() };

let body = self.transform_ts_namespace_body(ident.to_id(), body);

let mut module_arg = self
.get_namespace_or_enum_init_arg(ident.clone(), is_export)
.into();

if is_export && self.namespace_id.is_some() {
module_arg = AssignExpr {
span: DUMMY_SP,
op: op!("="),
left: PatOrExpr::Pat(Box::new(Pat::Ident(ident.into()))),
right: module_arg,
}
.into();
}

let expr = FnExpr {
ident: None,
function: Box::new(Function {
params: vec![],
decorators: vec![],
span: DUMMY_SP,
body: Some(body),
is_generator: false,
is_async: false,
type_params: None,
return_type: None,
}),
}
.as_call(DUMMY_SP, vec![module_arg.into()]);

Stmt::Expr(ExprStmt {
span,
expr: expr.into(),
})
}

fn transform_ts_enum(&self, _ts_enum: TsEnumDecl) -> Stmt {
todo!()
}

fn transform_ts_namespace_body(
&self,
container_name: Id,
ts_namespace_body: TsNamespaceBody,
) -> BlockStmt {
let TsNamespaceDecl {
span,
declare,
global,
id: local_name,
body,
} = match ts_namespace_body {
TsNamespaceBody::TsModuleBlock(ts_module_block) => {
return self.transform_ts_module_block(container_name, ts_module_block);
}
TsNamespaceBody::TsNamespaceDecl(ts_namespace_decl) => ts_namespace_decl,
};

debug_assert!(!declare);
debug_assert!(!global);

let body = self.transform_ts_namespace_body(local_name.to_id(), *body);

let module_arg = self.get_namespace_or_enum_init_arg(local_name, true).into();

let expr = FnExpr {
ident: None,
function: Box::new(Function {
params: vec![],
decorators: vec![],
span: DUMMY_SP,
body: Some(body),
is_generator: false,
is_async: false,
type_params: None,
return_type: None,
}),
}
.as_call(DUMMY_SP, vec![module_arg]);

BlockStmt {
span,
stmts: vec![expr.into_stmt()],
}
}

fn transform_ts_module_block(&self, _id: Id, _ts_module_block: TsModuleBlock) -> BlockStmt {
BlockStmt {
span: DUMMY_SP,
stmts: vec![],
}
}

/// Gets the argument used in a transformed enum or namespace call expr.
///
/// Example:
/// * `MyNamespace.MyEnum || (MyNamespace.MyEnum = {})`
/// * or `MyEnum || (MyEnum = {})`
fn get_namespace_or_enum_init_arg(&self, ident: Ident, is_export: bool) -> Expr {
let mut left: Expr = ident.clone().into();
let mut assign_left: Pat = ident.clone().into();

if is_export {
if let Some(namespace_id) = self.namespace_id.clone() {
left = Ident::from(namespace_id).make_member(ident);
assign_left = Pat::Expr(Box::new(left.clone()))
}
}

BinExpr {
span: DUMMY_SP,
op: op!("||"),
left: left.into(),
right: Box::new(
AssignExpr {
span: DUMMY_SP,
op: op!("="),
left: assign_left.into(),
right: Box::new(
ObjectLit {
span: DUMMY_SP,
props: vec![],
}
.into(),
),
}
.into(),
),
}
.into()
}
}
Loading

0 comments on commit 9d72649

Please sign in to comment.