pub mod ast_language;
pub mod documentation_analysis;
pub mod function_extraction;
pub mod language_metrics;
pub use ast_language::{AstLanguage, LanguageFeatures, LanguageTier};
pub use documentation_analysis::{DocumentationAnalyzer, DocumentationCoverage};
pub use function_extraction::{ClassInfo, FunctionExtractor, FunctionInfo};
pub use language_metrics::{LanguageMetrics, LanguageSpecificComplexity};
use scribe_core::Result;
use std::collections::HashMap;
pub struct LanguageSupport {
function_extractors: HashMap<AstLanguage, FunctionExtractor>,
doc_analyzers: HashMap<AstLanguage, DocumentationAnalyzer>,
}
impl LanguageSupport {
pub fn new() -> Result<Self> {
let mut support = Self {
function_extractors: HashMap::new(),
doc_analyzers: HashMap::new(),
};
support.initialize_extractors()?;
Ok(support)
}
fn initialize_extractors(&mut self) -> Result<()> {
for language in AstLanguage::all_supported() {
self.function_extractors
.insert(language, FunctionExtractor::new(language)?);
self.doc_analyzers
.insert(language, DocumentationAnalyzer::new(language)?);
}
Ok(())
}
pub fn get_language_features(&self, language: AstLanguage) -> LanguageFeatures {
language.features()
}
pub fn extract_functions(
&mut self,
content: &str,
language: AstLanguage,
) -> Result<Vec<FunctionInfo>> {
if let Some(extractor) = self.function_extractors.get_mut(&language) {
extractor.extract_functions(content)
} else {
Ok(Vec::new())
}
}
pub fn analyze_documentation(
&self,
content: &str,
language: AstLanguage,
) -> Result<DocumentationCoverage> {
if let Some(analyzer) = self.doc_analyzers.get(&language) {
analyzer.analyze_coverage(content)
} else {
Ok(DocumentationCoverage::default())
}
}
pub fn calculate_language_metrics(
&self,
content: &str,
language: AstLanguage,
) -> Result<LanguageMetrics> {
LanguageMetrics::calculate(content, language)
}
pub fn is_supported(&self, language: AstLanguage) -> bool {
self.function_extractors.contains_key(&language)
}
pub fn supported_languages(&self) -> Vec<AstLanguage> {
self.function_extractors.keys().copied().collect()
}
}
impl Default for LanguageSupport {
fn default() -> Self {
Self::new().expect("Failed to create LanguageSupport")
}
}
#[derive(Debug, Clone)]
pub struct LanguageAnalysisResult {
pub language: AstLanguage,
pub tier: LanguageTier,
pub functions: Vec<FunctionInfo>,
pub documentation: DocumentationCoverage,
pub metrics: LanguageMetrics,
}
pub fn analyze_file_language(
content: &str,
file_extension: &str,
language_support: &mut LanguageSupport,
) -> Result<Option<LanguageAnalysisResult>> {
let language = match AstLanguage::from_extension(file_extension) {
Some(lang) => lang,
None => return Ok(None),
};
if !language_support.is_supported(language) {
return Ok(None);
}
let functions = language_support.extract_functions(content, language)?;
let documentation = language_support.analyze_documentation(content, language)?;
let metrics = language_support.calculate_language_metrics(content, language)?;
Ok(Some(LanguageAnalysisResult {
language,
tier: language.tier(),
functions,
documentation,
metrics,
}))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_language_support_creation() {
let support = LanguageSupport::new();
if let Err(e) = &support {
println!("Error creating LanguageSupport: {:?}", e);
}
assert!(support.is_ok());
}
#[test]
fn test_supported_languages() {
let support = LanguageSupport::new().unwrap();
let languages = support.supported_languages();
assert!(languages.contains(&AstLanguage::Python));
assert!(languages.contains(&AstLanguage::JavaScript));
assert!(languages.contains(&AstLanguage::Rust));
}
#[test]
fn test_python_function_extraction() {
let mut support = LanguageSupport::new().unwrap();
let python_code = r#"
def hello_world():
"""A simple function."""
print("Hello, World!")
class Calculator:
"""A simple calculator class."""
def add(self, a, b):
"""Add two numbers."""
return a + b
"#;
let functions = support.extract_functions(python_code, AstLanguage::Python);
assert!(functions.is_ok());
let functions = functions.unwrap();
assert!(!functions.is_empty());
}
#[test]
fn test_language_analysis() {
let mut support = LanguageSupport::new().unwrap();
let result = analyze_file_language("def test(): pass", "py", &mut support);
assert!(result.is_ok());
let result = result.unwrap();
assert!(result.is_some());
assert_eq!(result.unwrap().language, AstLanguage::Python);
}
}