swc_ecma_compat_es2015/
function_name.rs

1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::perf::Parallel;
4use swc_ecma_utils::{private_ident, IdentUsageFinder};
5use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
6use swc_trace_macro::swc_trace;
7
8/// `@babel/plugin-transform-function-name`
9///
10/// # Example
11/// ## In
12/// ```js
13/// var number = function (x) {
14///   return x;
15/// };
16/// var Foo = (class {});
17/// ```
18/// ## Out
19/// ```js
20/// var number = function number(x) {
21///   return x;
22/// }
23/// var Foo = (class Foo {});
24/// ```
25pub fn function_name() -> impl Pass {
26    visit_mut_pass(FnName)
27}
28
29#[derive(Clone, Copy)]
30struct FnName;
31
32impl Parallel for FnName {
33    fn create(&self) -> Self {
34        *self
35    }
36
37    fn merge(&mut self, _: Self) {}
38}
39
40struct Rename {
41    name: Option<Ident>,
42}
43
44/// This function makes a new private identifier if required.
45fn prepare(i: Ident) -> Ident {
46    if i.is_reserved() || i.is_reserved_in_strict_mode(true) || i.is_reserved_in_strict_bind() {
47        return private_ident!(i.span, format!("_{}", i.sym));
48    }
49
50    private_ident!(i.span, i.sym)
51}
52
53#[swc_trace]
54impl VisitMut for FnName {
55    noop_visit_mut_type!(fail);
56
57    fn visit_mut_assign_expr(&mut self, expr: &mut AssignExpr) {
58        expr.visit_mut_children_with(self);
59
60        if expr.op != op!("=") {
61            return;
62        }
63
64        if let Some(ident) = expr.left.as_ident_mut() {
65            let mut folder = Rename {
66                name: Some(Ident::from(&*ident)),
67            };
68
69            expr.right.visit_mut_with(&mut folder);
70        }
71    }
72
73    fn visit_mut_key_value_prop(&mut self, p: &mut KeyValueProp) {
74        p.visit_mut_children_with(self);
75
76        if let Expr::Fn(expr @ FnExpr { ident: None, .. }) = &mut *p.value {
77            //
78            p.value = if let PropName::Ident(ref i) = p.key {
79                FnExpr {
80                    ident: Some(prepare(i.clone().into())),
81                    ..expr.take()
82                }
83                .into()
84            } else {
85                expr.take().into()
86            };
87        };
88    }
89
90    fn visit_mut_var_declarator(&mut self, decl: &mut VarDeclarator) {
91        decl.visit_mut_children_with(self);
92
93        if let Pat::Ident(ref mut ident) = decl.name {
94            let mut folder = Rename {
95                name: Some(prepare(Ident::from(&*ident))),
96            };
97            decl.init.visit_mut_with(&mut folder);
98        }
99    }
100}
101
102macro_rules! impl_for {
103    ($name:ident, $T:tt) => {
104        fn $name(&mut self, node: &mut $T) {
105            match node.ident {
106                Some(..) => return,
107                None => {
108                    //
109                    let name = match self.name.take() {
110                        None => {
111                            node.ident = None;
112                            return;
113                        }
114                        Some(name) => name,
115                    };
116                    // If function's body references the name of variable, we just skip the
117                    // function
118                    if IdentUsageFinder::find(&name.to_id(), &*node) {
119                        // self.name = Some(name);
120                        node.ident = None;
121                    } else {
122                        node.ident = Some(private_ident!(DUMMY_SP, name.sym));
123                    }
124                }
125            }
126        }
127    };
128}
129
130macro_rules! noop {
131    ($name:ident, $T:tt) => {
132        /// Don't recurse.
133        fn $name(&mut self, _: &mut $T) {}
134    };
135}
136
137impl VisitMut for Rename {
138    noop_visit_mut_type!(fail);
139
140    impl_for!(visit_mut_fn_expr, FnExpr);
141
142    impl_for!(visit_mut_class_expr, ClassExpr);
143
144    noop!(visit_mut_object_lit, ObjectLit);
145
146    noop!(visit_mut_array_lit, ArrayLit);
147
148    noop!(visit_mut_call_expr, CallExpr);
149
150    noop!(visit_mut_new_expr, NewExpr);
151
152    noop!(visit_mut_bin_expr, BinExpr);
153
154    noop!(visit_mut_unary_expr, UnaryExpr);
155}