1use std::hash::Hash;
2
3use anyhow::Result;
4use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc, turbobail};
5use turbo_tasks_fs::{FileSystemPath, WriteLinkContent};
6
7use crate::{
8 asset::{Asset, AssetContent},
9 module::Module,
10 output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
11 reference::referenced_modules_and_affecting_sources,
12};
13
14#[turbo_tasks::value]
17#[derive(Hash)]
18pub struct RebasedAsset {
19 module: ResolvedVc<Box<dyn Module>>,
20 input_dir: FileSystemPath,
21 output_dir: FileSystemPath,
22}
23
24#[turbo_tasks::value_impl]
25impl RebasedAsset {
26 #[turbo_tasks::function]
27 pub fn new(
28 module: ResolvedVc<Box<dyn Module>>,
29 input_dir: FileSystemPath,
30 output_dir: FileSystemPath,
31 ) -> Vc<Self> {
32 Self::cell(RebasedAsset {
33 module,
34 input_dir,
35 output_dir,
36 })
37 }
38}
39
40#[turbo_tasks::value_impl]
41impl OutputAssetsReference for RebasedAsset {
42 #[turbo_tasks::function]
43 async fn references(&self) -> Result<Vc<OutputAssetsWithReferenced>> {
44 let references = referenced_modules_and_affecting_sources(*self.module, false)
45 .await?
46 .iter()
47 .flat_map(|(_, ref_data)| ref_data.modules.iter())
48 .map(async |module| {
49 Ok(ResolvedVc::upcast(
50 RebasedAsset::new(**module, self.input_dir.clone(), self.output_dir.clone())
51 .to_resolved()
52 .await?,
53 ))
54 })
55 .try_join()
56 .await?;
57 Ok(OutputAssetsWithReferenced::from_assets(Vc::cell(
58 references,
59 )))
60 }
61}
62
63#[turbo_tasks::value_impl]
64impl OutputAsset for RebasedAsset {
65 #[turbo_tasks::function]
66 async fn path(&self) -> Result<Vc<FileSystemPath>> {
67 Ok(FileSystemPath::rebase(
68 self.module.ident().await?.path.clone(),
69 self.input_dir.clone(),
70 self.output_dir.clone(),
71 ))
72 }
73}
74
75#[turbo_tasks::value_impl]
76impl Asset for RebasedAsset {
77 #[turbo_tasks::function]
78 async fn content(&self) -> Result<Vc<AssetContent>> {
79 if let Some(source) = *self.module.source().await? {
80 let source_content = source.content();
81 let AssetContent::Redirect(redirect) = &*source_content.await? else {
82 return Ok(source_content);
83 };
84 let redirect = WriteLinkContent {
87 target: FileSystemPath::rebase(
88 redirect.target.clone(),
89 self.input_dir.clone(),
90 self.output_dir.clone(),
91 )
92 .owned()
93 .await?,
94 target_type: redirect.target_type.clone(),
95 };
96 Ok(AssetContent::Redirect(redirect).cell())
97 } else {
98 turbobail!("Module {} has no source", self.module.ident());
99 }
100 }
101}