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