#![cfg_attr(coverage_nightly, coverage(off))]
use super::types::{EnforcementResult, EnforcementState, QualityProfile, QualityViolation};
use crate::cli::colors as c;
fn parse_line_num(location: &str) -> i32 {
location
.split(':')
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(1)
}
use crate::cli::EnforceOutputFormat;
use anyhow::{Context, Result};
use std::path::Path;
pub(crate) fn emit_report(text: &str, output: Option<&Path>) -> Result<()> {
match output {
Some(path) => std::fs::write(path, text)
.with_context(|| format!("failed to write report to {}", path.display())),
None => {
println!("{text}");
Ok(())
}
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn output_result(
result: &EnforcementResult,
format: EnforceOutputFormat,
show_progress: bool,
output: Option<&Path>,
) -> Result<()> {
if show_progress
&& matches!(
format,
EnforceOutputFormat::Json | EnforceOutputFormat::Sarif
)
{
eprint!("{}", render_progress_bar(result));
}
let mut text = String::new();
if show_progress
&& matches!(
format,
EnforceOutputFormat::Summary | EnforceOutputFormat::Progress
)
{
text.push_str(&render_progress_bar(result));
}
match format {
EnforceOutputFormat::Json => {
text.push_str(&serde_json::to_string_pretty(result)?);
}
EnforceOutputFormat::Summary => {
text.push_str(&format!("{} {:?}\n", c::label("State:"), result.state));
text.push_str(&format!(
"{} {}{:.2}{}/{}{:.2}{}\n",
c::label("Score:"),
c::BOLD_WHITE,
result.score,
c::RESET,
c::DIM,
result.target,
c::RESET
));
if let Some(file) = &result.current_file {
text.push_str(&format!(
"{} {}\n",
c::label("Current File:"),
c::path(file)
));
}
text.push_str(&format!(
"{} {}",
c::label("Violations:"),
c::number(&result.violations.len().to_string())
));
}
EnforceOutputFormat::Progress => {
text.push_str(&format!("{} {:?}\n", c::label("State:"), result.state));
text.push_str(&format!(
"{} {}{:.2}{}/{}{:.2}{}",
c::label("Score:"),
c::BOLD_WHITE,
result.score,
c::RESET,
c::DIM,
result.target,
c::RESET
));
}
EnforceOutputFormat::Sarif => {
text.push_str(&serde_json::to_string_pretty(&sarif_document(
&result.violations,
))?);
}
}
emit_report(&text, output)
}
fn sarif_document(violations: &[QualityViolation]) -> serde_json::Value {
serde_json::json!({
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [{
"tool": {
"driver": {
"name": "pmat-enforce-extreme",
"version": env!("CARGO_PKG_VERSION"),
"informationUri": "https://github.com/paiml/paiml-mcp-agent-toolkit"
}
},
"results": violations.iter().map(|v| {
serde_json::json!({
"ruleId": format!("quality.{}", v.violation_type),
"level": match v.severity.as_str() {
"error" | "high" => "error",
"warning" | "medium" => "warning",
"note" | "low" => "note",
_ => "warning"
},
"message": {
"text": format!("{} (current: {:.1}, target: {:.1})",
v.suggestion, v.current, v.target)
},
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": v.location.split(':').next().unwrap_or(&v.location)
},
"region": {
"startLine": parse_line_num(&v.location)
}
}
}]
})
}).collect::<Vec<_>>()
}]
})
}
#[must_use]
pub fn render_progress_bar(result: &EnforcementResult) -> String {
let percentage = (result.score * 100.0) as u32;
let filled = (percentage as f32 / 5.0) as usize;
let empty = 20usize.saturating_sub(filled);
let bar_color = if percentage >= 80 {
c::GREEN
} else if percentage >= 50 {
c::YELLOW
} else {
c::RED
};
format!(
"\n{}\n{}\n{} {}{:.2}{}/1.00 {}{}{}{}{}{} {}\n\n",
c::header("Extreme Quality Enforcement Progress"),
c::rule(),
c::label("Overall Score:"),
c::BOLD_WHITE,
result.score,
c::RESET,
bar_color,
"\u{2588}".repeat(filled),
c::RESET,
c::DIM,
"\u{2591}".repeat(empty),
c::RESET,
c::pct(f64::from(percentage), 80.0, 50.0)
)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn print_progress_bar(result: &EnforcementResult) {
print!("{}", render_progress_bar(result));
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn print_enforcement_header(project_path: &std::path::Path) {
crate::status_eprintln!("{}", c::header("Starting Extreme Quality Enforcement"));
crate::status_eprintln!(
"{} {}",
c::label("Project:"),
c::path(&project_path.display().to_string())
);
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn print_enforcement_summary(
current_score: f64,
iteration: u32,
duration: std::time::Duration,
) {
crate::status_eprintln!("\n{}", c::header("Enforcement Complete"));
crate::status_eprintln!(
"{} {}{current_score:.2}{}/1.00",
c::label("Final Score:"),
c::BOLD_WHITE,
c::RESET
);
crate::status_eprintln!(
"{} {}",
c::label("Iterations:"),
c::number(&iteration.to_string())
);
crate::status_eprintln!("{} {duration:?}", c::label("Duration:"));
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn handle_ci_mode_exit(ci_mode: bool, current_state: EnforcementState) {
if ci_mode && current_state != EnforcementState::Complete {
std::process::exit(1);
}
}
fn tally(
violations: &[QualityViolation],
key: impl Fn(&QualityViolation) -> &String,
) -> std::collections::BTreeMap<String, usize> {
let mut counts = std::collections::BTreeMap::new();
for v in violations {
*counts.entry(key(v).clone()).or_insert(0) += 1;
}
counts
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn format_violations_output(
violations: &[QualityViolation],
profile: &QualityProfile,
format: EnforceOutputFormat,
) -> Result<String> {
if format == EnforceOutputFormat::Sarif {
return Ok(serde_json::to_string_pretty(&sarif_document(violations))?);
}
if format == EnforceOutputFormat::Json {
Ok(serde_json::to_string_pretty(&serde_json::json!({
"profile": profile.clone(),
"violations": violations,
"summary": {
"total": violations.len(),
"by_severity": tally(violations, |v| &v.severity),
"by_type": tally(violations, |v| &v.violation_type),
}
}))?)
} else {
let mut output = String::new();
output.push_str(&format!(
"{} {} violations:\n\n",
c::label("Found"),
c::number(&violations.len().to_string())
));
for violation in violations {
let sev_color = match violation.severity.as_str() {
"high" => c::BOLD_RED,
"medium" => c::BOLD_YELLOW,
_ => c::DIM_WHITE,
};
output.push_str(&format!(
"{}{}{} [{}{}{}]: {} (current: {}, target: {})\n -> {}\n\n",
c::BOLD,
violation.violation_type.to_uppercase(),
c::RESET,
sev_color,
violation.severity,
c::RESET,
c::path(&violation.location),
c::number(&format!("{}", violation.current)),
c::number(&format!("{}", violation.target)),
violation.suggestion
));
}
Ok(output)
}
}