Skip to main content

just_lsp/
config.rs

1use super::*;
2
3#[derive(Clone, Debug, Default, Deserialize)]
4pub struct Config {
5  #[serde(default)]
6  pub rules: HashMap<String, RuleConfig>,
7}
8
9impl Config {
10  #[must_use]
11  pub fn rule_config(&self, id: &str) -> RuleConfig {
12    self.rules.get(id).cloned().unwrap_or_default()
13  }
14}
15
16#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
17#[serde(rename_all = "kebab-case")]
18pub enum RuleLevel {
19  Error,
20  Hint,
21  #[serde(alias = "info")]
22  Information,
23  Off,
24  Warning,
25}
26
27impl From<RuleLevel> for lsp::DiagnosticSeverity {
28  fn from(value: RuleLevel) -> Self {
29    match value {
30      RuleLevel::Error => Self::ERROR,
31      RuleLevel::Hint | RuleLevel::Off => Self::HINT,
32      RuleLevel::Information => Self::INFORMATION,
33      RuleLevel::Warning => Self::WARNING,
34    }
35  }
36}
37
38#[derive(Clone, Debug, Deserialize)]
39#[serde(untagged)]
40pub enum RuleConfig {
41  Level(RuleLevel),
42  Settings {
43    #[serde(default)]
44    level: Option<RuleLevel>,
45  },
46}
47
48impl Default for RuleConfig {
49  fn default() -> Self {
50    Self::Settings { level: None }
51  }
52}
53
54impl RuleConfig {
55  #[must_use]
56  pub fn level(&self) -> Option<RuleLevel> {
57    match self {
58      RuleConfig::Level(level) => Some(*level),
59      RuleConfig::Settings { level } => *level,
60    }
61  }
62
63  #[must_use]
64  pub fn severity(
65    &self,
66    default: lsp::DiagnosticSeverity,
67  ) -> Option<lsp::DiagnosticSeverity> {
68    match self.level() {
69      None => Some(default),
70      Some(RuleLevel::Off) => None,
71      Some(level) => Some(level.into()),
72    }
73  }
74}
75
76#[cfg(test)]
77mod tests {
78  use {super::*, serde_json::json};
79
80  #[test]
81  fn parses_rule_config_from_string() {
82    let config: Config = serde_json::from_value(json!({
83      "rules": {
84        "foo": "warning"
85      }
86    }))
87    .unwrap();
88
89    assert_eq!(config.rule_config("foo").level(), Some(RuleLevel::Warning));
90  }
91
92  #[test]
93  fn parses_rule_config_from_table() {
94    let config: Config = serde_json::from_value(json!({
95      "rules": {
96        "foo": { "level": "hint" }
97      }
98    }))
99    .unwrap();
100
101    assert_eq!(config.rule_config("foo").level(), Some(RuleLevel::Hint));
102  }
103
104  #[test]
105  fn missing_rule_config_returns_default() {
106    let config = Config::default();
107
108    assert_eq!(config.rule_config("foo").level(), None);
109  }
110
111  #[test]
112  fn off_level_produces_none_severity() {
113    let config: Config = serde_json::from_value(json!({
114      "rules": {
115        "foo": "off"
116      }
117    }))
118    .unwrap();
119
120    assert_eq!(
121      config
122        .rule_config("foo")
123        .severity(lsp::DiagnosticSeverity::ERROR),
124      None
125    );
126  }
127
128  #[test]
129  fn rule_config_overrides_default_severity() {
130    let config: Config = serde_json::from_value(json!({
131      "rules": {
132        "foo": "warning"
133      }
134    }))
135    .unwrap();
136
137    assert_eq!(
138      config
139        .rule_config("foo")
140        .severity(lsp::DiagnosticSeverity::ERROR),
141      Some(lsp::DiagnosticSeverity::WARNING)
142    );
143  }
144
145  #[test]
146  fn missing_rule_config_uses_default_severity() {
147    let config = Config::default();
148
149    assert_eq!(
150      config
151        .rule_config("foo")
152        .severity(lsp::DiagnosticSeverity::ERROR),
153      Some(lsp::DiagnosticSeverity::ERROR)
154    );
155  }
156
157  #[test]
158  fn info_alias_parses() {
159    let config: Config = serde_json::from_value(json!({
160      "rules": {
161        "foo": "info"
162      }
163    }))
164    .unwrap();
165
166    assert_eq!(
167      config.rule_config("foo").level(),
168      Some(RuleLevel::Information)
169    );
170  }
171}