use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Severity {
Error,
Warning,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DiagnosticCode {
UnknownTable,
UnknownField,
TypeMismatch,
MissingRequired,
OutOfRange,
LutNotFound,
ExtendsNotFound,
ExtendsCycle,
FileNotReadable,
SyntaxError,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Location {
pub line: usize,
pub column: usize,
pub field: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Diagnostic {
pub severity: Severity,
pub code: DiagnosticCode,
pub message: String,
pub location: Location,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FileReport {
pub path: String,
pub status: FileStatus,
pub diagnostics: Vec<Diagnostic>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FileStatus {
Ok,
Error,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ValidationReport {
pub files: Vec<FileReport>,
pub summary: Summary,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Summary {
pub total: usize,
pub ok: usize,
pub errors: usize,
}
impl ValidationReport {
pub fn from_files(files: Vec<FileReport>) -> Self {
let total = files.len();
let errors = files
.iter()
.filter(|f| f.status == FileStatus::Error)
.count();
let ok = total - errors;
Self {
files,
summary: Summary { total, ok, errors },
}
}
pub fn has_errors(&self) -> bool {
self.summary.errors > 0
}
}
impl FileReport {
pub fn new(path: impl Into<String>, diagnostics: Vec<Diagnostic>) -> Self {
let status = if diagnostics.iter().any(|d| d.severity == Severity::Error) {
FileStatus::Error
} else {
FileStatus::Ok
};
Self {
path: path.into(),
status,
diagnostics,
}
}
}