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    #[turbo_tasks::function]
20    fn origin_path(self: Vc<Self>) -> Vc<FileSystemPath>;
21
22    /// The AssetContext that carries the configuration for building that
23    /// subgraph.
24    #[turbo_tasks::function]
25    fn asset_context(self: Vc<Self>) -> Vc<Box<dyn AssetContext>>;
26
27    /// Get the resolve options that apply for this origin.
28    #[turbo_tasks::function]
29    async fn resolve_options(self: Vc<Self>) -> Result<Vc<ResolveOptions>> {
30        Ok(self
31            .asset_context()
32            .resolve_options(self.origin_path().owned().await?))
33    }
34}
35
36// TODO it would be nice if these methods can be moved to the trait to allow
37// overriding it, but currently we explicitly disallow it due to the way
38// transitions work. Maybe transitions should be decorators on ResolveOrigin?
39pub trait ResolveOriginExt: Send {
40    /// Resolve to an asset from that origin. Custom resolve options can be
41    /// passed. Otherwise provide `origin.resolve_options()` unmodified.
42    fn resolve_asset(
43        self: Vc<Self>,
44        request: Vc<Request>,
45        options: Vc<ResolveOptions>,
46        reference_type: ReferenceType,
47    ) -> impl Future<Output = Result<Vc<ModuleResolveResult>>> + Send;
48
49    /// Adds a transition that is used for resolved assets.
50    fn with_transition(self: ResolvedVc<Self>, transition: RcStr) -> Vc<Box<dyn ResolveOrigin>>;
51}
52
53impl<T> ResolveOriginExt for T
54where
55    T: ResolveOrigin + Upcast<Box<dyn ResolveOrigin>>,
56{
57    async fn resolve_asset(
58        self: Vc<Self>,
59        request: Vc<Request>,
60        options: Vc<ResolveOptions>,
61        reference_type: ReferenceType,
62    ) -> Result<Vc<ModuleResolveResult>> {
63        Ok(self.asset_context().to_resolved().await?.resolve_asset(
64            self.origin_path().owned().await?,
65            *request.to_resolved().await?,
66            *options.to_resolved().await?,
67            reference_type,
68        ))
69    }
70
71    fn with_transition(self: ResolvedVc<Self>, transition: RcStr) -> Vc<Box<dyn ResolveOrigin>> {
72        Vc::upcast(
73            ResolveOriginWithTransition {
74                previous: ResolvedVc::upcast_non_strict(self),
75                transition,
76            }
77            .cell(),
78        )
79    }
80}
81
82/// A resolve origin for some path and context without additional modifications.
83#[turbo_tasks::value]
84pub struct PlainResolveOrigin {
85    asset_context: ResolvedVc<Box<dyn AssetContext>>,
86    origin_path: FileSystemPath,
87}
88
89#[turbo_tasks::value_impl]
90impl PlainResolveOrigin {
91    #[turbo_tasks::function]
92    pub fn new(
93        asset_context: ResolvedVc<Box<dyn AssetContext>>,
94        origin_path: FileSystemPath,
95    ) -> Vc<Self> {
96        PlainResolveOrigin {
97            asset_context,
98            origin_path,
99        }
100        .cell()
101    }
102}
103
104#[turbo_tasks::value_impl]
105impl ResolveOrigin for PlainResolveOrigin {
106    #[turbo_tasks::function]
107    fn origin_path(&self) -> Vc<FileSystemPath> {
108        self.origin_path.clone().cell()
109    }
110
111    #[turbo_tasks::function]
112    fn asset_context(&self) -> Vc<Box<dyn AssetContext>> {
113        *self.asset_context
114    }
115}
116
117/// Wraps a ResolveOrigin to add a transition.
118#[turbo_tasks::value]
119struct ResolveOriginWithTransition {
120    previous: ResolvedVc<Box<dyn ResolveOrigin>>,
121    transition: RcStr,
122}
123
124#[turbo_tasks::value_impl]
125impl ResolveOrigin for ResolveOriginWithTransition {
126    #[turbo_tasks::function]
127    fn origin_path(&self) -> Vc<FileSystemPath> {
128        self.previous.origin_path()
129    }
130
131    #[turbo_tasks::function]
132    fn asset_context(&self) -> Vc<Box<dyn AssetContext>> {
133        self.previous
134            .asset_context()
135            .with_transition(self.transition.clone())
136    }
137}