Skip to main content

turbopack_core/
file_source.rs

1use anyhow::{Result, bail};
2use turbo_rcstr::RcStr;
3use turbo_tasks::Vc;
4use turbo_tasks_fs::{
5    FileContent, FileSystemEntryType, FileSystemPath, LinkContent, LinkTarget, WriteLinkContent,
6    WriteLinkTarget, WriteLinkTargetType,
7};
8
9use crate::{
10    asset::{Asset, AssetContent},
11    ident::AssetIdent,
12    source::Source,
13};
14
15/// The raw [Source]. It represents raw content from a path without any
16/// references to other [Source]s.
17#[turbo_tasks::value]
18pub struct FileSource {
19    path: FileSystemPath,
20    query: RcStr,
21    fragment: RcStr,
22}
23
24impl FileSource {
25    pub fn new(path: FileSystemPath) -> Vc<Self> {
26        FileSource::new_with_query_and_fragment(path, RcStr::default(), RcStr::default())
27    }
28    pub fn new_with_query(path: FileSystemPath, query: RcStr) -> Vc<Self> {
29        FileSource::new_with_query_and_fragment(path, query, RcStr::default())
30    }
31}
32
33#[turbo_tasks::value_impl]
34impl FileSource {
35    #[turbo_tasks::function]
36    pub fn new_with_query_and_fragment(
37        path: FileSystemPath,
38        query: RcStr,
39        fragment: RcStr,
40    ) -> Vc<Self> {
41        Self::cell(FileSource {
42            path,
43            query,
44            fragment,
45        })
46    }
47}
48
49#[turbo_tasks::value_impl]
50impl Source for FileSource {
51    #[turbo_tasks::function]
52    fn ident(&self) -> Vc<AssetIdent> {
53        AssetIdent::from_path(self.path.clone())
54            .with_query(self.query.clone())
55            .with_fragment(self.fragment.clone())
56            .into_vc()
57    }
58
59    #[turbo_tasks::function]
60    fn description(&self) -> Vc<RcStr> {
61        Vc::cell(format!("file content of {}", self.path).into())
62    }
63}
64
65#[turbo_tasks::value_impl]
66impl Asset for FileSource {
67    #[turbo_tasks::function]
68    async fn content(&self) -> Result<Vc<AssetContent>> {
69        let file_type = &*self.path.get_type().await?;
70        match file_type {
71            FileSystemEntryType::Symlink => match &*self.path.read_link().await? {
72                LinkContent::Link { target } => {
73                    let write_target = match target {
74                        LinkTarget::Absolute { resolved } => {
75                            WriteLinkTarget::Absolute(resolved.path.clone())
76                        }
77                        LinkTarget::Relative { raw, .. } => WriteLinkTarget::Relative(raw.clone()),
78                    };
79                    let target_fs_path = target.file_system_path();
80                    let write_target_type = match *target_fs_path.get_type().await? {
81                        FileSystemEntryType::Directory => {
82                            WriteLinkTargetType::DirectoryOrJunctionPoint
83                        }
84                        FileSystemEntryType::Symlink
85                            if *target_fs_path.is_junction_point().await? =>
86                        {
87                            WriteLinkTargetType::DirectoryOrJunctionPoint
88                        }
89                        _ => WriteLinkTargetType::FileNonPortable,
90                    };
91                    Ok(AssetContent::Redirect(WriteLinkContent {
92                        target: write_target,
93                        target_type: write_target_type,
94                    })
95                    .cell())
96                }
97                _ => bail!("Invalid symlink"),
98            },
99            FileSystemEntryType::File => {
100                Ok(AssetContent::File(self.path.read().to_resolved().await?).cell())
101            }
102            FileSystemEntryType::NotFound => {
103                Ok(AssetContent::File(FileContent::NotFound.resolved_cell()).cell())
104            }
105            _ => bail!("Invalid file type {:?}", file_type),
106        }
107    }
108}