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, TracedMode},
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 .to_resolved()
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 mode: TracedMode::Entry,
84 })
85 }
86
87 fn source(&self) -> Option<IssueSource> {
88 Some(self.issue_source)
89 }
90}
91
92#[turbo_tasks::value]
93#[derive(Hash, Debug, ValueToString)]
94#[value_to_string("directory assets {path}")]
95pub struct DirAssetReference {
96 context_dir: FileSystemPath,
97 path: ResolvedVc<Pattern>,
98 issue_source: IssueSource,
99}
100
101#[turbo_tasks::value_impl]
102impl DirAssetReference {
103 #[turbo_tasks::function]
104 pub fn new(
105 context_dir: FileSystemPath,
106 path: ResolvedVc<Pattern>,
107 issue_source: IssueSource,
108 ) -> Vc<Self> {
109 Self::cell(DirAssetReference {
110 context_dir,
111 path,
112 issue_source,
113 })
114 }
115}
116
117async fn resolve_reference_from_dir(
118 context_dir: FileSystemPath,
119 path: Vc<Pattern>,
120) -> Result<Vc<ModuleResolveResult>> {
121 let path_ref = path.await?;
122 let (abs_path, rel_path) = path_ref.split_could_match("/ROOT/");
123 if abs_path.is_none() && rel_path.is_none() {
124 return Ok(*ModuleResolveResult::unresolvable());
125 }
126
127 let abs_matches = if let Some(abs_path) = &abs_path {
128 Some(
129 read_matches(
130 context_dir.root().owned().await?,
131 rcstr!("/ROOT/"),
132 true,
133 Pattern::new(abs_path.or_any_nested_file()),
134 )
135 .await?,
136 )
137 } else {
138 None
139 };
140 let rel_matches = if let Some(rel_path) = &rel_path {
141 Some(
142 read_matches(
143 context_dir,
144 rcstr!(""),
145 true,
146 Pattern::new(rel_path.or_any_nested_file()),
147 )
148 .await?,
149 )
150 } else {
151 None
152 };
153
154 let matches = abs_matches
155 .iter()
156 .flatten()
157 .chain(rel_matches.iter().flatten());
158
159 let mut affecting_sources = Vec::new();
160 let mut results = Vec::new();
161 for pat_match in matches {
162 match pat_match {
163 PatternMatch::File(matched_path, file) => {
164 let realpath = file.realpath_with_links().await?;
165 for symlink in &realpath.symlinks {
166 affecting_sources.push(ResolvedVc::upcast(
167 FileSource::new(symlink.clone()).to_resolved().await?,
168 ));
169 }
170 let path: FileSystemPath = match &realpath.path_result {
171 Ok(path) => path.clone(),
172 Err(e) => bail!(e.as_error_message(file, &realpath).await?),
173 };
174 results.push((
175 RequestKey::new(matched_path.clone()),
176 ResolvedVc::upcast(
177 RawModule::new(Vc::upcast(FileSource::new(path.clone())))
178 .to_resolved()
179 .await?,
180 ),
181 ));
182 }
183 PatternMatch::Directory(..) => {}
184 }
185 }
186 Ok(*ModuleResolveResult::modules_with_affecting_sources(
187 results,
188 affecting_sources,
189 ))
190}
191
192#[turbo_tasks::value_impl]
193impl ModuleReference for DirAssetReference {
194 #[turbo_tasks::function]
195 async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
196 let span = tracing::info_span!(
197 "trace directory",
198 pattern = display(self.path.to_string().await?)
199 );
200 async {
201 let result = resolve_reference_from_dir(self.context_dir.clone(), *self.path).await?;
202 check_and_emit_too_many_matches_warning(
203 result,
204 self.issue_source,
205 self.context_dir.clone(),
206 self.path,
207 )
208 .await?;
209 Ok(result)
210 }
211 .instrument(span)
212 .await
213 }
214
215 fn chunking_type(&self) -> Option<ChunkingType> {
216 Some(ChunkingType::Traced {
217 mode: TracedMode::Entry,
218 })
219 }
220
221 fn source(&self) -> Option<IssueSource> {
222 Some(self.issue_source)
223 }
224}