turbopack_core/resolve/
mod.rs

1use std::{
2    borrow::Cow,
3    collections::BTreeMap,
4    fmt::{Display, Formatter, Write},
5    future::Future,
6    iter::once,
7};
8
9use anyhow::{Result, bail};
10use rustc_hash::{FxHashMap, FxHashSet};
11use serde::{Deserialize, Serialize};
12use tracing::{Instrument, Level};
13use turbo_rcstr::{RcStr, rcstr};
14use turbo_tasks::{
15    FxIndexMap, FxIndexSet, NonLocalValue, ReadRef, ResolvedVc, SliceMap, TaskInput,
16    TryFlatJoinIterExt, TryJoinIterExt, ValueToString, Vc, trace::TraceRawVcs,
17};
18use turbo_tasks_fs::{FileSystemEntryType, FileSystemPath};
19use turbo_unix_path::normalize_request;
20
21use self::{
22    options::{
23        ConditionValue, ImportMapResult, ResolveInPackage, ResolveIntoPackage, ResolveModules,
24        ResolveModulesOptions, ResolveOptions, resolve_modules_options,
25    },
26    origin::{ResolveOrigin, ResolveOriginExt},
27    parse::Request,
28    pattern::Pattern,
29    plugin::BeforeResolvePlugin,
30    remap::{ExportsField, ImportsField},
31};
32use crate::{
33    context::AssetContext,
34    data_uri_source::DataUriSource,
35    file_source::FileSource,
36    issue::{
37        IssueExt, IssueSource, module::emit_unknown_module_type_error, resolve::ResolvingIssue,
38    },
39    module::{Module, Modules, OptionModule},
40    output::{OutputAsset, OutputAssets},
41    package_json::{PackageJsonIssue, read_package_json},
42    raw_module::RawModule,
43    reference_type::ReferenceType,
44    resolve::{
45        alias_map::AliasKey,
46        node::{node_cjs_resolve_options, node_esm_resolve_options},
47        parse::stringify_data_uri,
48        pattern::{PatternMatch, read_matches},
49        plugin::AfterResolvePlugin,
50        remap::ReplacedSubpathValueResult,
51    },
52    source::{OptionSource, Source, Sources},
53};
54
55mod alias_map;
56pub mod node;
57pub mod options;
58pub mod origin;
59pub mod parse;
60pub mod pattern;
61pub mod plugin;
62pub(crate) mod remap;
63
64pub use alias_map::{
65    AliasMap, AliasMapIntoIter, AliasMapLookupIterator, AliasMatch, AliasPattern, AliasTemplate,
66};
67pub use remap::{ResolveAliasMap, SubpathValue};
68
69use crate::{error::PrettyPrintError, issue::IssueSeverity};
70
71#[turbo_tasks::value(shared)]
72#[derive(Clone, Debug)]
73pub enum ModuleResolveResultItem {
74    Module(ResolvedVc<Box<dyn Module>>),
75    OutputAsset(ResolvedVc<Box<dyn OutputAsset>>),
76    External {
77        /// uri, path, reference, etc.
78        name: RcStr,
79        ty: ExternalType,
80    },
81    /// A module could not be created (according to the rules, e.g. no module type as assigned)
82    Unknown(ResolvedVc<Box<dyn Source>>),
83    Ignore,
84    Error(ResolvedVc<RcStr>),
85    Empty,
86    Custom(u8),
87}
88
89impl ModuleResolveResultItem {
90    async fn as_module(&self) -> Result<Option<ResolvedVc<Box<dyn Module>>>> {
91        Ok(match *self {
92            ModuleResolveResultItem::Module(module) => Some(module),
93            ModuleResolveResultItem::Unknown(source) => {
94                emit_unknown_module_type_error(*source).await?;
95                None
96            }
97            ModuleResolveResultItem::Error(_err) => {
98                // TODO emit error?
99                None
100            }
101            _ => None,
102        })
103    }
104}
105
106#[turbo_tasks::value]
107#[derive(Debug, Clone, Default, Hash)]
108pub enum ExportUsage {
109    Named(RcStr),
110    /// This means the whole content of the module is used.
111    #[default]
112    All,
113    /// Only side effects are used.
114    Evaluation,
115}
116
117impl Display for ExportUsage {
118    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119        match self {
120            ExportUsage::Named(name) => write!(f, "export {name}"),
121            ExportUsage::All => write!(f, "all"),
122            ExportUsage::Evaluation => write!(f, "evaluation"),
123        }
124    }
125}
126
127#[turbo_tasks::value_impl]
128impl ExportUsage {
129    #[turbo_tasks::function]
130    pub fn all() -> Vc<Self> {
131        Self::All.cell()
132    }
133
134    #[turbo_tasks::function]
135    pub fn evaluation() -> Vc<Self> {
136        Self::Evaluation.cell()
137    }
138
139    #[turbo_tasks::function]
140    pub fn named(name: RcStr) -> Vc<Self> {
141        Self::Named(name).cell()
142    }
143}
144
145#[turbo_tasks::value(shared)]
146#[derive(Clone, Debug)]
147pub struct ModuleResolveResult {
148    pub primary: SliceMap<RequestKey, ModuleResolveResultItem>,
149    /// Affecting sources are other files that influence the resolve result.  For example,
150    /// traversed symlinks
151    pub affecting_sources: Box<[ResolvedVc<Box<dyn Source>>]>,
152}
153
154impl ModuleResolveResult {
155    pub fn unresolvable() -> ResolvedVc<Self> {
156        ModuleResolveResult {
157            primary: Default::default(),
158            affecting_sources: Default::default(),
159        }
160        .resolved_cell()
161    }
162
163    pub fn module(module: ResolvedVc<Box<dyn Module>>) -> ResolvedVc<Self> {
164        Self::module_with_key(RequestKey::default(), module)
165    }
166
167    pub fn module_with_key(
168        request_key: RequestKey,
169        module: ResolvedVc<Box<dyn Module>>,
170    ) -> ResolvedVc<Self> {
171        ModuleResolveResult {
172            primary: vec![(request_key, ModuleResolveResultItem::Module(module))]
173                .into_boxed_slice(),
174            affecting_sources: Default::default(),
175        }
176        .resolved_cell()
177    }
178
179    pub fn output_asset(
180        request_key: RequestKey,
181        output_asset: ResolvedVc<Box<dyn OutputAsset>>,
182    ) -> ResolvedVc<Self> {
183        ModuleResolveResult {
184            primary: vec![(
185                request_key,
186                ModuleResolveResultItem::OutputAsset(output_asset),
187            )]
188            .into_boxed_slice(),
189            affecting_sources: Default::default(),
190        }
191        .resolved_cell()
192    }
193
194    pub fn modules(
195        modules: impl IntoIterator<Item = (RequestKey, ResolvedVc<Box<dyn Module>>)>,
196    ) -> ResolvedVc<Self> {
197        ModuleResolveResult {
198            primary: modules
199                .into_iter()
200                .map(|(k, v)| (k, ModuleResolveResultItem::Module(v)))
201                .collect(),
202            affecting_sources: Default::default(),
203        }
204        .resolved_cell()
205    }
206
207    pub fn modules_with_affecting_sources(
208        modules: impl IntoIterator<Item = (RequestKey, ResolvedVc<Box<dyn Module>>)>,
209        affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
210    ) -> ResolvedVc<Self> {
211        ModuleResolveResult {
212            primary: modules
213                .into_iter()
214                .map(|(k, v)| (k, ModuleResolveResultItem::Module(v)))
215                .collect(),
216            affecting_sources: affecting_sources.into_boxed_slice(),
217        }
218        .resolved_cell()
219    }
220}
221
222impl ModuleResolveResult {
223    /// Returns all module results (but ignoring any errors).
224    pub fn primary_modules_raw_iter(
225        &self,
226    ) -> impl Iterator<Item = ResolvedVc<Box<dyn Module>>> + '_ {
227        self.primary.iter().filter_map(|(_, item)| match *item {
228            ModuleResolveResultItem::Module(a) => Some(a),
229            _ => None,
230        })
231    }
232
233    pub fn affecting_sources_iter(&self) -> impl Iterator<Item = ResolvedVc<Box<dyn Source>>> + '_ {
234        self.affecting_sources.iter().copied()
235    }
236
237    pub fn is_unresolvable_ref(&self) -> bool {
238        self.primary.is_empty()
239    }
240}
241
242pub struct ModuleResolveResultBuilder {
243    pub primary: FxIndexMap<RequestKey, ModuleResolveResultItem>,
244    pub affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
245}
246
247impl From<ModuleResolveResultBuilder> for ModuleResolveResult {
248    fn from(v: ModuleResolveResultBuilder) -> Self {
249        ModuleResolveResult {
250            primary: v.primary.into_iter().collect(),
251            affecting_sources: v.affecting_sources.into_boxed_slice(),
252        }
253    }
254}
255impl From<ModuleResolveResult> for ModuleResolveResultBuilder {
256    fn from(v: ModuleResolveResult) -> Self {
257        ModuleResolveResultBuilder {
258            primary: IntoIterator::into_iter(v.primary).collect(),
259            affecting_sources: v.affecting_sources.into_vec(),
260        }
261    }
262}
263impl ModuleResolveResultBuilder {
264    pub fn merge_alternatives(&mut self, other: &ModuleResolveResult) {
265        for (k, v) in other.primary.iter() {
266            if !self.primary.contains_key(k) {
267                self.primary.insert(k.clone(), v.clone());
268            }
269        }
270        let set = self
271            .affecting_sources
272            .iter()
273            .copied()
274            .collect::<FxHashSet<_>>();
275        self.affecting_sources.extend(
276            other
277                .affecting_sources
278                .iter()
279                .filter(|source| !set.contains(source))
280                .copied(),
281        );
282    }
283}
284
285#[turbo_tasks::value_impl]
286impl ModuleResolveResult {
287    #[turbo_tasks::function]
288    pub async fn alternatives(results: Vec<Vc<ModuleResolveResult>>) -> Result<Vc<Self>> {
289        if results.len() == 1 {
290            return Ok(results.into_iter().next().unwrap());
291        }
292        let mut iter = results.into_iter().try_join().await?.into_iter();
293        if let Some(current) = iter.next() {
294            let mut current: ModuleResolveResultBuilder = ReadRef::into_owned(current).into();
295            for result in iter {
296                // For clippy -- This explicit deref is necessary
297                let other = &*result;
298                current.merge_alternatives(other);
299            }
300            Ok(Self::cell(current.into()))
301        } else {
302            Ok(*ModuleResolveResult::unresolvable())
303        }
304    }
305
306    #[turbo_tasks::function]
307    pub fn is_unresolvable(&self) -> Vc<bool> {
308        Vc::cell(self.is_unresolvable_ref())
309    }
310
311    #[turbo_tasks::function]
312    pub async fn first_module(&self) -> Result<Vc<OptionModule>> {
313        for (_, item) in self.primary.iter() {
314            if let Some(module) = item.as_module().await? {
315                return Ok(Vc::cell(Some(module)));
316            }
317        }
318        Ok(Vc::cell(None))
319    }
320
321    /// Returns a set (no duplicates) of primary modules in the result. All
322    /// modules are already resolved Vc.
323    #[turbo_tasks::function]
324    pub async fn primary_modules(&self) -> Result<Vc<Modules>> {
325        let mut set = FxIndexSet::default();
326        for (_, item) in self.primary.iter() {
327            if let Some(module) = item.as_module().await? {
328                set.insert(module);
329            }
330        }
331        Ok(Vc::cell(set.into_iter().collect()))
332    }
333
334    #[turbo_tasks::function]
335    pub fn primary_output_assets(&self) -> Vc<OutputAssets> {
336        Vc::cell(
337            self.primary
338                .iter()
339                .filter_map(|(_, item)| match item {
340                    &ModuleResolveResultItem::OutputAsset(a) => Some(a),
341                    _ => None,
342                })
343                .collect(),
344        )
345    }
346}
347
348#[derive(
349    Copy,
350    Clone,
351    Debug,
352    PartialEq,
353    Eq,
354    TaskInput,
355    Hash,
356    NonLocalValue,
357    TraceRawVcs,
358    Serialize,
359    Deserialize,
360)]
361pub enum ExternalTraced {
362    Untraced,
363    Traced,
364}
365
366impl Display for ExternalTraced {
367    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
368        match self {
369            ExternalTraced::Untraced => write!(f, "untraced"),
370            ExternalTraced::Traced => write!(f, "traced"),
371        }
372    }
373}
374
375#[derive(
376    Copy,
377    Clone,
378    Debug,
379    Eq,
380    PartialEq,
381    Hash,
382    Serialize,
383    Deserialize,
384    TraceRawVcs,
385    TaskInput,
386    NonLocalValue,
387)]
388pub enum ExternalType {
389    Url,
390    CommonJs,
391    EcmaScriptModule,
392    Global,
393    Script,
394}
395
396impl Display for ExternalType {
397    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
398        match self {
399            ExternalType::CommonJs => write!(f, "commonjs"),
400            ExternalType::EcmaScriptModule => write!(f, "esm"),
401            ExternalType::Url => write!(f, "url"),
402            ExternalType::Global => write!(f, "global"),
403            ExternalType::Script => write!(f, "script"),
404        }
405    }
406}
407
408#[turbo_tasks::value(shared)]
409#[derive(Debug, Clone)]
410pub enum ResolveResultItem {
411    Source(ResolvedVc<Box<dyn Source>>),
412    External {
413        /// uri, path, reference, etc.
414        name: RcStr,
415        ty: ExternalType,
416        traced: ExternalTraced,
417    },
418    Ignore,
419    Error(ResolvedVc<RcStr>),
420    Empty,
421    Custom(u8),
422}
423
424/// Represents the key for a request that leads to a certain results during
425/// resolving.
426///
427/// A primary factor is the actual request string, but there are
428/// other factors like exports conditions that can affect resolting and become
429/// part of the key (assuming the condition is unknown at compile time)
430#[derive(Clone, Debug, Default, Hash, TaskInput)]
431#[turbo_tasks::value]
432pub struct RequestKey {
433    pub request: Option<RcStr>,
434    pub conditions: BTreeMap<String, bool>,
435}
436
437impl Display for RequestKey {
438    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439        if let Some(request) = &self.request {
440            write!(f, "{request}")?;
441        } else {
442            write!(f, "<default>")?;
443        }
444        if !self.conditions.is_empty() {
445            write!(f, " (")?;
446            for (i, (k, v)) in self.conditions.iter().enumerate() {
447                if i > 0 {
448                    write!(f, ", ")?;
449                }
450                write!(f, "{k}={v}")?;
451            }
452            write!(f, ")")?;
453        }
454        Ok(())
455    }
456}
457
458impl RequestKey {
459    pub fn new(request: RcStr) -> Self {
460        RequestKey {
461            request: Some(request),
462            ..Default::default()
463        }
464    }
465}
466
467#[turbo_tasks::value(shared)]
468#[derive(Clone)]
469pub struct ResolveResult {
470    pub primary: SliceMap<RequestKey, ResolveResultItem>,
471    /// Affecting sources are other files that influence the resolve result.  For example,
472    /// traversed symlinks
473    pub affecting_sources: Box<[ResolvedVc<Box<dyn Source>>]>,
474}
475
476#[turbo_tasks::value_impl]
477impl ValueToString for ResolveResult {
478    #[turbo_tasks::function]
479    async fn to_string(&self) -> Result<Vc<RcStr>> {
480        let mut result = String::new();
481        if self.is_unresolvable_ref() {
482            result.push_str("unresolvable");
483        }
484        for (i, (request, item)) in self.primary.iter().enumerate() {
485            if i > 0 {
486                result.push_str(", ");
487            }
488            write!(result, "{request} -> ").unwrap();
489            match item {
490                ResolveResultItem::Source(a) => {
491                    result.push_str(&a.ident().to_string().await?);
492                }
493                ResolveResultItem::External {
494                    name: s,
495                    ty,
496                    traced,
497                } => {
498                    result.push_str("external ");
499                    result.push_str(s);
500                    write!(result, " ({ty}, {traced})")?;
501                }
502                ResolveResultItem::Ignore => {
503                    result.push_str("ignore");
504                }
505                ResolveResultItem::Empty => {
506                    result.push_str("empty");
507                }
508                ResolveResultItem::Error(_) => {
509                    result.push_str("error");
510                }
511                ResolveResultItem::Custom(_) => {
512                    result.push_str("custom");
513                }
514            }
515            result.push('\n');
516        }
517        if !self.affecting_sources.is_empty() {
518            result.push_str(" (affecting sources: ");
519            for (i, source) in self.affecting_sources.iter().enumerate() {
520                if i > 0 {
521                    result.push_str(", ");
522                }
523                result.push_str(&source.ident().to_string().await?);
524            }
525            result.push(')');
526        }
527        Ok(Vc::cell(result.into()))
528    }
529}
530
531impl ResolveResult {
532    pub fn unresolvable() -> ResolvedVc<Self> {
533        ResolveResult {
534            primary: Default::default(),
535            affecting_sources: Default::default(),
536        }
537        .resolved_cell()
538    }
539
540    pub fn unresolvable_with_affecting_sources(
541        affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
542    ) -> ResolvedVc<Self> {
543        ResolveResult {
544            primary: Default::default(),
545            affecting_sources: affecting_sources.into_boxed_slice(),
546        }
547        .resolved_cell()
548    }
549
550    pub fn primary(result: ResolveResultItem) -> ResolvedVc<Self> {
551        Self::primary_with_key(RequestKey::default(), result)
552    }
553
554    pub fn primary_with_key(
555        request_key: RequestKey,
556        result: ResolveResultItem,
557    ) -> ResolvedVc<Self> {
558        ResolveResult {
559            primary: vec![(request_key, result)].into_boxed_slice(),
560            affecting_sources: Default::default(),
561        }
562        .resolved_cell()
563    }
564
565    pub fn primary_with_affecting_sources(
566        request_key: RequestKey,
567        result: ResolveResultItem,
568        affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
569    ) -> ResolvedVc<Self> {
570        ResolveResult {
571            primary: vec![(request_key, result)].into_boxed_slice(),
572            affecting_sources: affecting_sources.into_boxed_slice(),
573        }
574        .resolved_cell()
575    }
576
577    pub fn source(source: ResolvedVc<Box<dyn Source>>) -> ResolvedVc<Self> {
578        Self::source_with_key(RequestKey::default(), source).resolved_cell()
579    }
580
581    fn source_with_key(request_key: RequestKey, source: ResolvedVc<Box<dyn Source>>) -> Self {
582        ResolveResult {
583            primary: vec![(request_key, ResolveResultItem::Source(source))].into_boxed_slice(),
584            affecting_sources: Default::default(),
585        }
586    }
587
588    fn source_with_affecting_sources(
589        request_key: RequestKey,
590        source: ResolvedVc<Box<dyn Source>>,
591        affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
592    ) -> Self {
593        ResolveResult {
594            primary: vec![(request_key, ResolveResultItem::Source(source))].into_boxed_slice(),
595            affecting_sources: affecting_sources.into_boxed_slice(),
596        }
597    }
598}
599
600impl ResolveResult {
601    /// Returns the affecting sources for this result. Will be empty if affecting sources are
602    /// disabled for this result.
603    pub fn get_affecting_sources(&self) -> impl Iterator<Item = ResolvedVc<Box<dyn Source>>> + '_ {
604        self.affecting_sources.iter().copied()
605    }
606
607    pub fn is_unresolvable_ref(&self) -> bool {
608        self.primary.is_empty()
609    }
610
611    pub async fn map_module<A, AF>(&self, source_fn: A) -> Result<ModuleResolveResult>
612    where
613        A: Fn(ResolvedVc<Box<dyn Source>>) -> AF,
614        AF: Future<Output = Result<ModuleResolveResultItem>>,
615    {
616        Ok(ModuleResolveResult {
617            primary: self
618                .primary
619                .iter()
620                .map(|(request, item)| {
621                    let asset_fn = &source_fn;
622                    let request = request.clone();
623                    let item = item.clone();
624                    async move {
625                        Ok((
626                            request,
627                            match item {
628                                ResolveResultItem::Source(source) => asset_fn(source).await?,
629                                ResolveResultItem::External { name, ty, traced } => {
630                                    if traced == ExternalTraced::Traced {
631                                        // Should use map_primary_items instead
632                                        bail!("map_module doesn't handle traced externals");
633                                    }
634                                    ModuleResolveResultItem::External { name, ty }
635                                }
636                                ResolveResultItem::Ignore => ModuleResolveResultItem::Ignore,
637                                ResolveResultItem::Empty => ModuleResolveResultItem::Empty,
638                                ResolveResultItem::Error(e) => ModuleResolveResultItem::Error(e),
639                                ResolveResultItem::Custom(u8) => {
640                                    ModuleResolveResultItem::Custom(u8)
641                                }
642                            },
643                        ))
644                    }
645                })
646                .try_join()
647                .await?
648                .into_iter()
649                .collect(),
650            affecting_sources: self.affecting_sources.clone(),
651        })
652    }
653
654    pub async fn map_primary_items<A, AF>(&self, item_fn: A) -> Result<ModuleResolveResult>
655    where
656        A: Fn(ResolveResultItem) -> AF,
657        AF: Future<Output = Result<ModuleResolveResultItem>>,
658    {
659        Ok(ModuleResolveResult {
660            primary: self
661                .primary
662                .iter()
663                .map(|(request, item)| {
664                    let asset_fn = &item_fn;
665                    let request = request.clone();
666                    let item = item.clone();
667                    async move { Ok((request, asset_fn(item).await?)) }
668                })
669                .try_join()
670                .await?
671                .into_iter()
672                .collect(),
673            affecting_sources: self.affecting_sources.clone(),
674        })
675    }
676
677    /// Returns a new [ResolveResult] where all [RequestKey]s are set to the
678    /// passed `request`.
679    fn with_request_ref(&self, request: RcStr) -> Self {
680        let new_primary = self
681            .primary
682            .iter()
683            .map(|(k, v)| {
684                (
685                    RequestKey {
686                        request: Some(request.clone()),
687                        conditions: k.conditions.clone(),
688                    },
689                    v.clone(),
690                )
691            })
692            .collect();
693        ResolveResult {
694            primary: new_primary,
695            affecting_sources: self.affecting_sources.clone(),
696        }
697    }
698
699    pub fn add_conditions(&mut self, conditions: impl IntoIterator<Item = (RcStr, bool)>) {
700        let mut primary = std::mem::take(&mut self.primary);
701        for (k, v) in conditions {
702            for (key, _) in primary.iter_mut() {
703                key.conditions.insert(k.to_string(), v);
704            }
705        }
706        // Deduplicate
707        self.primary = IntoIterator::into_iter(primary)
708            .collect::<FxIndexMap<_, _>>()
709            .into_iter()
710            .collect::<Vec<_>>()
711            .into_boxed_slice();
712    }
713}
714
715struct ResolveResultBuilder {
716    primary: FxIndexMap<RequestKey, ResolveResultItem>,
717    affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
718}
719
720impl From<ResolveResultBuilder> for ResolveResult {
721    fn from(v: ResolveResultBuilder) -> Self {
722        ResolveResult {
723            primary: v.primary.into_iter().collect(),
724            affecting_sources: v.affecting_sources.into_boxed_slice(),
725        }
726    }
727}
728impl From<ResolveResult> for ResolveResultBuilder {
729    fn from(v: ResolveResult) -> Self {
730        ResolveResultBuilder {
731            primary: IntoIterator::into_iter(v.primary).collect(),
732            affecting_sources: v.affecting_sources.into_vec(),
733        }
734    }
735}
736impl ResolveResultBuilder {
737    pub fn merge_alternatives(&mut self, other: &ResolveResult) {
738        for (k, v) in other.primary.iter() {
739            if !self.primary.contains_key(k) {
740                self.primary.insert(k.clone(), v.clone());
741            }
742        }
743        let set = self
744            .affecting_sources
745            .iter()
746            .copied()
747            .collect::<FxHashSet<_>>();
748        self.affecting_sources.extend(
749            other
750                .affecting_sources
751                .iter()
752                .filter(|source| !set.contains(source))
753                .copied(),
754        );
755    }
756}
757
758#[turbo_tasks::value_impl]
759impl ResolveResult {
760    #[turbo_tasks::function]
761    pub async fn as_raw_module_result(&self) -> Result<Vc<ModuleResolveResult>> {
762        Ok(self
763            .map_module(|asset| async move {
764                Ok(ModuleResolveResultItem::Module(ResolvedVc::upcast(
765                    RawModule::new(*asset).to_resolved().await?,
766                )))
767            })
768            .await?
769            .cell())
770    }
771
772    #[turbo_tasks::function]
773    fn with_affecting_sources(
774        &self,
775        sources: Vec<ResolvedVc<Box<dyn Source>>>,
776    ) -> Result<Vc<Self>> {
777        Ok(Self {
778            primary: self.primary.clone(),
779            affecting_sources: self
780                .affecting_sources
781                .iter()
782                .copied()
783                .chain(sources)
784                .collect(),
785        }
786        .cell())
787    }
788
789    #[turbo_tasks::function]
790    async fn alternatives(results: Vec<Vc<ResolveResult>>) -> Result<Vc<Self>> {
791        if results.len() == 1 {
792            return Ok(results.into_iter().next().unwrap());
793        }
794        let mut iter = results.into_iter().try_join().await?.into_iter();
795        if let Some(current) = iter.next() {
796            let mut current: ResolveResultBuilder = ReadRef::into_owned(current).into();
797            for result in iter {
798                // For clippy -- This explicit deref is necessary
799                let other = &*result;
800                current.merge_alternatives(other);
801            }
802            Ok(Self::cell(current.into()))
803        } else {
804            Ok(*ResolveResult::unresolvable())
805        }
806    }
807
808    #[turbo_tasks::function]
809    async fn alternatives_with_affecting_sources(
810        results: Vec<Vc<ResolveResult>>,
811        affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
812    ) -> Result<Vc<Self>> {
813        debug_assert!(
814            !affecting_sources.is_empty(),
815            "Caller should not call this function if there are no affecting sources"
816        );
817        if results.len() == 1 {
818            return Ok(results
819                .into_iter()
820                .next()
821                .unwrap()
822                .with_affecting_sources(affecting_sources.into_iter().map(|src| *src).collect()));
823        }
824        let mut iter = results.into_iter().try_join().await?.into_iter();
825        if let Some(current) = iter.next() {
826            let mut current: ResolveResultBuilder = ReadRef::into_owned(current).into();
827            for result in iter {
828                // For clippy -- This explicit deref is necessary
829                let other = &*result;
830                current.merge_alternatives(other);
831            }
832            current.affecting_sources.extend(affecting_sources);
833            Ok(Self::cell(current.into()))
834        } else {
835            Ok(*ResolveResult::unresolvable_with_affecting_sources(
836                affecting_sources,
837            ))
838        }
839    }
840
841    #[turbo_tasks::function]
842    pub fn is_unresolvable(&self) -> Vc<bool> {
843        Vc::cell(self.is_unresolvable_ref())
844    }
845
846    #[turbo_tasks::function]
847    pub fn first_source(&self) -> Vc<OptionSource> {
848        Vc::cell(self.primary.iter().find_map(|(_, item)| {
849            if let &ResolveResultItem::Source(a) = item {
850                Some(a)
851            } else {
852                None
853            }
854        }))
855    }
856
857    #[turbo_tasks::function]
858    pub fn primary_sources(&self) -> Vc<Sources> {
859        Vc::cell(
860            self.primary
861                .iter()
862                .filter_map(|(_, item)| {
863                    if let &ResolveResultItem::Source(a) = item {
864                        Some(a)
865                    } else {
866                        None
867                    }
868                })
869                .collect(),
870        )
871    }
872
873    /// Returns a new [ResolveResult] where all [RequestKey]s are updated. The `old_request_key`
874    /// (prefix) is replaced with the `request_key`. It's not expected that the [ResolveResult]
875    /// contains [RequestKey]s that don't have the `old_request_key` prefix, but if there are still
876    /// some, they are discarded.
877    #[turbo_tasks::function]
878    fn with_replaced_request_key(
879        &self,
880        old_request_key: RcStr,
881        request_key: RequestKey,
882    ) -> Result<Vc<Self>> {
883        let new_primary = self
884            .primary
885            .iter()
886            .filter_map(|(k, v)| {
887                let remaining = k.request.as_ref()?.strip_prefix(&*old_request_key)?;
888                Some((
889                    RequestKey {
890                        request: request_key
891                            .request
892                            .as_ref()
893                            .map(|r| format!("{r}{remaining}").into()),
894                        conditions: request_key.conditions.clone(),
895                    },
896                    v.clone(),
897                ))
898            })
899            .collect();
900        Ok(ResolveResult {
901            primary: new_primary,
902            affecting_sources: self.affecting_sources.clone(),
903        }
904        .cell())
905    }
906
907    /// Returns a new [ResolveResult] where all [RequestKey]s are updated. The prefix is removed
908    /// from all [RequestKey]s. It's not expected that the [ResolveResult] contains [RequestKey]s
909    /// without the prefix, but if there are still some, they are discarded.
910    #[turbo_tasks::function]
911    fn with_stripped_request_key_prefix(&self, prefix: RcStr) -> Result<Vc<Self>> {
912        let new_primary = self
913            .primary
914            .iter()
915            .filter_map(|(k, v)| {
916                let remaining = k.request.as_ref()?.strip_prefix(&*prefix)?;
917                Some((
918                    RequestKey {
919                        request: Some(remaining.into()),
920                        conditions: k.conditions.clone(),
921                    },
922                    v.clone(),
923                ))
924            })
925            .collect();
926        Ok(ResolveResult {
927            primary: new_primary,
928            affecting_sources: self.affecting_sources.clone(),
929        }
930        .cell())
931    }
932
933    /// Returns a new [ResolveResult] where all [RequestKey]s are updated. All keys matching
934    /// `old_request_key` are rewritten according to `request_key`. It's not expected that the
935    /// [ResolveResult] contains [RequestKey]s that do not match the `old_request_key` prefix, but
936    /// if there are still some, they are discarded.
937    #[turbo_tasks::function]
938    async fn with_replaced_request_key_pattern(
939        &self,
940        old_request_key: Vc<Pattern>,
941        request_key: Vc<Pattern>,
942    ) -> Result<Vc<Self>> {
943        let old_request_key = &*old_request_key.await?;
944        let request_key = &*request_key.await?;
945
946        let new_primary = self
947            .primary
948            .iter()
949            .map(|(k, v)| {
950                (
951                    RequestKey {
952                        request: k
953                            .request
954                            .as_ref()
955                            .and_then(|r| old_request_key.match_apply_template(r, request_key))
956                            .map(Into::into),
957                        conditions: k.conditions.clone(),
958                    },
959                    v.clone(),
960                )
961            })
962            .collect();
963        Ok(ResolveResult {
964            primary: new_primary,
965            affecting_sources: self.affecting_sources.clone(),
966        }
967        .cell())
968    }
969
970    /// Returns a new [ResolveResult] where all [RequestKey]s are set to the
971    /// passed `request`.
972    #[turbo_tasks::function]
973    fn with_request(&self, request: RcStr) -> Vc<Self> {
974        let new_primary = self
975            .primary
976            .iter()
977            .map(|(k, v)| {
978                (
979                    RequestKey {
980                        request: Some(request.clone()),
981                        conditions: k.conditions.clone(),
982                    },
983                    v.clone(),
984                )
985            })
986            .collect();
987        ResolveResult {
988            primary: new_primary,
989            affecting_sources: self.affecting_sources.clone(),
990        }
991        .cell()
992    }
993}
994
995#[turbo_tasks::value(transparent)]
996pub struct ResolveResultOption(Option<ResolvedVc<ResolveResult>>);
997
998#[turbo_tasks::value_impl]
999impl ResolveResultOption {
1000    #[turbo_tasks::function]
1001    pub fn some(result: ResolvedVc<ResolveResult>) -> Vc<Self> {
1002        ResolveResultOption(Some(result)).cell()
1003    }
1004
1005    #[turbo_tasks::function]
1006    pub fn none() -> Vc<Self> {
1007        ResolveResultOption(None).cell()
1008    }
1009}
1010
1011async fn exists(
1012    fs_path: &FileSystemPath,
1013    refs: Option<&mut Vec<ResolvedVc<Box<dyn Source>>>>,
1014) -> Result<Option<FileSystemPath>> {
1015    type_exists(fs_path, FileSystemEntryType::File, refs).await
1016}
1017
1018async fn dir_exists(
1019    fs_path: &FileSystemPath,
1020    refs: Option<&mut Vec<ResolvedVc<Box<dyn Source>>>>,
1021) -> Result<Option<FileSystemPath>> {
1022    type_exists(fs_path, FileSystemEntryType::Directory, refs).await
1023}
1024
1025async fn type_exists(
1026    fs_path: &FileSystemPath,
1027    ty: FileSystemEntryType,
1028    refs: Option<&mut Vec<ResolvedVc<Box<dyn Source>>>>,
1029) -> Result<Option<FileSystemPath>> {
1030    let path = realpath(fs_path, refs).await?;
1031    Ok(if *path.get_type().await? == ty {
1032        Some(path)
1033    } else {
1034        None
1035    })
1036}
1037
1038async fn realpath(
1039    fs_path: &FileSystemPath,
1040    refs: Option<&mut Vec<ResolvedVc<Box<dyn Source>>>>,
1041) -> Result<FileSystemPath> {
1042    let result = fs_path.realpath_with_links().await?;
1043    if let Some(refs) = refs {
1044        refs.extend(
1045            result
1046                .symlinks
1047                .iter()
1048                .map(|path| async move {
1049                    Ok(ResolvedVc::upcast(
1050                        FileSource::new(path.clone()).to_resolved().await?,
1051                    ))
1052                })
1053                .try_join()
1054                .await?,
1055        );
1056    }
1057    match &result.path_result {
1058        Ok(path) => Ok(path.clone()),
1059        Err(e) => bail!(e.as_error_message(fs_path, &result)),
1060    }
1061}
1062
1063#[turbo_tasks::value(shared)]
1064enum ExportsFieldResult {
1065    Some(#[turbo_tasks(debug_ignore, trace_ignore)] ExportsField),
1066    None,
1067}
1068
1069/// Extracts the "exports" field out of the package.json, parsing it into an
1070/// appropriate [AliasMap] for lookups.
1071#[turbo_tasks::function]
1072async fn exports_field(
1073    package_json_path: ResolvedVc<Box<dyn Source>>,
1074) -> Result<Vc<ExportsFieldResult>> {
1075    let read = read_package_json(*package_json_path).await?;
1076    let package_json = match &*read {
1077        Some(json) => json,
1078        None => return Ok(ExportsFieldResult::None.cell()),
1079    };
1080
1081    let Some(exports) = package_json.get("exports") else {
1082        return Ok(ExportsFieldResult::None.cell());
1083    };
1084    match exports.try_into() {
1085        Ok(exports) => Ok(ExportsFieldResult::Some(exports).cell()),
1086        Err(err) => {
1087            PackageJsonIssue {
1088                error_message: err.to_string().into(),
1089                // TODO(PACK-4879): add line column information
1090                source: IssueSource::from_source_only(package_json_path),
1091            }
1092            .resolved_cell()
1093            .emit();
1094            Ok(ExportsFieldResult::None.cell())
1095        }
1096    }
1097}
1098
1099#[turbo_tasks::value(shared)]
1100enum ImportsFieldResult {
1101    Some(
1102        #[turbo_tasks(debug_ignore, trace_ignore)] ImportsField,
1103        FileSystemPath,
1104    ),
1105    None,
1106}
1107
1108/// Extracts the "imports" field out of the nearest package.json, parsing it
1109/// into an appropriate [AliasMap] for lookups.
1110#[turbo_tasks::function]
1111async fn imports_field(lookup_path: FileSystemPath) -> Result<Vc<ImportsFieldResult>> {
1112    // We don't need to collect affecting sources here because we don't use them
1113    let package_json_context = find_context_file(lookup_path, package_json(), false).await?;
1114    let FindContextFileResult::Found(package_json_path, _refs) = &*package_json_context else {
1115        return Ok(ImportsFieldResult::None.cell());
1116    };
1117    let source = Vc::upcast::<Box<dyn Source>>(FileSource::new(package_json_path.clone()))
1118        .to_resolved()
1119        .await?;
1120
1121    let read = read_package_json(*source).await?;
1122    let package_json = match &*read {
1123        Some(json) => json,
1124        None => return Ok(ImportsFieldResult::None.cell()),
1125    };
1126
1127    let Some(imports) = package_json.get("imports") else {
1128        return Ok(ImportsFieldResult::None.cell());
1129    };
1130    match imports.try_into() {
1131        Ok(imports) => Ok(ImportsFieldResult::Some(imports, package_json_path.clone()).cell()),
1132        Err(err) => {
1133            PackageJsonIssue {
1134                error_message: err.to_string().into(),
1135                // TODO(PACK-4879): Add line-column information
1136                source: IssueSource::from_source_only(source),
1137            }
1138            .resolved_cell()
1139            .emit();
1140            Ok(ImportsFieldResult::None.cell())
1141        }
1142    }
1143}
1144
1145#[turbo_tasks::function]
1146pub fn package_json() -> Vc<Vec<RcStr>> {
1147    Vc::cell(vec![rcstr!("package.json")])
1148}
1149
1150#[turbo_tasks::value(shared)]
1151pub enum FindContextFileResult {
1152    Found(FileSystemPath, Vec<ResolvedVc<Box<dyn Source>>>),
1153    NotFound(Vec<ResolvedVc<Box<dyn Source>>>),
1154}
1155
1156#[turbo_tasks::function]
1157pub async fn find_context_file(
1158    lookup_path: FileSystemPath,
1159    names: Vc<Vec<RcStr>>,
1160    collect_affecting_sources: bool,
1161) -> Result<Vc<FindContextFileResult>> {
1162    let mut refs = Vec::new();
1163    for name in &*names.await? {
1164        let fs_path = lookup_path.join(name)?;
1165        if let Some(fs_path) = exists(
1166            &fs_path,
1167            if collect_affecting_sources {
1168                Some(&mut refs)
1169            } else {
1170                None
1171            },
1172        )
1173        .await?
1174        {
1175            return Ok(FindContextFileResult::Found(fs_path, refs).cell());
1176        }
1177    }
1178    if lookup_path.is_root() {
1179        return Ok(FindContextFileResult::NotFound(refs).cell());
1180    }
1181    if refs.is_empty() {
1182        // Tailcall
1183        Ok(find_context_file(
1184            lookup_path.parent(),
1185            names,
1186            collect_affecting_sources,
1187        ))
1188    } else {
1189        let parent_result =
1190            find_context_file(lookup_path.parent(), names, collect_affecting_sources).await?;
1191        Ok(match &*parent_result {
1192            FindContextFileResult::Found(p, r) => {
1193                refs.extend(r.iter().copied());
1194                FindContextFileResult::Found(p.clone(), refs)
1195            }
1196            FindContextFileResult::NotFound(r) => {
1197                refs.extend(r.iter().copied());
1198                FindContextFileResult::NotFound(refs)
1199            }
1200        }
1201        .cell())
1202    }
1203}
1204
1205// Same as find_context_file, but also stop for package.json with the specified key
1206// This function never collects affecting sources
1207#[turbo_tasks::function]
1208pub async fn find_context_file_or_package_key(
1209    lookup_path: FileSystemPath,
1210    names: Vc<Vec<RcStr>>,
1211    package_key: RcStr,
1212) -> Result<Vc<FindContextFileResult>> {
1213    let package_json_path = lookup_path.join("package.json")?;
1214    if let Some(package_json_path) = exists(&package_json_path, None).await?
1215        && let Some(json) =
1216            &*read_package_json(Vc::upcast(FileSource::new(package_json_path.clone()))).await?
1217        && json.get(&*package_key).is_some()
1218    {
1219        return Ok(FindContextFileResult::Found(package_json_path, Vec::new()).cell());
1220    }
1221    for name in &*names.await? {
1222        let fs_path = lookup_path.join(name)?;
1223        if let Some(fs_path) = exists(&fs_path, None).await? {
1224            return Ok(FindContextFileResult::Found(fs_path, Vec::new()).cell());
1225        }
1226    }
1227    if lookup_path.is_root() {
1228        return Ok(FindContextFileResult::NotFound(Vec::new()).cell());
1229    }
1230
1231    Ok(find_context_file(lookup_path.parent(), names, false))
1232}
1233
1234#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, Debug, NonLocalValue)]
1235enum FindPackageItem {
1236    PackageDirectory { name: RcStr, dir: FileSystemPath },
1237    PackageFile { name: RcStr, file: FileSystemPath },
1238}
1239
1240#[turbo_tasks::value]
1241#[derive(Debug)]
1242struct FindPackageResult {
1243    packages: Vec<FindPackageItem>,
1244    // Only populated if collect_affecting_sources is true
1245    affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
1246}
1247
1248#[turbo_tasks::function]
1249async fn find_package(
1250    lookup_path: FileSystemPath,
1251    package_name: Pattern,
1252    options: Vc<ResolveModulesOptions>,
1253    collect_affecting_sources: bool,
1254) -> Result<Vc<FindPackageResult>> {
1255    let mut packages = vec![];
1256    let mut affecting_sources = vec![];
1257    let options = options.await?;
1258    let package_name_cell = Pattern::new(package_name.clone());
1259
1260    fn get_package_name(basepath: &FileSystemPath, package_dir: &FileSystemPath) -> Result<RcStr> {
1261        if let Some(name) = basepath.get_path_to(package_dir) {
1262            Ok(name.into())
1263        } else {
1264            bail!("Package directory {package_dir} is not inside the lookup path {basepath}");
1265        }
1266    }
1267
1268    for resolve_modules in &options.modules {
1269        match resolve_modules {
1270            ResolveModules::Nested(root, names) => {
1271                let mut lookup_path = lookup_path.clone();
1272                let mut lookup_path_value = lookup_path.clone();
1273                while lookup_path_value.is_inside_ref(root) {
1274                    for name in names.iter() {
1275                        let fs_path = lookup_path.join(name)?;
1276                        if let Some(fs_path) = dir_exists(
1277                            &fs_path,
1278                            collect_affecting_sources.then_some(&mut affecting_sources),
1279                        )
1280                        .await?
1281                        {
1282                            let matches =
1283                                read_matches(fs_path.clone(), rcstr!(""), true, package_name_cell)
1284                                    .await?;
1285                            for m in &*matches {
1286                                if let PatternMatch::Directory(_, package_dir) = m {
1287                                    packages.push(FindPackageItem::PackageDirectory {
1288                                        name: get_package_name(&fs_path, package_dir)?,
1289                                        dir: realpath(
1290                                            package_dir,
1291                                            collect_affecting_sources
1292                                                .then_some(&mut affecting_sources),
1293                                        )
1294                                        .await?,
1295                                    });
1296                                }
1297                            }
1298                        }
1299                    }
1300                    lookup_path = lookup_path.parent();
1301                    let new_context_value = lookup_path.clone();
1302                    if new_context_value == lookup_path_value {
1303                        break;
1304                    }
1305                    lookup_path_value = new_context_value;
1306                }
1307            }
1308            ResolveModules::Path {
1309                dir,
1310                excluded_extensions,
1311            } => {
1312                let matches =
1313                    read_matches(dir.clone(), rcstr!(""), true, package_name_cell).await?;
1314                for m in &*matches {
1315                    match m {
1316                        PatternMatch::Directory(_, package_dir) => {
1317                            packages.push(FindPackageItem::PackageDirectory {
1318                                name: get_package_name(dir, package_dir)?,
1319                                dir: realpath(
1320                                    package_dir,
1321                                    collect_affecting_sources.then_some(&mut affecting_sources),
1322                                )
1323                                .await?,
1324                            });
1325                        }
1326                        PatternMatch::File(_, package_file) => {
1327                            packages.push(FindPackageItem::PackageFile {
1328                                name: get_package_name(dir, package_file)?,
1329                                file: realpath(
1330                                    package_file,
1331                                    collect_affecting_sources.then_some(&mut affecting_sources),
1332                                )
1333                                .await?,
1334                            });
1335                        }
1336                    }
1337                }
1338
1339                let excluded_extensions = excluded_extensions.await?;
1340                let mut package_name_with_extensions = package_name.clone();
1341                package_name_with_extensions.push(Pattern::alternatives(
1342                    options
1343                        .extensions
1344                        .iter()
1345                        .filter(|ext| !excluded_extensions.contains(*ext))
1346                        .cloned()
1347                        .map(Pattern::from),
1348                ));
1349                let package_name_with_extensions = Pattern::new(package_name_with_extensions);
1350
1351                let matches =
1352                    read_matches(dir.clone(), rcstr!(""), true, package_name_with_extensions)
1353                        .await?;
1354                for m in matches {
1355                    if let PatternMatch::File(_, package_file) = m {
1356                        packages.push(FindPackageItem::PackageFile {
1357                            name: get_package_name(dir, package_file)?,
1358                            file: realpath(
1359                                package_file,
1360                                collect_affecting_sources.then_some(&mut affecting_sources),
1361                            )
1362                            .await?,
1363                        });
1364                    }
1365                }
1366            }
1367        }
1368    }
1369    Ok(FindPackageResult::cell(FindPackageResult {
1370        packages,
1371        affecting_sources,
1372    }))
1373}
1374
1375fn merge_results(results: Vec<Vc<ResolveResult>>) -> Vc<ResolveResult> {
1376    match results.len() {
1377        0 => *ResolveResult::unresolvable(),
1378        1 => results.into_iter().next().unwrap(),
1379        _ => ResolveResult::alternatives(results),
1380    }
1381}
1382
1383fn merge_results_with_affecting_sources(
1384    results: Vec<Vc<ResolveResult>>,
1385    affecting_sources: Vec<ResolvedVc<Box<dyn Source>>>,
1386) -> Vc<ResolveResult> {
1387    if affecting_sources.is_empty() {
1388        return merge_results(results);
1389    }
1390    match results.len() {
1391        0 => *ResolveResult::unresolvable_with_affecting_sources(affecting_sources),
1392        1 => results
1393            .into_iter()
1394            .next()
1395            .unwrap()
1396            .with_affecting_sources(affecting_sources.into_iter().map(|src| *src).collect()),
1397        _ => ResolveResult::alternatives_with_affecting_sources(
1398            results,
1399            affecting_sources.into_iter().map(|src| *src).collect(),
1400        ),
1401    }
1402}
1403
1404// Resolves the pattern
1405#[turbo_tasks::function]
1406pub async fn resolve_raw(
1407    lookup_dir: FileSystemPath,
1408    path: Vc<Pattern>,
1409    collect_affecting_sources: bool,
1410    force_in_lookup_dir: bool,
1411) -> Result<Vc<ResolveResult>> {
1412    async fn to_result(
1413        request: RcStr,
1414        path: &FileSystemPath,
1415        collect_affecting_sources: bool,
1416    ) -> Result<ResolveResult> {
1417        let result = &*path.realpath_with_links().await?;
1418        let path = match &result.path_result {
1419            Ok(path) => path,
1420            Err(e) => bail!(e.as_error_message(path, result)),
1421        };
1422        let request_key = RequestKey::new(request);
1423        let source = ResolvedVc::upcast(FileSource::new(path.clone()).to_resolved().await?);
1424        Ok(if collect_affecting_sources {
1425            ResolveResult::source_with_affecting_sources(
1426                request_key,
1427                source,
1428                result
1429                    .symlinks
1430                    .iter()
1431                    .map(|symlink| {
1432                        Vc::upcast::<Box<dyn Source>>(FileSource::new(symlink.clone()))
1433                            .to_resolved()
1434                    })
1435                    .try_join()
1436                    .await?,
1437            )
1438        } else {
1439            ResolveResult::source_with_key(request_key, source)
1440        })
1441    }
1442
1443    async fn collect_matches(
1444        matches: &[PatternMatch],
1445        collect_affecting_sources: bool,
1446    ) -> Result<Vec<Vc<ResolveResult>>> {
1447        Ok(matches
1448            .iter()
1449            .map(|m| async move {
1450                Ok(if let PatternMatch::File(request, path) = m {
1451                    Some(to_result(request.clone(), path, collect_affecting_sources).await?)
1452                } else {
1453                    None
1454                })
1455            })
1456            .try_flat_join()
1457            .await?
1458            // Construct all the cells after resolving the results to ensure they are constructed in
1459            // a deterministic order.
1460            .into_iter()
1461            .map(|res| res.cell())
1462            .collect())
1463    }
1464
1465    let mut results = Vec::new();
1466
1467    let pat = path.await?;
1468    if let Some(pat) = pat
1469        .filter_could_match("/ROOT/")
1470        // Checks if this pattern is more specific than everything, so we test using a random path
1471        // that is unlikely to actually exist
1472        .and_then(|pat| pat.filter_could_not_match("/ROOT/fsd8nz8og54z"))
1473    {
1474        let path = Pattern::new(pat);
1475        let matches = read_matches(
1476            lookup_dir.root().owned().await?,
1477            rcstr!("/ROOT/"),
1478            true,
1479            path,
1480        )
1481        .await?;
1482        results.extend(
1483            collect_matches(&matches, collect_affecting_sources)
1484                .await?
1485                .into_iter(),
1486        );
1487    }
1488
1489    {
1490        let matches =
1491            read_matches(lookup_dir.clone(), rcstr!(""), force_in_lookup_dir, path).await?;
1492
1493        results.extend(
1494            collect_matches(&matches, collect_affecting_sources)
1495                .await?
1496                .into_iter(),
1497        );
1498    }
1499
1500    Ok(merge_results(results))
1501}
1502
1503#[turbo_tasks::function]
1504pub async fn resolve(
1505    lookup_path: FileSystemPath,
1506    reference_type: ReferenceType,
1507    request: Vc<Request>,
1508    options: Vc<ResolveOptions>,
1509) -> Result<Vc<ResolveResult>> {
1510    resolve_inline(lookup_path, reference_type, request, options).await
1511}
1512
1513pub async fn resolve_inline(
1514    lookup_path: FileSystemPath,
1515    reference_type: ReferenceType,
1516    request: Vc<Request>,
1517    options: Vc<ResolveOptions>,
1518) -> Result<Vc<ResolveResult>> {
1519    let span = tracing::info_span!(
1520        "resolving",
1521        lookup_path = display(lookup_path.value_to_string().await?),
1522        name = tracing::field::Empty,
1523        reference_type = display(&reference_type),
1524    );
1525    if !span.is_disabled() {
1526        // You can't await multiple times in the span macro call parameters.
1527        span.record("name", request.to_string().await?.as_str());
1528    }
1529
1530    async {
1531        let before_plugins_result = handle_before_resolve_plugins(
1532            lookup_path.clone(),
1533            reference_type.clone(),
1534            request,
1535            options,
1536        )
1537        .await?;
1538
1539        let raw_result = match before_plugins_result {
1540            Some(result) => result,
1541            None => {
1542                resolve_internal(lookup_path.clone(), request, options)
1543                    .resolve()
1544                    .await?
1545            }
1546        };
1547
1548        let result =
1549            handle_after_resolve_plugins(lookup_path, reference_type, request, options, raw_result)
1550                .await?;
1551        Ok(result)
1552    }
1553    .instrument(span)
1554    .await
1555}
1556
1557#[turbo_tasks::function]
1558pub async fn url_resolve(
1559    origin: Vc<Box<dyn ResolveOrigin>>,
1560    request: Vc<Request>,
1561    reference_type: ReferenceType,
1562    issue_source: Option<IssueSource>,
1563    is_optional: bool,
1564) -> Result<Vc<ModuleResolveResult>> {
1565    let resolve_options = origin.resolve_options(reference_type.clone()).await?;
1566    let rel_request = request.as_relative();
1567    let rel_result = resolve(
1568        origin.origin_path().await?.parent(),
1569        reference_type.clone(),
1570        rel_request,
1571        resolve_options,
1572    );
1573    let result = if *rel_result.is_unresolvable().await? && rel_request.resolve().await? != request
1574    {
1575        let result = resolve(
1576            origin.origin_path().await?.parent(),
1577            reference_type.clone(),
1578            request,
1579            resolve_options,
1580        );
1581        if resolve_options.await?.collect_affecting_sources {
1582            result.with_affecting_sources(
1583                rel_result
1584                    .await?
1585                    .get_affecting_sources()
1586                    .map(|src| *src)
1587                    .collect(),
1588            )
1589        } else {
1590            result
1591        }
1592    } else {
1593        rel_result
1594    };
1595    let result = origin
1596        .asset_context()
1597        .process_resolve_result(result, reference_type.clone());
1598    handle_resolve_error(
1599        result,
1600        reference_type,
1601        origin.origin_path().owned().await?,
1602        request,
1603        resolve_options,
1604        is_optional,
1605        issue_source,
1606    )
1607    .await
1608}
1609
1610#[tracing::instrument(level = "trace", skip_all)]
1611async fn handle_before_resolve_plugins(
1612    lookup_path: FileSystemPath,
1613    reference_type: ReferenceType,
1614    request: Vc<Request>,
1615    options: Vc<ResolveOptions>,
1616) -> Result<Option<Vc<ResolveResult>>> {
1617    for plugin in &options.await?.before_resolve_plugins {
1618        let condition = plugin.before_resolve_condition().resolve().await?;
1619        if !*condition.matches(request).await? {
1620            continue;
1621        }
1622
1623        if let Some(result) = *plugin
1624            .before_resolve(lookup_path.clone(), reference_type.clone(), request)
1625            .await?
1626        {
1627            return Ok(Some(*result));
1628        }
1629    }
1630    Ok(None)
1631}
1632
1633#[tracing::instrument(level = "trace", skip_all)]
1634async fn handle_after_resolve_plugins(
1635    lookup_path: FileSystemPath,
1636    reference_type: ReferenceType,
1637    request: Vc<Request>,
1638    options: Vc<ResolveOptions>,
1639    result: Vc<ResolveResult>,
1640) -> Result<Vc<ResolveResult>> {
1641    async fn apply_plugins_to_path(
1642        path: FileSystemPath,
1643        lookup_path: FileSystemPath,
1644        reference_type: ReferenceType,
1645        request: Vc<Request>,
1646        options: Vc<ResolveOptions>,
1647    ) -> Result<Option<Vc<ResolveResult>>> {
1648        for plugin in &options.await?.after_resolve_plugins {
1649            let after_resolve_condition = plugin.after_resolve_condition().resolve().await?;
1650            if *after_resolve_condition.matches(path.clone()).await?
1651                && let Some(result) = *plugin
1652                    .after_resolve(
1653                        path.clone(),
1654                        lookup_path.clone(),
1655                        reference_type.clone(),
1656                        request,
1657                    )
1658                    .await?
1659            {
1660                return Ok(Some(*result));
1661            }
1662        }
1663        Ok(None)
1664    }
1665
1666    let mut changed = false;
1667    let result_value = result.await?;
1668
1669    let mut new_primary = FxIndexMap::default();
1670    let mut new_affecting_sources = Vec::new();
1671
1672    for (key, primary) in result_value.primary.iter() {
1673        if let &ResolveResultItem::Source(source) = primary {
1674            let path = source.ident().path().owned().await?;
1675            if let Some(new_result) = apply_plugins_to_path(
1676                path.clone(),
1677                lookup_path.clone(),
1678                reference_type.clone(),
1679                request,
1680                options,
1681            )
1682            .await?
1683            {
1684                let new_result = new_result.await?;
1685                changed = true;
1686                new_primary.extend(
1687                    new_result
1688                        .primary
1689                        .iter()
1690                        .map(|(_, item)| (key.clone(), item.clone())),
1691                );
1692                new_affecting_sources.extend(new_result.affecting_sources.iter().copied());
1693            } else {
1694                new_primary.insert(key.clone(), primary.clone());
1695            }
1696        } else {
1697            new_primary.insert(key.clone(), primary.clone());
1698        }
1699    }
1700
1701    if !changed {
1702        return Ok(result);
1703    }
1704
1705    let mut affecting_sources = result_value.affecting_sources.to_vec();
1706    affecting_sources.append(&mut new_affecting_sources);
1707
1708    Ok(ResolveResult {
1709        primary: new_primary.into_iter().collect(),
1710        affecting_sources: affecting_sources.into_boxed_slice(),
1711    }
1712    .cell())
1713}
1714
1715#[turbo_tasks::function]
1716async fn resolve_internal(
1717    lookup_path: FileSystemPath,
1718    request: ResolvedVc<Request>,
1719    options: ResolvedVc<ResolveOptions>,
1720) -> Result<Vc<ResolveResult>> {
1721    resolve_internal_inline(lookup_path.clone(), *request, *options).await
1722}
1723
1724async fn resolve_internal_inline(
1725    lookup_path: FileSystemPath,
1726    request: Vc<Request>,
1727    options: Vc<ResolveOptions>,
1728) -> Result<Vc<ResolveResult>> {
1729    let span = tracing::info_span!(
1730        "internal resolving",
1731        lookup_path = display(lookup_path.value_to_string().await?),
1732        name = tracing::field::Empty
1733    );
1734    if !span.is_disabled() {
1735        // You can't await multiple times in the span macro call parameters.
1736        span.record("name", request.to_string().await?.as_str());
1737    }
1738
1739    async move {
1740        let options_value: &ResolveOptions = &*options.await?;
1741
1742        let request_value = request.await?;
1743
1744        // Apply import mappings if provided
1745        let mut has_alias = false;
1746        if let Some(import_map) = &options_value.import_map {
1747            let request_parts = match &*request_value {
1748                Request::Alternatives { requests } => requests.as_slice(),
1749                _ => &[request.to_resolved().await?],
1750            };
1751            for &request in request_parts {
1752                let result = import_map
1753                    .await?
1754                    .lookup(lookup_path.clone(), *request)
1755                    .await?;
1756                if !matches!(result, ImportMapResult::NoEntry) {
1757                    has_alias = true;
1758                    let resolved_result = resolve_import_map_result(
1759                        &result,
1760                        lookup_path.clone(),
1761                        lookup_path.clone(),
1762                        *request,
1763                        options,
1764                        request.query().owned().await?,
1765                    )
1766                    .await?;
1767                    // We might have matched an alias in the import map, but there is no guarantee
1768                    // the alias actually resolves to something. For instance, a tsconfig.json
1769                    // `compilerOptions.paths` option might alias "@*" to "./*", which
1770                    // would also match a request to "@emotion/core". Here, we follow what the
1771                    // Typescript resolution algorithm does in case an alias match
1772                    // doesn't resolve to anything: fall back to resolving the request normally.
1773                    if let Some(result) = resolved_result
1774                        && !*result.is_unresolvable().await?
1775                    {
1776                        return Ok(result);
1777                    }
1778                }
1779            }
1780        }
1781
1782        let result = match &*request_value {
1783            Request::Dynamic => *ResolveResult::unresolvable(),
1784            Request::Alternatives { requests } => {
1785                let results = requests
1786                    .iter()
1787                    .map(|req| async {
1788                        resolve_internal_inline(lookup_path.clone(), **req, options).await
1789                    })
1790                    .try_join()
1791                    .await?;
1792
1793                merge_results(results)
1794            }
1795            Request::Raw {
1796                path,
1797                query,
1798                force_in_lookup_dir,
1799                fragment,
1800            } => {
1801                let mut results = Vec::new();
1802                let matches = read_matches(
1803                    lookup_path.clone(),
1804                    rcstr!(""),
1805                    *force_in_lookup_dir,
1806                    Pattern::new(path.clone()).resolve().await?,
1807                )
1808                .await?;
1809
1810                for m in matches.iter() {
1811                    match m {
1812                        PatternMatch::File(matched_pattern, path) => {
1813                            results.push(
1814                                resolved(
1815                                    RequestKey::new(matched_pattern.clone()),
1816                                    path.clone(),
1817                                    lookup_path.clone(),
1818                                    request,
1819                                    options_value,
1820                                    options,
1821                                    query.clone(),
1822                                    fragment.clone(),
1823                                )
1824                                .await?,
1825                            );
1826                        }
1827                        PatternMatch::Directory(matched_pattern, path) => {
1828                            results.push(
1829                                resolve_into_folder(path.clone(), options)
1830                                    .with_request(matched_pattern.clone()),
1831                            );
1832                        }
1833                    }
1834                }
1835
1836                merge_results(results)
1837            }
1838            Request::Relative {
1839                path,
1840                query,
1841                force_in_lookup_dir,
1842                fragment,
1843            } => {
1844                resolve_relative_request(
1845                    lookup_path.clone(),
1846                    request,
1847                    options,
1848                    options_value,
1849                    path,
1850                    query.clone(),
1851                    *force_in_lookup_dir,
1852                    fragment.clone(),
1853                )
1854                .await?
1855            }
1856            Request::Module {
1857                module,
1858                path,
1859                query,
1860                fragment,
1861            } => {
1862                resolve_module_request(
1863                    lookup_path.clone(),
1864                    request,
1865                    options,
1866                    options_value,
1867                    module,
1868                    path,
1869                    query.clone(),
1870                    fragment.clone(),
1871                )
1872                .await?
1873            }
1874            Request::ServerRelative {
1875                path,
1876                query,
1877                fragment,
1878            } => {
1879                let mut new_pat = path.clone();
1880                new_pat.push_front(rcstr!(".").into());
1881                let relative = Request::relative(new_pat, query.clone(), fragment.clone(), true);
1882
1883                if !has_alias {
1884                    ResolvingIssue {
1885                        severity: error_severity(options).await?,
1886                        request_type: "server relative import: not implemented yet".to_string(),
1887                        request: relative.to_resolved().await?,
1888                        file_path: lookup_path.clone(),
1889                        resolve_options: options.to_resolved().await?,
1890                        error_message: Some(
1891                            "server relative imports are not implemented yet. Please try an \
1892                             import relative to the file you are importing from."
1893                                .to_string(),
1894                        ),
1895                        source: None,
1896                    }
1897                    .resolved_cell()
1898                    .emit();
1899                }
1900
1901                Box::pin(resolve_internal_inline(
1902                    lookup_path.root().owned().await?,
1903                    relative,
1904                    options,
1905                ))
1906                .await?
1907            }
1908            Request::Windows {
1909                path: _,
1910                query: _,
1911                fragment: _,
1912            } => {
1913                if !has_alias {
1914                    ResolvingIssue {
1915                        severity: error_severity(options).await?,
1916                        request_type: "windows import: not implemented yet".to_string(),
1917                        request: request.to_resolved().await?,
1918                        file_path: lookup_path.clone(),
1919                        resolve_options: options.to_resolved().await?,
1920                        error_message: Some("windows imports are not implemented yet".to_string()),
1921                        source: None,
1922                    }
1923                    .resolved_cell()
1924                    .emit();
1925                }
1926
1927                *ResolveResult::unresolvable()
1928            }
1929            Request::Empty => *ResolveResult::unresolvable(),
1930            Request::PackageInternal { path } => {
1931                let (conditions, unspecified_conditions) = options_value
1932                    .in_package
1933                    .iter()
1934                    .find_map(|item| match item {
1935                        ResolveInPackage::ImportsField {
1936                            conditions,
1937                            unspecified_conditions,
1938                        } => Some((Cow::Borrowed(conditions), *unspecified_conditions)),
1939                        _ => None,
1940                    })
1941                    .unwrap_or_else(|| (Default::default(), ConditionValue::Unset));
1942                resolve_package_internal_with_imports_field(
1943                    lookup_path.clone(),
1944                    request,
1945                    options,
1946                    path,
1947                    &conditions,
1948                    &unspecified_conditions,
1949                )
1950                .await?
1951            }
1952            Request::DataUri {
1953                media_type,
1954                encoding,
1955                data,
1956            } => {
1957                // Behave like Request::Uri
1958                let uri: RcStr = stringify_data_uri(media_type, encoding, *data)
1959                    .await?
1960                    .into();
1961                if options_value.parse_data_uris {
1962                    *ResolveResult::primary_with_key(
1963                        RequestKey::new(uri.clone()),
1964                        ResolveResultItem::Source(ResolvedVc::upcast(
1965                            DataUriSource::new(
1966                                media_type.clone(),
1967                                encoding.clone(),
1968                                **data,
1969                                lookup_path.clone(),
1970                            )
1971                            .to_resolved()
1972                            .await?,
1973                        )),
1974                    )
1975                } else {
1976                    *ResolveResult::primary_with_key(
1977                        RequestKey::new(uri.clone()),
1978                        ResolveResultItem::External {
1979                            name: uri,
1980                            ty: ExternalType::Url,
1981                            traced: ExternalTraced::Untraced,
1982                        },
1983                    )
1984                }
1985            }
1986            Request::Uri {
1987                protocol,
1988                remainder,
1989                query: _,
1990                fragment: _,
1991            } => {
1992                let uri: RcStr = format!("{protocol}{remainder}").into();
1993                *ResolveResult::primary_with_key(
1994                    RequestKey::new(uri.clone()),
1995                    ResolveResultItem::External {
1996                        name: uri,
1997                        ty: ExternalType::Url,
1998                        traced: ExternalTraced::Untraced,
1999                    },
2000                )
2001            }
2002            Request::Unknown { path } => {
2003                if !has_alias {
2004                    ResolvingIssue {
2005                        severity: error_severity(options).await?,
2006                        request_type: format!("unknown import: `{}`", path.describe_as_string()),
2007                        request: request.to_resolved().await?,
2008                        file_path: lookup_path.clone(),
2009                        resolve_options: options.to_resolved().await?,
2010                        error_message: None,
2011                        source: None,
2012                    }
2013                    .resolved_cell()
2014                    .emit();
2015                }
2016                *ResolveResult::unresolvable()
2017            }
2018        };
2019
2020        // The individual variants inside the alternative already looked at the fallback import
2021        // map in the recursive `resolve_internal_inline` calls
2022        if !matches!(*request_value, Request::Alternatives { .. }) {
2023            // Apply fallback import mappings if provided
2024            if let Some(import_map) = &options_value.fallback_import_map
2025                && *result.is_unresolvable().await?
2026            {
2027                let result = import_map
2028                    .await?
2029                    .lookup(lookup_path.clone(), request)
2030                    .await?;
2031                let resolved_result = resolve_import_map_result(
2032                    &result,
2033                    lookup_path.clone(),
2034                    lookup_path.clone(),
2035                    request,
2036                    options,
2037                    request.query().owned().await?,
2038                )
2039                .await?;
2040                if let Some(result) = resolved_result
2041                    && !*result.is_unresolvable().await?
2042                {
2043                    return Ok(result);
2044                }
2045            }
2046        }
2047
2048        Ok(result)
2049    }
2050    .instrument(span)
2051    .await
2052}
2053
2054#[turbo_tasks::function]
2055async fn resolve_into_folder(
2056    package_path: FileSystemPath,
2057    options: Vc<ResolveOptions>,
2058) -> Result<Vc<ResolveResult>> {
2059    let options_value = options.await?;
2060
2061    let mut affecting_sources = vec![];
2062    if let Some(package_json_path) = exists(
2063        &package_path.join("package.json")?,
2064        if options_value.collect_affecting_sources {
2065            Some(&mut affecting_sources)
2066        } else {
2067            None
2068        },
2069    )
2070    .await?
2071    {
2072        for resolve_into_package in options_value.into_package.iter() {
2073            match resolve_into_package {
2074                ResolveIntoPackage::MainField { field: name } => {
2075                    if let Some(package_json) =
2076                        &*read_package_json(Vc::upcast(FileSource::new(package_json_path.clone())))
2077                            .await?
2078                        && let Some(field_value) = package_json[name.as_str()].as_str()
2079                    {
2080                        let normalized_request = RcStr::from(normalize_request(field_value));
2081                        if normalized_request.is_empty()
2082                            || &*normalized_request == "."
2083                            || &*normalized_request == "./"
2084                        {
2085                            continue;
2086                        }
2087                        let request = Request::parse_string(normalized_request);
2088
2089                        // main field will always resolve not fully specified
2090                        let options = if options_value.fully_specified {
2091                            options.with_fully_specified(false).resolve().await?
2092                        } else {
2093                            options
2094                        };
2095                        let result =
2096                            &*resolve_internal_inline(package_path.clone(), request, options)
2097                                .await?
2098                                .await?;
2099                        // we are not that strict when a main field fails to resolve
2100                        // we continue to try other alternatives
2101                        if !result.is_unresolvable_ref() {
2102                            let mut result: ResolveResultBuilder =
2103                                result.with_request_ref(rcstr!(".")).into();
2104                            if options_value.collect_affecting_sources {
2105                                result.affecting_sources.push(ResolvedVc::upcast(
2106                                    FileSource::new(package_json_path).to_resolved().await?,
2107                                ));
2108                                result.affecting_sources.extend(affecting_sources);
2109                            }
2110                            return Ok(ResolveResult::from(result).cell());
2111                        }
2112                    };
2113                }
2114                ResolveIntoPackage::ExportsField { .. } => {}
2115            }
2116        }
2117    }
2118
2119    if options_value.fully_specified {
2120        return Ok(*ResolveResult::unresolvable_with_affecting_sources(
2121            affecting_sources,
2122        ));
2123    }
2124
2125    // fall back to dir/index.[js,ts,...]
2126    let pattern = match &options_value.default_files[..] {
2127        [] => {
2128            return Ok(*ResolveResult::unresolvable_with_affecting_sources(
2129                affecting_sources,
2130            ));
2131        }
2132        [file] => Pattern::Constant(format!("./{file}").into()),
2133        files => Pattern::Alternatives(
2134            files
2135                .iter()
2136                .map(|file| Pattern::Constant(format!("./{file}").into()))
2137                .collect(),
2138        ),
2139    };
2140
2141    let request = Request::parse(pattern);
2142    let result = resolve_internal_inline(package_path.clone(), request, options)
2143        .await?
2144        .with_request(rcstr!("."));
2145
2146    Ok(if !affecting_sources.is_empty() {
2147        result.with_affecting_sources(ResolvedVc::deref_vec(affecting_sources))
2148    } else {
2149        result
2150    })
2151}
2152
2153#[tracing::instrument(level = Level::TRACE, skip_all)]
2154async fn resolve_relative_request(
2155    lookup_path: FileSystemPath,
2156    request: Vc<Request>,
2157    options: Vc<ResolveOptions>,
2158    options_value: &ResolveOptions,
2159    path_pattern: &Pattern,
2160    query: RcStr,
2161    force_in_lookup_dir: bool,
2162    fragment: RcStr,
2163) -> Result<Vc<ResolveResult>> {
2164    // Check alias field for aliases first
2165    let lookup_path_ref = lookup_path.clone();
2166    if let Some(result) = apply_in_package(
2167        lookup_path.clone(),
2168        options,
2169        options_value,
2170        |package_path| {
2171            let request = path_pattern.as_constant_string()?;
2172            let prefix_path = package_path.get_path_to(&lookup_path_ref)?;
2173            let request = normalize_request(&format!("./{prefix_path}/{request}"));
2174            Some(request.into())
2175        },
2176        query.clone(),
2177        fragment.clone(),
2178    )
2179    .await?
2180    {
2181        return Ok(result);
2182    }
2183
2184    let mut new_path = path_pattern.clone();
2185
2186    if !fragment.is_empty() {
2187        new_path.push(Pattern::Alternatives(vec![
2188            Pattern::Constant(RcStr::default()),
2189            Pattern::Constant(fragment.clone()),
2190        ]));
2191    }
2192
2193    if !options_value.fully_specified {
2194        // Add the extensions as alternatives to the path
2195        // read_matches keeps the order of alternatives intact
2196        new_path.push(Pattern::Alternatives(
2197            once(Pattern::Constant(RcStr::default()))
2198                .chain(
2199                    options_value
2200                        .extensions
2201                        .iter()
2202                        .map(|ext| Pattern::Constant(ext.clone())),
2203                )
2204                .collect(),
2205        ));
2206        new_path.normalize();
2207    };
2208
2209    if options_value.enable_typescript_with_output_extension {
2210        new_path.replace_final_constants(&|c: &RcStr| -> Option<Pattern> {
2211            let (base, replacement) = match c.rsplit_once(".") {
2212                Some((base, "js")) => (
2213                    base,
2214                    vec![
2215                        Pattern::Constant(rcstr!(".ts")),
2216                        Pattern::Constant(rcstr!(".tsx")),
2217                        Pattern::Constant(rcstr!(".js")),
2218                    ],
2219                ),
2220                Some((base, "mjs")) => (
2221                    base,
2222                    vec![
2223                        Pattern::Constant(rcstr!(".mts")),
2224                        Pattern::Constant(rcstr!(".mjs")),
2225                    ],
2226                ),
2227                Some((base, "cjs")) => (
2228                    base,
2229                    vec![
2230                        Pattern::Constant(rcstr!(".cts")),
2231                        Pattern::Constant(rcstr!(".cjs")),
2232                    ],
2233                ),
2234                _ => {
2235                    return None;
2236                }
2237            };
2238            if base.is_empty() {
2239                Some(Pattern::Alternatives(replacement))
2240            } else {
2241                Some(Pattern::Concatenation(vec![
2242                    Pattern::Constant(base.into()),
2243                    Pattern::Alternatives(replacement),
2244                ]))
2245            }
2246        });
2247        new_path.normalize();
2248    }
2249
2250    let mut results = Vec::new();
2251    let matches = read_matches(
2252        lookup_path.clone(),
2253        rcstr!(""),
2254        force_in_lookup_dir,
2255        Pattern::new(new_path).resolve().await?,
2256    )
2257    .await?;
2258
2259    for m in matches.iter() {
2260        if let PatternMatch::File(matched_pattern, path) = m {
2261            let mut pushed = false;
2262            if !options_value.fully_specified {
2263                for ext in options_value.extensions.iter() {
2264                    let Some(matched_pattern) = matched_pattern.strip_suffix(&**ext) else {
2265                        continue;
2266                    };
2267
2268                    if !fragment.is_empty() {
2269                        // If the fragment is not empty, we need to strip it from the matched
2270                        // pattern
2271                        if let Some(matched_pattern) = matched_pattern
2272                            .strip_suffix(fragment.as_str())
2273                            .and_then(|s| s.strip_suffix('#'))
2274                        {
2275                            results.push(
2276                                resolved(
2277                                    RequestKey::new(matched_pattern.into()),
2278                                    path.clone(),
2279                                    lookup_path.clone(),
2280                                    request,
2281                                    options_value,
2282                                    options,
2283                                    query.clone(),
2284                                    RcStr::default(),
2285                                )
2286                                .await?,
2287                            );
2288                            pushed = true;
2289                        }
2290                    }
2291                    if !pushed && path_pattern.is_match(matched_pattern) {
2292                        results.push(
2293                            resolved(
2294                                RequestKey::new(matched_pattern.into()),
2295                                path.clone(),
2296                                lookup_path.clone(),
2297                                request,
2298                                options_value,
2299                                options,
2300                                query.clone(),
2301                                fragment.clone(),
2302                            )
2303                            .await?,
2304                        );
2305                        pushed = true;
2306                    }
2307                }
2308            }
2309            if !fragment.is_empty() {
2310                // If the fragment is not empty, we need to strip it from the matched pattern
2311                if let Some(matched_pattern) = matched_pattern.strip_suffix(fragment.as_str()) {
2312                    results.push(
2313                        resolved(
2314                            RequestKey::new(matched_pattern.into()),
2315                            path.clone(),
2316                            lookup_path.clone(),
2317                            request,
2318                            options_value,
2319                            options,
2320                            query.clone(),
2321                            RcStr::default(),
2322                        )
2323                        .await?,
2324                    );
2325                    pushed = true;
2326                }
2327            }
2328
2329            if !pushed || path_pattern.is_match(matched_pattern) {
2330                results.push(
2331                    resolved(
2332                        RequestKey::new(matched_pattern.clone()),
2333                        path.clone(),
2334                        lookup_path.clone(),
2335                        request,
2336                        options_value,
2337                        options,
2338                        query.clone(),
2339                        fragment.clone(),
2340                    )
2341                    .await?,
2342                );
2343            }
2344        }
2345    }
2346    // Directory matches must be resolved AFTER file matches
2347    for m in matches.iter() {
2348        if let PatternMatch::Directory(matched_pattern, path) = m {
2349            results.push(
2350                resolve_into_folder(path.clone(), options).with_request(matched_pattern.clone()),
2351            );
2352        }
2353    }
2354
2355    Ok(merge_results(results))
2356}
2357
2358#[tracing::instrument(level = Level::TRACE, skip_all)]
2359async fn apply_in_package(
2360    lookup_path: FileSystemPath,
2361    options: Vc<ResolveOptions>,
2362    options_value: &ResolveOptions,
2363    get_request: impl Fn(&FileSystemPath) -> Option<RcStr>,
2364    query: RcStr,
2365    fragment: RcStr,
2366) -> Result<Option<Vc<ResolveResult>>> {
2367    // Check alias field for module aliases first
2368    for in_package in options_value.in_package.iter() {
2369        // resolve_module_request is called when importing a node
2370        // module, not a PackageInternal one, so the imports field
2371        // doesn't apply.
2372        let ResolveInPackage::AliasField(field) = in_package else {
2373            continue;
2374        };
2375
2376        let FindContextFileResult::Found(package_json_path, refs) = &*find_context_file(
2377            lookup_path.clone(),
2378            package_json().resolve().await?,
2379            options_value.collect_affecting_sources,
2380        )
2381        .await?
2382        else {
2383            continue;
2384        };
2385
2386        let read =
2387            read_package_json(Vc::upcast(FileSource::new(package_json_path.clone()))).await?;
2388        let Some(package_json) = &*read else {
2389            continue;
2390        };
2391
2392        let Some(field_value) = package_json[field.as_str()].as_object() else {
2393            continue;
2394        };
2395
2396        let package_path = package_json_path.parent();
2397
2398        let Some(request) = get_request(&package_path) else {
2399            continue;
2400        };
2401
2402        let value = if let Some(value) = field_value.get(&*request) {
2403            value
2404        } else if let Some(request) = request.strip_prefix("./") {
2405            let Some(value) = field_value.get(request) else {
2406                continue;
2407            };
2408            value
2409        } else {
2410            continue;
2411        };
2412
2413        let refs = refs.clone();
2414        let request_key = RequestKey::new(request.clone());
2415
2416        if value.as_bool() == Some(false) {
2417            return Ok(Some(*ResolveResult::primary_with_affecting_sources(
2418                request_key,
2419                ResolveResultItem::Ignore,
2420                refs,
2421            )));
2422        }
2423
2424        if let Some(value) = value.as_str() {
2425            if value == &*request {
2426                // This would be a cycle, so we ignore it
2427                return Ok(None);
2428            }
2429            let mut result = resolve_internal(
2430                package_path,
2431                Request::parse(Pattern::Constant(value.into()))
2432                    .with_query(query.clone())
2433                    .with_fragment(fragment.clone()),
2434                options,
2435            )
2436            .with_replaced_request_key(value.into(), request_key);
2437            if options_value.collect_affecting_sources && !refs.is_empty() {
2438                result = result.with_affecting_sources(refs.into_iter().map(|src| *src).collect());
2439            }
2440            return Ok(Some(result));
2441        }
2442
2443        ResolvingIssue {
2444            severity: error_severity(options).await?,
2445            file_path: package_json_path.clone(),
2446            request_type: format!("alias field ({field})"),
2447            request: Request::parse(Pattern::Constant(request))
2448                .to_resolved()
2449                .await?,
2450            resolve_options: options.to_resolved().await?,
2451            error_message: Some(format!("invalid alias field value: {value}")),
2452            source: None,
2453        }
2454        .resolved_cell()
2455        .emit();
2456
2457        return Ok(Some(*ResolveResult::unresolvable_with_affecting_sources(
2458            refs,
2459        )));
2460    }
2461    Ok(None)
2462}
2463
2464#[turbo_tasks::value]
2465enum FindSelfReferencePackageResult {
2466    Found {
2467        name: String,
2468        package_path: FileSystemPath,
2469    },
2470    NotFound,
2471}
2472
2473#[turbo_tasks::function]
2474/// Finds the nearest folder containing package.json that could be used for a
2475/// self-reference (i.e. has an exports fields).
2476async fn find_self_reference(
2477    lookup_path: FileSystemPath,
2478) -> Result<Vc<FindSelfReferencePackageResult>> {
2479    let package_json_context = find_context_file(lookup_path, package_json(), false).await?;
2480    if let FindContextFileResult::Found(package_json_path, _refs) = &*package_json_context {
2481        let read =
2482            read_package_json(Vc::upcast(FileSource::new(package_json_path.clone()))).await?;
2483        if let Some(json) = &*read
2484            && json.get("exports").is_some()
2485            && let Some(name) = json["name"].as_str()
2486        {
2487            return Ok(FindSelfReferencePackageResult::Found {
2488                name: name.to_string(),
2489                package_path: package_json_path.parent(),
2490            }
2491            .cell());
2492        }
2493    }
2494    Ok(FindSelfReferencePackageResult::NotFound.cell())
2495}
2496
2497#[tracing::instrument(level = Level::TRACE, skip_all)]
2498async fn resolve_module_request(
2499    lookup_path: FileSystemPath,
2500    request: Vc<Request>,
2501    options: Vc<ResolveOptions>,
2502    options_value: &ResolveOptions,
2503    module: &Pattern,
2504    path: &Pattern,
2505    query: RcStr,
2506    fragment: RcStr,
2507) -> Result<Vc<ResolveResult>> {
2508    // Check alias field for module aliases first
2509    if let Some(result) = apply_in_package(
2510        lookup_path.clone(),
2511        options,
2512        options_value,
2513        |_| {
2514            let full_pattern = Pattern::concat([module.clone(), path.clone()]);
2515            full_pattern.as_constant_string().cloned()
2516        },
2517        query.clone(),
2518        fragment.clone(),
2519    )
2520    .await?
2521    {
2522        return Ok(result);
2523    }
2524
2525    let mut results = vec![];
2526
2527    // Self references, if the nearest package.json has the name of the requested
2528    // module. This should match only using the exports field and no other
2529    // fields/fallbacks.
2530    if let FindSelfReferencePackageResult::Found { name, package_path } =
2531        &*find_self_reference(lookup_path.clone()).await?
2532        && module.is_match(name)
2533    {
2534        let result = resolve_into_package(
2535            path.clone(),
2536            package_path.clone(),
2537            query.clone(),
2538            fragment.clone(),
2539            options,
2540        );
2541        if !(*result.is_unresolvable().await?) {
2542            return Ok(result);
2543        }
2544    }
2545
2546    let result = find_package(
2547        lookup_path.clone(),
2548        module.clone(),
2549        resolve_modules_options(options).resolve().await?,
2550        options_value.collect_affecting_sources,
2551    )
2552    .await?;
2553
2554    if result.packages.is_empty() {
2555        return Ok(*ResolveResult::unresolvable_with_affecting_sources(
2556            result.affecting_sources.clone(),
2557        ));
2558    }
2559
2560    // There may be more than one package with the same name. For instance, in a
2561    // TypeScript project, `compilerOptions.baseUrl` can declare a path where to
2562    // resolve packages. A request to "foo/bar" might resolve to either
2563    // "[baseUrl]/foo/bar" or "[baseUrl]/node_modules/foo/bar", and we'll need to
2564    // try both.
2565    for item in &result.packages {
2566        match item {
2567            FindPackageItem::PackageDirectory { name, dir } => {
2568                results.push(
2569                    resolve_into_package(
2570                        path.clone(),
2571                        dir.clone(),
2572                        query.clone(),
2573                        fragment.clone(),
2574                        options,
2575                    )
2576                    .with_replaced_request_key(rcstr!("."), RequestKey::new(name.clone())),
2577                );
2578            }
2579            FindPackageItem::PackageFile { name, file } => {
2580                if path.is_match("") {
2581                    let resolved = resolved(
2582                        RequestKey::new(rcstr!(".")),
2583                        file.clone(),
2584                        lookup_path.clone(),
2585                        request,
2586                        options_value,
2587                        options,
2588                        query.clone(),
2589                        fragment.clone(),
2590                    )
2591                    .await?
2592                    .with_replaced_request_key(rcstr!("."), RequestKey::new(name.clone()));
2593                    results.push(resolved)
2594                }
2595            }
2596        }
2597    }
2598
2599    let module_result =
2600        merge_results_with_affecting_sources(results, result.affecting_sources.clone());
2601
2602    if options_value.prefer_relative {
2603        let mut module_prefixed = module.clone();
2604        module_prefixed.push_front(rcstr!("./").into());
2605        let pattern = Pattern::concat([module_prefixed.clone(), rcstr!("/").into(), path.clone()]);
2606        let relative = Request::relative(pattern, query, fragment, true)
2607            .to_resolved()
2608            .await?;
2609        let relative_result = Box::pin(resolve_internal_inline(
2610            lookup_path.clone(),
2611            *relative,
2612            options,
2613        ))
2614        .await?;
2615        let relative_result = relative_result.with_stripped_request_key_prefix(rcstr!("./"));
2616
2617        Ok(merge_results(vec![relative_result, module_result]))
2618    } else {
2619        Ok(module_result)
2620    }
2621}
2622
2623#[turbo_tasks::function]
2624async fn resolve_into_package(
2625    path: Pattern,
2626    package_path: FileSystemPath,
2627    query: RcStr,
2628    fragment: RcStr,
2629    options: ResolvedVc<ResolveOptions>,
2630) -> Result<Vc<ResolveResult>> {
2631    let options_value = options.await?;
2632    let mut results = Vec::new();
2633
2634    let is_root_match = path.is_match("") || path.is_match("/");
2635    let could_match_others = path.could_match_others("");
2636
2637    let mut export_path_request = path.clone();
2638    export_path_request.push_front(rcstr!(".").into());
2639    for resolve_into_package in options_value.into_package.iter() {
2640        match resolve_into_package {
2641            // handled by the `resolve_into_folder` call below
2642            ResolveIntoPackage::MainField { .. } => {}
2643            ResolveIntoPackage::ExportsField {
2644                conditions,
2645                unspecified_conditions,
2646            } => {
2647                let package_json_path = package_path.join("package.json")?;
2648                let ExportsFieldResult::Some(exports_field) =
2649                    &*exports_field(Vc::upcast(FileSource::new(package_json_path.clone()))).await?
2650                else {
2651                    continue;
2652                };
2653
2654                results.push(
2655                    handle_exports_imports_field(
2656                        package_path.clone(),
2657                        package_json_path,
2658                        *options,
2659                        exports_field,
2660                        export_path_request.clone(),
2661                        conditions,
2662                        unspecified_conditions,
2663                        query,
2664                    )
2665                    .await?,
2666                );
2667
2668                // other options do not apply anymore when an exports
2669                // field exist
2670                return Ok(merge_results(results));
2671            }
2672        }
2673    }
2674
2675    // apply main field(s) or fallback to index.js if there's no subpath
2676    if is_root_match {
2677        results.push(resolve_into_folder(
2678            package_path.clone(),
2679            options.with_fully_specified(false),
2680        ));
2681    }
2682
2683    if could_match_others {
2684        let mut new_pat = path.clone();
2685        new_pat.push_front(rcstr!(".").into());
2686
2687        let relative = Request::relative(new_pat, query, fragment, true)
2688            .to_resolved()
2689            .await?;
2690        results.push(resolve_internal_inline(package_path.clone(), *relative, *options).await?);
2691    }
2692
2693    Ok(merge_results(results))
2694}
2695
2696#[tracing::instrument(level = Level::TRACE, skip_all)]
2697async fn resolve_import_map_result(
2698    result: &ImportMapResult,
2699    lookup_path: FileSystemPath,
2700    original_lookup_path: FileSystemPath,
2701    original_request: Vc<Request>,
2702    options: Vc<ResolveOptions>,
2703    query: RcStr,
2704) -> Result<Option<Vc<ResolveResult>>> {
2705    Ok(match result {
2706        ImportMapResult::Result(result) => Some(**result),
2707        ImportMapResult::Alias(request, alias_lookup_path) => {
2708            let request = **request;
2709            let lookup_path = match alias_lookup_path {
2710                Some(path) => path.clone(),
2711                None => lookup_path,
2712            };
2713            // We must avoid cycles during resolving
2714            if request == original_request && lookup_path == original_lookup_path {
2715                None
2716            } else {
2717                let result = resolve_internal(lookup_path, request, options);
2718                Some(result.with_replaced_request_key_pattern(
2719                    request.request_pattern(),
2720                    original_request.request_pattern(),
2721                ))
2722            }
2723        }
2724        ImportMapResult::External(name, ty, traced) => {
2725            Some(*ResolveResult::primary(ResolveResultItem::External {
2726                name: name.clone(),
2727                ty: *ty,
2728                traced: *traced,
2729            }))
2730        }
2731        ImportMapResult::AliasExternal {
2732            name,
2733            ty,
2734            traced,
2735            lookup_dir: alias_lookup_path,
2736        } => {
2737            let request = Request::parse_string(name.clone());
2738
2739            // We must avoid cycles during resolving
2740            if request.resolve().await? == original_request
2741                && *alias_lookup_path == original_lookup_path
2742            {
2743                None
2744            } else {
2745                let is_external_resolvable = !resolve_internal(
2746                    alias_lookup_path.clone(),
2747                    request,
2748                    match ty {
2749                        // TODO is that root correct?
2750                        ExternalType::CommonJs => {
2751                            node_cjs_resolve_options(alias_lookup_path.root().owned().await?)
2752                        }
2753                        ExternalType::EcmaScriptModule => {
2754                            node_esm_resolve_options(alias_lookup_path.root().owned().await?)
2755                        }
2756                        ExternalType::Script | ExternalType::Url | ExternalType::Global => options,
2757                    },
2758                )
2759                .await?
2760                .is_unresolvable_ref();
2761                if is_external_resolvable {
2762                    Some(*ResolveResult::primary(ResolveResultItem::External {
2763                        name: name.clone(),
2764                        ty: *ty,
2765                        traced: *traced,
2766                    }))
2767                } else {
2768                    None
2769                }
2770            }
2771        }
2772        ImportMapResult::Alternatives(list) => {
2773            let results = list
2774                .iter()
2775                .map(|result| {
2776                    resolve_import_map_result(
2777                        result,
2778                        lookup_path.clone(),
2779                        original_lookup_path.clone(),
2780                        original_request,
2781                        options,
2782                        query.clone(),
2783                    )
2784                })
2785                .try_join()
2786                .await?;
2787
2788            Some(merge_results(results.into_iter().flatten().collect()))
2789        }
2790        ImportMapResult::NoEntry => None,
2791    })
2792}
2793
2794#[tracing::instrument(level = Level::TRACE, skip_all)]
2795async fn resolved(
2796    request_key: RequestKey,
2797    fs_path: FileSystemPath,
2798    original_context: FileSystemPath,
2799    original_request: Vc<Request>,
2800    options_value: &ResolveOptions,
2801    options: Vc<ResolveOptions>,
2802    query: RcStr,
2803    fragment: RcStr,
2804) -> Result<Vc<ResolveResult>> {
2805    let result = &*fs_path.realpath_with_links().await?;
2806    let path = match &result.path_result {
2807        Ok(path) => path,
2808        Err(e) => bail!(e.as_error_message(&fs_path, result)),
2809    };
2810
2811    let path_ref = path.clone();
2812    // Check alias field for path aliases first
2813    if let Some(result) = apply_in_package(
2814        path.parent(),
2815        options,
2816        options_value,
2817        |package_path| package_path.get_relative_path_to(&path_ref),
2818        query.clone(),
2819        fragment.clone(),
2820    )
2821    .await?
2822    {
2823        return Ok(result);
2824    }
2825
2826    if let Some(resolved_map) = options_value.resolved_map {
2827        let result = resolved_map
2828            .lookup(path.clone(), original_context.clone(), original_request)
2829            .await?;
2830
2831        let resolved_result = resolve_import_map_result(
2832            &result,
2833            path.parent(),
2834            original_context.clone(),
2835            original_request,
2836            options,
2837            query.clone(),
2838        )
2839        .await?;
2840
2841        if let Some(result) = resolved_result {
2842            return Ok(result);
2843        }
2844    }
2845    let source = ResolvedVc::upcast(
2846        FileSource::new_with_query_and_fragment(path.clone(), query, fragment)
2847            .to_resolved()
2848            .await?,
2849    );
2850    Ok(if options_value.collect_affecting_sources {
2851        ResolveResult::source_with_affecting_sources(
2852            request_key,
2853            source,
2854            result
2855                .symlinks
2856                .iter()
2857                .map(|symlink| async move {
2858                    anyhow::Ok(ResolvedVc::upcast(
2859                        FileSource::new(symlink.clone()).to_resolved().await?,
2860                    ))
2861                })
2862                .try_join()
2863                .await?,
2864        )
2865    } else {
2866        ResolveResult::source_with_key(request_key, source)
2867    }
2868    .cell())
2869}
2870
2871async fn handle_exports_imports_field(
2872    package_path: FileSystemPath,
2873    package_json_path: FileSystemPath,
2874    options: Vc<ResolveOptions>,
2875    exports_imports_field: &AliasMap<SubpathValue>,
2876    mut path: Pattern,
2877    conditions: &BTreeMap<RcStr, ConditionValue>,
2878    unspecified_conditions: &ConditionValue,
2879    query: RcStr,
2880) -> Result<Vc<ResolveResult>> {
2881    let mut results = Vec::new();
2882    let mut conditions_state = FxHashMap::default();
2883
2884    if !query.is_empty() {
2885        path.push(query.into());
2886    }
2887    let req = path;
2888
2889    let values = exports_imports_field.lookup(&req);
2890    for value in values {
2891        let value = value?;
2892        if value.output.add_results(
2893            value.prefix,
2894            value.key,
2895            conditions,
2896            unspecified_conditions,
2897            &mut conditions_state,
2898            &mut results,
2899        ) {
2900            // Match found, stop (leveraging the lazy `lookup` iterator).
2901            break;
2902        }
2903    }
2904
2905    let mut resolved_results = Vec::new();
2906    for ReplacedSubpathValueResult {
2907        result_path,
2908        conditions,
2909        map_prefix,
2910        map_key,
2911    } in results
2912    {
2913        if let Some(result_path) = result_path.with_normalized_path() {
2914            let request = Request::parse(Pattern::Concatenation(vec![
2915                Pattern::Constant(rcstr!("./")),
2916                result_path.clone(),
2917            ]))
2918            .resolve()
2919            .await?;
2920
2921            let resolve_result = Box::pin(resolve_internal_inline(
2922                package_path.clone(),
2923                request,
2924                options,
2925            ))
2926            .await?;
2927
2928            let resolve_result = if let Some(req) = req.as_constant_string() {
2929                resolve_result.with_request(req.clone())
2930            } else {
2931                match map_key {
2932                    AliasKey::Exact => resolve_result.with_request(map_prefix.clone().into()),
2933                    AliasKey::Wildcard { .. } => {
2934                        // - `req` is the user's request (key of the export map)
2935                        // - `result_path` is the final request (value of the export map), so
2936                        //   effectively `'{foo}*{bar}'`
2937
2938                        // Because of the assertion in AliasMapLookupIterator, `req` is of the
2939                        // form:
2940                        // - "prefix...<dynamic>" or
2941                        // - "prefix...<dynamic>...suffix"
2942
2943                        let mut old_request_key = result_path;
2944                        // Remove the Pattern::Constant(rcstr!("./")), from above again
2945                        old_request_key.push_front(rcstr!("./").into());
2946                        let new_request_key = req.clone();
2947
2948                        resolve_result.with_replaced_request_key_pattern(
2949                            Pattern::new(old_request_key),
2950                            Pattern::new(new_request_key),
2951                        )
2952                    }
2953                }
2954            };
2955
2956            let resolve_result = if !conditions.is_empty() {
2957                let mut resolve_result = resolve_result.owned().await?;
2958                resolve_result.add_conditions(conditions);
2959                resolve_result.cell()
2960            } else {
2961                resolve_result
2962            };
2963            resolved_results.push(resolve_result);
2964        }
2965    }
2966
2967    // other options do not apply anymore when an exports field exist
2968    Ok(merge_results_with_affecting_sources(
2969        resolved_results,
2970        vec![ResolvedVc::upcast(
2971            FileSource::new(package_json_path).to_resolved().await?,
2972        )],
2973    ))
2974}
2975
2976/// Resolves a `#dep` import using the containing package.json's `imports`
2977/// field. The dep may be a constant string or a pattern, and the values can be
2978/// static strings or conditions like `import` or `require` to handle ESM/CJS
2979/// with differently compiled files.
2980async fn resolve_package_internal_with_imports_field(
2981    file_path: FileSystemPath,
2982    request: Vc<Request>,
2983    resolve_options: Vc<ResolveOptions>,
2984    pattern: &Pattern,
2985    conditions: &BTreeMap<RcStr, ConditionValue>,
2986    unspecified_conditions: &ConditionValue,
2987) -> Result<Vc<ResolveResult>> {
2988    let Pattern::Constant(specifier) = pattern else {
2989        bail!("PackageInternal requests can only be Constant strings");
2990    };
2991    // https://github.com/nodejs/node/blob/1b177932/lib/internal/modules/esm/resolve.js#L615-L619
2992    if specifier == "#" || specifier.starts_with("#/") || specifier.ends_with('/') {
2993        ResolvingIssue {
2994            severity: error_severity(resolve_options).await?,
2995            file_path: file_path.clone(),
2996            request_type: format!("package imports request: `{specifier}`"),
2997            request: request.to_resolved().await?,
2998            resolve_options: resolve_options.to_resolved().await?,
2999            error_message: None,
3000            source: None,
3001        }
3002        .resolved_cell()
3003        .emit();
3004        return Ok(*ResolveResult::unresolvable());
3005    }
3006
3007    let imports_result = imports_field(file_path).await?;
3008    let (imports, package_json_path) = match &*imports_result {
3009        ImportsFieldResult::Some(i, p) => (i, p.clone()),
3010        ImportsFieldResult::None => return Ok(*ResolveResult::unresolvable()),
3011    };
3012
3013    handle_exports_imports_field(
3014        package_json_path.parent(),
3015        package_json_path.clone(),
3016        resolve_options,
3017        imports,
3018        Pattern::Constant(specifier.clone()),
3019        conditions,
3020        unspecified_conditions,
3021        RcStr::default(),
3022    )
3023    .await
3024}
3025
3026pub async fn handle_resolve_error(
3027    result: Vc<ModuleResolveResult>,
3028    reference_type: ReferenceType,
3029    origin_path: FileSystemPath,
3030    request: Vc<Request>,
3031    resolve_options: Vc<ResolveOptions>,
3032    is_optional: bool,
3033    source: Option<IssueSource>,
3034) -> Result<Vc<ModuleResolveResult>> {
3035    async fn is_unresolvable(result: Vc<ModuleResolveResult>) -> Result<bool> {
3036        Ok(*result.resolve().await?.is_unresolvable().await?)
3037    }
3038    Ok(match is_unresolvable(result).await {
3039        Ok(unresolvable) => {
3040            if unresolvable {
3041                emit_unresolvable_issue(
3042                    is_optional,
3043                    origin_path,
3044                    reference_type,
3045                    request,
3046                    resolve_options,
3047                    source,
3048                )
3049                .await?;
3050            }
3051
3052            result
3053        }
3054        Err(err) => {
3055            emit_resolve_error_issue(
3056                is_optional,
3057                origin_path,
3058                reference_type,
3059                request,
3060                resolve_options,
3061                err,
3062                source,
3063            )
3064            .await?;
3065            *ModuleResolveResult::unresolvable()
3066        }
3067    })
3068}
3069
3070pub async fn handle_resolve_source_error(
3071    result: Vc<ResolveResult>,
3072    reference_type: ReferenceType,
3073    origin_path: FileSystemPath,
3074    request: Vc<Request>,
3075    resolve_options: Vc<ResolveOptions>,
3076    is_optional: bool,
3077    source: Option<IssueSource>,
3078) -> Result<Vc<ResolveResult>> {
3079    async fn is_unresolvable(result: Vc<ResolveResult>) -> Result<bool> {
3080        Ok(*result.resolve().await?.is_unresolvable().await?)
3081    }
3082    Ok(match is_unresolvable(result).await {
3083        Ok(unresolvable) => {
3084            if unresolvable {
3085                emit_unresolvable_issue(
3086                    is_optional,
3087                    origin_path,
3088                    reference_type,
3089                    request,
3090                    resolve_options,
3091                    source,
3092                )
3093                .await?;
3094            }
3095
3096            result
3097        }
3098        Err(err) => {
3099            emit_resolve_error_issue(
3100                is_optional,
3101                origin_path,
3102                reference_type,
3103                request,
3104                resolve_options,
3105                err,
3106                source,
3107            )
3108            .await?;
3109            *ResolveResult::unresolvable()
3110        }
3111    })
3112}
3113
3114async fn emit_resolve_error_issue(
3115    is_optional: bool,
3116    origin_path: FileSystemPath,
3117    reference_type: ReferenceType,
3118    request: Vc<Request>,
3119    resolve_options: Vc<ResolveOptions>,
3120    err: anyhow::Error,
3121    source: Option<IssueSource>,
3122) -> Result<()> {
3123    let severity = if is_optional || resolve_options.await?.loose_errors {
3124        IssueSeverity::Warning
3125    } else {
3126        IssueSeverity::Error
3127    };
3128    ResolvingIssue {
3129        severity,
3130        file_path: origin_path.clone(),
3131        request_type: format!("{reference_type} request"),
3132        request: request.to_resolved().await?,
3133        resolve_options: resolve_options.to_resolved().await?,
3134        error_message: Some(format!("{}", PrettyPrintError(&err))),
3135        source,
3136    }
3137    .resolved_cell()
3138    .emit();
3139    Ok(())
3140}
3141
3142async fn emit_unresolvable_issue(
3143    is_optional: bool,
3144    origin_path: FileSystemPath,
3145    reference_type: ReferenceType,
3146    request: Vc<Request>,
3147    resolve_options: Vc<ResolveOptions>,
3148    source: Option<IssueSource>,
3149) -> Result<()> {
3150    let severity = if is_optional || resolve_options.await?.loose_errors {
3151        IssueSeverity::Warning
3152    } else {
3153        IssueSeverity::Error
3154    };
3155    ResolvingIssue {
3156        severity,
3157        file_path: origin_path.clone(),
3158        request_type: format!("{reference_type} request"),
3159        request: request.to_resolved().await?,
3160        resolve_options: resolve_options.to_resolved().await?,
3161        error_message: None,
3162        source,
3163    }
3164    .resolved_cell()
3165    .emit();
3166    Ok(())
3167}
3168
3169async fn error_severity(resolve_options: Vc<ResolveOptions>) -> Result<IssueSeverity> {
3170    Ok(if resolve_options.await?.loose_errors {
3171        IssueSeverity::Warning
3172    } else {
3173        IssueSeverity::Error
3174    })
3175}
3176
3177/// ModulePart represents a part of a module.
3178///
3179/// Currently this is used only for ESMs.
3180#[derive(
3181    Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, TraceRawVcs, TaskInput, NonLocalValue,
3182)]
3183pub enum ModulePart {
3184    /// Represents the side effects of a module. This part is evaluated even if
3185    /// all exports are unused.
3186    Evaluation,
3187    /// Represents an export of a module.
3188    Export(RcStr),
3189    /// Represents a renamed export of a module.
3190    RenamedExport {
3191        original_export: RcStr,
3192        export: RcStr,
3193    },
3194    /// Represents a namespace object of a module exported as named export.
3195    RenamedNamespace { export: RcStr },
3196    /// A pointer to a specific part.
3197    Internal(u32),
3198    /// The local declarations of a module.
3199    Locals,
3200    /// The whole exports of a module.
3201    Exports,
3202    /// A facade of the module behaving like the original, but referencing
3203    /// internal parts.
3204    Facade,
3205}
3206
3207impl ModulePart {
3208    pub fn evaluation() -> Self {
3209        ModulePart::Evaluation
3210    }
3211
3212    pub fn export(export: RcStr) -> Self {
3213        ModulePart::Export(export)
3214    }
3215
3216    pub fn renamed_export(original_export: RcStr, export: RcStr) -> Self {
3217        ModulePart::RenamedExport {
3218            original_export,
3219            export,
3220        }
3221    }
3222
3223    pub fn renamed_namespace(export: RcStr) -> Self {
3224        ModulePart::RenamedNamespace { export }
3225    }
3226
3227    pub fn internal(id: u32) -> Self {
3228        ModulePart::Internal(id)
3229    }
3230
3231    pub fn locals() -> Self {
3232        ModulePart::Locals
3233    }
3234
3235    pub fn exports() -> Self {
3236        ModulePart::Exports
3237    }
3238
3239    pub fn facade() -> Self {
3240        ModulePart::Facade
3241    }
3242}
3243
3244impl Display for ModulePart {
3245    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3246        match self {
3247            ModulePart::Evaluation => f.write_str("module evaluation"),
3248            ModulePart::Export(export) => write!(f, "export {export}"),
3249            ModulePart::RenamedExport {
3250                original_export,
3251                export,
3252            } => write!(f, "export {original_export} as {export}"),
3253            ModulePart::RenamedNamespace { export } => {
3254                write!(f, "export * as {export}")
3255            }
3256            ModulePart::Internal(id) => write!(f, "internal part {id}"),
3257            ModulePart::Locals => f.write_str("locals"),
3258            ModulePart::Exports => f.write_str("exports"),
3259            ModulePart::Facade => f.write_str("facade"),
3260        }
3261    }
3262}