swc_ecma_minifier/compress/pure/
arrows.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{contains_arguments, contains_this_expr};

use super::Pure;
use crate::compress::util::contains_super;

/// Methods related to the option `arrows`.
impl Pure<'_> {
    pub(super) fn unsafe_optimize_fn_as_arrow(&mut self, e: &mut Expr) {
        if self.options.ecma < EsVersion::Es2015 {
            return;
        }

        if !self.options.unsafe_arrows {
            return;
        }

        if let Expr::Fn(FnExpr {
            ident: None,
            function,
        }) = e
        {
            if function.params.iter().any(contains_this_expr)
                || contains_this_expr(&function.body)
                || function.is_generator
            {
                return;
            }

            self.changed = true;
            report_change!("unsafe_arrows: Fn expr => arrow");

            *e = ArrowExpr {
                span: function.span,
                params: function.params.take().into_iter().map(|p| p.pat).collect(),
                body: Box::new(BlockStmtOrExpr::BlockStmt(function.body.take().unwrap())),
                is_async: function.is_async,
                is_generator: function.is_generator,
                ..Default::default()
            }
            .into();
        }
    }

    pub(super) fn optimize_arrow_body(&mut self, b: &mut BlockStmtOrExpr) {
        match b {
            BlockStmtOrExpr::BlockStmt(s) => {
                if s.stmts.len() == 1 {
                    if let Stmt::Return(s) = &mut s.stmts[0] {
                        if let Some(arg) = &mut s.arg {
                            report_change!("arrows: Optimizing the body of an arrow");
                            *b = BlockStmtOrExpr::Expr(arg.take());
                        }
                    }
                }
            }
            BlockStmtOrExpr::Expr(_) => {}
        }
    }

    pub(super) fn optimize_arrow_method_prop(&mut self, p: &mut Prop) {
        if !self.options.unsafe_methods && !self.options.arrows {
            return;
        }

        if let Prop::Method(m) = p {
            if m.function.is_generator
                || contains_arguments(&m.function.body)
                || contains_super(&m.function.body)
                || m.function.params.iter().any(contains_this_expr)
            {
                return;
            }

            let m_span = m.function.span;

            if let Some(body) = &mut m.function.body {
                if body.stmts.len() == 1
                    && matches!(
                        body.stmts[0],
                        Stmt::Return(ReturnStmt { arg: Some(..), .. })
                    )
                {
                    if contains_this_expr(body) {
                        return;
                    }
                    self.changed = true;
                    report_change!("Method property => arrow");

                    let arg = body
                        .take()
                        .stmts
                        .remove(0)
                        .expect_return_stmt()
                        .arg
                        .take()
                        .unwrap();

                    *p = Prop::KeyValue(KeyValueProp {
                        key: m.key.take(),
                        value: ArrowExpr {
                            span: m_span,
                            params: m
                                .function
                                .params
                                .take()
                                .into_iter()
                                .map(|v| v.pat)
                                .collect(),
                            body: Box::new(BlockStmtOrExpr::Expr(arg)),
                            is_async: m.function.is_async,
                            is_generator: m.function.is_generator,
                            ..Default::default()
                        }
                        .into(),
                    });
                    return;
                }
            }
        }

        if let Prop::KeyValue(kv) = p {
            // See https://github.com/swc-project/swc/pull/6521
            //
            // ({foo(){}}).foo.toString()
            //
            // returns `foo(){}`
            if !self.options.unsafe_methods {
                return;
            }

            //
            if contains_this_expr(&kv.value) {
                return;
            }

            match &mut *kv.value {
                Expr::Arrow(m) if m.body.is_block_stmt() => {
                    *p = Prop::Method(MethodProp {
                        key: kv.key.take(),
                        function: Box::new(Function {
                            params: m
                                .params
                                .take()
                                .into_iter()
                                .map(|pat| Param {
                                    span: DUMMY_SP,
                                    decorators: Default::default(),
                                    pat,
                                })
                                .collect(),
                            span: m.span,
                            body: m.body.take().block_stmt(),
                            is_generator: m.is_generator,
                            is_async: m.is_async,
                            ..Default::default()
                        }),
                    });
                }
                _ => (),
            }
        }
    }
}