Skip to main content

react_auditor/
docs.rs

1use std::collections::BTreeMap;
2use std::fs;
3use std::path::Path;
4
5use crate::rules::{RuleRegistry, Severity};
6
7pub fn generate_docs() {
8    let registry = RuleRegistry::new();
9    let ids = registry.get_rule_ids();
10
11    let mut categories: BTreeMap<&str, Vec<(&str, &str, &str)>> = BTreeMap::new();
12
13    for id in &ids {
14        if let Some(rule) = registry.get_rule(id) {
15            let meta = rule.meta();
16            categories.entry(meta.category).or_default().push((
17                meta.id,
18                meta.description,
19                severity_str(&meta.default_severity),
20            ));
21        }
22    }
23
24    let docs_dir = Path::new("docs/rules");
25    fs::create_dir_all(docs_dir).expect("failed to create docs/rules");
26
27    for id in &ids {
28        if let Some(rule) = registry.get_rule(id) {
29            let meta = rule.meta();
30            let filename = format!("{}.md", meta.id);
31            let path = docs_dir.join(&filename);
32            let content = format!(
33                concat!(
34                    "# {}\n\n",
35                    "- **Category:** {}\n",
36                    "- **Default severity:** {}\n",
37                    "- **Auto-fix:** {}\n\n",
38                    "{}\n",
39                ),
40                meta.id,
41                meta.category,
42                severity_str(&meta.default_severity),
43                if rule.has_fix() { "Yes" } else { "No" },
44                meta.description,
45            );
46            fs::write(&path, content).expect("failed to write rule doc");
47            println!("wrote {}", path.display());
48        }
49    }
50
51    let mut index = String::from("# Rules\n\nAll rules organized by category.\n\n");
52    for (category, rules) in &categories {
53        index.push_str(&format!("## {}\n\n", capitalize(category)));
54        index.push_str("| Rule | Default | Description |\n|------|---------|-------------|\n");
55        for (id, desc, sev) in rules {
56            index.push_str(&format!("| [{}]({}.md) | {} | {} |\n", id, id, sev, desc));
57        }
58        index.push('\n');
59    }
60
61    let index_path = docs_dir.join("README.md");
62    fs::write(&index_path, index).expect("failed to write index");
63    println!("wrote {}", index_path.display());
64}
65
66fn severity_str(s: &Severity) -> &str {
67    match s {
68        Severity::Error => "error",
69        Severity::Warning => "warning",
70        Severity::Off => "off",
71    }
72}
73
74fn capitalize(s: &str) -> String {
75    let mut chars = s.chars();
76    match chars.next() {
77        None => String::new(),
78        Some(c) => c.to_uppercase().to_string() + chars.as_str(),
79    }
80}