- Add filesystem-based module discovery via `discover_module_paths` - Decouple documentation coverage from Python import behavior - Ensure GriffeLoader receives a full module list instead of a single root - Make MkDocs renderer level-agnostic using global package detection - Emit `index.md` only for true packages, suppress `<package>.md` - Mirror full dotted module hierarchy into nested docs directories - Update CLI, exports, and type stubs to expose discovery helper - Align tests with filesystem-driven module coverage This fixes missing docs for submodules and removes invalid package `.md` files.
153 lines
3.8 KiB
Python
153 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Sequence, Optional
|
|
|
|
import click
|
|
|
|
from docforge.loader import GriffeLoader, discover_module_paths
|
|
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()
|
|
discovered_paths = discover_module_paths(
|
|
"docforge",
|
|
Path(r"C:\Users\vishe\WorkSpace\code\aetos\doc-forge")
|
|
)
|
|
project = loader.load_project(
|
|
discovered_paths,
|
|
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()
|