use super::*;
pub struct NamingConventionRule;
impl Rule for NamingConventionRule {
fn name(&self) -> &'static str {
"naming-convention"
}
fn check(&self, ctx: &mut RuleContext) {
let mut issues_to_report = Vec::new();
for item in &ctx.syntax_tree.items {
match item {
syn::Item::Fn(func) => {
let name = func.sig.ident.to_string();
if !is_snake_case(&name) && !name.starts_with("test_") {
let (line, col) = ctx.line_col(func.sig.ident.span());
issues_to_report.push(Issue {
rule: self.name().to_string(),
severity: Severity::Warning,
message: format!("Function '{}' should be snake_case", name),
location: Location {
line,
column: col,
end_line: None,
end_column: None,
},
fix: Some(Fix {
description: "Convert to snake_case".to_string(),
replacements: vec![Replacement {
start: 0, end: 0,
text: to_snake_case(&name),
}],
}),
});
}
}
syn::Item::Struct(s) => {
let name = s.ident.to_string();
if !is_pascal_case(&name) {
let (line, col) = ctx.line_col(s.ident.span());
issues_to_report.push(Issue {
rule: self.name().to_string(),
severity: Severity::Warning,
message: format!("Struct '{}' should be PascalCase", name),
location: Location {
line,
column: col,
end_line: None,
end_column: None,
},
fix: None,
});
}
}
_ => {}
}
}
for issue in issues_to_report {
ctx.report(issue);
}
}
}
pub struct LineLengthRule {
max_length: usize,
}
impl LineLengthRule {
pub fn new(max_length: usize) -> Self {
Self { max_length }
}
}
impl Rule for LineLengthRule {
fn name(&self) -> &'static str {
"line-too-long"
}
fn check(&self, ctx: &mut RuleContext) {
let lines: Vec<_> = ctx.content.lines().enumerate().collect();
let mut issues_to_report = Vec::new();
for (i, line) in lines {
if line.len() > self.max_length {
issues_to_report.push(Issue {
rule: self.name().to_string(),
severity: Severity::Info,
message: format!(
"Line exceeds {} characters ({})",
self.max_length,
line.len()
),
location: Location {
line: i + 1,
column: self.max_length + 1,
end_line: None,
end_column: None,
},
fix: None,
});
}
}
for issue in issues_to_report {
ctx.report(issue);
}
}
}
fn is_snake_case(s: &str) -> bool {
s.chars().all(|c| c.is_lowercase() || c.is_numeric() || c == '_')
}
fn is_pascal_case(s: &str) -> bool {
s.chars().next().map_or(false, |c| c.is_uppercase())
&& s.chars().all(|c| c.is_alphanumeric())
}
fn to_snake_case(s: &str) -> String {
let mut result = String::new();
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() && i > 0 {
result.push('_');
}
result.push(ch.to_lowercase().next().unwrap());
}
result
}