//! Diagnostic report types for el-lint. #[derive(Debug, Clone, PartialEq)] pub enum LintSeverity { Error, Warning, Info, } #[derive(Debug, Clone)] pub struct LintDiagnostic { pub severity: LintSeverity, /// Rule code, e.g. "E001", "W002", "S001", "I001". pub code: String, pub message: String, /// Human-readable location hint, e.g. "function foo" or "file". pub location: String, pub suggestion: Option, } #[derive(Debug)] pub struct LintReport { pub diagnostics: Vec, pub file_path: Option, pub source_lines: usize, } impl LintReport { pub fn has_errors(&self) -> bool { self.diagnostics .iter() .any(|d| d.severity == LintSeverity::Error) } pub fn error_count(&self) -> usize { self.diagnostics .iter() .filter(|d| d.severity == LintSeverity::Error) .count() } pub fn warning_count(&self) -> usize { self.diagnostics .iter() .filter(|d| d.severity == LintSeverity::Warning) .count() } /// Format as human-readable output (similar to rustc error output). pub fn display(&self) -> String { let mut out = String::new(); for d in &self.diagnostics { let prefix = match d.severity { LintSeverity::Error => "error", LintSeverity::Warning => "warning", LintSeverity::Info => "info", }; out.push_str(&format!("[{}] {}: {}\n", d.code, prefix, d.message)); out.push_str(&format!(" --> {}\n", d.location)); if let Some(suggestion) = &d.suggestion { out.push_str(&format!(" help: {}\n", suggestion)); } out.push('\n'); } if self.diagnostics.is_empty() { out.push_str("No issues found.\n"); } out } /// Format as JSON for editor integration. pub fn to_json(&self) -> String { let items: Vec = self .diagnostics .iter() .map(|d| { serde_json::json!({ "severity": match d.severity { LintSeverity::Error => "error", LintSeverity::Warning => "warning", LintSeverity::Info => "info", }, "code": d.code, "message": d.message, "location": d.location, "suggestion": d.suggestion, }) }) .collect(); serde_json::to_string_pretty(&items).unwrap() } }