1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct Diagnostic {
7 pub severity: Severity,
8 pub code: String,
10 pub message: String,
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 pub location: Option<SpecLocation>,
13 #[serde(default, skip_serializing_if = "Vec::is_empty")]
14 pub related: Vec<RelatedInfo>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 pub suggested_fix: Option<FixSuggestion>,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[serde(rename_all = "kebab-case")]
21pub enum Severity {
22 Error,
23 Warning,
24 Info,
25 Hint,
26}
27
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub struct RelatedInfo {
30 pub message: String,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub location: Option<SpecLocation>,
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub struct FixSuggestion {
37 pub message: String,
38 pub edits: Vec<FixEdit>,
39}
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct FixEdit {
43 pub location: SpecLocation,
44 pub replacement: String,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
48pub struct SpecLocation {
49 pub pointer: String,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 pub file: Option<String>,
53}
54
55impl SpecLocation {
56 pub fn new(pointer: impl Into<String>) -> Self {
57 Self {
58 pointer: pointer.into(),
59 file: None,
60 }
61 }
62
63 pub fn with_file(pointer: impl Into<String>, file: impl Into<String>) -> Self {
64 Self {
65 pointer: pointer.into(),
66 file: Some(file.into()),
67 }
68 }
69}