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