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}