use std::fmt;
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum LintSeverity {
Critical,
Warning,
Info,
}
impl fmt::Display for LintSeverity {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Critical => write!(formatter, "critical"),
Self::Warning => write!(formatter, "warning"),
Self::Info => write!(formatter, "info"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum LintCategory {
DestructiveDrop,
AddNotNullNoDefault,
UnsafeNotNull,
TypeNarrowing,
DangerousRename,
BlockingIndex,
}
impl fmt::Display for LintCategory {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
Self::DestructiveDrop => "destructive-drop",
Self::AddNotNullNoDefault => "add-not-null-no-default",
Self::UnsafeNotNull => "unsafe-not-null",
Self::TypeNarrowing => "type-narrowing",
Self::DangerousRename => "dangerous-rename",
Self::BlockingIndex => "blocking-index",
};
write!(formatter, "{name}")
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Finding {
pub severity: LintSeverity,
pub category: LintCategory,
pub message: String,
pub fix: String,
pub statement: usize,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct LintReport {
pub findings: Vec<Finding>,
pub statements: usize,
}
impl LintReport {
#[must_use]
pub fn is_clean(&self) -> bool {
self.findings.is_empty()
}
#[must_use]
pub fn count_at(&self, severity: LintSeverity) -> usize {
self.findings
.iter()
.filter(|finding| finding.severity == severity)
.count()
}
#[must_use]
pub fn has_critical(&self) -> bool {
self.count_at(LintSeverity::Critical) > 0
}
}
impl fmt::Display for LintReport {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.findings.is_empty() {
return write!(
formatter,
"no migration lint findings ({} statements analyzed)",
self.statements
);
}
writeln!(
formatter,
"{} finding(s) across {} statement(s):",
self.findings.len(),
self.statements
)?;
for finding in &self.findings {
writeln!(
formatter,
" statement #{} [{}] {}: {}",
finding.statement, finding.severity, finding.category, finding.message,
)?;
writeln!(formatter, " fix: {}", finding.fix)?;
}
Ok(())
}
}