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};
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 { .. } => Ok(FileJsonContent::unparsable(rcstr!(
47                "a redirect can't be parsed as json"
48            ))
49            .cell()),
50        }
51    }
52
53    #[turbo_tasks::function]
54    pub async fn file_content(self: Vc<Self>) -> Result<Vc<FileContent>> {
55        let this = self.await?;
56        match &*this {
57            AssetContent::File(content) => Ok(**content),
58            AssetContent::Redirect { .. } => Ok(FileContent::NotFound.cell()),
59        }
60    }
61
62    #[turbo_tasks::function]
63    pub async fn lines(self: Vc<Self>) -> Result<Vc<FileLinesContent>> {
64        let this = self.await?;
65        match &*this {
66            AssetContent::File(content) => Ok(content.lines()),
67            AssetContent::Redirect { .. } => Ok(FileLinesContent::Unparsable.cell()),
68        }
69    }
70
71    #[turbo_tasks::function]
72    pub async fn len(self: Vc<Self>) -> Result<Vc<Option<u64>>> {
73        let this = self.await?;
74        match &*this {
75            AssetContent::File(content) => Ok(content.len()),
76            AssetContent::Redirect { .. } => Ok(Vc::cell(None)),
77        }
78    }
79
80    #[turbo_tasks::function]
81    pub async fn parse_json_with_comments(self: Vc<Self>) -> Result<Vc<FileJsonContent>> {
82        let this = self.await?;
83        match &*this {
84            AssetContent::File(content) => Ok(content.parse_json_with_comments()),
85            AssetContent::Redirect { .. } => Ok(FileJsonContent::unparsable(rcstr!(
86                "a redirect can't be parsed as json"
87            ))
88            .cell()),
89        }
90    }
91
92    #[turbo_tasks::function]
93    pub async fn write(self: Vc<Self>, path: FileSystemPath) -> Result<()> {
94        let this = self.await?;
95        match &*this {
96            AssetContent::File(file) => {
97                path.write(**file).as_side_effect().await?;
98            }
99            AssetContent::Redirect { target, link_type } => {
100                path.write_link(
101                    LinkContent::Link {
102                        target: target.clone(),
103                        link_type: *link_type,
104                    }
105                    .cell(),
106                )
107                .as_side_effect()
108                .await?;
109            }
110        }
111        Ok(())
112    }
113}