baobao_codegen/pipeline/phases/validate/lints/
empty_description.rs

1//! Lint for empty command descriptions.
2
3use baobao_manifest::Manifest;
4
5use super::super::Lint;
6use crate::pipeline::Diagnostic;
7
8/// Lint that warns about commands missing descriptions.
9pub struct EmptyDescriptionLint;
10
11impl Lint for EmptyDescriptionLint {
12    fn name(&self) -> &'static str {
13        "empty-description"
14    }
15
16    fn description(&self) -> &'static str {
17        "Warn about commands missing descriptions"
18    }
19
20    fn check(&self, manifest: &Manifest, diagnostics: &mut Vec<Diagnostic>) {
21        for (name, cmd) in &manifest.commands {
22            if cmd.description.is_empty() {
23                diagnostics.push(
24                    Diagnostic::warning(
25                        "validate",
26                        format!("command '{}' has no description", name),
27                    )
28                    .at(format!("commands.{}", name)),
29                );
30            }
31
32            check_subcommand_descriptions(name, cmd, diagnostics);
33        }
34    }
35}
36
37fn check_subcommand_descriptions(
38    parent_path: &str,
39    cmd: &baobao_manifest::Command,
40    diagnostics: &mut Vec<Diagnostic>,
41) {
42    for (name, subcmd) in &cmd.commands {
43        let path = format!("{}.{}", parent_path, name);
44        if subcmd.description.is_empty() {
45            diagnostics.push(
46                Diagnostic::warning("validate", format!("command '{}' has no description", path))
47                    .at(format!("commands.{}", path)),
48            );
49        }
50        check_subcommand_descriptions(&path, subcmd, diagnostics);
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    fn parse_manifest(content: &str) -> Manifest {
59        toml::from_str(content).expect("Failed to parse test manifest")
60    }
61
62    #[test]
63    fn test_empty_description() {
64        let manifest = parse_manifest(
65            r#"
66            [cli]
67            name = "test"
68            language = "rust"
69
70            [commands.deploy]
71            description = ""
72        "#,
73        );
74
75        let mut diagnostics = Vec::new();
76        EmptyDescriptionLint.check(&manifest, &mut diagnostics);
77
78        assert_eq!(diagnostics.len(), 1);
79        assert!(diagnostics[0].message.contains("deploy"));
80        assert!(diagnostics[0].severity.is_warning());
81    }
82
83    #[test]
84    fn test_has_description() {
85        let manifest = parse_manifest(
86            r#"
87            [cli]
88            name = "test"
89            language = "rust"
90
91            [commands.deploy]
92            description = "Deploy the application"
93        "#,
94        );
95
96        let mut diagnostics = Vec::new();
97        EmptyDescriptionLint.check(&manifest, &mut diagnostics);
98
99        assert!(diagnostics.is_empty());
100    }
101}