swc_ecma_usage_analyzer/
util.rs1use swc_ecma_ast::*;
2
3pub fn is_global_var_with_pure_property_access(s: &str) -> bool {
4 match s {
5 "JSON" | "Array" | "Set" | "Map" | "String" | "Object" | "Number" | "Date" | "BigInt"
6 | "Boolean" | "Math" | "Error" | "Reflect" => return true,
7 _ => {}
8 }
9
10 matches!(
11 s,
12 "console"
13 | "clearInterval"
14 | "clearTimeout"
15 | "setInterval"
16 | "setTimeout"
17 | "setImmediate"
18 | "btoa"
19 | "decodeURI"
20 | "decodeURIComponent"
21 | "encodeURI"
22 | "encodeURIComponent"
23 | "escape"
24 | "eval"
25 | "EvalError"
26 | "Function"
27 | "isFinite"
28 | "isNaN"
29 | "parseFloat"
30 | "parseInt"
31 | "RegExp"
32 | "RangeError"
33 | "ReferenceError"
34 | "SyntaxError"
35 | "TypeError"
36 | "unescape"
37 | "URIError"
38 | "atob"
39 | "globalThis"
40 | "NaN"
41 | "Symbol"
42 | "Promise"
43 | "WeakRef"
44 | "ArrayBuffer"
45 )
46}
47
48pub fn can_end_conditionally(s: &Stmt) -> bool {
49 fn can_end(s: &Stmt, ignore_always: bool) -> bool {
52 match s {
53 Stmt::If(s) => {
54 can_end(&s.cons, false)
55 || s.alt
56 .as_deref()
57 .map(|s| can_end(s, false))
58 .unwrap_or_default()
59 }
60
61 Stmt::Switch(s) => s
62 .cases
63 .iter()
64 .any(|case| case.cons.iter().any(|s| can_end(s, false))),
65
66 Stmt::Try(s) => {
67 s.block.stmts.iter().any(|s| can_end(s, ignore_always))
68 || s.handler
69 .as_ref()
70 .map(|h| h.body.stmts.iter().any(|s| can_end(s, ignore_always)))
71 .unwrap_or_default()
72 || s.finalizer
73 .as_ref()
74 .map(|f| f.stmts.iter().any(|s| can_end(s, ignore_always)))
75 .unwrap_or_default()
76 }
77
78 Stmt::DoWhile(s) => can_end(&s.body, ignore_always),
79
80 Stmt::While(s) => can_end(&s.body, ignore_always),
81
82 Stmt::For(s) => can_end(&s.body, ignore_always),
83
84 Stmt::ForOf(s) => can_end(&s.body, ignore_always),
85
86 Stmt::ForIn(s) => can_end(&s.body, ignore_always),
87
88 Stmt::Return(..) | Stmt::Break(..) | Stmt::Continue(..) => !ignore_always,
89
90 Stmt::Block(s) => s.stmts.iter().any(|s| can_end(s, ignore_always)),
91
92 _ => false,
93 }
94 }
95
96 can_end(s, true)
97}
98
99fn is_object_property_call(call: &CallExpr) -> bool {
101 if let Callee::Expr(callee) = &call.callee {
102 match &**callee {
103 Expr::Member(MemberExpr {
104 obj,
105 prop: MemberProp::Ident(IdentName { sym, .. }),
106 ..
107 }) if *sym == *"defineProperty" && obj.is_ident_ref_to("Object") => {
108 return true;
109 }
110
111 _ => {}
112 }
113 };
114
115 false
116}
117
118pub fn get_mut_object_define_property_name_arg(call: &mut CallExpr) -> Option<&mut Str> {
119 if is_object_property_call(call) {
120 let second_arg: &mut Expr = call.args.get_mut(1).map(|arg| &mut arg.expr)?;
121 second_arg.as_mut_lit().and_then(|lit| lit.as_mut_str())
122 } else {
123 None
124 }
125}
126
127pub fn get_object_define_property_name_arg(call: &CallExpr) -> Option<&Str> {
128 if is_object_property_call(call) {
129 let second_arg: &Expr = call.args.get(1).map(|arg| &arg.expr)?;
130 second_arg.as_lit().and_then(|lit| lit.as_str())
131 } else {
132 None
133 }
134}