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