mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
Fix stack overflow (#1032)
swc_ecma_codegen: - Fix codegen of large binary expressions. swc_ecma_parser: - Fix stack overflow while parsing large binary expressions. swc_ecma_transforms: - typescrip::strip: Fix stack overflow while handling large binary operations. - hygiene: Fix stack overflow by migrating it to `VisitMut`. - hygiene: Improve performance. - fixer: Fix stack overflow by migrating it to `VisitMut`. - resolver: Migrate to `VisitMut`.
This commit is contained in:
parent
c0cb9e4401
commit
eb2162cbd2
1
.github/workflows/cargo.yml
vendored
1
.github/workflows/cargo.yml
vendored
@ -79,6 +79,7 @@ jobs:
|
|||||||
- name: Run cargo test
|
- name: Run cargo test
|
||||||
run: |
|
run: |
|
||||||
export PATH="$PATH:$HOME/npm/bin"
|
export PATH="$PATH:$HOME/npm/bin"
|
||||||
|
EXEC=0 cargo test --color always --all --exclude node --exclude wasm
|
||||||
cargo test --color always --all --exclude node --exclude wasm
|
cargo test --color always --all --exclude node --exclude wasm
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "swc_ecma_codegen"
|
name = "swc_ecma_codegen"
|
||||||
version = "0.35.0"
|
version = "0.35.1"
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
@ -16,6 +16,11 @@ mod tests {
|
|||||||
assert_min(r#" 'foobar' "#, r#"'foobar';"#);
|
assert_min(r#" 'foobar' "#, r#"'foobar';"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bin_expr() {
|
||||||
|
assert_min("1+2+3+4+5", "1+2+3+4+5;");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn template_expression() {
|
fn template_expression() {
|
||||||
assert_min("``", "``;");
|
assert_min("``", "``;");
|
||||||
|
@ -690,10 +690,9 @@ impl<'a> Emitter<'a> {
|
|||||||
emit!(node.right);
|
emit!(node.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[emitter]
|
/// Prints operator and right node of a binary expression.
|
||||||
fn emit_bin_expr(&mut self, node: &BinExpr) -> Result {
|
#[inline(never)]
|
||||||
self.emit_leading_comments_of_pos(node.span().lo())?;
|
fn emit_bin_expr_trailing(&mut self, node: &BinExpr) -> Result {
|
||||||
|
|
||||||
// let indent_before_op = needs_indention(node, &node.left, node.op);
|
// let indent_before_op = needs_indention(node, &node.left, node.op);
|
||||||
// let indent_after_op = needs_indention(node, node.op, &node.right);
|
// let indent_after_op = needs_indention(node, node.op, &node.right);
|
||||||
let need_space = match node.op {
|
let need_space = match node.op {
|
||||||
@ -701,19 +700,17 @@ impl<'a> Emitter<'a> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
emit!(node.left);
|
|
||||||
|
|
||||||
let need_pre_space = need_space
|
let need_pre_space = need_space
|
||||||
|| match *node.left {
|
|| match *node.left {
|
||||||
Expr::Update(UpdateExpr { prefix: false, .. }) => true,
|
Expr::Update(UpdateExpr { prefix: false, .. }) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if need_pre_space {
|
if need_pre_space {
|
||||||
space!();
|
space!(self);
|
||||||
} else {
|
} else {
|
||||||
formatting_space!();
|
formatting_space!(self);
|
||||||
}
|
}
|
||||||
operator!(node.op.as_str());
|
operator!(self, node.op.as_str());
|
||||||
|
|
||||||
let need_post_space = need_space
|
let need_post_space = need_space
|
||||||
|| match *node.right {
|
|| match *node.right {
|
||||||
@ -721,11 +718,47 @@ impl<'a> Emitter<'a> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if need_post_space {
|
if need_post_space {
|
||||||
space!();
|
space!(self);
|
||||||
} else {
|
} else {
|
||||||
formatting_space!();
|
formatting_space!(self);
|
||||||
}
|
}
|
||||||
emit!(node.right);
|
emit!(self, node.right);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[emitter]
|
||||||
|
fn emit_bin_expr(&mut self, node: &BinExpr) -> Result {
|
||||||
|
self.emit_leading_comments_of_pos(node.span().lo())?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut left = Some(node);
|
||||||
|
let mut lefts = vec![];
|
||||||
|
while let Some(l) = left {
|
||||||
|
lefts.push(l);
|
||||||
|
|
||||||
|
match &*l.left {
|
||||||
|
Expr::Bin(b) => {
|
||||||
|
left = Some(b);
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = lefts.len();
|
||||||
|
|
||||||
|
for (i, left) in lefts.into_iter().rev().enumerate() {
|
||||||
|
if i == 0 {
|
||||||
|
emit!(left.left);
|
||||||
|
}
|
||||||
|
// Check if it's last
|
||||||
|
if i + 1 != len {
|
||||||
|
self.emit_bin_expr_trailing(left)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.emit_bin_expr_trailing(node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[emitter]
|
#[emitter]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "swc_ecma_parser"
|
name = "swc_ecma_parser"
|
||||||
version = "0.37.0"
|
version = "0.37.1"
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
@ -39,10 +39,50 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
///
|
///
|
||||||
/// `parseExprOp`
|
/// `parseExprOp`
|
||||||
pub(in crate::parser) fn parse_bin_op_recursively(
|
pub(in crate::parser) fn parse_bin_op_recursively(
|
||||||
|
&mut self,
|
||||||
|
mut left: Box<Expr>,
|
||||||
|
mut min_prec: u8,
|
||||||
|
) -> PResult<Box<Expr>> {
|
||||||
|
loop {
|
||||||
|
let (next_left, next_prec) = self.parse_bin_op_recursively_inner(left, min_prec)?;
|
||||||
|
|
||||||
|
match &*next_left {
|
||||||
|
Expr::Bin(BinExpr {
|
||||||
|
span,
|
||||||
|
left,
|
||||||
|
op: op!("&&"),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| Expr::Bin(BinExpr {
|
||||||
|
span,
|
||||||
|
left,
|
||||||
|
op: op!("||"),
|
||||||
|
..
|
||||||
|
}) => match &**left {
|
||||||
|
Expr::Bin(BinExpr { op: op!("??"), .. }) => {
|
||||||
|
self.emit_err(*span, SyntaxError::NullishCoalescingWithLogicalOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
min_prec = match next_prec {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Ok(next_left),
|
||||||
|
};
|
||||||
|
|
||||||
|
left = next_left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `(left, Some(next_prec))` or `(expr, None)`.
|
||||||
|
fn parse_bin_op_recursively_inner(
|
||||||
&mut self,
|
&mut self,
|
||||||
left: Box<Expr>,
|
left: Box<Expr>,
|
||||||
min_prec: u8,
|
min_prec: u8,
|
||||||
) -> PResult<Box<Expr>> {
|
) -> PResult<(Box<Expr>, Option<u8>)> {
|
||||||
const PREC_OF_IN: u8 = 7;
|
const PREC_OF_IN: u8 = 7;
|
||||||
|
|
||||||
if self.input.syntax().typescript()
|
if self.input.syntax().typescript()
|
||||||
@ -69,21 +109,21 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
return self.parse_bin_op_recursively(node, min_prec);
|
return self.parse_bin_op_recursively_inner(node, min_prec);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx = self.ctx();
|
let ctx = self.ctx();
|
||||||
// Return left on eof
|
// Return left on eof
|
||||||
let word = match cur!(false) {
|
let word = match cur!(false) {
|
||||||
Ok(cur) => cur,
|
Ok(cur) => cur,
|
||||||
Err(..) => return Ok(left),
|
Err(..) => return Ok((left, None)),
|
||||||
};
|
};
|
||||||
let op = match *word {
|
let op = match *word {
|
||||||
Word(Word::Keyword(Keyword::In)) if ctx.include_in_expr => op!("in"),
|
Word(Word::Keyword(Keyword::In)) if ctx.include_in_expr => op!("in"),
|
||||||
Word(Word::Keyword(Keyword::InstanceOf)) => op!("instanceof"),
|
Word(Word::Keyword(Keyword::InstanceOf)) => op!("instanceof"),
|
||||||
Token::BinOp(op) => op.into(),
|
Token::BinOp(op) => op.into(),
|
||||||
_ => {
|
_ => {
|
||||||
return Ok(left);
|
return Ok((left, None));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,7 +140,7 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
op.precedence()
|
op.precedence()
|
||||||
);
|
);
|
||||||
|
|
||||||
return Ok(left);
|
return Ok((left, None));
|
||||||
}
|
}
|
||||||
bump!();
|
bump!();
|
||||||
trace!(
|
trace!(
|
||||||
@ -173,18 +213,7 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
right,
|
right,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let expr = self.parse_bin_op_recursively(node, min_prec)?;
|
return Ok((node, Some(min_prec)));
|
||||||
|
|
||||||
if op == op!("??") {
|
|
||||||
match *expr {
|
|
||||||
Expr::Bin(BinExpr { span, op, .. }) if op == op!("&&") || op == op!("||") => {
|
|
||||||
self.emit_err(span, SyntaxError::NullishCoalescingWithLogicalOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(expr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse unary expression and update expression.
|
/// Parse unary expression and update expression.
|
||||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
name = "swc_ecma_transforms"
|
name = "swc_ecma_transforms"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
version = "0.23.1"
|
version = "0.23.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
const-modules = ["dashmap"]
|
const-modules = ["dashmap"]
|
||||||
@ -25,6 +25,7 @@ jsdoc = {version = "0.5.0", path = "../jsdoc"}
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
ordered-float = "1.0.1"
|
ordered-float = "1.0.1"
|
||||||
|
phf = {version = "0.8.0", features = ["macros"]}
|
||||||
regex = "1"
|
regex = "1"
|
||||||
retain_mut = "=0.1.1"
|
retain_mut = "=0.1.1"
|
||||||
scoped-tls = "1"
|
scoped-tls = "1"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
use swc_common::Spanned;
|
// use swc_common::Spanned;
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{Fold, FoldWith};
|
use swc_ecma_visit::Fold;
|
||||||
|
|
||||||
/// This transform validates span on debug mode and does nothing on release
|
/// This transform validates span on debug mode and does nothing on release
|
||||||
/// mode.
|
/// mode.
|
||||||
@ -8,148 +8,109 @@ pub struct Validator {
|
|||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! ne {
|
|
||||||
($v:expr, $T:ty, $l:expr, $r:expr) => {{
|
|
||||||
// debug_assert_ne!(
|
|
||||||
// $l,
|
|
||||||
// $r,
|
|
||||||
// "{}: {}: {} should not be same as {}",
|
|
||||||
// $v.name,
|
|
||||||
// stringify!($T),
|
|
||||||
// stringify!($l),
|
|
||||||
// stringify!($r),
|
|
||||||
// );
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! lte {
|
|
||||||
($v:expr, $T:ty, $l:expr, $r:expr) => {{
|
|
||||||
// debug_assert!(
|
|
||||||
// $l <= $r,
|
|
||||||
// "{}: {}: {} should be <= {}; l={:?}; r={:?}",
|
|
||||||
// $v.name,
|
|
||||||
// stringify!($T),
|
|
||||||
// stringify!($l),
|
|
||||||
// stringify!($r),
|
|
||||||
// $l,
|
|
||||||
// $r
|
|
||||||
// );
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! gte {
|
|
||||||
($v:expr, $T:ty, $l:expr, $r:expr) => {{
|
|
||||||
// debug_assert!(
|
|
||||||
// $l >= $r,
|
|
||||||
// "{}: {}: {} should be >= {}; l={:?}; r={:?}",
|
|
||||||
// $v.name,
|
|
||||||
// stringify!($T),
|
|
||||||
// stringify!($l),
|
|
||||||
// stringify!($r),
|
|
||||||
// $l,
|
|
||||||
// $r
|
|
||||||
// );
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fold for Validator {
|
impl Fold for Validator {
|
||||||
fn fold_assign_expr(&mut self, node: AssignExpr) -> AssignExpr {
|
// fn fold_assign_expr(&mut self, node: AssignExpr) -> AssignExpr {
|
||||||
if node.span.is_dummy() {
|
// if node.span.is_dummy() {
|
||||||
return node.fold_children_with(self);
|
// return node.fold_children_with(self);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// if !node.left.span().is_dummy() {
|
||||||
|
// gte!(self, AssignExpr, node.left.span().lo(), node.span().lo());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // if !node.right.span().is_dummy() {
|
||||||
|
// // eq!(self, AssignExpr, node.right.span().hi(),
|
||||||
|
// node.span().hi()); // }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn fold_bin_expr(&mut self, node: BinExpr) -> BinExpr {
|
||||||
|
// if node.span.is_dummy() {
|
||||||
|
// return node.fold_children_with(self);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.left.span().is_dummy() {
|
||||||
|
// gte!(self, BinExpr, node.left.span().lo(), node.span().lo());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.right.span().is_dummy() {
|
||||||
|
// gte!(self, BinExpr, node.span().hi(), node.right.span().hi());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn fold_cond_expr(&mut self, node: CondExpr) -> CondExpr {
|
||||||
|
// if node.span.is_dummy() {
|
||||||
|
// return node.fold_children_with(self);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.test.span().is_dummy() {
|
||||||
|
// gte!(self, CondExpr, node.test.span().lo(), node.span().lo());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.alt.span().is_dummy() {
|
||||||
|
// lte!(self, CondExpr, node.alt.span().hi(), node.span().hi());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn fold_member_expr(&mut self, node: MemberExpr) -> MemberExpr {
|
||||||
|
// if node.span.is_dummy() {
|
||||||
|
// return node.fold_children_with(self);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.obj.span().is_dummy() {
|
||||||
|
// ne!(self, MemberExpr, node.span(), node.obj.span());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.prop.span().is_dummy() {
|
||||||
|
// ne!(self, MemberExpr, node.span(), node.prop.span());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.obj.span().is_dummy() {
|
||||||
|
// lte!(self, MemberExpr, node.span().lo(), node.obj.span().lo());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.computed && !node.prop.span().is_dummy() {
|
||||||
|
// gte!(self, MemberExpr, node.span().hi(), node.prop.span().hi());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn fold_unary_expr(&mut self, node: UnaryExpr) -> UnaryExpr {
|
||||||
|
// if node.span.is_dummy() {
|
||||||
|
// return node.fold_children_with(self);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !node.arg.span().is_dummy() {
|
||||||
|
// lte!(self, UnaryExpr, node.arg.span().hi(), node.span().hi())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn fold_update_expr(&mut self, node: UpdateExpr) -> UpdateExpr {
|
||||||
|
// if node.span.is_dummy() {
|
||||||
|
// return node.fold_children_with(self);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if node.prefix {
|
||||||
|
// if !node.arg.span().is_dummy() {
|
||||||
|
// lte!(self, UpdateExpr, node.arg.span().hi(), node.span().hi())
|
||||||
|
// }
|
||||||
|
// } else if !node.arg.span().is_dummy() {
|
||||||
|
// gte!(self, UpdateExpr, node.arg.span().lo(), node.span().lo())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// node.fold_children_with(self)
|
||||||
|
// }
|
||||||
|
|
||||||
if !node.left.span().is_dummy() {
|
#[inline(always)] // prevent stack overflow on debug build
|
||||||
gte!(self, AssignExpr, node.left.span().lo(), node.span().lo());
|
fn fold_module(&mut self, module: Module) -> Module {
|
||||||
}
|
module
|
||||||
|
|
||||||
// if !node.right.span().is_dummy() {
|
|
||||||
// eq!(self, AssignExpr, node.right.span().hi(), node.span().hi());
|
|
||||||
// }
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_bin_expr(&mut self, node: BinExpr) -> BinExpr {
|
|
||||||
if node.span.is_dummy() {
|
|
||||||
return node.fold_children_with(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.left.span().is_dummy() {
|
|
||||||
gte!(self, BinExpr, node.left.span().lo(), node.span().lo());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.right.span().is_dummy() {
|
|
||||||
gte!(self, BinExpr, node.span().hi(), node.right.span().hi());
|
|
||||||
}
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_cond_expr(&mut self, node: CondExpr) -> CondExpr {
|
|
||||||
if node.span.is_dummy() {
|
|
||||||
return node.fold_children_with(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.test.span().is_dummy() {
|
|
||||||
gte!(self, CondExpr, node.test.span().lo(), node.span().lo());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.alt.span().is_dummy() {
|
|
||||||
lte!(self, CondExpr, node.alt.span().hi(), node.span().hi());
|
|
||||||
}
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_member_expr(&mut self, node: MemberExpr) -> MemberExpr {
|
|
||||||
if node.span.is_dummy() {
|
|
||||||
return node.fold_children_with(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.obj.span().is_dummy() {
|
|
||||||
ne!(self, MemberExpr, node.span(), node.obj.span());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.prop.span().is_dummy() {
|
|
||||||
ne!(self, MemberExpr, node.span(), node.prop.span());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.obj.span().is_dummy() {
|
|
||||||
lte!(self, MemberExpr, node.span().lo(), node.obj.span().lo());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.computed && !node.prop.span().is_dummy() {
|
|
||||||
gte!(self, MemberExpr, node.span().hi(), node.prop.span().hi());
|
|
||||||
}
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_unary_expr(&mut self, node: UnaryExpr) -> UnaryExpr {
|
|
||||||
if node.span.is_dummy() {
|
|
||||||
return node.fold_children_with(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !node.arg.span().is_dummy() {
|
|
||||||
lte!(self, UnaryExpr, node.arg.span().hi(), node.span().hi())
|
|
||||||
}
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_update_expr(&mut self, node: UpdateExpr) -> UpdateExpr {
|
|
||||||
if node.span.is_dummy() {
|
|
||||||
return node.fold_children_with(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.prefix {
|
|
||||||
if !node.arg.span().is_dummy() {
|
|
||||||
lte!(self, UpdateExpr, node.arg.span().hi(), node.span().hi())
|
|
||||||
}
|
|
||||||
} else if !node.arg.span().is_dummy() {
|
|
||||||
gte!(self, UpdateExpr, node.arg.span().lo(), node.span().lo())
|
|
||||||
}
|
|
||||||
|
|
||||||
node.fold_children_with(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@ use swc_ecma_utils::ExprExt;
|
|||||||
pub(crate) trait MapWithMut: Sized {
|
pub(crate) trait MapWithMut: Sized {
|
||||||
fn dummy() -> Self;
|
fn dummy() -> Self;
|
||||||
|
|
||||||
|
fn take(&mut self) -> Self {
|
||||||
|
replace(self, Self::dummy())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map_with_mut<F>(&mut self, op: F)
|
fn map_with_mut<F>(&mut self, op: F)
|
||||||
where
|
where
|
||||||
@ -71,6 +75,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MapWithMut for Ident {
|
||||||
|
fn dummy() -> Self {
|
||||||
|
Ident::new(js_word!(""), DUMMY_SP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapWithMut for ObjectPatProp {
|
||||||
|
fn dummy() -> Self {
|
||||||
|
ObjectPatProp::Assign(AssignPatProp {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
key: Ident::dummy(),
|
||||||
|
value: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) trait PatOrExprExt: AsOptExpr {
|
pub(crate) trait PatOrExprExt: AsOptExpr {
|
||||||
fn as_ref(&self) -> &PatOrExpr;
|
fn as_ref(&self) -> &PatOrExpr;
|
||||||
fn as_mut(&mut self) -> &mut PatOrExpr;
|
fn as_mut(&mut self) -> &mut PatOrExpr;
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
use crate::{
|
use crate::ext::{AsOptExpr, MapWithMut, PatOrExprExt};
|
||||||
ext::{AsOptExpr, PatOrExprExt},
|
|
||||||
util::ExprFactory,
|
|
||||||
};
|
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use swc_common::{
|
use swc_common::{comments::Comments, Span, Spanned};
|
||||||
comments::Comments,
|
|
||||||
util::{map::Map, move_map::MoveMap},
|
|
||||||
Span, Spanned,
|
|
||||||
};
|
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||||
|
|
||||||
pub fn fixer<'a>(comments: Option<&'a dyn Comments>) -> impl 'a + Fold {
|
pub fn fixer<'a>(comments: Option<&'a dyn Comments>) -> impl 'a + Fold {
|
||||||
Fixer {
|
as_folder(Fixer {
|
||||||
comments,
|
comments,
|
||||||
ctx: Default::default(),
|
ctx: Default::default(),
|
||||||
span_map: Default::default(),
|
span_map: Default::default(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Fixer<'a> {
|
struct Fixer<'a> {
|
||||||
@ -56,123 +49,90 @@ impl Default for Context {
|
|||||||
|
|
||||||
macro_rules! array {
|
macro_rules! array {
|
||||||
($name:ident, $T:tt) => {
|
($name:ident, $T:tt) => {
|
||||||
fn $name(&mut self, e: $T) -> $T {
|
fn $name(&mut self, e: &mut $T) {
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: false }.into();
|
self.ctx = Context::ForcedExpr { is_var_decl: false }.into();
|
||||||
let elems = e.elems.fold_with(self);
|
e.elems.visit_mut_with(self);
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
$T { elems, ..e }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fold for Fixer<'_> {
|
impl VisitMut for Fixer<'_> {
|
||||||
noop_fold_type!();
|
noop_visit_mut_type!();
|
||||||
|
|
||||||
array!(fold_array_lit, ArrayLit);
|
array!(visit_mut_array_lit, ArrayLit);
|
||||||
// array!(ArrayPat);
|
// array!(ArrayPat);
|
||||||
|
|
||||||
fn fold_new_expr(&mut self, node: NewExpr) -> NewExpr {
|
fn visit_mut_new_expr(&mut self, node: &mut NewExpr) {
|
||||||
let NewExpr {
|
|
||||||
span,
|
|
||||||
mut callee,
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
} = node;
|
|
||||||
|
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
||||||
let args = args.fold_with(self);
|
node.args.visit_mut_with(self);
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::Callee { is_new: true };
|
self.ctx = Context::Callee { is_new: true };
|
||||||
callee = callee.fold_with(self);
|
node.callee.visit_mut_with(self);
|
||||||
match *callee {
|
match *node.callee {
|
||||||
Expr::Call(..) | Expr::Bin(..) => callee = Box::new(self.wrap(*callee)),
|
Expr::Call(..) | Expr::Bin(..) => self.wrap(&mut node.callee),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
NewExpr {
|
|
||||||
span,
|
|
||||||
callee,
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_call_expr(&mut self, node: CallExpr) -> CallExpr {
|
fn visit_mut_call_expr(&mut self, node: &mut CallExpr) {
|
||||||
let CallExpr {
|
|
||||||
span,
|
|
||||||
callee,
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
} = node;
|
|
||||||
|
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
||||||
let args = args.fold_with(self);
|
node.args.visit_mut_with(self);
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::Callee { is_new: false };
|
self.ctx = Context::Callee { is_new: false };
|
||||||
let callee = callee.fold_with(self);
|
node.callee.visit_mut_with(self);
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
CallExpr {
|
|
||||||
span,
|
|
||||||
callee,
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_arrow_expr(&mut self, node: ArrowExpr) -> ArrowExpr {
|
fn visit_mut_arrow_expr(&mut self, node: &mut ArrowExpr) {
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::Default;
|
self.ctx = Context::Default;
|
||||||
let mut node = node.fold_children_with(self);
|
node.visit_mut_children_with(self);
|
||||||
node.body = match node.body {
|
match &mut node.body {
|
||||||
BlockStmtOrExpr::Expr(e) if e.is_seq() => {
|
BlockStmtOrExpr::Expr(ref mut e) if e.is_seq() => {
|
||||||
BlockStmtOrExpr::Expr(Box::new(self.wrap(*e)))
|
self.wrap(&mut **e);
|
||||||
}
|
}
|
||||||
_ => node.body,
|
_ => {}
|
||||||
};
|
};
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_assign_pat_prop(&mut self, node: AssignPatProp) -> AssignPatProp {
|
fn visit_mut_assign_pat_prop(&mut self, node: &mut AssignPatProp) {
|
||||||
let key = node.key.fold_children_with(self);
|
node.key.visit_mut_children_with(self);
|
||||||
|
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
||||||
let value = node.value.fold_with(self);
|
node.value.visit_mut_with(self);
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
AssignPatProp { key, value, ..node }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block_stmt_or_expr(&mut self, body: BlockStmtOrExpr) -> BlockStmtOrExpr {
|
fn visit_mut_block_stmt_or_expr(&mut self, body: &mut BlockStmtOrExpr) {
|
||||||
let body = body.fold_children_with(self);
|
body.visit_mut_children_with(self);
|
||||||
|
|
||||||
match body {
|
match body {
|
||||||
BlockStmtOrExpr::Expr(expr) if expr.is_object() => {
|
BlockStmtOrExpr::Expr(ref mut expr) if expr.is_object() => {
|
||||||
BlockStmtOrExpr::Expr(Box::new(self.wrap(*expr)))
|
self.wrap(&mut **expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => body,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_class(&mut self, node: Class) -> Class {
|
fn visit_mut_class(&mut self, node: &mut Class) {
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::Default;
|
self.ctx = Context::Default;
|
||||||
let mut node: Class = node.fold_children_with(self);
|
node.visit_mut_children_with(self);
|
||||||
node.super_class = match node.super_class {
|
match &mut node.super_class {
|
||||||
Some(e) if e.is_seq() || e.is_await_expr() => Some(Box::new(self.wrap(*e))),
|
Some(ref mut e) if e.is_seq() || e.is_await_expr() => self.wrap(&mut **e),
|
||||||
_ => node.super_class,
|
_ => {}
|
||||||
};
|
};
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
|
|
||||||
@ -180,52 +140,159 @@ impl Fold for Fixer<'_> {
|
|||||||
ClassMember::Empty(..) => false,
|
ClassMember::Empty(..) => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_export_default_expr(&mut self, node: ExportDefaultExpr) -> ExportDefaultExpr {
|
fn visit_mut_export_default_expr(&mut self, node: &mut ExportDefaultExpr) {
|
||||||
let old = self.ctx;
|
let old = self.ctx;
|
||||||
self.ctx = Context::Default;
|
self.ctx = Context::Default;
|
||||||
let mut node = node.fold_children_with(self);
|
node.visit_mut_children_with(self);
|
||||||
node.expr = match *node.expr {
|
match &mut *node.expr {
|
||||||
Expr::Arrow(..) | Expr::Seq(..) => Box::new(self.wrap(*node.expr)),
|
Expr::Arrow(..) | Expr::Seq(..) => self.wrap(&mut node.expr),
|
||||||
_ => node.expr,
|
_ => {}
|
||||||
};
|
};
|
||||||
self.ctx = old;
|
self.ctx = old;
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
fn visit_mut_expr(&mut self, e: &mut Expr) {
|
||||||
let expr = expr.fold_children_with(self);
|
e.visit_mut_children_with(self);
|
||||||
let expr = self.unwrap_expr(expr);
|
self.unwrap_expr(e);
|
||||||
|
|
||||||
match expr {
|
self.wrap_with_paren_if_required(e)
|
||||||
Expr::Member(MemberExpr {
|
}
|
||||||
span,
|
|
||||||
computed,
|
fn visit_mut_expr_or_spread(&mut self, e: &mut ExprOrSpread) {
|
||||||
obj,
|
e.visit_mut_children_with(self);
|
||||||
prop,
|
|
||||||
}) if obj.as_expr().map(|e| e.is_object()).unwrap_or(false)
|
if e.spread.is_none() {
|
||||||
&& match self.ctx {
|
match *e.expr {
|
||||||
Context::ForcedExpr { is_var_decl: true } => true,
|
Expr::Yield(..) => {
|
||||||
_ => false,
|
self.wrap(&mut e.expr);
|
||||||
} =>
|
|
||||||
{
|
|
||||||
MemberExpr {
|
|
||||||
span,
|
|
||||||
computed,
|
|
||||||
obj,
|
|
||||||
prop,
|
|
||||||
}
|
}
|
||||||
.into()
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_if_stmt(&mut self, node: &mut IfStmt) {
|
||||||
|
node.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
match *node.cons {
|
||||||
|
Stmt::If(..) => {
|
||||||
|
node.cons = Box::new(Stmt::Block(BlockStmt {
|
||||||
|
span: node.cons.span(),
|
||||||
|
stmts: vec![*node.cons.take()],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_key_value_pat_prop(&mut self, node: &mut KeyValuePatProp) {
|
||||||
|
let old = self.ctx;
|
||||||
|
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
||||||
|
node.key.visit_mut_with(self);
|
||||||
|
self.ctx = old;
|
||||||
|
|
||||||
|
node.value.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_key_value_prop(&mut self, prop: &mut KeyValueProp) {
|
||||||
|
prop.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
match *prop.value {
|
||||||
|
Expr::Seq(..) => self.wrap(&mut prop.value),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_prop_name(&mut self, name: &mut PropName) {
|
||||||
|
name.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
match name {
|
||||||
|
PropName::Computed(c) if c.expr.is_seq() => {
|
||||||
|
self.wrap(&mut c.expr);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_stmt(&mut self, stmt: &mut Stmt) {
|
||||||
|
match stmt {
|
||||||
|
Stmt::Expr(expr) => {
|
||||||
|
let old = self.ctx;
|
||||||
|
self.ctx = Context::Default;
|
||||||
|
expr.visit_mut_with(self);
|
||||||
|
self.ctx = old;
|
||||||
|
}
|
||||||
|
_ => stmt.visit_mut_children_with(self),
|
||||||
|
};
|
||||||
|
|
||||||
|
match stmt {
|
||||||
|
Stmt::Expr(ExprStmt { ref mut expr, .. }) => {
|
||||||
|
self.handle_expr_stmt(&mut **expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_var_declarator(&mut self, node: &mut VarDeclarator) {
|
||||||
|
node.name.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
let old = self.ctx;
|
||||||
|
self.ctx = Context::ForcedExpr { is_var_decl: true };
|
||||||
|
node.init.visit_mut_with(self);
|
||||||
|
self.ctx = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_module(&mut self, n: &mut Module) {
|
||||||
|
debug_assert!(self.span_map.is_empty());
|
||||||
|
self.span_map.clear();
|
||||||
|
|
||||||
|
let n = n.visit_mut_children_with(self);
|
||||||
|
if let Some(c) = self.comments {
|
||||||
|
for (to, from) in self.span_map.drain() {
|
||||||
|
c.move_leading(from.lo, to.lo);
|
||||||
|
c.move_trailing(from.hi, to.hi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_script(&mut self, n: &mut Script) {
|
||||||
|
debug_assert!(self.span_map.is_empty());
|
||||||
|
self.span_map.clear();
|
||||||
|
|
||||||
|
let n = n.visit_mut_children_with(self);
|
||||||
|
if let Some(c) = self.comments {
|
||||||
|
for (to, from) in self.span_map.drain() {
|
||||||
|
c.move_leading(from.lo, to.lo);
|
||||||
|
c.move_trailing(from.hi, to.hi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fixer<'_> {
|
||||||
|
fn wrap_with_paren_if_required(&mut self, e: &mut Expr) {
|
||||||
|
match e {
|
||||||
|
Expr::Member(MemberExpr { obj, .. })
|
||||||
|
if obj.as_expr().map(|e| e.is_object()).unwrap_or(false)
|
||||||
|
&& match self.ctx {
|
||||||
|
Context::ForcedExpr { is_var_decl: true } => true,
|
||||||
|
_ => false,
|
||||||
|
} =>
|
||||||
|
{
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Member(MemberExpr {
|
Expr::Member(MemberExpr {
|
||||||
span,
|
obj: ExprOrSuper::Expr(ref mut obj),
|
||||||
computed,
|
..
|
||||||
obj: ExprOrSuper::Expr(obj),
|
|
||||||
prop,
|
|
||||||
}) if obj.is_fn_expr()
|
}) if obj.is_fn_expr()
|
||||||
|| obj.is_cond()
|
|| obj.is_cond()
|
||||||
|| obj.is_unary()
|
|| obj.is_unary()
|
||||||
@ -238,18 +305,12 @@ impl Fold for Fixer<'_> {
|
|||||||
|| obj.is_class()
|
|| obj.is_class()
|
||||||
|| obj.is_yield_expr()
|
|| obj.is_yield_expr()
|
||||||
|| obj.is_await_expr()
|
|| obj.is_await_expr()
|
||||||
|| match *obj {
|
|| match **obj {
|
||||||
Expr::New(NewExpr { args: None, .. }) => true,
|
Expr::New(NewExpr { args: None, .. }) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
} =>
|
} =>
|
||||||
{
|
{
|
||||||
MemberExpr {
|
self.wrap(&mut **obj);
|
||||||
span,
|
|
||||||
computed,
|
|
||||||
obj: self.wrap(*obj).as_obj(),
|
|
||||||
prop,
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten seq expr
|
// Flatten seq expr
|
||||||
@ -270,23 +331,25 @@ impl Fold for Fixer<'_> {
|
|||||||
.filter_map(|(i, e)| {
|
.filter_map(|(i, e)| {
|
||||||
let is_last = i + 1 == exprs_len;
|
let is_last = i + 1 == exprs_len;
|
||||||
if is_last {
|
if is_last {
|
||||||
Some(e)
|
Some(e.take())
|
||||||
} else {
|
} else {
|
||||||
ignore_return_value(e)
|
ignore_return_value(e.take())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if exprs.len() == 1 {
|
if exprs.len() == 1 {
|
||||||
return *exprs.pop().unwrap();
|
*e = *exprs.pop().unwrap();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Expr::Seq(SeqExpr { span, exprs })
|
Expr::Seq(SeqExpr { span: *span, exprs })
|
||||||
} else {
|
} else {
|
||||||
let mut buf = Vec::with_capacity(len);
|
let mut buf = Vec::with_capacity(len);
|
||||||
for (i, expr) in exprs.into_iter().enumerate() {
|
for (i, expr) in exprs.into_iter().enumerate() {
|
||||||
let is_last = i + 1 == exprs_len;
|
let is_last = i + 1 == exprs_len;
|
||||||
|
|
||||||
match *expr {
|
match **expr {
|
||||||
Expr::Seq(SeqExpr { exprs, .. }) => {
|
Expr::Seq(SeqExpr { ref mut exprs, .. }) => {
|
||||||
|
let exprs = exprs.take();
|
||||||
if !is_last {
|
if !is_last {
|
||||||
buf.extend(exprs.into_iter().filter_map(ignore_return_value));
|
buf.extend(exprs.into_iter().filter_map(ignore_return_value));
|
||||||
} else {
|
} else {
|
||||||
@ -301,360 +364,166 @@ impl Fold for Fixer<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => buf.push(expr),
|
_ => buf.push(expr.take()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if buf.len() == 1 {
|
if buf.len() == 1 {
|
||||||
return *buf.pop().unwrap();
|
*e = *buf.pop().unwrap();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
buf.shrink_to_fit();
|
buf.shrink_to_fit();
|
||||||
Expr::Seq(SeqExpr { span, exprs: buf })
|
|
||||||
|
Expr::Seq(SeqExpr {
|
||||||
|
span: *span,
|
||||||
|
exprs: buf,
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.ctx {
|
match self.ctx {
|
||||||
Context::ForcedExpr { .. } => Expr::Paren(ParenExpr {
|
Context::ForcedExpr { .. } => {
|
||||||
span,
|
*e = Expr::Paren(ParenExpr {
|
||||||
expr: Box::new(expr),
|
span: *span,
|
||||||
}),
|
expr: Box::new(expr),
|
||||||
_ => expr,
|
})
|
||||||
}
|
}
|
||||||
|
_ => *e = expr,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Bin(mut expr) => {
|
Expr::Bin(ref mut expr) => {
|
||||||
expr.right = match *expr.right {
|
match &mut *expr.right {
|
||||||
e @ Expr::Assign(..)
|
Expr::Assign(..)
|
||||||
| e @ Expr::Seq(..)
|
| Expr::Seq(..)
|
||||||
| e @ Expr::Yield(..)
|
| Expr::Yield(..)
|
||||||
| e @ Expr::Cond(..)
|
| Expr::Cond(..)
|
||||||
| e @ Expr::Arrow(..) => Box::new(self.wrap(e)),
|
| Expr::Arrow(..) => {
|
||||||
|
self.wrap(&mut expr.right);
|
||||||
|
}
|
||||||
Expr::Bin(BinExpr { op: op_of_rhs, .. }) => {
|
Expr::Bin(BinExpr { op: op_of_rhs, .. }) => {
|
||||||
if op_of_rhs.precedence() <= expr.op.precedence() {
|
if op_of_rhs.precedence() <= expr.op.precedence() {
|
||||||
Box::new(self.wrap(*expr.right))
|
self.wrap(&mut expr.right);
|
||||||
} else {
|
|
||||||
expr.right
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => expr.right,
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
match *expr.left {
|
match &mut *expr.left {
|
||||||
// While simplifying, (1 + x) * Nan becomes `1 + x * Nan`.
|
// While simplifying, (1 + x) * Nan becomes `1 + x * Nan`.
|
||||||
// But it should be `(1 + x) * Nan`
|
// But it should be `(1 + x) * Nan`
|
||||||
Expr::Bin(BinExpr { op: op_of_lhs, .. }) => {
|
Expr::Bin(BinExpr { op: op_of_lhs, .. }) => {
|
||||||
if op_of_lhs.precedence() < expr.op.precedence() {
|
if op_of_lhs.precedence() < expr.op.precedence() {
|
||||||
Expr::Bin(BinExpr {
|
self.wrap(&mut expr.left);
|
||||||
left: Box::new(self.wrap(*expr.left)),
|
|
||||||
..expr
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Expr::Bin(expr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e @ Expr::Seq(..)
|
Expr::Seq(..)
|
||||||
| e @ Expr::Update(..)
|
| Expr::Update(..)
|
||||||
| e
|
| Expr::Unary(UnaryExpr {
|
||||||
@
|
|
||||||
Expr::Unary(UnaryExpr {
|
|
||||||
op: op!("delete"), ..
|
op: op!("delete"), ..
|
||||||
})
|
})
|
||||||
| e
|
| Expr::Unary(UnaryExpr {
|
||||||
@
|
|
||||||
Expr::Unary(UnaryExpr {
|
|
||||||
op: op!("void"), ..
|
op: op!("void"), ..
|
||||||
})
|
})
|
||||||
| e @ Expr::Yield(..)
|
| Expr::Yield(..)
|
||||||
| e @ Expr::Cond(..)
|
| Expr::Cond(..)
|
||||||
| e @ Expr::Assign(..)
|
| Expr::Assign(..)
|
||||||
| e @ Expr::Arrow(..) => Expr::Bin(BinExpr {
|
| Expr::Arrow(..) => {
|
||||||
left: Box::new(self.wrap(e)),
|
self.wrap(&mut expr.left);
|
||||||
..expr
|
}
|
||||||
}),
|
Expr::Object(..)
|
||||||
e @ Expr::Object(..)
|
|
||||||
if expr.op == op!("instanceof")
|
if expr.op == op!("instanceof")
|
||||||
|| expr.op == op!("==")
|
|| expr.op == op!("==")
|
||||||
|| expr.op == op!("===")
|
|| expr.op == op!("===")
|
||||||
|| expr.op == op!("!=")
|
|| expr.op == op!("!=")
|
||||||
|| expr.op == op!("!==") =>
|
|| expr.op == op!("!==") =>
|
||||||
{
|
{
|
||||||
Expr::Bin(BinExpr {
|
self.wrap(&mut expr.left)
|
||||||
left: Box::new(e.wrap_with_paren()),
|
|
||||||
..expr
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => Expr::Bin(expr),
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Cond(expr) => {
|
Expr::Cond(expr) => {
|
||||||
let test = match *expr.test {
|
match &mut *expr.test {
|
||||||
e @ Expr::Seq(..)
|
Expr::Seq(..) | Expr::Assign(..) | Expr::Cond(..) | Expr::Arrow(..) => {
|
||||||
| e @ Expr::Assign(..)
|
self.wrap(&mut expr.test)
|
||||||
| e @ Expr::Cond(..)
|
}
|
||||||
| e @ Expr::Arrow(..) => Box::new(self.wrap(e)),
|
|
||||||
|
|
||||||
e @ Expr::Object(..) | e @ Expr::Fn(..) | e @ Expr::Class(..) => {
|
Expr::Object(..) | Expr::Fn(..) | Expr::Class(..) => {
|
||||||
if self.ctx == Context::Default {
|
if self.ctx == Context::Default {
|
||||||
Box::new(self.wrap(e))
|
self.wrap(&mut expr.test)
|
||||||
} else {
|
|
||||||
Box::new(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => expr.test,
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let cons = match *expr.cons {
|
match *expr.cons {
|
||||||
e @ Expr::Seq(..) => Box::new(self.wrap(e)),
|
Expr::Seq(..) => self.wrap(&mut expr.cons),
|
||||||
_ => expr.cons,
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let alt = match *expr.alt {
|
match *expr.alt {
|
||||||
e @ Expr::Seq(..) => Box::new(self.wrap(e)),
|
Expr::Seq(..) => self.wrap(&mut expr.alt),
|
||||||
_ => expr.alt,
|
_ => {}
|
||||||
};
|
};
|
||||||
let expr = Expr::Cond(CondExpr {
|
|
||||||
test,
|
|
||||||
cons,
|
|
||||||
alt,
|
|
||||||
..expr
|
|
||||||
});
|
|
||||||
match self.ctx {
|
match self.ctx {
|
||||||
Context::Callee { is_new: true } => self.wrap(expr),
|
Context::Callee { is_new: true } => self.wrap(e),
|
||||||
_ => expr,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Unary(expr) => {
|
Expr::Unary(expr) => match *expr.arg {
|
||||||
let arg = match *expr.arg {
|
Expr::Assign(..)
|
||||||
e @ Expr::Assign(..)
|
| Expr::Bin(..)
|
||||||
| e @ Expr::Bin(..)
|
| Expr::Seq(..)
|
||||||
| e @ Expr::Seq(..)
|
| Expr::Cond(..)
|
||||||
| e @ Expr::Cond(..)
|
| Expr::Arrow(..)
|
||||||
| e @ Expr::Arrow(..)
|
| Expr::Yield(..) => self.wrap(&mut expr.arg),
|
||||||
| e @ Expr::Yield(..) => Box::new(self.wrap(e)),
|
_ => {}
|
||||||
_ => expr.arg,
|
},
|
||||||
};
|
|
||||||
|
|
||||||
Expr::Unary(UnaryExpr { arg, ..expr })
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr::Assign(expr) => {
|
Expr::Assign(expr) => {
|
||||||
let right = match *expr.right {
|
match &mut *expr.right {
|
||||||
// `foo = (bar = baz)` => foo = bar = baz
|
// `foo = (bar = baz)` => foo = bar = baz
|
||||||
Expr::Assign(AssignExpr { ref left, .. }) if left.as_ident().is_some() => {
|
Expr::Assign(AssignExpr { ref left, .. }) if left.as_ident().is_some() => {}
|
||||||
expr.right
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle `foo = bar = init()
|
// Handle `foo = bar = init()
|
||||||
Expr::Seq(right) => Box::new(self.wrap(right)),
|
Expr::Seq(..) => self.wrap(&mut expr.right),
|
||||||
_ => expr.right,
|
_ => {}
|
||||||
};
|
}
|
||||||
|
|
||||||
Expr::Assign(AssignExpr { right, ..expr })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Call(CallExpr {
|
Expr::Call(CallExpr {
|
||||||
span,
|
callee: ExprOrSuper::Expr(ref mut callee),
|
||||||
callee: ExprOrSuper::Expr(callee),
|
..
|
||||||
args,
|
}) if callee.is_arrow() => {
|
||||||
type_args,
|
self.wrap(&mut **callee);
|
||||||
}) if callee.is_arrow() => Expr::Call(CallExpr {
|
}
|
||||||
span,
|
|
||||||
callee: self.wrap(*callee).as_callee(),
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Function expression cannot start with `function`
|
// Function expression cannot start with `function`
|
||||||
Expr::Call(CallExpr {
|
Expr::Call(CallExpr {
|
||||||
span,
|
callee: ExprOrSuper::Expr(ref mut callee),
|
||||||
callee: ExprOrSuper::Expr(callee),
|
..
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}) if callee.is_fn_expr() => match self.ctx {
|
}) if callee.is_fn_expr() => match self.ctx {
|
||||||
Context::ForcedExpr { .. } => Expr::Call(CallExpr {
|
Context::ForcedExpr { .. } => {}
|
||||||
span,
|
|
||||||
callee: callee.as_callee(),
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Context::Callee { is_new: true } => self.wrap(CallExpr {
|
Context::Callee { is_new: true } => self.wrap(e),
|
||||||
span,
|
|
||||||
callee: callee.as_callee(),
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => Expr::Call(CallExpr {
|
_ => self.wrap(&mut **callee),
|
||||||
span,
|
|
||||||
callee: self.wrap(*callee).as_callee(),
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
Expr::Call(CallExpr {
|
Expr::Call(CallExpr {
|
||||||
span,
|
callee: ExprOrSuper::Expr(ref mut callee),
|
||||||
callee: ExprOrSuper::Expr(callee),
|
..
|
||||||
args,
|
}) if callee.is_assign() => self.wrap(&mut **callee),
|
||||||
type_args,
|
|
||||||
}) if callee.is_assign() => Expr::Call(CallExpr {
|
|
||||||
span,
|
|
||||||
callee: self.wrap(*callee).as_callee(),
|
|
||||||
args,
|
|
||||||
type_args,
|
|
||||||
}),
|
|
||||||
_ => expr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_expr_or_spread(&mut self, e: ExprOrSpread) -> ExprOrSpread {
|
|
||||||
let e = e.fold_children_with(self);
|
|
||||||
|
|
||||||
if e.spread.is_none() {
|
|
||||||
match *e.expr {
|
|
||||||
Expr::Yield(..) => {
|
|
||||||
return ExprOrSpread {
|
|
||||||
spread: None,
|
|
||||||
expr: Box::new(self.wrap(*e.expr)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_if_stmt(&mut self, node: IfStmt) -> IfStmt {
|
|
||||||
let node: IfStmt = node.fold_children_with(self);
|
|
||||||
|
|
||||||
match *node.cons {
|
|
||||||
Stmt::If(..) => IfStmt {
|
|
||||||
cons: Box::new(Stmt::Block(BlockStmt {
|
|
||||||
span: node.cons.span(),
|
|
||||||
stmts: vec![*node.cons],
|
|
||||||
})),
|
|
||||||
..node
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => node,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_key_value_pat_prop(&mut self, node: KeyValuePatProp) -> KeyValuePatProp {
|
|
||||||
let old = self.ctx;
|
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: false };
|
|
||||||
let key = node.key.fold_with(self);
|
|
||||||
self.ctx = old;
|
|
||||||
|
|
||||||
let value = node.value.fold_with(self);
|
|
||||||
|
|
||||||
KeyValuePatProp { key, value }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_key_value_prop(&mut self, prop: KeyValueProp) -> KeyValueProp {
|
|
||||||
let prop = prop.fold_children_with(self);
|
|
||||||
|
|
||||||
match *prop.value {
|
|
||||||
Expr::Seq(..) => KeyValueProp {
|
|
||||||
value: Box::new(self.wrap(*prop.value)),
|
|
||||||
..prop
|
|
||||||
},
|
|
||||||
_ => prop,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_prop_name(&mut self, mut name: PropName) -> PropName {
|
|
||||||
name = name.fold_children_with(self);
|
|
||||||
|
|
||||||
match name {
|
|
||||||
PropName::Computed(c) if c.expr.is_seq() => {
|
|
||||||
return PropName::Computed(ComputedPropName {
|
|
||||||
span: c.span,
|
|
||||||
expr: Box::new(self.wrap(*c.expr)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
|
/// Wrap with a paren.
|
||||||
let stmt = match stmt {
|
fn wrap(&mut self, e: &mut Expr) {
|
||||||
Stmt::Expr(expr) => {
|
let span = e.span();
|
||||||
let old = self.ctx;
|
|
||||||
self.ctx = Context::Default;
|
|
||||||
let expr = expr.fold_with(self);
|
|
||||||
self.ctx = old;
|
|
||||||
Stmt::Expr(expr)
|
|
||||||
}
|
|
||||||
_ => stmt.fold_children_with(self),
|
|
||||||
};
|
|
||||||
|
|
||||||
let stmt = match stmt {
|
|
||||||
Stmt::Expr(ExprStmt { span, expr }) => Stmt::Expr(ExprStmt {
|
|
||||||
span,
|
|
||||||
expr: expr.map(|e| self.handle_expr_stmt(e)),
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => stmt,
|
|
||||||
};
|
|
||||||
|
|
||||||
stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_var_declarator(&mut self, node: VarDeclarator) -> VarDeclarator {
|
|
||||||
let name = node.name.fold_children_with(self);
|
|
||||||
|
|
||||||
let old = self.ctx;
|
|
||||||
self.ctx = Context::ForcedExpr { is_var_decl: true };
|
|
||||||
let init = node.init.fold_with(self);
|
|
||||||
self.ctx = old;
|
|
||||||
|
|
||||||
VarDeclarator { name, init, ..node }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_module(&mut self, n: Module) -> Module {
|
|
||||||
debug_assert!(self.span_map.is_empty());
|
|
||||||
self.span_map.clear();
|
|
||||||
|
|
||||||
let n = n.fold_children_with(self);
|
|
||||||
if let Some(c) = self.comments {
|
|
||||||
for (to, from) in self.span_map.drain() {
|
|
||||||
c.move_leading(from.lo, to.lo);
|
|
||||||
c.move_trailing(from.hi, to.hi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_script(&mut self, n: Script) -> Script {
|
|
||||||
debug_assert!(self.span_map.is_empty());
|
|
||||||
self.span_map.clear();
|
|
||||||
|
|
||||||
let n = n.fold_children_with(self);
|
|
||||||
if let Some(c) = self.comments {
|
|
||||||
for (to, from) in self.span_map.drain() {
|
|
||||||
c.move_leading(from.lo, to.lo);
|
|
||||||
c.move_trailing(from.hi, to.hi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fixer<'_> {
|
|
||||||
fn wrap<T>(&mut self, e: T) -> Expr
|
|
||||||
where
|
|
||||||
T: Into<Expr>,
|
|
||||||
{
|
|
||||||
let expr = Box::new(e.into());
|
|
||||||
let span = expr.span();
|
|
||||||
|
|
||||||
let span = if let Some(span) = self.span_map.remove(&span) {
|
let span = if let Some(span) = self.span_map.remove(&span) {
|
||||||
span
|
span
|
||||||
@ -662,71 +531,61 @@ impl Fixer<'_> {
|
|||||||
span
|
span
|
||||||
};
|
};
|
||||||
|
|
||||||
Expr::Paren(ParenExpr { expr, span })
|
let expr = Box::new(e.take());
|
||||||
|
*e = Expr::Paren(ParenExpr { expr, span })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes paren
|
/// Removes paren
|
||||||
fn unwrap_expr(&mut self, mut e: Expr) -> Expr {
|
fn unwrap_expr(&mut self, e: &mut Expr) {
|
||||||
match e {
|
match e {
|
||||||
Expr::Seq(SeqExpr { ref mut exprs, .. }) if exprs.len() == 1 => {
|
Expr::Seq(SeqExpr { ref mut exprs, .. }) if exprs.len() == 1 => {
|
||||||
self.unwrap_expr(*exprs.pop().unwrap())
|
self.unwrap_expr(exprs.last_mut().unwrap());
|
||||||
|
*e = *exprs.last_mut().unwrap().take();
|
||||||
}
|
}
|
||||||
Expr::Paren(ParenExpr {
|
Expr::Paren(ParenExpr {
|
||||||
span: paren_span,
|
span: paren_span,
|
||||||
expr,
|
ref mut expr,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let e = self.unwrap_expr(*expr);
|
let expr_span = expr.span();
|
||||||
|
let paren_span = *paren_span;
|
||||||
|
self.unwrap_expr(&mut **expr);
|
||||||
|
*e = *expr.take();
|
||||||
|
|
||||||
self.span_map.insert(e.span(), paren_span);
|
self.span_map.insert(expr_span, paren_span);
|
||||||
e
|
|
||||||
}
|
}
|
||||||
_ => e,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_expr_stmt(&mut self, expr: Expr) -> Expr {
|
fn handle_expr_stmt(&mut self, expr: &mut Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
// It's important for arrow pass to work properly.
|
// It's important for arrow pass to work properly.
|
||||||
Expr::Object(..) | Expr::Class(..) | Expr::Fn(..) => self.wrap(expr),
|
Expr::Object(..) | Expr::Class(..) | Expr::Fn(..) => self.wrap(expr),
|
||||||
|
|
||||||
// ({ a } = foo)
|
// ({ a } = foo)
|
||||||
Expr::Assign(AssignExpr {
|
Expr::Assign(AssignExpr {
|
||||||
span,
|
|
||||||
left: PatOrExpr::Pat(left),
|
left: PatOrExpr::Pat(left),
|
||||||
op,
|
..
|
||||||
right,
|
}) if left.is_object() => self.wrap(expr),
|
||||||
}) if left.is_object() => self.wrap(AssignExpr {
|
|
||||||
span,
|
|
||||||
left: PatOrExpr::Pat(left),
|
|
||||||
op,
|
|
||||||
right,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Expr::Seq(SeqExpr { span, exprs }) => {
|
Expr::Seq(SeqExpr { exprs, .. }) => {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
exprs.len() != 1,
|
exprs.len() != 1,
|
||||||
"SeqExpr should be unwrapped if exprs.len() == 1, but length is 1"
|
"SeqExpr should be unwrapped if exprs.len() == 1, but length is 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
let len = exprs.len();
|
let len = exprs.len();
|
||||||
Expr::Seq(SeqExpr {
|
exprs.into_iter().enumerate().for_each(|(i, mut expr)| {
|
||||||
span,
|
let is_last = len == i + 1;
|
||||||
exprs: exprs.move_map(|expr| {
|
|
||||||
i += 1;
|
|
||||||
let is_last = len == i;
|
|
||||||
|
|
||||||
if !is_last {
|
if !is_last {
|
||||||
expr.map(|e| self.handle_expr_stmt(e))
|
self.handle_expr_stmt(&mut expr);
|
||||||
} else {
|
}
|
||||||
expr
|
});
|
||||||
}
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => expr,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use self::ops::{Operator, ScopeOp};
|
use self::ops::{Operations, Operator};
|
||||||
use crate::{
|
use crate::{
|
||||||
compat::es2015::classes::native::is_native,
|
compat::es2015::classes::native::{is_native, is_native_word},
|
||||||
scope::{IdentType, ScopeKind},
|
scope::{IdentType, ScopeKind},
|
||||||
};
|
};
|
||||||
|
use fxhash::FxHashMap;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{cell::RefCell, collections::HashMap};
|
use std::cell::RefCell;
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{chain, Span, SyntaxContext};
|
use swc_common::{chain, SyntaxContext};
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{as_folder, noop_fold_type, noop_visit_mut_type, Fold, FoldWith, VisitMut};
|
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||||
|
|
||||||
mod ops;
|
mod ops;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -16,6 +17,16 @@ mod tests;
|
|||||||
|
|
||||||
const LOG: bool = false;
|
const LOG: bool = false;
|
||||||
|
|
||||||
|
trait ToBoxedStr {
|
||||||
|
fn to_boxed_str(&self) -> Box<str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToBoxedStr for JsWord {
|
||||||
|
fn to_boxed_str(&self) -> Box<str> {
|
||||||
|
(**self).to_owned().into_boxed_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Hygiene<'a> {
|
struct Hygiene<'a> {
|
||||||
current: Scope<'a>,
|
current: Scope<'a>,
|
||||||
ident_type: IdentType,
|
ident_type: IdentType,
|
||||||
@ -31,14 +42,19 @@ impl<'a> Hygiene<'a> {
|
|||||||
eprintln!("Declaring {}{:?} ", ident.sym, ctxt);
|
eprintln!("Declaring {}{:?} ", ident.sym, ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
let can_declare_without_renaming = self.current.can_declare(ident.sym.clone(), ctxt);
|
let can_declare_without_renaming =
|
||||||
|
self.current.can_declare(&ident.sym.to_boxed_str(), ctxt);
|
||||||
let sym = self.current.change_symbol(ident.sym, ctxt);
|
let sym = self.current.change_symbol(ident.sym, ctxt);
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) && LOG {
|
||||||
|
eprintln!("Changed symbol to {}{:?} ", sym, ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
self.current
|
self.current
|
||||||
.declared_symbols
|
.declared_symbols
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.entry(sym.clone())
|
.entry(sym.to_boxed_str())
|
||||||
.or_insert_with(Vec::new)
|
.or_default()
|
||||||
.push(ctxt);
|
.push(ctxt);
|
||||||
|
|
||||||
if can_declare_without_renaming {
|
if can_declare_without_renaming {
|
||||||
@ -86,7 +102,7 @@ impl<'a> Hygiene<'a> {
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
i += 1;
|
i += 1;
|
||||||
let sym: JsWord = format!("{}{}", sym, i).into();
|
let sym = format!("{}{}", sym, i);
|
||||||
|
|
||||||
if !self.current.is_declared(&sym) {
|
if !self.current.is_declared(&sym) {
|
||||||
break sym;
|
break sym;
|
||||||
@ -99,14 +115,13 @@ impl<'a> Hygiene<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sym = self.current.change_symbol(sym, ctxt);
|
let sym = self.current.change_symbol(sym, ctxt);
|
||||||
let scope = self.current.scope_of(sym.clone(), ctxt);
|
let boxed_sym = sym.to_boxed_str();
|
||||||
|
let scope = self.current.scope_of(&boxed_sym, ctxt);
|
||||||
|
|
||||||
// Update symbol list
|
// Update symbol list
|
||||||
let mut declared_symbols = scope.declared_symbols.borrow_mut();
|
let mut declared_symbols = scope.declared_symbols.borrow_mut();
|
||||||
|
|
||||||
let is_not_renamed = scope.ops.borrow().iter().all(|op| match *op {
|
let is_not_renamed = !scope.ops.borrow().rename.contains_key(&(sym.clone(), ctxt));
|
||||||
ScopeOp::Rename { ref from, .. } => from.0 != sym || from.1 != ctxt,
|
|
||||||
});
|
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
is_not_renamed,
|
is_not_renamed,
|
||||||
@ -116,7 +131,7 @@ impl<'a> Hygiene<'a> {
|
|||||||
scope.ops.borrow(),
|
scope.ops.borrow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let old = declared_symbols.entry(sym.clone()).or_default();
|
let old = declared_symbols.entry(sym.to_boxed_str()).or_default();
|
||||||
assert!(
|
assert!(
|
||||||
old.contains(&ctxt),
|
old.contains(&ctxt),
|
||||||
"{:?} does not contain {}{:?}",
|
"{:?} does not contain {}{:?}",
|
||||||
@ -127,23 +142,26 @@ impl<'a> Hygiene<'a> {
|
|||||||
old.retain(|c| *c != ctxt);
|
old.retain(|c| *c != ctxt);
|
||||||
// debug_assert!(old.is_empty() || old.len() == 1);
|
// debug_assert!(old.is_empty() || old.len() == 1);
|
||||||
|
|
||||||
let new = declared_symbols.entry(renamed.clone()).or_default();
|
let new = declared_symbols
|
||||||
|
.entry(renamed.clone().into_boxed_str())
|
||||||
|
.or_insert_with(|| Vec::with_capacity(2));
|
||||||
new.push(ctxt);
|
new.push(ctxt);
|
||||||
debug_assert!(new.len() == 1);
|
debug_assert!(new.len() == 1);
|
||||||
|
|
||||||
scope.ops.borrow_mut().push(ScopeOp::Rename {
|
scope
|
||||||
from: (sym, ctxt),
|
.ops
|
||||||
to: renamed,
|
.borrow_mut()
|
||||||
});
|
.rename
|
||||||
|
.insert((sym, ctxt), renamed.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hygiene() -> impl Fold + 'static {
|
pub fn hygiene() -> impl Fold + 'static {
|
||||||
chain!(
|
chain!(
|
||||||
Hygiene {
|
as_folder(Hygiene {
|
||||||
current: Default::default(),
|
current: Default::default(),
|
||||||
ident_type: IdentType::Ref,
|
ident_type: IdentType::Ref,
|
||||||
},
|
}),
|
||||||
as_folder(MarkClearer)
|
as_folder(MarkClearer)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -153,27 +171,27 @@ struct MarkClearer;
|
|||||||
impl VisitMut for MarkClearer {
|
impl VisitMut for MarkClearer {
|
||||||
noop_visit_mut_type!();
|
noop_visit_mut_type!();
|
||||||
|
|
||||||
fn visit_mut_span(&mut self, span: &mut Span) {
|
fn visit_mut_ident(&mut self, ident: &mut Ident) {
|
||||||
*span = span.with_ctxt(SyntaxContext::empty());
|
ident.span.ctxt = SyntaxContext::empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Hygiene<'a> {
|
impl<'a> Hygiene<'a> {
|
||||||
fn apply_ops<N>(&mut self, node: N) -> N
|
fn apply_ops<N>(&mut self, node: &mut N)
|
||||||
where
|
where
|
||||||
for<'o> N: FoldWith<Operator<'o>>,
|
for<'o> N: VisitMutWith<Operator<'o>>,
|
||||||
{
|
{
|
||||||
let ops = self.current.ops.borrow();
|
let ops = self.current.ops.borrow();
|
||||||
|
|
||||||
if ops.is_empty() {
|
if ops.rename.is_empty() {
|
||||||
return node;
|
return;
|
||||||
}
|
}
|
||||||
node.fold_with(&mut Operator(&ops))
|
node.visit_mut_with(&mut Operator(&ops))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Hygiene<'a> {
|
impl<'a> Hygiene<'a> {
|
||||||
fn fold_fn(&mut self, ident: Option<Ident>, mut node: Function) -> Function {
|
fn visit_mut_fn(&mut self, ident: Option<Ident>, node: &mut Function) {
|
||||||
match ident {
|
match ident {
|
||||||
Some(ident) => {
|
Some(ident) => {
|
||||||
self.add_declared_ref(ident);
|
self.add_declared_ref(ident);
|
||||||
@ -187,13 +205,15 @@ impl<'a> Hygiene<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
folder.ident_type = IdentType::Ref;
|
folder.ident_type = IdentType::Ref;
|
||||||
node.decorators = node.decorators.fold_with(&mut folder);
|
node.decorators.visit_mut_with(&mut folder);
|
||||||
|
|
||||||
folder.ident_type = IdentType::Binding;
|
folder.ident_type = IdentType::Binding;
|
||||||
node.params = node.params.fold_with(&mut folder);
|
node.params.visit_mut_with(&mut folder);
|
||||||
|
|
||||||
folder.ident_type = IdentType::Ref;
|
folder.ident_type = IdentType::Ref;
|
||||||
node.body = node.body.map(|stmt| stmt.fold_children_with(&mut folder));
|
node.body
|
||||||
|
.as_mut()
|
||||||
|
.map(|stmt| stmt.visit_mut_children_with(&mut folder));
|
||||||
|
|
||||||
folder.apply_ops(node)
|
folder.apply_ops(node)
|
||||||
}
|
}
|
||||||
@ -208,9 +228,9 @@ struct Scope<'a> {
|
|||||||
pub kind: ScopeKind,
|
pub kind: ScopeKind,
|
||||||
|
|
||||||
/// All references declared in this scope
|
/// All references declared in this scope
|
||||||
pub declared_symbols: RefCell<HashMap<JsWord, Vec<SyntaxContext>>>,
|
pub declared_symbols: RefCell<FxHashMap<Box<str>, Vec<SyntaxContext>>>,
|
||||||
|
|
||||||
pub(crate) ops: RefCell<Vec<ScopeOp>>,
|
pub(crate) ops: RefCell<Operations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Scope<'a> {
|
impl<'a> Default for Scope<'a> {
|
||||||
@ -230,8 +250,8 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scope_of(&self, sym: JsWord, ctxt: SyntaxContext) -> &'a Scope<'_> {
|
fn scope_of(&self, sym: &Box<str>, ctxt: SyntaxContext) -> &'a Scope<'_> {
|
||||||
if let Some(prev) = self.declared_symbols.borrow().get(&sym) {
|
if let Some(prev) = self.declared_symbols.borrow().get(sym) {
|
||||||
if prev.contains(&ctxt) {
|
if prev.contains(&ctxt) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -243,11 +263,11 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_declare(&self, sym: JsWord, ctxt: SyntaxContext) -> bool {
|
fn can_declare(&self, sym: &Box<str>, ctxt: SyntaxContext) -> bool {
|
||||||
match self.parent {
|
match self.parent {
|
||||||
None => {}
|
None => {}
|
||||||
Some(parent) => {
|
Some(parent) => {
|
||||||
if !parent.can_declare(sym.clone(), ctxt) {
|
if !parent.can_declare(sym, ctxt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +277,7 @@ impl<'a> Scope<'a> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctxts) = self.declared_symbols.borrow().get(&sym) {
|
if let Some(ctxts) = self.declared_symbols.borrow().get(sym) {
|
||||||
ctxts.contains(&ctxt)
|
ctxts.contains(&ctxt)
|
||||||
} else {
|
} else {
|
||||||
// No variable named `sym` is declared
|
// No variable named `sym` is declared
|
||||||
@ -279,7 +299,7 @@ impl<'a> Scope<'a> {
|
|||||||
|
|
||||||
let mut ctxts = smallvec![];
|
let mut ctxts = smallvec![];
|
||||||
{
|
{
|
||||||
if let Some(cxs) = self.declared_symbols.get_mut().get(&sym) {
|
if let Some(cxs) = self.declared_symbols.get_mut().get(&*sym) {
|
||||||
if cxs.len() != 1 || cxs[0] != ctxt {
|
if cxs.len() != 1 || cxs[0] != ctxt {
|
||||||
ctxts.extend_from_slice(&cxs);
|
ctxts.extend_from_slice(&cxs);
|
||||||
}
|
}
|
||||||
@ -289,7 +309,7 @@ impl<'a> Scope<'a> {
|
|||||||
let mut cur = self.parent;
|
let mut cur = self.parent;
|
||||||
|
|
||||||
while let Some(scope) = cur {
|
while let Some(scope) = cur {
|
||||||
if let Some(cxs) = scope.declared_symbols.borrow().get(&sym) {
|
if let Some(cxs) = scope.declared_symbols.borrow().get(&*sym) {
|
||||||
if cxs.len() != 1 || cxs[0] != ctxt {
|
if cxs.len() != 1 || cxs[0] != ctxt {
|
||||||
ctxts.extend_from_slice(&cxs);
|
ctxts.extend_from_slice(&cxs);
|
||||||
}
|
}
|
||||||
@ -308,16 +328,11 @@ impl<'a> Scope<'a> {
|
|||||||
let mut cur = Some(self);
|
let mut cur = Some(self);
|
||||||
|
|
||||||
while let Some(scope) = cur {
|
while let Some(scope) = cur {
|
||||||
for op in scope.ops.borrow().iter() {
|
if let Some(to) = scope.ops.borrow().rename.get(&(sym.clone(), ctxt)) {
|
||||||
match *op {
|
if cfg!(debug_assertions) && LOG {
|
||||||
ScopeOp::Rename { ref from, ref to } if from.0 == *sym && from.1 == ctxt => {
|
eprintln!("Changing symbol: {}{:?} -> {}", sym, ctxt, to);
|
||||||
if cfg!(debug_assertions) && LOG {
|
|
||||||
eprintln!("Changing symbol: {}{:?} -> {}", sym, ctxt, to);
|
|
||||||
}
|
|
||||||
sym = to.clone()
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
sym = to.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = scope.parent;
|
cur = scope.parent;
|
||||||
@ -326,14 +341,13 @@ impl<'a> Scope<'a> {
|
|||||||
sym
|
sym
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_declared(&self, sym: &JsWord) -> bool {
|
fn is_declared(&self, sym: &str) -> bool {
|
||||||
if self.declared_symbols.borrow().contains_key(sym) {
|
if self.declared_symbols.borrow().contains_key(sym) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for op in self.ops.borrow().iter() {
|
for (_, to) in &self.ops.borrow().rename {
|
||||||
match *op {
|
if to == sym {
|
||||||
ScopeOp::Rename { ref to, .. } if sym == to => return true,
|
return true;
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.parent {
|
match self.parent {
|
||||||
@ -344,6 +358,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[deprecated = "Not a public api"]
|
||||||
macro_rules! track_ident {
|
macro_rules! track_ident {
|
||||||
() => {
|
() => {
|
||||||
fn fold_export_specifier(&mut self, s: ExportSpecifier) -> ExportSpecifier {
|
fn fold_export_specifier(&mut self, s: ExportSpecifier) -> ExportSpecifier {
|
||||||
@ -492,168 +507,260 @@ macro_rules! track_ident {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Fold for Hygiene<'a> {
|
macro_rules! track_ident_mut {
|
||||||
noop_fold_type!();
|
() => {
|
||||||
|
fn visit_mut_export_specifier(&mut self, s: &mut ExportSpecifier) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
s.visit_mut_children_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
}
|
||||||
|
|
||||||
track_ident!();
|
fn visit_mut_import_specifier(&mut self, s: &mut ImportSpecifier) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
|
||||||
fn fold_arrow_expr(&mut self, mut node: ArrowExpr) -> ArrowExpr {
|
match s {
|
||||||
|
ImportSpecifier::Named(ImportNamedSpecifier { imported: None, .. })
|
||||||
|
| ImportSpecifier::Namespace(..)
|
||||||
|
| ImportSpecifier::Default(..) => s.visit_mut_children_with(self),
|
||||||
|
ImportSpecifier::Named(s) => s.local.visit_mut_with(self),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ident_type = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_setter_prop(&mut self, f: &mut SetterProp) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
f.param.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
f.body.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl<'a> Fold for $T<'a> {
|
||||||
|
// fn fold(&mut self, f: GetterProp) -> GetterProp {
|
||||||
|
// let body = f.body.visit_mut_with(self);
|
||||||
|
|
||||||
|
// GetterProp { body, ..c }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn visit_mut_labeled_stmt(&mut self, s: &mut LabeledStmt) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Label;
|
||||||
|
s.label.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
s.body.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_break_stmt(&mut self, s: &mut BreakStmt) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Label;
|
||||||
|
s.label.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_continue_stmt(&mut self, s: &mut ContinueStmt) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Label;
|
||||||
|
s.label.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_class_decl(&mut self, n: &mut ClassDecl) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
n.ident.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
n.class.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_class_expr(&mut self, n: &mut ClassExpr) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
n.ident.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
n.class.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_key_value_pat_prop(&mut self, n: &mut KeyValuePatProp) {
|
||||||
|
n.key.visit_mut_with(self);
|
||||||
|
n.value.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_class(&mut self, c: &mut Class) {
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
c.decorators.visit_mut_with(self);
|
||||||
|
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
c.super_class.visit_mut_with(self);
|
||||||
|
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
c.type_params.visit_mut_with(self);
|
||||||
|
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
c.super_type_params.visit_mut_with(self);
|
||||||
|
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
c.implements.visit_mut_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
c.body.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_prop_name(&mut self, n: &mut PropName) {
|
||||||
|
match n {
|
||||||
|
PropName::Computed(c) => {
|
||||||
|
c.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VisitMut for Hygiene<'a> {
|
||||||
|
noop_visit_mut_type!();
|
||||||
|
|
||||||
|
track_ident_mut!();
|
||||||
|
|
||||||
|
fn visit_mut_arrow_expr(&mut self, node: &mut ArrowExpr) {
|
||||||
let mut folder = Hygiene {
|
let mut folder = Hygiene {
|
||||||
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
||||||
ident_type: IdentType::Ref,
|
ident_type: IdentType::Ref,
|
||||||
};
|
};
|
||||||
|
|
||||||
folder.ident_type = IdentType::Binding;
|
folder.ident_type = IdentType::Binding;
|
||||||
node.params = node.params.fold_with(&mut folder);
|
node.params.visit_mut_with(&mut folder);
|
||||||
|
|
||||||
folder.ident_type = IdentType::Ref;
|
folder.ident_type = IdentType::Ref;
|
||||||
node.body = node.body.fold_with(&mut folder);
|
node.body.visit_mut_with(&mut folder);
|
||||||
|
|
||||||
folder.apply_ops(node)
|
folder.apply_ops(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_block_stmt(&mut self, node: BlockStmt) -> BlockStmt {
|
fn visit_mut_block_stmt(&mut self, node: &mut BlockStmt) {
|
||||||
let mut folder = Hygiene {
|
let mut folder = Hygiene {
|
||||||
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
||||||
ident_type: IdentType::Ref,
|
ident_type: IdentType::Ref,
|
||||||
};
|
};
|
||||||
let node = node.fold_children_with(&mut folder);
|
node.visit_mut_children_with(&mut folder);
|
||||||
|
|
||||||
folder.apply_ops(node)
|
folder.apply_ops(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_catch_clause(&mut self, c: CatchClause) -> CatchClause {
|
fn visit_mut_catch_clause(&mut self, c: &mut CatchClause) {
|
||||||
let mut folder = Hygiene {
|
let mut folder = Hygiene {
|
||||||
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
current: Scope::new(ScopeKind::Fn, Some(&self.current)),
|
||||||
ident_type: IdentType::Ref,
|
ident_type: IdentType::Ref,
|
||||||
};
|
};
|
||||||
folder.ident_type = IdentType::Binding;
|
folder.ident_type = IdentType::Binding;
|
||||||
let param = c.param.fold_with(&mut folder);
|
c.param.visit_mut_with(&mut folder);
|
||||||
folder.ident_type = IdentType::Ref;
|
folder.ident_type = IdentType::Ref;
|
||||||
|
|
||||||
let body = c.body.fold_with(&mut folder);
|
c.body.visit_mut_with(&mut folder);
|
||||||
|
|
||||||
CatchClause { param, body, ..c }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_constructor(&mut self, c: Constructor) -> Constructor {
|
fn visit_mut_constructor(&mut self, c: &mut Constructor) {
|
||||||
let old = self.ident_type;
|
let old = self.ident_type;
|
||||||
self.ident_type = IdentType::Binding;
|
self.ident_type = IdentType::Binding;
|
||||||
let params = c.params.fold_with(self);
|
c.params.visit_mut_with(self);
|
||||||
self.ident_type = old;
|
self.ident_type = old;
|
||||||
|
|
||||||
let body = c.body.map(|bs| bs.fold_children_with(self));
|
c.body.as_mut().map(|bs| bs.visit_mut_children_with(self));
|
||||||
let key = c.key.fold_with(self);
|
c.key.visit_mut_with(self);
|
||||||
|
|
||||||
let c = Constructor {
|
|
||||||
params,
|
|
||||||
body,
|
|
||||||
key,
|
|
||||||
..c
|
|
||||||
};
|
|
||||||
|
|
||||||
self.apply_ops(c)
|
self.apply_ops(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_expr(&mut self, node: Expr) -> Expr {
|
fn visit_mut_expr(&mut self, node: &mut Expr) {
|
||||||
let old = self.ident_type;
|
let old = self.ident_type;
|
||||||
self.ident_type = IdentType::Ref;
|
self.ident_type = IdentType::Ref;
|
||||||
let node = match node {
|
match node {
|
||||||
Expr::Ident(..) => node.fold_children_with(self),
|
Expr::Ident(..) => node.visit_mut_children_with(self),
|
||||||
Expr::Member(e) => {
|
Expr::Member(e) => {
|
||||||
if e.computed {
|
if e.computed {
|
||||||
Expr::Member(MemberExpr {
|
e.obj.visit_mut_with(self);
|
||||||
obj: e.obj.fold_with(self),
|
e.prop.visit_mut_with(self);
|
||||||
prop: e.prop.fold_with(self),
|
|
||||||
..e
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Expr::Member(MemberExpr {
|
e.obj.visit_mut_with(self)
|
||||||
obj: e.obj.fold_with(self),
|
|
||||||
..e
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::This(..) => node,
|
Expr::This(..) => {}
|
||||||
|
|
||||||
_ => node.fold_children_with(self),
|
_ => node.visit_mut_children_with(self),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ident_type = old;
|
self.ident_type = old;
|
||||||
|
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_fn_decl(&mut self, mut node: FnDecl) -> FnDecl {
|
fn visit_mut_fn_decl(&mut self, node: &mut FnDecl) {
|
||||||
node.function = self.fold_fn(Some(node.ident.clone()), node.function);
|
self.visit_mut_fn(Some(node.ident.clone()), &mut node.function);
|
||||||
|
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_fn_expr(&mut self, mut node: FnExpr) -> FnExpr {
|
fn visit_mut_fn_expr(&mut self, node: &mut FnExpr) {
|
||||||
node.function = self.fold_fn(node.ident.clone(), node.function);
|
self.visit_mut_fn(node.ident.clone(), &mut node.function);
|
||||||
|
|
||||||
node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked for `IdetifierRefrence` / `BindingIdentifier`
|
/// Invoked for `IdetifierRefrence` / `BindingIdentifier`
|
||||||
fn fold_ident(&mut self, i: Ident) -> Ident {
|
fn visit_mut_ident(&mut self, i: &mut Ident) {
|
||||||
if i.sym == js_word!("arguments") || i.sym == js_word!("undefined") {
|
if i.sym == js_word!("arguments") || i.sym == js_word!("undefined") {
|
||||||
return i;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.ident_type {
|
match self.ident_type {
|
||||||
IdentType::Binding => self.add_declared_ref(i.clone()),
|
IdentType::Binding => self.add_declared_ref(i.clone()),
|
||||||
IdentType::Ref => {
|
IdentType::Ref => {
|
||||||
// Special cases
|
// Special cases
|
||||||
if is_native(&i.sym) {
|
if is_native_word(&i.sym) {
|
||||||
return i;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_used_ref(&i);
|
self.add_used_ref(&i);
|
||||||
}
|
}
|
||||||
IdentType::Label => {
|
IdentType::Label => {
|
||||||
// We currently does not touch labels
|
// We currently does not touch labels
|
||||||
return i;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_module(&mut self, module: Module) -> Module {
|
fn visit_mut_module(&mut self, module: &mut Module) {
|
||||||
let module = validate!(module.fold_children_with(self));
|
module.visit_mut_children_with(self);
|
||||||
|
|
||||||
validate!(self.apply_ops(module))
|
self.apply_ops(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_object_lit(&mut self, node: ObjectLit) -> ObjectLit {
|
fn visit_mut_object_lit(&mut self, node: &mut ObjectLit) {
|
||||||
let mut folder = Hygiene {
|
let mut folder = Hygiene {
|
||||||
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
current: Scope::new(ScopeKind::Block, Some(&self.current)),
|
||||||
ident_type: IdentType::Ref,
|
ident_type: IdentType::Ref,
|
||||||
};
|
};
|
||||||
let node = node.fold_children_with(&mut folder);
|
node.visit_mut_children_with(&mut folder);
|
||||||
|
|
||||||
folder.apply_ops(node)
|
folder.apply_ops(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_try_stmt(&mut self, node: TryStmt) -> TryStmt {
|
fn visit_mut_try_stmt(&mut self, node: &mut TryStmt) {
|
||||||
TryStmt {
|
node.block.visit_mut_children_with(self);
|
||||||
span: node.span,
|
|
||||||
block: node.block.fold_children_with(self),
|
node.handler.visit_mut_with(self);
|
||||||
handler: node.handler.fold_with(self),
|
node.finalizer.visit_mut_children_with(self);
|
||||||
finalizer: node.finalizer.fold_children_with(self),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_var_declarator(&mut self, decl: VarDeclarator) -> VarDeclarator {
|
fn visit_mut_var_declarator(&mut self, decl: &mut VarDeclarator) {
|
||||||
let old = self.ident_type;
|
let old = self.ident_type;
|
||||||
self.ident_type = IdentType::Binding;
|
self.ident_type = IdentType::Binding;
|
||||||
let name = decl.name.fold_with(self);
|
decl.name.visit_mut_with(self);
|
||||||
self.ident_type = old;
|
self.ident_type = old;
|
||||||
|
|
||||||
let init = decl.init.fold_with(self);
|
decl.init.visit_mut_with(self);
|
||||||
VarDeclarator { name, init, ..decl }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
|
use crate::ext::MapWithMut;
|
||||||
|
use fxhash::FxHashMap;
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{util::move_map::MoveMap, Spanned, SyntaxContext, DUMMY_SP};
|
use swc_common::{util::move_map::MoveMap, Spanned, SyntaxContext, DUMMY_SP};
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
use swc_ecma_utils::{ident::IdentLike, Id};
|
||||||
|
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub(super) enum ScopeOp {
|
pub(super) struct Operations {
|
||||||
Rename {
|
pub rename: FxHashMap<Id, JsWord>,
|
||||||
from: (JsWord, SyntaxContext),
|
|
||||||
to: JsWord,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct Operator<'a>(pub &'a [ScopeOp]);
|
pub(super) struct Operator<'a>(pub &'a Operations);
|
||||||
|
|
||||||
impl<'a> Fold for Operator<'a> {
|
impl<'a> VisitMut for Operator<'a> {
|
||||||
noop_fold_type!();
|
noop_visit_mut_type!();
|
||||||
|
|
||||||
fn fold_module_items(&mut self, items: Vec<ModuleItem>) -> Vec<ModuleItem> {
|
fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
|
||||||
let mut stmts = Vec::with_capacity(items.len());
|
let mut stmts = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
for item in items {
|
for mut item in items.take() {
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
|
|
||||||
macro_rules! export {
|
macro_rules! export {
|
||||||
@ -44,15 +43,15 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
span,
|
span,
|
||||||
decl:
|
decl:
|
||||||
Decl::Class(ClassDecl {
|
Decl::Class(ClassDecl {
|
||||||
ident,
|
mut ident,
|
||||||
class,
|
mut class,
|
||||||
declare,
|
declare,
|
||||||
}),
|
}),
|
||||||
})) => {
|
})) => {
|
||||||
let class = class.fold_with(self);
|
class.visit_mut_with(self);
|
||||||
let orig_ident = ident.clone();
|
let orig_ident = ident.clone();
|
||||||
match self.rename_ident(ident) {
|
match self.rename_ident(&mut ident) {
|
||||||
Ok(ident) => {
|
Ok(..) => {
|
||||||
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
|
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
|
||||||
ident: ident.clone(),
|
ident: ident.clone(),
|
||||||
class,
|
class,
|
||||||
@ -60,7 +59,7 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
}))));
|
}))));
|
||||||
export!(orig_ident, ident);
|
export!(orig_ident, ident);
|
||||||
}
|
}
|
||||||
Err(ident) => {
|
Err(..) => {
|
||||||
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||||
span,
|
span,
|
||||||
decl: Decl::Class(ClassDecl {
|
decl: Decl::Class(ClassDecl {
|
||||||
@ -76,15 +75,15 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
span,
|
span,
|
||||||
decl:
|
decl:
|
||||||
Decl::Fn(FnDecl {
|
Decl::Fn(FnDecl {
|
||||||
ident,
|
mut ident,
|
||||||
function,
|
mut function,
|
||||||
declare,
|
declare,
|
||||||
}),
|
}),
|
||||||
})) => {
|
})) => {
|
||||||
let function = function.fold_with(self);
|
function.visit_mut_with(self);
|
||||||
let orig_ident = ident.clone();
|
let orig_ident = ident.clone();
|
||||||
match self.rename_ident(ident) {
|
match self.rename_ident(&mut ident) {
|
||||||
Ok(ident) => {
|
Ok(..) => {
|
||||||
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
|
stmts.push(ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
|
||||||
ident: ident.clone(),
|
ident: ident.clone(),
|
||||||
function,
|
function,
|
||||||
@ -92,7 +91,7 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
}))));
|
}))));
|
||||||
export!(orig_ident, ident);
|
export!(orig_ident, ident);
|
||||||
}
|
}
|
||||||
Err(ident) => {
|
Err(..) => {
|
||||||
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||||
span,
|
span,
|
||||||
decl: Decl::Fn(FnDecl {
|
decl: Decl::Fn(FnDecl {
|
||||||
@ -111,13 +110,13 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
let decls = var.decls;
|
let decls = var.decls;
|
||||||
|
|
||||||
let mut renamed: Vec<ExportSpecifier> = vec![];
|
let mut renamed: Vec<ExportSpecifier> = vec![];
|
||||||
let decls = decls.move_map(|decl| {
|
let decls = decls.move_map(|mut decl| {
|
||||||
let name = decl.name.fold_with(&mut VarFolder {
|
decl.name.visit_mut_with(&mut VarFolder {
|
||||||
orig: self,
|
orig: self,
|
||||||
renamed: &mut renamed,
|
renamed: &mut renamed,
|
||||||
});
|
});
|
||||||
let init = decl.init.fold_with(self);
|
decl.init.visit_mut_with(self);
|
||||||
VarDeclarator { name, init, ..decl }
|
decl
|
||||||
});
|
});
|
||||||
if renamed.is_empty() {
|
if renamed.is_empty() {
|
||||||
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||||
@ -139,144 +138,132 @@ impl<'a> Fold for Operator<'a> {
|
|||||||
},
|
},
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
_ => stmts.push(item.fold_with(self)),
|
_ => {
|
||||||
|
item.visit_mut_with(self);
|
||||||
|
stmts.push(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stmts
|
*items = stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preserve key of properties.
|
/// Preserve key of properties.
|
||||||
fn fold_assign_pat_prop(&mut self, p: AssignPatProp) -> AssignPatProp {
|
fn visit_mut_assign_pat_prop(&mut self, p: &mut AssignPatProp) {
|
||||||
match p.value {
|
match &mut p.value {
|
||||||
Some(value) => AssignPatProp {
|
Some(value) => {
|
||||||
value: Some(value.fold_children_with(self)),
|
value.visit_mut_children_with(self);
|
||||||
..p
|
}
|
||||||
},
|
None => {}
|
||||||
None => p,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_export_named_specifier(&mut self, s: ExportNamedSpecifier) -> ExportNamedSpecifier {
|
fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {
|
||||||
if s.exported.is_some() {
|
if s.exported.is_some() {
|
||||||
return ExportNamedSpecifier {
|
s.orig.visit_mut_with(self);
|
||||||
orig: s.orig.fold_with(self),
|
return;
|
||||||
..s
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let exported = s.orig.clone();
|
let exported = s.orig.clone();
|
||||||
|
|
||||||
match self.rename_ident(s.orig) {
|
match self.rename_ident(&mut s.orig) {
|
||||||
Ok(orig) => ExportNamedSpecifier {
|
Ok(..) => {
|
||||||
exported: Some(exported),
|
s.exported = Some(exported);
|
||||||
orig,
|
}
|
||||||
..s
|
Err(..) => {}
|
||||||
},
|
|
||||||
Err(orig) => ExportNamedSpecifier { orig, ..s },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ident(&mut self, ident: Ident) -> Ident {
|
fn visit_mut_ident(&mut self, ident: &mut Ident) {
|
||||||
match self.rename_ident(ident) {
|
match self.rename_ident(ident) {
|
||||||
Ok(i) | Err(i) => i,
|
Ok(i) | Err(i) => i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_import_named_specifier(&mut self, s: ImportNamedSpecifier) -> ImportNamedSpecifier {
|
fn visit_mut_import_named_specifier(&mut self, s: &mut ImportNamedSpecifier) {
|
||||||
if s.imported.is_some() {
|
if s.imported.is_some() {
|
||||||
return ImportNamedSpecifier {
|
s.local.visit_mut_with(self);
|
||||||
local: s.local.fold_with(self),
|
return;
|
||||||
..s
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let imported = s.local.clone();
|
let imported = s.local.clone();
|
||||||
let local = self.rename_ident(s.local);
|
let local = self.rename_ident(&mut s.local);
|
||||||
|
|
||||||
match local {
|
match local {
|
||||||
Ok(local) => ImportNamedSpecifier {
|
Ok(..) => {
|
||||||
imported: Some(imported),
|
s.imported = Some(imported);
|
||||||
local,
|
}
|
||||||
..s
|
Err(..) => {}
|
||||||
},
|
|
||||||
Err(local) => ImportNamedSpecifier { local, ..s },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preserve key of properties.
|
/// Preserve key of properties.
|
||||||
fn fold_key_value_pat_prop(&mut self, p: KeyValuePatProp) -> KeyValuePatProp {
|
fn visit_mut_key_value_pat_prop(&mut self, p: &mut KeyValuePatProp) {
|
||||||
KeyValuePatProp {
|
p.key.visit_mut_with(self);
|
||||||
key: p.key.fold_with(self),
|
p.value.visit_mut_with(self);
|
||||||
value: p.value.fold_with(self),
|
}
|
||||||
..p
|
|
||||||
|
fn visit_mut_key_value_prop(&mut self, p: &mut KeyValueProp) {
|
||||||
|
p.value.visit_mut_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_member_expr(&mut self, expr: &mut MemberExpr) {
|
||||||
|
expr.span.visit_mut_with(self);
|
||||||
|
expr.obj.visit_mut_with(self);
|
||||||
|
|
||||||
|
if expr.computed {
|
||||||
|
expr.prop.visit_mut_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_key_value_prop(&mut self, p: KeyValueProp) -> KeyValueProp {
|
fn visit_mut_object_pat_prop(&mut self, n: &mut ObjectPatProp) {
|
||||||
KeyValueProp {
|
n.visit_mut_children_with(self);
|
||||||
value: p.value.fold_with(self),
|
|
||||||
..p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_member_expr(&mut self, expr: MemberExpr) -> MemberExpr {
|
match n {
|
||||||
let span = expr.span.fold_with(self);
|
ObjectPatProp::Assign(p) => {
|
||||||
let obj = expr.obj.fold_with(self);
|
let mut renamed = p.key.clone();
|
||||||
|
match self.rename_ident(&mut renamed) {
|
||||||
let prop = if expr.computed {
|
Ok(..) => {
|
||||||
expr.prop.fold_with(self)
|
*n = KeyValuePatProp {
|
||||||
} else {
|
key: PropName::Ident(p.key.take()),
|
||||||
expr.prop
|
value: Box::new(Pat::Ident(renamed)),
|
||||||
};
|
}
|
||||||
MemberExpr {
|
.into();
|
||||||
span,
|
}
|
||||||
obj,
|
Err(_) => {}
|
||||||
prop,
|
|
||||||
computed: expr.computed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_object_pat_prop(&mut self, p: ObjectPatProp) -> ObjectPatProp {
|
|
||||||
let p = p.fold_children_with(self);
|
|
||||||
|
|
||||||
match p {
|
|
||||||
ObjectPatProp::Assign(p) => match self.rename_ident(p.key.clone()) {
|
|
||||||
Ok(renamed) => KeyValuePatProp {
|
|
||||||
key: PropName::Ident(p.key),
|
|
||||||
|
|
||||||
value: Box::new(Pat::Ident(renamed)),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
Err(_) => p.into(),
|
|
||||||
},
|
|
||||||
_ => p,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_prop(&mut self, prop: Prop) -> Prop {
|
|
||||||
match prop {
|
|
||||||
Prop::Shorthand(i) => {
|
|
||||||
match self.rename_ident(i.clone()) {
|
|
||||||
Ok(renamed) => Prop::KeyValue(KeyValueProp {
|
|
||||||
key: PropName::Ident(Ident {
|
|
||||||
// clear mark
|
|
||||||
span: i.span.with_ctxt(SyntaxContext::empty()),
|
|
||||||
..i
|
|
||||||
}),
|
|
||||||
value: Box::new(Expr::Ident(renamed)),
|
|
||||||
}),
|
|
||||||
Err(i) => Prop::Shorthand(i),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => prop.fold_children_with(self),
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_prop_name(&mut self, n: PropName) -> PropName {
|
fn visit_mut_prop(&mut self, prop: &mut Prop) {
|
||||||
|
match prop {
|
||||||
|
Prop::Shorthand(i) => {
|
||||||
|
let mut renamed = i.clone();
|
||||||
|
match self.rename_ident(&mut renamed) {
|
||||||
|
Ok(..) => {
|
||||||
|
*prop = Prop::KeyValue(KeyValueProp {
|
||||||
|
key: PropName::Ident(Ident {
|
||||||
|
// clear mark
|
||||||
|
span: i.span.with_ctxt(SyntaxContext::empty()),
|
||||||
|
type_ann: None,
|
||||||
|
..i.clone()
|
||||||
|
}),
|
||||||
|
value: Box::new(Expr::Ident(renamed)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => prop.visit_mut_children_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_prop_name(&mut self, n: &mut PropName) {
|
||||||
match n {
|
match n {
|
||||||
PropName::Computed(c) => PropName::Computed(c.fold_with(self)),
|
PropName::Computed(c) => c.visit_mut_with(self),
|
||||||
_ => n,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,48 +273,37 @@ struct VarFolder<'a, 'b> {
|
|||||||
renamed: &'a mut Vec<ExportSpecifier>,
|
renamed: &'a mut Vec<ExportSpecifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fold for VarFolder<'_, '_> {
|
impl VisitMut for VarFolder<'_, '_> {
|
||||||
noop_fold_type!();
|
noop_visit_mut_type!();
|
||||||
|
|
||||||
fn fold_expr(&mut self, n: Expr) -> Expr {
|
#[inline]
|
||||||
n
|
fn visit_mut_expr(&mut self, _: &mut Expr) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ident(&mut self, i: Ident) -> Ident {
|
fn visit_mut_ident(&mut self, i: &mut Ident) {
|
||||||
let orig = i.clone();
|
let orig = i.clone();
|
||||||
match self.orig.rename_ident(i) {
|
match self.orig.rename_ident(i) {
|
||||||
Ok(i) => {
|
Ok(..) => {
|
||||||
self.renamed
|
self.renamed
|
||||||
.push(ExportSpecifier::Named(ExportNamedSpecifier {
|
.push(ExportSpecifier::Named(ExportNamedSpecifier {
|
||||||
span: i.span,
|
span: i.span,
|
||||||
exported: Some(orig),
|
exported: Some(orig),
|
||||||
orig: i.clone(),
|
orig: i.clone(),
|
||||||
}));
|
}));
|
||||||
i
|
|
||||||
}
|
}
|
||||||
Err(i) => i,
|
Err(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Operator<'a> {
|
impl<'a> Operator<'a> {
|
||||||
/// Returns `Ok(renamed_ident)` if ident should be renamed.
|
/// Returns `Ok(renamed_ident)` if ident should be renamed.
|
||||||
fn rename_ident(&mut self, ident: Ident) -> Result<Ident, Ident> {
|
fn rename_ident(&mut self, ident: &mut Ident) -> Result<(), ()> {
|
||||||
for op in self.0 {
|
if let Some(sym) = self.0.rename.get(&ident.to_id()) {
|
||||||
match *op {
|
ident.span = ident.span.with_ctxt(SyntaxContext::empty());
|
||||||
ScopeOp::Rename { ref from, ref to }
|
ident.sym = sym.clone();
|
||||||
if *from.0 == ident.sym && from.1 == ident.span.ctxt() =>
|
return Ok(());
|
||||||
{
|
|
||||||
return Ok(Ident {
|
|
||||||
// Clear mark
|
|
||||||
span: ident.span.with_ctxt(SyntaxContext::empty()),
|
|
||||||
sym: to.clone(),
|
|
||||||
..ident
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(ident)
|
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use crate::tests::HygieneVisualizer;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use swc_common::{hygiene::*, DUMMY_SP};
|
use swc_common::{hygiene::*, DUMMY_SP};
|
||||||
use swc_ecma_parser::Syntax;
|
use swc_ecma_parser::Syntax;
|
||||||
|
use swc_ecma_visit::{Fold, FoldWith};
|
||||||
|
|
||||||
struct Marker {
|
struct Marker {
|
||||||
map: HashMap<JsWord, Mark>,
|
map: HashMap<JsWord, Mark>,
|
||||||
@ -1183,93 +1184,3 @@ fn exported_class_1() {
|
|||||||
export { Foo1 as Foo };",
|
export { Foo1 as Foo };",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn issue_598() {
|
|
||||||
// test_module(
|
|
||||||
// |tester| {
|
|
||||||
// let mark1 = Mark::fresh(Mark::root());
|
|
||||||
// let mark2 = Mark::fresh(Mark::root());
|
|
||||||
|
|
||||||
// Ok(tester
|
|
||||||
// .parse_module(
|
|
||||||
// "actual1.js",
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// )?
|
|
||||||
// .fold_with(&mut OnceMarker::new(&[(
|
|
||||||
// "_templateObject",
|
|
||||||
// &[mark1, mark2],
|
|
||||||
// )])))
|
|
||||||
// },
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject1()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn issue_598_2() {
|
|
||||||
// test_module(
|
|
||||||
// |tester| {
|
|
||||||
// let mark1 = Mark::fresh(Mark::root());
|
|
||||||
// let mark2 = Mark::fresh(Mark::root());
|
|
||||||
// let mark3 = Mark::fresh(Mark::root());
|
|
||||||
|
|
||||||
// Ok(tester
|
|
||||||
// .parse_module(
|
|
||||||
// "actual1.js",
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// )?
|
|
||||||
// .fold_with(&mut OnceMarker::new(&[(
|
|
||||||
// "_templateObject",
|
|
||||||
// &[mark1, mark2, mark3],
|
|
||||||
// )])))
|
|
||||||
// },
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject1()));
|
|
||||||
// console.log(i18n(_templateObject2()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn issue_598_3() {
|
|
||||||
// test_module(
|
|
||||||
// |tester| {
|
|
||||||
// let mark1 = Mark::fresh(Mark::root());
|
|
||||||
// let mark2 = Mark::fresh(Mark::root());
|
|
||||||
// let mark3 = Mark::fresh(Mark::root());
|
|
||||||
// let mark4 = Mark::fresh(Mark::root());
|
|
||||||
|
|
||||||
// Ok(tester
|
|
||||||
// .parse_module(
|
|
||||||
// "actual1.js",
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// )?
|
|
||||||
// .fold_with(&mut OnceMarker::new(&[(
|
|
||||||
// "_templateObject",
|
|
||||||
// &[mark1, mark2, mark3, mark4],
|
|
||||||
// )])))
|
|
||||||
// },
|
|
||||||
// "export function foo() {
|
|
||||||
// console.log(i18n(_templateObject1()));
|
|
||||||
// console.log(i18n(_templateObject2()));
|
|
||||||
// console.log(i18n(_templateObject3()));
|
|
||||||
// console.log(i18n(_templateObject()));
|
|
||||||
// }",
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1096,7 +1096,8 @@ var instance = new SomeClass({
|
|||||||
console.log('CORRECT FUNCTION CALLED');
|
console.log('CORRECT FUNCTION CALLED');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
instance.call();"
|
instance.call();",
|
||||||
|
ok_if_code_eq
|
||||||
);
|
);
|
||||||
|
|
||||||
test!(
|
test!(
|
||||||
@ -1220,7 +1221,8 @@ export class HygieneTest {
|
|||||||
_defineProperty(this, 'duration', DURATION);
|
_defineProperty(this, 'duration', DURATION);
|
||||||
this.duration = duration ?? DURATION;
|
this.duration = duration ?? DURATION;
|
||||||
}
|
}
|
||||||
}"
|
}",
|
||||||
|
ok_if_code_eq
|
||||||
);
|
);
|
||||||
|
|
||||||
identical_ts!(ts_resolver_001, "type A = B;");
|
identical_ts!(ts_resolver_001, "type A = B;");
|
||||||
|
@ -201,11 +201,11 @@ pub(crate) fn test_transform<F, P>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let actual = actual
|
let actual = actual
|
||||||
.fold_with(&mut crate::debug::validator::Validator { name: "actual-1" })
|
|
||||||
.fold_with(&mut crate::hygiene::hygiene())
|
.fold_with(&mut crate::hygiene::hygiene())
|
||||||
.fold_with(&mut crate::debug::validator::Validator { name: "actual-2" })
|
|
||||||
.fold_with(&mut crate::fixer::fixer(None))
|
.fold_with(&mut crate::fixer::fixer(None))
|
||||||
.fold_with(&mut crate::debug::validator::Validator { name: "actual-3" });
|
.fold_with(&mut as_folder(DropSpan {
|
||||||
|
preserve_ctxt: false,
|
||||||
|
}));
|
||||||
|
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -101,6 +101,70 @@ impl Strip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Strip {
|
impl Strip {
|
||||||
|
/// Returns [Some] if the method should be called again.
|
||||||
|
fn handle_expr<'a>(&mut self, n: &'a mut Expr) -> Vec<&'a mut Expr> {
|
||||||
|
match n {
|
||||||
|
Expr::Bin(BinExpr { left, right, .. }) => return vec![&mut **left, &mut **right],
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.map_with_mut(|expr| {
|
||||||
|
let mut expr = match expr {
|
||||||
|
Expr::TsAs(TsAsExpr { expr, .. })
|
||||||
|
| Expr::TsNonNull(TsNonNullExpr { expr, .. })
|
||||||
|
| Expr::TsTypeAssertion(TsTypeAssertion { expr, .. })
|
||||||
|
| Expr::TsConstAssertion(TsConstAssertion { expr, .. })
|
||||||
|
| Expr::TsTypeCast(TsTypeCastExpr { expr, .. }) => {
|
||||||
|
let mut expr = *expr;
|
||||||
|
expr.visit_mut_with(self);
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
_ => expr,
|
||||||
|
};
|
||||||
|
|
||||||
|
let expr = match expr {
|
||||||
|
Expr::Bin(..) => expr,
|
||||||
|
Expr::Member(MemberExpr {
|
||||||
|
span,
|
||||||
|
mut obj,
|
||||||
|
mut prop,
|
||||||
|
computed,
|
||||||
|
}) => {
|
||||||
|
obj.visit_mut_with(self);
|
||||||
|
|
||||||
|
let prop = if computed {
|
||||||
|
prop.visit_mut_with(self);
|
||||||
|
prop
|
||||||
|
} else {
|
||||||
|
match *prop {
|
||||||
|
Expr::Ident(i) => Box::new(Expr::Ident(Ident {
|
||||||
|
optional: false,
|
||||||
|
type_ann: None,
|
||||||
|
..i
|
||||||
|
})),
|
||||||
|
_ => prop,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Expr::Member(MemberExpr {
|
||||||
|
span,
|
||||||
|
obj,
|
||||||
|
prop,
|
||||||
|
computed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
expr.visit_mut_children_with(self);
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expr
|
||||||
|
});
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_enum<T>(&mut self, e: TsEnumDecl, stmts: &mut Vec<T>)
|
fn handle_enum<T>(&mut self, e: TsEnumDecl, stmts: &mut Vec<T>)
|
||||||
where
|
where
|
||||||
T: StmtLike,
|
T: StmtLike,
|
||||||
@ -577,59 +641,22 @@ impl VisitMut for Strip {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_mut_expr(&mut self, expr: &mut Expr) {
|
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||||
expr.map_with_mut(|expr| {
|
let mut stack = vec![n];
|
||||||
let mut expr = match expr {
|
loop {
|
||||||
Expr::TsAs(TsAsExpr { expr, .. })
|
let mut new_stack = vec![];
|
||||||
| Expr::TsNonNull(TsNonNullExpr { expr, .. })
|
for expr in stack {
|
||||||
| Expr::TsTypeAssertion(TsTypeAssertion { expr, .. })
|
let res = self.handle_expr(expr);
|
||||||
| Expr::TsConstAssertion(TsConstAssertion { expr, .. })
|
|
||||||
| Expr::TsTypeCast(TsTypeCastExpr { expr, .. }) => {
|
|
||||||
let mut expr = *expr;
|
|
||||||
expr.visit_mut_with(self);
|
|
||||||
expr
|
|
||||||
}
|
|
||||||
_ => expr,
|
|
||||||
};
|
|
||||||
|
|
||||||
let expr = match expr {
|
new_stack.extend(res)
|
||||||
Expr::Member(MemberExpr {
|
}
|
||||||
span,
|
|
||||||
mut obj,
|
|
||||||
mut prop,
|
|
||||||
computed,
|
|
||||||
}) => {
|
|
||||||
obj.visit_mut_with(self);
|
|
||||||
|
|
||||||
let prop = if computed {
|
if new_stack.is_empty() {
|
||||||
prop.visit_mut_with(self);
|
return;
|
||||||
prop
|
}
|
||||||
} else {
|
|
||||||
match *prop {
|
|
||||||
Expr::Ident(i) => Box::new(Expr::Ident(Ident {
|
|
||||||
optional: false,
|
|
||||||
type_ann: None,
|
|
||||||
..i
|
|
||||||
})),
|
|
||||||
_ => prop,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Expr::Member(MemberExpr {
|
stack = new_stack;
|
||||||
span,
|
}
|
||||||
obj,
|
|
||||||
prop,
|
|
||||||
computed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
expr.visit_mut_children_with(self);
|
|
||||||
expr
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expr
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_mut_ident(&mut self, i: &mut Ident) {
|
fn visit_mut_ident(&mut self, i: &mut Ident) {
|
||||||
|
@ -5,46 +5,22 @@ use std::{
|
|||||||
fmt,
|
fmt,
|
||||||
fs::{create_dir_all, remove_dir_all, OpenOptions},
|
fs::{create_dir_all, remove_dir_all, OpenOptions},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
|
mem::replace,
|
||||||
path::Path,
|
path::Path,
|
||||||
process::Command,
|
process::Command,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
use swc_common::{
|
use swc_common::{
|
||||||
chain, comments::SingleThreadedComments, errors::Handler, sync::Lrc, FileName, SourceMap,
|
comments::SingleThreadedComments, errors::Handler, sync::Lrc, FileName, SourceMap, DUMMY_SP,
|
||||||
};
|
};
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_codegen::Emitter;
|
use swc_ecma_codegen::Emitter;
|
||||||
use swc_ecma_parser::{error::Error, lexer::Lexer, Parser, StringInput, Syntax};
|
use swc_ecma_parser::{error::Error, lexer::Lexer, Parser, StringInput, Syntax};
|
||||||
use swc_ecma_transforms::helpers::{inject_helpers, HELPERS};
|
use swc_ecma_transforms::helpers::{inject_helpers, HELPERS};
|
||||||
use swc_ecma_utils::DropSpan;
|
use swc_ecma_utils::DropSpan;
|
||||||
use swc_ecma_visit::{as_folder, Fold, FoldWith};
|
use swc_ecma_visit::{as_folder, Fold, FoldWith, VisitMut, VisitMutWith};
|
||||||
use tempfile::tempdir_in;
|
use tempfile::tempdir_in;
|
||||||
|
use testing::assert_eq;
|
||||||
pub fn validating(name: &'static str, tr: impl Fold + 'static) -> Box<dyn Fold> {
|
|
||||||
Box::new(chain!(
|
|
||||||
tr,
|
|
||||||
swc_ecma_transforms::debug::validator::Validator { name },
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! validating {
|
|
||||||
($folder:expr) => {{
|
|
||||||
common::validating(stringify!($folder), $folder)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! validate {
|
|
||||||
($e:expr) => {{
|
|
||||||
use swc_ecma_visit::FoldWith;
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
$e.fold_with(&mut swc_ecma_transforms::debug::validator::Validator {
|
|
||||||
name: concat!(file!(), ':', line!(), ':', column!()),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
$e
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Tester<'a> {
|
pub struct Tester<'a> {
|
||||||
pub cm: Lrc<SourceMap>,
|
pub cm: Lrc<SourceMap>,
|
||||||
@ -127,12 +103,12 @@ impl<'a> Tester<'a> {
|
|||||||
res?
|
res?
|
||||||
};
|
};
|
||||||
|
|
||||||
let module = validate!(module)
|
let mut module = module.fold_with(&mut tr);
|
||||||
.fold_with(&mut tr)
|
|
||||||
.fold_with(&mut as_folder(DropSpan {
|
module.visit_mut_with(&mut DropSpan {
|
||||||
preserve_ctxt: true,
|
preserve_ctxt: true,
|
||||||
}))
|
});
|
||||||
.fold_with(&mut Normalizer);
|
module.visit_mut_with(&mut Normalizer);
|
||||||
|
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
@ -211,11 +187,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let actual = actual
|
let actual = actual
|
||||||
.fold_with(&mut swc_ecma_transforms::debug::validator::Validator { name: "actual-1" })
|
|
||||||
.fold_with(&mut swc_ecma_transforms::hygiene())
|
.fold_with(&mut swc_ecma_transforms::hygiene())
|
||||||
.fold_with(&mut swc_ecma_transforms::debug::validator::Validator { name: "actual-2" })
|
|
||||||
.fold_with(&mut swc_ecma_transforms::fixer(None))
|
.fold_with(&mut swc_ecma_transforms::fixer(None))
|
||||||
.fold_with(&mut swc_ecma_transforms::debug::validator::Validator { name: "actual-3" });
|
.fold_with(&mut as_folder(DropSpan {
|
||||||
|
preserve_ctxt: false,
|
||||||
|
}));
|
||||||
|
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -401,16 +377,19 @@ impl Write for Buf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Normalizer;
|
struct Normalizer;
|
||||||
impl Fold for Normalizer {
|
impl VisitMut for Normalizer {
|
||||||
fn fold_pat_or_expr(&mut self, node: PatOrExpr) -> PatOrExpr {
|
fn visit_mut_pat_or_expr(&mut self, node: &mut PatOrExpr) {
|
||||||
let node = node.fold_children_with(self);
|
node.visit_mut_children_with(self);
|
||||||
|
|
||||||
match node {
|
match node {
|
||||||
PatOrExpr::Pat(pat) => match *pat {
|
PatOrExpr::Pat(pat) => match &mut **pat {
|
||||||
Pat::Expr(expr) => PatOrExpr::Expr(expr),
|
Pat::Expr(e) => {
|
||||||
_ => PatOrExpr::Pat(pat),
|
let e = replace(e, Box::new(Expr::Invalid(Invalid { span: DUMMY_SP })));
|
||||||
|
*node = PatOrExpr::Expr(e);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => node,
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,19 +17,19 @@ mod common;
|
|||||||
struct ParenRemover;
|
struct ParenRemover;
|
||||||
impl Fold for ParenRemover {
|
impl Fold for ParenRemover {
|
||||||
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
||||||
let expr = validate!(expr);
|
let expr = expr;
|
||||||
let span = expr.span();
|
let span = expr.span();
|
||||||
|
|
||||||
let expr = expr.fold_children_with(self);
|
let expr = expr.fold_children_with(self);
|
||||||
|
|
||||||
validate!(match expr {
|
match expr {
|
||||||
Expr::Paren(ParenExpr { expr, .. }) => match *expr {
|
Expr::Paren(ParenExpr { expr, .. }) => match *expr {
|
||||||
Expr::Member(e) => Expr::Member(MemberExpr { span, ..e }),
|
Expr::Member(e) => Expr::Member(MemberExpr { span, ..e }),
|
||||||
Expr::New(e) => Expr::New(NewExpr { span, ..e }),
|
Expr::New(e) => Expr::New(NewExpr { span, ..e }),
|
||||||
_ => *expr,
|
_ => *expr,
|
||||||
},
|
},
|
||||||
_ => expr,
|
_ => expr,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ fn syntax() -> Syntax {
|
|||||||
fn tr() -> impl Fold {
|
fn tr() -> impl Fold {
|
||||||
chain!(
|
chain!(
|
||||||
ParenRemover,
|
ParenRemover,
|
||||||
validating!(arrow()),
|
arrow(),
|
||||||
validating!(parameters()),
|
parameters(),
|
||||||
validating!(destructuring(destructuring::Config { loose: false })),
|
destructuring(destructuring::Config { loose: false }),
|
||||||
validating!(function_name()),
|
function_name(),
|
||||||
async_to_generator(),
|
async_to_generator(),
|
||||||
fixer(None)
|
fixer(None)
|
||||||
)
|
)
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "swc_ecma_visit"
|
|
||||||
version = "0.17.0"
|
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
license = "Apache-2.0/MIT"
|
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
|
||||||
documentation = "https://swc-project.github.io/rustdoc/swc_ecma_visit/"
|
|
||||||
description = "Visitors for swc ecmascript nodes which works on stable rustc"
|
description = "Visitors for swc ecmascript nodes which works on stable rustc"
|
||||||
|
documentation = "https://swc-project.github.io/rustdoc/swc_ecma_visit/"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
license = "Apache-2.0/MIT"
|
||||||
|
name = "swc_ecma_visit"
|
||||||
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
version = "0.17.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
swc_atoms = { version = "0.2", path = "../../atoms" }
|
num-bigint = {version = "0.2", features = ["serde"]}
|
||||||
swc_common = { version = "0.10.0", path = "../../common" }
|
swc_atoms = {version = "0.2", path = "../../atoms"}
|
||||||
swc_ecma_ast = { version = "0.31.0", path ="../ast" }
|
swc_common = {version = "0.10.0", path = "../../common"}
|
||||||
swc_visit = { version = "0.2.0", path ="../../visit" }
|
swc_ecma_ast = {version = "0.31.0", path = "../ast"}
|
||||||
num-bigint = { version = "0.2", features = ["serde"] }
|
swc_visit = {version = "0.2.0", path = "../../visit"}
|
||||||
|
@ -20,11 +20,13 @@ where
|
|||||||
|
|
||||||
B: Fold,
|
B: Fold,
|
||||||
{
|
{
|
||||||
|
#[inline(always)]
|
||||||
fn fold_module(&mut self, n: Module) -> Module {
|
fn fold_module(&mut self, n: Module) -> Module {
|
||||||
let n = self.first.fold_module(n);
|
let n = self.first.fold_module(n);
|
||||||
self.second.fold_module(n)
|
self.second.fold_module(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn fold_script(&mut self, n: Script) -> Script {
|
fn fold_script(&mut self, n: Script) -> Script {
|
||||||
let n = self.first.fold_script(n);
|
let n = self.first.fold_script(n);
|
||||||
self.second.fold_script(n)
|
self.second.fold_script(n)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@swc/core",
|
"name": "@swc/core",
|
||||||
"version": "1.2.23",
|
"version": "1.2.23-alpha.1",
|
||||||
"description": "Super-fast alternative for babel",
|
"description": "Super-fast alternative for babel",
|
||||||
"homepage": "https://swc-project.github.io",
|
"homepage": "https://swc-project.github.io",
|
||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
@ -73,4 +73,4 @@
|
|||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/swc"
|
"url": "https://opencollective.com/swc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "testing"
|
|
||||||
version = "0.10.0"
|
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
license = "Apache-2.0/MIT"
|
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
|
||||||
documentation = "https://swc-project.github.io/rustdoc/testing/"
|
|
||||||
description = "Testing utilities for the swc project."
|
description = "Testing utilities for the swc project."
|
||||||
|
documentation = "https://swc-project.github.io/rustdoc/testing/"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
license = "Apache-2.0/MIT"
|
||||||
|
name = "testing"
|
||||||
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
version = "0.10.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
swc_common = { version = "0.10.0", path ="../common", features = ["tty-emitter"] }
|
|
||||||
once_cell = "1"
|
|
||||||
regex = "1"
|
|
||||||
difference = "2"
|
|
||||||
log = "0.4"
|
|
||||||
env_logger = "0.7.1"
|
|
||||||
ansi_term = "0.12.1"
|
ansi_term = "0.12.1"
|
||||||
|
difference = "2"
|
||||||
|
env_logger = "0.7.1"
|
||||||
|
log = "0.4"
|
||||||
|
once_cell = "1"
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
|
regex = "1"
|
||||||
|
swc_common = {version = "0.10.0", path = "../common", features = ["tty-emitter"]}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
pub use self::output::{NormalizedOutput, StdErr, StdOut, TestOutput};
|
pub use self::output::{NormalizedOutput, StdErr, StdOut, TestOutput};
|
||||||
use difference::Changeset;
|
use difference::Changeset;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
pub use pretty_assertions::{assert_eq, assert_ne};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
Loading…
Reference in New Issue
Block a user