1use crate::{
2 context::LintContext,
3 lint::{Severity, Violation},
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum RuleCategory {
8 Style,
9 BestPractices,
10 Performance,
11 Documentation,
12 TypeSafety,
13}
14
15impl std::fmt::Display for RuleCategory {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 RuleCategory::Style => write!(f, "style"),
19 RuleCategory::BestPractices => write!(f, "best-practices"),
20 RuleCategory::Performance => write!(f, "performance"),
21 RuleCategory::Documentation => write!(f, "documentation"),
22 RuleCategory::TypeSafety => write!(f, "type-safety"),
23 }
24 }
25}
26
27pub trait RuleMetadata: Send + Sync {
29 fn id(&self) -> &str;
30 fn category(&self) -> RuleCategory;
31 fn severity(&self) -> Severity;
32 fn description(&self) -> &str;
33}
34
35pub trait RegexRule: RuleMetadata {
37 fn check(&self, context: &LintContext) -> Vec<Violation>;
38}
39
40pub trait AstRule: RuleMetadata {
42 fn check(&self, context: &LintContext) -> Vec<Violation>;
43}
44
45pub enum Rule {
47 Regex(Box<dyn RegexRule>),
48 Ast(Box<dyn AstRule>),
49}
50
51impl Rule {
52 #[must_use]
54 pub fn check(&self, context: &LintContext) -> Vec<Violation> {
55 match self {
56 Rule::Regex(rule) => rule.check(context),
57 Rule::Ast(rule) => rule.check(context),
58 }
59 }
60
61 #[must_use]
63 pub fn is_ast_rule(&self) -> bool {
64 matches!(self, Rule::Ast(_))
65 }
66}
67
68impl RuleMetadata for Rule {
69 fn id(&self) -> &str {
70 match self {
71 Rule::Regex(rule) => rule.id(),
72 Rule::Ast(rule) => rule.id(),
73 }
74 }
75
76 fn category(&self) -> RuleCategory {
77 match self {
78 Rule::Regex(rule) => rule.category(),
79 Rule::Ast(rule) => rule.category(),
80 }
81 }
82
83 fn severity(&self) -> Severity {
84 match self {
85 Rule::Regex(rule) => rule.severity(),
86 Rule::Ast(rule) => rule.severity(),
87 }
88 }
89
90 fn description(&self) -> &str {
91 match self {
92 Rule::Regex(rule) => rule.description(),
93 Rule::Ast(rule) => rule.description(),
94 }
95 }
96}