Skip to main content

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    context::ProcessResult, module::Module, reference_type::ReferenceType, source::Source,
10};
11
12use crate::{ModuleAssetContext, module_options::transition_rule::TransitionRule};
13
14/// Some kind of operation that is executed during reference processing. e. g.
15/// you can transition to a different environment on a specific import
16/// (reference).
17#[turbo_tasks::value_trait]
18pub trait Transition {
19    /// Apply modifications/wrapping to the final asset
20    #[turbo_tasks::function]
21    fn process_module(
22        self: Vc<Self>,
23        module: Vc<Box<dyn Module>>,
24        _context: Vc<ModuleAssetContext>,
25    ) -> Vc<Box<dyn Module>> {
26        module
27    }
28
29    /// Apply modifications to the context
30    #[turbo_tasks::function]
31    async fn process_context(
32        self: Vc<Self>,
33        module_asset_context: Vc<ModuleAssetContext>,
34    ) -> Result<Vc<ModuleAssetContext>> {
35        let module_asset_context = module_asset_context.await?;
36        let module_asset_context = ModuleAssetContext::new(
37            *module_asset_context.transitions,
38            *module_asset_context.compile_time_info,
39            *module_asset_context.module_options_context,
40            *module_asset_context.resolve_options_context,
41            module_asset_context.layer.clone(),
42        );
43        Ok(module_asset_context)
44    }
45
46    /// Apply modification on the processing of the asset
47    #[turbo_tasks::function]
48    async fn process(
49        self: Vc<Self>,
50        source: Vc<Box<dyn Source>>,
51        module_asset_context: Vc<ModuleAssetContext>,
52        reference_type: ReferenceType,
53    ) -> Result<Vc<ProcessResult>> {
54        let module_asset_context = self.process_context(module_asset_context);
55        let source = source.to_resolved().await?;
56
57        Ok(match &*module_asset_context
58            .process_default(source, reference_type)
59            .await?
60            .await?
61        {
62            ProcessResult::Module(m) => ProcessResult::Module(
63                self.process_module(**m, module_asset_context)
64                    .to_resolved()
65                    .await?,
66            ),
67            ProcessResult::Unknown(source) => ProcessResult::Unknown(*source),
68            ProcessResult::Ignore => ProcessResult::Ignore,
69        }
70        .cell())
71    }
72}
73
74#[turbo_tasks::value(shared)]
75#[derive(Default)]
76pub struct TransitionOptions {
77    pub named_transitions: FxHashMap<RcStr, ResolvedVc<Box<dyn Transition>>>,
78    pub transition_rules: Vec<TransitionRule>,
79    pub placeholder_for_future_extensions: (),
80}
81
82#[turbo_tasks::value_impl]
83impl ValueDefault for TransitionOptions {
84    #[turbo_tasks::function]
85    fn value_default() -> Vc<Self> {
86        Self::default().cell()
87    }
88}
89
90impl TransitionOptions {
91    pub fn get_named(&self, name: RcStr) -> Option<ResolvedVc<Box<dyn Transition>>> {
92        self.named_transitions.get(&name).copied()
93    }
94
95    pub async fn get_by_rules(
96        &self,
97        source: ResolvedVc<Box<dyn Source>>,
98        reference_type: &ReferenceType,
99    ) -> Result<Option<ResolvedVc<Box<dyn Transition>>>> {
100        if self.transition_rules.is_empty() {
101            return Ok(None);
102        }
103        let path = &source.ident().await?.path;
104        for rule in &self.transition_rules {
105            if rule.matches(source, path, reference_type).await? {
106                return Ok(Some(rule.transition()));
107            }
108        }
109        Ok(None)
110    }
111}