boa_ast/module_item_list/
mod.rs1use crate::{
9 StatementListItem,
10 declaration::{
11 ExportDeclaration, ExportEntry, ExportSpecifier, ImportAttribute, ImportDeclaration,
12 ImportEntry, ImportKind, ImportName, IndirectExportEntry, LocalExportEntry,
13 ModuleSpecifier, ReExportImportName, ReExportKind,
14 },
15 operations::{BoundNamesVisitor, bound_names},
16 visitor::{VisitWith, Visitor, VisitorMut},
17};
18use boa_interner::Sym;
19use indexmap::IndexSet;
20use rustc_hash::{FxHashSet, FxHasher};
21use std::{convert::Infallible, hash::BuildHasherDefault, ops::ControlFlow};
22
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32#[derive(Clone, Debug, Default, PartialEq)]
33pub struct ModuleItemList {
34 items: Box<[ModuleItem]>,
35}
36
37impl ModuleItemList {
38 #[inline]
40 #[must_use]
41 pub const fn items(&self) -> &[ModuleItem] {
42 &self.items
43 }
44
45 #[inline]
49 #[must_use]
50 pub fn exported_names(&self) -> Vec<Sym> {
51 #[derive(Debug)]
52 struct ExportedItemsVisitor<'vec>(&'vec mut Vec<Sym>);
53
54 impl<'ast> Visitor<'ast> for ExportedItemsVisitor<'_> {
55 type BreakTy = Infallible;
56
57 fn visit_import_declaration(
58 &mut self,
59 _: &'ast ImportDeclaration,
60 ) -> ControlFlow<Self::BreakTy> {
61 ControlFlow::Continue(())
62 }
63 fn visit_statement_list_item(
64 &mut self,
65 _: &'ast StatementListItem,
66 ) -> ControlFlow<Self::BreakTy> {
67 ControlFlow::Continue(())
68 }
69 fn visit_export_specifier(
70 &mut self,
71 node: &'ast ExportSpecifier,
72 ) -> ControlFlow<Self::BreakTy> {
73 self.0.push(node.alias());
74 ControlFlow::Continue(())
75 }
76 fn visit_export_declaration(
77 &mut self,
78 node: &'ast ExportDeclaration,
79 ) -> ControlFlow<Self::BreakTy> {
80 match node {
81 ExportDeclaration::ReExport { kind, .. } => {
82 match kind {
83 ReExportKind::Namespaced { name: Some(name) } => self.0.push(*name),
84 ReExportKind::Namespaced { name: None } => {}
85 ReExportKind::Named { names } => {
86 for specifier in &**names {
87 self.visit_export_specifier(specifier)?;
88 }
89 }
90 }
91 ControlFlow::Continue(())
92 }
93 ExportDeclaration::List(list) => {
94 for specifier in &**list {
95 self.visit_export_specifier(specifier)?;
96 }
97 ControlFlow::Continue(())
98 }
99 ExportDeclaration::VarStatement(var) => {
100 BoundNamesVisitor(self.0).visit_var_declaration(var)
101 }
102 ExportDeclaration::Declaration(decl) => {
103 BoundNamesVisitor(self.0).visit_declaration(decl)
104 }
105 ExportDeclaration::DefaultFunctionDeclaration(_)
106 | ExportDeclaration::DefaultGeneratorDeclaration(_)
107 | ExportDeclaration::DefaultAsyncFunctionDeclaration(_)
108 | ExportDeclaration::DefaultAsyncGeneratorDeclaration(_)
109 | ExportDeclaration::DefaultClassDeclaration(_)
110 | ExportDeclaration::DefaultAssignmentExpression(_) => {
111 self.0.push(Sym::DEFAULT);
112 ControlFlow::Continue(())
113 }
114 }
115 }
116 }
117
118 let mut names = Vec::new();
119
120 let _ = ExportedItemsVisitor(&mut names).visit_module_item_list(self);
121
122 names
123 }
124
125 #[inline]
129 #[must_use]
130 pub fn exported_bindings(&self) -> FxHashSet<Sym> {
131 #[derive(Debug)]
132 struct ExportedBindingsVisitor<'vec>(&'vec mut FxHashSet<Sym>);
133
134 impl<'ast> Visitor<'ast> for ExportedBindingsVisitor<'_> {
135 type BreakTy = Infallible;
136
137 fn visit_import_declaration(
138 &mut self,
139 _: &'ast ImportDeclaration,
140 ) -> ControlFlow<Self::BreakTy> {
141 ControlFlow::Continue(())
142 }
143 fn visit_statement_list_item(
144 &mut self,
145 _: &'ast StatementListItem,
146 ) -> ControlFlow<Self::BreakTy> {
147 ControlFlow::Continue(())
148 }
149 fn visit_export_specifier(
150 &mut self,
151 node: &'ast ExportSpecifier,
152 ) -> ControlFlow<Self::BreakTy> {
153 self.0.insert(node.private_name());
154 ControlFlow::Continue(())
155 }
156 fn visit_export_declaration(
157 &mut self,
158 node: &'ast ExportDeclaration,
159 ) -> ControlFlow<Self::BreakTy> {
160 let name = match node {
161 ExportDeclaration::ReExport { .. } => return ControlFlow::Continue(()),
162 ExportDeclaration::List(list) => {
163 for specifier in &**list {
164 self.visit_export_specifier(specifier)?;
165 }
166 return ControlFlow::Continue(());
167 }
168 ExportDeclaration::DefaultAssignmentExpression(expr) => {
169 return BoundNamesVisitor(self.0).visit_expression(expr);
170 }
171 ExportDeclaration::VarStatement(var) => {
172 return BoundNamesVisitor(self.0).visit_var_declaration(var);
173 }
174 ExportDeclaration::Declaration(decl) => {
175 return BoundNamesVisitor(self.0).visit_declaration(decl);
176 }
177 ExportDeclaration::DefaultFunctionDeclaration(f) => f.name(),
178 ExportDeclaration::DefaultGeneratorDeclaration(g) => g.name(),
179 ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => af.name(),
180 ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => ag.name(),
181 ExportDeclaration::DefaultClassDeclaration(cl) => cl.name(),
182 };
183
184 self.0.insert(name.sym());
185
186 ControlFlow::Continue(())
187 }
188 }
189
190 let mut names = FxHashSet::default();
191
192 let _ = ExportedBindingsVisitor(&mut names).visit_module_item_list(self);
193
194 names
195 }
196
197 #[inline]
203 #[must_use]
204 pub fn requests(&self) -> IndexSet<Sym, BuildHasherDefault<FxHasher>> {
205 #[derive(Debug)]
206 struct RequestsVisitor<'vec>(&'vec mut IndexSet<Sym, BuildHasherDefault<FxHasher>>);
207
208 impl<'ast> Visitor<'ast> for RequestsVisitor<'_> {
209 type BreakTy = Infallible;
210
211 fn visit_statement_list_item(
212 &mut self,
213 _: &'ast StatementListItem,
214 ) -> ControlFlow<Self::BreakTy> {
215 ControlFlow::Continue(())
216 }
217 fn visit_module_specifier(
218 &mut self,
219 node: &'ast ModuleSpecifier,
220 ) -> ControlFlow<Self::BreakTy> {
221 self.0.insert(node.sym());
222 ControlFlow::Continue(())
223 }
224 }
225
226 let mut requests = IndexSet::default();
227
228 let _ = RequestsVisitor(&mut requests).visit_module_item_list(self);
229
230 requests
231 }
232
233 #[inline]
239 #[must_use]
240 pub fn import_entries(&self) -> Vec<ImportEntry> {
241 #[derive(Debug)]
242 struct ImportEntriesVisitor<'vec>(&'vec mut Vec<ImportEntry>);
243
244 impl<'ast> Visitor<'ast> for ImportEntriesVisitor<'_> {
245 type BreakTy = Infallible;
246
247 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
248 match node {
249 ModuleItem::ImportDeclaration(import) => self.visit_import_declaration(import),
250 ModuleItem::ExportDeclaration(_) | ModuleItem::StatementListItem(_) => {
251 ControlFlow::Continue(())
252 }
253 }
254 }
255
256 fn visit_import_declaration(
257 &mut self,
258 node: &'ast ImportDeclaration,
259 ) -> ControlFlow<Self::BreakTy> {
260 let module = node.specifier().sym();
261 let attributes: Box<[ImportAttribute]> = Box::from(node.attributes());
262
263 if let Some(default) = node.default() {
264 self.0.push(ImportEntry::new(
265 module,
266 ImportName::Name(Sym::DEFAULT),
267 default,
268 attributes.clone(),
269 ));
270 }
271
272 match node.kind() {
273 ImportKind::DefaultOrUnnamed => {}
274 ImportKind::Namespaced { binding } => {
275 self.0.push(ImportEntry::new(
276 module,
277 ImportName::Namespace,
278 *binding,
279 attributes.clone(),
280 ));
281 }
282 ImportKind::Named { names } => {
283 for name in &**names {
284 self.0.push(ImportEntry::new(
285 module,
286 ImportName::Name(name.export_name()),
287 name.binding(),
288 attributes.clone(),
289 ));
290 }
291 }
292 }
293
294 ControlFlow::Continue(())
295 }
296 }
297
298 let mut entries = Vec::default();
299
300 let _ = ImportEntriesVisitor(&mut entries).visit_module_item_list(self);
301
302 entries
303 }
304
305 #[inline]
311 #[must_use]
312 pub fn export_entries(&self) -> Vec<ExportEntry> {
313 #[derive(Debug)]
314 struct ExportEntriesVisitor<'vec>(&'vec mut Vec<ExportEntry>);
315
316 impl<'ast> Visitor<'ast> for ExportEntriesVisitor<'_> {
317 type BreakTy = Infallible;
318
319 fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
320 match node {
321 ModuleItem::ExportDeclaration(import) => self.visit_export_declaration(import),
322 ModuleItem::ImportDeclaration(_) | ModuleItem::StatementListItem(_) => {
323 ControlFlow::Continue(())
324 }
325 }
326 }
327
328 fn visit_export_declaration(
329 &mut self,
330 node: &'ast ExportDeclaration,
331 ) -> ControlFlow<Self::BreakTy> {
332 let name = match node {
333 ExportDeclaration::ReExport {
334 kind,
335 specifier,
336 attributes,
337 } => {
338 let module = specifier.sym();
339 let attrs = attributes.clone();
340
341 match kind {
342 ReExportKind::Namespaced { name: Some(name) } => {
343 self.0.push(
344 IndirectExportEntry::new(
345 module,
346 ReExportImportName::Star,
347 *name,
348 attrs.clone(),
349 )
350 .into(),
351 );
352 }
353 ReExportKind::Namespaced { name: None } => {
354 self.0.push(ExportEntry::StarReExport {
355 module_request: module,
356 attributes: attrs.clone(),
357 });
358 }
359
360 ReExportKind::Named { names } => {
361 for name in &**names {
362 self.0.push(
363 IndirectExportEntry::new(
364 module,
365 ReExportImportName::Name(name.private_name()),
366 name.alias(),
367 attrs.clone(),
368 )
369 .into(),
370 );
371 }
372 }
373 }
374
375 return ControlFlow::Continue(());
376 }
377 ExportDeclaration::List(names) => {
378 for name in &**names {
379 self.0.push(
380 LocalExportEntry::new(name.private_name(), name.alias()).into(),
381 );
382 }
383 return ControlFlow::Continue(());
384 }
385 ExportDeclaration::VarStatement(var) => {
386 for name in bound_names(var) {
387 self.0.push(LocalExportEntry::new(name, name).into());
388 }
389 return ControlFlow::Continue(());
390 }
391 ExportDeclaration::Declaration(decl) => {
392 for name in bound_names(decl) {
393 self.0.push(LocalExportEntry::new(name, name).into());
394 }
395 return ControlFlow::Continue(());
396 }
397 ExportDeclaration::DefaultFunctionDeclaration(f) => f.name().sym(),
398 ExportDeclaration::DefaultGeneratorDeclaration(g) => g.name().sym(),
399 ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => af.name().sym(),
400 ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => ag.name().sym(),
401 ExportDeclaration::DefaultClassDeclaration(c) => c.name().sym(),
402 ExportDeclaration::DefaultAssignmentExpression(_) => Sym::DEFAULT_EXPORT,
403 };
404
405 self.0
406 .push(LocalExportEntry::new(name, Sym::DEFAULT).into());
407
408 ControlFlow::Continue(())
409 }
410 }
411
412 let mut entries = Vec::default();
413
414 let _ = ExportEntriesVisitor(&mut entries).visit_module_item_list(self);
415
416 entries
417 }
418}
419
420impl<T> From<T> for ModuleItemList
421where
422 T: Into<Box<[ModuleItem]>>,
423{
424 #[inline]
425 fn from(items: T) -> Self {
426 Self {
427 items: items.into(),
428 }
429 }
430}
431
432impl VisitWith for ModuleItemList {
433 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
434 where
435 V: Visitor<'a>,
436 {
437 for item in &*self.items {
438 visitor.visit_module_item(item)?;
439 }
440
441 ControlFlow::Continue(())
442 }
443
444 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
445 where
446 V: VisitorMut<'a>,
447 {
448 for item in &mut *self.items {
449 visitor.visit_module_item_mut(item)?;
450 }
451
452 ControlFlow::Continue(())
453 }
454}
455
456#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
467#[derive(Clone, Debug, PartialEq)]
468pub enum ModuleItem {
469 ImportDeclaration(ImportDeclaration),
471 ExportDeclaration(Box<ExportDeclaration>),
473 StatementListItem(StatementListItem),
475}
476
477impl VisitWith for ModuleItem {
478 fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
479 where
480 V: Visitor<'a>,
481 {
482 match self {
483 Self::ImportDeclaration(i) => visitor.visit_import_declaration(i),
484 Self::ExportDeclaration(e) => visitor.visit_export_declaration(e),
485 Self::StatementListItem(s) => visitor.visit_statement_list_item(s),
486 }
487 }
488
489 fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
490 where
491 V: VisitorMut<'a>,
492 {
493 match self {
494 Self::ImportDeclaration(i) => visitor.visit_import_declaration_mut(i),
495 Self::ExportDeclaration(e) => visitor.visit_export_declaration_mut(e),
496 Self::StatementListItem(s) => visitor.visit_statement_list_item_mut(s),
497 }
498 }
499}