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}