1use num_bigint::{BigInt as BigIntValue, Sign};
2use swc_common::SyntaxContext;
3use swc_ecma_ast::*;
4
5pub trait Size {
7 fn size(&self) -> usize;
8}
9
10impl Size for Lit {
11 fn size(&self) -> usize {
12 match self {
13 Lit::Str(s) => s.value.len() + 2,
14 Lit::Bool(_) => 2,
16 Lit::Null(_) => 4,
17 Lit::Num(num) => num.value.size(),
18 Lit::BigInt(i) => i.value.size(),
19 Lit::Regex(r) => r.exp.len(),
20 Lit::JSXText(s) => s.value.len(),
21 #[cfg(swc_ast_unknown)]
22 _ => TODO,
23 }
24 }
25}
26
27impl Size for UnaryOp {
28 fn size(&self) -> usize {
29 use UnaryOp::*;
30 match self {
31 Minus | Plus | Bang | Tilde => 1,
32 TypeOf => 7,
33 Void => 5,
34 Delete => 7,
35 #[cfg(swc_ast_unknown)]
36 _ => TODO,
37 }
38 }
39}
40
41impl Size for UpdateOp {
42 fn size(&self) -> usize {
43 2
44 }
45}
46
47impl Size for BinaryOp {
48 fn size(&self) -> usize {
49 use BinaryOp::*;
50 match self {
51 Lt | Gt | Add | Sub | Mul | Div | Mod | BitOr | BitXor | BitAnd | EqEq | NotEq
52 | LtEq | GtEq | LShift | RShift | LogicalOr | LogicalAnd | Exp | NullishCoalescing
53 | EqEqEq | NotEqEq | ZeroFillRShift => self.as_str().len(),
54
55 In => 4,
56 InstanceOf => 12,
57 #[cfg(swc_ast_unknown)]
58 _ => TODO,
59 }
60 }
61}
62
63impl Size for AssignOp {
64 fn size(&self) -> usize {
65 self.as_str().len()
66 }
67}
68
69impl Size for PrivateName {
70 fn size(&self) -> usize {
71 2
73 }
74}
75
76impl Size for f64 {
78 fn size(&self) -> usize {
79 if self.fract() == 0.0 {
80 self.log10().ceil() as usize + 1
81 } else {
82 self.to_string().len()
83 }
84 }
85}
86
87#[allow(clippy::bool_to_int_with_if)]
88impl Size for BigIntValue {
89 fn size(&self) -> usize {
90 let sign = if let Sign::Minus = self.sign() { 1 } else { 0 };
91 let value = ((self.bits() as f64) / 10.0_f64.log2()).ceil() as usize + 1;
94 sign + value + 1 }
96}
97
98pub trait SizeWithCtxt {
100 fn size(&self, unresolved: SyntaxContext) -> usize;
101}
102
103const TODO: usize = 10000;
104
105impl SizeWithCtxt for Expr {
106 fn size(&self, unresolved: SyntaxContext) -> usize {
107 match self {
108 Expr::Lit(lit) => lit.size(),
109 Expr::Ident(id) => id.size(unresolved),
110
111 Expr::Bin(BinExpr {
112 op, left, right, ..
113 }) => op.size() + left.size(unresolved) + right.size(unresolved),
114
115 Expr::Unary(UnaryExpr { arg, op, .. }) => op.size() + arg.size(unresolved),
116
117 Expr::Call(CallExpr { callee, args, .. }) => {
118 callee.size(unresolved) + args.size(unresolved) + 2
119 }
120
121 Expr::New(NewExpr { callee, args, .. }) => {
122 args.as_ref().map_or(0, |args| args.size(unresolved) + 2)
123 + 4
124 + callee.size(unresolved)
125 }
126
127 Expr::Member(m) => m.obj.size(unresolved) + m.prop.size(unresolved),
128 Expr::SuperProp(s) => 6 + s.prop.size(unresolved),
129 Expr::Update(e) => e.arg.size(unresolved) + e.op.size(),
130
131 Expr::Assign(AssignExpr {
132 op, left, right, ..
133 }) => left.size(unresolved) + op.size() + right.size(unresolved),
134
135 Expr::Seq(e) => {
136 e.exprs
137 .iter()
138 .map(|v| v.size(unresolved) + 1)
139 .sum::<usize>()
140 - 1
141 }
142
143 Expr::This(_) => 4,
144 Expr::Array(a) => 2 + a.elems.size(unresolved),
145 Expr::Object(o) => 2 + o.props.size(unresolved),
146
147 Expr::Yield(YieldExpr { arg, delegate, .. }) => {
148 6 + *delegate as usize + arg.as_ref().map_or(0, |a| a.size(unresolved))
149 }
150 Expr::Await(a) => 6 + a.arg.size(unresolved),
151 Expr::Cond(CondExpr {
152 test, cons, alt, ..
153 }) => test.size(unresolved) + 1 + cons.size(unresolved) + 1 + alt.size(unresolved),
154 Expr::Tpl(t) => t.size(unresolved),
155 Expr::TaggedTpl(t) => t.tag.size(unresolved) + t.tpl.size(unresolved),
156
157 Expr::Arrow(ArrowExpr {
158 params,
159 body,
160 is_async,
161 ..
162 }) => match &**body {
163 BlockStmtOrExpr::BlockStmt(_) => TODO,
164 BlockStmtOrExpr::Expr(e) => {
165 let p = match ¶ms[..] {
166 [] => 2,
167 [Pat::Ident(_)] => 1,
168 _ => 2 + params.size(unresolved),
169 };
170 let a = if *is_async {
171 5 + usize::from(params.len() != 1)
172 } else {
173 0
174 };
175
176 p + a + 2 + e.size(unresolved)
177 }
178 #[cfg(swc_ast_unknown)]
179 _ => TODO,
180 },
181 Expr::Fn(_) => TODO,
182 Expr::Class(_) => TODO,
183
184 Expr::MetaProp(m) => match m.kind {
185 MetaPropKind::NewTarget => 10,
186 MetaPropKind::ImportMeta => 11,
187 #[cfg(swc_ast_unknown)]
188 _ => TODO,
189 },
190 Expr::PrivateName(p) => p.size(),
191 Expr::OptChain(p) => match &*p.base {
192 OptChainBase::Member(m) => 1 + m.obj.size(unresolved) + m.prop.size(unresolved),
193 OptChainBase::Call(c) => {
194 1 + c.callee.size(unresolved) + c.args.size(unresolved) + 2
195 }
196 #[cfg(swc_ast_unknown)]
197 _ => TODO,
198 },
199
200 Expr::Paren(p) => 2 + p.expr.size(unresolved),
201 Expr::Invalid(_) => 0,
202
203 Expr::JSXMember(_) => TODO,
204 Expr::JSXNamespacedName(_) => TODO,
205 Expr::JSXEmpty(_) => TODO,
206 Expr::JSXElement(_) => TODO,
207 Expr::JSXFragment(_) => TODO,
208 Expr::TsTypeAssertion(_) => TODO,
209 Expr::TsConstAssertion(_) => TODO,
210 Expr::TsNonNull(_) => TODO,
211 Expr::TsAs(_) => TODO,
212 Expr::TsInstantiation(_) => TODO,
213 Expr::TsSatisfies(_) => TODO,
214 #[cfg(swc_ast_unknown)]
215 _ => TODO,
216 }
217 }
218}
219
220impl SizeWithCtxt for Ident {
221 fn size(&self, unresolved: SyntaxContext) -> usize {
222 if self.ctxt == unresolved {
223 self.sym.len()
224 } else {
225 1
226 }
227 }
228}
229
230impl SizeWithCtxt for Callee {
231 fn size(&self, unresolved: SyntaxContext) -> usize {
232 match self {
233 Callee::Super(_) => 5,
234 Callee::Import(_) => 6,
235 Callee::Expr(e) => e.size(unresolved),
236 #[cfg(swc_ast_unknown)]
237 _ => TODO,
238 }
239 }
240}
241
242impl SizeWithCtxt for ExprOrSpread {
243 fn size(&self, unresolved: SyntaxContext) -> usize {
244 let mut c = 0;
245
246 if self.spread.is_some() {
247 c += 3;
248 }
249
250 c += self.expr.size(unresolved);
251
252 c
253 }
254}
255
256impl SizeWithCtxt for MemberProp {
257 fn size(&self, unresolved: SyntaxContext) -> usize {
258 match self {
259 MemberProp::Ident(id) => 1 + id.sym.len(),
260 MemberProp::PrivateName(priv_name) => 1 + priv_name.size(),
261 MemberProp::Computed(c) => 2 + c.expr.size(unresolved),
262 #[cfg(swc_ast_unknown)]
263 _ => TODO,
264 }
265 }
266}
267
268impl SizeWithCtxt for SuperProp {
269 fn size(&self, unresolved: SyntaxContext) -> usize {
270 match self {
271 SuperProp::Ident(id) => 1 + id.sym.len(),
272 SuperProp::Computed(c) => 2 + c.expr.size(unresolved),
273 #[cfg(swc_ast_unknown)]
274 _ => TODO,
275 }
276 }
277}
278
279impl SizeWithCtxt for Pat {
280 fn size(&self, unresolved: SyntaxContext) -> usize {
281 match self {
282 Pat::Ident(id) => id.size(unresolved),
283 Pat::Array(a) => 2 + a.elems.size(unresolved),
284 Pat::Rest(r) => 3 + r.arg.size(unresolved),
285 Pat::Object(o) => 2 + o.props.size(unresolved),
286 Pat::Assign(a) => a.left.size(unresolved) + 1 + a.right.size(unresolved),
287 Pat::Invalid(_) => 0,
288 Pat::Expr(e) => e.size(unresolved),
289 #[cfg(swc_ast_unknown)]
290 _ => TODO,
291 }
292 }
293}
294
295impl SizeWithCtxt for AssignTarget {
296 fn size(&self, unresolved: SyntaxContext) -> usize {
297 match self {
298 AssignTarget::Simple(e) => e.size(unresolved),
299 AssignTarget::Pat(p) => p.size(unresolved),
300 #[cfg(swc_ast_unknown)]
301 _ => TODO,
302 }
303 }
304}
305
306impl SizeWithCtxt for SimpleAssignTarget {
307 fn size(&self, unresolved: SyntaxContext) -> usize {
308 match self {
309 SimpleAssignTarget::Ident(e) => {
310 if e.ctxt == unresolved {
311 e.sym.len()
312 } else {
313 1
314 }
315 }
316 SimpleAssignTarget::Member(e) => e.obj.size(unresolved) + e.prop.size(unresolved),
317 SimpleAssignTarget::SuperProp(e) => 6 + e.prop.size(unresolved),
318 SimpleAssignTarget::Paren(e) => 2 + e.expr.size(unresolved),
319 SimpleAssignTarget::OptChain(e) => match &*e.base {
320 OptChainBase::Member(m) => 1 + m.obj.size(unresolved) + m.prop.size(unresolved),
321 OptChainBase::Call(c) => {
322 1 + c.callee.size(unresolved) + c.args.size(unresolved) + 2
323 }
324 #[cfg(swc_ast_unknown)]
325 _ => TODO,
326 },
327 SimpleAssignTarget::TsAs(_)
328 | SimpleAssignTarget::TsSatisfies(_)
329 | SimpleAssignTarget::TsNonNull(_)
330 | SimpleAssignTarget::TsTypeAssertion(_)
331 | SimpleAssignTarget::TsInstantiation(_)
332 | SimpleAssignTarget::Invalid(_) => TODO,
333 #[cfg(swc_ast_unknown)]
334 _ => TODO,
335 }
336 }
337}
338
339impl SizeWithCtxt for AssignTargetPat {
340 fn size(&self, unresolved: SyntaxContext) -> usize {
341 match self {
342 AssignTargetPat::Array(a) => 2 + a.elems.size(unresolved),
343 AssignTargetPat::Object(o) => 2 + o.props.size(unresolved),
344 AssignTargetPat::Invalid(_) => unreachable!(),
345 #[cfg(swc_ast_unknown)]
346 _ => TODO,
347 }
348 }
349}
350
351impl SizeWithCtxt for PropName {
352 fn size(&self, unresolved: SyntaxContext) -> usize {
353 match self {
354 PropName::Ident(id) => id.sym.len(),
355 PropName::Str(s) => s.value.len(),
356 PropName::Num(n) => n.value.size(),
357 PropName::Computed(c) => 2 + c.expr.size(unresolved),
358 PropName::BigInt(n) => n.value.size(),
359 #[cfg(swc_ast_unknown)]
360 _ => TODO,
361 }
362 }
363}
364
365impl SizeWithCtxt for ObjectPatProp {
366 fn size(&self, unresolved: SyntaxContext) -> usize {
367 match self {
368 ObjectPatProp::KeyValue(k) => k.key.size(unresolved) + 1 + k.value.size(unresolved),
369 ObjectPatProp::Assign(a) => {
370 a.key.sym.len() + a.value.as_ref().map_or(0, |v| v.size(unresolved) + 1)
371 }
372 ObjectPatProp::Rest(r) => 3 + r.arg.size(unresolved),
373 #[cfg(swc_ast_unknown)]
374 _ => TODO,
375 }
376 }
377}
378
379impl SizeWithCtxt for PropOrSpread {
380 fn size(&self, unresolved: SyntaxContext) -> usize {
381 match self {
382 PropOrSpread::Spread(s) => 3 + s.expr.size(unresolved),
383 PropOrSpread::Prop(p) => match &**p {
384 Prop::Shorthand(s) => s.sym.len(),
385 Prop::KeyValue(KeyValueProp { key, value }) => {
386 key.size(unresolved) + 1 + value.size(unresolved)
387 }
388 Prop::Assign(_) => TODO,
390 Prop::Getter(_) => TODO,
391 Prop::Setter(_) => TODO,
392 Prop::Method(_) => TODO,
393 #[cfg(swc_ast_unknown)]
394 _ => TODO,
395 },
396 #[cfg(swc_ast_unknown)]
397 _ => TODO,
398 }
399 }
400}
401
402impl SizeWithCtxt for Tpl {
403 fn size(&self, unresolved: SyntaxContext) -> usize {
404 let Self { exprs, quasis, .. } = self;
405 let expr_len: usize = exprs.iter().map(|e| e.size(unresolved) + 3).sum();
406 let str_len: usize = quasis.iter().map(|q| q.raw.len()).sum();
407 2 + expr_len + str_len
408 }
409}
410
411impl<T: SizeWithCtxt> SizeWithCtxt for Vec<T> {
412 fn size(&self, unresolved: SyntaxContext) -> usize {
413 let mut c = 0;
414
415 for item in self.iter() {
416 c += item.size(unresolved) + 1; }
418
419 if !self.is_empty() {
420 c -= 1;
421 }
422
423 c
424 }
425}
426
427impl<T: SizeWithCtxt> SizeWithCtxt for Vec<Option<T>> {
428 fn size(&self, unresolved: SyntaxContext) -> usize {
429 let mut c = 0;
430
431 for item in self.iter() {
432 c += 1; if let Some(item) = item {
434 c += item.size(unresolved); }
436 }
437
438 c -= match self.last() {
439 None | Some(None) => 0,
441 _ => 1,
442 };
443
444 c
445 }
446}