feat(ES/transform/typescript): Support namespace (#1325)

swc_common:
 - Update `serde`.

swc_ecma_transforms_typescript:
 - Add support for namespace.
This commit is contained in:
강동윤 2021-01-12 21:59:42 +09:00 committed by GitHub
parent ebc0d0a203
commit 6984217200
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 382 additions and 22 deletions

View File

@ -0,0 +1 @@
export * from 'https://raw.githubusercontent.com/colinhacks/zod/654680afc2ede388e71e09104eac5a0088fe3207/deno/lib/index.ts'

View File

@ -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"}

View File

@ -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 {

View File

@ -0,0 +1,3 @@
//! This module is private module and can be changed without notice.
pub use serde::__private as serde;

View File

@ -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}

View File

@ -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"

View File

@ -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"}

View File

@ -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,
}
}

View File

@ -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 = {}));
"
);

View File

@ -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

View File

@ -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,
),
)?;