turbopack_ecmascript/references/
raw.rs

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