use std::path::PathBuf;
use xuanji::{BoundaryKind, Polarity, RuleKey, Severity, Violation, ViolationId};
use crate::finding::SemanticFact;
pub(crate) struct SingleModuleViolationContext<'a> {
pub(crate) module: &'a str,
pub(crate) rule: &'a str,
pub(crate) rule_key: RuleKey,
pub(crate) reason: &'a str,
pub(crate) severity: Severity,
pub(crate) anchor: Option<&'a str>,
pub(crate) crate_package: &'a str,
pub(crate) unit: &'a str,
}
struct ViolationContext<'a> {
unit: &'a str,
target: &'a str,
rule: &'a str,
rule_key: RuleKey,
reason: &'a str,
severity: Severity,
anchor: Option<String>,
polarity: Polarity,
crate_package: &'a str,
}
fn push_violation(
violations: &mut Vec<Violation>,
context: &ViolationContext<'_>,
finding: SemanticFact,
file: PathBuf,
) {
let finding = finding.into_finding(context.crate_package, context.unit);
let id = ViolationId::new(
context.target,
context.rule_key.clone(),
finding.fact().clone(),
);
violations.push(
Violation::new(
BoundaryKind::Semantic,
id,
context.rule,
finding.text(),
context.reason.to_string(),
context.severity,
)
.with_file(Some(file.display().to_string()))
.with_anchor(context.anchor.clone())
.with_polarity(context.polarity),
);
}
pub(crate) fn push_single_module_violations(
violations: &mut Vec<Violation>,
context: SingleModuleViolationContext<'_>,
findings: Vec<(SemanticFact, PathBuf)>,
) {
let shared = ViolationContext {
target: context.module,
rule: context.rule,
rule_key: context.rule_key,
reason: context.reason,
severity: context.severity,
anchor: context.anchor.map(str::to_string),
polarity: Polarity::DenyBreach,
crate_package: context.crate_package,
unit: context.unit,
};
for (finding, file) in findings {
push_violation(violations, &shared, finding, file);
}
}
pub(crate) struct MultiModuleViolationContext<'a> {
pub(crate) target: &'a str,
pub(crate) rule: &'a str,
pub(crate) rule_key: RuleKey,
pub(crate) reason: &'a str,
pub(crate) severity: Severity,
pub(crate) anchor: Option<&'a str>,
pub(crate) polarity: Polarity,
pub(crate) crate_package: &'a str,
pub(crate) unit: &'a str,
}
pub(crate) fn push_multi_module_violations(
violations: &mut Vec<Violation>,
context: MultiModuleViolationContext<'_>,
findings: Vec<(SemanticFact, String, PathBuf)>,
) {
let shared = ViolationContext {
target: context.target,
rule: context.rule,
rule_key: context.rule_key,
reason: context.reason,
severity: context.severity,
anchor: context.anchor.map(str::to_string),
polarity: context.polarity,
crate_package: context.crate_package,
unit: context.unit,
};
for (finding, _module, file) in findings {
push_violation(violations, &shared, finding, file);
}
}