turbopack_ecmascript/references/
raw.rs1use anyhow::{Result, bail};
2use tracing::Instrument;
3use turbo_rcstr::rcstr;
4use turbo_tasks::{ResolvedVc, ValueToString, Vc};
5use turbo_tasks_fs::FileSystemPath;
6use turbopack_core::{
7 chunk::ChunkingType,
8 file_source::FileSource,
9 issue::IssueSource,
10 raw_module::RawModule,
11 reference::ModuleReference,
12 resolve::{
13 ModuleResolveResult, RequestKey,
14 pattern::{Pattern, PatternMatch, read_matches},
15 resolve_raw,
16 },
17};
18
19use crate::references::util::check_and_emit_too_many_matches_warning;
20
21#[turbo_tasks::value]
22#[derive(Hash, Debug, ValueToString)]
23#[value_to_string("raw asset {path}")]
24pub struct FileSourceReference {
25 context_dir: FileSystemPath,
26 path: ResolvedVc<Pattern>,
27 collect_affecting_sources: bool,
28 issue_source: IssueSource,
29}
30
31#[turbo_tasks::value_impl]
32impl FileSourceReference {
33 #[turbo_tasks::function]
34 pub fn new(
35 context_dir: FileSystemPath,
36 path: ResolvedVc<Pattern>,
37 collect_affecting_sources: bool,
38 issue_source: IssueSource,
39 ) -> Vc<Self> {
40 Self::cell(FileSourceReference {
41 context_dir,
42 path,
43 collect_affecting_sources,
44 issue_source,
45 })
46 }
47}
48
49#[turbo_tasks::value_impl]
50impl ModuleReference for FileSourceReference {
51 #[turbo_tasks::function]
52 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
53 let span = tracing::info_span!(
54 "trace file",
55 pattern = display(self.path.to_string().await?)
56 );
57 async {
58 let result = resolve_raw(
59 self.context_dir.clone(),
60 *self.path,
61 self.collect_affecting_sources,
62 false,
63 )
64 .as_raw_module_result()
65 .resolve()
66 .await?;
67 check_and_emit_too_many_matches_warning(
68 result,
69 self.issue_source,
70 self.context_dir.clone(),
71 self.path,
72 )
73 .await?;
74
75 Ok(result)
76 }
77 .instrument(span)
78 .await
79 }
80
81 fn chunking_type(&self) -> Option<ChunkingType> {
82 Some(ChunkingType::Traced)
83 }
84}
85
86#[turbo_tasks::value]
87#[derive(Hash, Debug, ValueToString)]
88#[value_to_string("directory assets {path}")]
89pub struct DirAssetReference {
90 context_dir: FileSystemPath,
91 path: ResolvedVc<Pattern>,
92 issue_source: IssueSource,
93}
94
95#[turbo_tasks::value_impl]
96impl DirAssetReference {
97 #[turbo_tasks::function]
98 pub fn new(
99 context_dir: FileSystemPath,
100 path: ResolvedVc<Pattern>,
101 issue_source: IssueSource,
102 ) -> Vc<Self> {
103 Self::cell(DirAssetReference {
104 context_dir,
105 path,
106 issue_source,
107 })
108 }
109}
110
111async fn resolve_reference_from_dir(
112 context_dir: FileSystemPath,
113 path: Vc<Pattern>,
114) -> Result<Vc<ModuleResolveResult>> {
115 let path_ref = path.await?;
116 let (abs_path, rel_path) = path_ref.split_could_match("/ROOT/");
117 if abs_path.is_none() && rel_path.is_none() {
118 return Ok(*ModuleResolveResult::unresolvable());
119 }
120
121 let abs_matches = if let Some(abs_path) = &abs_path {
122 Some(
123 read_matches(
124 context_dir.root().owned().await?,
125 rcstr!("/ROOT/"),
126 true,
127 Pattern::new(abs_path.or_any_nested_file()),
128 )
129 .await?,
130 )
131 } else {
132 None
133 };
134 let rel_matches = if let Some(rel_path) = &rel_path {
135 Some(
136 read_matches(
137 context_dir,
138 rcstr!(""),
139 true,
140 Pattern::new(rel_path.or_any_nested_file()),
141 )
142 .await?,
143 )
144 } else {
145 None
146 };
147
148 let matches = abs_matches
149 .into_iter()
150 .flatten()
151 .chain(rel_matches.into_iter().flatten());
152
153 let mut affecting_sources = Vec::new();
154 let mut results = Vec::new();
155 for pat_match in matches {
156 match pat_match {
157 PatternMatch::File(matched_path, file) => {
158 let realpath = file.realpath_with_links().await?;
159 for symlink in &realpath.symlinks {
160 affecting_sources.push(ResolvedVc::upcast(
161 FileSource::new(symlink.clone()).to_resolved().await?,
162 ));
163 }
164 let path: FileSystemPath = match &realpath.path_result {
165 Ok(path) => path.clone(),
166 Err(e) => bail!(e.as_error_message(file, &realpath).await?),
167 };
168 results.push((
169 RequestKey::new(matched_path.clone()),
170 ResolvedVc::upcast(
171 RawModule::new(Vc::upcast(FileSource::new(path)))
172 .to_resolved()
173 .await?,
174 ),
175 ));
176 }
177 PatternMatch::Directory(..) => {}
178 }
179 }
180 Ok(*ModuleResolveResult::modules_with_affecting_sources(
181 results,
182 affecting_sources,
183 ))
184}
185
186#[turbo_tasks::value_impl]
187impl ModuleReference for DirAssetReference {
188 #[turbo_tasks::function]
189 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
190 let span = tracing::info_span!(
191 "trace directory",
192 pattern = display(self.path.to_string().await?)
193 );
194 async {
195 let result = resolve_reference_from_dir(self.context_dir.clone(), *self.path).await?;
196 check_and_emit_too_many_matches_warning(
197 result,
198 self.issue_source,
199 self.context_dir.clone(),
200 self.path,
201 )
202 .await?;
203 Ok(result)
204 }
205 .instrument(span)
206 .await
207 }
208
209 fn chunking_type(&self) -> Option<ChunkingType> {
210 Some(ChunkingType::Traced)
211 }
212}