turbopack_ecmascript/references/
node.rs

1use anyhow::Result;
2use either::Either;
3use turbo_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    raw_module::RawModule,
10    reference::ModuleReference,
11    resolve::{
12        ModuleResolveResult, RequestKey,
13        pattern::{Pattern, PatternMatch, read_matches},
14    },
15    source::Source,
16};
17
18#[turbo_tasks::value]
19#[derive(Hash, Clone, Debug)]
20pub struct PackageJsonReference {
21    pub package_json: ResolvedVc<FileSystemPath>,
22}
23
24#[turbo_tasks::value_impl]
25impl PackageJsonReference {
26    #[turbo_tasks::function]
27    pub fn new(package_json: ResolvedVc<FileSystemPath>) -> Vc<Self> {
28        Self::cell(PackageJsonReference { package_json })
29    }
30}
31
32#[turbo_tasks::value_impl]
33impl ModuleReference for PackageJsonReference {
34    #[turbo_tasks::function]
35    async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
36        Ok(*ModuleResolveResult::module(ResolvedVc::upcast(
37            RawModule::new(Vc::upcast(FileSource::new(*self.package_json)))
38                .to_resolved()
39                .await?,
40        )))
41    }
42}
43
44#[turbo_tasks::value_impl]
45impl ValueToString for PackageJsonReference {
46    #[turbo_tasks::function]
47    async fn to_string(&self) -> Result<Vc<RcStr>> {
48        Ok(Vc::cell(
49            format!("package.json {}", self.package_json.to_string().await?,).into(),
50        ))
51    }
52}
53
54#[turbo_tasks::value]
55#[derive(Hash, Debug)]
56pub struct DirAssetReference {
57    pub source: ResolvedVc<Box<dyn Source>>,
58    pub path: ResolvedVc<Pattern>,
59}
60
61#[turbo_tasks::value_impl]
62impl DirAssetReference {
63    #[turbo_tasks::function]
64    pub fn new(source: ResolvedVc<Box<dyn Source>>, path: ResolvedVc<Pattern>) -> Vc<Self> {
65        Self::cell(DirAssetReference { source, path })
66    }
67}
68
69#[turbo_tasks::function]
70async fn resolve_reference_from_dir(
71    parent_path: Vc<FileSystemPath>,
72    path: Vc<Pattern>,
73) -> Result<Vc<ModuleResolveResult>> {
74    let path_ref = path.await?;
75    let (abs_path, rel_path) = path_ref.split_could_match("/ROOT/");
76    let matches = match (abs_path, rel_path) {
77        (Some(abs_path), Some(rel_path)) => Either::Right(
78            read_matches(
79                parent_path.root().resolve().await?,
80                "/ROOT/".into(),
81                true,
82                Pattern::new(abs_path.or_any_nested_file()),
83            )
84            .await?
85            .into_iter()
86            .chain(
87                read_matches(
88                    parent_path,
89                    "".into(),
90                    true,
91                    Pattern::new(rel_path.or_any_nested_file()),
92                )
93                .await?
94                .into_iter(),
95            ),
96        ),
97        (Some(abs_path), None) => Either::Left(
98            // absolute path only
99            read_matches(
100                parent_path.root().resolve().await?,
101                "/ROOT/".into(),
102                true,
103                Pattern::new(abs_path.or_any_nested_file()),
104            )
105            .await?
106            .into_iter(),
107        ),
108        (None, Some(rel_path)) => Either::Left(
109            // relative path only
110            read_matches(
111                parent_path,
112                "".into(),
113                true,
114                Pattern::new(rel_path.or_any_nested_file()),
115            )
116            .await?
117            .into_iter(),
118        ),
119        (None, None) => return Ok(*ModuleResolveResult::unresolvable()),
120    };
121    let mut affecting_sources = Vec::new();
122    let mut results = Vec::new();
123    for pat_match in matches {
124        match pat_match {
125            PatternMatch::File(matched_path, file) => {
126                let realpath = file.realpath_with_links().await?;
127                for &symlink in &realpath.symlinks {
128                    affecting_sources.push(ResolvedVc::upcast(
129                        FileSource::new(*symlink).to_resolved().await?,
130                    ));
131                }
132                results.push((
133                    RequestKey::new(matched_path.clone()),
134                    ResolvedVc::upcast(
135                        RawModule::new(Vc::upcast(FileSource::new(*realpath.path)))
136                            .to_resolved()
137                            .await?,
138                    ),
139                ));
140            }
141            PatternMatch::Directory(..) => {}
142        }
143    }
144    Ok(*ModuleResolveResult::modules_with_affecting_sources(
145        results,
146        affecting_sources,
147    ))
148}
149
150#[turbo_tasks::value_impl]
151impl ModuleReference for DirAssetReference {
152    #[turbo_tasks::function]
153    async fn resolve_reference(&self) -> Result<Vc<ModuleResolveResult>> {
154        let parent_path = self.source.ident().path().parent();
155        Ok(resolve_reference_from_dir(
156            parent_path.resolve().await?,
157            *self.path,
158        ))
159    }
160}
161
162#[turbo_tasks::value_impl]
163impl ChunkableModuleReference for DirAssetReference {
164    #[turbo_tasks::function]
165    fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
166        Vc::cell(Some(ChunkingType::Traced))
167    }
168}
169
170#[turbo_tasks::value_impl]
171impl ValueToString for DirAssetReference {
172    #[turbo_tasks::function]
173    async fn to_string(&self) -> Result<Vc<RcStr>> {
174        Ok(Vc::cell(
175            format!("directory assets {}", self.path.to_string().await?,).into(),
176        ))
177    }
178}