from pathlib import Path from importlib import resources import click import yaml from docforge.loaders import GriffeLoader, discover_module_paths from docforge.renderers import MkDocsRenderer from docforge.nav import load_nav_spec, resolve_nav, MkDocsNavEmitter def generate_sources(module: str, project_name: str | None, docs_dir: Path) -> None: """ Generate Markdown source files for the specified module. Args: module: The dotted path of the primary module to document. project_name: Optional override for the project name. docs_dir: Directory where the generated Markdown files will be written. """ loader = GriffeLoader() discovered_paths = discover_module_paths(module) project = loader.load_project(discovered_paths, project_name) renderer = MkDocsRenderer() renderer.generate_sources(project, docs_dir) def generate_config(docs_dir: Path, nav_file: Path, template: Path | None, out: Path, site_name: str) -> None: """ Generate an mkdocs.yml configuration file. Args: docs_dir: Path to the directory containing documentation Markdown files. nav_file: Path to the docforge.nav.yml specification. template: Optional path to an mkdocs.yml template (overrides built-in). out: Path where the final mkdocs.yml will be written. site_name: The display name for the documentation site. """ if not nav_file.exists(): raise click.FileError(str(nav_file), hint="Nav spec not found") spec = load_nav_spec(nav_file) resolved = resolve_nav(spec, docs_dir) nav_block = MkDocsNavEmitter().emit(resolved) # Load template if template is not None: if not template.exists(): raise click.FileError(str(template), hint="Template not found") data = yaml.safe_load(template.read_text(encoding="utf-8")) else: text = ( resources.files("docforge.templates") .joinpath("mkdocs.sample.yml") .read_text(encoding="utf-8") ) data = yaml.safe_load(text) data["site_name"] = site_name data["nav"] = nav_block out.write_text(yaml.safe_dump(data, sort_keys=False), encoding="utf-8") def build(mkdocs_yml: Path) -> None: """ Build the documentation site using MkDocs. Args: mkdocs_yml: Path to the mkdocs.yml configuration file. """ 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))) def serve(mkdocs_yml: Path) -> None: """ Serve the documentation site with live-reload using MkDocs. Args: mkdocs_yml: Path to the mkdocs.yml configuration file. """ 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))