374 lines
11 KiB
Python
374 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
API Reference Builder
|
|
|
|
Generates markdown API documentation from code analysis results.
|
|
Supports Python, JavaScript/TypeScript, and C++.
|
|
|
|
Output Format:
|
|
- One .md file per analyzed source file
|
|
- Organized by: Classes → Methods, then standalone Functions
|
|
- Includes: Signatures, parameters, return types, docstrings
|
|
|
|
Usage:
|
|
from skill_seekers.cli.api_reference_builder import APIReferenceBuilder
|
|
|
|
builder = APIReferenceBuilder(code_analysis_results)
|
|
builder.build_reference(output_dir)
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
class APIReferenceBuilder:
|
|
"""
|
|
Builds markdown API reference from code analysis results.
|
|
|
|
Processes code analysis data and generates well-formatted markdown
|
|
documentation for each analyzed source file.
|
|
"""
|
|
|
|
def __init__(self, code_analysis: dict[str, Any]):
|
|
"""
|
|
Initialize builder with code analysis results.
|
|
|
|
Args:
|
|
code_analysis: Dictionary containing analyzed files and their code structures.
|
|
Expected format: {'files': [{'file': 'path', 'classes': [...], 'functions': [...]}]}
|
|
"""
|
|
self.code_analysis = code_analysis
|
|
self.files_data = code_analysis.get("files", [])
|
|
|
|
def build_reference(self, output_dir: Path) -> dict[str, Path]:
|
|
"""
|
|
Generate markdown files for each analyzed source file.
|
|
|
|
Args:
|
|
output_dir: Directory to save generated markdown files
|
|
|
|
Returns:
|
|
Dictionary mapping source file paths to generated markdown file paths
|
|
"""
|
|
output_dir = Path(output_dir)
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
generated_files = {}
|
|
|
|
for file_data in self.files_data:
|
|
source_file = file_data.get("file", "unknown")
|
|
language = file_data.get("language", "Unknown")
|
|
|
|
# Skip files with no analysis
|
|
if not file_data.get("classes") and not file_data.get("functions"):
|
|
continue
|
|
|
|
# Generate markdown content
|
|
markdown_content = self._generate_file_reference(file_data, source_file, language)
|
|
|
|
# Determine output filename
|
|
output_filename = self._get_output_filename(source_file)
|
|
output_path = output_dir / output_filename
|
|
|
|
# Write markdown file
|
|
output_path.write_text(markdown_content, encoding="utf-8")
|
|
generated_files[source_file] = output_path
|
|
|
|
return generated_files
|
|
|
|
def _get_output_filename(self, source_file: str) -> str:
|
|
"""
|
|
Generate output filename from source file path.
|
|
|
|
Args:
|
|
source_file: Path to source file
|
|
|
|
Returns:
|
|
Safe filename for markdown output
|
|
"""
|
|
# Get base filename
|
|
basename = Path(source_file).name
|
|
|
|
# Replace extension with .md
|
|
name_without_ext = basename.rsplit(".", 1)[0] if "." in basename else basename
|
|
return f"{name_without_ext}.md"
|
|
|
|
def _generate_file_reference(
|
|
self, file_data: dict[str, Any], source_file: str, language: str
|
|
) -> str:
|
|
"""
|
|
Generate complete markdown reference for a single file.
|
|
|
|
Args:
|
|
file_data: Analysis data for the file
|
|
source_file: Path to source file
|
|
language: Programming language
|
|
|
|
Returns:
|
|
Complete markdown content
|
|
"""
|
|
lines = []
|
|
|
|
# Header
|
|
filename = Path(source_file).name
|
|
lines.append(f"# API Reference: {filename}\n")
|
|
lines.append(f"**Language**: {language}\n")
|
|
lines.append(f"**Source**: `{source_file}`\n")
|
|
lines.append("---\n")
|
|
|
|
# Classes section
|
|
classes = file_data.get("classes", [])
|
|
if classes:
|
|
lines.append("## Classes\n")
|
|
for cls in classes:
|
|
lines.append(self._format_class(cls))
|
|
lines.append("\n")
|
|
|
|
# Functions section
|
|
functions = file_data.get("functions", [])
|
|
if functions:
|
|
lines.append("## Functions\n")
|
|
for func in functions:
|
|
lines.append(self._format_function(func))
|
|
lines.append("\n")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def _format_class(self, class_sig: dict[str, Any]) -> str:
|
|
"""
|
|
Format class signature as markdown.
|
|
|
|
Args:
|
|
class_sig: Class signature dictionary
|
|
|
|
Returns:
|
|
Formatted markdown for class
|
|
"""
|
|
lines = []
|
|
|
|
# Class name
|
|
class_name = class_sig.get("name", "Unknown")
|
|
lines.append(f"### {class_name}\n")
|
|
|
|
# Docstring
|
|
docstring = class_sig.get("docstring")
|
|
if docstring:
|
|
lines.append(f"{docstring}\n")
|
|
|
|
# Inheritance
|
|
base_classes = class_sig.get("base_classes", [])
|
|
if base_classes:
|
|
bases_str = ", ".join(base_classes)
|
|
lines.append(f"**Inherits from**: {bases_str}\n")
|
|
else:
|
|
lines.append("**Inherits from**: (none)\n")
|
|
|
|
# Methods
|
|
methods = class_sig.get("methods", [])
|
|
if methods:
|
|
lines.append("#### Methods\n")
|
|
for method in methods:
|
|
lines.append(self._format_method(method))
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def _format_method(self, method_sig: dict[str, Any]) -> str:
|
|
"""
|
|
Format method signature as markdown.
|
|
|
|
Args:
|
|
method_sig: Method signature dictionary
|
|
|
|
Returns:
|
|
Formatted markdown for method
|
|
"""
|
|
lines = []
|
|
|
|
# Method signature
|
|
signature = self._build_signature(method_sig)
|
|
lines.append(f"##### {signature}\n")
|
|
|
|
# Docstring
|
|
docstring = method_sig.get("docstring")
|
|
if docstring:
|
|
lines.append(f"{docstring}\n")
|
|
|
|
# Decorators
|
|
decorators = method_sig.get("decorators", [])
|
|
if decorators:
|
|
dec_str = ", ".join(f"`@{d}`" for d in decorators)
|
|
lines.append(f"**Decorators**: {dec_str}\n")
|
|
|
|
# Parameters table
|
|
params = method_sig.get("parameters", [])
|
|
if params:
|
|
lines.append(self._format_parameters(params))
|
|
lines.append("")
|
|
|
|
# Return type
|
|
return_type = method_sig.get("return_type")
|
|
if return_type:
|
|
lines.append(f"**Returns**: `{return_type}`\n")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def _format_function(self, func_sig: dict[str, Any]) -> str:
|
|
"""
|
|
Format function signature as markdown.
|
|
|
|
Args:
|
|
func_sig: Function signature dictionary
|
|
|
|
Returns:
|
|
Formatted markdown for function
|
|
"""
|
|
lines = []
|
|
|
|
# Function signature
|
|
signature = self._build_signature(func_sig)
|
|
lines.append(f"### {signature}\n")
|
|
|
|
# Async indicator
|
|
if func_sig.get("is_async"):
|
|
lines.append("**Async function**\n")
|
|
|
|
# Docstring
|
|
docstring = func_sig.get("docstring")
|
|
if docstring:
|
|
lines.append(f"{docstring}\n")
|
|
|
|
# Parameters table
|
|
params = func_sig.get("parameters", [])
|
|
if params:
|
|
lines.append(self._format_parameters(params))
|
|
lines.append("")
|
|
|
|
# Return type
|
|
return_type = func_sig.get("return_type")
|
|
if return_type:
|
|
lines.append(f"**Returns**: `{return_type}`\n")
|
|
else:
|
|
lines.append("**Returns**: (none)\n")
|
|
|
|
return "\n".join(lines)
|
|
|
|
def _build_signature(self, sig: dict[str, Any]) -> str:
|
|
"""
|
|
Build function/method signature string.
|
|
|
|
Args:
|
|
sig: Signature dictionary
|
|
|
|
Returns:
|
|
Formatted signature string
|
|
"""
|
|
name = sig.get("name", "unknown")
|
|
params = sig.get("parameters", [])
|
|
return_type = sig.get("return_type")
|
|
|
|
# Build parameter list
|
|
param_strs = []
|
|
for param in params:
|
|
param_str = param.get("name", "")
|
|
|
|
# Add type hint if available
|
|
type_hint = param.get("type_hint")
|
|
if type_hint:
|
|
param_str += f": {type_hint}"
|
|
|
|
# Add default value if available
|
|
default = param.get("default")
|
|
if default:
|
|
param_str += f" = {default}"
|
|
|
|
param_strs.append(param_str)
|
|
|
|
params_str = ", ".join(param_strs)
|
|
|
|
# Build full signature
|
|
if return_type:
|
|
return f"{name}({params_str}) → {return_type}"
|
|
else:
|
|
return f"{name}({params_str})"
|
|
|
|
def _format_parameters(self, params: list[dict]) -> str:
|
|
"""
|
|
Format parameter list as markdown table.
|
|
|
|
Args:
|
|
params: List of parameter dictionaries
|
|
|
|
Returns:
|
|
Formatted markdown table
|
|
"""
|
|
if not params:
|
|
return ""
|
|
|
|
lines = []
|
|
lines.append("**Parameters**:")
|
|
lines.append("")
|
|
lines.append("| Name | Type | Default | Description |")
|
|
lines.append("|------|------|---------|-------------|")
|
|
|
|
for param in params:
|
|
name = param.get("name", "-")
|
|
type_hint = param.get("type_hint", "-")
|
|
default = param.get("default")
|
|
|
|
# Show "-" for parameters without defaults
|
|
default_str = default if default is not None else "-"
|
|
|
|
# For description, use empty for now (would need JSDoc/docstring parsing)
|
|
description = "-"
|
|
|
|
lines.append(f"| {name} | {type_hint} | {default_str} | {description} |")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main():
|
|
"""
|
|
Command-line interface for API reference generation.
|
|
|
|
Reads code analysis JSON and generates markdown API documentation.
|
|
"""
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate API reference from code analysis results"
|
|
)
|
|
|
|
parser.add_argument("input_file", help="Code analysis JSON file")
|
|
parser.add_argument("output_dir", help="Output directory for markdown files")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Read code analysis
|
|
input_path = Path(args.input_file)
|
|
if not input_path.exists():
|
|
print(f"Error: Input file not found: {input_path}")
|
|
return 1
|
|
|
|
with open(input_path, encoding="utf-8") as f:
|
|
code_analysis = json.load(f)
|
|
|
|
# Build API reference
|
|
builder = APIReferenceBuilder(code_analysis)
|
|
generated_files = builder.build_reference(Path(args.output_dir))
|
|
|
|
# Report results
|
|
print(f"✅ Generated {len(generated_files)} API reference files")
|
|
print(f"📁 Output directory: {args.output_dir}")
|
|
for source, output in generated_files.items():
|
|
print(f" • {output.name} (from {Path(source).name})")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
sys.exit(main())
|