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