scribe_analysis/language_support/
documentation_analysis.rs

1//! # Documentation Coverage Analysis
2//!
3//! Analyzes documentation coverage in source code files, including docstrings,
4//! comments, and inline documentation patterns.
5
6use super::ast_language::AstLanguage;
7use scribe_core::Result;
8use serde::{Deserialize, Serialize};
9
10/// Documentation coverage analysis results
11#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct DocumentationCoverage {
13    /// Total number of functions/methods
14    pub total_functions: usize,
15    /// Number of documented functions
16    pub documented_functions: usize,
17    /// Total number of classes
18    pub total_classes: usize,
19    /// Number of documented classes
20    pub documented_classes: usize,
21    /// Documentation coverage percentage
22    pub coverage_percentage: f64,
23    /// Lines of documentation
24    pub documentation_lines: usize,
25    /// Total lines of code
26    pub total_lines: usize,
27}
28
29/// Documentation analyzer for specific languages
30#[derive(Debug)]
31pub struct DocumentationAnalyzer {
32    language: AstLanguage,
33}
34
35impl DocumentationAnalyzer {
36    /// Create a new documentation analyzer
37    pub fn new(language: AstLanguage) -> Result<Self> {
38        Ok(Self { language })
39    }
40
41    /// Analyze documentation coverage in source code
42    pub fn analyze_coverage(&self, content: &str) -> Result<DocumentationCoverage> {
43        // Basic implementation - can be enhanced with AST analysis
44        let lines: Vec<&str> = content.lines().collect();
45        let total_lines = lines.len();
46        let documentation_lines = self.count_documentation_lines(&lines);
47
48        let coverage_percentage = if total_lines > 0 {
49            (documentation_lines as f64 / total_lines as f64) * 100.0
50        } else {
51            0.0
52        };
53
54        Ok(DocumentationCoverage {
55            total_functions: 0,      // TODO: Extract from AST
56            documented_functions: 0, // TODO: Extract from AST
57            total_classes: 0,        // TODO: Extract from AST
58            documented_classes: 0,   // TODO: Extract from AST
59            coverage_percentage,
60            documentation_lines,
61            total_lines,
62        })
63    }
64
65    /// Count lines that contain documentation
66    fn count_documentation_lines(&self, lines: &[&str]) -> usize {
67        lines
68            .iter()
69            .filter(|line| self.is_documentation_line(line))
70            .count()
71    }
72
73    /// Check if a line contains documentation
74    fn is_documentation_line(&self, line: &str) -> bool {
75        let trimmed = line.trim();
76
77        match self.language {
78            AstLanguage::Python => {
79                trimmed.starts_with('#')
80                    || trimmed.starts_with("\"\"\"")
81                    || trimmed.starts_with("'''")
82            }
83            AstLanguage::JavaScript | AstLanguage::TypeScript => {
84                trimmed.starts_with("//")
85                    || trimmed.starts_with("/*")
86                    || trimmed.starts_with("*")
87                    || trimmed.starts_with("/**")
88            }
89            AstLanguage::Rust => {
90                trimmed.starts_with("//")
91                    || trimmed.starts_with("///")
92                    || trimmed.starts_with("//!")
93            }
94            AstLanguage::Go => trimmed.starts_with("//"),
95            _ => {
96                // Generic comment detection
97                trimmed.starts_with("//")
98                    || trimmed.starts_with("#")
99                    || trimmed.starts_with("/*")
100                    || trimmed.starts_with("*")
101            }
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn test_python_documentation_analysis() {
112        let analyzer = DocumentationAnalyzer::new(AstLanguage::Python).unwrap();
113        let python_code = r#"
114# This is a comment
115def hello():
116    """This is a docstring."""
117    print("Hello")
118
119def world():
120    # Another comment
121    print("World")
122"#;
123
124        let coverage = analyzer.analyze_coverage(python_code).unwrap();
125        assert!(coverage.documentation_lines > 0);
126        assert!(coverage.coverage_percentage > 0.0);
127    }
128}