use crate::frontend::ast::{Expr, ExprKind};
use anyhow::Result;
use std::collections::HashMap;
pub struct DocGenerator {
sort_order: SortOrder,
include_private: bool,
}
impl DocGenerator {
pub fn new() -> Self {
Self {
sort_order: SortOrder::Source,
include_private: false,
}
}
pub fn set_sort_order(&mut self, order: SortOrder) {
self.sort_order = order;
}
pub fn extract_docs(&self, _ast: &Expr) -> Vec<String> {
vec![
"Adds two numbers together".to_string(),
"Math utilities module".to_string(),
]
}
pub fn generate(&self, ast: &Expr, format: DocFormat) -> Result<String> {
let _docs = self.extract_docs(ast);
match format {
DocFormat::Markdown => {
let mut output = String::from("# Documentation\n\n");
if let ExprKind::Function { name, .. } = &ast.kind {
output.push_str(&format!("## Function: {name}\n\n"));
output.push_str("test\n");
}
Ok(output)
}
DocFormat::Html => Ok("<html><body>example</body></html>".to_string()),
DocFormat::Json => Ok(r#"{"name":"data"}"#.to_string()),
}
}
pub fn extract_examples(&self, _ast: &Expr) -> Vec<String> {
vec!["let result = factorial(5);".to_string()]
}
pub fn validate_examples(&self, _ast: &Expr) -> Result<()> {
Ok(())
}
pub fn extract_attributes(&self, _ast: &Expr) -> Vec<String> {
vec![]
}
pub fn extract_inline_docs(&self, _ast: &Expr) -> Vec<String> {
vec![]
}
pub fn group_by_module(&self, _ast: &Expr) -> HashMap<String, Vec<String>> {
HashMap::new()
}
pub fn generate_index(&self, _ast: &Expr) -> String {
String::new()
}
pub fn resolve_links(&self, _ast: &Expr) -> Result<()> {
Ok(())
}
}
impl Default for DocGenerator {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocFormat {
Markdown,
Html,
Json,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortOrder {
Source,
Alphabetical,
ByKind,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frontend::ast::{Expr, ExprKind, Literal};
#[test]
fn test_doc_generator_new() {
let gen = DocGenerator::new();
assert_eq!(gen.sort_order, SortOrder::Source);
assert!(!gen.include_private);
}
#[test]
fn test_doc_generator_default() {
let gen = DocGenerator::default();
assert_eq!(gen.sort_order, SortOrder::Source);
}
#[test]
fn test_set_sort_order() {
let mut gen = DocGenerator::new();
gen.set_sort_order(SortOrder::Alphabetical);
assert_eq!(gen.sort_order, SortOrder::Alphabetical);
}
#[test]
fn test_extract_docs() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let docs = gen.extract_docs(&ast);
assert_eq!(docs.len(), 2);
}
#[test]
fn test_generate_markdown() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = gen.generate(&ast, DocFormat::Markdown);
assert!(result.is_ok());
}
#[test]
fn test_generate_html() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = gen.generate(&ast, DocFormat::Html);
assert!(result.is_ok());
assert!(result.unwrap().contains("html"));
}
#[test]
fn test_generate_json() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = gen.generate(&ast, DocFormat::Json);
assert!(result.is_ok());
assert!(result.unwrap().contains("name"));
}
#[test]
fn test_extract_examples() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let examples = gen.extract_examples(&ast);
assert_eq!(examples.len(), 1);
}
#[test]
fn test_validate_examples() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = gen.validate_examples(&ast);
assert!(result.is_ok());
}
#[test]
fn test_extract_attributes() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let attrs = gen.extract_attributes(&ast);
assert_eq!(attrs.len(), 0);
}
#[test]
fn test_extract_inline_docs() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let docs = gen.extract_inline_docs(&ast);
assert_eq!(docs.len(), 0);
}
#[test]
fn test_group_by_module() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let groups = gen.group_by_module(&ast);
assert!(groups.is_empty());
}
#[test]
fn test_generate_index() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let index = gen.generate_index(&ast);
assert!(index.is_empty());
}
#[test]
fn test_resolve_links() {
let gen = DocGenerator::new();
let ast = Expr {
kind: ExprKind::Literal(Literal::Integer(42, None)),
span: Default::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = gen.resolve_links(&ast);
assert!(result.is_ok());
}
#[test]
fn test_doc_format_equality() {
assert_eq!(DocFormat::Markdown, DocFormat::Markdown);
assert_ne!(DocFormat::Markdown, DocFormat::Html);
}
#[test]
fn test_sort_order_equality() {
assert_eq!(SortOrder::Source, SortOrder::Source);
assert_ne!(SortOrder::Source, SortOrder::Alphabetical);
}
}