rigsql_rules/capitalisation/
cp05.rs1use rigsql_core::SegmentType;
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::violation::{LintViolation, SourceEdit};
5
6#[derive(Debug)]
10pub struct RuleCP05 {
11 pub policy: DataTypeCapPolicy,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum DataTypeCapPolicy {
16 Upper,
17 Lower,
18}
19
20impl Default for RuleCP05 {
21 fn default() -> Self {
22 Self {
23 policy: DataTypeCapPolicy::Upper,
24 }
25 }
26}
27
28impl Rule for RuleCP05 {
29 fn code(&self) -> &'static str {
30 "CP05"
31 }
32 fn name(&self) -> &'static str {
33 "capitalisation.types"
34 }
35 fn description(&self) -> &'static str {
36 "Data type names must be consistently capitalised."
37 }
38 fn explanation(&self) -> &'static str {
39 "Data type names (INT, VARCHAR, TEXT, etc.) should use consistent capitalisation. \
40 Most style guides recommend upper case for data types to distinguish them from column names."
41 }
42 fn groups(&self) -> &[RuleGroup] {
43 &[RuleGroup::Capitalisation]
44 }
45 fn is_fixable(&self) -> bool {
46 true
47 }
48
49 fn configure(&mut self, settings: &std::collections::HashMap<String, String>) {
50 if let Some(val) = settings.get("capitalisation_policy") {
51 self.policy = match val.as_str() {
52 "lower" => DataTypeCapPolicy::Lower,
53 _ => DataTypeCapPolicy::Upper,
54 };
55 }
56 }
57
58 fn crawl_type(&self) -> CrawlType {
59 CrawlType::Segment(vec![SegmentType::DataType])
60 }
61
62 fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
63 let tokens = ctx.segment.tokens();
65 let mut violations = Vec::new();
66
67 for token in tokens {
68 let text = token.text.as_str();
69 if text
71 .chars()
72 .all(|c| c.is_ascii_digit() || c == '(' || c == ')' || c == ',')
73 {
74 continue;
75 }
76
77 let expected = match self.policy {
78 DataTypeCapPolicy::Upper => text.to_ascii_uppercase(),
79 DataTypeCapPolicy::Lower => text.to_ascii_lowercase(),
80 };
81
82 if text != expected {
83 violations.push(LintViolation::with_fix(
84 self.code(),
85 format!(
86 "Data type must be {} case. Found '{}' instead of '{}'.",
87 match self.policy {
88 DataTypeCapPolicy::Upper => "upper",
89 DataTypeCapPolicy::Lower => "lower",
90 },
91 text,
92 expected
93 ),
94 token.span,
95 vec![SourceEdit::replace(token.span, expected.clone())],
96 ));
97 }
98 }
99
100 violations
101 }
102}