mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
feat(ES/transform/typescript): Support namespace (#1325)
swc_common: - Update `serde`. swc_ecma_transforms_typescript: - Add support for namespace.
This commit is contained in:
parent
ebc0d0a203
commit
6984217200
1
bundler/tests/deno-exec/deno-9097/entry.ts
Normal file
1
bundler/tests/deno-exec/deno-9097/entry.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from 'https://raw.githubusercontent.com/colinhacks/zod/654680afc2ede388e71e09104eac5a0088fe3207/deno/lib/index.ts'
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_common"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.10.8"
|
||||
version = "0.10.9"
|
||||
|
||||
[features]
|
||||
concurrent = ["parking_lot"]
|
||||
@ -15,7 +15,7 @@ tty-emitter = ["atty", "termcolor"]
|
||||
|
||||
[dependencies]
|
||||
arbitrary = {version = "0.4.7", optional = true, features = ["derive"]}
|
||||
ast_node = {version = "0.7", path = "../macros/ast_node"}
|
||||
ast_node = {version = "0.7.1", path = "../macros/ast_node"}
|
||||
atty = {version = "0.2", optional = true}
|
||||
cfg-if = "0.1.2"
|
||||
either = "1.5"
|
||||
@ -27,7 +27,7 @@ once_cell = "1"
|
||||
owning_ref = "0.4"
|
||||
parking_lot = {version = "0.7.1", optional = true}
|
||||
scoped-tls = {version = "1"}
|
||||
serde = {version = "1", features = ["derive"]}
|
||||
serde = {version = "1.0.119", features = ["derive"]}
|
||||
sourcemap = {version = "6", optional = true}
|
||||
string_cache = "0.8.1"
|
||||
swc_eq_ignore_macros = {version = "0.1", path = "../macros/eq_ignore"}
|
||||
|
@ -32,6 +32,8 @@ use std::fmt::Debug;
|
||||
pub use swc_eq_ignore_macros::EqIgnoreSpan;
|
||||
pub use swc_eq_ignore_macros::TypeEq;
|
||||
pub use swc_visit::chain;
|
||||
#[doc(hidden)]
|
||||
pub mod private;
|
||||
|
||||
/// A trait for ast nodes.
|
||||
pub trait AstNode: Debug + PartialEq + Clone + Spanned + Serialize {
|
||||
|
3
common/src/private/mod.rs
Normal file
3
common/src/private/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! This module is private module and can be changed without notice.
|
||||
|
||||
pub use serde::__private as serde;
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecmascript"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.17.1"
|
||||
version = "0.17.2"
|
||||
|
||||
[features]
|
||||
codegen = ["swc_ecma_codegen"]
|
||||
@ -28,7 +28,7 @@ swc_ecma_ast = {version = "0.36.0", path = "./ast"}
|
||||
swc_ecma_codegen = {version = "0.42.0", path = "./codegen", optional = true}
|
||||
swc_ecma_dep_graph = {version = "0.11.0", path = "./dep-graph", optional = true}
|
||||
swc_ecma_parser = {version = "0.44.0", path = "./parser", optional = true}
|
||||
swc_ecma_transforms = {version = "0.32.1", path = "./transforms", optional = true}
|
||||
swc_ecma_transforms = {version = "0.32.2", path = "./transforms", optional = true}
|
||||
swc_ecma_utils = {version = "0.26.0", path = "./utils", optional = true}
|
||||
swc_ecma_visit = {version = "0.22.0", path = "./visit", optional = true}
|
||||
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.32.1"
|
||||
version = "0.32.2"
|
||||
|
||||
[features]
|
||||
compat = ["swc_ecma_transforms_compat"]
|
||||
@ -27,7 +27,7 @@ swc_ecma_transforms_module = {version = "0.2.0", path = "./module", optional = t
|
||||
swc_ecma_transforms_optimization = {version = "0.2.2", path = "./optimization", optional = true}
|
||||
swc_ecma_transforms_proposal = {version = "0.2.0", path = "./proposal", optional = true}
|
||||
swc_ecma_transforms_react = {version = "0.2.0", path = "./react", optional = true}
|
||||
swc_ecma_transforms_typescript = {version = "0.2.1", path = "./typescript", optional = true}
|
||||
swc_ecma_transforms_typescript = {version = "0.2.2", path = "./typescript", optional = true}
|
||||
swc_ecma_utils = {version = "0.26.0", path = "../utils"}
|
||||
swc_ecma_visit = {version = "0.22.0", path = "../visit"}
|
||||
unicode-xid = "0.2"
|
||||
|
@ -6,14 +6,14 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms_typescript"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
fxhash = "0.2.1"
|
||||
serde = {version = "1.0.118", features = ["derive"]}
|
||||
swc_atoms = {version = "0.2", path = "../../../atoms"}
|
||||
swc_common = {version = "0.10", path = "../../../common"}
|
||||
swc_common = {version = "0.10.9", path = "../../../common"}
|
||||
swc_ecma_ast = {version = "0.36", path = "../../ast"}
|
||||
swc_ecma_parser = {version = "0.44.1", path = "../../parser"}
|
||||
swc_ecma_transforms_base = {version = "0.1", path = "../base"}
|
||||
|
@ -6,6 +6,7 @@ use swc_common::{util::move_map::MoveMap, Span, Spanned, SyntaxContext, DUMMY_SP
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::ext::MapWithMut;
|
||||
use swc_ecma_utils::prepend_stmts;
|
||||
use swc_ecma_utils::private_ident;
|
||||
use swc_ecma_utils::var::VarCollector;
|
||||
use swc_ecma_utils::ExprFactory;
|
||||
use swc_ecma_utils::{ident::IdentLike, Id, StmtLike};
|
||||
@ -501,6 +502,186 @@ impl Strip {
|
||||
.into_stmt(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns `(var_decl, init)`.
|
||||
fn handle_ts_module(&mut self, module: TsModuleDecl) -> Option<(Decl, Stmt)> {
|
||||
let module_name = match module.id {
|
||||
TsModuleName::Ident(i) => i,
|
||||
TsModuleName::Str(_) => return None,
|
||||
};
|
||||
let body = module.body?;
|
||||
let mut body = match body {
|
||||
TsNamespaceBody::TsModuleBlock(body) => body,
|
||||
TsNamespaceBody::TsNamespaceDecl(_) => return None,
|
||||
};
|
||||
let mut init_stmts = vec![];
|
||||
|
||||
let var = VarDeclarator {
|
||||
span: module_name.span,
|
||||
name: Pat::Ident(module_name.clone()),
|
||||
init: None,
|
||||
definite: false,
|
||||
};
|
||||
|
||||
// This makes body valid javascript.
|
||||
body.body.visit_mut_with(self);
|
||||
|
||||
let private_name = private_ident!(module_name.sym.clone());
|
||||
|
||||
for item in body.body {
|
||||
// Drop
|
||||
|
||||
match item {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
span, decl, ..
|
||||
})) => {
|
||||
let decl_name = match decl {
|
||||
Decl::Class(ref c) => c.ident.clone(),
|
||||
Decl::Fn(ref f) => f.ident.clone(),
|
||||
Decl::Var(v) => {
|
||||
let mut exprs = vec![];
|
||||
for decl in v.decls {
|
||||
let init = match decl.init {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
match decl.name {
|
||||
Pat::Ident(name) => {
|
||||
//
|
||||
let left =
|
||||
PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr {
|
||||
span: DUMMY_SP,
|
||||
obj: private_name.clone().as_obj(),
|
||||
prop: Box::new(Expr::Ident(name.clone())),
|
||||
computed: false,
|
||||
})));
|
||||
|
||||
exprs.push(Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left,
|
||||
right: init,
|
||||
})))
|
||||
}
|
||||
_ => {
|
||||
let pat =
|
||||
Box::new(create_prop_pat(&private_name, decl.name));
|
||||
// Destructure the variable.
|
||||
exprs.push(Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left: PatOrExpr::Pat(pat),
|
||||
right: init,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
if !exprs.is_empty() {
|
||||
init_stmts.push(Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: if exprs.len() == 1 {
|
||||
exprs.into_iter().next().unwrap()
|
||||
} else {
|
||||
Box::new(Expr::Seq(SeqExpr {
|
||||
span: DUMMY_SP,
|
||||
exprs,
|
||||
}))
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO: Implement this using alias.
|
||||
continue;
|
||||
}
|
||||
Decl::TsInterface(_)
|
||||
| Decl::TsTypeAlias(_)
|
||||
| Decl::TsEnum(_)
|
||||
| Decl::TsModule(_) => continue,
|
||||
};
|
||||
init_stmts.push(Stmt::Decl(decl));
|
||||
|
||||
//
|
||||
let left = PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr {
|
||||
span: DUMMY_SP,
|
||||
obj: private_name.clone().as_obj(),
|
||||
prop: Box::new(Expr::Ident(decl_name.clone())),
|
||||
computed: false,
|
||||
})));
|
||||
|
||||
let right = Box::new(Expr::Ident(decl_name));
|
||||
|
||||
init_stmts.push(Stmt::Expr(ExprStmt {
|
||||
span,
|
||||
expr: Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left,
|
||||
right,
|
||||
})),
|
||||
}))
|
||||
}
|
||||
|
||||
ModuleItem::Stmt(stmt) => init_stmts.push(stmt),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let init_fn_expr = FnExpr {
|
||||
ident: None,
|
||||
function: Function {
|
||||
params: vec![Param {
|
||||
span: DUMMY_SP,
|
||||
decorators: Default::default(),
|
||||
pat: Pat::Ident(private_name.clone()),
|
||||
}],
|
||||
decorators: Default::default(),
|
||||
span: DUMMY_SP,
|
||||
body: Some(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: init_stmts,
|
||||
}),
|
||||
is_generator: false,
|
||||
is_async: false,
|
||||
type_params: Default::default(),
|
||||
return_type: Default::default(),
|
||||
},
|
||||
};
|
||||
|
||||
let init_arg = BinExpr {
|
||||
span: DUMMY_SP,
|
||||
left: Box::new(Expr::Ident(module_name.clone())),
|
||||
op: op!("||"),
|
||||
right: Box::new(Expr::Assign(AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left: PatOrExpr::Pat(Box::new(Pat::Ident(module_name.clone()))),
|
||||
right: Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: Default::default(),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
|
||||
let initializer = Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: init_fn_expr.as_callee(),
|
||||
args: vec![init_arg.as_arg()],
|
||||
type_args: Default::default(),
|
||||
}));
|
||||
|
||||
Some((
|
||||
Decl::Var(VarDecl {
|
||||
span: module.span,
|
||||
kind: VarDeclKind::Var,
|
||||
declare: false,
|
||||
decls: vec![var],
|
||||
}),
|
||||
Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: initializer,
|
||||
}),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for Strip {
|
||||
@ -765,7 +946,6 @@ impl VisitMut for Strip {
|
||||
match stmt {
|
||||
Stmt::Decl(ref decl) => match decl {
|
||||
Decl::TsInterface(..)
|
||||
| Decl::TsModule(..)
|
||||
| Decl::TsTypeAlias(..)
|
||||
| Decl::Var(VarDecl { declare: true, .. })
|
||||
| Decl::Class(ClassDecl { declare: true, .. })
|
||||
@ -789,6 +969,15 @@ impl VisitMut for Strip {
|
||||
match item {
|
||||
Stmt::Empty(..) => continue,
|
||||
|
||||
Stmt::Decl(Decl::TsModule(module)) => {
|
||||
let (decl, init) = match self.handle_ts_module(module) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
stmts.push(Stmt::Decl(decl));
|
||||
stmts.push(init)
|
||||
}
|
||||
|
||||
Stmt::Decl(Decl::TsEnum(e)) => {
|
||||
// var Foo;
|
||||
// (function (Foo) {
|
||||
@ -814,8 +1003,6 @@ impl VisitMut for Strip {
|
||||
function: Function { body: None, .. },
|
||||
..
|
||||
}))
|
||||
| Stmt::Decl(Decl::TsInterface(..))
|
||||
| Stmt::Decl(Decl::TsModule(..))
|
||||
| Stmt::Decl(Decl::TsTypeAlias(..)) => continue,
|
||||
|
||||
_ => {
|
||||
@ -891,22 +1078,42 @@ impl VisitMut for Strip {
|
||||
for mut item in take(items) {
|
||||
self.is_side_effect_import = false;
|
||||
match item {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
span,
|
||||
decl: Decl::TsModule(module),
|
||||
..
|
||||
})) => {
|
||||
let (decl, init) = match self.handle_ts_module(module) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
span,
|
||||
decl,
|
||||
})));
|
||||
stmts.push(init.into())
|
||||
}
|
||||
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::TsModule(module))) => {
|
||||
let (decl, init) = match self.handle_ts_module(module) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
stmts.push(Stmt::Decl(decl).into());
|
||||
stmts.push(init.into())
|
||||
}
|
||||
|
||||
// Strip out ts-only extensions
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
|
||||
function: Function { body: None, .. },
|
||||
..
|
||||
})))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsInterface(..)))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsModule(..)))
|
||||
| ModuleItem::Stmt(Stmt::Decl(Decl::TsTypeAlias(..)))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
decl: Decl::TsInterface(..),
|
||||
..
|
||||
}))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
decl: Decl::TsModule(..),
|
||||
..
|
||||
}))
|
||||
| ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
decl: Decl::TsTypeAlias(..),
|
||||
..
|
||||
@ -1124,3 +1331,50 @@ fn ts_entity_name_to_expr(n: TsEntityName) -> Expr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_prop_pat(obj: &Ident, pat: Pat) -> Pat {
|
||||
match pat {
|
||||
Pat::Invalid(_) => pat,
|
||||
|
||||
Pat::Ident(i) => Pat::Expr(Box::new(Expr::Member(MemberExpr {
|
||||
span: i.span,
|
||||
obj: obj.clone().as_obj(),
|
||||
prop: Box::new(Expr::Ident(i)),
|
||||
computed: false,
|
||||
}))),
|
||||
Pat::Array(p) => Pat::Array(ArrayPat {
|
||||
elems: p
|
||||
.elems
|
||||
.into_iter()
|
||||
.map(|elem| Some(create_prop_pat(obj, elem?)))
|
||||
.collect(),
|
||||
..p
|
||||
}),
|
||||
Pat::Rest(_) => {
|
||||
todo!("Rest pattern in an exported variable from namespace")
|
||||
}
|
||||
Pat::Object(p) => Pat::Object(ObjectPat {
|
||||
props: p
|
||||
.props
|
||||
.into_iter()
|
||||
.map(|prop| match prop {
|
||||
ObjectPatProp::KeyValue(kv) => ObjectPatProp::KeyValue(KeyValuePatProp {
|
||||
value: Box::new(create_prop_pat(obj, *kv.value)),
|
||||
..kv
|
||||
}),
|
||||
ObjectPatProp::Assign(..) => prop,
|
||||
ObjectPatProp::Rest(_) => {
|
||||
todo!("Rest pattern property in an exported variable from namespace")
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
..p
|
||||
}),
|
||||
Pat::Assign(p) => Pat::Assign(AssignPat {
|
||||
left: Box::new(create_prop_pat(obj, *p.left)),
|
||||
..p
|
||||
}),
|
||||
// TODO
|
||||
Pat::Expr(..) => pat,
|
||||
}
|
||||
}
|
||||
|
@ -3309,3 +3309,103 @@ to!(
|
||||
export { any };
|
||||
"
|
||||
);
|
||||
|
||||
to!(
|
||||
deno_9097,
|
||||
"
|
||||
export namespace util {
|
||||
export type AssertEqual<T, Expected> = T extends Expected
|
||||
? Expected extends T
|
||||
? true
|
||||
: false
|
||||
: false;
|
||||
|
||||
export function assertNever(_x: never): never {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type OmitKeys<T, K extends string> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type MakePartial<T, K extends keyof T> = Omit<T, K> &
|
||||
Partial<Pick<T, K>>;
|
||||
|
||||
export const arrayToEnum = <T extends string, U extends [T, ...T[]]>(
|
||||
items: U
|
||||
): { [k in U[number]]: k } => {
|
||||
};
|
||||
|
||||
export const getValidEnumValues = (obj: any) => {
|
||||
};
|
||||
|
||||
export const getValues = (obj: any) => {
|
||||
|
||||
};
|
||||
|
||||
export const objectValues = (obj: any) => {
|
||||
|
||||
};
|
||||
}
|
||||
",
|
||||
"
|
||||
export var util;
|
||||
(function (util1) {
|
||||
function assertNever(_x) {
|
||||
throw new Error();
|
||||
}
|
||||
util1.assertNever = assertNever;
|
||||
util1.arrayToEnum = (items) => {
|
||||
};
|
||||
util1.getValidEnumValues = (obj) => {
|
||||
};
|
||||
util1.getValues = (obj) => {
|
||||
};
|
||||
util1.objectValues = (obj) => {
|
||||
};
|
||||
})(util || (util = {}));
|
||||
|
||||
"
|
||||
);
|
||||
|
||||
to!(
|
||||
namespace_001,
|
||||
"
|
||||
export namespace util {
|
||||
const c = 3;
|
||||
export const [a, b] = [1, 2, 3];
|
||||
}
|
||||
",
|
||||
"
|
||||
export var util;
|
||||
(function (util1) {
|
||||
const c = 3;
|
||||
[util1.a, util1.b] = [1, 2, 3];
|
||||
})(util || (util = {}));
|
||||
"
|
||||
);
|
||||
|
||||
to!(
|
||||
namespace_002,
|
||||
"
|
||||
export namespace util {
|
||||
const c = 3;
|
||||
export function foo() {
|
||||
|
||||
}
|
||||
|
||||
function bar() {
|
||||
|
||||
}
|
||||
}
|
||||
",
|
||||
"
|
||||
export var util;
|
||||
(function (util1) {
|
||||
const c = 3;
|
||||
function foo() {
|
||||
}
|
||||
util1.foo = foo;
|
||||
function bar() {
|
||||
}
|
||||
})(util || (util = {}));
|
||||
"
|
||||
);
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "ast_node"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
@ -90,7 +90,7 @@ pub fn expand(
|
||||
{
|
||||
match std::result::Result::map(
|
||||
<VariantFieldType as serde::Deserialize>::deserialize(
|
||||
serde::private::de::ContentRefDeserializer::<D::Error>::new(
|
||||
swc_common::private::serde::de::ContentRefDeserializer::<D::Error>::new(
|
||||
&content,
|
||||
),
|
||||
),
|
||||
@ -120,7 +120,7 @@ pub fn expand(
|
||||
if TAGS.contains(&&*ty.ty) {
|
||||
return std::result::Result::map(
|
||||
<VariantFieldType as serde::Deserialize>::deserialize(
|
||||
serde::private::de::ContentRefDeserializer::<
|
||||
swc_common::private::serde::de::ContentRefDeserializer::<
|
||||
D::Error,
|
||||
>::new(
|
||||
&content
|
||||
@ -160,12 +160,12 @@ pub fn expand(
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let content =
|
||||
<serde::private::de::Content as serde::Deserialize>::deserialize(
|
||||
<swc_common::private::serde::de::Content as serde::Deserialize>::deserialize(
|
||||
Deserializer,
|
||||
)?;
|
||||
|
||||
let ty = swc_common::serializer::Type::deserialize(
|
||||
serde::private::de::ContentRefDeserializer::<D::Error>::new(
|
||||
swc_common::private::serde::de::ContentRefDeserializer::<D::Error>::new(
|
||||
&content,
|
||||
),
|
||||
)?;
|
||||
|
Loading…
Reference in New Issue
Block a user