Skip to main content

kcl_error/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3pub use source_range::ModuleId;
4pub use source_range::SourceRange;
5
6mod source_range;
7
8/// An issue which occurred during parsing, etc. The severity determines whether
9/// it's an error, warning, or other kind of issue.
10#[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        // Will use the error source range if none is supplied
47        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_err(self) -> bool {
87        match self {
88            Severity::Warning => false,
89            Severity::Error | Severity::Fatal => true,
90        }
91    }
92}
93
94#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
95#[ts(export)]
96pub enum Tag {
97    Deprecated,
98    Unnecessary,
99    UnknownNumericUnits,
100    None,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
104#[ts(export)]
105pub struct Suggestion {
106    pub title: String,
107    pub insert: String,
108    pub source_range: SourceRange,
109}
110
111impl Suggestion {
112    /// Apply the suggestion to the source code.
113    pub fn apply(&self, src: &str) -> String {
114        format!(
115            "{}{}{}",
116            &src[0..self.source_range.start()],
117            self.insert,
118            &src[self.source_range.end()..]
119        )
120    }
121}