Skip to main content

turbopack_core/resolve/
origin.rs

1use std::future::Future;
2
3use anyhow::Result;
4use turbo_rcstr::RcStr;
5use turbo_tasks::{ResolvedVc, Upcast, Vc};
6use turbo_tasks_fs::FileSystemPath;
7
8use super::{ModuleResolveResult, options::ResolveOptions, parse::Request};
9use crate::{context::AssetContext, reference_type::ReferenceType};
10
11/// A location where resolving can occur from. It carries some meta information
12/// that are needed for resolving from here.
13#[turbo_tasks::value_trait]
14pub trait ResolveOrigin {
15    /// The origin path where resolving starts. This is pointing to a file,
16    /// since that might be needed to infer custom resolving options for that
17    /// specific file. But usually only the directory is relevant for the real
18    /// resolving.
19    fn origin_path(&self) -> FileSystemPath;
20
21    /// The AssetContext that carries the configuration for building that
22    /// subgraph.
23    fn asset_context(&self) -> ResolvedVc<Box<dyn AssetContext>>;
24
25    /// Get the resolve options that apply for this origin.
26    fn resolve_options(&self) -> Vc<ResolveOptions> {
27        self.asset_context().resolve_options(self.origin_path())
28    }
29}
30
31// TODO it would be nice if these methods can be moved to the trait to allow
32// overriding it, but currently we explicitly disallow it due to the way
33// transitions work. Maybe transitions should be decorators on ResolveOrigin?
34pub trait ResolveOriginExt: Send {
35    /// Resolve to an asset from that origin. Custom resolve options can be
36    /// passed. Otherwise provide `origin.resolve_options()` unmodified.
37    fn resolve_asset(
38        self: Vc<Self>,
39        request: Vc<Request>,
40        options: Vc<ResolveOptions>,
41        reference_type: ReferenceType,
42    ) -> impl Future<Output = Result<Vc<ModuleResolveResult>>> + Send;
43
44    /// Adds a transition that is used for resolved assets.
45    fn with_transition(
46        self: ResolvedVc<Self>,
47        transition: RcStr,
48    ) -> impl Future<Output = Result<Vc<Box<dyn ResolveOrigin>>>> + Send;
49}
50
51impl<T> ResolveOriginExt for T
52where
53    T: ResolveOrigin + Upcast<Box<dyn ResolveOrigin>>,
54{
55    async fn resolve_asset(
56        self: Vc<Self>,
57        request: Vc<Request>,
58        options: Vc<ResolveOptions>,
59        reference_type: ReferenceType,
60    ) -> Result<Vc<ModuleResolveResult>> {
61        let origin = Vc::upcast_non_strict::<Box<dyn ResolveOrigin>>(self)
62            .into_trait_ref()
63            .await?;
64        Ok(origin.asset_context().resolve_asset(
65            origin.origin_path(),
66            *request.to_resolved().await?,
67            *options.to_resolved().await?,
68            reference_type,
69        ))
70    }
71
72    async fn with_transition(
73        self: ResolvedVc<Self>,
74        transition: RcStr,
75    ) -> Result<Vc<Box<dyn ResolveOrigin>>> {
76        let origin = Vc::upcast_non_strict::<Box<dyn ResolveOrigin>>(*self)
77            .into_trait_ref()
78            .await?;
79        Ok(Vc::upcast(
80            ResolveOriginWithTransition {
81                origin_path: origin.origin_path(),
82                asset_context: origin
83                    .asset_context()
84                    .with_transition(transition)
85                    .to_resolved()
86                    .await?,
87            }
88            .cell(),
89        ))
90    }
91}
92
93/// A resolve origin for some path and context without additional modifications.
94#[turbo_tasks::value]
95pub struct PlainResolveOrigin {
96    asset_context: ResolvedVc<Box<dyn AssetContext>>,
97    origin_path: FileSystemPath,
98}
99
100#[turbo_tasks::value_impl]
101impl PlainResolveOrigin {
102    #[turbo_tasks::function]
103    pub fn new(
104        asset_context: ResolvedVc<Box<dyn AssetContext>>,
105        origin_path: FileSystemPath,
106    ) -> Vc<Self> {
107        PlainResolveOrigin {
108            asset_context,
109            origin_path,
110        }
111        .cell()
112    }
113}
114
115#[turbo_tasks::value_impl]
116impl ResolveOrigin for PlainResolveOrigin {
117    fn origin_path(&self) -> FileSystemPath {
118        self.origin_path.clone()
119    }
120
121    fn asset_context(&self) -> ResolvedVc<Box<dyn AssetContext>> {
122        self.asset_context
123    }
124}
125
126/// Wraps a ResolveOrigin to add a transition.
127///
128/// The transition is applied to the wrapped origin's [`AssetContext`] eagerly at
129/// construction (see [`ResolveOriginExt::with_transition`]) so that the trait
130/// methods can be synchronous.
131#[turbo_tasks::value]
132struct ResolveOriginWithTransition {
133    origin_path: FileSystemPath,
134    asset_context: ResolvedVc<Box<dyn AssetContext>>,
135}
136
137#[turbo_tasks::value_impl]
138impl ResolveOrigin for ResolveOriginWithTransition {
139    fn origin_path(&self) -> FileSystemPath {
140        self.origin_path.clone()
141    }
142
143    fn asset_context(&self) -> ResolvedVc<Box<dyn AssetContext>> {
144        self.asset_context
145    }
146}