Skip to main content

boa_ast/declaration/
import.rs

1//! Import declaration AST nodes.
2//!
3//! This module contains `import` declaration AST nodes.
4//!
5//! More information:
6//! - [MDN documentation][mdn]
7//!  - [ECMAScript specification][spec]
8//!
9//! [spec]: https://tc39.es/ecma262/#sec-imports
10//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
11
12use std::ops::ControlFlow;
13
14use crate::{
15    expression::Identifier,
16    visitor::{VisitWith, Visitor, VisitorMut},
17};
18use boa_interner::Sym;
19
20use super::{ImportAttribute, ModuleSpecifier};
21
22/// The kind of import in an [`ImportDeclaration`].
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum ImportKind {
27    /// Default (`import defaultName from "module-name"`) or unnamed (`import "module-name"`).
28    DefaultOrUnnamed,
29    /// Namespaced import (`import * as name from "module-name"`).
30    Namespaced {
31        /// Binding for the namespace created from the exports of the imported module.
32        binding: Identifier,
33    },
34    /// Import list (`import { export1, export2 as alias2 } from "module-name"`).
35    Named {
36        /// List of the required exports of the imported module.
37        names: Box<[ImportSpecifier]>,
38    },
39}
40
41impl VisitWith for ImportKind {
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::DefaultOrUnnamed => ControlFlow::Continue(()),
48            Self::Namespaced { binding } => visitor.visit_identifier(binding),
49            Self::Named { names } => {
50                for name in &**names {
51                    visitor.visit_import_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::DefaultOrUnnamed => ControlFlow::Continue(()),
64            Self::Namespaced { binding } => visitor.visit_identifier_mut(binding),
65            Self::Named { names } => {
66                for name in &mut **names {
67                    visitor.visit_import_specifier_mut(name)?;
68                }
69                ControlFlow::Continue(())
70            }
71        }
72    }
73}
74
75/// An import declaration AST node.
76///
77/// More information:
78///  - [ECMAScript specification][spec]
79///
80/// [spec]: https://tc39.es/ecma262/#prod-ImportDeclaration
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82#[derive(Clone, Debug, PartialEq, Eq)]
83pub struct ImportDeclaration {
84    /// Binding for the default export of `specifier`.
85    default: Option<Identifier>,
86    /// See [`ImportKind`].
87    kind: ImportKind,
88    /// Module specifier.
89    specifier: ModuleSpecifier,
90    /// Import attributes.
91    attributes: Box<[ImportAttribute]>,
92}
93
94impl ImportDeclaration {
95    /// Creates a new import declaration.
96    #[inline]
97    #[must_use]
98    pub fn new(
99        default: Option<Identifier>,
100        kind: ImportKind,
101        specifier: ModuleSpecifier,
102        attributes: Box<[ImportAttribute]>,
103    ) -> Self {
104        Self {
105            default,
106            kind,
107            specifier,
108            attributes,
109        }
110    }
111
112    /// Gets the binding for the default export of the module.
113    #[inline]
114    #[must_use]
115    pub const fn default(&self) -> Option<Identifier> {
116        self.default
117    }
118
119    /// Gets the module specifier of the import declaration.
120    #[inline]
121    #[must_use]
122    pub const fn specifier(&self) -> ModuleSpecifier {
123        self.specifier
124    }
125
126    /// Gets the import kind of the import declaration.
127    #[inline]
128    #[must_use]
129    pub const fn kind(&self) -> &ImportKind {
130        &self.kind
131    }
132
133    /// Gets the import attributes of the import declaration.
134    #[inline]
135    #[must_use]
136    pub const fn attributes(&self) -> &[ImportAttribute] {
137        &self.attributes
138    }
139}
140
141impl VisitWith for ImportDeclaration {
142    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
143    where
144        V: Visitor<'a>,
145    {
146        if let Some(default) = &self.default {
147            visitor.visit_identifier(default)?;
148        }
149        visitor.visit_import_kind(&self.kind)?;
150        visitor.visit_module_specifier(&self.specifier)?;
151        for attribute in &*self.attributes {
152            visitor.visit_import_attribute(attribute)?;
153        }
154        ControlFlow::Continue(())
155    }
156
157    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
158    where
159        V: VisitorMut<'a>,
160    {
161        if let Some(default) = &mut self.default {
162            visitor.visit_identifier_mut(default)?;
163        }
164        visitor.visit_import_kind_mut(&mut self.kind)?;
165        visitor.visit_module_specifier_mut(&mut self.specifier)?;
166        for attribute in &mut *self.attributes {
167            visitor.visit_import_attribute_mut(attribute)?;
168        }
169        ControlFlow::Continue(())
170    }
171}
172
173/// Import specifier
174///
175/// More information:
176///  - [ECMAScript specification][spec]
177///
178/// [spec]: https://tc39.es/ecma262/#prod-ImportSpecifier
179#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
180#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub struct ImportSpecifier {
183    binding: Identifier,
184    export_name: Sym,
185}
186
187impl ImportSpecifier {
188    /// Creates a new [`ImportSpecifier`].
189    #[inline]
190    #[must_use]
191    pub const fn new(binding: Identifier, export_name: Sym) -> Self {
192        Self {
193            binding,
194            export_name,
195        }
196    }
197
198    /// Gets the binding of the import specifier.
199    #[inline]
200    #[must_use]
201    pub const fn binding(self) -> Identifier {
202        self.binding
203    }
204
205    /// Gets the optional export name of the import.
206    #[inline]
207    #[must_use]
208    pub const fn export_name(self) -> Sym {
209        self.export_name
210    }
211}
212
213impl VisitWith for ImportSpecifier {
214    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
215    where
216        V: Visitor<'a>,
217    {
218        visitor.visit_identifier(&self.binding)?;
219        visitor.visit_sym(&self.export_name)
220    }
221
222    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
223    where
224        V: VisitorMut<'a>,
225    {
226        visitor.visit_identifier_mut(&mut self.binding)?;
227        visitor.visit_sym_mut(&mut self.export_name)
228    }
229}
230
231/// The name under which the imported binding is exported by a module.
232#[derive(Debug, Clone, Copy)]
233pub enum ImportName {
234    /// The namespace object of the imported module.
235    Namespace,
236    /// A binding of the imported module.
237    Name(Sym),
238}
239
240/// [`ImportEntry`][spec] record.
241///
242/// [spec]: https://tc39.es/ecma262/#table-importentry-record-fields
243#[derive(Debug, Clone)]
244pub struct ImportEntry {
245    module_request: Sym,
246    import_name: ImportName,
247    local_name: Identifier,
248    attributes: Box<[ImportAttribute]>,
249}
250
251impl ImportEntry {
252    /// Creates a new `ImportEntry`.
253    #[must_use]
254    pub fn new(
255        module_request: Sym,
256        import_name: ImportName,
257        local_name: Identifier,
258        attributes: Box<[ImportAttribute]>,
259    ) -> Self {
260        Self {
261            module_request,
262            import_name,
263            local_name,
264            attributes,
265        }
266    }
267
268    /// Gets the module from where the binding must be imported.
269    #[must_use]
270    pub const fn module_request(&self) -> Sym {
271        self.module_request
272    }
273
274    /// Gets the import name of the imported binding.
275    #[must_use]
276    pub const fn import_name(&self) -> ImportName {
277        self.import_name
278    }
279
280    /// Gets the local name of the imported binding.
281    #[must_use]
282    pub const fn local_name(&self) -> Identifier {
283        self.local_name
284    }
285
286    /// Gets the import attributes.
287    #[must_use]
288    pub fn attributes(&self) -> &[ImportAttribute] {
289        &self.attributes
290    }
291}