Skip to content

Commit 5bc461d

Browse files
committed
Check IIFE block under && binary expression (close #1)
1 parent fbf7bc0 commit 5bc461d

File tree

2 files changed

+155
-95
lines changed

2 files changed

+155
-95
lines changed

src/cjs.rs

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ pub struct CJSLexer {
2727
pub fn_returned: bool,
2828
pub exports_alias: IndexSet<String>,
2929
pub idents: IndexMap<String, IdentKind>,
30-
pub exports: IndexSet<String>,
30+
pub named_exports: IndexSet<String>,
3131
pub reexports: IndexSet<String>,
3232
}
3333

3434
impl CJSLexer {
3535
fn clear(&mut self) {
36-
self.exports.clear();
36+
self.named_exports.clear();
3737
self.reexports.clear();
3838
}
3939

@@ -51,15 +51,15 @@ impl CJSLexer {
5151
} else if let Some(class) = self.as_class(expr) {
5252
self.clear();
5353
for name in get_class_static_names(&class) {
54-
self.exports.insert(name);
54+
self.named_exports.insert(name);
5555
}
5656
} else if let Some(FnDesc { stmts, extends }) = self.as_function(expr) {
5757
self.clear();
5858
if self.call_mode {
5959
self.walk_body(stmts, true);
6060
} else {
6161
for name in extends {
62-
self.exports.insert(name);
62+
self.named_exports.insert(name);
6363
}
6464
}
6565
} else if let Expr::Call(call) = expr {
@@ -316,7 +316,7 @@ impl CJSLexer {
316316
_ => None,
317317
};
318318
if let Some(name) = name {
319-
self.exports.insert(name);
319+
self.named_exports.insert(name);
320320
}
321321
}
322322
PropOrSpread::Spread(SpreadElement { expr, .. }) => match expr.as_ref() {
@@ -426,11 +426,17 @@ impl CJSLexer {
426426

427427
fn is_exports_expr(&self, expr: &Expr) -> bool {
428428
match expr {
429+
// (0, exports)
430+
Expr::Seq(SeqExpr { exprs, .. }) => {
431+
let last_expr = exprs.last().unwrap();
432+
self.is_exports_expr(last_expr)
433+
}
429434
Expr::Ident(id) => {
430435
let id = id.sym.as_ref();
431436
self.is_exports_ident(id)
432437
}
433438
Expr::Member(_) => is_member(expr, "module", "exports"),
439+
Expr::Paren(ParenExpr { expr, .. }) => self.is_exports_expr(expr),
434440
_ => false,
435441
}
436442
}
@@ -448,9 +454,9 @@ impl CJSLexer {
448454

449455
// exports.foo || (exports.foo = {})
450456
// foo = exports.foo || (exports.foo = {})
451-
fn get_bare_export_names(&mut self, expr: &Expr) -> Option<String> {
457+
fn get_export_name_of_call_arg(&mut self, expr: &Expr) -> Option<String> {
452458
if let Expr::Assign(assign) = expr {
453-
return self.get_bare_export_names(assign.right.as_ref());
459+
return self.get_export_name_of_call_arg(assign.right.as_ref());
454460
}
455461

456462
if let Expr::Bin(bin) = expr {
@@ -499,7 +505,7 @@ impl CJSLexer {
499505
let obj_name = obj.sym.as_ref();
500506
if self.is_exports_ident(obj_name) {
501507
// exports.foo = 'bar'
502-
self.exports.insert(prop);
508+
self.named_exports.insert(prop);
503509
if let Expr::Assign(dep_assign) = assign.right.as_ref() {
504510
self.get_exports_from_assign(dep_assign);
505511
}
@@ -511,15 +517,15 @@ impl CJSLexer {
511517
}
512518
Expr::Member(_) => {
513519
if is_member(obj, "module", "exports") {
514-
self.exports.insert(prop);
520+
self.named_exports.insert(prop);
515521
}
516522
}
517523
_ => {}
518524
}
519525
}
520526
} else {
521-
if let Some(bare_export_name) = self.get_bare_export_names(assign.right.as_ref()) {
522-
self.exports.insert(bare_export_name);
527+
if let Some(name) = self.get_export_name_of_call_arg(assign.right.as_ref()) {
528+
self.named_exports.insert(name);
523529
}
524530
}
525531
}
@@ -545,13 +551,13 @@ impl CJSLexer {
545551
(&**obj, &*prop)
546552
{
547553
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("r") {
548-
self.exports.insert("__esModule".to_string());
554+
self.named_exports.insert("__esModule".to_string());
549555
}
550556
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("d") {
551557
let CallExpr { args, .. } = &*call;
552558
if let Some(ExprOrSpread { expr, .. }) = args.get(1) {
553559
if let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr {
554-
self.exports.insert(value.as_ref().to_string());
560+
self.named_exports.insert(value.as_ref().to_string());
555561
}
556562
}
557563
}
@@ -587,7 +593,7 @@ impl CJSLexer {
587593
if sym.as_ref().eq(webpack_exports_sym) {
588594
if let MemberProp::Ident(prop) = prop {
589595
if prop.sym.as_ref().eq("default") {
590-
self.exports.insert("default".to_string());
596+
self.named_exports.insert("default".to_string());
591597
}
592598
}
593599
}
@@ -616,7 +622,7 @@ impl CJSLexer {
616622
let prop_sym_ref = prop_sym.as_ref();
617623

618624
if prop_sym_ref.eq("r") {
619-
self.exports.insert("__esModule".to_string());
625+
self.named_exports.insert("__esModule".to_string());
620626
found_webpack_require_exprs = true;
621627
}
622628
if prop_sym_ref.eq("d") {
@@ -630,7 +636,7 @@ impl CJSLexer {
630636
..
631637
}) = &**prop
632638
{
633-
self.exports.insert(sym.as_ref().to_string());
639+
self.named_exports.insert(sym.as_ref().to_string());
634640
found_webpack_require_exprs = true;
635641
}
636642
}
@@ -747,6 +753,7 @@ impl CJSLexer {
747753
})
748754
.sum();
749755
}
756+
750757
fn is_umd_iife_call(&mut self, call: &CallExpr) -> Option<Vec<Stmt>> {
751758
if call.args.len() == 2 {
752759
let mut arg1 = call.args.get(1).unwrap().expr.as_ref();
@@ -953,21 +960,22 @@ impl CJSLexer {
953960

954961
fn parse_expr(&mut self, expr: &Expr) {
955962
match expr {
963+
Expr::Seq(SeqExpr { exprs, .. }) => {
964+
for expr in exprs {
965+
self.parse_expr(expr);
966+
}
967+
}
956968
// exports.foo = 'bar'
957969
// module.exports.foo = 'bar'
958970
// module.exports = { foo: 'bar' }
959971
// module.exports = { ...require('a'), ...require('b') }
960972
// module.exports = require('lib')
961973
// foo = exports.foo || (exports.foo = {})
962-
Expr::Seq(SeqExpr { exprs, .. }) => {
963-
for expr in exprs {
964-
self.parse_expr(expr);
965-
}
966-
}
967974
Expr::Assign(assign) => {
968975
self.get_exports_from_assign(&assign);
969976
}
970977
// Object.defineProperty(exports, 'foo', { value: 'bar' })
978+
// Object.defineProperty((0, exports), 'foo', { value: 'bar' })
971979
// Object.defineProperty(module.exports, 'foo', { value: 'bar' })
972980
// Object.defineProperty(module, 'exports', { value: { foo: 'bar' }})
973981
// Object.assign(exports, { foo: 'bar' })
@@ -1016,7 +1024,7 @@ impl CJSLexer {
10161024
}
10171025
if is_exports && with_value_or_getter {
10181026
if let Some(name) = name {
1019-
self.exports.insert(name);
1027+
self.named_exports.insert(name);
10201028
}
10211029
}
10221030
if is_module {
@@ -1028,7 +1036,7 @@ impl CJSLexer {
10281036
let is_module = is_module_ident(call.args[0].expr.as_ref());
10291037
let is_exports = self.is_exports_expr(call.args[0].expr.as_ref());
10301038
for arg in &call.args[1..] {
1031-
if let Some(props) = self.as_obj(arg.expr.as_ref()) {
1039+
if let Some(props) = self.as_obj(&arg.expr) {
10321040
if is_module {
10331041
let mut with_exports: Option<Expr> = None;
10341042
for prop in props {
@@ -1050,7 +1058,7 @@ impl CJSLexer {
10501058
} else if is_exports {
10511059
self.use_object_as_exports(props);
10521060
}
1053-
} else if let Some(reexport) = self.as_reexport(arg.expr.as_ref()) {
1061+
} else if let Some(reexport) = self.as_reexport(&arg.expr) {
10541062
if is_exports {
10551063
self.reexports.insert(reexport);
10561064
}
@@ -1077,8 +1085,8 @@ impl CJSLexer {
10771085
for arg in &call.args {
10781086
if arg.spread.is_none() {
10791087
// (function() { ... })(exports.foo || (exports.foo = {}))
1080-
if let Some(bare_export_name) = self.get_bare_export_names(arg.expr.as_ref()) {
1081-
self.exports.insert(bare_export_name);
1088+
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1089+
self.named_exports.insert(name);
10821090
}
10831091
}
10841092
}
@@ -1096,8 +1104,8 @@ impl CJSLexer {
10961104
// (function() { ... })(exports.foo || (exports.foo = {}))
10971105
for arg in &call.args {
10981106
if arg.spread.is_none() {
1099-
if let Some(bare_export_name) = self.get_bare_export_names(arg.expr.as_ref()) {
1100-
self.exports.insert(bare_export_name);
1107+
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1108+
self.named_exports.insert(name);
11011109
}
11021110
}
11031111
}
@@ -1117,13 +1125,28 @@ impl CJSLexer {
11171125
);
11181126
}
11191127
// 0 && (module.exports = { foo })
1120-
Expr::Bin(BinExpr { op, right, .. }) => {
1128+
// process.env.NODE_ENV === 'production' && (() => { module.exports = { foo } })()
1129+
Expr::Bin(BinExpr { left, op, right, .. }) => {
11211130
if matches!(op, BinaryOp::LogicalAnd) {
1122-
if let Expr::Assign(assign) = right.as_ref() {
1123-
self.get_exports_from_assign(assign);
1131+
if let Expr::Call(call) = right.as_ref() {
1132+
if let Some(body) = is_iife_call(&call) {
1133+
if self.is_true(left) {
1134+
for arg in &call.args {
1135+
if arg.spread.is_none() {
1136+
// (function() { ... })(exports.foo || (exports.foo = {}))
1137+
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1138+
self.named_exports.insert(name);
1139+
}
1140+
}
1141+
}
1142+
self.walk_body(body, false);
1143+
}
1144+
}
11241145
} else if let Expr::Paren(paren) = right.as_ref() {
11251146
if let Expr::Assign(assign) = paren.expr.as_ref() {
1126-
self.get_exports_from_assign(assign);
1147+
if is_lit_number(&left) || self.is_true(&left) {
1148+
self.get_exports_from_assign(assign);
1149+
}
11271150
}
11281151
}
11291152
}
@@ -1172,8 +1195,8 @@ impl CJSLexer {
11721195
for decl in var.as_ref().decls.iter() {
11731196
self.try_to_mark_exports_alias(decl);
11741197
if let Some(init_expr) = &decl.init {
1175-
if let Some(bare_export_name) = self.get_bare_export_names(init_expr) {
1176-
self.exports.insert(bare_export_name);
1198+
if let Some(name) = self.get_export_name_of_call_arg(init_expr) {
1199+
self.named_exports.insert(name);
11771200
}
11781201
}
11791202
}
@@ -1475,12 +1498,12 @@ impl CJSLexer {
14751498
fn_returned: false,
14761499
idents: self.idents.clone(),
14771500
exports_alias: self.exports_alias.clone(),
1478-
exports: self.exports.clone(),
1501+
named_exports: self.named_exports.clone(),
14791502
reexports: self.reexports.clone(),
14801503
};
14811504
lexer.walk(body, as_fn);
14821505
self.fn_returned = lexer.fn_returned;
1483-
self.exports = lexer.exports;
1506+
self.named_exports = lexer.named_exports;
14841507
self.reexports = lexer.reexports;
14851508
}
14861509
}
@@ -1588,6 +1611,13 @@ fn is_string_literal(expr: &Expr, value: &str) -> bool {
15881611
}
15891612
}
15901613

1614+
fn is_lit_number(expr: &Expr) -> bool {
1615+
match expr {
1616+
Expr::Lit(Lit::Num(_)) => true,
1617+
_ => false,
1618+
}
1619+
}
1620+
15911621
fn is_typeof(expr: &Expr, identifier: &str) -> bool {
15921622
match &*expr {
15931623
Expr::Unary(UnaryExpr { arg, op, .. }) => match op {

0 commit comments

Comments
 (0)