1use swc_ecma_ast::*;
2
3pub trait EndsWithAlphaNum {
4 fn ends_with_alpha_num(&self) -> bool;
5}
6
7impl EndsWithAlphaNum for ForHead {
8 fn ends_with_alpha_num(&self) -> bool {
9 match self {
10 ForHead::VarDecl(n) => n.ends_with_alpha_num(),
11 ForHead::Pat(n) => n.ends_with_alpha_num(),
12 ForHead::UsingDecl(n) => n.ends_with_alpha_num(),
13 #[cfg(swc_ast_unknown)]
14 _ => false,
15 }
16 }
17}
18
19impl EndsWithAlphaNum for Pat {
20 fn ends_with_alpha_num(&self) -> bool {
21 match self {
22 Pat::Object(_) | Pat::Array(_) => false,
23 Pat::Rest(p) => p.arg.ends_with_alpha_num(),
24 Pat::Assign(p) => p.right.ends_with_alpha_num(),
25 Pat::Expr(p) => p.ends_with_alpha_num(),
26 _ => true,
27 }
28 }
29}
30
31impl EndsWithAlphaNum for VarDecl {
32 fn ends_with_alpha_num(&self) -> bool {
33 match self.decls.last() {
34 None => true,
35 Some(d) => match d.init.as_deref() {
36 Some(e) => e.ends_with_alpha_num(),
37 None => d.name.ends_with_alpha_num(),
38 },
39 }
40 }
41}
42
43impl EndsWithAlphaNum for UsingDecl {
44 fn ends_with_alpha_num(&self) -> bool {
45 match self.decls.last() {
46 None => true,
47 Some(d) => match d.init.as_deref() {
48 Some(e) => e.ends_with_alpha_num(),
49 None => d.name.ends_with_alpha_num(),
50 },
51 }
52 }
53}
54
55impl EndsWithAlphaNum for Expr {
56 fn ends_with_alpha_num(&self) -> bool {
57 match self {
58 Expr::Array(..)
59 | Expr::Object(..)
60 | Expr::Lit(Lit::Str(..))
61 | Expr::Paren(..)
62 | Expr::Member(MemberExpr {
63 prop: MemberProp::Computed(..),
64 ..
65 })
66 | Expr::Tpl(..)
67 | Expr::TaggedTpl(..)
68 | Expr::Call(..) => false,
69
70 Expr::Unary(n) => n.arg.ends_with_alpha_num(),
71
72 Expr::Update(n) => n.prefix && n.arg.ends_with_alpha_num(),
73
74 Expr::OptChain(n) => match n.base.as_ref() {
75 OptChainBase::Member(base) => !base.prop.is_computed(),
76 OptChainBase::Call(_) => false,
77 #[cfg(swc_ast_unknown)]
78 _ => false,
79 },
80
81 Expr::Bin(n) => n.right.ends_with_alpha_num(),
82
83 Expr::New(NewExpr {
84 args: Some(args), ..
85 }) => args.is_empty(),
86
87 _ => true,
88 }
89 }
90}
91
92pub trait StartsWithAlphaNum {
94 fn starts_with_alpha_num(&self) -> bool;
95}
96
97macro_rules! alpha_num_enum {
98 ($T:ty, [$($name:ident),*]) => {
99 impl StartsWithAlphaNum for $T {
100 #[inline]
101 fn starts_with_alpha_num(&self) -> bool {
102 match *self {
103 $(
104 Self::$name(ref n) => n.starts_with_alpha_num(),
105 )*
106 #[cfg(swc_ast_unknown)]
107 _ => false,
108 }
109 }
110 }
111 };
112}
113
114macro_rules! alpha_num_const {
115 ($value:tt, $($ty:ident),*) => {
116 $(
117 impl StartsWithAlphaNum for $ty {
118 #[inline]
119 fn starts_with_alpha_num(&self) -> bool {
120 $value
121 }
122 }
123 )*
124 };
125}
126
127alpha_num_const!(true, BindingIdent, Ident, SuperPropExpr, TsTypeAssertion);
128alpha_num_const!(false, ArrayPat, ObjectPat, Invalid, ParenExpr);
129
130impl StartsWithAlphaNum for MemberExpr {
131 #[inline]
132 fn starts_with_alpha_num(&self) -> bool {
133 self.obj.starts_with_alpha_num()
134 }
135}
136
137impl StartsWithAlphaNum for TsAsExpr {
138 #[inline]
139 fn starts_with_alpha_num(&self) -> bool {
140 self.expr.starts_with_alpha_num()
141 }
142}
143
144impl StartsWithAlphaNum for TsSatisfiesExpr {
145 #[inline]
146 fn starts_with_alpha_num(&self) -> bool {
147 self.expr.starts_with_alpha_num()
148 }
149}
150
151impl StartsWithAlphaNum for TsNonNullExpr {
152 #[inline]
153 fn starts_with_alpha_num(&self) -> bool {
154 self.expr.starts_with_alpha_num()
155 }
156}
157
158impl StartsWithAlphaNum for TsInstantiation {
159 #[inline]
160 fn starts_with_alpha_num(&self) -> bool {
161 self.expr.starts_with_alpha_num()
162 }
163}
164
165impl StartsWithAlphaNum for PropName {
166 #[inline]
167 fn starts_with_alpha_num(&self) -> bool {
168 match self {
169 PropName::Str(_) | PropName::Computed(_) => false,
170 PropName::Ident(_) | PropName::Num(_) | PropName::BigInt(_) => true,
171 #[cfg(swc_ast_unknown)]
172 _ => false,
173 }
174 }
175}
176
177impl StartsWithAlphaNum for Expr {
178 fn starts_with_alpha_num(&self) -> bool {
179 match self {
180 Expr::Ident(_)
181 | Expr::Lit(Lit::Bool(_))
182 | Expr::Lit(Lit::Num(_))
183 | Expr::Lit(Lit::Null(_))
184 | Expr::Lit(Lit::BigInt(_))
185 | Expr::Await(_)
186 | Expr::Fn(_)
187 | Expr::Class(_)
188 | Expr::This(_)
189 | Expr::Yield(_)
190 | Expr::New(_)
191 | Expr::MetaProp(_)
192 | Expr::SuperProp(_) => true,
193
194 Expr::PrivateName(_) => false,
195
196 Expr::Lit(_) => false,
198
199 Expr::Seq(SeqExpr { ref exprs, .. }) => exprs
200 .first()
201 .map(|e| e.starts_with_alpha_num())
202 .unwrap_or(false),
203
204 Expr::Assign(AssignExpr { ref left, .. }) => left.starts_with_alpha_num(),
206
207 Expr::Bin(BinExpr { ref left, .. }) | Expr::Cond(CondExpr { test: ref left, .. }) => {
208 left.starts_with_alpha_num()
209 }
210 Expr::Call(CallExpr { callee: left, .. }) => left.starts_with_alpha_num(),
211 Expr::Member(MemberExpr { obj: ref left, .. }) => left.starts_with_alpha_num(),
212
213 Expr::Unary(UnaryExpr { op, .. }) => {
214 matches!(op, op!("void") | op!("delete") | op!("typeof"))
215 }
216
217 Expr::Arrow(ref expr) => {
218 if expr.is_async {
219 true
220 } else {
221 match expr.params.as_slice() {
222 [p] => p.starts_with_alpha_num(),
223 _ => false,
224 }
225 }
226 }
227
228 Expr::Update(ref expr) => {
229 if expr.prefix {
230 false
231 } else {
232 expr.arg.starts_with_alpha_num()
233 }
234 }
235
236 Expr::Tpl(_) | Expr::Array(_) | Expr::Object(_) | Expr::Paren(_) => false,
237
238 Expr::TaggedTpl(TaggedTpl { ref tag, .. }) => tag.starts_with_alpha_num(),
239
240 Expr::JSXEmpty(..) => false,
242 Expr::JSXFragment(..) | Expr::JSXElement(..) => false,
244 Expr::JSXNamespacedName(..) => true,
245 Expr::JSXMember(..) => true,
246
247 Expr::TsTypeAssertion(..) => false,
248 Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
249 | Expr::TsAs(TsAsExpr { ref expr, .. })
250 | Expr::TsConstAssertion(TsConstAssertion { ref expr, .. })
251 | Expr::TsInstantiation(TsInstantiation { ref expr, .. })
252 | Expr::TsSatisfies(TsSatisfiesExpr { ref expr, .. }) => expr.starts_with_alpha_num(),
253
254 Expr::OptChain(e) => e.starts_with_alpha_num(),
255
256 Expr::Invalid(..) => true,
257 #[cfg(swc_ast_unknown)]
258 _ => false,
259 }
260 }
261}
262
263impl StartsWithAlphaNum for OptChainExpr {
264 fn starts_with_alpha_num(&self) -> bool {
265 match &*self.base {
266 OptChainBase::Member(base) => base.obj.starts_with_alpha_num(),
267 OptChainBase::Call(base) => base.callee.starts_with_alpha_num(),
268 #[cfg(swc_ast_unknown)]
269 _ => false,
270 }
271 }
272}
273
274impl StartsWithAlphaNum for Pat {
275 fn starts_with_alpha_num(&self) -> bool {
276 match *self {
277 Pat::Ident(..) => true,
278 Pat::Assign(AssignPat { ref left, .. }) => left.starts_with_alpha_num(),
279 Pat::Object(..) | Pat::Array(..) | Pat::Rest(..) => false,
280 Pat::Expr(ref expr) => expr.starts_with_alpha_num(),
281 Pat::Invalid(..) => true,
282 #[cfg(swc_ast_unknown)]
283 _ => false,
284 }
285 }
286}
287
288alpha_num_enum!(AssignTarget, [Pat, Simple]);
289alpha_num_enum!(
290 SimpleAssignTarget,
291 [
292 Ident,
293 Member,
294 SuperProp,
295 OptChain,
296 Paren,
297 TsAs,
298 TsSatisfies,
299 TsNonNull,
300 TsTypeAssertion,
301 TsInstantiation,
302 Invalid
303 ]
304);
305alpha_num_enum!(AssignTargetPat, [Array, Object, Invalid]);
306
307impl StartsWithAlphaNum for ExprOrSpread {
308 fn starts_with_alpha_num(&self) -> bool {
309 match *self {
310 ExprOrSpread {
311 spread: Some(_), ..
312 } => false,
313 ExprOrSpread {
314 spread: None,
315 ref expr,
316 } => expr.starts_with_alpha_num(),
317 }
318 }
319}
320impl StartsWithAlphaNum for Callee {
321 fn starts_with_alpha_num(&self) -> bool {
322 match *self {
323 Callee::Super(_) | Callee::Import(_) => true,
324 Callee::Expr(ref e) => e.starts_with_alpha_num(),
325 #[cfg(swc_ast_unknown)]
326 _ => false,
327 }
328 }
329}
330impl StartsWithAlphaNum for Stmt {
331 fn starts_with_alpha_num(&self) -> bool {
332 match *self {
333 Stmt::Expr(ref expr) => expr.expr.starts_with_alpha_num(),
334 Stmt::Decl(ref decl) => decl.starts_with_alpha_num(),
335 Stmt::Debugger(..)
336 | Stmt::With(..)
337 | Stmt::While(..)
338 | Stmt::DoWhile(..)
339 | Stmt::Return(..)
340 | Stmt::Labeled(..)
341 | Stmt::Break(..)
342 | Stmt::Continue(..)
343 | Stmt::Switch(..)
344 | Stmt::Throw(..)
345 | Stmt::Try(..)
346 | Stmt::For(..)
347 | Stmt::ForIn(..)
348 | Stmt::ForOf(..)
349 | Stmt::If(..) => true,
350 Stmt::Block(..) | Stmt::Empty(..) => false,
351 #[cfg(swc_ast_unknown)]
352 _ => false,
353 }
354 }
355}
356
357impl StartsWithAlphaNum for Decl {
358 fn starts_with_alpha_num(&self) -> bool {
359 match *self {
360 Decl::Class(..)
361 | Decl::Fn(..)
362 | Decl::Var(..)
363 | Decl::TsEnum(..)
364 | Decl::TsInterface(..)
365 | Decl::TsModule(..)
366 | Decl::TsTypeAlias(..)
367 | Decl::Using(..) => true,
368 #[cfg(swc_ast_unknown)]
369 _ => false,
370 }
371 }
372}