use std::path::Path;
use serde_json::Value;
use xuanji::{Outcome, Report, Severity, Violation};
use crate::errors::unreadable_workspace_error;
use xingbiao::cargo_metadata;
pub(crate) fn outcome_from(violations: Vec<Violation>) -> Outcome {
let mut deduped: Vec<Violation> = Vec::new();
for violation in violations {
match deduped.iter_mut().find(|kept| kept.id() == violation.id()) {
Some(kept) => {
if kept.severity == Severity::Warn && violation.severity == Severity::Enforce {
*kept = violation;
}
}
None => deduped.push(violation),
}
}
if deduped.is_empty() {
Outcome::Clean
} else {
Outcome::Violations(Report::new(deduped))
}
}
pub(crate) fn read_metadata(manifest_path: &Path) -> Result<Value, Outcome> {
cargo_metadata(manifest_path)
.map_err(|err| Outcome::ConstitutionError(unreadable_workspace_error(manifest_path, &err)))
}
pub(crate) fn eval_into<B>(
metadata: &Value,
boundaries: &[B],
per_boundary: impl Fn(&Value, &B, &mut Vec<Violation>) -> Result<(), String>,
violations: &mut Vec<Violation>,
) -> Result<(), String> {
for boundary in boundaries {
per_boundary(metadata, boundary, violations)?;
}
Ok(())
}
pub(crate) fn run_boundaries<B>(
boundaries: &[B],
manifest_path: &Path,
per_boundary: impl Fn(&Value, &B, &mut Vec<Violation>) -> Result<(), String>,
) -> Outcome {
let metadata = match read_metadata(manifest_path) {
Ok(metadata) => metadata,
Err(outcome) => return outcome,
};
let mut violations = Vec::new();
match eval_into(&metadata, boundaries, per_boundary, &mut violations) {
Ok(()) => outcome_from(violations),
Err(error) => Outcome::ConstitutionError(error),
}
}