from pathlib import Path from importlib import resources import click import yaml from docforge.nav import load_nav_spec from docforge.nav import resolve_nav from docforge.nav import MkDocsNavEmitter def _load_template(template: Path | None) -> dict: if template is not None: if not template.exists(): raise click.FileError(str(template), hint="Template not found") return yaml.safe_load(template.read_text(encoding="utf-8")) # Load built-in default text = ( resources.files("docforge.templates") .joinpath("mkdocs.sample.yml") .read_text(encoding="utf-8") ) return yaml.safe_load(text) @click.command("mkdocs") @click.option( "--docs-dir", type=click.Path(path_type=Path), default=Path("docs"), ) @click.option( "--nav", "nav_file", type=click.Path(path_type=Path), default=Path("docforge.nav.yml"), ) @click.option( "--template", type=click.Path(path_type=Path), default=None, help="Override the built-in mkdocs template", ) @click.option( "--out", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), ) def mkdocs_cmd( docs_dir: Path, nav_file: Path, template: Path | None, out: Path, ) -> None: """Generate mkdocs.yml from nav spec and template.""" if not nav_file.exists(): raise click.FileError(str(nav_file), hint="Nav spec not found") # Load nav spec spec = load_nav_spec(nav_file) # Resolve nav resolved = resolve_nav(spec, docs_dir) # Emit mkdocs nav nav_block = MkDocsNavEmitter().emit(resolved) # Load template (user or built-in) data = _load_template(template) # Inject nav data["nav"] = nav_block # Write output out.write_text( yaml.safe_dump(data, sort_keys=False), encoding="utf-8", ) click.echo(f"mkdocs.yml written to {out}")