1use clap::ValueEnum;
4use core::fmt;
5use serde::{Deserialize, Deserializer, Serialize};
6use solar::interface::diagnostics::Level;
7use std::str::FromStr;
8use yansi::Paint;
9
10#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
12pub struct LinterConfig {
13 pub severity: Vec<Severity>,
17
18 pub exclude_lints: Vec<String>,
20
21 pub ignore: Vec<String>,
23
24 pub lint_on_build: bool,
28
29 pub mixed_case_exceptions: Vec<String>,
34}
35
36impl Default for LinterConfig {
37 fn default() -> Self {
38 Self {
39 lint_on_build: true,
40 severity: vec![Severity::High, Severity::Med, Severity::Low],
41 exclude_lints: Vec::new(),
42 ignore: Vec::new(),
43 mixed_case_exceptions: vec![
44 "ERC".to_string(),
45 "URI".to_string(),
46 "ID".to_string(),
47 "URL".to_string(),
48 "API".to_string(),
49 "JSON".to_string(),
50 "XML".to_string(),
51 "HTML".to_string(),
52 "HTTP".to_string(),
53 "HTTPS".to_string(),
54 ],
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
61pub enum Severity {
62 High,
63 Med,
64 Low,
65 Info,
66 Gas,
67 CodeSize,
68}
69
70impl Severity {
71 fn to_str(self) -> &'static str {
72 match self {
73 Self::High => "High",
74 Self::Med => "Med",
75 Self::Low => "Low",
76 Self::Info => "Info",
77 Self::Gas => "Gas",
78 Self::CodeSize => "CodeSize",
79 }
80 }
81
82 fn to_str_kebab(self) -> &'static str {
83 match self {
84 Self::High => "high",
85 Self::Med => "medium",
86 Self::Low => "low",
87 Self::Info => "info",
88 Self::Gas => "gas",
89 Self::CodeSize => "code-size",
90 }
91 }
92
93 pub fn color(&self, message: &str) -> String {
94 match self {
95 Self::High => Paint::red(message).bold().to_string(),
96 Self::Med => Paint::rgb(message, 255, 135, 61).bold().to_string(),
97 Self::Low => Paint::yellow(message).bold().to_string(),
98 Self::Info => Paint::cyan(message).bold().to_string(),
99 Self::Gas => Paint::green(message).bold().to_string(),
100 Self::CodeSize => Paint::green(message).bold().to_string(),
101 }
102 }
103}
104
105impl From<Severity> for Level {
106 fn from(severity: Severity) -> Self {
107 match severity {
108 Severity::High | Severity::Med | Severity::Low => Self::Warning,
109 Severity::Info | Severity::Gas | Severity::CodeSize => Self::Note,
110 }
111 }
112}
113
114impl fmt::Display for Severity {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{}", self.color(self.to_str()))
117 }
118}
119
120impl Serialize for Severity {
121 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122 where
123 S: serde::Serializer,
124 {
125 self.to_str_kebab().serialize(serializer)
126 }
127}
128
129impl<'de> Deserialize<'de> for Severity {
131 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
132 where
133 D: Deserializer<'de>,
134 {
135 let s = String::deserialize(deserializer)?;
136 FromStr::from_str(&s).map_err(serde::de::Error::custom)
137 }
138}
139
140impl FromStr for Severity {
141 type Err = String;
142
143 fn from_str(s: &str) -> Result<Self, Self::Err> {
144 match s.to_lowercase().as_str() {
145 "high" => Ok(Self::High),
146 "med" | "medium" => Ok(Self::Med),
147 "low" => Ok(Self::Low),
148 "info" => Ok(Self::Info),
149 "gas" => Ok(Self::Gas),
150 "size" | "codesize" | "code-size" => Ok(Self::CodeSize),
151 _ => Err(format!(
152 "unknown variant: found `{s}`, expected `one of `High`, `Med`, `Low`, `Info`, `Gas`, `CodeSize`"
153 )),
154 }
155 }
156}