portal_es_tipsy/
lib.rs

1use std::mem::take;
2
3use swc_atoms::Atom;
4use swc_common::Spanned;
5use swc_ecma_ast::{
6    ArrowExpr, AssignExpr, AssignOp, AssignTarget, Bool, CallExpr, Callee, CondExpr, Expr,
7    ExprOrSpread, Ident, IdentName, Lit, MemberExpr, OptChainExpr, SeqExpr, SimpleAssignTarget,
8    Str,
9};
10use swc_ecma_visit::{VisitMut, VisitMutWith};
11#[non_exhaustive]
12pub struct Tipper {
13    pub haven: Ident,
14    pub activity: bool,
15}
16impl Tipper {
17    pub fn new(haven: Ident) -> Self {
18        Self {
19            haven,
20            activity: false,
21        }
22    }
23}
24impl VisitMut for Tipper {
25    fn visit_mut_expr(&mut self, e2: &mut Expr) {
26        let mut eb = if self.activity {
27            Some({
28                let mut eb = e2.clone();
29                eb.visit_mut_children_with(self);
30                eb
31            })
32        } else {
33            None
34        };
35        let f = match take(e2) {
36            Expr::Member(m) => {
37                let mut o = m.obj;
38                o.visit_mut_with(self);
39                let mut a = match m.prop {
40                    swc_ecma_ast::MemberProp::Ident(ident_name) => Expr::Lit(Lit::Str(Str {
41                        span: ident_name.span,
42                        value: ident_name.sym,
43                        raw: None,
44                    })),
45                    swc_ecma_ast::MemberProp::PrivateName(private_name) => todo!(),
46                    swc_ecma_ast::MemberProp::Computed(computed_prop_name) => {
47                        *computed_prop_name.expr
48                    }
49                };
50                a.visit_mut_with(self);
51                Expr::Call(CallExpr {
52                    span: m.span,
53                    ctxt: Default::default(),
54                    callee: swc_ecma_ast::Callee::Expr(Box::new(
55                        match Expr::Ident(self.haven.clone()) {
56                            c => match c.span() {
57                                s => Expr::Member(MemberExpr {
58                                    span: c.span(),
59                                    obj: Box::new(c),
60                                    prop: swc_ecma_ast::MemberProp::Ident(IdentName {
61                                        span: s,
62                                        sym: Atom::new("get"),
63                                    }),
64                                }),
65                            },
66                        },
67                    )),
68                    args: [o, Box::new(a)]
69                        .into_iter()
70                        .map(|a| ExprOrSpread {
71                            expr: a,
72                            spread: None,
73                        })
74                        .collect(),
75                    type_args: None,
76                })
77            }
78            Expr::Assign(AssignExpr {
79                span,
80                op,
81                mut right,
82                left: AssignTarget::Simple(SimpleAssignTarget::Member(m)),
83            }) => {
84                right.visit_mut_with(self);
85                let mut o = m.obj;
86                o.visit_mut_with(self);
87                let mut a = match m.prop {
88                    swc_ecma_ast::MemberProp::Ident(ident_name) => Expr::Lit(Lit::Str(Str {
89                        span: ident_name.span,
90                        value: ident_name.sym,
91                        raw: None,
92                    })),
93                    swc_ecma_ast::MemberProp::PrivateName(private_name) => todo!(),
94                    swc_ecma_ast::MemberProp::Computed(computed_prop_name) => {
95                        *computed_prop_name.expr
96                    }
97                };
98                a.visit_mut_with(self);
99                Expr::Call(CallExpr {
100                    span: m.span,
101                    ctxt: Default::default(),
102                    callee: swc_ecma_ast::Callee::Expr(Box::new(
103                        match Expr::Ident(self.haven.clone()) {
104                            c => match c.span() {
105                                s => Expr::Member(MemberExpr {
106                                    span: c.span(),
107                                    obj: Box::new(c),
108                                    prop: swc_ecma_ast::MemberProp::Ident(IdentName {
109                                        span: s,
110                                        sym: Atom::new("set"),
111                                    }),
112                                }),
113                            },
114                        },
115                    )),
116                    args: [o, Box::new(a), right]
117                        .into_iter()
118                        .chain(op.to_update().iter().cloned().map(|a| {
119                            Box::new(Expr::Lit(Lit::Str(Str {
120                                span: span,
121                                value: Atom::new(a.to_string()),
122                                raw: None,
123                            })))
124                        }))
125                        .map(|a| ExprOrSpread {
126                            expr: a,
127                            spread: None,
128                        })
129                        .collect(),
130                    type_args: None,
131                })
132            }
133
134            Expr::Call(CallExpr {
135                span,
136                ctxt,
137                callee,
138                mut args,
139                type_args,
140            }) => {
141                args.visit_mut_with(self);
142                match callee {
143                    Callee::Expr(mut e) => {
144                        let mut e = *e;
145                        match e {
146                            Expr::Member(mut m) => {
147                                m.visit_mut_with(self);
148                                let mut a = match m.prop {
149                                    swc_ecma_ast::MemberProp::Ident(ident_name) => {
150                                        Expr::Lit(Lit::Str(Str {
151                                            span: ident_name.span,
152                                            value: ident_name.sym,
153                                            raw: None,
154                                        }))
155                                    }
156                                    swc_ecma_ast::MemberProp::PrivateName(private_name) => todo!(),
157                                    swc_ecma_ast::MemberProp::Computed(computed_prop_name) => {
158                                        *computed_prop_name.expr
159                                    }
160                                };
161                                Expr::Call(CallExpr {
162                                    span: m.span,
163                                    ctxt: Default::default(),
164                                    callee: swc_ecma_ast::Callee::Expr(Box::new(
165                                        match Expr::Ident(self.haven.clone()) {
166                                            c => match c.span() {
167                                                s => Expr::Member(MemberExpr {
168                                                    span: c.span(),
169                                                    obj: Box::new(c),
170                                                    prop: swc_ecma_ast::MemberProp::Ident(
171                                                        IdentName {
172                                                            span: s,
173                                                            sym: Atom::new("call_member"),
174                                                        },
175                                                    ),
176                                                }),
177                                            },
178                                        },
179                                    )),
180                                    args: [
181                                        ExprOrSpread {
182                                            expr: m.obj,
183                                            spread: None,
184                                        },
185                                        ExprOrSpread {
186                                            expr: Box::new(a),
187                                            spread: None,
188                                        },
189                                    ]
190                                    .into_iter()
191                                    .chain(args)
192                                    .collect(),
193                                    type_args: None,
194                                })
195                            }
196                            Expr::Ident(Ident {
197                                span,
198                                ctxt,
199                                sym,
200                                optional,
201                            }) if sym.as_str() == "eval" => Expr::Call(CallExpr {
202                                span,
203                                ctxt,
204                                callee: Callee::Expr(Box::new(Expr::Ident(Ident {
205                                    span,
206                                    ctxt,
207                                    sym,
208                                    optional,
209                                }))),
210                                args,
211                                type_args: None,
212                            }),
213                            mut e => {
214                                e.visit_mut_with(self);
215                                Expr::Call(CallExpr {
216                                    span: e.span(),
217                                    ctxt: Default::default(),
218                                    callee: swc_ecma_ast::Callee::Expr(Box::new(
219                                        match Expr::Ident(self.haven.clone()) {
220                                            c => match c.span() {
221                                                s => Expr::Member(MemberExpr {
222                                                    span: c.span(),
223                                                    obj: Box::new(c),
224                                                    prop: swc_ecma_ast::MemberProp::Ident(
225                                                        IdentName {
226                                                            span: s,
227                                                            sym: Atom::new("call"),
228                                                        },
229                                                    ),
230                                                }),
231                                            },
232                                        },
233                                    )),
234                                    args: [ExprOrSpread {
235                                        expr: Box::new(e),
236                                        spread: None,
237                                    }]
238                                    .into_iter()
239                                    .chain(args)
240                                    .collect(),
241                                    type_args: None,
242                                })
243                            }
244                        }
245                    }
246                    _ => todo!(),
247                }
248            }
249            mut e => {
250                e.visit_mut_children_with(self);
251                *e2 = e;
252                return;
253            }
254        };
255        *e2 = match eb {
256            Some(eb) => Expr::Cond(CondExpr {
257                span: eb.span(),
258                test: Box::new(Expr::OptChain(OptChainExpr {
259                    span: eb.span(),
260                    optional: true,
261                    base: Box::new(swc_ecma_ast::OptChainBase::Member(MemberExpr {
262                        span: eb.span(),
263                        obj: Box::new(Expr::Ident(self.haven.clone())),
264                        prop: swc_ecma_ast::MemberProp::Ident(IdentName {
265                            span: eb.span(),
266                            sym: Atom::new("active"),
267                        }),
268                    })),
269                })),
270                cons: Box::new(Expr::Seq(SeqExpr {
271                    span: eb.span(),
272                    exprs: vec![
273                        Box::new(Expr::Assign(AssignExpr {
274                            span: eb.span(),
275                            op: AssignOp::Assign,
276                            left: AssignTarget::Simple(SimpleAssignTarget::OptChain(
277                                OptChainExpr {
278                                    span: eb.span(),
279                                    optional: true,
280                                    base: Box::new(swc_ecma_ast::OptChainBase::Member(
281                                        (MemberExpr {
282                                            span: eb.span(),
283                                            obj: Box::new(Expr::Ident(self.haven.clone())),
284                                            prop: swc_ecma_ast::MemberProp::Ident(IdentName {
285                                                span: eb.span(),
286                                                sym: Atom::new("active"),
287                                            }),
288                                        }),
289                                    )),
290                                },
291                            )),
292                            right: Box::new(Expr::Lit(Lit::Bool(Bool {
293                                span: eb.span(),
294                                value: false,
295                            }))),
296                        })),
297                        Box::new(f),
298                    ],
299                })),
300                alt: Box::new(eb),
301            }),
302            None => f,
303        };
304    }
305}