Skip to main content

rspack_plugin_javascript/visitors/dependency/parser/
estree.rs

1//! The compat estree helpers for swc ecma ast
2
3use 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  /// `export * from 'm'`
45  All(&'ast ExportAll<'ast>),
46  /// `export * as x from 'm'`
47  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  /// `export var x = 1`
120  /// `export class X {}`
121  Decl(&'ast ExportDecl<'ast>),
122  /// `export { x } from 'm'`
123  /// `export { x }`
124  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  /// `export default class X {}`
194  /// `export default class {}`
195  /// `export default function x() {}`
196  /// `export default function () {}`
197  Decl(&'ast ExportDefaultDecl<'ast>),
198  /// `export default (class X {})`
199  /// `export default 'x'`
200  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  /// `export default function () {}`
224  FnDecl(&'ast FnExpr<'ast>),
225  /// `export default class {}`
226  ClassDecl(&'ast ClassExpr<'ast>),
227  /// `export default (class {})`
228  /// `export default 'x'`
229  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  // ClassDecl, don't put ClassExpr into it, unless it's DefaultDecl::ClassExpr
433  // which is represented by ClassExpr but it actually is a ClassDecl without ident
434  Class(MaybeNamedClassDecl<'ast>),
435  // FnDecl, don't put FnExpr into it, unless it's DefaultDecl::FnExpr
436  // which is represented by FnExpr but it actually is a FnDecl without ident
437  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}