Skip to main content

turbopack_ecmascript/rename/
module.rs

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