1use swc_atoms::Atom;
4use swc_experimental_ecma_ast::{
5 BlockStmt, BreakStmt, Class, ClassDecl, ClassExpr, ContinueStmt, DebuggerStmt, Decl, DoWhileStmt,
6 EmptyStmt, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr, ExportSpecifier, Expr,
7 ExprStmt, FnDecl, FnExpr, ForInStmt, ForOfStmt, ForStmt, Function, GetSpan, Ident, IfStmt,
8 LabeledStmt, ModuleExportName, NamedExport, ObjectLit, ReturnStmt, Span, Stmt, SwitchStmt,
9 ThrowStmt, TryStmt, UsingDecl, VarDecl, VarDeclKind, VarDeclarator, WhileStmt, WithStmt,
10};
11
12use crate::JS_DEFAULT_KEYWORD;
13
14fn wtf8_atom_to_atom(value: swc_experimental_allocator::atom::Wtf8Atom<'_>) -> Atom {
15 Atom::from(value.as_wtf8().to_string_lossy().as_ref())
16}
17
18#[derive(Debug, Clone, Copy)]
19pub enum ClassDeclOrExpr<'ast> {
20 Decl(MaybeNamedClassDecl<'ast>),
21 Expr(&'ast ClassExpr<'ast>),
22}
23
24impl ClassDeclOrExpr<'_> {
25 pub fn span(&self) -> Span {
26 match self {
27 ClassDeclOrExpr::Decl(decl) => decl.span(),
28 ClassDeclOrExpr::Expr(expr) => expr.span(),
29 }
30 }
31}
32
33impl ClassDeclOrExpr<'_> {
34 pub fn ident(&self) -> Option<&Ident<'_>> {
35 match self {
36 ClassDeclOrExpr::Decl(decl) => decl.ident,
37 ClassDeclOrExpr::Expr(expr) => expr.ident.as_deref(),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Copy)]
43pub enum ExportAllDeclaration<'ast> {
44 All(&'ast ExportAll<'ast>),
46 NamedAll(&'ast NamedExport<'ast>),
48}
49
50impl ExportAllDeclaration<'_> {
51 pub fn span(&self) -> Span {
52 match self {
53 ExportAllDeclaration::All(all) => all.span(),
54 ExportAllDeclaration::NamedAll(all) => all.span(),
55 }
56 }
57}
58
59impl ExportAllDeclaration<'_> {
60 pub fn source(&self) -> Atom {
61 match self {
62 ExportAllDeclaration::All(e) => wtf8_atom_to_atom(e.src.value),
63 ExportAllDeclaration::NamedAll(e) => wtf8_atom_to_atom(
64 e.src
65 .as_ref()
66 .expect("ExportAllDeclaration::NamedAll (export * as x from 'm') must have src")
67 .value,
68 ),
69 }
70 }
71
72 pub fn source_span(&self) -> Span {
73 match self {
74 ExportAllDeclaration::All(all) => all.src.span(),
75 ExportAllDeclaration::NamedAll(all) => all
76 .src
77 .as_ref()
78 .expect("ExportAllDeclaration::NamedAll (export * as x from 'm') must have src")
79 .span(),
80 }
81 }
82
83 pub fn exported_name_span(&self) -> Option<Span> {
84 match self {
85 ExportAllDeclaration::All(_) => None,
86 ExportAllDeclaration::NamedAll(e) => Some(
87 e.specifiers
88 .first()
89 .and_then(|e| e.as_namespace())
90 .map(|e| e.name.span())
91 .expect("ExportAllDeclaration::NamedAll (export * as x from 'm') must one specifier"),
92 ),
93 }
94 }
95
96 pub fn exported_name(&self) -> Option<Atom> {
97 match self {
98 ExportAllDeclaration::All(_) => None,
99 ExportAllDeclaration::NamedAll(e) => Some(
100 e.specifiers
101 .first()
102 .and_then(|e| e.as_namespace())
103 .map(|e| module_export_name_to_atom(&e.name))
104 .expect("ExportAllDeclaration::NamedAll (export * as x from 'm') must one specifier"),
105 ),
106 }
107 }
108
109 pub fn get_with_obj(&self) -> Option<&ObjectLit<'_>> {
110 match self {
111 ExportAllDeclaration::All(e) => e.with.as_deref(),
112 ExportAllDeclaration::NamedAll(e) => e.with.as_deref(),
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
118pub enum ExportNamedDeclaration<'ast> {
119 Decl(&'ast ExportDecl<'ast>),
122 Specifiers(&'ast NamedExport<'ast>),
125}
126
127impl ExportNamedDeclaration<'_> {
128 pub fn span(&self) -> Span {
129 match self {
130 ExportNamedDeclaration::Decl(decl) => decl.span(),
131 ExportNamedDeclaration::Specifiers(export) => export.span(),
132 }
133 }
134}
135
136impl ExportNamedDeclaration<'_> {
137 pub fn source(&self) -> Option<Atom> {
138 match self {
139 Self::Decl(_) => None,
140 Self::Specifiers(e) => e.src.as_ref().map(|s| wtf8_atom_to_atom(s.value)),
141 }
142 }
143
144 pub fn source_span(&self) -> Option<Span> {
145 match self {
146 ExportNamedDeclaration::Decl(_) => None,
147 ExportNamedDeclaration::Specifiers(e) => e.src.as_ref().map(|s| s.span()),
148 }
149 }
150
151 pub fn declaration_span(&self) -> Option<Span> {
152 match self {
153 ExportNamedDeclaration::Decl(decl) => Some(decl.decl.span()),
154 ExportNamedDeclaration::Specifiers(_) => None,
155 }
156 }
157
158 pub fn get_with_obj(&self) -> Option<&ObjectLit<'_>> {
159 match self {
160 ExportNamedDeclaration::Decl(_) => None,
161 ExportNamedDeclaration::Specifiers(e) => e.with.as_deref(),
162 }
163 }
164
165 pub fn named_export_specifiers<'a>(
166 named: &'a NamedExport<'a>,
167 ) -> impl Iterator<Item = (Atom, Atom, Span)> + use<'a> {
168 named.specifiers.iter().map(|spec| {
169 match spec {
170 ExportSpecifier::Namespace(_) => unreachable!("should handle ExportSpecifier::Namespace by ExportAllOrNamedAll::NamedAll in block_pre_walk_export_all_declaration"),
171 ExportSpecifier::Default(s) => {
172 (
173 JS_DEFAULT_KEYWORD.clone(),
174 Atom::from(s.exported.sym.as_str()),
175 s.exported.span(),
176 )
177 },
178 ExportSpecifier::Named(n) => {
179 let exported_name = n.exported.as_ref().unwrap_or(&n.orig);
180 (
181 module_export_name_to_atom(&n.orig),
182 module_export_name_to_atom(exported_name),
183 exported_name.span(),
184 )
185 },
186 }
187 })
188 }
189}
190
191#[derive(Debug, Clone, Copy)]
192pub enum ExportDefaultDeclaration<'ast> {
193 Decl(&'ast ExportDefaultDecl<'ast>),
198 Expr(&'ast ExportDefaultExpr<'ast>),
201}
202
203impl ExportDefaultDeclaration<'_> {
204 pub fn span(&self) -> Span {
205 match self {
206 ExportDefaultDeclaration::Decl(decl) => decl.span(),
207 ExportDefaultDeclaration::Expr(expr) => expr.span(),
208 }
209 }
210}
211
212impl ExportDefaultDeclaration<'_> {
213 fn declaration_span(&self) -> Span {
214 match self {
215 ExportDefaultDeclaration::Decl(decl) => decl.decl.span(),
216 ExportDefaultDeclaration::Expr(expr) => expr.expr.span(),
217 }
218 }
219}
220
221#[derive(Debug, Clone, Copy)]
222pub enum ExportDefaultExpression<'ast> {
223 FnDecl(&'ast FnExpr<'ast>),
225 ClassDecl(&'ast ClassExpr<'ast>),
227 Expr(&'ast Expr<'ast>),
230}
231
232impl ExportDefaultExpression<'_> {
233 pub fn span(&self) -> Span {
234 match self {
235 ExportDefaultExpression::FnDecl(f) => f.span(),
236 ExportDefaultExpression::ClassDecl(c) => c.span(),
237 ExportDefaultExpression::Expr(e) => e.span(),
238 }
239 }
240}
241
242impl ExportDefaultExpression<'_> {
243 pub fn ident(&self) -> Option<Atom> {
244 match self {
245 ExportDefaultExpression::FnDecl(f) => {
246 f.ident.as_ref().map(|ident| Atom::from(ident.sym.as_str()))
247 }
248 ExportDefaultExpression::ClassDecl(c) => {
249 c.ident.as_ref().map(|ident| Atom::from(ident.sym.as_str()))
250 }
251 ExportDefaultExpression::Expr(_) => None,
252 }
253 }
254}
255
256#[derive(Debug, Clone, Copy)]
257pub enum ExportImport<'ast> {
258 All(ExportAllDeclaration<'ast>),
259 Named(ExportNamedDeclaration<'ast>),
260}
261
262impl ExportImport<'_> {
263 pub fn span(&self) -> Span {
264 match self {
265 ExportImport::All(all) => all.span(),
266 ExportImport::Named(named) => named.span(),
267 }
268 }
269}
270
271impl ExportImport<'_> {
272 pub fn source(&self) -> Atom {
273 match self {
274 ExportImport::All(e) => e.source(),
275 ExportImport::Named(e) => e
276 .source()
277 .expect("ExportImport::Named (export { x } from 'm') should have src"),
278 }
279 }
280
281 pub fn source_span(&self) -> Span {
282 match self {
283 ExportImport::All(all) => all.source_span(),
284 ExportImport::Named(named) => named
285 .source_span()
286 .expect("ExportImport::Named (export { x } from 'm') should have src"),
287 }
288 }
289
290 pub fn get_with_obj(&self) -> Option<&ObjectLit<'_>> {
291 match self {
292 ExportImport::All(e) => e.get_with_obj(),
293 ExportImport::Named(e) => e.get_with_obj(),
294 }
295 }
296
297 pub fn is_star_export(&self) -> bool {
298 matches!(self, ExportImport::All(ExportAllDeclaration::All(_)))
299 }
300}
301
302#[derive(Debug, Clone, Copy)]
303pub enum ExportLocal<'ast> {
304 Named(ExportNamedDeclaration<'ast>),
305 Default(ExportDefaultDeclaration<'ast>),
306}
307
308impl ExportLocal<'_> {
309 pub fn span(&self) -> Span {
310 match self {
311 ExportLocal::Named(decl) => decl.span(),
312 ExportLocal::Default(decl) => decl.span(),
313 }
314 }
315}
316
317impl ExportLocal<'_> {
318 pub fn declaration_span(&self) -> Option<Span> {
319 match self {
320 ExportLocal::Named(named) => named.declaration_span(),
321 ExportLocal::Default(default) => Some(default.declaration_span()),
322 }
323 }
324}
325
326#[derive(Debug, Clone, Copy)]
327pub struct MaybeNamedFunctionDecl<'ast> {
328 span: Span,
329 ident: Option<&'ast Ident<'ast>>,
330 function: &'ast Function<'ast>,
331}
332
333impl MaybeNamedFunctionDecl<'_> {
334 pub fn span(&self) -> Span {
335 self.span
336 }
337}
338
339impl<'ast> From<&'ast FnDecl<'ast>> for MaybeNamedFunctionDecl<'ast> {
340 fn from(value: &'ast FnDecl<'ast>) -> Self {
341 Self {
342 span: value.span(),
343 ident: Some(&value.ident),
344 function: &value.function,
345 }
346 }
347}
348
349impl<'ast> From<&'ast FnExpr<'ast>> for MaybeNamedFunctionDecl<'ast> {
350 fn from(f: &'ast FnExpr<'ast>) -> Self {
351 Self {
352 span: f.span(),
353 ident: f.ident.as_deref(),
354 function: &f.function,
355 }
356 }
357}
358
359impl<'ast> MaybeNamedFunctionDecl<'ast> {
360 pub fn ident(&self) -> Option<&'ast Ident<'ast>> {
361 self.ident
362 }
363
364 pub fn function(&self) -> &'ast Function<'ast> {
365 self.function
366 }
367}
368
369#[derive(Debug, Clone, Copy)]
370pub struct MaybeNamedClassDecl<'ast> {
371 span: Span,
372 ident: Option<&'ast Ident<'ast>>,
373 class: &'ast Class<'ast>,
374}
375
376impl MaybeNamedClassDecl<'_> {
377 pub fn span(&self) -> Span {
378 self.span
379 }
380}
381
382impl<'ast> From<&'ast ClassDecl<'ast>> for MaybeNamedClassDecl<'ast> {
383 fn from(value: &'ast ClassDecl<'ast>) -> Self {
384 Self {
385 span: value.span(),
386 ident: Some(&value.ident),
387 class: &value.class,
388 }
389 }
390}
391
392impl<'ast> From<&'ast ClassExpr<'ast>> for MaybeNamedClassDecl<'ast> {
393 fn from(value: &'ast ClassExpr<'ast>) -> Self {
394 Self {
395 span: value.span(),
396 ident: value.ident.as_deref(),
397 class: &value.class,
398 }
399 }
400}
401
402impl MaybeNamedClassDecl<'_> {
403 pub fn ident(&self) -> Option<&Ident<'_>> {
404 self.ident
405 }
406
407 pub fn class(&self) -> &Class<'_> {
408 self.class
409 }
410}
411
412#[derive(Debug, Clone, Copy)]
413pub enum Statement<'ast> {
414 Block(&'ast BlockStmt<'ast>),
415 Empty(&'ast EmptyStmt),
416 Debugger(&'ast DebuggerStmt),
417 With(&'ast WithStmt<'ast>),
418 Return(&'ast ReturnStmt<'ast>),
419 Labeled(&'ast LabeledStmt<'ast>),
420 Break(&'ast BreakStmt<'ast>),
421 Continue(&'ast ContinueStmt<'ast>),
422 If(&'ast IfStmt<'ast>),
423 Switch(&'ast SwitchStmt<'ast>),
424 Throw(&'ast ThrowStmt<'ast>),
425 Try(&'ast TryStmt<'ast>),
426 While(&'ast WhileStmt<'ast>),
427 DoWhile(&'ast DoWhileStmt<'ast>),
428 For(&'ast ForStmt<'ast>),
429 ForIn(&'ast ForInStmt<'ast>),
430 ForOf(&'ast ForOfStmt<'ast>),
431 Expr(&'ast ExprStmt<'ast>),
432 Class(MaybeNamedClassDecl<'ast>),
435 Fn(MaybeNamedFunctionDecl<'ast>),
438 Var(VariableDeclaration<'ast>),
439}
440
441impl Statement<'_> {
442 pub fn span(&self) -> Span {
443 use Statement::*;
444 match self {
445 Block(d) => d.span(),
446 Empty(d) => d.span(),
447 Debugger(d) => d.span(),
448 With(d) => d.span(),
449 Return(d) => d.span(),
450 Labeled(d) => d.span(),
451 Break(d) => d.span(),
452 Continue(d) => d.span(),
453 If(d) => d.span(),
454 Switch(d) => d.span(),
455 Throw(d) => d.span(),
456 Try(d) => d.span(),
457 While(d) => d.span(),
458 DoWhile(d) => d.span(),
459 For(d) => d.span(),
460 ForIn(d) => d.span(),
461 ForOf(d) => d.span(),
462 Expr(d) => d.span(),
463 Class(d) => d.span(),
464 Fn(d) => d.span(),
465 Var(d) => d.span(),
466 }
467 }
468}
469
470impl<'ast> From<&'ast Stmt<'ast>> for Statement<'ast> {
471 fn from(value: &'ast Stmt<'ast>) -> Self {
472 use Statement::*;
473 match value {
474 Stmt::Block(d) => Block(d),
475 Stmt::Empty(d) => Empty(d),
476 Stmt::Debugger(d) => Debugger(d),
477 Stmt::With(d) => With(d),
478 Stmt::Return(d) => Return(d),
479 Stmt::Labeled(d) => Labeled(d),
480 Stmt::Break(d) => Break(d),
481 Stmt::Continue(d) => Continue(d),
482 Stmt::If(d) => If(d),
483 Stmt::Switch(d) => Switch(d),
484 Stmt::Throw(d) => Throw(d),
485 Stmt::Try(d) => Try(d),
486 Stmt::While(d) => While(d),
487 Stmt::DoWhile(d) => DoWhile(d),
488 Stmt::For(d) => For(d),
489 Stmt::ForIn(d) => ForIn(d),
490 Stmt::ForOf(d) => ForOf(d),
491 Stmt::Expr(d) => Expr(d),
492 Stmt::Decl(d) => (&**d).into(),
493 }
494 }
495}
496
497impl<'ast> From<&'ast Decl<'ast>> for Statement<'ast> {
498 fn from(value: &'ast Decl<'ast>) -> Self {
499 use Statement::*;
500 match value {
501 Decl::Class(d) => Class((&**d).into()),
502 Decl::Fn(d) => Fn((&**d).into()),
503 Decl::Var(d) => Var(VariableDeclaration::VarDecl(d)),
504 Decl::Using(d) => Var(VariableDeclaration::UsingDecl(d)),
505 }
506 }
507}
508
509impl<'ast> Statement<'ast> {
510 pub fn as_function_decl(&self) -> Option<MaybeNamedFunctionDecl<'ast>> {
511 match self {
512 Statement::Fn(f) => Some(*f),
513 _ => None,
514 }
515 }
516
517 pub fn as_class_decl(&self) -> Option<MaybeNamedClassDecl<'ast>> {
518 match self {
519 Statement::Class(c) => Some(*c),
520 _ => None,
521 }
522 }
523}
524
525#[derive(Debug, Clone, Copy)]
526pub enum VariableDeclaration<'a> {
527 VarDecl(&'a VarDecl<'a>),
528 UsingDecl(&'a UsingDecl<'a>),
529}
530
531#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
532pub enum VariableDeclarationKind {
533 Var,
534 Let,
535 Const,
536 Using,
537 AwaitUsing,
538}
539
540impl VariableDeclaration<'_> {
541 pub fn span(&self) -> Span {
542 match self {
543 VariableDeclaration::VarDecl(var_decl) => var_decl.span(),
544 VariableDeclaration::UsingDecl(using_decl) => using_decl.span(),
545 }
546 }
547}
548
549impl<'a> VariableDeclaration<'a> {
550 pub fn kind(&self) -> VariableDeclarationKind {
551 match self {
552 VariableDeclaration::VarDecl(v) => match v.kind {
553 VarDeclKind::Var => VariableDeclarationKind::Var,
554 VarDeclKind::Let => VariableDeclarationKind::Let,
555 VarDeclKind::Const => VariableDeclarationKind::Const,
556 },
557 VariableDeclaration::UsingDecl(u) => {
558 if u.is_await {
559 VariableDeclarationKind::AwaitUsing
560 } else {
561 VariableDeclarationKind::Using
562 }
563 }
564 }
565 }
566
567 pub fn declarators(&self) -> &'a [VarDeclarator<'a>] {
568 match self {
569 VariableDeclaration::VarDecl(v) => &v.decls,
570 VariableDeclaration::UsingDecl(u) => &u.decls,
571 }
572 }
573}
574
575fn module_export_name_to_atom(name: &ModuleExportName<'_>) -> Atom {
576 match name {
577 ModuleExportName::Ident(ident) => Atom::from(ident.sym.as_str()),
578 ModuleExportName::Str(s) => wtf8_atom_to_atom(s.value),
579 }
580}