refactor: restructure CLI and improve documentation/typing
- Consolidated CLI commands into [build](cci:1://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/mkdocs/logic.py:48:0-58:46) and [serve](cci:1://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/commands.py:70:0-92:32) using `--mkdocs` and `--mcp` flags. - Separated CLI orchestration logic into [docforge/cli/mkdocs/logic.py](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/mkdocs/logic.py:0:0-0:0) and [docforge/cli/mcp/logic.py](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/mcp/logic.py:0:0-0:0). - Moved command definitions to [docforge/cli/commands.py](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/commands.py:0:0-0:0), making [main.py](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/main.py:0:0-0:0) a thin entry point. - Aligned [.pyi](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/docforge/cli/main.pyi:0:0-0:0) type stubs with [.py](cci:7://file:///c:/Users/vishe/WorkSpace/code/aetos/doc-forge/tests/conftest.py:0:0-0:0) implementations across the package. - Added missing docstrings to internal helper functions and core classes. - Restructured tests into `tests/mkdocs/` and `tests/mcp/`. - Updated navigation specification to reflect the new project structure.
This commit is contained in:
129
docforge/cli/commands.py
Normal file
129
docforge/cli/commands.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import click
|
||||
from pathlib import Path
|
||||
from typing import Sequence, Optional
|
||||
from docforge.loaders import GriffeLoader
|
||||
from docforge.cli.mkdocs import logic as mkdocs_logic
|
||||
from docforge.cli.mcp import logic as mcp_logic
|
||||
|
||||
@click.group()
|
||||
def cli() -> None:
|
||||
"""
|
||||
doc-forge CLI: A tool for introspecting Python projects and generating
|
||||
documentation.
|
||||
"""
|
||||
pass
|
||||
|
||||
@cli.command()
|
||||
@click.option("--mcp", is_flag=True, help="Build MCP resources")
|
||||
@click.option("--mkdocs", is_flag=True, help="Build MkDocs site")
|
||||
@click.option("--module", help="Python module to document")
|
||||
@click.option("--project-name", help="Project name override")
|
||||
# MkDocs specific
|
||||
@click.option("--site-name", help="MkDocs site name")
|
||||
@click.option("--docs-dir", type=click.Path(path_type=Path), default=Path("docs"), help="Directory for MD sources")
|
||||
@click.option("--nav", "nav_file", type=click.Path(path_type=Path), default=Path("docforge.nav.yml"), help="Nav spec path")
|
||||
@click.option("--template", type=click.Path(path_type=Path), help="MkDocs template path")
|
||||
@click.option("--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), help="Output config path")
|
||||
# MCP specific
|
||||
@click.option("--out-dir", type=click.Path(path_type=Path), default=Path("mcp_docs"), help="MCP output directory")
|
||||
def build(
|
||||
mcp: bool,
|
||||
mkdocs: bool,
|
||||
module: Optional[str],
|
||||
project_name: Optional[str],
|
||||
site_name: Optional[str],
|
||||
docs_dir: Path,
|
||||
nav_file: Path,
|
||||
template: Optional[Path],
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Build documentation (MkDocs site or MCP resources).
|
||||
"""
|
||||
if not mcp and not mkdocs:
|
||||
raise click.UsageError("Must specify either --mcp or --mkdocs")
|
||||
|
||||
if mkdocs:
|
||||
if not module:
|
||||
raise click.UsageError("--module is required for MkDocs build")
|
||||
if not site_name:
|
||||
site_name = module
|
||||
|
||||
click.echo(f"Generating MkDocs sources in {docs_dir}...")
|
||||
mkdocs_logic.generate_sources(module, project_name, docs_dir)
|
||||
|
||||
click.echo(f"Generating MkDocs config {mkdocs_yml}...")
|
||||
mkdocs_logic.generate_config(docs_dir, nav_file, template, mkdocs_yml, site_name)
|
||||
|
||||
click.echo("Running MkDocs build...")
|
||||
mkdocs_logic.build(mkdocs_yml)
|
||||
click.echo("MkDocs build completed.")
|
||||
|
||||
if mcp:
|
||||
if not module:
|
||||
raise click.UsageError("--module is required for MCP build")
|
||||
|
||||
click.echo(f"Generating MCP resources in {out_dir}...")
|
||||
mcp_logic.generate_resources(module, project_name, out_dir)
|
||||
click.echo("MCP build completed.")
|
||||
|
||||
@cli.command()
|
||||
@click.option("--mcp", is_flag=True, help="Serve MCP documentation")
|
||||
@click.option("--mkdocs", is_flag=True, help="Serve MkDocs site")
|
||||
@click.option("--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), help="MkDocs config path")
|
||||
@click.option("--out-dir", type=click.Path(path_type=Path), default=Path("mcp_docs"), help="MCP root directory")
|
||||
def serve(
|
||||
mcp: bool,
|
||||
mkdocs: bool,
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
) -> None:
|
||||
"""
|
||||
Serve documentation.
|
||||
"""
|
||||
if mcp and mkdocs:
|
||||
raise click.UsageError("Cannot specify both --mcp and --mkdocs")
|
||||
if not mcp and not mkdocs:
|
||||
raise click.UsageError("Must specify either --mcp or --mkdocs")
|
||||
|
||||
if mkdocs:
|
||||
mkdocs_logic.serve(mkdocs_yml)
|
||||
elif mcp:
|
||||
mcp_logic.serve(out_dir)
|
||||
|
||||
@cli.command()
|
||||
@click.option(
|
||||
"--modules",
|
||||
multiple=True,
|
||||
required=True,
|
||||
help="Python module import paths to introspect",
|
||||
)
|
||||
@click.option(
|
||||
"--project-name",
|
||||
help="Project name (defaults to first module)",
|
||||
)
|
||||
def tree(
|
||||
modules: Sequence[str],
|
||||
project_name: Optional[str],
|
||||
) -> None:
|
||||
"""
|
||||
Visualize the project structure.
|
||||
"""
|
||||
loader = GriffeLoader()
|
||||
project = loader.load_project(list(modules), project_name)
|
||||
|
||||
click.echo(project.name)
|
||||
|
||||
for module in project.get_all_modules():
|
||||
click.echo(f"├── {module.path}")
|
||||
for obj in module.get_all_objects():
|
||||
_print_object(obj, indent="│ ")
|
||||
|
||||
def _print_object(obj, indent: str) -> None:
|
||||
"""
|
||||
Recursive helper to print doc objects and their members to the console.
|
||||
"""
|
||||
click.echo(f"{indent}├── {obj.name}")
|
||||
for member in obj.get_all_members():
|
||||
_print_object(member, indent + "│ ")
|
||||
Reference in New Issue
Block a user