turbopack_core/
file_source.rs1use 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#[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}