anni_common/
diagnostic.rs

1// https://github.com/reviewdog/reviewdog/tree/master/proto/rdf
2
3use serde::Serialize;
4
5#[derive(Serialize)]
6pub struct Diagnostic<T> {
7    pub message: DiagnosticMessage<T>,
8    pub location: DiagnosticLocation,
9    pub severity: DiagnosticSeverity,
10
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub source: Option<DiagnosticSource>,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub code: Option<DiagnosticCode>,
15    #[serde(skip_serializing_if = "Vec::is_empty")]
16    pub suggestions: Vec<DiagnosticSuggestion>,
17}
18
19impl<T> Diagnostic<T> {
20    pub fn error(message: DiagnosticMessage<T>, location: DiagnosticLocation) -> Self {
21        Self {
22            message,
23            location,
24            severity: DiagnosticSeverity::Error,
25
26            source: None,
27            code: None,
28            suggestions: Vec::new(),
29        }
30    }
31
32    pub fn warning(message: DiagnosticMessage<T>, location: DiagnosticLocation) -> Self {
33        Self {
34            message,
35            location,
36            severity: DiagnosticSeverity::Warning,
37
38            source: None,
39            code: None,
40            suggestions: Vec::new(),
41        }
42    }
43}
44
45pub struct DiagnosticMessage<T> {
46    pub target: T,
47    pub message: String,
48}
49
50impl<T> Serialize for DiagnosticMessage<T> {
51    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
52    where
53        S: serde::Serializer,
54    {
55        serializer.serialize_str(&self.message)
56    }
57}
58
59// Serialize here may never be used, but we need this for compile
60#[derive(Clone, Serialize)]
61pub enum MetadataDiagnosticTarget {
62    Identifier(String, Option<u8>, Option<u8>),
63    Tag(String),
64}
65
66impl MetadataDiagnosticTarget {
67    pub fn album(album_id: String) -> Self {
68        Self::Identifier(album_id, None, None)
69    }
70
71    pub fn disc(album_id: String, disc_id: u8) -> Self {
72        Self::Identifier(album_id, Some(disc_id), None)
73    }
74
75    pub fn track(album_id: String, disc_id: u8, track_id: u8) -> Self {
76        Self::Identifier(album_id, Some(disc_id), Some(track_id))
77    }
78}
79
80#[derive(Serialize)]
81pub struct DiagnosticLocation {
82    pub path: String,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub range: Option<DiagnosticRange>,
85}
86
87impl DiagnosticLocation {
88    pub fn simple(path: String) -> DiagnosticLocation {
89        DiagnosticLocation { path, range: None }
90    }
91}
92
93impl DiagnosticLocation {
94    pub fn start_line(&self) -> u32 {
95        self.range.as_ref().map(|r| r.start.line).unwrap_or(0)
96    }
97
98    pub fn start_column(&self) -> Option<u32> {
99        self.range.as_ref().and_then(|r| r.start.column)
100    }
101
102    pub fn end_line(&self) -> Option<u32> {
103        self.range
104            .as_ref()
105            .and_then(|r| r.end.as_ref().map(|p| p.line))
106    }
107
108    pub fn end_column(&self) -> Option<u32> {
109        self.range
110            .as_ref()
111            .and_then(|r| r.end.as_ref().and_then(|p| p.column))
112    }
113}
114
115#[derive(Serialize, Default)]
116pub struct DiagnosticRange {
117    pub start: DiagnosticPosition,
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub end: Option<DiagnosticPosition>,
120}
121
122#[derive(Serialize, Default)]
123pub struct DiagnosticPosition {
124    pub line: u32,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub column: Option<u32>,
127}
128
129#[derive(Serialize)]
130#[serde(rename_all = "UPPERCASE")]
131pub enum DiagnosticSeverity {
132    Error,
133    Warning,
134    // should be Info
135    #[serde(rename = "INFO")]
136    Information,
137    // does not exist in rdf
138    Hint,
139}
140
141impl Default for DiagnosticSeverity {
142    fn default() -> Self {
143        DiagnosticSeverity::Information
144    }
145}
146
147#[derive(Serialize, Default)]
148pub struct DiagnosticSource {
149    pub name: String,
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub url: Option<String>,
152}
153
154#[derive(Serialize, Default)]
155pub struct DiagnosticCode {
156    pub value: String,
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub url: Option<String>,
159}
160
161impl DiagnosticCode {
162    pub fn new(value: String) -> Self {
163        Self {
164            value,
165            ..Default::default()
166        }
167    }
168}
169
170#[derive(Serialize, Default)]
171pub struct DiagnosticSuggestion {
172    pub range: DiagnosticRange,
173    pub text: String,
174}