turbopack_core/
asset.rs

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