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