mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
Initialize var to undefined in loops (#306)
swc_ecma_transforms: - block_scoping: initialize var to undefined if it's declared in a loop (#305)
This commit is contained in:
parent
5dc4ba181d
commit
b5d3b9a7c7
@ -1,12 +1,132 @@
|
||||
use crate::pass::Pass;
|
||||
use crate::{pass::Pass, util::undefined};
|
||||
use ast::*;
|
||||
use swc_common::{Fold, FoldWith};
|
||||
use swc_common::{Fold, FoldWith, Spanned};
|
||||
|
||||
pub fn block_scoping() -> impl Pass {
|
||||
BlockScoping
|
||||
BlockScoping {
|
||||
in_loop_body: false,
|
||||
}
|
||||
}
|
||||
|
||||
struct BlockScoping;
|
||||
struct BlockScoping {
|
||||
in_loop_body: bool,
|
||||
}
|
||||
|
||||
impl Fold<DoWhileStmt> for BlockScoping {
|
||||
fn fold(&mut self, node: DoWhileStmt) -> DoWhileStmt {
|
||||
let body = node
|
||||
.body
|
||||
.fold_with(&mut BlockScoping { in_loop_body: true });
|
||||
|
||||
let test = node.test.fold_with(self);
|
||||
|
||||
DoWhileStmt { body, test, ..node }
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<WhileStmt> for BlockScoping {
|
||||
fn fold(&mut self, node: WhileStmt) -> WhileStmt {
|
||||
let body = node
|
||||
.body
|
||||
.fold_with(&mut BlockScoping { in_loop_body: true });
|
||||
|
||||
let test = node.test.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
WhileStmt { body, test, ..node }
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<ForStmt> for BlockScoping {
|
||||
fn fold(&mut self, node: ForStmt) -> ForStmt {
|
||||
let body = node
|
||||
.body
|
||||
.fold_with(&mut BlockScoping { in_loop_body: true });
|
||||
|
||||
let init = node.init.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
let test = node.test.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
let update = node.update.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
ForStmt {
|
||||
init,
|
||||
test,
|
||||
update,
|
||||
body,
|
||||
..node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<ForOfStmt> for BlockScoping {
|
||||
fn fold(&mut self, node: ForOfStmt) -> ForOfStmt {
|
||||
let body = node
|
||||
.body
|
||||
.fold_with(&mut BlockScoping { in_loop_body: true });
|
||||
|
||||
let left = node.left.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
let right = node.right.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
ForOfStmt {
|
||||
left,
|
||||
right,
|
||||
body,
|
||||
..node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<ForInStmt> for BlockScoping {
|
||||
fn fold(&mut self, node: ForInStmt) -> ForInStmt {
|
||||
let body = node
|
||||
.body
|
||||
.fold_with(&mut BlockScoping { in_loop_body: true });
|
||||
|
||||
let left = node.left.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
let right = node.right.fold_with(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
ForInStmt {
|
||||
left,
|
||||
right,
|
||||
body,
|
||||
..node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<Function> for BlockScoping {
|
||||
fn fold(&mut self, f: Function) -> Function {
|
||||
let f = f.fold_children(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
f
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<ArrowExpr> for BlockScoping {
|
||||
fn fold(&mut self, f: ArrowExpr) -> ArrowExpr {
|
||||
let f = f.fold_children(&mut BlockScoping {
|
||||
in_loop_body: false,
|
||||
});
|
||||
|
||||
f
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<VarDecl> for BlockScoping {
|
||||
fn fold(&mut self, var: VarDecl) -> VarDecl {
|
||||
@ -18,3 +138,58 @@ impl Fold<VarDecl> for BlockScoping {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold<VarDeclarator> for BlockScoping {
|
||||
fn fold(&mut self, var: VarDeclarator) -> VarDeclarator {
|
||||
let var = var.fold_children(self);
|
||||
|
||||
let init = if self.in_loop_body && var.init.is_none() {
|
||||
Some(undefined(var.span()))
|
||||
} else {
|
||||
var.init
|
||||
};
|
||||
|
||||
VarDeclarator { init, ..var }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::block_scoping;
|
||||
|
||||
test!(
|
||||
::swc_ecma_parser::Syntax::default(),
|
||||
|_| block_scoping(),
|
||||
for_loop,
|
||||
"for (const key in obj) {
|
||||
const bar = obj[key];
|
||||
|
||||
let qux;
|
||||
let fog;
|
||||
|
||||
if (Array.isArray(bar)) {
|
||||
qux = bar[0];
|
||||
fog = bar[1];
|
||||
} else {
|
||||
qux = bar;
|
||||
}
|
||||
|
||||
baz(key, qux, fog);
|
||||
}",
|
||||
"for (var key in obj) {
|
||||
var bar = obj[key];
|
||||
|
||||
var qux = void 0;
|
||||
var fog = void 0;
|
||||
|
||||
if (Array.isArray(bar)) {
|
||||
qux = bar[0];
|
||||
fog = bar[1];
|
||||
} else {
|
||||
qux = bar;
|
||||
}
|
||||
|
||||
baz(key, qux, fog);
|
||||
}"
|
||||
);
|
||||
}
|
||||
|
@ -774,7 +774,7 @@ var store = global[SHARED] || (global[SHARED] = {});
|
||||
identical!(member_await, "async function foo(){ (await bar).baz }");
|
||||
|
||||
identical!(bin_yield_expr_1, "function* foo(){ (yield foo) && bar }");
|
||||
|
||||
|
||||
identical!(bin_yield_expr_2, "function* foo(){ bar && (yield foo) }");
|
||||
|
||||
identical!(bin_seq_expr_1, "(foo(), op) || (seq(), foo)");
|
||||
|
Loading…
Reference in New Issue
Block a user