feat: major improvements — layout, cycles, integrations, usage examples, tests #1

Merged
dparmeev merged 15 commits from feature/improvements-v2 into main 2026-02-15 11:21:47 +03:00
9 changed files with 377 additions and 4 deletions
Showing only changes of commit b7d3e3e488 - Show all commits

View File

View File

@@ -325,10 +325,20 @@ fn generate_docs(model: &ProjectModel, out: &str) -> Result<()> {
// Create individual documentation files for modules and files
for (module_id, _module) in &model.modules {
let module_doc_path = modules_path.join(format!("{}.md", sanitize_filename(module_id)));
match renderer.render_module_md(model, module_id) {
Ok(module_content) => {
std::fs::write(&module_doc_path, module_content)
.map_err(|e| anyhow::anyhow!("Failed to create module doc {}: {}", module_doc_path.display(), e))?;
}
Err(e) => {
eprintln!("Warning: Failed to render module doc for {}: {}", module_id, e);
// Fallback to simple template
let module_content = format!("# Module: {}\n\nTODO: Add module documentation\n", module_id);
std::fs::write(&module_doc_path, module_content)
.map_err(|e| anyhow::anyhow!("Failed to create module doc {}: {}", module_doc_path.display(), e))?;
}
}
}
for (_file_id, file_doc) in &model.files {
let file_doc_path = files_path.join(format!("{}.md", sanitize_filename(&file_doc.path)));

View File

@@ -28,7 +28,9 @@ impl Renderer {
handlebars.register_template_string("architecture_md", Self::architecture_md_template())
.expect("Failed to register architecture_md template");
// TODO: Register other templates
// Register module documentation template
handlebars.register_template_string("module_md", Self::module_md_template())
.expect("Failed to register module_md template");
Self {
templates: handlebars,
@@ -151,6 +153,82 @@ impl Renderer {
"#
}
fn module_md_template() -> &'static str {
r#"# Module: {{{module_name}}}
{{{module_summary}}}
## Symbols
{{#each symbols}}
### {{{name}}}
{{{signature}}}
{{{docstring}}}
**Type:** {{{kind}}}
**Metrics:**
- Fan-in: {{{fan_in}}}
- Fan-out: {{{fan_out}}}
{{#if is_critical}}
- Critical: Yes
{{/if}}
{{/each}}
## Dependencies
### Imports
{{#each imports}}
- {{{this}}}
{{/each}}
### Outbound Modules
{{#each outbound_modules}}
- {{{this}}}
{{/each}}
### Inbound Modules
{{#each inbound_modules}}
- {{{this}}}
{{/each}}
## Integrations
{{#if has_db_integrations}}
### Database Integrations
{{#each db_symbols}}
- {{{this}}}
{{/each}}
{{/if}}
{{#if has_http_integrations}}
### HTTP/API Integrations
{{#each http_symbols}}
- {{{this}}}
{{/each}}
{{/if}}
{{#if has_queue_integrations}}
### Queue Integrations
{{#each queue_symbols}}
- {{{this}}}
{{/each}}
{{/if}}
## Usage Examples
{{#each usage_examples}}
```python
{{{this}}}
```
{{/each}}
"#
}
pub fn render_architecture_md(&self, model: &ProjectModel) -> Result<String, anyhow::Error> {
// Collect integration information
let mut db_integrations = Vec::new();
@@ -188,6 +266,72 @@ impl Renderer {
.map_err(|e| anyhow::anyhow!("Failed to render architecture.md: {}", e))
}
pub fn render_module_md(&self, model: &ProjectModel, module_id: &str) -> Result<String, anyhow::Error> {
// Find the module in the project model
let module = model.modules.get(module_id)
.ok_or_else(|| anyhow::anyhow!("Module {} not found", module_id))?;
// Collect symbols for this module
let mut symbols = Vec::new();
for symbol_id in &module.symbols {
if let Some(symbol) = model.symbols.get(symbol_id) {
symbols.push(serde_json::json!({
"name": symbol.qualname,
"signature": symbol.signature,
"docstring": symbol.docstring_first_line.as_deref().unwrap_or("No documentation available"),
"kind": format!("{:?}", symbol.kind),
"fan_in": symbol.metrics.fan_in,
"fan_out": symbol.metrics.fan_out,
"is_critical": symbol.metrics.is_critical,
}));
}
}
// Collect integration information for this module
let mut db_symbols = Vec::new();
let mut http_symbols = Vec::new();
let mut queue_symbols = Vec::new();
for symbol_id in &module.symbols {
if let Some(symbol) = model.symbols.get(symbol_id) {
if symbol.integrations_flags.db {
db_symbols.push(symbol.qualname.clone());
}
if symbol.integrations_flags.http {
http_symbols.push(symbol.qualname.clone());
}
if symbol.integrations_flags.queue {
queue_symbols.push(symbol.qualname.clone());
}
}
}
// Prepare usage examples (for now, just placeholders)
let usage_examples = vec![
"// Example usage of module functions\n// TODO: Add real usage examples based on module analysis".to_string()
];
// Prepare data for template
let data = serde_json::json!({
"module_name": module_id,
"module_summary": module.doc_summary.as_deref().unwrap_or("No summary available"),
"symbols": symbols,
"imports": model.files.get(&module.files[0]).map(|f| f.imports.clone()).unwrap_or_default(),
"outbound_modules": module.outbound_modules,
"inbound_modules": module.inbound_modules,
"has_db_integrations": !db_symbols.is_empty(),
"has_http_integrations": !http_symbols.is_empty(),
"has_queue_integrations": !queue_symbols.is_empty(),
"db_symbols": db_symbols,
"http_symbols": http_symbols,
"queue_symbols": queue_symbols,
"usage_examples": usage_examples,
});
self.templates.render("module_md", &data)
.map_err(|e| anyhow::anyhow!("Failed to render module.md: {}", e))
}
pub fn render_integrations_section(&self, model: &ProjectModel) -> Result<String, anyhow::Error> {
// Collect integration information
let mut db_integrations = Vec::new();

View File

@@ -0,0 +1,3 @@
# File: ../test-project/src/__init__.py
TODO: Add file documentation

View File

@@ -0,0 +1,3 @@
# File: ../test-project/src/core.py
TODO: Add file documentation

View File

@@ -0,0 +1,3 @@
# File: ../test-project/src/utils.py
TODO: Add file documentation

View File

@@ -0,0 +1,27 @@
# Module: ../test-project/src/__init__.py
No summary available
## Symbols
## Dependencies
### Imports
### Outbound Modules
### Inbound Modules
## Integrations
## Usage Examples
```python
// Example usage of module functions
// TODO: Add real usage examples based on module analysis
```

View File

@@ -0,0 +1,106 @@
# Module: ../test-project/src/core.py
No summary available
## Symbols
### DatabaseManager
class DatabaseManager
No documentation available
**Type:** Class
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### __init__
def __init__(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### connect
def connect(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### execute_query
def execute_query(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### fetch_external_data
def fetch_external_data(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### process_user_data
def process_user_data(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 1
## Dependencies
### Imports
- sqlite3
- requests
### Outbound Modules
### Inbound Modules
## Integrations
### Database Integrations
- DatabaseManager
- connect
### HTTP/API Integrations
- fetch_external_data
## Usage Examples
```python
// Example usage of module functions
// TODO: Add real usage examples based on module analysis
```

View File

@@ -0,0 +1,77 @@
# Module: ../test-project/src/utils.py
No summary available
## Symbols
### load_config
def load_config(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### save_config
def save_config(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### get_file_size
def get_file_size(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
### format_bytes
def format_bytes(...)
No documentation available
**Type:** Function
**Metrics:**
- Fan-in: 0
- Fan-out: 0
## Dependencies
### Imports
- json
- os
### Outbound Modules
### Inbound Modules
## Integrations
## Usage Examples
```python
// Example usage of module functions
// TODO: Add real usage examples based on module analysis
```