Skip to content

Commit c4c303e

Browse files
committed
lexer: support var foo = exports.foo = ... pattern
1 parent a8f1748 commit c4c303e

File tree

2 files changed

+114
-88
lines changed

2 files changed

+114
-88
lines changed

lexer/src/lexer.rs

Lines changed: 85 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,9 @@ impl ModuleLexer {
456456

457457
// exports.foo || (exports.foo = {})
458458
// foo = exports.foo || (exports.foo = {})
459-
fn get_export_name_of_call_arg(&mut self, expr: &Expr) -> Option<String> {
459+
fn get_export_name_from_bin_expr(&mut self, expr: &Expr) -> Option<String> {
460460
if let Expr::Assign(assign) = expr {
461-
return self.get_export_name_of_call_arg(assign.right.as_ref());
461+
return self.get_export_name_from_bin_expr(assign.right.as_ref());
462462
}
463463

464464
if let Expr::Bin(bin) = expr {
@@ -527,90 +527,16 @@ impl ModuleLexer {
527527
if self.is_exports_ident(id.sym.as_ref()) {
528528
// exports = ??
529529
self.replace_exports_from_expr(assign.right.as_ref());
530-
return
530+
return;
531531
}
532532
}
533533
}
534-
if let Some(name) = self.get_export_name_of_call_arg(assign.right.as_ref()) {
534+
if let Some(name) = self.get_export_name_from_bin_expr(assign.right.as_ref()) {
535535
self.named_exports.insert(name);
536536
}
537537
}
538538
}
539539

540-
// function (e, t, r) {
541-
// "use strict";
542-
// r.r(t), r.d(t, "named", (function () { return n }));
543-
// var n = "named-export";
544-
// t.default = "default-export";
545-
// }
546-
fn get_webpack4_exports(&mut self, expr: &Expr, webpack_exports_sym: &str, webpack_require_sym: Option<&str>) {
547-
match &*expr {
548-
Expr::Seq(SeqExpr { exprs, .. }) => {
549-
for expr in exprs {
550-
self.get_webpack4_exports(&expr, webpack_exports_sym, webpack_require_sym)
551-
}
552-
}
553-
Expr::Call(call) => match webpack_require_sym {
554-
Some(webpack_require_sym) => {
555-
if let Some(Expr::Member(MemberExpr { obj, prop, .. })) = with_expr_callee(call) {
556-
if let (Expr::Ident(Ident { sym: obj_sym, .. }), MemberProp::Ident(IdentName { sym: prop_sym, .. })) =
557-
(&**obj, &*prop)
558-
{
559-
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("r") {
560-
self.named_exports.insert("__esModule".to_string());
561-
}
562-
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("d") {
563-
let CallExpr { args, .. } = &*call;
564-
if let Some(ExprOrSpread { expr, .. }) = args.get(1) {
565-
if let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr {
566-
self.named_exports.insert(value.as_ref().to_string());
567-
}
568-
}
569-
}
570-
}
571-
}
572-
}
573-
None => {}
574-
},
575-
Expr::Assign(AssignExpr {
576-
left,
577-
op: AssignOp::Assign,
578-
..
579-
}) => {
580-
// if let PatOrExpr::Expr(expr) = &*left {
581-
// if let Expr::Member(MemberExpr { obj, prop, .. }) = &**expr {
582-
// if let Expr::Ident(Ident { sym, .. }) = &**obj {
583-
// if sym.as_ref().eq(webpack_exports_sym.as_ref()) {
584-
// if let MemberProp::Ident(prop) = prop {
585-
// if prop.sym.as_ref().eq("default") {
586-
// self.exports.insert("default".to_string());
587-
// }
588-
// }
589-
// }
590-
// }
591-
// }
592-
// }
593-
// This doesn't feel right but is what ends up matching
594-
// t.default = "default-export"
595-
// May be an swc ast bug
596-
if let AssignTarget::Simple(simple) = &left {
597-
if let SimpleAssignTarget::Member(MemberExpr { obj, prop, .. }) = &simple {
598-
if let Expr::Ident(Ident { sym, .. }) = &**obj {
599-
if sym.as_ref().eq(webpack_exports_sym) {
600-
if let MemberProp::Ident(prop) = prop {
601-
if prop.sym.as_ref().eq("default") {
602-
self.named_exports.insert("default".to_string());
603-
}
604-
}
605-
}
606-
}
607-
}
608-
}
609-
}
610-
_ => {}
611-
}
612-
}
613-
614540
fn get_webpack_exports(&mut self, stmts: &Vec<Stmt>, webpack_require_sym: &str, first_stmt_index: &usize) {
615541
stmts.iter().skip(*first_stmt_index).take(8).find(|stmt| match stmt {
616542
Stmt::Expr(ExprStmt { expr, .. }) => {
@@ -760,6 +686,80 @@ impl ModuleLexer {
760686
.sum();
761687
}
762688

689+
// function (e, t, r) {
690+
// "use strict";
691+
// r.r(t), r.d(t, "named", (function () { return n }));
692+
// var n = "named-export";
693+
// t.default = "default-export";
694+
// }
695+
fn get_webpack4_exports(&mut self, expr: &Expr, webpack_exports_sym: &str, webpack_require_sym: Option<&str>) {
696+
match &*expr {
697+
Expr::Seq(SeqExpr { exprs, .. }) => {
698+
for expr in exprs {
699+
self.get_webpack4_exports(&expr, webpack_exports_sym, webpack_require_sym)
700+
}
701+
}
702+
Expr::Call(call) => match webpack_require_sym {
703+
Some(webpack_require_sym) => {
704+
if let Some(Expr::Member(MemberExpr { obj, prop, .. })) = with_expr_callee(call) {
705+
if let (Expr::Ident(Ident { sym: obj_sym, .. }), MemberProp::Ident(IdentName { sym: prop_sym, .. })) =
706+
(&**obj, &*prop)
707+
{
708+
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("r") {
709+
self.named_exports.insert("__esModule".to_string());
710+
}
711+
if obj_sym.as_ref().eq(webpack_require_sym) && prop_sym.as_ref().eq("d") {
712+
let CallExpr { args, .. } = &*call;
713+
if let Some(ExprOrSpread { expr, .. }) = args.get(1) {
714+
if let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr {
715+
self.named_exports.insert(value.as_ref().to_string());
716+
}
717+
}
718+
}
719+
}
720+
}
721+
}
722+
None => {}
723+
},
724+
Expr::Assign(AssignExpr {
725+
left,
726+
op: AssignOp::Assign,
727+
..
728+
}) => {
729+
// if let PatOrExpr::Expr(expr) = &*left {
730+
// if let Expr::Member(MemberExpr { obj, prop, .. }) = &**expr {
731+
// if let Expr::Ident(Ident { sym, .. }) = &**obj {
732+
// if sym.as_ref().eq(webpack_exports_sym.as_ref()) {
733+
// if let MemberProp::Ident(prop) = prop {
734+
// if prop.sym.as_ref().eq("default") {
735+
// self.exports.insert("default".to_string());
736+
// }
737+
// }
738+
// }
739+
// }
740+
// }
741+
// }
742+
// This doesn't feel right but is what ends up matching
743+
// t.default = "default-export"
744+
// May be an swc ast bug
745+
if let AssignTarget::Simple(simple) = &left {
746+
if let SimpleAssignTarget::Member(MemberExpr { obj, prop, .. }) = &simple {
747+
if let Expr::Ident(Ident { sym, .. }) = &**obj {
748+
if sym.as_ref().eq(webpack_exports_sym) {
749+
if let MemberProp::Ident(prop) = prop {
750+
if prop.sym.as_ref().eq("default") {
751+
self.named_exports.insert("default".to_string());
752+
}
753+
}
754+
}
755+
}
756+
}
757+
}
758+
}
759+
_ => {}
760+
}
761+
}
762+
763763
fn is_umd_iife_call(&mut self, call: &CallExpr) -> Option<Vec<Stmt>> {
764764
if call.args.len() == 2 {
765765
let mut arg1 = call.args.get(1).unwrap().expr.as_ref();
@@ -1093,7 +1093,7 @@ impl ModuleLexer {
10931093
for arg in &call.args {
10941094
if arg.spread.is_none() {
10951095
// (function() { ... })(exports.foo || (exports.foo = {}))
1096-
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1096+
if let Some(name) = self.get_export_name_from_bin_expr(&arg.expr) {
10971097
self.named_exports.insert(name);
10981098
}
10991099
}
@@ -1112,7 +1112,7 @@ impl ModuleLexer {
11121112
// (function() { ... })(exports.foo || (exports.foo = {}))
11131113
for arg in &call.args {
11141114
if arg.spread.is_none() {
1115-
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1115+
if let Some(name) = self.get_export_name_from_bin_expr(&arg.expr) {
11161116
self.named_exports.insert(name);
11171117
}
11181118
}
@@ -1142,7 +1142,7 @@ impl ModuleLexer {
11421142
for arg in &call.args {
11431143
if arg.spread.is_none() {
11441144
// (function() { ... })(exports.foo || (exports.foo = {}))
1145-
if let Some(name) = self.get_export_name_of_call_arg(&arg.expr) {
1145+
if let Some(name) = self.get_export_name_from_bin_expr(&arg.expr) {
11461146
self.named_exports.insert(name);
11471147
}
11481148
}
@@ -1199,12 +1199,15 @@ impl ModuleLexer {
11991199
for stmt in &stmts {
12001200
match stmt {
12011201
// var foo = exports.foo || (exports.foo = {})
1202+
// var foo = exports.foo = "bar"
12021203
Stmt::Decl(Decl::Var(var)) => {
12031204
for decl in var.as_ref().decls.iter() {
12041205
self.try_to_mark_exports_alias(decl);
12051206
if let Some(init_expr) = &decl.init {
1206-
if let Some(name) = self.get_export_name_of_call_arg(init_expr) {
1207+
if let Some(name) = self.get_export_name_from_bin_expr(init_expr) {
12071208
self.named_exports.insert(name);
1209+
} else {
1210+
self.parse_expr(init_expr);
12081211
}
12091212
}
12101213
}

lexer/src/test.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,15 @@ mod tests {
171171
let source = r#"
172172
class Module {
173173
static foo = 'bar'
174-
static greet() {}
174+
static greeting() {}
175175
alas = true
176176
boom() {}
177177
}
178178
module.exports = Module
179179
"#;
180180
let lexer = CommonJSModuleLexer::init("index.cjs", source).expect("could not parse the module");
181181
let (exports, _) = lexer.analyze("development", false);
182-
assert_eq!(exports.join(","), "foo,greet");
182+
assert_eq!(exports.join(","), "foo,greeting");
183183
}
184184

185185
#[test]
@@ -288,6 +288,7 @@ mod tests {
288288
}
289289

290290
#[test]
291+
// block
291292
fn parse_cjs_exports_case_13() {
292293
let source = r#"
293294
{
@@ -624,23 +625,45 @@ mod tests {
624625
var foo;
625626
foo = exports.foo || (exports.foo = {});
626627
var bar = exports.bar || (exports.bar = {});
627-
exports.greet = 123;
628+
exports.greeting = "hello";
628629
"#;
629630
let lexer = CommonJSModuleLexer::init("index.cjs", source).expect("could not parse the module");
630631
let (exports, _) = lexer.analyze("production", true);
631-
assert_eq!(exports.join(","), "foo,bar,greet");
632+
assert_eq!(exports.join(","), "foo,bar,greeting");
632633
}
633634

634635
#[test]
635636
fn parse_cjs_exports_case_20_2() {
636637
let source = r#"
637638
var bar;
638639
((foo, bar) => { })(exports.foo || (exports.foo = {}), bar = exports.bar || (exports.bar = {}));
639-
exports.greet = 123;
640+
exports.greeting = "hello";
640641
"#;
641642
let lexer = CommonJSModuleLexer::init("index.cjs", source).expect("could not parse the module");
642643
let (exports, _) = lexer.analyze("production", true);
643-
assert_eq!(exports.join(","), "foo,bar,greet");
644+
assert_eq!(exports.join(","), "foo,bar,greeting");
645+
}
646+
647+
#[test]
648+
fn parse_cjs_exports_case_20_3() {
649+
let source = r#"
650+
var foo = exports.foo = "bar";
651+
exports.greeting = "hello";
652+
"#;
653+
let lexer = CommonJSModuleLexer::init("index.cjs", source).expect("could not parse the module");
654+
let (exports, _) = lexer.analyze("production", true);
655+
assert_eq!(exports.join(","), "foo,greeting");
656+
}
657+
658+
#[test]
659+
fn parse_cjs_exports_case_20_4() {
660+
let source = r#"
661+
var foo = module.exports.foo = "bar";
662+
exports.greeting = "hello";
663+
"#;
664+
let lexer = CommonJSModuleLexer::init("index.cjs", source).expect("could not parse the module");
665+
let (exports, _) = lexer.analyze("production", true);
666+
assert_eq!(exports.join(","), "foo,greeting");
644667
}
645668

646669
#[test]

0 commit comments

Comments
 (0)