Skip to main content

turbopack_ecmascript/rename/
module.rs

1use std::collections::BTreeMap;
2
3use anyhow::{Result, bail};
4use turbo_tasks::{ResolvedVc, Vc};
5use turbo_tasks_fs::{File, FileContent};
6use turbopack_core::{
7    asset::{Asset, AssetContent},
8    chunk::{
9        AsyncModuleInfo, ChunkableModule, ChunkingContext, EvaluatableAsset, MergeableModule,
10        MergeableModules, MergeableModulesExposed,
11    },
12    ident::AssetIdent,
13    module::{Module, ModuleSideEffects},
14    module_graph::ModuleGraph,
15    reference::ModuleReferences,
16    resolve::{ExportUsage, ModulePart},
17    source::OptionSource,
18};
19
20use crate::{
21    AnalyzeEcmascriptModuleResult, EcmascriptAnalyzable, EcmascriptAnalyzableExt,
22    EcmascriptModuleContent, EcmascriptModuleContentOptions, EcmascriptOptions,
23    MergedEcmascriptModule, SpecifiedModuleType,
24    chunk::{
25        EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
26        ecmascript_chunk_item,
27    },
28    code_gen::CodeGens,
29    references::{
30        async_module::{AsyncModule, OptionAsyncModule},
31        esm::{EsmExport, EsmExports, base::EsmAssetReferences},
32    },
33    side_effect_optimization::reference::EcmascriptModulePartReference,
34};
35
36/// A module derived from an original ecmascript module that reexports a single export or the whole
37/// namespace object under a different name.
38#[turbo_tasks::value]
39pub struct EcmascriptModuleRenameModule {
40    module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
41    /// The part of the module that this facade represents.
42    /// ModulePart::Facade | ModulePart::RenamedExport |
43    /// ModulePart::RenamedNamespace
44    part: ModulePart,
45}
46
47#[turbo_tasks::value_impl]
48impl EcmascriptModuleRenameModule {
49    #[turbo_tasks::function]
50    pub fn new(
51        module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
52        part: ModulePart,
53    ) -> Vc<Self> {
54        assert!(
55            matches!(
56                part,
57                ModulePart::RenamedExport { .. } | ModulePart::RenamedNamespace { .. }
58            ),
59            "{part:?} is unexpected for EcmascriptModuleRenameModule"
60        );
61        EcmascriptModuleRenameModule { module, part }.cell()
62    }
63
64    #[turbo_tasks::function]
65    pub async fn async_module(&self) -> Result<Vc<AsyncModule>> {
66        let (import_externals, has_top_level_await) =
67            if let Some(async_module) = *self.module.get_async_module().await? {
68                (
69                    async_module.await?.import_externals,
70                    async_module.await?.has_top_level_await,
71                )
72            } else {
73                (false, false)
74            };
75        Ok(AsyncModule {
76            has_top_level_await,
77            import_externals,
78        }
79        .cell())
80    }
81}
82
83impl EcmascriptModuleRenameModule {
84    pub async fn module_reference(&self) -> Result<ResolvedVc<EcmascriptModulePartReference>> {
85        match &self.part {
86            ModulePart::RenamedNamespace { .. } => {
87                EcmascriptModulePartReference::new_normal(
88                    *self.module,
89                    self.part.clone(),
90                    ExportUsage::all(),
91                )
92                .to_resolved()
93                .await
94            }
95            ModulePart::RenamedExport {
96                original_export, ..
97            } => {
98                EcmascriptModulePartReference::new_normal(
99                    *self.module,
100                    self.part.clone(),
101                    ExportUsage::named(original_export.clone()),
102                )
103                .to_resolved()
104                .await
105            }
106            _ => {
107                bail!("Unexpected ModulePart for EcmascriptModuleRenameModule");
108            }
109        }
110    }
111}
112
113#[turbo_tasks::value_impl]
114impl Module for EcmascriptModuleRenameModule {
115    #[turbo_tasks::function]
116    fn source(&self) -> Vc<OptionSource> {
117        Vc::cell(None)
118    }
119
120    #[turbo_tasks::function]
121    fn ident(&self) -> Vc<AssetIdent> {
122        self.module.ident().with_part(self.part.clone())
123    }
124
125    #[turbo_tasks::function]
126    async fn references(self: Vc<Self>) -> Result<Vc<ModuleReferences>> {
127        let reference = self.await?.module_reference().await?;
128        Ok(Vc::cell(vec![ResolvedVc::upcast(reference)]))
129    }
130
131    #[turbo_tasks::function]
132    async fn is_self_async(self: Vc<Self>) -> Result<Vc<bool>> {
133        let async_module = self.async_module();
134        let references = self.references();
135        let is_self_async = async_module
136            .resolve()
137            .await?
138            .is_self_async(references.resolve().await?)
139            .resolve()
140            .await?;
141        Ok(is_self_async)
142    }
143
144    #[turbo_tasks::function]
145    fn side_effects(&self) -> Vc<ModuleSideEffects> {
146        // This just re-exports another import
147        ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
148    }
149}
150
151#[turbo_tasks::value_impl]
152impl Asset for EcmascriptModuleRenameModule {
153    #[turbo_tasks::function]
154    fn content(&self) -> Vc<AssetContent> {
155        let f = File::from("");
156
157        AssetContent::file(FileContent::Content(f).cell())
158    }
159}
160
161#[turbo_tasks::value_impl]
162impl EcmascriptAnalyzable for EcmascriptModuleRenameModule {
163    #[turbo_tasks::function]
164    fn analyze(&self) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
165        bail!("EcmascriptModuleRenameModule::analyze shouldn't be called");
166    }
167
168    #[turbo_tasks::function]
169    fn module_content_without_analysis(
170        &self,
171        _generate_source_map: bool,
172    ) -> Result<Vc<EcmascriptModuleContent>> {
173        bail!("EcmascriptModuleRenameModule::module_content_without_analysis shouldn't be called");
174    }
175
176    #[turbo_tasks::function]
177    async fn module_content_options(
178        self: ResolvedVc<Self>,
179        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
180        async_module_info: Option<ResolvedVc<AsyncModuleInfo>>,
181    ) -> Result<Vc<EcmascriptModuleContentOptions>> {
182        let reference = self.await?.module_reference().await?;
183
184        Ok(EcmascriptModuleContentOptions {
185            parsed: None,
186            module: ResolvedVc::upcast(self),
187            specified_module_type: SpecifiedModuleType::EcmaScript,
188            chunking_context,
189            references: self.references().to_resolved().await?,
190            part_references: vec![reference],
191            esm_references: EsmAssetReferences::empty().to_resolved().await?,
192            code_generation: CodeGens::empty().to_resolved().await?,
193            async_module: ResolvedVc::cell(Some(self.async_module().to_resolved().await?)),
194            // The facade module cannot generate source maps, because the inserted references
195            // contain spans from the original module, but the facade module itself doesn't have the
196            // original module's swc_common::SourceMap in `parsed`.
197            generate_source_map: false,
198            original_source_map: None,
199            exports: self.get_exports().to_resolved().await?,
200            async_module_info,
201        }
202        .cell())
203    }
204}
205
206#[turbo_tasks::value_impl]
207impl EcmascriptChunkPlaceable for EcmascriptModuleRenameModule {
208    #[turbo_tasks::function]
209    async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
210        let reference = self.module_reference().await?;
211        let mut exports = BTreeMap::new();
212
213        match &self.part {
214            ModulePart::RenamedExport {
215                original_export,
216                export,
217            } => {
218                exports.insert(
219                    export.clone(),
220                    EsmExport::ImportedBinding(
221                        ResolvedVc::upcast(reference),
222                        original_export.clone(),
223                        false,
224                    ),
225                );
226            }
227            ModulePart::RenamedNamespace { export } => {
228                exports.insert(
229                    export.clone(),
230                    EsmExport::ImportedNamespace(ResolvedVc::upcast(reference)),
231                );
232            }
233            _ => bail!("Unexpected ModulePart for EcmascriptModuleRenameModule"),
234        }
235
236        let exports = EsmExports {
237            exports,
238            star_exports: Vec::new(),
239        }
240        .resolved_cell();
241        Ok(EcmascriptExports::EsmExports(exports).cell())
242    }
243
244    #[turbo_tasks::function]
245    async fn get_async_module(self: Vc<Self>) -> Result<Vc<OptionAsyncModule>> {
246        Ok(Vc::cell(Some(self.async_module().to_resolved().await?)))
247    }
248
249    #[turbo_tasks::function]
250    async fn chunk_item_content(
251        self: Vc<Self>,
252        chunking_context: Vc<Box<dyn ChunkingContext>>,
253        _module_graph: Vc<ModuleGraph>,
254        async_module_info: Option<Vc<AsyncModuleInfo>>,
255        _estimated: bool,
256    ) -> Result<Vc<EcmascriptChunkItemContent>> {
257        let async_module_options = self.get_async_module().module_options(async_module_info);
258        let content = self.module_content(chunking_context, async_module_info);
259        Ok(EcmascriptChunkItemContent::new(
260            content,
261            chunking_context,
262            async_module_options,
263        ))
264    }
265}
266
267#[turbo_tasks::value_impl]
268impl ChunkableModule for EcmascriptModuleRenameModule {
269    #[turbo_tasks::function]
270    fn as_chunk_item(
271        self: ResolvedVc<Self>,
272        module_graph: ResolvedVc<ModuleGraph>,
273        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
274    ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
275        ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
276    }
277}
278
279#[turbo_tasks::value_impl]
280impl EvaluatableAsset for EcmascriptModuleRenameModule {}
281
282#[turbo_tasks::value_impl]
283impl MergeableModule for EcmascriptModuleRenameModule {
284    #[turbo_tasks::function]
285    async fn merge(
286        self: Vc<Self>,
287        modules: Vc<MergeableModulesExposed>,
288        entry_points: Vc<MergeableModules>,
289    ) -> Result<Vc<Box<dyn ChunkableModule>>> {
290        Ok(Vc::upcast(
291            *MergedEcmascriptModule::new(
292                modules,
293                entry_points,
294                EcmascriptOptions::default().resolved_cell(),
295            )
296            .await?,
297        ))
298    }
299}