rigsql_rules/layout/
lt05.rs1use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
2use crate::violation::LintViolation;
3
4#[derive(Debug)]
8pub struct RuleLT05 {
9 pub max_line_length: usize,
10}
11
12impl Default for RuleLT05 {
13 fn default() -> Self {
14 Self {
15 max_line_length: 80,
16 }
17 }
18}
19
20impl Rule for RuleLT05 {
21 fn code(&self) -> &'static str {
22 "LT05"
23 }
24 fn name(&self) -> &'static str {
25 "layout.long_lines"
26 }
27 fn description(&self) -> &'static str {
28 "Line too long."
29 }
30 fn explanation(&self) -> &'static str {
31 "Long lines are harder to read and review. Keep lines under the configured \
32 maximum length (default 80 characters). Break long queries across multiple lines."
33 }
34 fn groups(&self) -> &[RuleGroup] {
35 &[RuleGroup::Layout]
36 }
37 fn is_fixable(&self) -> bool {
38 false
39 }
40
41 fn configure(&mut self, settings: &std::collections::HashMap<String, String>) {
42 if let Some(val) = settings.get("max_line_length") {
43 if let Ok(n) = val.parse() {
44 self.max_line_length = n;
45 }
46 }
47 }
48
49 fn crawl_type(&self) -> CrawlType {
50 CrawlType::RootOnly
51 }
52
53 fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
54 let mut violations = Vec::new();
55 let source = ctx.source;
56 let mut offset = 0usize;
57
58 for line in source.lines() {
59 let line_len = line.len();
60 if line_len > self.max_line_length {
61 let span = rigsql_core::Span::new(offset as u32, (offset + line_len) as u32);
62 violations.push(LintViolation::new(
63 self.code(),
64 format!(
65 "Line is too long ({} > {} characters).",
66 line_len, self.max_line_length
67 ),
68 span,
69 ));
70 }
71 offset += line_len + 1; }
73
74 violations
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::test_utils::lint_sql;
82
83 #[test]
84 fn test_lt05_flags_long_line() {
85 let long_sql = format!("SELECT {} FROM t", "a, ".repeat(30));
86 let violations = lint_sql(&long_sql, RuleLT05::default());
87 assert!(!violations.is_empty());
88 assert!(violations.iter().all(|v| v.rule_code == "LT05"));
89 }
90
91 #[test]
92 fn test_lt05_accepts_short_line() {
93 let violations = lint_sql("SELECT * FROM t", RuleLT05::default());
94 assert_eq!(violations.len(), 0);
95 }
96
97 #[test]
98 fn test_lt05_custom_max_length() {
99 let rule = RuleLT05 {
100 max_line_length: 120,
101 };
102 let sql_100_chars = format!("SELECT {} FROM t", "x".repeat(88));
103 let violations = lint_sql(&sql_100_chars, rule);
104 assert_eq!(violations.len(), 0);
105 }
106}