turbopack_core/
asset.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, Vc};
4use turbo_tasks_fs::{
5    FileContent, FileJsonContent, FileLinesContent, FileSystemPath, LinkContent, LinkType,
6};
7use turbo_tasks_hash::Xxh3Hash64Hasher;
8
9use crate::version::{VersionedAssetContent, VersionedContent};
10
11/// An asset. It also forms a graph when following [Asset::references].
12#[turbo_tasks::value_trait]
13pub trait Asset {
14    /// The content of the [Asset].
15    #[turbo_tasks::function]
16    fn content(self: Vc<Self>) -> Vc<AssetContent>;
17
18    /// The content of the [Asset] alongside its version.
19    #[turbo_tasks::function]
20    fn versioned_content(self: Vc<Self>) -> Result<Vc<Box<dyn VersionedContent>>> {
21        Ok(Vc::upcast(VersionedAssetContent::new(self.content())))
22    }
23}
24
25#[turbo_tasks::value(shared)]
26#[derive(Clone)]
27pub enum AssetContent {
28    File(ResolvedVc<FileContent>),
29    // for the relative link, the target is raw value read from the link
30    // for the absolute link, the target is stripped of the root path while reading
31    // See [LinkContent::Link] for more details.
32    Redirect { target: RcStr, link_type: LinkType },
33}
34
35#[turbo_tasks::value_impl]
36impl AssetContent {
37    #[turbo_tasks::function]
38    pub fn file(file: ResolvedVc<FileContent>) -> Result<Vc<Self>> {
39        Ok(AssetContent::File(file).cell())
40    }
41
42    #[turbo_tasks::function]
43    pub fn parse_json(&self) -> Vc<FileJsonContent> {
44        match self {
45            AssetContent::File(content) => content.parse_json(),
46            AssetContent::Redirect { .. } => {
47                FileJsonContent::unparsable(rcstr!("a redirect can't be parsed as json")).cell()
48            }
49        }
50    }
51
52    #[turbo_tasks::function]
53    pub fn file_content(&self) -> Vc<FileContent> {
54        match self {
55            AssetContent::File(content) => **content,
56            AssetContent::Redirect { .. } => FileContent::NotFound.cell(),
57        }
58    }
59
60    #[turbo_tasks::function]
61    pub fn lines(&self) -> Vc<FileLinesContent> {
62        match self {
63            AssetContent::File(content) => content.lines(),
64            AssetContent::Redirect { .. } => FileLinesContent::Unparsable.cell(),
65        }
66    }
67
68    #[turbo_tasks::function]
69    pub fn len(&self) -> Vc<Option<u64>> {
70        match self {
71            AssetContent::File(content) => content.len(),
72            AssetContent::Redirect { .. } => Vc::cell(None),
73        }
74    }
75
76    #[turbo_tasks::function]
77    pub fn parse_json_with_comments(&self) -> Vc<FileJsonContent> {
78        match self {
79            AssetContent::File(content) => content.parse_json_with_comments(),
80            AssetContent::Redirect { .. } => {
81                FileJsonContent::unparsable(rcstr!("a redirect can't be parsed as json")).cell()
82            }
83        }
84    }
85
86    #[turbo_tasks::function]
87    pub async fn write(&self, path: FileSystemPath) -> Result<()> {
88        match self {
89            AssetContent::File(file) => {
90                path.write(**file).as_side_effect().await?;
91            }
92            AssetContent::Redirect { target, link_type } => {
93                path.write_symbolic_link_dir(
94                    LinkContent::Link {
95                        target: target.clone(),
96                        link_type: *link_type,
97                    }
98                    .cell(),
99                )
100                .as_side_effect()
101                .await?;
102            }
103        }
104        Ok(())
105    }
106
107    #[turbo_tasks::function]
108    pub async fn hash(&self) -> Result<Vc<u64>> {
109        match self {
110            AssetContent::File(content) => Ok(content.hash()),
111            AssetContent::Redirect { target, link_type } => {
112                use turbo_tasks_hash::DeterministicHash;
113                let mut hasher = Xxh3Hash64Hasher::new();
114                target.deterministic_hash(&mut hasher);
115                link_type.deterministic_hash(&mut hasher);
116                Ok(Vc::cell(hasher.finish()))
117            }
118        }
119    }
120}