dprint 0.17.2

Binary for dprint code formatter—a pluggable and configurable code formatting platform.
use std::path::Path;

use dprint_cli_core::types::ErrBox;
use globset::GlobBuilder;
use globset::GlobSet;
use globset::GlobSetBuilder;

use super::is_negated_glob;

#[derive(Debug)]
pub struct GlobPatterns {
  pub includes: Vec<String>,
  pub excludes: Vec<String>,
}

pub struct GlobMatcherOptions {
  pub case_insensitive: bool,
}

pub struct GlobMatcher {
  include_globset: GlobSet,
  exclude_globset: GlobSet,
}

impl GlobMatcher {
  pub fn new(patterns: &GlobPatterns, opts: &GlobMatcherOptions) -> Result<GlobMatcher, ErrBox> {
    let excludes = patterns
      .excludes
      .iter()
      .map(|pattern| if is_negated_glob(pattern) { &pattern[1..] } else { pattern })
      .collect::<Vec<_>>();
    Ok(GlobMatcher {
      include_globset: build_glob_set(&patterns.includes, opts)?,
      exclude_globset: build_glob_set(&excludes, opts)?,
    })
  }

  pub fn is_match(&self, pattern: impl AsRef<Path>) -> bool {
    self.include_globset.is_match(&pattern) && !self.exclude_globset.is_match(&pattern)
  }

  pub fn is_ignored(&self, pattern: impl AsRef<Path>) -> bool {
    self.exclude_globset.is_match(&pattern)
  }
}

fn build_glob_set(file_patterns: &[impl AsRef<str>], opts: &GlobMatcherOptions) -> Result<GlobSet, ErrBox> {
  let mut builder = GlobSetBuilder::new();
  for pattern in file_patterns {
    builder.add(GlobBuilder::new(pattern.as_ref()).case_insensitive(opts.case_insensitive).build()?);
  }
  return Ok(builder.build().unwrap());
}