use std::path::PathBuf;
use rowan::TextRange;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Severity {
Error,
Warning,
Info,
Hint,
}
impl Severity {
pub fn label(self) -> &'static str {
match self {
Severity::Error => "error",
Severity::Warning => "warning",
Severity::Info => "info",
Severity::Hint => "hint",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Applicability {
Safe,
Unsafe,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Fix {
pub description: String,
pub content: String,
pub start: usize,
pub end: usize,
pub applicability: Applicability,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ViolationData {
pub name: String,
pub body: String,
pub suggestion: Option<String>,
}
impl ViolationData {
pub fn new(name: impl Into<String>, body: impl Into<String>) -> Self {
Self {
name: name.into(),
body: body.into(),
suggestion: None,
}
}
pub fn with_suggestion(mut self, hint: impl Into<String>) -> Self {
self.suggestion = Some(hint.into());
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Diagnostic {
pub rule: &'static str,
pub severity: Severity,
pub path: Option<PathBuf>,
#[serde(serialize_with = "serialize_text_range")]
pub range: TextRange,
pub message: ViolationData,
pub fixes: Vec<Fix>,
}
fn serialize_text_range<S: serde::Serializer>(
range: &TextRange,
serializer: S,
) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("Range", 2)?;
s.serialize_field("start", &u32::from(range.start()))?;
s.serialize_field("end", &u32::from(range.end()))?;
s.end()
}
impl Diagnostic {
pub fn new(rule: &'static str, range: TextRange, message: impl Into<String>) -> Self {
Self {
rule,
severity: Severity::Warning,
path: None,
range,
message: ViolationData::new(rule, message),
fixes: Vec::new(),
}
}
}