Skip to main content

turbopack_core/source_map/
source_map_asset.rs

1use anyhow::Result;
2use bincode::{Decode, Encode};
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{
5    FxIndexSet, NonLocalValue, ResolvedVc, ValueToString, Vc, debug::ValueDebugFormat,
6};
7use turbo_tasks_fs::{File, FileContent, FileSystemPath};
8
9use crate::{
10    asset::{Asset, AssetContent},
11    chunk::ChunkingContext,
12    ident::AssetIdent,
13    introspect::{Introspectable, IntrospectableChildren},
14    output::{OutputAsset, OutputAssetsReference},
15    source_map::{GenerateSourceMap, SourceMap},
16};
17
18#[derive(PartialEq, Eq, NonLocalValue, ValueDebugFormat, Encode, Decode)]
19enum PathType {
20    Fixed {
21        path: FileSystemPath,
22    },
23    FromIdent {
24        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
25        ident_for_path: ResolvedVc<AssetIdent>,
26    },
27}
28
29/// Represents the source map of an ecmascript asset.
30#[turbo_tasks::value]
31pub struct SourceMapAsset {
32    path_ty: PathType,
33    generate_source_map: ResolvedVc<Box<dyn GenerateSourceMap>>,
34}
35
36#[turbo_tasks::value_impl]
37impl SourceMapAsset {
38    #[turbo_tasks::function]
39    pub fn new(
40        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
41        ident_for_path: ResolvedVc<AssetIdent>,
42        generate_source_map: ResolvedVc<Box<dyn GenerateSourceMap>>,
43    ) -> Vc<Self> {
44        SourceMapAsset {
45            path_ty: PathType::FromIdent {
46                chunking_context,
47                ident_for_path,
48            },
49            generate_source_map,
50        }
51        .cell()
52    }
53
54    #[turbo_tasks::function]
55    pub fn new_fixed(
56        path: FileSystemPath,
57        generate_source_map: ResolvedVc<Box<dyn GenerateSourceMap>>,
58    ) -> Vc<Self> {
59        SourceMapAsset {
60            path_ty: PathType::Fixed { path },
61            generate_source_map,
62        }
63        .cell()
64    }
65}
66
67#[turbo_tasks::value_impl]
68impl OutputAssetsReference for SourceMapAsset {}
69
70#[turbo_tasks::value_impl]
71impl OutputAsset for SourceMapAsset {
72    #[turbo_tasks::function]
73    async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
74        // NOTE(alexkirsz) We used to include the asset's version id in the path,
75        // but this caused `all_assets_map` to be recomputed on every change.
76        let this = self.await?;
77        Ok(match &this.path_ty {
78            PathType::FromIdent {
79                chunking_context,
80                ident_for_path,
81            } => chunking_context
82                .chunk_path(
83                    Some(Vc::upcast(self)),
84                    **ident_for_path,
85                    None,
86                    rcstr!(".js"),
87                )
88                .await?
89                .append(".map")?
90                .cell(),
91            PathType::Fixed { path } => path.append(".map")?.cell(),
92        })
93    }
94}
95
96#[turbo_tasks::value_impl]
97impl Asset for SourceMapAsset {
98    #[turbo_tasks::function]
99    async fn content(&self) -> Result<Vc<AssetContent>> {
100        let content = self.generate_source_map.generate_source_map();
101        if content.await?.is_content() {
102            Ok(AssetContent::file(content))
103        } else {
104            Ok(AssetContent::file(
105                FileContent::Content(File::from(SourceMap::empty_rope())).cell(),
106            ))
107        }
108    }
109}
110
111#[turbo_tasks::value_impl]
112impl Introspectable for SourceMapAsset {
113    #[turbo_tasks::function]
114    fn ty(&self) -> Vc<RcStr> {
115        Vc::cell(rcstr!("source map"))
116    }
117
118    #[turbo_tasks::function]
119    fn title(self: Vc<Self>) -> Vc<RcStr> {
120        self.path().to_string()
121    }
122
123    #[turbo_tasks::function]
124    fn details(&self) -> Vc<RcStr> {
125        Vc::cell(rcstr!("source map of an asset"))
126    }
127
128    #[turbo_tasks::function]
129    fn children(&self) -> Result<Vc<IntrospectableChildren>> {
130        let mut children = FxIndexSet::default();
131        if let Some(asset) =
132            ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.generate_source_map)
133        {
134            children.insert((rcstr!("asset"), asset));
135        }
136        Ok(Vc::cell(children))
137    }
138}