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 error which occurred during parsing, etc.
9#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
10#[ts(export)]
11pub struct CompilationError {
12    #[serde(rename = "sourceRange")]
13    pub source_range: SourceRange,
14    pub message: String,
15    pub suggestion: Option<Suggestion>,
16    pub severity: Severity,
17    pub tag: Tag,
18}
19
20impl CompilationError {
21    pub fn err(source_range: SourceRange, message: impl ToString) -> CompilationError {
22        CompilationError {
23            source_range,
24            message: message.to_string(),
25            suggestion: None,
26            severity: Severity::Error,
27            tag: Tag::None,
28        }
29    }
30
31    pub fn fatal(source_range: SourceRange, message: impl ToString) -> CompilationError {
32        CompilationError {
33            source_range,
34            message: message.to_string(),
35            suggestion: None,
36            severity: Severity::Fatal,
37            tag: Tag::None,
38        }
39    }
40
41    pub fn with_suggestion(
42        self,
43        suggestion_title: impl ToString,
44        suggestion_insert: impl ToString,
45        // Will use the error source range if none is supplied
46        source_range: Option<SourceRange>,
47        tag: Tag,
48    ) -> CompilationError {
49        CompilationError {
50            suggestion: Some(Suggestion {
51                title: suggestion_title.to_string(),
52                insert: suggestion_insert.to_string(),
53                source_range: source_range.unwrap_or(self.source_range),
54            }),
55            tag,
56            ..self
57        }
58    }
59
60    #[cfg(test)]
61    pub fn apply_suggestion(&self, src: &str) -> Option<String> {
62        let suggestion = self.suggestion.as_ref()?;
63        Some(format!(
64            "{}{}{}",
65            &src[0..suggestion.source_range.start()],
66            suggestion.insert,
67            &src[suggestion.source_range.end()..]
68        ))
69    }
70}
71
72#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
73#[ts(export)]
74pub enum Severity {
75    Warning,
76    Error,
77    Fatal,
78}
79
80impl Severity {
81    pub fn is_err(self) -> bool {
82        match self {
83            Severity::Warning => false,
84            Severity::Error | Severity::Fatal => true,
85        }
86    }
87}
88
89#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
90#[ts(export)]
91pub enum Tag {
92    Deprecated,
93    Unnecessary,
94    UnknownNumericUnits,
95    None,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
99#[ts(export)]
100pub struct Suggestion {
101    pub title: String,
102    pub insert: String,
103    pub source_range: SourceRange,
104}
105
106impl Suggestion {
107    /// Apply the suggestion to the source code.
108    pub fn apply(&self, src: &str) -> String {
109        format!(
110            "{}{}{}",
111            &src[0..self.source_range.start()],
112            self.insert,
113            &src[self.source_range.end()..]
114        )
115    }
116}