from __future__ import annotations from pathlib import Path from typing import Sequence, Optional import click from docforge.loader import GriffeLoader from docforge.renderers.mkdocs import MkDocsRenderer from docforge.cli.mkdocs import mkdocs_cmd @click.group() def cli() -> None: """doc-forge command-line interface.""" pass cli.add_command(mkdocs_cmd) # --------------------------------------------------------------------- # tree # --------------------------------------------------------------------- @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: """Show introspection tree.""" 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: click.echo(f"{indent}├── {obj.name}") for member in obj.get_all_members(): _print_object(member, indent + "│ ") # --------------------------------------------------------------------- # generate # --------------------------------------------------------------------- @cli.command() @click.option( "--modules", multiple=True, required=True, help="Python module import paths to document", ) @click.option( "--project-name", help="Project name (defaults to first module)", ) @click.option( "--docs-dir", type=click.Path(path_type=Path), default=Path("docs"), ) def generate( modules: Sequence[str], project_name: Optional[str], docs_dir: Path, ) -> None: """Generate documentation source files using MkDocs renderer.""" loader = GriffeLoader() project = loader.load_project(list(modules), project_name) renderer = MkDocsRenderer() renderer.generate_sources(project, docs_dir) click.echo(f"Documentation sources generated in {docs_dir}") # --------------------------------------------------------------------- # build # --------------------------------------------------------------------- @cli.command() @click.option( "--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), ) def build(mkdocs_yml: Path) -> None: """Build documentation using MkDocs.""" if not mkdocs_yml.exists(): raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}") from mkdocs.config import load_config from mkdocs.commands.build import build as mkdocs_build mkdocs_build(load_config(str(mkdocs_yml))) click.echo("MkDocs build completed") # --------------------------------------------------------------------- # serve # --------------------------------------------------------------------- @cli.command() @click.option( "--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), ) def serve(mkdocs_yml: Path) -> None: """Serve documentation using MkDocs.""" if not mkdocs_yml.exists(): raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}") from mkdocs.commands.serve import serve as mkdocs_serve mkdocs_serve(config_file=str(mkdocs_yml)) # --------------------------------------------------------------------- # entry point # --------------------------------------------------------------------- def main() -> None: cli() if __name__ == "__main__": main()