jsona-util 0.4.0

Shared code for jsona utilities.
Documentation
use globset::{Glob, GlobSetBuilder};
use std::{fmt::Debug, path::Path};
use url::Url;

use super::path as path_utils;
use super::url as url_utils;

#[derive(Clone)]
pub struct GlobRule {
    raw_include: Vec<String>,
    raw_exclude: Vec<String>,
    include: globset::GlobSet,
    exclude: globset::GlobSet,
}

impl Debug for GlobRule {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("GlobRule")
            .field("include", &self.raw_include)
            .field("exclude", &self.raw_exclude)
            .finish()
    }
}

impl GlobRule {
    pub fn new(
        include: impl IntoIterator<Item = impl AsRef<str>>,
        exclude: impl IntoIterator<Item = impl AsRef<str>>,
    ) -> Result<Self, anyhow::Error> {
        let mut inc = GlobSetBuilder::new();
        let mut raw_include = vec![];
        for glob in include {
            inc.add(Glob::new(glob.as_ref())?);
            raw_include.push(glob.as_ref().to_string());
        }

        let mut exc = GlobSetBuilder::new();
        let mut raw_exclude = vec![];
        for glob in exclude {
            exc.add(Glob::new(glob.as_ref())?);
            raw_exclude.push(glob.as_ref().to_string());
        }

        Ok(Self {
            include: inc.build()?,
            exclude: exc.build()?,
            raw_include,
            raw_exclude,
        })
    }

    pub fn preprocessing_pattern(pattern: &str, base: &Option<Url>) -> Option<String> {
        let path = path_utils::to_unix(pattern);
        if path.starts_with('/') {
            let base = base.as_ref().and_then(url_utils::to_file_path)?;
            Some(format!("{}{}", base.trim_end_matches('/'), path))
        } else {
            Some(format!("**/{}", path))
        }
    }

    pub fn is_match(&self, path: impl AsRef<Path>) -> bool {
        if !self.include.is_match(path.as_ref()) {
            return false;
        }

        !self.exclude.is_match(path.as_ref())
    }
    pub fn is_match_url(&self, url: &Url) -> bool {
        if let Some(path) = url_utils::to_file_path(url).map(path_utils::to_unix) {
            self.is_match(path)
        } else {
            false
        }
    }
}