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