1use serde::Deserialize;
2use serde::Serialize;
3pub use source_range::ModuleId;
4pub use source_range::SourceRange;
5
6mod source_range;
7
8#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
11#[ts(export)]
12pub struct CompilationIssue {
13 #[serde(rename = "sourceRange")]
14 pub source_range: SourceRange,
15 pub message: String,
16 pub suggestion: Option<Suggestion>,
17 pub severity: Severity,
18 pub tag: Tag,
19}
20
21impl CompilationIssue {
22 pub fn err(source_range: SourceRange, message: impl ToString) -> CompilationIssue {
23 CompilationIssue {
24 source_range,
25 message: message.to_string(),
26 suggestion: None,
27 severity: Severity::Error,
28 tag: Tag::None,
29 }
30 }
31
32 pub fn fatal(source_range: SourceRange, message: impl ToString) -> CompilationIssue {
33 CompilationIssue {
34 source_range,
35 message: message.to_string(),
36 suggestion: None,
37 severity: Severity::Fatal,
38 tag: Tag::None,
39 }
40 }
41
42 pub fn with_suggestion(
43 self,
44 suggestion_title: impl ToString,
45 suggestion_insert: impl ToString,
46 source_range: Option<SourceRange>,
48 tag: Tag,
49 ) -> CompilationIssue {
50 CompilationIssue {
51 suggestion: Some(Suggestion {
52 title: suggestion_title.to_string(),
53 insert: suggestion_insert.to_string(),
54 source_range: source_range.unwrap_or(self.source_range),
55 }),
56 tag,
57 ..self
58 }
59 }
60
61 #[cfg(test)]
62 pub fn apply_suggestion(&self, src: &str) -> Option<String> {
63 let suggestion = self.suggestion.as_ref()?;
64 Some(format!(
65 "{}{}{}",
66 &src[0..suggestion.source_range.start()],
67 suggestion.insert,
68 &src[suggestion.source_range.end()..]
69 ))
70 }
71
72 pub fn is_err(&self) -> bool {
73 self.severity.is_err()
74 }
75}
76
77#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
78#[ts(export)]
79pub enum Severity {
80 Warning,
81 Error,
82 Fatal,
83}
84
85impl Severity {
86 pub fn is_warning(self) -> bool {
87 match self {
88 Severity::Warning => true,
89 Severity::Error => false,
90 Severity::Fatal => false,
91 }
92 }
93
94 pub fn is_err(self) -> bool {
95 match self {
96 Severity::Warning => false,
97 Severity::Error | Severity::Fatal => true,
98 }
99 }
100
101 pub fn is_fatal(self) -> bool {
102 match self {
103 Severity::Warning => false,
104 Severity::Error => false,
105 Severity::Fatal => true,
106 }
107 }
108}
109
110#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
111#[ts(export)]
112pub enum Tag {
113 Deprecated,
114 Unnecessary,
115 UnknownNumericUnits,
116 None,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
120#[ts(export)]
121pub struct Suggestion {
122 pub title: String,
123 pub insert: String,
124 pub source_range: SourceRange,
125}
126
127impl Suggestion {
128 pub fn apply(&self, src: &str) -> String {
130 format!(
131 "{}{}{}",
132 &src[0..self.source_range.start()],
133 self.insert,
134 &src[self.source_range.end()..]
135 )
136 }
137}