use super::OverwriteArgs;
use crate::lang::SgLang;
use crate::utils::ErrorContext as EC;
use anyhow::Result;
use ast_grep_config::{RuleConfig, Severity};
use ast_grep_core::Language;
use regex::Regex;
use std::collections::HashMap;
#[derive(Default)]
pub struct RuleOverwrite {
default_severity: Option<Severity>,
by_rule_id: HashMap<String, Severity>,
rule_filter: Option<Regex>,
}
fn read_severity(
severity: Severity,
ids: &Option<Vec<String>>,
by_rule_id: &mut HashMap<String, Severity>,
default_severity: &mut Option<Severity>,
) {
let Some(ids) = ids.as_ref() else { return };
if ids.is_empty() {
*default_severity = Some(severity);
return;
}
for id in ids {
by_rule_id.insert(id.clone(), severity.clone());
}
}
impl RuleOverwrite {
pub fn new_for_verify(filter: Option<&Regex>, include_off: bool) -> Self {
Self {
default_severity: if include_off {
Some(Severity::Hint)
} else {
None
},
by_rule_id: HashMap::new(),
rule_filter: filter.cloned(),
}
}
pub fn new(cli: &OverwriteArgs) -> Result<Self> {
let mut default_severity = None;
let mut by_rule_id = HashMap::new();
read_severity(
Severity::Error,
&cli.error,
&mut by_rule_id,
&mut default_severity,
);
read_severity(
Severity::Warning,
&cli.warning,
&mut by_rule_id,
&mut default_severity,
);
read_severity(
Severity::Info,
&cli.info,
&mut by_rule_id,
&mut default_severity,
);
read_severity(
Severity::Hint,
&cli.hint,
&mut by_rule_id,
&mut default_severity,
);
read_severity(
Severity::Off,
&cli.off,
&mut by_rule_id,
&mut default_severity,
);
Ok(Self {
default_severity,
by_rule_id,
rule_filter: cli.filter.clone(),
})
}
pub fn process_configs(
&self,
configs: Vec<RuleConfig<SgLang>>,
) -> Result<Vec<RuleConfig<SgLang>>> {
let mut configs = if let Some(filter) = &self.rule_filter {
filter_rule_by_regex(configs, filter)?
} else {
configs
};
for config in &mut configs {
let overwrite = self.find(&config.id);
overwrite.overwrite(config);
}
Ok(configs)
}
pub fn find(&self, id: &str) -> OverwriteResult {
let severity = self
.by_rule_id
.get(id)
.cloned()
.or_else(|| self.default_severity.clone());
OverwriteResult { severity }
}
}
fn filter_rule_by_regex(
configs: Vec<RuleConfig<SgLang>>,
filter: &Regex,
) -> Result<Vec<RuleConfig<SgLang>>> {
let selected: Vec<_> = configs
.into_iter()
.filter(|c| filter.is_match(&c.id))
.collect();
if selected.is_empty() {
Err(anyhow::anyhow!(EC::RuleNotFound(filter.to_string())))
} else {
Ok(selected)
}
}
pub struct OverwriteResult {
pub severity: Option<Severity>,
}
impl OverwriteResult {
fn overwrite<L>(&self, rule: &mut RuleConfig<L>)
where
L: Language,
{
if let Some(severity) = &self.severity {
rule.severity = severity.clone();
}
}
}