use crate::domain::finding::Finding;
use crate::domain::rule_id::RuleId;
use crate::gates::{GateCtx, GateResult, Violation};
pub const CITES: &[RuleId] = &[RuleId::CaseIdIsASlug];
const RULE: RuleId = RuleId::CaseIdIsASlug;
pub fn run(_ctx: &GateCtx, files: &[String]) -> GateResult {
let mut violations = Vec::new();
for file in files {
let basename = file.rsplit('/').next().unwrap_or(file);
let Some(after_prefix) = basename.strip_prefix("KI-") else {
violations.push(Violation::Finding(Finding::on_file(
RULE,
file,
"no KI- prefix",
)));
continue;
};
let Some(slug) = after_prefix.strip_suffix(".md") else {
violations.push(Violation::Finding(Finding::on_file(
RULE,
file,
"not a markdown file",
)));
continue;
};
if slug.as_bytes().first().is_some_and(u8::is_ascii_digit) {
violations.push(Violation::Finding(Finding::on_file(
RULE,
file,
"a slug, not a counter",
)));
} else if slug.is_empty()
|| !slug
.bytes()
.all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-')
{
violations.push(Violation::Finding(Finding::on_file(
RULE,
file,
"the slug is lowercase, digits and hyphens",
)));
}
}
Ok(violations)
}
#[cfg(test)]
mod tests {
use super::*;
fn run_on(files: &[&str]) -> Vec<String> {
let ctx = GateCtx::new(".");
let files: Vec<String> = files.iter().map(ToString::to_string).collect();
run(&ctx, &files)
.unwrap()
.iter()
.map(ToString::to_string)
.collect()
}
#[test]
fn accepts_a_slug_with_an_inner_digit() {
assert!(run_on(&["_docs/reference/known-issues/KI-vendor-500.md"]).is_empty());
}
#[test]
fn rejects_a_counter() {
let out = run_on(&["_docs/reference/known-issues/KI-001-vendor.md"]);
assert_eq!(out.len(), 1);
assert!(out[0].contains("known-issues:case-id-is-a-slug"));
assert!(out[0].ends_with(": a slug, not a counter"));
}
#[test]
fn rejects_missing_prefix_wrong_extension_and_bad_charset() {
assert!(run_on(&["x/ISSUE-a.md"])[0].ends_with(": no KI- prefix"));
assert!(run_on(&["x/KI-a.txt"])[0].ends_with(": not a markdown file"));
assert!(
run_on(&["x/KI-Weird.md"])[0].ends_with(": the slug is lowercase, digits and hyphens")
);
}
}