use std::{
collections::{BTreeMap, BTreeSet},
convert::TryInto,
};
use miette::{IntoDiagnostic, Result, SourceOffset, SourceSpan};
use mit_lint::{Lint, Lints, CONFIG_KEY_PREFIX};
use crate::{external::Vcs, lints::cmd::errors::SerialiseLintError};
pub fn read_from_toml_or_else_vcs(config: &str, vcs: &dyn Vcs) -> Result<Lints> {
let vcs_lints = try_from_vcs(vcs)?;
let config: BTreeMap<String, BTreeMap<String, BTreeMap<String, bool>>> = toml::from_str(config)
.map_err(|x| SerialiseLintError {
src: config.to_string(),
message: x.to_string(),
span: x.span().map_or_else(
|| SourceSpan::new(0.into(), SourceOffset::from(0)),
Into::into,
),
})?;
let lint_prefix = CONFIG_KEY_PREFIX.split('.').collect::<Vec<_>>();
let namespace = (*lint_prefix.first().unwrap()).to_string();
let Some(config) = config.get(&namespace) else {
return Ok(vcs_lints);
};
let group = (*lint_prefix.get(1).unwrap()).to_string();
let Some(lint_names) = config.get(&group) else {
return Ok(vcs_lints);
};
let to_add: Lints = lint_names
.iter()
.filter_map(|(key, value)| if *value { Some(key as &str) } else { None })
.collect::<Vec<&str>>()
.try_into()
.into_diagnostic()?;
let to_remove: Lints = lint_names
.iter()
.filter_map(|(key, value)| if *value { None } else { Some(key as &str) })
.collect::<Vec<&str>>()
.try_into()
.into_diagnostic()?;
Ok(vcs_lints.subtract(&to_remove).merge(&to_add))
}
fn try_from_vcs(config: &dyn Vcs) -> Result<Lints> {
Ok(Lints::new(
Lint::all_lints()
.filter_map(|lint| {
get_config_or_default(config, lint, lint.enabled_by_default()).transpose()
})
.collect::<Result<BTreeSet<Lint>>>()?,
))
}
fn get_config_or_default(config: &dyn Vcs, lint: Lint, default: bool) -> Result<Option<Lint>> {
Ok(config
.get_bool(&lint.config_key())?
.or(Some(default))
.filter(|lint_value| lint_value == &true)
.map(|_| lint))
}