swc_ecma_minifier/compress/pure/
arrows.rs1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_utils::{contains_arguments, contains_this_expr};
4
5use super::Pure;
6use crate::compress::util::contains_super;
7
8impl Pure<'_> {
10 pub(super) fn unsafe_optimize_fn_as_arrow(&mut self, e: &mut Expr) {
11 if self.options.ecma < EsVersion::Es2015 {
12 return;
13 }
14
15 if !self.options.unsafe_arrows {
16 return;
17 }
18
19 if let Expr::Fn(FnExpr {
20 ident: None,
21 function,
22 }) = e
23 {
24 if function.params.iter().any(contains_this_expr)
25 || contains_this_expr(&function.body)
26 || function.is_generator
27 {
28 return;
29 }
30
31 self.changed = true;
32 report_change!("unsafe_arrows: Fn expr => arrow");
33
34 *e = ArrowExpr {
35 span: function.span,
36 params: function.params.take().into_iter().map(|p| p.pat).collect(),
37 body: Box::new(BlockStmtOrExpr::BlockStmt(function.body.take().unwrap())),
38 is_async: function.is_async,
39 is_generator: function.is_generator,
40 ..Default::default()
41 }
42 .into();
43 }
44 }
45
46 pub(super) fn optimize_arrow_body(&mut self, b: &mut BlockStmtOrExpr) {
47 match b {
48 BlockStmtOrExpr::BlockStmt(s) => {
49 if s.stmts.len() == 1 {
50 if let Stmt::Return(s) = &mut s.stmts[0] {
51 if let Some(arg) = &mut s.arg {
52 report_change!("arrows: Optimizing the body of an arrow");
53 *b = BlockStmtOrExpr::Expr(arg.take());
54 }
55 }
56 }
57 }
58 BlockStmtOrExpr::Expr(_) => {}
59 #[cfg(swc_ast_unknown)]
60 _ => panic!("unable to access unknown nodes"),
61 }
62 }
63
64 pub(super) fn optimize_arrow_method_prop(&mut self, p: &mut Prop) {
65 if !self.options.unsafe_methods && !self.options.arrows {
66 return;
67 }
68
69 if let Prop::Method(m) = p {
70 if m.function.is_generator
71 || contains_arguments(&m.function.body)
72 || contains_super(&m.function.body)
73 || m.function.params.iter().any(contains_this_expr)
74 {
75 return;
76 }
77
78 let m_span = m.function.span;
79
80 if let Some(body) = &mut m.function.body {
81 if body.stmts.len() == 1
82 && matches!(
83 body.stmts[0],
84 Stmt::Return(ReturnStmt { arg: Some(..), .. })
85 )
86 {
87 if contains_this_expr(body) {
88 return;
89 }
90 self.changed = true;
91 report_change!("Method property => arrow");
92
93 let arg = body
94 .take()
95 .stmts
96 .remove(0)
97 .expect_return_stmt()
98 .arg
99 .take()
100 .unwrap();
101
102 *p = Prop::KeyValue(KeyValueProp {
103 key: m.key.take(),
104 value: ArrowExpr {
105 span: m_span,
106 params: m
107 .function
108 .params
109 .take()
110 .into_iter()
111 .map(|v| v.pat)
112 .collect(),
113 body: Box::new(BlockStmtOrExpr::Expr(arg)),
114 is_async: m.function.is_async,
115 is_generator: m.function.is_generator,
116 ..Default::default()
117 }
118 .into(),
119 });
120 return;
121 }
122 }
123 }
124
125 if let Prop::KeyValue(kv) = p {
126 if !self.options.unsafe_methods {
132 return;
133 }
134
135 if contains_this_expr(&kv.value) {
137 return;
138 }
139
140 match &mut *kv.value {
141 Expr::Arrow(m) if m.body.is_block_stmt() => {
142 *p = Prop::Method(MethodProp {
143 key: kv.key.take(),
144 function: Box::new(Function {
145 params: m
146 .params
147 .take()
148 .into_iter()
149 .map(|pat| Param {
150 span: DUMMY_SP,
151 decorators: Default::default(),
152 pat,
153 })
154 .collect(),
155 span: m.span,
156 body: m.body.take().block_stmt(),
157 is_generator: m.is_generator,
158 is_async: m.is_async,
159 ..Default::default()
160 }),
161 });
162 }
163 _ => (),
164 }
165 }
166 }
167}