turbopack/transition/
mod.rs

1pub(crate) mod full_context_transition;
2
3use anyhow::Result;
4pub use full_context_transition::FullContextTransition;
5use rustc_hash::FxHashMap;
6use turbo_rcstr::RcStr;
7use turbo_tasks::{ResolvedVc, ValueDefault, Vc};
8use turbopack_core::{
9    compile_time_info::CompileTimeInfo, context::ProcessResult, module::Module,
10    reference_type::ReferenceType, source::Source,
11};
12use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
13
14use crate::{
15    ModuleAssetContext,
16    module_options::{ModuleOptionsContext, transition_rule::TransitionRule},
17};
18
19/// Some kind of operation that is executed during reference processing. e. g.
20/// you can transition to a different environment on a specific import
21/// (reference).
22#[turbo_tasks::value_trait]
23pub trait Transition {
24    /// Apply modifications/wrapping to the source asset
25    #[turbo_tasks::function]
26    fn process_source(self: Vc<Self>, asset: Vc<Box<dyn Source>>) -> Vc<Box<dyn Source>> {
27        asset
28    }
29
30    /// Apply modifications to the compile-time information
31    #[turbo_tasks::function]
32    fn process_compile_time_info(
33        self: Vc<Self>,
34        compile_time_info: Vc<CompileTimeInfo>,
35    ) -> Vc<CompileTimeInfo> {
36        compile_time_info
37    }
38
39    /// Apply modifications/wrapping to the module options context
40    #[turbo_tasks::function]
41    fn process_module_options_context(
42        self: Vc<Self>,
43        module_options_context: Vc<ModuleOptionsContext>,
44    ) -> Vc<ModuleOptionsContext> {
45        module_options_context
46    }
47
48    /// Apply modifications/wrapping to the resolve options context
49    #[turbo_tasks::function]
50    fn process_resolve_options_context(
51        self: Vc<Self>,
52        resolve_options_context: Vc<ResolveOptionsContext>,
53    ) -> Vc<ResolveOptionsContext> {
54        resolve_options_context
55    }
56
57    /// Apply modifications/wrapping to the transition options
58    #[turbo_tasks::function]
59    fn process_transition_options(
60        self: Vc<Self>,
61        transition_options: Vc<TransitionOptions>,
62    ) -> Vc<TransitionOptions> {
63        transition_options
64    }
65
66    /// Apply modifications/wrapping to the final asset
67    #[turbo_tasks::function]
68    fn process_module(
69        self: Vc<Self>,
70        module: Vc<Box<dyn Module>>,
71        _context: Vc<ModuleAssetContext>,
72    ) -> Vc<Box<dyn Module>> {
73        module
74    }
75
76    /// Apply modifications to the context
77    #[turbo_tasks::function]
78    async fn process_context(
79        self: Vc<Self>,
80        module_asset_context: Vc<ModuleAssetContext>,
81    ) -> Result<Vc<ModuleAssetContext>> {
82        let module_asset_context = module_asset_context.await?;
83        let compile_time_info =
84            self.process_compile_time_info(*module_asset_context.compile_time_info);
85        let module_options_context =
86            self.process_module_options_context(*module_asset_context.module_options_context);
87        let resolve_options_context =
88            self.process_resolve_options_context(*module_asset_context.resolve_options_context);
89        let layer = module_asset_context.layer.clone();
90        let transition_options = self.process_transition_options(*module_asset_context.transitions);
91        let module_asset_context = ModuleAssetContext::new(
92            transition_options,
93            compile_time_info,
94            module_options_context,
95            resolve_options_context,
96            layer,
97        );
98        Ok(module_asset_context)
99    }
100
101    /// Apply modification on the processing of the asset
102    #[turbo_tasks::function]
103    async fn process(
104        self: Vc<Self>,
105        asset: Vc<Box<dyn Source>>,
106        module_asset_context: Vc<ModuleAssetContext>,
107        reference_type: ReferenceType,
108    ) -> Result<Vc<ProcessResult>> {
109        let asset = self.process_source(asset);
110        let module_asset_context = self.process_context(module_asset_context);
111        let asset = asset.to_resolved().await?;
112
113        Ok(match &*module_asset_context
114            .process_default(asset, reference_type)
115            .await?
116            .await?
117        {
118            ProcessResult::Module(m) => ProcessResult::Module(
119                self.process_module(**m, module_asset_context)
120                    .to_resolved()
121                    .await?,
122            ),
123            ProcessResult::Unknown(source) => ProcessResult::Unknown(*source),
124            ProcessResult::Ignore => ProcessResult::Ignore,
125        }
126        .cell())
127    }
128}
129
130#[turbo_tasks::value(shared)]
131#[derive(Default)]
132pub struct TransitionOptions {
133    pub named_transitions: FxHashMap<RcStr, ResolvedVc<Box<dyn Transition>>>,
134    pub transition_rules: Vec<TransitionRule>,
135    pub placeholder_for_future_extensions: (),
136}
137
138#[turbo_tasks::value_impl]
139impl ValueDefault for TransitionOptions {
140    #[turbo_tasks::function]
141    fn value_default() -> Vc<Self> {
142        Self::default().cell()
143    }
144}
145
146impl TransitionOptions {
147    pub fn get_named(&self, name: RcStr) -> Option<ResolvedVc<Box<dyn Transition>>> {
148        self.named_transitions.get(&name).copied()
149    }
150
151    pub async fn get_by_rules(
152        &self,
153        source: ResolvedVc<Box<dyn Source>>,
154        reference_type: &ReferenceType,
155    ) -> Result<Option<ResolvedVc<Box<dyn Transition>>>> {
156        if self.transition_rules.is_empty() {
157            return Ok(None);
158        }
159        let path = &*source.ident().path().await?;
160        for rule in &self.transition_rules {
161            if rule.matches(source, path, reference_type).await? {
162                return Ok(Some(rule.transition()));
163            }
164        }
165        Ok(None)
166    }
167}