diff --git a/packages/transformers/js/core/src/collect.rs b/packages/transformers/js/core/src/collect.rs index 3bf6c2ddf12..f26f09e240d 100644 --- a/packages/transformers/js/core/src/collect.rs +++ b/packages/transformers/js/core/src/collect.rs @@ -8,7 +8,7 @@ use std::collections::{HashMap, HashSet}; use swc_core::common::{sync::Lrc, Mark, Span, DUMMY_SP}; use swc_core::ecma::ast::*; use swc_core::ecma::atoms::{js_word, JsWord}; -use swc_core::ecma::visit::{Visit, VisitWith}; +use swc_core::ecma::visit::{noop_visit_type, Visit, VisitWith}; macro_rules! collect_visit_fn { ($name:ident, $type:ident) => { @@ -822,29 +822,27 @@ impl Visit for Collect { self.in_assign = false; node.right.visit_with(self); - if let PatOrExpr::Pat(pat) = &node.left { - if has_binding_identifier(pat, &"exports".into(), self.unresolved_mark) { - // Must wrap for cases like - // ``` - // function logExports() { - // console.log(exports); - // } - // exports.test = 2; - // logExports(); - // exports = {test: 4}; - // logExports(); - // ``` - self.static_cjs_exports = false; - self.has_cjs_exports = true; - self.should_wrap = true; - self.add_bailout(node.span, BailoutReason::ExportsReassignment); - } else if has_binding_identifier(pat, &"module".into(), self.unresolved_mark) { - // Same for `module`. If it is reassigned we can't correctly statically analyze. - self.static_cjs_exports = false; - self.has_cjs_exports = true; - self.should_wrap = true; - self.add_bailout(node.span, BailoutReason::ModuleReassignment); - } + if has_binding_identifier(&node.left, &"exports".into(), self.unresolved_mark) { + // Must wrap for cases like + // ``` + // function logExports() { + // console.log(exports); + // } + // exports.test = 2; + // logExports(); + // exports = {test: 4}; + // logExports(); + // ``` + self.static_cjs_exports = false; + self.has_cjs_exports = true; + self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::ExportsReassignment); + } else if has_binding_identifier(&node.left, &"module".into(), self.unresolved_mark) { + // Same for `module`. If it is reassigned we can't correctly statically analyze. + self.static_cjs_exports = false; + self.has_cjs_exports = true; + self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::ModuleReassignment); } } @@ -1096,7 +1094,7 @@ impl Collect { } ObjectPatProp::Assign(assign) => { if self.non_const_bindings.contains_key(&id!(assign.key)) { - idents.push(assign.key.clone()); + idents.push(assign.key.id.clone()); } } ObjectPatProp::Rest(rest) => { @@ -1124,43 +1122,28 @@ impl Collect { } } -fn has_binding_identifier(node: &Pat, sym: &JsWord, unresolved_mark: Mark) -> bool { - match node { - Pat::Ident(ident) => { - if ident.id.sym == *sym && is_unresolved(&ident, unresolved_mark) { - return true; - } - } - Pat::Object(object) => { - for prop in &object.props { - match prop { - ObjectPatProp::KeyValue(kv) => { - if has_binding_identifier(&kv.value, sym, unresolved_mark) { - return true; - } - } - ObjectPatProp::Assign(assign) => { - if assign.key.sym == *sym && is_unresolved(&assign.key, unresolved_mark) { - return true; - } - } - ObjectPatProp::Rest(rest) => { - if has_binding_identifier(&rest.arg, sym, unresolved_mark) { - return true; - } - } - } - } - } - Pat::Array(array) => { - for el in array.elems.iter().flatten() { - if has_binding_identifier(el, sym, unresolved_mark) { - return true; - } +fn has_binding_identifier(node: &AssignTarget, sym: &JsWord, unresolved_mark: Mark) -> bool { + pub struct BindingIdentFinder<'a> { + sym: &'a JsWord, + unresolved_mark: Mark, + found: bool, + } + + impl Visit for BindingIdentFinder<'_> { + noop_visit_type!(); + + fn visit_binding_ident(&mut self, ident: &BindingIdent) { + if ident.id.sym == *self.sym && is_unresolved(&ident, self.unresolved_mark) { + self.found = true; } } - _ => {} } - false + let mut visitor = BindingIdentFinder { + sym, + unresolved_mark, + found: false, + }; + node.visit_with(&mut visitor); + visitor.found } diff --git a/packages/transformers/js/core/src/env_replacer.rs b/packages/transformers/js/core/src/env_replacer.rs index e6355f53ea5..1de14706b98 100644 --- a/packages/transformers/js/core/src/env_replacer.rs +++ b/packages/transformers/js/core/src/env_replacer.rs @@ -24,20 +24,16 @@ impl<'a> Fold for EnvReplacer<'a> { // Replace assignments to process.browser with `true` // TODO: this seems questionable but we did it in the JS version?? if let Expr::Assign(ref assign) = node { - if let PatOrExpr::Pat(ref pat) = assign.left { - if let Pat::Expr(ref expr) = &**pat { - if let Expr::Member(ref member) = &**expr { - if self.is_browser - && match_member_expr(member, vec!["process", "browser"], self.unresolved_mark) - { - let mut res = assign.clone(); - res.right = Box::new(Expr::Lit(Lit::Bool(Bool { - value: true, - span: DUMMY_SP, - }))); - return Expr::Assign(res); - } - } + if let AssignTarget::Simple(SimpleAssignTarget::Member(member)) = &assign.left { + if self.is_browser + && match_member_expr(member, vec!["process", "browser"], self.unresolved_mark) + { + let mut res = assign.clone(); + res.right = Box::new(Expr::Lit(Lit::Bool(Bool { + value: true, + span: DUMMY_SP, + }))); + return Expr::Assign(res); } } } @@ -87,56 +83,58 @@ impl<'a> Fold for EnvReplacer<'a> { return node.fold_children_with(self); } - let expr = match &assign.left { - PatOrExpr::Pat(pat) => { - if let Pat::Expr(expr) = &**pat { - Some(&**expr) - } else if let Expr::Member(member) = &*assign.right { - if assign.op == AssignOp::Assign - && match_member_expr(member, vec!["process", "env"], self.unresolved_mark) - { - let mut decls = vec![]; - self.collect_pat_bindings(pat, &mut decls); + // process.env.FOO = ...; + if let AssignTarget::Simple(SimpleAssignTarget::Member(member)) = &assign.left { + if let Expr::Member(obj) = &*member.obj { + if match_member_expr(obj, vec!["process", "env"], self.unresolved_mark) { + self.emit_mutating_error(assign.span); + return *assign.right.clone().fold_with(self); + } + } + } - let mut exprs: Vec> = decls - .iter() - .map(|decl| { - Box::new(Expr::Assign(AssignExpr { - span: DUMMY_SP, - op: AssignOp::Assign, - left: PatOrExpr::Pat(Box::new(decl.name.clone())), - right: Box::new(if let Some(init) = &decl.init { - *init.clone() - } else { - Expr::Ident(get_undefined_ident(self.unresolved_mark)) - }), - })) - }) - .collect(); + if let Expr::Member(member) = &*assign.right { + if assign.op == AssignOp::Assign + && match_member_expr(member, vec!["process", "env"], self.unresolved_mark) + { + let pat = match &assign.left { + // ({x, y, z, ...} = process.env); + AssignTarget::Simple(SimpleAssignTarget::Ident(ident)) => { + Some(Pat::Ident(ident.clone())) + } + // foo = process.env; + AssignTarget::Pat(AssignTargetPat::Object(obj)) => Some(obj.clone().into()), + _ => None, + }; + if let Some(pat) = pat { + let mut decls = vec![]; + self.collect_pat_bindings(&pat, &mut decls); - exprs.push(Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: vec![], - }))); + let mut exprs: Vec> = decls + .iter() + .map(|decl| { + Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: decl.name.clone().try_into().unwrap(), + right: Box::new(if let Some(init) = &decl.init { + *init.clone() + } else { + Expr::Ident(get_undefined_ident(self.unresolved_mark)) + }), + })) + }) + .collect(); - return Expr::Seq(SeqExpr { - span: assign.span, - exprs, - }); - } - None - } else { - None - } - } - PatOrExpr::Expr(expr) => Some(&**expr), - }; + exprs.push(Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: vec![], + }))); - if let Some(Expr::Member(MemberExpr { obj, .. })) = &expr { - if let Expr::Member(member) = &**obj { - if match_member_expr(member, vec!["process", "env"], self.unresolved_mark) { - self.emit_mutating_error(assign.span); - return *assign.right.clone().fold_with(self); + return Expr::Seq(SeqExpr { + span: assign.span, + exprs, + }); } } } diff --git a/packages/transformers/js/core/src/hoist.rs b/packages/transformers/js/core/src/hoist.rs index 6c701d39eff..a951f20f7f2 100644 --- a/packages/transformers/js/core/src/hoist.rs +++ b/packages/transformers/js/core/src/hoist.rs @@ -874,21 +874,13 @@ impl<'a> Fold for Hoist<'a> { return node.fold_children_with(self); } - let expr = match &node.left { - PatOrExpr::Expr(expr) => expr, - PatOrExpr::Pat(pat) => match &**pat { - Pat::Expr(expr) => expr, - _ => return node.fold_children_with(self), - }, - }; - - if let Expr::Member(member) = &**expr { + if let AssignTarget::Simple(SimpleAssignTarget::Member(member)) = &node.left { if match_member_expr(member, vec!["module", "exports"], self.unresolved_mark) { let ident = BindingIdent::from(self.get_export_ident(member.span, &"*".into())); return AssignExpr { span: node.span, op: node.op, - left: PatOrExpr::Pat(Box::new(Pat::Ident(ident))), + left: AssignTarget::Simple(SimpleAssignTarget::Ident(ident.into())), right: node.right.fold_with(self), }; } @@ -940,13 +932,13 @@ impl<'a> Fold for Hoist<'a> { span: node.span, op: node.op, left: if self.collect.static_cjs_exports { - PatOrExpr::Pat(Box::new(Pat::Ident(ident))) + AssignTarget::Simple(SimpleAssignTarget::Ident(ident.into())) } else { - PatOrExpr::Pat(Box::new(Pat::Expr(Box::new(Expr::Member(MemberExpr { + AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { span: member.span, obj: Box::new(Expr::Ident(ident.id)), prop: member.prop.clone().fold_with(self), - }))))) + })) }, right: node.right.fold_with(self), }; diff --git a/packages/transformers/js/core/src/modules.rs b/packages/transformers/js/core/src/modules.rs index 58f84b6dbcf..ef73b8d9eb6 100644 --- a/packages/transformers/js/core/src/modules.rs +++ b/packages/transformers/js/core/src/modules.rs @@ -211,11 +211,11 @@ impl ESMFold { ModuleItem::Stmt(Stmt::Expr(ExprStmt { expr: Box::new(Expr::Assign(AssignExpr { op: AssignOp::Assign, - left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr { obj: Box::new(Expr::Ident(Ident::new("exports".into(), DUMMY_SP))), prop: MemberProp::Ident(Ident::new(name, DUMMY_SP)), span: DUMMY_SP, - }))), + })), right: Box::new(right), span: DUMMY_SP, })), @@ -584,7 +584,7 @@ impl Fold for ESMFold { if self.in_export_decl { self.create_export( node.key.sym.clone(), - Expr::Ident(node.key.clone()), + Expr::Ident(node.key.id.clone()), DUMMY_SP, ); }