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,
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 origin_fn_name: RcStr,
32}
33
34#[turbo_tasks::value_impl]
35impl FileSourceReference {
36 #[turbo_tasks::function]
37 pub fn new(
38 context_dir: FileSystemPath,
39 path: ResolvedVc<Pattern>,
40 collect_affecting_sources: bool,
41 issue_source: IssueSource,
42 origin_fn_name: RcStr,
43 ) -> Vc<Self> {
44 Self::cell(FileSourceReference {
45 context_dir,
46 path,
47 collect_affecting_sources,
48 issue_source,
49 origin_fn_name,
50 })
51 }
52}
53
54#[turbo_tasks::value_impl]
55impl ModuleReference for FileSourceReference {
56 #[turbo_tasks::function]
57 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
58 let span = tracing::info_span!(
59 "trace file",
60 pattern = display(self.path.to_string().await?)
61 );
62 async {
63 let result = resolve_raw(
64 self.context_dir.clone(),
65 *self.path,
66 self.collect_affecting_sources,
67 false,
68 )
69 .as_raw_module_result()
70 .to_resolved()
71 .await?;
72 check_and_emit_too_many_matches_warning(
73 *result,
74 self.issue_source,
75 self.context_dir.clone(),
76 self.path,
77 )
78 .await?;
79
80 Ok(*result)
81 }
82 .instrument(span)
83 .await
84 }
85
86 fn chunking_type(&self) -> Option<ChunkingType> {
87 Some(ChunkingType::Traced {
88 mode: TracedMode::Entry,
89 })
90 }
91
92 fn source(&self) -> Option<IssueSource> {
93 Some(self.issue_source)
94 }
95}
96
97#[turbo_tasks::value_impl]
98impl DynamicTraceReference for FileSourceReference {
99 fn origin_fn_name(&self) -> RcStr {
100 self.origin_fn_name.clone()
101 }
102}
103
104#[turbo_tasks::value]
105#[derive(Hash, Debug, ValueToString)]
106#[value_to_string("directory assets {path}")]
107pub struct DirAssetReference {
108 context_dir: FileSystemPath,
109 path: ResolvedVc<Pattern>,
110 issue_source: IssueSource,
111 origin_fn_name: RcStr,
114}
115
116#[turbo_tasks::value_impl]
117impl DirAssetReference {
118 #[turbo_tasks::function]
119 pub fn new(
120 context_dir: FileSystemPath,
121 path: ResolvedVc<Pattern>,
122 issue_source: IssueSource,
123 origin_fn_name: RcStr,
124 ) -> Vc<Self> {
125 Self::cell(DirAssetReference {
126 context_dir,
127 path,
128 issue_source,
129 origin_fn_name,
130 })
131 }
132}
133
134async fn resolve_reference_from_dir(
135 context_dir: FileSystemPath,
136 path: Vc<Pattern>,
137) -> Result<Vc<ModuleResolveResult>> {
138 let path_ref = path.await?;
139 let (abs_path, rel_path) = path_ref.split_could_match("/ROOT/");
140 if abs_path.is_none() && rel_path.is_none() {
141 return Ok(*ModuleResolveResult::unresolvable());
142 }
143
144 let abs_matches = if let Some(abs_path) = &abs_path {
145 Some(
146 read_matches(
147 context_dir.root().owned().await?,
148 rcstr!("/ROOT/"),
149 true,
150 Pattern::new(abs_path.or_any_nested_file()),
151 )
152 .await?,
153 )
154 } else {
155 None
156 };
157 let rel_matches = if let Some(rel_path) = &rel_path {
158 Some(
159 read_matches(
160 context_dir,
161 rcstr!(""),
162 true,
163 Pattern::new(rel_path.or_any_nested_file()),
164 )
165 .await?,
166 )
167 } else {
168 None
169 };
170
171 let matches = abs_matches
172 .iter()
173 .flatten()
174 .chain(rel_matches.iter().flatten());
175
176 let mut affecting_sources = Vec::new();
177 let mut results = Vec::new();
178 for pat_match in matches {
179 match pat_match {
180 PatternMatch::File(matched_path, file) => {
181 let realpath = file.realpath_with_links().await?;
182 for symlink in &realpath.symlinks {
183 affecting_sources.push(ResolvedVc::upcast(
184 FileSource::new(symlink.clone()).to_resolved().await?,
185 ));
186 }
187 let path: FileSystemPath = match &realpath.path_result {
188 Ok(path) => path.clone(),
189 Err(error) => bail!(error.clone()),
190 };
191 results.push((
192 RequestKey::new(matched_path.clone()),
193 ResolvedVc::upcast(
194 RawModule::new(Vc::upcast(FileSource::new(path.clone())))
195 .to_resolved()
196 .await?,
197 ),
198 ));
199 }
200 PatternMatch::Directory(..) => {}
201 }
202 }
203 Ok(*ModuleResolveResult::modules_with_affecting_sources(
204 results,
205 affecting_sources,
206 ))
207}
208
209#[turbo_tasks::value_impl]
210impl ModuleReference for DirAssetReference {
211 #[turbo_tasks::function]
212 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
213 let span = tracing::info_span!(
214 "trace directory",
215 pattern = display(self.path.to_string().await?)
216 );
217 async {
218 let result = resolve_reference_from_dir(self.context_dir.clone(), *self.path).await?;
219 check_and_emit_too_many_matches_warning(
220 result,
221 self.issue_source,
222 self.context_dir.clone(),
223 self.path,
224 )
225 .await?;
226 Ok(result)
227 }
228 .instrument(span)
229 .await
230 }
231
232 fn chunking_type(&self) -> Option<ChunkingType> {
233 Some(ChunkingType::Traced {
234 mode: TracedMode::Entry,
235 })
236 }
237
238 fn source(&self) -> Option<IssueSource> {
239 Some(self.issue_source)
240 }
241}
242
243#[turbo_tasks::value_impl]
244impl DynamicTraceReference for DirAssetReference {
245 fn origin_fn_name(&self) -> RcStr {
246 self.origin_fn_name.clone()
247 }
248}