turbopack_ecmascript/tree_shake/
merge.rs1use anyhow::Error;
2use rustc_hash::FxHashSet;
3use swc_core::ecma::{
4 ast::{Module, ModuleDecl, ModuleItem},
5 atoms::Atom,
6};
7
8use super::{PartId, graph::find_turbopack_part_id_in_asserts};
9
10pub trait Load {
12 fn load(&mut self, uri: &str, part_id: u32) -> Result<Option<Module>, Error>;
14}
15
16pub struct Merger<L>
20where
21 L: Load,
22{
23 loader: L,
24
25 done: FxHashSet<(Atom, u32)>,
26}
27
28impl<L> Merger<L>
29where
30 L: Load,
31{
32 pub fn new(loader: L) -> Self {
34 Merger {
35 loader,
36 done: Default::default(),
37 }
38 }
39
40 pub fn merge_recursively(&mut self, entry: Module) -> Result<Module, Error> {
43 let mut content = vec![];
44 let mut extra_body = vec![];
45
46 for stmt in entry.body {
47 match stmt {
48 ModuleItem::ModuleDecl(ModuleDecl::Import(import)) => {
49 let part_id = import
52 .with
53 .as_deref()
54 .and_then(find_turbopack_part_id_in_asserts);
55
56 if let Some(PartId::Internal(part_id, _)) = part_id {
57 if self.done.insert((import.src.value.clone(), part_id)) {
58 if let Some(dep) = self.loader.load(&import.src.value, part_id)? {
59 let mut dep = self.merge_recursively(dep)?;
60
61 extra_body.append(&mut dep.body);
62 } else {
63 content.push(ModuleItem::ModuleDecl(ModuleDecl::Import(import)));
64 }
65 } else {
66 }
68 } else {
69 content.push(ModuleItem::ModuleDecl(ModuleDecl::Import(import)));
71 }
72 }
73 _ => extra_body.push(stmt),
74 }
75 }
76
77 content.append(&mut extra_body);
78
79 Ok(Module {
80 span: entry.span,
81 body: content,
82 shebang: entry.shebang,
83 })
84 }
85}