use std::path::PathBuf;
use rowan::TextRange;
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum Severity {
Error,
Warning,
Info,
Hint,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Applicability {
Safe,
Unsafe,
}
#[derive(Debug, Clone, Serialize)]
pub struct Fix {
pub content: String,
pub start: usize,
pub end: usize,
pub applicability: Applicability,
pub description: String,
}
impl Fix {
pub fn safe(
start: usize,
end: usize,
content: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self {
content: content.into(),
start,
end,
applicability: Applicability::Safe,
description: description.into(),
}
}
pub fn unsafe_(
start: usize,
end: usize,
content: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self {
content: content.into(),
start,
end,
applicability: Applicability::Unsafe,
description: description.into(),
}
}
}
#[derive(Debug, Clone, 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, Serialize)]
pub struct Diagnostic {
pub rule: &'static str,
pub severity: Severity,
pub path: PathBuf,
#[serde(serialize_with = "serialize_text_range")]
pub range: TextRange,
pub message: ViolationData,
#[serde(skip_serializing_if = "Option::is_none")]
pub fix: Option<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()
}
pub trait Violation {
fn name(&self) -> String;
fn body(&self) -> String;
fn suggestion(&self) -> Option<String> {
None
}
}
impl<T: Violation> From<&T> for ViolationData {
fn from(value: &T) -> Self {
Self {
name: value.name(),
body: value.body(),
suggestion: value.suggestion(),
}
}
}