Skip to main content

turbopack_core/resolve/
plugin.rs

1use anyhow::Result;
2use rustc_hash::FxHashSet;
3use turbo_rcstr::RcStr;
4use turbo_tasks::{ResolvedVc, Vc};
5use turbo_tasks_fs::{FileSystemPath, glob::Glob};
6
7use crate::{
8    reference_type::ReferenceType,
9    resolve::{ResolveResultOption, parse::Request},
10};
11
12/// A condition which determines if the hooks of a resolve plugin gets called.
13#[turbo_tasks::value(shared)]
14pub enum AfterResolvePluginCondition {
15    Glob {
16        root: FileSystemPath,
17        glob: ResolvedVc<Glob>,
18    },
19    Always,
20    Never,
21}
22
23#[turbo_tasks::value_impl]
24impl AfterResolvePluginCondition {
25    #[turbo_tasks::function]
26    pub fn new_with_glob(root: FileSystemPath, glob: ResolvedVc<Glob>) -> Vc<Self> {
27        AfterResolvePluginCondition::Glob { root, glob }.cell()
28    }
29}
30
31#[turbo_tasks::value_impl]
32impl AfterResolvePluginCondition {
33    #[turbo_tasks::function]
34    pub async fn matches(&self, fs_path: FileSystemPath) -> Result<Vc<bool>> {
35        match self {
36            AfterResolvePluginCondition::Glob { root, glob } => {
37                let path = fs_path;
38
39                if let Some(path) = root.get_path_to(&path)
40                    && glob.await?.matches(path)
41                {
42                    return Ok(Vc::cell(true));
43                }
44
45                Ok(Vc::cell(false))
46            }
47            AfterResolvePluginCondition::Always => Ok(Vc::cell(true)),
48            AfterResolvePluginCondition::Never => Ok(Vc::cell(false)),
49        }
50    }
51}
52
53/// A condition which determines if the hooks of a resolve plugin gets called.
54#[turbo_tasks::value(shared)]
55pub enum BeforeResolvePluginCondition {
56    Request(ResolvedVc<Glob>),
57    Modules(FxHashSet<RcStr>),
58    Always,
59    Never,
60}
61
62#[turbo_tasks::value_impl]
63impl BeforeResolvePluginCondition {
64    #[turbo_tasks::function]
65    pub async fn from_modules(modules: ResolvedVc<Vec<RcStr>>) -> Result<Vc<Self>> {
66        Ok(BeforeResolvePluginCondition::Modules(modules.await?.iter().cloned().collect()).cell())
67    }
68
69    #[turbo_tasks::function]
70    pub fn from_request_glob(glob: ResolvedVc<Glob>) -> Vc<Self> {
71        BeforeResolvePluginCondition::Request(glob).cell()
72    }
73}
74
75#[turbo_tasks::value_impl]
76impl BeforeResolvePluginCondition {
77    #[turbo_tasks::function]
78    pub async fn matches(&self, request: Vc<Request>) -> Result<Vc<bool>> {
79        Ok(Vc::cell(match self {
80            BeforeResolvePluginCondition::Request(glob) => match request.await?.request() {
81                Some(request) => glob.await?.matches(request.as_str()),
82                None => false,
83            },
84            BeforeResolvePluginCondition::Modules(modules) => {
85                if let Request::Module { module, .. } = &*request.await? {
86                    modules.iter().any(|m| module.is_match(m))
87                } else {
88                    false
89                }
90            }
91            BeforeResolvePluginCondition::Always => true,
92            BeforeResolvePluginCondition::Never => false,
93        }))
94    }
95}
96
97#[turbo_tasks::value_trait]
98pub trait BeforeResolvePlugin {
99    #[turbo_tasks::function]
100    fn before_resolve_condition(self: Vc<Self>) -> Vc<BeforeResolvePluginCondition>;
101
102    #[turbo_tasks::function]
103    fn before_resolve(
104        self: Vc<Self>,
105        lookup_path: FileSystemPath,
106        reference_type: ReferenceType,
107        request: Vc<Request>,
108    ) -> Vc<ResolveResultOption>;
109}
110
111#[turbo_tasks::value_trait]
112pub trait AfterResolvePlugin {
113    /// A condition which determines if the hooks gets called.
114    #[turbo_tasks::function]
115    fn after_resolve_condition(self: Vc<Self>) -> Vc<AfterResolvePluginCondition>;
116
117    /// This hook gets called when a full filepath has been resolved and the
118    /// condition matches. If a value is returned it replaces the resolve
119    /// result.
120    #[turbo_tasks::function]
121    fn after_resolve(
122        self: Vc<Self>,
123        fs_path: FileSystemPath,
124        lookup_path: FileSystemPath,
125        reference_type: ReferenceType,
126        request: Vc<Request>,
127    ) -> Vc<ResolveResultOption>;
128}