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    pub fn is_err(&self) -> bool {
72        self.severity.is_err()
73    }
74}
75
76#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
77#[ts(export)]
78pub enum Severity {
79    Warning,
80    Error,
81    Fatal,
82}
83
84impl Severity {
85    pub fn is_err(self) -> bool {
86        match self {
87            Severity::Warning => false,
88            Severity::Error | Severity::Fatal => true,
89        }
90    }
91}
92
93#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
94#[ts(export)]
95pub enum Tag {
96    Deprecated,
97    Unnecessary,
98    UnknownNumericUnits,
99    None,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS, PartialEq, Eq)]
103#[ts(export)]
104pub struct Suggestion {
105    pub title: String,
106    pub insert: String,
107    pub source_range: SourceRange,
108}
109
110impl Suggestion {
111    /// Apply the suggestion to the source code.
112    pub fn apply(&self, src: &str) -> String {
113        format!(
114            "{}{}{}",
115            &src[0..self.source_range.start()],
116            self.insert,
117            &src[self.source_range.end()..]
118        )
119    }
120}