Skip to main content

turbopack_ecmascript/references/
raw.rs

1use 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                /* force_in_lookup_dir */ 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}