swc_config/
glob.rs

1use std::sync::Arc;
2
3use anyhow::{Context, Result};
4use dashmap::DashMap;
5use globset::{Glob, GlobMatcher};
6use once_cell::sync::Lazy;
7use rustc_hash::FxBuildHasher;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone)]
11pub struct CachedGlob {
12    glob: Arc<GlobMatcher>,
13}
14
15impl CachedGlob {
16    pub fn new(glob_str: &str) -> Result<Self> {
17        static CACHE: Lazy<DashMap<String, Arc<GlobMatcher>, FxBuildHasher>> =
18            Lazy::new(Default::default);
19
20        if let Some(cache) = CACHE.get(glob_str).as_deref().cloned() {
21            return Ok(Self { glob: cache });
22        }
23
24        let glob = Glob::new(glob_str)
25            .with_context(|| format!("failed to create glob for '{glob_str}'"))?
26            .compile_matcher();
27
28        let glob = Arc::new(glob);
29
30        CACHE.insert(glob_str.to_string(), glob.clone());
31
32        Ok(Self { glob })
33    }
34
35    pub fn is_match(&self, path: &str) -> bool {
36        self.glob.is_match(path)
37    }
38}
39
40impl Serialize for CachedGlob {
41    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42    where
43        S: serde::Serializer,
44    {
45        String::serialize(&self.glob.glob().to_string(), serializer)
46    }
47}
48
49impl<'de> Deserialize<'de> for CachedGlob {
50    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51    where
52        D: serde::Deserializer<'de>,
53    {
54        use serde::de::Error;
55
56        let glob = String::deserialize(deserializer)?;
57
58        Self::new(&glob).map_err(|err| D::Error::custom(err.to_string()))
59    }
60}