swc_ecma_transforms:
 - hygiene::operator now handles export correctly (#295)
 - make function hoisting respect directives
This commit is contained in:
강동윤 2019-03-01 14:02:33 +09:00 committed by GitHub
parent 21f3f792d1
commit 99e34ddbbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 246 additions and 1 deletions

View File

@ -11,6 +11,14 @@ impl Fold<Vec<Stmt>> for BlockScopedFns {
let mut extra_stmts = Vec::with_capacity(items.len());
for stmt in items {
match stmt {
Stmt::Expr(box Expr::Lit(Lit::Str(..))) => {
stmts.push(stmt);
continue;
}
_ => {}
}
// This is to preserve function Class()
if stmt.span().is_dummy() {
extra_stmts.push(stmt)
@ -181,4 +189,25 @@ function foo(scope) {
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| BlockScopedFns,
hoisting_directives,
"function foo() {
'use strict';
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
}",
"function foo() {
'use strict';
let _interopRequireDefault = function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
};
}
"
);
}

View File

@ -664,3 +664,13 @@ identical!(
__assign.apply(this, arguments);"
);
identical!(
issue_295,
"export var bar = {};
class Foo {
constructor() {
bar;
}
}"
);

View File

@ -1,6 +1,6 @@
use ast::*;
use swc_atoms::JsWord;
use swc_common::{Fold, FoldWith, SyntaxContext};
use swc_common::{util::move_map::MoveMap, Fold, FoldWith, Spanned, SyntaxContext, DUMMY_SP};
#[derive(Debug)]
pub(super) enum ScopeOp {
@ -12,6 +12,152 @@ pub(super) enum ScopeOp {
pub(super) struct Operator<'a>(pub &'a [ScopeOp]);
impl<'a> Fold<Vec<ModuleItem>> for Operator<'a> {
fn fold(&mut self, items: Vec<ModuleItem>) -> Vec<ModuleItem> {
let mut stmts = Vec::with_capacity(items.len());
for item in items {
let span = item.span();
macro_rules! export {
($orig:expr, $ident:expr) => {
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
span,
specifiers: vec![ExportSpecifier::Named(NamedExportSpecifier {
span: DUMMY_SP,
orig: $ident,
exported: Some($orig),
})],
src: None,
},
)));
};
}
match item {
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl:
Decl::Class(ClassDecl {
ident,
class,
declare,
}),
..
})) => {
let orig_ident = ident.clone();
match self.rename_ident(ident) {
Ok(ident) => {
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
ident: ident.clone(),
class,
declare,
}))));
export!(orig_ident, ident);
}
Err(ident) => {
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
ident,
class,
declare,
}))))
}
}
}
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl:
Decl::Fn(FnDecl {
ident,
function,
declare,
}),
..
})) => {
let orig_ident = ident.clone();
match self.rename_ident(ident) {
Ok(ident) => {
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
ident: ident.clone(),
function,
declare,
}))));
export!(orig_ident, ident);
}
Err(ident) => stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
ident,
function,
declare,
})))),
}
}
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::Var(var),
..
})) => {
let mut renamed: Vec<ExportSpecifier> = vec![];
let decls = var.decls.move_map(|decl| {
let name = decl.name.fold_with(&mut VarFolder {
orig: self,
renamed: &mut renamed,
});
VarDeclarator { name, ..decl }
});
if renamed.is_empty() {
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
span,
decl: Decl::Var(VarDecl { decls, ..var }),
})));
continue;
}
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
decls,
..var
}))));
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
span,
specifiers: renamed,
src: None,
},
)));
}
_ => stmts.push(item.fold_with(self)),
}
}
stmts
}
}
struct VarFolder<'a, 'b> {
orig: &'a mut Operator<'b>,
renamed: &'a mut Vec<ExportSpecifier>,
}
impl Fold<Ident> for VarFolder<'_, '_> {
fn fold(&mut self, i: Ident) -> Ident {
let orig = i.clone();
match self.orig.rename_ident(i) {
Ok(i) => {
self.renamed
.push(ExportSpecifier::Named(NamedExportSpecifier {
span: i.span,
exported: Some(orig),
orig: i.clone(),
}));
i
}
Err(i) => return i,
}
}
}
impl Fold<Expr> for VarFolder<'_, '_> {
fn fold(&mut self, n: Expr) -> Expr {
n
}
}
impl<'a> Fold<Prop> for Operator<'a> {
fn fold(&mut self, prop: Prop) -> Prop {
match prop {

View File

@ -1063,3 +1063,63 @@ fn issue_281_02() {
}",
);
}
#[test]
fn issue_295_01() {
test_module(
|tester| {
let mark1 = Mark::fresh(Mark::root());
Ok(tester
.parse_module(
"actual1.js",
"export const bar = {};
class Foo {
constructor() {
bar;
}
}",
)?
.fold_with(&mut OnceMarker::new(&[("bar", &[mark1, mark1, mark1])])))
},
"export const bar = {};
class Foo {
constructor() {
bar;
}
}",
);
}
#[test]
fn issue_295_02() {
test_module(
|tester| {
let mark1 = Mark::fresh(Mark::root());
let mark2 = Mark::fresh(Mark::root());
Ok(tester
.parse_module(
"actual1.js",
"export const bar = {};
class Foo {
constructor() {
bar;
}
}",
)?
.fold_with(&mut OnceMarker::new(&[("bar", &[mark1, mark2])])))
},
"const bar1 = {};
export { bar1 as bar };
class Foo {
constructor() {
bar;
}
}",
);
}