next.js/turbopack/crates/turbopack-core/src/resolve/plugin.rs
plugin.rs129 lines3.9 KB
use anyhow::Result;
use rustc_hash::FxHashSet;
use turbo_rcstr::RcStr;
use turbo_tasks::{ResolvedVc, Vc};
use turbo_tasks_fs::{FileSystemPath, glob::Glob};

use crate::{
    reference_type::ReferenceType,
    resolve::{ResolveResultOption, parse::Request},
};

/// A condition which determines if the hooks of a resolve plugin gets called.
#[turbo_tasks::value(shared)]
pub enum AfterResolvePluginCondition {
    Glob {
        root: FileSystemPath,
        glob: ResolvedVc<Glob>,
    },
    Always,
    Never,
}

#[turbo_tasks::value_impl]
impl AfterResolvePluginCondition {
    #[turbo_tasks::function]
    pub fn new_with_glob(root: FileSystemPath, glob: ResolvedVc<Glob>) -> Vc<Self> {
        AfterResolvePluginCondition::Glob { root, glob }.cell()
    }
}

#[turbo_tasks::value_impl]
impl AfterResolvePluginCondition {
    #[turbo_tasks::function]
    pub async fn matches(&self, fs_path: FileSystemPath) -> Result<Vc<bool>> {
        match self {
            AfterResolvePluginCondition::Glob { root, glob } => {
                let path = fs_path;

                if let Some(path) = root.get_path_to(&path)
                    && glob.await?.matches(path)
                {
                    return Ok(Vc::cell(true));
                }

                Ok(Vc::cell(false))
            }
            AfterResolvePluginCondition::Always => Ok(Vc::cell(true)),
            AfterResolvePluginCondition::Never => Ok(Vc::cell(false)),
        }
    }
}

/// A condition which determines if the hooks of a resolve plugin gets called.
#[turbo_tasks::value(shared)]
pub enum BeforeResolvePluginCondition {
    Request(ResolvedVc<Glob>),
    Modules(FxHashSet<RcStr>),
    Always,
    Never,
}

#[turbo_tasks::value_impl]
impl BeforeResolvePluginCondition {
    #[turbo_tasks::function]
    pub async fn from_modules(modules: ResolvedVc<Vec<RcStr>>) -> Result<Vc<Self>> {
        Ok(BeforeResolvePluginCondition::Modules(modules.await?.iter().cloned().collect()).cell())
    }

    #[turbo_tasks::function]
    pub fn from_request_glob(glob: ResolvedVc<Glob>) -> Vc<Self> {
        BeforeResolvePluginCondition::Request(glob).cell()
    }
}

#[turbo_tasks::value_impl]
impl BeforeResolvePluginCondition {
    #[turbo_tasks::function]
    pub async fn matches(&self, request: Vc<Request>) -> Result<Vc<bool>> {
        Ok(Vc::cell(match self {
            BeforeResolvePluginCondition::Request(glob) => match request.await?.request() {
                Some(request) => glob.await?.matches(request.as_str()),
                None => false,
            },
            BeforeResolvePluginCondition::Modules(modules) => {
                if let Request::Module { module, .. } = &*request.await? {
                    modules.iter().any(|m| module.is_match(m))
                } else {
                    false
                }
            }
            BeforeResolvePluginCondition::Always => true,
            BeforeResolvePluginCondition::Never => false,
        }))
    }
}

#[turbo_tasks::value_trait]
pub trait BeforeResolvePlugin {
    #[turbo_tasks::function]
    fn before_resolve_condition(self: Vc<Self>) -> Vc<BeforeResolvePluginCondition>;

    #[turbo_tasks::function]
    fn before_resolve(
        self: Vc<Self>,
        lookup_path: FileSystemPath,
        reference_type: ReferenceType,
        request: Vc<Request>,
    ) -> Vc<ResolveResultOption>;
}

#[turbo_tasks::value_trait]
pub trait AfterResolvePlugin {
    /// A condition which determines if the hooks gets called.
    #[turbo_tasks::function]
    fn after_resolve_condition(self: Vc<Self>) -> Vc<AfterResolvePluginCondition>;

    /// This hook gets called when a full filepath has been resolved and the
    /// condition matches. If a value is returned it replaces the resolve
    /// result.
    #[turbo_tasks::function]
    fn after_resolve(
        self: Vc<Self>,
        fs_path: FileSystemPath,
        lookup_path: FileSystemPath,
        reference_type: ReferenceType,
        request: Vc<Request>,
    ) -> Vc<ResolveResultOption>;
}
Quest for Codev2.0.0
/
SIGN IN