turbopack_core/resolve/
plugin.rs

1use anyhow::Result;
2use rustc_hash::FxHashSet;
3use turbo_rcstr::RcStr;
4use turbo_tasks::{ResolvedVc, Value, 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: ResolvedVc<FileSystemPath>,
16    glob: ResolvedVc<Glob>,
17}
18
19#[turbo_tasks::value_impl]
20impl AfterResolvePluginCondition {
21    #[turbo_tasks::function]
22    pub fn new(root: ResolvedVc<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: Vc<FileSystemPath>) -> Result<Vc<bool>> {
28        let root = self.root.await?;
29        let glob = self.glob.await?;
30
31        let path = fs_path.await?;
32
33        if let Some(path) = root.get_path_to(&path) {
34            if glob.matches(path) {
35                return Ok(Vc::cell(true));
36            }
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    fn before_resolve_condition(self: Vc<Self>) -> Vc<BeforeResolvePluginCondition>;
86
87    fn before_resolve(
88        self: Vc<Self>,
89        lookup_path: Vc<FileSystemPath>,
90        reference_type: Value<ReferenceType>,
91        request: Vc<Request>,
92    ) -> Vc<ResolveResultOption>;
93}
94
95#[turbo_tasks::value_trait]
96pub trait AfterResolvePlugin {
97    /// A condition which determines if the hooks gets called.
98    fn after_resolve_condition(self: Vc<Self>) -> Vc<AfterResolvePluginCondition>;
99
100    /// This hook gets called when a full filepath has been resolved and the
101    /// condition matches. If a value is returned it replaces the resolve
102    /// result.
103    fn after_resolve(
104        self: Vc<Self>,
105        fs_path: Vc<FileSystemPath>,
106        lookup_path: Vc<FileSystemPath>,
107        reference_type: Value<ReferenceType>,
108        request: Vc<Request>,
109    ) -> Vc<ResolveResultOption>;
110}