swc_ecma_compat_bugfixes/
edge_default_param.rs

1use swc_ecma_ast::*;
2use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
3use swc_trace_macro::swc_trace;
4
5/// A bugfix pass for Edge.
6///
7/// Converts destructured parameters with default values to non-shorthand
8/// syntax. This fixes the only arguments-related bug in ES Modules-supporting
9/// browsers (Edge 16 & 17). Use this plugin instead of
10/// @babel/plugin-transform-parameters when targeting ES Modules.
11pub fn edge_default_param() -> impl Pass {
12    visit_mut_pass(EdgeDefaultParam::default())
13}
14#[derive(Default, Clone, Copy)]
15struct EdgeDefaultParam {
16    in_arrow: bool,
17}
18
19#[swc_trace]
20impl VisitMut for EdgeDefaultParam {
21    noop_visit_mut_type!(fail);
22
23    fn visit_mut_arrow_expr(&mut self, n: &mut ArrowExpr) {
24        self.in_arrow = true;
25        n.params.visit_mut_children_with(self);
26        self.in_arrow = false;
27
28        n.body.visit_mut_children_with(self);
29    }
30
31    fn visit_mut_object_pat(&mut self, n: &mut ObjectPat) {
32        n.visit_mut_children_with(self);
33        if !self.in_arrow {
34            return;
35        }
36
37        for idx in 0..n.props.len() {
38            let prop = &(n.props[idx]);
39
40            if let ObjectPatProp::Assign(AssignPatProp {
41                value: Some(value),
42                key,
43                span,
44                ..
45            }) = prop
46            {
47                let prop = ObjectPatProp::KeyValue(KeyValuePatProp {
48                    key: PropName::Ident(key.clone().into()),
49                    value: AssignPat {
50                        span: *span,
51                        left: key.clone().into(),
52                        right: value.clone(),
53                    }
54                    .into(),
55                });
56
57                n.props[idx] = prop;
58            }
59        }
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use swc_common::Mark;
66    use swc_ecma_transforms_base::resolver;
67    use swc_ecma_transforms_testing::test;
68
69    use super::*;
70
71    fn tr() -> impl Pass {
72        (
73            resolver(Mark::new(), Mark::new(), false),
74            edge_default_param(),
75        )
76    }
77
78    test!(
79        ::swc_ecma_parser::Syntax::default(),
80        |_| tr(),
81        destructured_default_value,
82        "const f = ({ a = 1 }) => a;"
83    );
84
85    test!(
86        ::swc_ecma_parser::Syntax::default(),
87        |_| tr(),
88        destructured_no_default_value,
89        "const f = ({ a }) => a;"
90    );
91
92    test!(
93        ::swc_ecma_parser::Syntax::default(),
94        |_| tr(),
95        nested_default_value,
96        "const f = ({ a: { b = 1 } }) => [a, b];"
97    );
98
99    test!(
100        ::swc_ecma_parser::Syntax::default(),
101        |_| tr(),
102        non_arguments,
103        "const f = () => { const { a = 1 } = {}; };"
104    );
105}