turbopack_ecmascript/references/
node.rs

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