mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 14:16:12 +03:00
swc_ecma_transforms: - hygiene::operator now handles export correctly (#295) - make function hoisting respect directives
This commit is contained in:
parent
21f3f792d1
commit
99e34ddbbd
@ -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 };
|
||||
};
|
||||
}
|
||||
"
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -664,3 +664,13 @@ identical!(
|
||||
|
||||
__assign.apply(this, arguments);"
|
||||
);
|
||||
|
||||
identical!(
|
||||
issue_295,
|
||||
"export var bar = {};
|
||||
class Foo {
|
||||
constructor() {
|
||||
bar;
|
||||
}
|
||||
}"
|
||||
);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}",
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user