Skip to main content

boa_ast/declaration/
export.rs

1//! Export declaration AST nodes.
2//!
3//! This module contains `export` declaration AST nodes.
4//!
5//! More information:
6//!  - [MDN documentation][mdn]
7//!  - [ECMAScript specification][spec]
8//!
9//! [spec]: https://tc39.es/ecma262/#sec-exports
10//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
11
12use super::{ImportAttribute, ModuleSpecifier, VarDeclaration};
13use crate::{
14    Declaration, Expression,
15    function::{
16        AsyncFunctionDeclaration, AsyncGeneratorDeclaration, ClassDeclaration, FunctionDeclaration,
17        GeneratorDeclaration,
18    },
19    visitor::{VisitWith, Visitor, VisitorMut},
20};
21use boa_interner::Sym;
22use std::ops::ControlFlow;
23
24/// The kind of re-export in an [`ExportDeclaration`].
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub enum ReExportKind {
29    /// Namespaced Re-export (`export * as name from "module-name"`).
30    Namespaced {
31        /// Reexported name for the imported module.
32        name: Option<Sym>,
33    },
34    /// Re-export list (`export { export1, export2 as alias2 } from "module-name"`).
35    Named {
36        /// List of the required re-exports of the re-exported module.
37        names: Box<[ExportSpecifier]>,
38    },
39}
40
41impl VisitWith for ReExportKind {
42    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
43    where
44        V: Visitor<'a>,
45    {
46        match self {
47            Self::Namespaced { name: Some(name) } => visitor.visit_sym(name),
48            Self::Namespaced { name: None } => ControlFlow::Continue(()),
49            Self::Named { names } => {
50                for name in &**names {
51                    visitor.visit_export_specifier(name)?;
52                }
53                ControlFlow::Continue(())
54            }
55        }
56    }
57
58    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
59    where
60        V: VisitorMut<'a>,
61    {
62        match self {
63            Self::Namespaced { name: Some(name) } => visitor.visit_sym_mut(name),
64            Self::Namespaced { name: None } => ControlFlow::Continue(()),
65            Self::Named { names } => {
66                for name in &mut **names {
67                    visitor.visit_export_specifier_mut(name)?;
68                }
69                ControlFlow::Continue(())
70            }
71        }
72    }
73}
74
75/// An export declaration AST node.
76///
77/// More information:
78///  - [ECMAScript specification][spec]
79///
80/// [spec]: https://tc39.es/ecma262/#prod-ExportDeclaration
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82#[derive(Clone, Debug, PartialEq)]
83pub enum ExportDeclaration {
84    /// Re-export.
85    ReExport {
86        /// The kind of reexport declared.
87        kind: ReExportKind,
88        /// Reexported module specifier.
89        specifier: ModuleSpecifier,
90        /// Re-export attributes.
91        attributes: Box<[ImportAttribute]>,
92    },
93    /// List of exports.
94    List(Box<[ExportSpecifier]>),
95    /// Variable statement export.
96    VarStatement(VarDeclaration),
97    /// Declaration export.
98    Declaration(Declaration),
99    /// Default function export.
100    DefaultFunctionDeclaration(FunctionDeclaration),
101    /// Default generator export.
102    DefaultGeneratorDeclaration(GeneratorDeclaration),
103    /// Default async function export.
104    DefaultAsyncFunctionDeclaration(AsyncFunctionDeclaration),
105    /// Default async generator export.
106    DefaultAsyncGeneratorDeclaration(AsyncGeneratorDeclaration),
107    /// Default class declaration export.
108    DefaultClassDeclaration(Box<ClassDeclaration>),
109    /// Default assignment expression export.
110    DefaultAssignmentExpression(Expression),
111}
112
113impl VisitWith for ExportDeclaration {
114    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
115    where
116        V: Visitor<'a>,
117    {
118        match self {
119            Self::ReExport {
120                specifier,
121                kind,
122                attributes,
123            } => {
124                visitor.visit_module_specifier(specifier)?;
125                visitor.visit_re_export_kind(kind)?;
126                for attribute in &**attributes {
127                    visitor.visit_import_attribute(attribute)?;
128                }
129                ControlFlow::Continue(())
130            }
131            Self::List(list) => {
132                for item in &**list {
133                    visitor.visit_export_specifier(item)?;
134                }
135                ControlFlow::Continue(())
136            }
137            Self::VarStatement(var) => visitor.visit_var_declaration(var),
138            Self::Declaration(decl) => visitor.visit_declaration(decl),
139            Self::DefaultFunctionDeclaration(f) => visitor.visit_function_declaration(f),
140            Self::DefaultGeneratorDeclaration(g) => visitor.visit_generator_declaration(g),
141            Self::DefaultAsyncFunctionDeclaration(af) => {
142                visitor.visit_async_function_declaration(af)
143            }
144            Self::DefaultAsyncGeneratorDeclaration(ag) => {
145                visitor.visit_async_generator_declaration(ag)
146            }
147            Self::DefaultClassDeclaration(c) => visitor.visit_class_declaration(c),
148            Self::DefaultAssignmentExpression(expr) => visitor.visit_expression(expr),
149        }
150    }
151
152    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
153    where
154        V: VisitorMut<'a>,
155    {
156        match self {
157            Self::ReExport {
158                specifier,
159                kind,
160                attributes,
161            } => {
162                visitor.visit_module_specifier_mut(specifier)?;
163                visitor.visit_re_export_kind_mut(kind)?;
164                for attribute in &mut **attributes {
165                    visitor.visit_import_attribute_mut(attribute)?;
166                }
167                ControlFlow::Continue(())
168            }
169            Self::List(list) => {
170                for item in &mut **list {
171                    visitor.visit_export_specifier_mut(item)?;
172                }
173                ControlFlow::Continue(())
174            }
175            Self::VarStatement(var) => visitor.visit_var_declaration_mut(var),
176            Self::Declaration(decl) => visitor.visit_declaration_mut(decl),
177            Self::DefaultFunctionDeclaration(f) => visitor.visit_function_declaration_mut(f),
178            Self::DefaultGeneratorDeclaration(g) => visitor.visit_generator_declaration_mut(g),
179            Self::DefaultAsyncFunctionDeclaration(af) => {
180                visitor.visit_async_function_declaration_mut(af)
181            }
182            Self::DefaultAsyncGeneratorDeclaration(ag) => {
183                visitor.visit_async_generator_declaration_mut(ag)
184            }
185            Self::DefaultClassDeclaration(c) => visitor.visit_class_declaration_mut(c),
186            Self::DefaultAssignmentExpression(expr) => visitor.visit_expression_mut(expr),
187        }
188    }
189}
190
191/// Export specifier
192///
193/// More information:
194///  - [ECMAScript specification][spec]
195///
196/// [spec]: https://tc39.es/ecma262/#prod-ExportSpecifier
197#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
198#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
199#[derive(Clone, Debug, Copy, PartialEq, Eq)]
200pub struct ExportSpecifier {
201    alias: Sym,
202    private_name: Sym,
203    string_literal: bool,
204}
205
206impl ExportSpecifier {
207    /// Creates a new [`ExportSpecifier`].
208    #[inline]
209    #[must_use]
210    pub const fn new(alias: Sym, private_name: Sym, string_literal: bool) -> Self {
211        Self {
212            alias,
213            private_name,
214            string_literal,
215        }
216    }
217
218    /// Gets the original alias.
219    #[inline]
220    #[must_use]
221    pub const fn alias(self) -> Sym {
222        self.alias
223    }
224
225    /// Gets the private name of the export inside the module.
226    #[inline]
227    #[must_use]
228    pub const fn private_name(self) -> Sym {
229        self.private_name
230    }
231
232    /// Returns `true` if the private name of the specifier was a `StringLiteral`.
233    #[inline]
234    #[must_use]
235    pub const fn string_literal(&self) -> bool {
236        self.string_literal
237    }
238}
239
240impl VisitWith for ExportSpecifier {
241    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
242    where
243        V: Visitor<'a>,
244    {
245        visitor.visit_sym(&self.alias)?;
246        visitor.visit_sym(&self.private_name)
247    }
248
249    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
250    where
251        V: VisitorMut<'a>,
252    {
253        visitor.visit_sym_mut(&mut self.alias)?;
254        visitor.visit_sym_mut(&mut self.private_name)
255    }
256}
257
258/// The name under which a reexported binding is exported by a module.
259///
260/// This differs slightly from the spec, since `[[ImportName]]` can be either a name, `all-but-default`
261/// or `all`, but the last two exports can be identified with the `export_name` field from
262/// [`ExportEntry`], which joins both variants into a single `Star` variant.
263#[derive(Debug, Clone, Copy)]
264pub enum ReExportImportName {
265    /// A binding of the imported module.
266    Name(Sym),
267    /// All exports of the module.
268    Star,
269}
270
271/// [`ExportEntry`][spec] record.
272///
273/// [spec]: https://tc39.es/ecma262/#table-exportentry-records
274#[derive(Debug, Clone)]
275pub enum ExportEntry {
276    /// An ordinary export entry
277    Ordinary(LocalExportEntry),
278    /// A star reexport entry.
279    StarReExport {
280        /// The module from where this reexport will import.
281        module_request: Sym,
282        /// The import attributes for this reexport.
283        attributes: Box<[ImportAttribute]>,
284    },
285    /// A reexport entry with an export name.
286    ReExport(IndirectExportEntry),
287}
288
289impl From<IndirectExportEntry> for ExportEntry {
290    fn from(v: IndirectExportEntry) -> Self {
291        Self::ReExport(v)
292    }
293}
294
295impl From<LocalExportEntry> for ExportEntry {
296    fn from(v: LocalExportEntry) -> Self {
297        Self::Ordinary(v)
298    }
299}
300
301/// A local export entry
302#[derive(Debug, Clone, Copy)]
303pub struct LocalExportEntry {
304    local_name: Sym,
305    export_name: Sym,
306}
307
308impl LocalExportEntry {
309    /// Creates a new `LocalExportEntry`.
310    #[must_use]
311    pub const fn new(local_name: Sym, export_name: Sym) -> Self {
312        Self {
313            local_name,
314            export_name,
315        }
316    }
317
318    /// Gets the local name of this export entry.
319    #[must_use]
320    pub const fn local_name(&self) -> Sym {
321        self.local_name
322    }
323
324    /// Gets the export name of this export entry.
325    #[must_use]
326    pub const fn export_name(&self) -> Sym {
327        self.export_name
328    }
329}
330
331/// A reexported export entry.
332#[derive(Debug, Clone)]
333pub struct IndirectExportEntry {
334    module_request: Sym,
335    import_name: ReExportImportName,
336    export_name: Sym,
337    attributes: Box<[ImportAttribute]>,
338}
339
340impl IndirectExportEntry {
341    /// Creates a new `IndirectExportEntry`.
342    #[must_use]
343    pub fn new(
344        module_request: Sym,
345        import_name: ReExportImportName,
346        export_name: Sym,
347        attributes: Box<[ImportAttribute]>,
348    ) -> Self {
349        Self {
350            module_request,
351            import_name,
352            export_name,
353            attributes,
354        }
355    }
356
357    /// Gets the module from where this entry reexports.
358    #[must_use]
359    pub const fn module_request(&self) -> Sym {
360        self.module_request
361    }
362
363    /// Gets the import name of the reexport.
364    #[must_use]
365    pub const fn import_name(&self) -> ReExportImportName {
366        self.import_name
367    }
368
369    /// Gets the public alias of the reexport.
370    #[must_use]
371    pub const fn export_name(&self) -> Sym {
372        self.export_name
373    }
374
375    /// Gets the import attributes.
376    #[must_use]
377    pub fn attributes(&self) -> &[ImportAttribute] {
378        &self.attributes
379    }
380}