turbopack_ecmascript/references/
raw.rs1use anyhow::{Result, bail};
2use tracing::Instrument;
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::{ResolvedVc, ValueToString, Vc};
5use turbo_tasks_fs::FileSystemPath;
6use turbopack_core::{
7 chunk::{ChunkingType, TracedMode},
8 file_source::FileSource,
9 issue::IssueSource,
10 raw_module::RawModule,
11 reference::{DynamicTraceReference, ModuleReference},
12 resolve::{
13 ModuleResolveResult, RequestKey, ResolveResult,
14 pattern::{Pattern, PatternMatch, read_matches},
15 resolve_raw,
16 },
17};
18
19use crate::references::util::check_and_emit_too_many_matches_warning;
20
21pub async fn resolve_static_files(
24 context_dir: &Option<FileSystemPath>,
25 path: ResolvedVc<Pattern>,
26 collect_affecting_sources: bool,
27) -> Result<Option<Vc<ResolveResult>>> {
28 let Some(context_dir) = context_dir else {
29 return Ok(None);
30 };
31 let Some(static_pattern) = path.await?.filter_static() else {
32 return Ok(None);
33 };
34 Ok(Some(resolve_raw(
35 context_dir.clone(),
36 Pattern::new(static_pattern),
37 collect_affecting_sources,
38 true,
39 )))
40}
41
42#[turbo_tasks::value]
43#[derive(Hash, Debug, ValueToString)]
44#[value_to_string("raw asset {path}")]
45pub struct FileSourceReference {
46 static_files_only_context_dir: Option<FileSystemPath>,
47 fallback_context_dir: FileSystemPath,
48 path: ResolvedVc<Pattern>,
49 collect_affecting_sources: bool,
50 issue_source: IssueSource,
51 origin_fn_name: RcStr,
54}
55
56#[turbo_tasks::value_impl]
57impl FileSourceReference {
58 #[turbo_tasks::function]
59 pub fn new(
60 static_files_only_context_dir: Option<FileSystemPath>,
61 fallback_context_dir: FileSystemPath,
62 path: ResolvedVc<Pattern>,
63 collect_affecting_sources: bool,
64 issue_source: IssueSource,
65 origin_fn_name: RcStr,
66 ) -> Vc<Self> {
67 Self::cell(FileSourceReference {
68 static_files_only_context_dir,
69 fallback_context_dir,
70 path,
71 collect_affecting_sources,
72 issue_source,
73 origin_fn_name,
74 })
75 }
76}
77
78#[turbo_tasks::value_impl]
79impl ModuleReference for FileSourceReference {
80 #[turbo_tasks::function]
81 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
82 let span = tracing::info_span!(
83 "trace file",
84 pattern = display(self.path.to_string().await?)
85 );
86 async {
87 let fallback = resolve_raw(
88 self.fallback_context_dir.clone(),
89 *self.path,
90 self.collect_affecting_sources,
91 false,
92 )
93 .as_raw_module_result();
94 let result = if let Some(static_files) = resolve_static_files(
95 &self.static_files_only_context_dir,
96 self.path,
97 self.collect_affecting_sources,
98 )
99 .await?
100 {
101 ModuleResolveResult::concat(vec![static_files.as_raw_module_result(), fallback])
102 } else {
103 fallback
104 };
105 check_and_emit_too_many_matches_warning(
106 result,
107 self.issue_source,
108 self.fallback_context_dir.clone(),
109 self.path,
110 )
111 .await?;
112
113 Ok(result)
114 }
115 .instrument(span)
116 .await
117 }
118
119 fn chunking_type(&self) -> Option<ChunkingType> {
120 Some(ChunkingType::Traced {
121 mode: TracedMode::Entry,
122 })
123 }
124
125 fn source(&self) -> Option<IssueSource> {
126 Some(self.issue_source)
127 }
128}
129
130#[turbo_tasks::value_impl]
131impl DynamicTraceReference for FileSourceReference {
132 fn origin_fn_name(&self) -> RcStr {
133 self.origin_fn_name.clone()
134 }
135}
136
137#[turbo_tasks::value]
138#[derive(Hash, Debug, ValueToString)]
139#[value_to_string("directory assets {path}")]
140pub struct DirAssetReference {
141 static_files_only_context_dir: Option<FileSystemPath>,
142 fallback_context_dir: FileSystemPath,
143 path: ResolvedVc<Pattern>,
144 issue_source: IssueSource,
145 origin_fn_name: RcStr,
148}
149
150#[turbo_tasks::value_impl]
151impl DirAssetReference {
152 #[turbo_tasks::function]
153 pub fn new(
154 static_files_only_context_dir: Option<FileSystemPath>,
155 fallback_context_dir: FileSystemPath,
156 path: ResolvedVc<Pattern>,
157 issue_source: IssueSource,
158 origin_fn_name: RcStr,
159 ) -> Vc<Self> {
160 Self::cell(DirAssetReference {
161 static_files_only_context_dir,
162 fallback_context_dir,
163 path,
164 issue_source,
165 origin_fn_name,
166 })
167 }
168}
169
170async fn resolve_reference_from_dir(
171 context_dir: FileSystemPath,
172 path: Vc<Pattern>,
173) -> Result<Vc<ModuleResolveResult>> {
174 let path_ref = path.await?;
175 let (abs_path, rel_path) = path_ref.split_could_match("/ROOT/");
176 if abs_path.is_none() && rel_path.is_none() {
177 return Ok(*ModuleResolveResult::unresolvable());
178 }
179
180 let abs_matches = if let Some(abs_path) = &abs_path {
181 Some(
182 read_matches(
183 context_dir.root().owned().await?,
184 rcstr!("/ROOT/"),
185 true,
186 Pattern::new(abs_path.or_any_nested_file()),
187 )
188 .await?,
189 )
190 } else {
191 None
192 };
193 let rel_matches = if let Some(rel_path) = &rel_path {
194 Some(
195 read_matches(
196 context_dir,
197 rcstr!(""),
198 true,
199 Pattern::new(rel_path.or_any_nested_file()),
200 )
201 .await?,
202 )
203 } else {
204 None
205 };
206
207 let matches = abs_matches
208 .iter()
209 .flatten()
210 .chain(rel_matches.iter().flatten());
211
212 let mut affecting_sources = Vec::new();
213 let mut results = Vec::new();
214 for pat_match in matches {
215 match pat_match {
216 PatternMatch::File(matched_path, file) => {
217 let realpath = file.realpath_with_links().await?;
218 for symlink in &realpath.symlinks {
219 affecting_sources.push(ResolvedVc::upcast(
220 FileSource::new(symlink.clone()).to_resolved().await?,
221 ));
222 }
223 let path: FileSystemPath = match &realpath.path_result {
224 Ok(path) => path.clone(),
225 Err(error) => bail!(error.clone()),
226 };
227 results.push((
228 RequestKey::new(matched_path.clone()),
229 ResolvedVc::upcast(
230 RawModule::new(Vc::upcast(FileSource::new(path.clone())))
231 .to_resolved()
232 .await?,
233 ),
234 ));
235 }
236 PatternMatch::Directory(..) => {}
237 }
238 }
239 Ok(*ModuleResolveResult::modules_with_affecting_sources(
240 results,
241 affecting_sources,
242 ))
243}
244
245#[turbo_tasks::value_impl]
246impl ModuleReference for DirAssetReference {
247 #[turbo_tasks::function]
248 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
249 let span = tracing::info_span!(
250 "trace directory",
251 pattern = display(self.path.to_string().await?)
252 );
253 async {
254 let fallback =
255 resolve_reference_from_dir(self.fallback_context_dir.clone(), *self.path).await?;
256 let result = if let Some(static_files) =
257 resolve_static_files(&self.static_files_only_context_dir, self.path, true).await?
258 {
259 ModuleResolveResult::concat(vec![static_files.as_raw_module_result(), fallback])
260 } else {
261 fallback
262 };
263 check_and_emit_too_many_matches_warning(
264 result,
265 self.issue_source,
266 self.fallback_context_dir.clone(),
267 self.path,
268 )
269 .await?;
270 Ok(result)
271 }
272 .instrument(span)
273 .await
274 }
275
276 fn chunking_type(&self) -> Option<ChunkingType> {
277 Some(ChunkingType::Traced {
278 mode: TracedMode::Entry,
279 })
280 }
281
282 fn source(&self) -> Option<IssueSource> {
283 Some(self.issue_source)
284 }
285}
286
287#[turbo_tasks::value_impl]
288impl DynamicTraceReference for DirAssetReference {
289 fn origin_fn_name(&self) -> RcStr {
290 self.origin_fn_name.clone()
291 }
292}