turbopack_core/source_map/
source_map_asset.rs

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