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    fn ident(&self) -> Vc<AssetIdent> {
121        self.module.ident().with_part(self.part.clone())
122    }
123
124    #[turbo_tasks::function]
125    async fn references(self: Vc<Self>) -> Result<Vc<ModuleReferences>> {
126        let reference = self.await?.module_reference().await?;
127        Ok(Vc::cell(vec![ResolvedVc::upcast(reference)]))
128    }
129
130    #[turbo_tasks::function]
131    async fn is_self_async(self: Vc<Self>) -> Result<Vc<bool>> {
132        let async_module = self.async_module();
133        let references = self.references();
134        let is_self_async = async_module
135            .to_resolved()
136            .await?
137            .is_self_async(*references.to_resolved().await?)
138            .to_resolved()
139            .await?;
140        Ok(*is_self_async)
141    }
142
143    #[turbo_tasks::function]
144    fn side_effects(&self) -> Vc<ModuleSideEffects> {
145        // This just re-exports another import
146        ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
147    }
148}
149
150#[turbo_tasks::value_impl]
151impl Asset for EcmascriptModuleRenameModule {
152    #[turbo_tasks::function]
153    fn content(&self) -> Vc<AssetContent> {
154        let f = File::from("");
155
156        AssetContent::file(FileContent::Content(f).cell())
157    }
158}
159
160#[turbo_tasks::value_impl]
161impl EcmascriptAnalyzable for EcmascriptModuleRenameModule {
162    #[turbo_tasks::function]
163    fn analyze(&self) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
164        bail!("EcmascriptModuleRenameModule::analyze shouldn't be called");
165    }
166
167    #[turbo_tasks::function]
168    fn module_content_without_analysis(
169        &self,
170        _generate_source_map: bool,
171    ) -> Result<Vc<EcmascriptModuleContent>> {
172        bail!("EcmascriptModuleRenameModule::module_content_without_analysis shouldn't be called");
173    }
174
175    #[turbo_tasks::function]
176    async fn module_content_options(
177        self: ResolvedVc<Self>,
178        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
179        async_module_info: Option<ResolvedVc<AsyncModuleInfo>>,
180    ) -> Result<Vc<EcmascriptModuleContentOptions>> {
181        let reference = self.await?.module_reference().await?;
182
183        Ok(EcmascriptModuleContentOptions {
184            parsed: None,
185            module: ResolvedVc::upcast(self),
186            specified_module_type: SpecifiedModuleType::EcmaScript,
187            chunking_context,
188            references: self.references().to_resolved().await?,
189            part_references: vec![reference],
190            esm_references: EsmAssetReferences::empty().to_resolved().await?,
191            code_generation: CodeGens::empty().to_resolved().await?,
192            async_module: ResolvedVc::cell(Some(self.async_module().to_resolved().await?)),
193            // The facade module cannot generate source maps, because the inserted references
194            // contain spans from the original module, but the facade module itself doesn't have the
195            // original module's swc_common::SourceMap in `parsed`.
196            generate_source_map: false,
197            original_source_map: None,
198            exports: self.get_exports().to_resolved().await?,
199            async_module_info,
200        }
201        .cell())
202    }
203}
204
205#[turbo_tasks::value_impl]
206impl EcmascriptChunkPlaceable for EcmascriptModuleRenameModule {
207    #[turbo_tasks::function]
208    async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
209        let reference = self.module_reference().await?;
210
211        let export = match &self.part {
212            ModulePart::RenamedExport {
213                original_export,
214                export,
215            } => (
216                export.clone(),
217                EsmExport::ImportedBinding(
218                    ResolvedVc::upcast(reference),
219                    original_export.clone(),
220                    false,
221                ),
222            ),
223            ModulePart::RenamedNamespace { export } => (
224                export.clone(),
225                EsmExport::ImportedNamespace(ResolvedVc::upcast(reference)),
226            ),
227            _ => bail!("Unexpected ModulePart for EcmascriptModuleRenameModule"),
228        };
229
230        let exports = EsmExports {
231            exports: FrozenMap::from_unique_sorted_box(Box::new([export])),
232            star_exports: Vec::new(),
233        }
234        .resolved_cell();
235        Ok(EcmascriptExports::EsmExports(exports).cell())
236    }
237
238    #[turbo_tasks::function]
239    async fn get_async_module(self: Vc<Self>) -> Result<Vc<OptionAsyncModule>> {
240        Ok(Vc::cell(Some(self.async_module().to_resolved().await?)))
241    }
242
243    #[turbo_tasks::function]
244    async fn chunk_item_content(
245        self: Vc<Self>,
246        chunking_context: Vc<Box<dyn ChunkingContext>>,
247        _module_graph: Vc<ModuleGraph>,
248        async_module_info: Option<Vc<AsyncModuleInfo>>,
249        _estimated: bool,
250    ) -> Result<Vc<EcmascriptChunkItemContent>> {
251        let async_module_options = self.get_async_module().module_options(async_module_info);
252        let content = self.module_content(chunking_context, async_module_info);
253        Ok(EcmascriptChunkItemContent::new(
254            content,
255            chunking_context,
256            async_module_options,
257        ))
258    }
259}
260
261#[turbo_tasks::value_impl]
262impl ChunkableModule for EcmascriptModuleRenameModule {
263    #[turbo_tasks::function]
264    fn as_chunk_item(
265        self: ResolvedVc<Self>,
266        module_graph: ResolvedVc<ModuleGraph>,
267        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
268    ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
269        ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
270    }
271}
272
273#[turbo_tasks::value_impl]
274impl EvaluatableAsset for EcmascriptModuleRenameModule {}
275
276#[turbo_tasks::value_impl]
277impl MergeableModule for EcmascriptModuleRenameModule {
278    #[turbo_tasks::function]
279    async fn merge(
280        self: Vc<Self>,
281        modules: Vc<MergeableModulesExposed>,
282        entry_points: Vc<MergeableModules>,
283    ) -> Result<Vc<Box<dyn ChunkableModule>>> {
284        Ok(Vc::upcast(
285            *MergedEcmascriptModule::new(
286                modules,
287                entry_points,
288                EcmascriptOptions::default().resolved_cell(),
289            )
290            .await?,
291        ))
292    }
293}