feat: build each doc kind with its own MkDocs config and site
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -53,6 +53,7 @@ test-results/
|
||||
site/
|
||||
docs/_site/
|
||||
docs/build/
|
||||
mkdocs.yml
|
||||
|
||||
# =========================
|
||||
# MkDocs / Sphinx output
|
||||
|
||||
44
README.md
44
README.md
@@ -23,41 +23,49 @@ pip install doc-forge
|
||||
|
||||
# CLI usage
|
||||
|
||||
## Generate an MkDocs site from a Python package:
|
||||
Each site kind (`lib`, `api`, `wiki`) is built independently into `site/{kind}`.
|
||||
|
||||
## Build the library reference from a Python package:
|
||||
|
||||
```bash
|
||||
doc-forge build --mkdocs --module my_package
|
||||
```
|
||||
|
||||
## Build the API reference from an OpenAPI spec:
|
||||
|
||||
```bash
|
||||
doc-forge build --api --openapi-spec spec.json
|
||||
```
|
||||
|
||||
## Build the hand-written wiki:
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --site-name my_package
|
||||
```
|
||||
|
||||
## Generate MCP JSON documentation:
|
||||
|
||||
```bash
|
||||
doc-forge build --mcp --module my_package
|
||||
```
|
||||
|
||||
|
||||
## Generate MkDocs site and MCP JSON documentation:
|
||||
## Build several kinds in one pass:
|
||||
|
||||
```bash
|
||||
doc-forge build --mcp --mkdocs --module my_package
|
||||
doc-forge build --mcp --mkdocs --wiki --module my_package
|
||||
```
|
||||
|
||||
## Include a hand-written wiki in the MkDocs site:
|
||||
Each enabled kind gets its own MkDocs config (`docs/mkdocs.{lib,api,wiki}.yml`)
|
||||
and its own site under `site/`.
|
||||
|
||||
## Serve a site locally:
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --mkdocs --module my_package
|
||||
```
|
||||
|
||||
## Build wiki pages only (no module required):
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --site-name my_package
|
||||
```
|
||||
|
||||
## Serve MkDocs locally:
|
||||
|
||||
```bash
|
||||
doc-forge serve --mkdocs --module my_package
|
||||
doc-forge serve --wiki # preview from docs/mkdocs.wiki.yml
|
||||
doc-forge serve --lib
|
||||
doc-forge serve --api
|
||||
# or any config directly:
|
||||
doc-forge serve --mkdocs --mkdocs-yml docs/mkdocs.wiki.yml
|
||||
```
|
||||
|
||||
## Serve MCP locally:
|
||||
|
||||
@@ -22,41 +22,49 @@ pip install doc-forge
|
||||
|
||||
# CLI usage
|
||||
|
||||
## Generate an MkDocs site from a Python package:
|
||||
Each site kind (`lib`, `api`, `wiki`) is built independently into `site/{kind}`.
|
||||
|
||||
## Build the library reference from a Python package:
|
||||
|
||||
```bash
|
||||
doc-forge build --mkdocs --module my_package
|
||||
```
|
||||
|
||||
## Build the API reference from an OpenAPI spec:
|
||||
|
||||
```bash
|
||||
doc-forge build --api --openapi-spec spec.json
|
||||
```
|
||||
|
||||
## Build the hand-written wiki:
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --site-name my_package
|
||||
```
|
||||
|
||||
## Generate MCP JSON documentation:
|
||||
|
||||
```bash
|
||||
doc-forge build --mcp --module my_package
|
||||
```
|
||||
|
||||
|
||||
## Generate MkDocs site and MCP JSON documentation:
|
||||
## Build several kinds in one pass:
|
||||
|
||||
```bash
|
||||
doc-forge build --mcp --mkdocs --module my_package
|
||||
doc-forge build --mcp --mkdocs --wiki --module my_package
|
||||
```
|
||||
|
||||
## Include a hand-written wiki in the MkDocs site:
|
||||
Each enabled kind gets its own MkDocs config (`docs/mkdocs.{lib,api,wiki}.yml`)
|
||||
and its own site under `site/`.
|
||||
|
||||
## Serve a site locally:
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --mkdocs --module my_package
|
||||
```
|
||||
|
||||
## Build wiki pages only (no module required):
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --site-name my_package
|
||||
```
|
||||
|
||||
## Serve MkDocs locally:
|
||||
|
||||
```bash
|
||||
doc-forge serve --mkdocs --module my_package
|
||||
doc-forge serve --wiki # preview from docs/mkdocs.wiki.yml
|
||||
doc-forge serve --lib
|
||||
doc-forge serve --api
|
||||
# or any config directly:
|
||||
doc-forge serve --mkdocs --mkdocs-yml docs/mkdocs.wiki.yml
|
||||
```
|
||||
|
||||
## Serve MCP locally:
|
||||
|
||||
@@ -9,12 +9,14 @@ Provides the CLI structure using Click, including build, serve, and tree command
|
||||
|
||||
Notes:
|
||||
- The `build` command validates requested modes before generating anything.
|
||||
- `--mkdocs`, `--api`, and `--wiki` share a single MkDocs build; `--mcp`
|
||||
generates a machine-readable bundle independently.
|
||||
- `--mkdocs`, `--api`, and `--wiki` each emit their own MkDocs config and
|
||||
build (`docs/mkdocs.{kind}.yml` into `site/{kind}`); `--mcp` generates a
|
||||
machine-readable bundle independently.
|
||||
|
||||
---
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
@@ -37,10 +39,10 @@ def cli() -> None:
|
||||
|
||||
@cli.command()
|
||||
@click.option("--mcp", is_flag=True, help="Build MCP resources")
|
||||
@click.option("--mkdocs", is_flag=True, help="Build MkDocs site")
|
||||
@click.option("--mkdocs", is_flag=True, help="Build the lib MkDocs site")
|
||||
@click.option("--api", is_flag=True, help="Build API docs from an OpenAPI spec")
|
||||
@click.option(
|
||||
"--wiki", is_flag=True, help="Include a hand-written wiki in the MkDocs site"
|
||||
"--wiki", is_flag=True, help="Build a hand-written wiki as its own MkDocs site"
|
||||
)
|
||||
@click.option(
|
||||
"--module-is-source",
|
||||
@@ -54,7 +56,7 @@ def cli() -> None:
|
||||
help="Path to the OpenAPI JSON specification",
|
||||
)
|
||||
@click.option("--project-name", help="Project name override")
|
||||
@click.option("--site-name", help="MkDocs site name")
|
||||
@click.option("--site-name", help="MkDocs site name for lib and wiki sites")
|
||||
@click.option(
|
||||
"--docs-dir",
|
||||
type=click.Path(path_type=Path),
|
||||
@@ -65,7 +67,7 @@ def cli() -> None:
|
||||
"--wiki-dir",
|
||||
type=click.Path(path_type=Path),
|
||||
default=Path("docs/wiki"),
|
||||
help="Hand-written wiki directory included in the MkDocs site",
|
||||
help="Hand-written wiki directory built as its own MkDocs site",
|
||||
)
|
||||
@click.option(
|
||||
"--nav",
|
||||
@@ -77,12 +79,6 @@ def cli() -> None:
|
||||
@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",
|
||||
)
|
||||
@click.option(
|
||||
"--out-dir",
|
||||
type=click.Path(path_type=Path),
|
||||
@@ -103,7 +99,6 @@ def build(
|
||||
wiki_dir: Path,
|
||||
nav_file: Path,
|
||||
template: Path | None,
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -111,33 +106,36 @@ def build(
|
||||
|
||||
This command runs the full documentation pipeline: it loads Python
|
||||
modules, generates renderer-specific documentation sources, and
|
||||
optionally builds or serves the final output.
|
||||
optionally builds the final output.
|
||||
|
||||
Depending on the selected options, the build can target:
|
||||
|
||||
- MkDocs static documentation sites for library reference docs
|
||||
- Swagger-enabled API docs generated from an OpenAPI spec
|
||||
- Hand-written wiki pages included in the MkDocs site
|
||||
- MCP structured documentation resources
|
||||
- A lib MkDocs site (`--mkdocs`) for library reference docs
|
||||
- A swagger-enabled API MkDocs site (`--api`) built from an OpenAPI spec
|
||||
- A wiki MkDocs site (`--wiki`) built from hand-written markdown
|
||||
- MCP structured documentation resources (`--mcp`)
|
||||
|
||||
Each enabled site kind produces its own MkDocs configuration
|
||||
(`docs/mkdocs.{kind}.yml`) and its own build (`site/{kind}`).
|
||||
|
||||
Notes:
|
||||
- At least one of `--mcp`, `--mkdocs`, `--wiki`, or `--api` must be
|
||||
provided.
|
||||
- `--mkdocs`, `--api`, and `--wiki` are combined into a single MkDocs
|
||||
build, while `--mcp` emits a machine-readable bundle.
|
||||
- `--mkdocs`, `--api`, and `--wiki` emit independent MkDocs builds,
|
||||
while `--mcp` emits a machine-readable bundle.
|
||||
|
||||
Args:
|
||||
mcp (bool):
|
||||
Enable MCP documentation generation.
|
||||
|
||||
mkdocs (bool):
|
||||
Enable MkDocs library documentation generation.
|
||||
Enable the lib MkDocs documentation generation.
|
||||
|
||||
api (bool):
|
||||
Enable API documentation generation from an OpenAPI spec.
|
||||
|
||||
wiki (bool):
|
||||
Include a hand-written wiki directory in the MkDocs site.
|
||||
Build a hand-written wiki directory as its own MkDocs site.
|
||||
|
||||
module_is_source (bool):
|
||||
Treat the specified module directory as the project root.
|
||||
@@ -152,11 +150,10 @@ def build(
|
||||
Optional override for the project name.
|
||||
|
||||
site_name (str | None):
|
||||
Display name for the MkDocs site.
|
||||
Display name for the lib and wiki MkDocs sites.
|
||||
|
||||
docs_dir (Path):
|
||||
Shared documentation root used as the MkDocs ``docs_dir``.
|
||||
|
||||
Shared documentation root used for generated sources.
|
||||
wiki_dir (Path):
|
||||
Directory containing hand-written wiki markdown files.
|
||||
|
||||
@@ -166,9 +163,6 @@ def build(
|
||||
template (Path | None):
|
||||
Optional custom MkDocs configuration template.
|
||||
|
||||
mkdocs_yml (Path):
|
||||
Output path for the generated MkDocs configuration.
|
||||
|
||||
out_dir (Path):
|
||||
Output directory for generated MCP resources.
|
||||
|
||||
@@ -188,18 +182,18 @@ def build(
|
||||
"the OpenAPI spec provides the site name"
|
||||
)
|
||||
|
||||
if (mkdocs or mcp) and not module:
|
||||
raise click.UsageError(
|
||||
"--module is required for MkDocs build"
|
||||
if mkdocs
|
||||
else "--module is required for MCP build"
|
||||
)
|
||||
if mkdocs and not module:
|
||||
raise click.UsageError("--module is required for MkDocs build")
|
||||
if mcp and not module:
|
||||
raise click.UsageError("--module is required for MCP build")
|
||||
|
||||
spec: dict | None = None
|
||||
if api:
|
||||
spec = api_utils.load_openapi_spec(openapi_spec)
|
||||
|
||||
kinds: list[str] = []
|
||||
if mkdocs:
|
||||
kinds.append("lib")
|
||||
lib_dir = docs_dir / "lib"
|
||||
click.echo(f"Generating MkDocs sources in {lib_dir}...")
|
||||
mkdocs_utils.generate_sources(
|
||||
@@ -207,54 +201,64 @@ def build(
|
||||
lib_dir,
|
||||
project_name,
|
||||
module_is_source,
|
||||
readme_dir=mkdocs_yml.parent,
|
||||
readme_dir=Path(".").resolve(),
|
||||
)
|
||||
|
||||
if api:
|
||||
kinds.append("api")
|
||||
api_dir = docs_dir / "api"
|
||||
click.echo(f"Generating API sources in {api_dir}...")
|
||||
api_utils.generate_api_sources(spec, api_dir)
|
||||
|
||||
if mkdocs or api or wiki:
|
||||
modes: list[str] = []
|
||||
if mkdocs:
|
||||
modes.append("lib")
|
||||
if wiki:
|
||||
kinds.append("wiki")
|
||||
|
||||
if kinds:
|
||||
api_metadata: api_utils.OpenAPIMetadata | None = None
|
||||
if api:
|
||||
modes.append("api")
|
||||
if wiki:
|
||||
modes.append("wiki")
|
||||
api_metadata = api_utils.derive_metadata(spec)
|
||||
theme_icon = mkdocs_utils.load_spec_icon(nav_file)
|
||||
|
||||
site_description: str | None = None
|
||||
site_author: str | None = None
|
||||
effective_site_name = site_name or module or Path.cwd().name
|
||||
config_paths: list[Path] = []
|
||||
for kind in kinds:
|
||||
kind_root = wiki_dir if kind == "wiki" else docs_dir / kind
|
||||
|
||||
if api:
|
||||
metadata = api_utils.derive_metadata(spec)
|
||||
effective_site_name = metadata.site_name
|
||||
site_description = metadata.site_description
|
||||
site_author = metadata.site_author
|
||||
site_name_kind = site_name or module or Path.cwd().name
|
||||
site_description: str | None = None
|
||||
site_author: str | None = None
|
||||
if kind == "api" and api_metadata:
|
||||
site_name_kind = api_metadata.site_name
|
||||
site_description = api_metadata.site_description
|
||||
site_author = api_metadata.site_author
|
||||
|
||||
click.echo(f"Generating MkDocs config {mkdocs_yml}...")
|
||||
mkdocs_utils.generate_config(
|
||||
docs_dir,
|
||||
nav_file,
|
||||
template,
|
||||
mkdocs_yml,
|
||||
effective_site_name,
|
||||
modes=modes,
|
||||
site_description=site_description,
|
||||
site_author=site_author,
|
||||
wiki_dir=wiki_dir if wiki else None,
|
||||
)
|
||||
if kind == "lib":
|
||||
nav_block, _kind_icon = mkdocs_utils.build_lib_nav(nav_file, docs_dir)
|
||||
elif kind == "wiki":
|
||||
nav_block = mkdocs_utils.build_wiki_nav_block(wiki_dir)
|
||||
else:
|
||||
nav_block = [{"API Reference": "index.md"}]
|
||||
|
||||
click.echo("Running MkDocs build...")
|
||||
mkdocs_utils.build(mkdocs_yml)
|
||||
click.echo("MkDocs build completed.")
|
||||
out = docs_dir / f"mkdocs.{kind}.yml"
|
||||
click.echo(f"Generating MkDocs config {out}...")
|
||||
mkdocs_utils.generate_site_config(
|
||||
kind,
|
||||
kind_root,
|
||||
nav_block,
|
||||
out,
|
||||
site_name_kind,
|
||||
Path(os.path.relpath(kind_root, docs_dir)).as_posix(),
|
||||
Path(os.path.relpath(Path.cwd() / "site" / kind, docs_dir)).as_posix(),
|
||||
template=template,
|
||||
site_description=site_description,
|
||||
site_author=site_author,
|
||||
theme_icon=theme_icon,
|
||||
)
|
||||
config_paths.append(out)
|
||||
|
||||
click.echo("Running MkDocs builds...")
|
||||
mkdocs_utils.build_configs(config_paths)
|
||||
|
||||
if mcp:
|
||||
if not module:
|
||||
raise click.UsageError("--module is required for MCP build")
|
||||
|
||||
click.echo(f"Generating MCP resources in {out_dir}...")
|
||||
mcp_utils.generate_resources(module, project_name, out_dir)
|
||||
click.echo("MCP build completed.")
|
||||
@@ -262,12 +266,15 @@ def build(
|
||||
|
||||
@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", is_flag=True, help="Serve an MkDocs site from --mkdocs-yml")
|
||||
@click.option("--lib", is_flag=True, help="Serve the lib MkDocs site")
|
||||
@click.option("--api", is_flag=True, help="Serve the API MkDocs site")
|
||||
@click.option("--wiki", is_flag=True, help="Serve the wiki MkDocs site")
|
||||
@click.option("--module", help="Python module to serve")
|
||||
@click.option(
|
||||
"--mkdocs-yml",
|
||||
type=click.Path(path_type=Path),
|
||||
default=Path("mkdocs.yml"),
|
||||
default=Path("docs/mkdocs.wiki.yml"),
|
||||
help="MkDocs config path",
|
||||
)
|
||||
@click.option(
|
||||
@@ -279,6 +286,9 @@ def build(
|
||||
def serve(
|
||||
mcp: bool,
|
||||
mkdocs: bool,
|
||||
lib: bool,
|
||||
api: bool,
|
||||
wiki: bool,
|
||||
module: str | None,
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
@@ -288,15 +298,28 @@ def serve(
|
||||
|
||||
Depending on the selected mode, this command starts either:
|
||||
|
||||
- A MkDocs development server for browsing documentation
|
||||
- A MkDocs development server for browsing a site, or
|
||||
- An MCP server exposing structured documentation resources
|
||||
|
||||
The kind flags (`--lib`, `--api`, `--wiki`) select the generated
|
||||
per-kind config (`docs/mkdocs.{kind}.yml`); `--mkdocs` serves the config
|
||||
passed via `--mkdocs-yml`.
|
||||
|
||||
Args:
|
||||
mcp (bool):
|
||||
Serve documentation using the MCP server.
|
||||
|
||||
mkdocs (bool):
|
||||
Serve the MkDocs development site.
|
||||
Serve the MkDocs development site from ``--mkdocs-yml``.
|
||||
|
||||
lib (bool):
|
||||
Serve the lib MkDocs site.
|
||||
|
||||
api (bool):
|
||||
Serve the API MkDocs site.
|
||||
|
||||
wiki (bool):
|
||||
Serve the wiki MkDocs site.
|
||||
|
||||
module (str | None):
|
||||
Python module import path to serve via MCP.
|
||||
@@ -311,17 +334,37 @@ def serve(
|
||||
click.UsageError:
|
||||
If invalid or conflicting options are provided.
|
||||
"""
|
||||
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 mcp and not module:
|
||||
raise click.UsageError("--module is required for MCP serve")
|
||||
selected = [
|
||||
name
|
||||
for name, enabled in (
|
||||
("mcp", mcp),
|
||||
("mkdocs", mkdocs),
|
||||
("lib", lib),
|
||||
("api", api),
|
||||
("wiki", wiki),
|
||||
)
|
||||
if enabled
|
||||
]
|
||||
if len(selected) != 1:
|
||||
raise click.UsageError(
|
||||
"Must specify exactly one of --mcp, --mkdocs, --lib, --api, --wiki"
|
||||
)
|
||||
|
||||
if mkdocs:
|
||||
mkdocs_utils.serve(mkdocs_yml)
|
||||
elif mcp:
|
||||
if mcp:
|
||||
if not module:
|
||||
raise click.UsageError("--module is required for MCP serve")
|
||||
mcp_utils.serve(module, out_dir)
|
||||
return
|
||||
|
||||
config = mkdocs_yml
|
||||
if lib:
|
||||
config = Path("docs/mkdocs.lib.yml")
|
||||
elif api:
|
||||
config = Path("docs/mkdocs.api.yml")
|
||||
elif wiki:
|
||||
config = Path("docs/mkdocs.wiki.yml")
|
||||
|
||||
mkdocs_utils.serve(config)
|
||||
|
||||
|
||||
@cli.command()
|
||||
|
||||
@@ -20,12 +20,14 @@ def build(
|
||||
wiki_dir: Path,
|
||||
nav_file: Path,
|
||||
template: Path | None,
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
) -> None: ...
|
||||
def serve(
|
||||
mcp: bool,
|
||||
mkdocs: bool,
|
||||
lib: bool,
|
||||
api: bool,
|
||||
wiki: bool,
|
||||
module: str | None,
|
||||
mkdocs_yml: Path,
|
||||
out_dir: Path,
|
||||
|
||||
@@ -6,17 +6,19 @@ Utilities for working with MkDocs in the doc-forge CLI.
|
||||
---
|
||||
|
||||
Notes:
|
||||
- A single generated `mkdocs.yml` serves lib, api, and wiki content with
|
||||
merged navigation. Wiki navigation, when enabled, precedes every other
|
||||
group and its `index.md` becomes the site `Home`.
|
||||
- A separate `mkdocs.{kind}.yml` configuration and build is emitted per
|
||||
enabled kind (lib, api, wiki), each scoped to its own `docs_dir` and
|
||||
written into its own `site_dir` (`site/lib`, `site/api`, `site/wiki`).
|
||||
- Navigation blocks are re-rooted per kind: the wiki navigation drops its
|
||||
leading `wiki/` scope and the resolved nav spec drops its `lib/` scope.
|
||||
|
||||
---
|
||||
"""
|
||||
|
||||
import os
|
||||
from collections.abc import Iterable
|
||||
from importlib import resources
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
|
||||
import click
|
||||
import yaml
|
||||
@@ -83,53 +85,171 @@ def generate_sources(
|
||||
)
|
||||
|
||||
|
||||
def generate_config(
|
||||
docs_dir: Path,
|
||||
def build_lib_nav(
|
||||
nav_file: Path,
|
||||
template: Path | None,
|
||||
out: Path,
|
||||
site_name: str,
|
||||
modes: Iterable[str] | None = None,
|
||||
site_description: str | None = None,
|
||||
site_author: str | None = None,
|
||||
wiki_dir: Path | None = None,
|
||||
) -> None:
|
||||
docs_root: Path,
|
||||
) -> tuple[list[dict[str, Any]], dict[str, str] | None]:
|
||||
"""
|
||||
Generate an `mkdocs.yml` configuration file.
|
||||
Build the re-rooted navigation block for a lib site.
|
||||
|
||||
The configuration is created by combining a template configuration
|
||||
with a navigation structure derived from the docforge navigation
|
||||
specification (and, when a wiki directory is provided, from the wiki
|
||||
file structure).
|
||||
|
||||
The ``docs_dir`` is always written relative to the MkDocs root and is
|
||||
expected to be the shared documentation parent (for example ``docs``),
|
||||
with generated sources nested under ``lib/`` or ``api/`` subdirectories
|
||||
and hand-written wiki content under a ``wiki/`` subdirectory.
|
||||
The navigation specification is resolved against the shared documentation
|
||||
root and every resulting path is re-rooted relative to the ``lib``
|
||||
subdirectory by stripping its leading ``lib/`` scope component.
|
||||
|
||||
Args:
|
||||
docs_dir (Path):
|
||||
Shared documentation root used as the MkDocs ``docs_dir``.
|
||||
|
||||
nav_file (Path):
|
||||
Path to the `docforge.nav.yml` navigation specification.
|
||||
|
||||
template (Path | None):
|
||||
Optional path to a fully custom MkDocs configuration template.
|
||||
If not provided, built-in templates are merged; the provided
|
||||
template replaces the built-in templates entirely.
|
||||
docs_root (Path):
|
||||
Shared documentation root containing the ``lib`` sources.
|
||||
|
||||
Returns:
|
||||
tuple[list[dict[str, Any]], dict[str, str] | None]:
|
||||
The re-rooted navigation block and the optional theme icon
|
||||
mapping from the specification.
|
||||
|
||||
Raises:
|
||||
click.FileError:
|
||||
If the navigation specification cannot be found.
|
||||
"""
|
||||
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_root)
|
||||
block = MkDocsNavEmitter().emit(resolved)
|
||||
return cast(list[dict[str, Any]], _strip_scope(block, "lib")), spec.icon
|
||||
|
||||
|
||||
def build_wiki_nav_block(wiki_dir: Path) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Build the re-rooted navigation block for a wiki site.
|
||||
|
||||
The wiki navigation derived from the wiki file structure is re-rooted
|
||||
relative to the wiki directory itself by stripping the leading ``wiki/``
|
||||
scope component.
|
||||
|
||||
Args:
|
||||
wiki_dir (Path):
|
||||
Path to the hand-written wiki directory, for example ``docs/wiki``.
|
||||
|
||||
Returns:
|
||||
list[dict[str, Any]]:
|
||||
Navigation entries relative to the wiki directory.
|
||||
|
||||
Raises:
|
||||
click.FileError:
|
||||
If the wiki directory does not exist.
|
||||
"""
|
||||
if not wiki_dir.exists():
|
||||
raise click.FileError(str(wiki_dir), hint="Wiki dir not found")
|
||||
|
||||
return cast(list[dict[str, Any]], _strip_scope(build_wiki_nav(wiki_dir), "wiki"))
|
||||
|
||||
|
||||
def load_spec_icon(nav_file: Path) -> dict[str, str] | None:
|
||||
"""
|
||||
Load the theme icon mapping from a navigation specification.
|
||||
|
||||
Args:
|
||||
nav_file (Path):
|
||||
Path to the navigation specification file.
|
||||
|
||||
Returns:
|
||||
dict[str, str] | None:
|
||||
The icon mapping, or ``None`` when the specification file is
|
||||
absent or cannot be parsed.
|
||||
"""
|
||||
if not nav_file.exists():
|
||||
return None
|
||||
|
||||
try:
|
||||
return load_nav_spec(nav_file).icon
|
||||
except (ValueError, yaml.YAMLError):
|
||||
return None
|
||||
|
||||
|
||||
def _strip_scope(value: object, scope: str) -> object:
|
||||
"""
|
||||
Re-root navigation paths by removing a leading scope component.
|
||||
|
||||
The navigation block is walked recursively and every relative path
|
||||
string that starts with ``{scope}/`` has that prefix removed, so a lib
|
||||
or wiki site scoped to its own ``docs_dir`` can reuse paths that were
|
||||
originally written relative to the shared documentation root.
|
||||
|
||||
Args:
|
||||
value (object):
|
||||
Navigation block, group list, path string, or scalar value.
|
||||
scope (str):
|
||||
Leading path component to strip, for example ``lib`` or ``wiki``.
|
||||
|
||||
Returns:
|
||||
object:
|
||||
The navigation structure with re-rooted paths.
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
prefix = f"{scope}/"
|
||||
return value[len(prefix) :] if value.startswith(prefix) else value
|
||||
if isinstance(value, list):
|
||||
return [_strip_scope(item, scope) for item in value]
|
||||
if isinstance(value, dict):
|
||||
return {key: _strip_scope(val, scope) for key, val in value.items()}
|
||||
return value
|
||||
|
||||
|
||||
def generate_site_config(
|
||||
kind: str,
|
||||
kind_root: Path,
|
||||
nav_block: list[dict[str, Any]],
|
||||
out: Path,
|
||||
site_name: str,
|
||||
docs_dir: str,
|
||||
site_dir: str,
|
||||
template: Path | None = None,
|
||||
site_description: str | None = None,
|
||||
site_author: str | None = None,
|
||||
theme_icon: dict[str, str] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Generate a per-kind `mkdocs.{kind}.yml` configuration file.
|
||||
|
||||
The configuration is created by merging the shared ``mkdocs.common.yml``
|
||||
template with the fragment contributed by the kind (``lib``, ``api``, or
|
||||
``wiki``). Both ``docs_dir`` and ``site_dir`` are written relative to the
|
||||
configuration file's directory: the kind's sources when expressed as a
|
||||
sibling path (for example ``lib``) and the per-kind site output (for
|
||||
example ``../site/lib``).
|
||||
|
||||
Args:
|
||||
kind (str):
|
||||
Documentation kind, one of ``lib``, ``api``, or ``wiki``.
|
||||
|
||||
kind_root (Path):
|
||||
Directory scoped to the kind (for example ``docs/lib``) that
|
||||
serves as the MkDocs ``docs_dir``.
|
||||
|
||||
nav_block (list[dict[str, Any]]):
|
||||
Re-rooted navigation entries for the kind's site.
|
||||
|
||||
out (Path):
|
||||
Destination path where the generated `mkdocs.yml` file will be written.
|
||||
Destination path where the generated ``mkdocs.{kind}.yml`` file
|
||||
is written.
|
||||
|
||||
site_name (str):
|
||||
Display name for the generated documentation site.
|
||||
|
||||
modes (Iterable[str] | None):
|
||||
Documentation modes to enable. Each mode contributes its own
|
||||
built-in template fragment (for example ``lib``, ``api``, or
|
||||
``wiki``), merged on top of the shared ``mkdocs.common.yml``
|
||||
template.
|
||||
docs_dir (str):
|
||||
MkDocs ``docs_dir`` value, relative to the configuration
|
||||
file's directory.
|
||||
|
||||
site_dir (str):
|
||||
MkDocs ``site_dir`` value, relative to the configuration
|
||||
file's directory.
|
||||
|
||||
template (Path | None):
|
||||
Optional path to a fully custom MkDocs configuration template
|
||||
that replaces the built-in templates entirely.
|
||||
|
||||
site_description (str | None):
|
||||
Optional site description written into the configuration.
|
||||
@@ -137,50 +257,26 @@ def generate_config(
|
||||
site_author (str | None):
|
||||
Optional site author written into the configuration.
|
||||
|
||||
wiki_dir (Path | None):
|
||||
Optional path to a hand-written wiki directory (for example
|
||||
``docs/wiki``). When provided, the site navigation is derived
|
||||
from the wiki file structure and placed before the navigation
|
||||
groups defined in ``nav_file``.
|
||||
|
||||
Raises:
|
||||
click.FileError:
|
||||
If the navigation specification, template, or wiki directory
|
||||
cannot be found.
|
||||
theme_icon (dict[str, str] | None):
|
||||
Optional mapping of theme icon entries injected as
|
||||
``theme.icon``.
|
||||
"""
|
||||
if not nav_file.exists() and wiki_dir is None:
|
||||
raise click.FileError(str(nav_file), hint="Nav spec not found")
|
||||
|
||||
nav_block: list[dict] = []
|
||||
if nav_file.exists():
|
||||
spec = load_nav_spec(nav_file)
|
||||
resolved = resolve_nav(spec, docs_dir)
|
||||
nav_block = MkDocsNavEmitter().emit(resolved)
|
||||
else:
|
||||
spec = None
|
||||
|
||||
if wiki_dir is not None:
|
||||
if not wiki_dir.exists():
|
||||
raise click.FileError(str(wiki_dir), hint="Wiki dir not found")
|
||||
wiki_nav = build_wiki_nav(wiki_dir)
|
||||
if wiki_nav:
|
||||
nav_block = wiki_nav + [entry for entry in nav_block if "Home" not in entry]
|
||||
|
||||
data = _load_template(template, modes)
|
||||
data = _load_template(template, [kind])
|
||||
|
||||
data["site_name"] = site_name
|
||||
if site_description:
|
||||
data["site_description"] = site_description
|
||||
if site_author:
|
||||
data["site_author"] = site_author
|
||||
data["docs_dir"] = Path(os.path.relpath(docs_dir, out.parent)).as_posix()
|
||||
data["docs_dir"] = docs_dir
|
||||
data["site_dir"] = site_dir
|
||||
data["nav"] = nav_block
|
||||
|
||||
if spec is not None and spec.icon:
|
||||
if theme_icon:
|
||||
theme = data.setdefault("theme", {})
|
||||
if not isinstance(theme, dict):
|
||||
theme = {}
|
||||
theme["icon"] = spec.icon
|
||||
theme["icon"] = theme_icon
|
||||
data["theme"] = theme
|
||||
|
||||
out.write_text(yaml.safe_dump(data, sort_keys=False), encoding="utf-8")
|
||||
@@ -310,28 +406,28 @@ def _deep_merge(base: dict, part: dict) -> dict:
|
||||
return base
|
||||
|
||||
|
||||
def build(mkdocs_yml: Path) -> None:
|
||||
def build_configs(yml_paths: Iterable[Path]) -> None:
|
||||
"""
|
||||
Build the MkDocs documentation site.
|
||||
Build the MkDocs documentation site for every given configuration.
|
||||
|
||||
This function loads the MkDocs configuration and runs the MkDocs
|
||||
build command to generate the final static documentation site.
|
||||
Each configuration file is loaded and built in turn, producing the
|
||||
per-kind static sites (``site/lib``, ``site/api``, ``site/wiki``).
|
||||
|
||||
Args:
|
||||
mkdocs_yml (Path):
|
||||
Path to the `mkdocs.yml` configuration file.
|
||||
yml_paths (Iterable[Path]):
|
||||
Configuration files to build, in order.
|
||||
|
||||
Raises:
|
||||
click.ClickException:
|
||||
If the configuration file does not exist.
|
||||
If a configuration file does not exist.
|
||||
"""
|
||||
if not mkdocs_yml.exists():
|
||||
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
|
||||
|
||||
from mkdocs.commands.build import build as mkdocs_build
|
||||
from mkdocs.config import load_config
|
||||
|
||||
mkdocs_build(load_config(str(mkdocs_yml)))
|
||||
for yml in yml_paths:
|
||||
if not yml.exists():
|
||||
raise click.ClickException(f"mkdocs.yml not found: {yml}")
|
||||
mkdocs_build(load_config(str(yml)))
|
||||
|
||||
|
||||
def serve(mkdocs_yml: Path) -> None:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
def generate_sources(
|
||||
module: str,
|
||||
@@ -8,16 +9,25 @@ def generate_sources(
|
||||
module_is_source: bool | None = None,
|
||||
readme_dir: Path | None = None,
|
||||
) -> None: ...
|
||||
def generate_config(
|
||||
docs_dir: Path,
|
||||
def build_lib_nav(
|
||||
nav_file: Path,
|
||||
template: Path | None,
|
||||
docs_root: Path,
|
||||
) -> tuple[list[dict[str, Any]], dict[str, str] | None]: ...
|
||||
def build_wiki_nav_block(wiki_dir: Path) -> list[dict[str, Any]]: ...
|
||||
def load_spec_icon(nav_file: Path) -> dict[str, str] | None: ...
|
||||
def _strip_scope(value: object, scope: str) -> object: ...
|
||||
def generate_site_config(
|
||||
kind: str,
|
||||
kind_root: Path,
|
||||
nav_block: list[dict[str, Any]],
|
||||
out: Path,
|
||||
site_name: str,
|
||||
modes: Iterable[str] | None = None,
|
||||
docs_dir: str,
|
||||
site_dir: str,
|
||||
template: Path | None = None,
|
||||
site_description: str | None = None,
|
||||
site_author: str | None = None,
|
||||
wiki_dir: Path | None = None,
|
||||
theme_icon: dict[str, str] | None = None,
|
||||
) -> None: ...
|
||||
def build(mkdocs_yml: Path) -> None: ...
|
||||
def build_configs(yml_paths: Iterable[Path]) -> None: ...
|
||||
def serve(mkdocs_yml: Path) -> None: ...
|
||||
|
||||
@@ -2,8 +2,15 @@
|
||||
"module": "docforge.cli.commands",
|
||||
"content": {
|
||||
"path": "docforge.cli.commands",
|
||||
"docstring": "# Summary\n\nCommand definitions for the doc-forge CLI.\n\nProvides the CLI structure using Click, including build, serve, and tree commands.\n\n---\n\nNotes:\n - The `build` command validates requested modes before generating anything.\n - `--mkdocs`, `--api`, and `--wiki` share a single MkDocs build; `--mcp`\n generates a machine-readable bundle independently.\n\n---",
|
||||
"docstring": "# Summary\n\nCommand definitions for the doc-forge CLI.\n\nProvides the CLI structure using Click, including build, serve, and tree commands.\n\n---\n\nNotes:\n - The `build` command validates requested modes before generating anything.\n - `--mkdocs`, `--api`, and `--wiki` each emit their own MkDocs config and\n build (`docs/mkdocs.{kind}.yml` into `site/{kind}`); `--mcp` generates a\n machine-readable bundle independently.\n\n---",
|
||||
"objects": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Path": {
|
||||
"name": "Path",
|
||||
"kind": "alias",
|
||||
@@ -245,15 +252,8 @@
|
||||
"kind": "module",
|
||||
"path": "docforge.cli.commands.mkdocs_utils",
|
||||
"signature": "<bound method Alias.signature of Alias('mkdocs_utils', 'docforge.cli.mkdocs_utils')>",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A single generated `mkdocs.yml` serves lib, api, and wiki content with\n merged navigation. Wiki navigation, when enabled, precedes every other\n group and its `index.md` becomes the site `Home`.\n\n---",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A separate `mkdocs.{kind}.yml` configuration and build is emitted per\n enabled kind (lib, api, wiki), each scoped to its own `docs_dir` and\n written into its own `site_dir` (`site/lib`, `site/api`, `site/wiki`).\n - Navigation blocks are re-rooted per kind: the wiki navigation drops its\n leading `wiki/` scope and the resolved nav spec drops its `lib/` scope.\n\n---",
|
||||
"members": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'docforge.cli.mkdocs_utils.os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Iterable": {
|
||||
"name": "Iterable",
|
||||
"kind": "alias",
|
||||
@@ -275,6 +275,20 @@
|
||||
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mkdocs_utils.Path')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Any": {
|
||||
"name": "Any",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.Any",
|
||||
"signature": "<bound method Alias.signature of Alias('Any', 'docforge.cli.mkdocs_utils.Any')>",
|
||||
"docstring": null
|
||||
},
|
||||
"cast": {
|
||||
"name": "cast",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.cast",
|
||||
"signature": "<bound method Alias.signature of Alias('cast', 'docforge.cli.mkdocs_utils.cast')>",
|
||||
"docstring": null
|
||||
},
|
||||
"click": {
|
||||
"name": "click",
|
||||
"kind": "alias",
|
||||
@@ -393,19 +407,40 @@
|
||||
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.cli.mkdocs_utils.generate_sources')>",
|
||||
"docstring": "Generate MkDocs Markdown sources for a Python module.\n\nThis function introspects the specified module, builds the internal\ndocumentation model, and renders Markdown documentation files for\nuse with MkDocs.\n\nArgs:\n module (str):\n Python module import path used as the entry point for\n documentation generation.\n\n docs_dir (Path):\n Directory where the generated Markdown files will be written.\n\n project_name (str | None):\n Optional override for the project name used in documentation metadata.\n\n module_is_source (bool | None):\n If True, treat the specified module directory as the project root\n rather than a nested module.\n\n readme_dir (Path | None):\n Directory where the generated README.md should be written. If not\n provided, defaults to the parent of ``docs_dir``."
|
||||
},
|
||||
"generate_config": {
|
||||
"name": "generate_config",
|
||||
"build_lib_nav": {
|
||||
"name": "build_lib_nav",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.generate_config",
|
||||
"signature": "<bound method Alias.signature of Alias('generate_config', 'docforge.cli.mkdocs_utils.generate_config')>",
|
||||
"docstring": "Generate an `mkdocs.yml` configuration file.\n\nThe configuration is created by combining a template configuration\nwith a navigation structure derived from the docforge navigation\nspecification (and, when a wiki directory is provided, from the wiki\nfile structure).\n\nThe ``docs_dir`` is always written relative to the MkDocs root and is\nexpected to be the shared documentation parent (for example ``docs``),\nwith generated sources nested under ``lib/`` or ``api/`` subdirectories\nand hand-written wiki content under a ``wiki/`` subdirectory.\n\nArgs:\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template.\n If not provided, built-in templates are merged; the provided\n template replaces the built-in templates entirely.\n\n out (Path):\n Destination path where the generated `mkdocs.yml` file will be written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n modes (Iterable[str] | None):\n Documentation modes to enable. Each mode contributes its own\n built-in template fragment (for example ``lib``, ``api``, or\n ``wiki``), merged on top of the shared ``mkdocs.common.yml``\n template.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n wiki_dir (Path | None):\n Optional path to a hand-written wiki directory (for example\n ``docs/wiki``). When provided, the site navigation is derived\n from the wiki file structure and placed before the navigation\n groups defined in ``nav_file``.\n\nRaises:\n click.FileError:\n If the navigation specification, template, or wiki directory\n cannot be found."
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_lib_nav",
|
||||
"signature": "<bound method Alias.signature of Alias('build_lib_nav', 'docforge.cli.mkdocs_utils.build_lib_nav')>",
|
||||
"docstring": "Build the re-rooted navigation block for a lib site.\n\nThe navigation specification is resolved against the shared documentation\nroot and every resulting path is re-rooted relative to the ``lib``\nsubdirectory by stripping its leading ``lib/`` scope component.\n\nArgs:\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n docs_root (Path):\n Shared documentation root containing the ``lib`` sources.\n\nReturns:\n tuple[list[dict[str, Any]], dict[str, str] | None]:\n The re-rooted navigation block and the optional theme icon\n mapping from the specification.\n\nRaises:\n click.FileError:\n If the navigation specification cannot be found."
|
||||
},
|
||||
"build": {
|
||||
"name": "build",
|
||||
"build_wiki_nav_block": {
|
||||
"name": "build_wiki_nav_block",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build",
|
||||
"signature": "<bound method Alias.signature of Alias('build', 'docforge.cli.mkdocs_utils.build')>",
|
||||
"docstring": "Build the MkDocs documentation site.\n\nThis function loads the MkDocs configuration and runs the MkDocs\nbuild command to generate the final static documentation site.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_wiki_nav_block",
|
||||
"signature": "<bound method Alias.signature of Alias('build_wiki_nav_block', 'docforge.cli.mkdocs_utils.build_wiki_nav_block')>",
|
||||
"docstring": "Build the re-rooted navigation block for a wiki site.\n\nThe wiki navigation derived from the wiki file structure is re-rooted\nrelative to the wiki directory itself by stripping the leading ``wiki/``\nscope component.\n\nArgs:\n wiki_dir (Path):\n Path to the hand-written wiki directory, for example ``docs/wiki``.\n\nReturns:\n list[dict[str, Any]]:\n Navigation entries relative to the wiki directory.\n\nRaises:\n click.FileError:\n If the wiki directory does not exist."
|
||||
},
|
||||
"load_spec_icon": {
|
||||
"name": "load_spec_icon",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.load_spec_icon",
|
||||
"signature": "<bound method Alias.signature of Alias('load_spec_icon', 'docforge.cli.mkdocs_utils.load_spec_icon')>",
|
||||
"docstring": "Load the theme icon mapping from a navigation specification.\n\nArgs:\n nav_file (Path):\n Path to the navigation specification file.\n\nReturns:\n dict[str, str] | None:\n The icon mapping, or ``None`` when the specification file is\n absent or cannot be parsed."
|
||||
},
|
||||
"generate_site_config": {
|
||||
"name": "generate_site_config",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.generate_site_config",
|
||||
"signature": "<bound method Alias.signature of Alias('generate_site_config', 'docforge.cli.mkdocs_utils.generate_site_config')>",
|
||||
"docstring": "Generate a per-kind `mkdocs.{kind}.yml` configuration file.\n\nThe configuration is created by merging the shared ``mkdocs.common.yml``\ntemplate with the fragment contributed by the kind (``lib``, ``api``, or\n``wiki``). Both ``docs_dir`` and ``site_dir`` are written relative to the\nconfiguration file's directory: the kind's sources when expressed as a\nsibling path (for example ``lib``) and the per-kind site output (for\nexample ``../site/lib``).\n\nArgs:\n kind (str):\n Documentation kind, one of ``lib``, ``api``, or ``wiki``.\n\n kind_root (Path):\n Directory scoped to the kind (for example ``docs/lib``) that\n serves as the MkDocs ``docs_dir``.\n\n nav_block (list[dict[str, Any]]):\n Re-rooted navigation entries for the kind's site.\n\n out (Path):\n Destination path where the generated ``mkdocs.{kind}.yml`` file\n is written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n docs_dir (str):\n MkDocs ``docs_dir`` value, relative to the configuration\n file's directory.\n\n site_dir (str):\n MkDocs ``site_dir`` value, relative to the configuration\n file's directory.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template\n that replaces the built-in templates entirely.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n theme_icon (dict[str, str] | None):\n Optional mapping of theme icon entries injected as\n ``theme.icon``."
|
||||
},
|
||||
"build_configs": {
|
||||
"name": "build_configs",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_configs",
|
||||
"signature": "<bound method Alias.signature of Alias('build_configs', 'docforge.cli.mkdocs_utils.build_configs')>",
|
||||
"docstring": "Build the MkDocs documentation site for every given configuration.\n\nEach configuration file is loaded and built in turn, producing the\nper-kind static sites (``site/lib``, ``site/api``, ``site/wiki``).\n\nArgs:\n yml_paths (Iterable[Path]):\n Configuration files to build, in order.\n\nRaises:\n click.ClickException:\n If a configuration file does not exist."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
@@ -522,21 +557,21 @@
|
||||
"name": "build",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.build",
|
||||
"signature": "<bound method Function.signature of Function('build', 38, 260)>",
|
||||
"docstring": "Build documentation artifacts.\n\nThis command runs the full documentation pipeline: it loads Python\nmodules, generates renderer-specific documentation sources, and\noptionally builds or serves the final output.\n\nDepending on the selected options, the build can target:\n\n- MkDocs static documentation sites for library reference docs\n- Swagger-enabled API docs generated from an OpenAPI spec\n- Hand-written wiki pages included in the MkDocs site\n- MCP structured documentation resources\n\nNotes:\n - At least one of `--mcp`, `--mkdocs`, `--wiki`, or `--api` must be\n provided.\n - `--mkdocs`, `--api`, and `--wiki` are combined into a single MkDocs\n build, while `--mcp` emits a machine-readable bundle.\n\nArgs:\n mcp (bool):\n Enable MCP documentation generation.\n\n mkdocs (bool):\n Enable MkDocs library documentation generation.\n\n api (bool):\n Enable API documentation generation from an OpenAPI spec.\n\n wiki (bool):\n Include a hand-written wiki directory in the MkDocs site.\n\n module_is_source (bool):\n Treat the specified module directory as the project root.\n\n module (str | None):\n Python module import path to document.\n\n openapi_spec (Path | None):\n Path to the OpenAPI JSON specification used for API docs.\n\n project_name (str | None):\n Optional override for the project name.\n\n site_name (str | None):\n Display name for the MkDocs site.\n\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n wiki_dir (Path):\n Directory containing hand-written wiki markdown files.\n\n nav_file (Path):\n Path to the navigation specification file.\n\n template (Path | None):\n Optional custom MkDocs configuration template.\n\n mkdocs_yml (Path):\n Output path for the generated MkDocs configuration.\n\n out_dir (Path):\n Output directory for generated MCP resources.\n\nRaises:\n click.UsageError:\n If required options are missing or conflicting."
|
||||
"signature": "<bound method Function.signature of Function('build', 40, 264)>",
|
||||
"docstring": "Build documentation artifacts.\n\nThis command runs the full documentation pipeline: it loads Python\nmodules, generates renderer-specific documentation sources, and\noptionally builds the final output.\n\nDepending on the selected options, the build can target:\n\n- A lib MkDocs site (`--mkdocs`) for library reference docs\n- A swagger-enabled API MkDocs site (`--api`) built from an OpenAPI spec\n- A wiki MkDocs site (`--wiki`) built from hand-written markdown\n- MCP structured documentation resources (`--mcp`)\n\nEach enabled site kind produces its own MkDocs configuration\n(`docs/mkdocs.{kind}.yml`) and its own build (`site/{kind}`).\n\nNotes:\n - At least one of `--mcp`, `--mkdocs`, `--wiki`, or `--api` must be\n provided.\n - `--mkdocs`, `--api`, and `--wiki` emit independent MkDocs builds,\n while `--mcp` emits a machine-readable bundle.\n\nArgs:\n mcp (bool):\n Enable MCP documentation generation.\n\n mkdocs (bool):\n Enable the lib MkDocs documentation generation.\n\n api (bool):\n Enable API documentation generation from an OpenAPI spec.\n\n wiki (bool):\n Build a hand-written wiki directory as its own MkDocs site.\n\n module_is_source (bool):\n Treat the specified module directory as the project root.\n\n module (str | None):\n Python module import path to document.\n\n openapi_spec (Path | None):\n Path to the OpenAPI JSON specification used for API docs.\n\n project_name (str | None):\n Optional override for the project name.\n\n site_name (str | None):\n Display name for the lib and wiki MkDocs sites.\n\n docs_dir (Path):\n Shared documentation root used for generated sources.\n wiki_dir (Path):\n Directory containing hand-written wiki markdown files.\n\n nav_file (Path):\n Path to the navigation specification file.\n\n template (Path | None):\n Optional custom MkDocs configuration template.\n\n out_dir (Path):\n Output directory for generated MCP resources.\n\nRaises:\n click.UsageError:\n If required options are missing or conflicting."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.serve",
|
||||
"signature": "<bound method Function.signature of Function('serve', 263, 324)>",
|
||||
"docstring": "Serve generated documentation locally.\n\nDepending on the selected mode, this command starts either:\n\n- A MkDocs development server for browsing documentation\n- An MCP server exposing structured documentation resources\n\nArgs:\n mcp (bool):\n Serve documentation using the MCP server.\n\n mkdocs (bool):\n Serve the MkDocs development site.\n\n module (str | None):\n Python module import path to serve via MCP.\n\n mkdocs_yml (Path):\n Path to the MkDocs configuration file.\n\n out_dir (Path):\n Root directory containing MCP documentation resources.\n\nRaises:\n click.UsageError:\n If invalid or conflicting options are provided."
|
||||
"signature": "<bound method Function.signature of Function('serve', 267, 367)>",
|
||||
"docstring": "Serve generated documentation locally.\n\nDepending on the selected mode, this command starts either:\n\n- A MkDocs development server for browsing a site, or\n- An MCP server exposing structured documentation resources\n\nThe kind flags (`--lib`, `--api`, `--wiki`) select the generated\nper-kind config (`docs/mkdocs.{kind}.yml`); `--mkdocs` serves the config\npassed via `--mkdocs-yml`.\n\nArgs:\n mcp (bool):\n Serve documentation using the MCP server.\n\n mkdocs (bool):\n Serve the MkDocs development site from ``--mkdocs-yml``.\n\n lib (bool):\n Serve the lib MkDocs site.\n\n api (bool):\n Serve the API MkDocs site.\n\n wiki (bool):\n Serve the wiki MkDocs site.\n\n module (str | None):\n Python module import path to serve via MCP.\n\n mkdocs_yml (Path):\n Path to the MkDocs configuration file.\n\n out_dir (Path):\n Root directory containing MCP documentation resources.\n\nRaises:\n click.UsageError:\n If invalid or conflicting options are provided."
|
||||
},
|
||||
"tree": {
|
||||
"name": "tree",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.tree",
|
||||
"signature": "<bound method Function.signature of Function('tree', 327, 363)>",
|
||||
"signature": "<bound method Function.signature of Function('tree', 370, 406)>",
|
||||
"docstring": "Display the documentation object tree for a module.\n\nThis command introspects the specified module and prints a\nhierarchical representation of the discovered documentation\nobjects, including modules, classes, functions, and members.\n\nArgs:\n module (str):\n Python module import path to introspect.\n\n project_name (str | None):\n Optional name to display as the project root."
|
||||
},
|
||||
"Group": {
|
||||
|
||||
@@ -134,8 +134,15 @@
|
||||
"kind": "module",
|
||||
"path": "docforge.cli.commands",
|
||||
"signature": null,
|
||||
"docstring": "# Summary\n\nCommand definitions for the doc-forge CLI.\n\nProvides the CLI structure using Click, including build, serve, and tree commands.\n\n---\n\nNotes:\n - The `build` command validates requested modes before generating anything.\n - `--mkdocs`, `--api`, and `--wiki` share a single MkDocs build; `--mcp`\n generates a machine-readable bundle independently.\n\n---",
|
||||
"docstring": "# Summary\n\nCommand definitions for the doc-forge CLI.\n\nProvides the CLI structure using Click, including build, serve, and tree commands.\n\n---\n\nNotes:\n - The `build` command validates requested modes before generating anything.\n - `--mkdocs`, `--api`, and `--wiki` each emit their own MkDocs config and\n build (`docs/mkdocs.{kind}.yml` into `site/{kind}`); `--mcp` generates a\n machine-readable bundle independently.\n\n---",
|
||||
"members": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Path": {
|
||||
"name": "Path",
|
||||
"kind": "alias",
|
||||
@@ -377,15 +384,8 @@
|
||||
"kind": "module",
|
||||
"path": "docforge.cli.commands.mkdocs_utils",
|
||||
"signature": "<bound method Alias.signature of Alias('mkdocs_utils', 'docforge.cli.mkdocs_utils')>",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A single generated `mkdocs.yml` serves lib, api, and wiki content with\n merged navigation. Wiki navigation, when enabled, precedes every other\n group and its `index.md` becomes the site `Home`.\n\n---",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A separate `mkdocs.{kind}.yml` configuration and build is emitted per\n enabled kind (lib, api, wiki), each scoped to its own `docs_dir` and\n written into its own `site_dir` (`site/lib`, `site/api`, `site/wiki`).\n - Navigation blocks are re-rooted per kind: the wiki navigation drops its\n leading `wiki/` scope and the resolved nav spec drops its `lib/` scope.\n\n---",
|
||||
"members": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'docforge.cli.mkdocs_utils.os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Iterable": {
|
||||
"name": "Iterable",
|
||||
"kind": "alias",
|
||||
@@ -407,6 +407,20 @@
|
||||
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mkdocs_utils.Path')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Any": {
|
||||
"name": "Any",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.Any",
|
||||
"signature": "<bound method Alias.signature of Alias('Any', 'docforge.cli.mkdocs_utils.Any')>",
|
||||
"docstring": null
|
||||
},
|
||||
"cast": {
|
||||
"name": "cast",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.cast",
|
||||
"signature": "<bound method Alias.signature of Alias('cast', 'docforge.cli.mkdocs_utils.cast')>",
|
||||
"docstring": null
|
||||
},
|
||||
"click": {
|
||||
"name": "click",
|
||||
"kind": "alias",
|
||||
@@ -525,19 +539,40 @@
|
||||
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.cli.mkdocs_utils.generate_sources')>",
|
||||
"docstring": "Generate MkDocs Markdown sources for a Python module.\n\nThis function introspects the specified module, builds the internal\ndocumentation model, and renders Markdown documentation files for\nuse with MkDocs.\n\nArgs:\n module (str):\n Python module import path used as the entry point for\n documentation generation.\n\n docs_dir (Path):\n Directory where the generated Markdown files will be written.\n\n project_name (str | None):\n Optional override for the project name used in documentation metadata.\n\n module_is_source (bool | None):\n If True, treat the specified module directory as the project root\n rather than a nested module.\n\n readme_dir (Path | None):\n Directory where the generated README.md should be written. If not\n provided, defaults to the parent of ``docs_dir``."
|
||||
},
|
||||
"generate_config": {
|
||||
"name": "generate_config",
|
||||
"build_lib_nav": {
|
||||
"name": "build_lib_nav",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.generate_config",
|
||||
"signature": "<bound method Alias.signature of Alias('generate_config', 'docforge.cli.mkdocs_utils.generate_config')>",
|
||||
"docstring": "Generate an `mkdocs.yml` configuration file.\n\nThe configuration is created by combining a template configuration\nwith a navigation structure derived from the docforge navigation\nspecification (and, when a wiki directory is provided, from the wiki\nfile structure).\n\nThe ``docs_dir`` is always written relative to the MkDocs root and is\nexpected to be the shared documentation parent (for example ``docs``),\nwith generated sources nested under ``lib/`` or ``api/`` subdirectories\nand hand-written wiki content under a ``wiki/`` subdirectory.\n\nArgs:\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template.\n If not provided, built-in templates are merged; the provided\n template replaces the built-in templates entirely.\n\n out (Path):\n Destination path where the generated `mkdocs.yml` file will be written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n modes (Iterable[str] | None):\n Documentation modes to enable. Each mode contributes its own\n built-in template fragment (for example ``lib``, ``api``, or\n ``wiki``), merged on top of the shared ``mkdocs.common.yml``\n template.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n wiki_dir (Path | None):\n Optional path to a hand-written wiki directory (for example\n ``docs/wiki``). When provided, the site navigation is derived\n from the wiki file structure and placed before the navigation\n groups defined in ``nav_file``.\n\nRaises:\n click.FileError:\n If the navigation specification, template, or wiki directory\n cannot be found."
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_lib_nav",
|
||||
"signature": "<bound method Alias.signature of Alias('build_lib_nav', 'docforge.cli.mkdocs_utils.build_lib_nav')>",
|
||||
"docstring": "Build the re-rooted navigation block for a lib site.\n\nThe navigation specification is resolved against the shared documentation\nroot and every resulting path is re-rooted relative to the ``lib``\nsubdirectory by stripping its leading ``lib/`` scope component.\n\nArgs:\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n docs_root (Path):\n Shared documentation root containing the ``lib`` sources.\n\nReturns:\n tuple[list[dict[str, Any]], dict[str, str] | None]:\n The re-rooted navigation block and the optional theme icon\n mapping from the specification.\n\nRaises:\n click.FileError:\n If the navigation specification cannot be found."
|
||||
},
|
||||
"build": {
|
||||
"name": "build",
|
||||
"build_wiki_nav_block": {
|
||||
"name": "build_wiki_nav_block",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build",
|
||||
"signature": "<bound method Alias.signature of Alias('build', 'docforge.cli.mkdocs_utils.build')>",
|
||||
"docstring": "Build the MkDocs documentation site.\n\nThis function loads the MkDocs configuration and runs the MkDocs\nbuild command to generate the final static documentation site.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_wiki_nav_block",
|
||||
"signature": "<bound method Alias.signature of Alias('build_wiki_nav_block', 'docforge.cli.mkdocs_utils.build_wiki_nav_block')>",
|
||||
"docstring": "Build the re-rooted navigation block for a wiki site.\n\nThe wiki navigation derived from the wiki file structure is re-rooted\nrelative to the wiki directory itself by stripping the leading ``wiki/``\nscope component.\n\nArgs:\n wiki_dir (Path):\n Path to the hand-written wiki directory, for example ``docs/wiki``.\n\nReturns:\n list[dict[str, Any]]:\n Navigation entries relative to the wiki directory.\n\nRaises:\n click.FileError:\n If the wiki directory does not exist."
|
||||
},
|
||||
"load_spec_icon": {
|
||||
"name": "load_spec_icon",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.load_spec_icon",
|
||||
"signature": "<bound method Alias.signature of Alias('load_spec_icon', 'docforge.cli.mkdocs_utils.load_spec_icon')>",
|
||||
"docstring": "Load the theme icon mapping from a navigation specification.\n\nArgs:\n nav_file (Path):\n Path to the navigation specification file.\n\nReturns:\n dict[str, str] | None:\n The icon mapping, or ``None`` when the specification file is\n absent or cannot be parsed."
|
||||
},
|
||||
"generate_site_config": {
|
||||
"name": "generate_site_config",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.generate_site_config",
|
||||
"signature": "<bound method Alias.signature of Alias('generate_site_config', 'docforge.cli.mkdocs_utils.generate_site_config')>",
|
||||
"docstring": "Generate a per-kind `mkdocs.{kind}.yml` configuration file.\n\nThe configuration is created by merging the shared ``mkdocs.common.yml``\ntemplate with the fragment contributed by the kind (``lib``, ``api``, or\n``wiki``). Both ``docs_dir`` and ``site_dir`` are written relative to the\nconfiguration file's directory: the kind's sources when expressed as a\nsibling path (for example ``lib``) and the per-kind site output (for\nexample ``../site/lib``).\n\nArgs:\n kind (str):\n Documentation kind, one of ``lib``, ``api``, or ``wiki``.\n\n kind_root (Path):\n Directory scoped to the kind (for example ``docs/lib``) that\n serves as the MkDocs ``docs_dir``.\n\n nav_block (list[dict[str, Any]]):\n Re-rooted navigation entries for the kind's site.\n\n out (Path):\n Destination path where the generated ``mkdocs.{kind}.yml`` file\n is written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n docs_dir (str):\n MkDocs ``docs_dir`` value, relative to the configuration\n file's directory.\n\n site_dir (str):\n MkDocs ``site_dir`` value, relative to the configuration\n file's directory.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template\n that replaces the built-in templates entirely.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n theme_icon (dict[str, str] | None):\n Optional mapping of theme icon entries injected as\n ``theme.icon``."
|
||||
},
|
||||
"build_configs": {
|
||||
"name": "build_configs",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.mkdocs_utils.build_configs",
|
||||
"signature": "<bound method Alias.signature of Alias('build_configs', 'docforge.cli.mkdocs_utils.build_configs')>",
|
||||
"docstring": "Build the MkDocs documentation site for every given configuration.\n\nEach configuration file is loaded and built in turn, producing the\nper-kind static sites (``site/lib``, ``site/api``, ``site/wiki``).\n\nArgs:\n yml_paths (Iterable[Path]):\n Configuration files to build, in order.\n\nRaises:\n click.ClickException:\n If a configuration file does not exist."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
@@ -654,21 +689,21 @@
|
||||
"name": "build",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.build",
|
||||
"signature": "<bound method Function.signature of Function('build', 38, 260)>",
|
||||
"docstring": "Build documentation artifacts.\n\nThis command runs the full documentation pipeline: it loads Python\nmodules, generates renderer-specific documentation sources, and\noptionally builds or serves the final output.\n\nDepending on the selected options, the build can target:\n\n- MkDocs static documentation sites for library reference docs\n- Swagger-enabled API docs generated from an OpenAPI spec\n- Hand-written wiki pages included in the MkDocs site\n- MCP structured documentation resources\n\nNotes:\n - At least one of `--mcp`, `--mkdocs`, `--wiki`, or `--api` must be\n provided.\n - `--mkdocs`, `--api`, and `--wiki` are combined into a single MkDocs\n build, while `--mcp` emits a machine-readable bundle.\n\nArgs:\n mcp (bool):\n Enable MCP documentation generation.\n\n mkdocs (bool):\n Enable MkDocs library documentation generation.\n\n api (bool):\n Enable API documentation generation from an OpenAPI spec.\n\n wiki (bool):\n Include a hand-written wiki directory in the MkDocs site.\n\n module_is_source (bool):\n Treat the specified module directory as the project root.\n\n module (str | None):\n Python module import path to document.\n\n openapi_spec (Path | None):\n Path to the OpenAPI JSON specification used for API docs.\n\n project_name (str | None):\n Optional override for the project name.\n\n site_name (str | None):\n Display name for the MkDocs site.\n\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n wiki_dir (Path):\n Directory containing hand-written wiki markdown files.\n\n nav_file (Path):\n Path to the navigation specification file.\n\n template (Path | None):\n Optional custom MkDocs configuration template.\n\n mkdocs_yml (Path):\n Output path for the generated MkDocs configuration.\n\n out_dir (Path):\n Output directory for generated MCP resources.\n\nRaises:\n click.UsageError:\n If required options are missing or conflicting."
|
||||
"signature": "<bound method Function.signature of Function('build', 40, 264)>",
|
||||
"docstring": "Build documentation artifacts.\n\nThis command runs the full documentation pipeline: it loads Python\nmodules, generates renderer-specific documentation sources, and\noptionally builds the final output.\n\nDepending on the selected options, the build can target:\n\n- A lib MkDocs site (`--mkdocs`) for library reference docs\n- A swagger-enabled API MkDocs site (`--api`) built from an OpenAPI spec\n- A wiki MkDocs site (`--wiki`) built from hand-written markdown\n- MCP structured documentation resources (`--mcp`)\n\nEach enabled site kind produces its own MkDocs configuration\n(`docs/mkdocs.{kind}.yml`) and its own build (`site/{kind}`).\n\nNotes:\n - At least one of `--mcp`, `--mkdocs`, `--wiki`, or `--api` must be\n provided.\n - `--mkdocs`, `--api`, and `--wiki` emit independent MkDocs builds,\n while `--mcp` emits a machine-readable bundle.\n\nArgs:\n mcp (bool):\n Enable MCP documentation generation.\n\n mkdocs (bool):\n Enable the lib MkDocs documentation generation.\n\n api (bool):\n Enable API documentation generation from an OpenAPI spec.\n\n wiki (bool):\n Build a hand-written wiki directory as its own MkDocs site.\n\n module_is_source (bool):\n Treat the specified module directory as the project root.\n\n module (str | None):\n Python module import path to document.\n\n openapi_spec (Path | None):\n Path to the OpenAPI JSON specification used for API docs.\n\n project_name (str | None):\n Optional override for the project name.\n\n site_name (str | None):\n Display name for the lib and wiki MkDocs sites.\n\n docs_dir (Path):\n Shared documentation root used for generated sources.\n wiki_dir (Path):\n Directory containing hand-written wiki markdown files.\n\n nav_file (Path):\n Path to the navigation specification file.\n\n template (Path | None):\n Optional custom MkDocs configuration template.\n\n out_dir (Path):\n Output directory for generated MCP resources.\n\nRaises:\n click.UsageError:\n If required options are missing or conflicting."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.serve",
|
||||
"signature": "<bound method Function.signature of Function('serve', 263, 324)>",
|
||||
"docstring": "Serve generated documentation locally.\n\nDepending on the selected mode, this command starts either:\n\n- A MkDocs development server for browsing documentation\n- An MCP server exposing structured documentation resources\n\nArgs:\n mcp (bool):\n Serve documentation using the MCP server.\n\n mkdocs (bool):\n Serve the MkDocs development site.\n\n module (str | None):\n Python module import path to serve via MCP.\n\n mkdocs_yml (Path):\n Path to the MkDocs configuration file.\n\n out_dir (Path):\n Root directory containing MCP documentation resources.\n\nRaises:\n click.UsageError:\n If invalid or conflicting options are provided."
|
||||
"signature": "<bound method Function.signature of Function('serve', 267, 367)>",
|
||||
"docstring": "Serve generated documentation locally.\n\nDepending on the selected mode, this command starts either:\n\n- A MkDocs development server for browsing a site, or\n- An MCP server exposing structured documentation resources\n\nThe kind flags (`--lib`, `--api`, `--wiki`) select the generated\nper-kind config (`docs/mkdocs.{kind}.yml`); `--mkdocs` serves the config\npassed via `--mkdocs-yml`.\n\nArgs:\n mcp (bool):\n Serve documentation using the MCP server.\n\n mkdocs (bool):\n Serve the MkDocs development site from ``--mkdocs-yml``.\n\n lib (bool):\n Serve the lib MkDocs site.\n\n api (bool):\n Serve the API MkDocs site.\n\n wiki (bool):\n Serve the wiki MkDocs site.\n\n module (str | None):\n Python module import path to serve via MCP.\n\n mkdocs_yml (Path):\n Path to the MkDocs configuration file.\n\n out_dir (Path):\n Root directory containing MCP documentation resources.\n\nRaises:\n click.UsageError:\n If invalid or conflicting options are provided."
|
||||
},
|
||||
"tree": {
|
||||
"name": "tree",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.commands.tree",
|
||||
"signature": "<bound method Function.signature of Function('tree', 327, 363)>",
|
||||
"signature": "<bound method Function.signature of Function('tree', 370, 406)>",
|
||||
"docstring": "Display the documentation object tree for a module.\n\nThis command introspects the specified module and prints a\nhierarchical representation of the discovered documentation\nobjects, including modules, classes, functions, and members.\n\nArgs:\n module (str):\n Python module import path to introspect.\n\n project_name (str | None):\n Optional name to display as the project root."
|
||||
},
|
||||
"Group": {
|
||||
@@ -805,15 +840,8 @@
|
||||
"kind": "module",
|
||||
"path": "docforge.cli.mkdocs_utils",
|
||||
"signature": null,
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A single generated `mkdocs.yml` serves lib, api, and wiki content with\n merged navigation. Wiki navigation, when enabled, precedes every other\n group and its `index.md` becomes the site `Home`.\n\n---",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A separate `mkdocs.{kind}.yml` configuration and build is emitted per\n enabled kind (lib, api, wiki), each scoped to its own `docs_dir` and\n written into its own `site_dir` (`site/lib`, `site/api`, `site/wiki`).\n - Navigation blocks are re-rooted per kind: the wiki navigation drops its\n leading `wiki/` scope and the resolved nav spec drops its `lib/` scope.\n\n---",
|
||||
"members": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Iterable": {
|
||||
"name": "Iterable",
|
||||
"kind": "alias",
|
||||
@@ -835,6 +863,20 @@
|
||||
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Any": {
|
||||
"name": "Any",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.Any",
|
||||
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
|
||||
"docstring": null
|
||||
},
|
||||
"cast": {
|
||||
"name": "cast",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.cast",
|
||||
"signature": "<bound method Alias.signature of Alias('cast', 'typing.cast')>",
|
||||
"docstring": null
|
||||
},
|
||||
"click": {
|
||||
"name": "click",
|
||||
"kind": "alias",
|
||||
@@ -950,28 +992,49 @@
|
||||
"name": "generate_sources",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_sources",
|
||||
"signature": "<bound method Function.signature of Function('generate_sources', 34, 83)>",
|
||||
"signature": "<bound method Function.signature of Function('generate_sources', 36, 85)>",
|
||||
"docstring": "Generate MkDocs Markdown sources for a Python module.\n\nThis function introspects the specified module, builds the internal\ndocumentation model, and renders Markdown documentation files for\nuse with MkDocs.\n\nArgs:\n module (str):\n Python module import path used as the entry point for\n documentation generation.\n\n docs_dir (Path):\n Directory where the generated Markdown files will be written.\n\n project_name (str | None):\n Optional override for the project name used in documentation metadata.\n\n module_is_source (bool | None):\n If True, treat the specified module directory as the project root\n rather than a nested module.\n\n readme_dir (Path | None):\n Directory where the generated README.md should be written. If not\n provided, defaults to the parent of ``docs_dir``."
|
||||
},
|
||||
"generate_config": {
|
||||
"name": "generate_config",
|
||||
"build_lib_nav": {
|
||||
"name": "build_lib_nav",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_config",
|
||||
"signature": "<bound method Function.signature of Function('generate_config', 86, 186)>",
|
||||
"docstring": "Generate an `mkdocs.yml` configuration file.\n\nThe configuration is created by combining a template configuration\nwith a navigation structure derived from the docforge navigation\nspecification (and, when a wiki directory is provided, from the wiki\nfile structure).\n\nThe ``docs_dir`` is always written relative to the MkDocs root and is\nexpected to be the shared documentation parent (for example ``docs``),\nwith generated sources nested under ``lib/`` or ``api/`` subdirectories\nand hand-written wiki content under a ``wiki/`` subdirectory.\n\nArgs:\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template.\n If not provided, built-in templates are merged; the provided\n template replaces the built-in templates entirely.\n\n out (Path):\n Destination path where the generated `mkdocs.yml` file will be written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n modes (Iterable[str] | None):\n Documentation modes to enable. Each mode contributes its own\n built-in template fragment (for example ``lib``, ``api``, or\n ``wiki``), merged on top of the shared ``mkdocs.common.yml``\n template.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n wiki_dir (Path | None):\n Optional path to a hand-written wiki directory (for example\n ``docs/wiki``). When provided, the site navigation is derived\n from the wiki file structure and placed before the navigation\n groups defined in ``nav_file``.\n\nRaises:\n click.FileError:\n If the navigation specification, template, or wiki directory\n cannot be found."
|
||||
"path": "docforge.cli.mkdocs_utils.build_lib_nav",
|
||||
"signature": "<bound method Function.signature of Function('build_lib_nav', 88, 121)>",
|
||||
"docstring": "Build the re-rooted navigation block for a lib site.\n\nThe navigation specification is resolved against the shared documentation\nroot and every resulting path is re-rooted relative to the ``lib``\nsubdirectory by stripping its leading ``lib/`` scope component.\n\nArgs:\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n docs_root (Path):\n Shared documentation root containing the ``lib`` sources.\n\nReturns:\n tuple[list[dict[str, Any]], dict[str, str] | None]:\n The re-rooted navigation block and the optional theme icon\n mapping from the specification.\n\nRaises:\n click.FileError:\n If the navigation specification cannot be found."
|
||||
},
|
||||
"build": {
|
||||
"name": "build",
|
||||
"build_wiki_nav_block": {
|
||||
"name": "build_wiki_nav_block",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.build",
|
||||
"signature": "<bound method Function.signature of Function('build', 313, 334)>",
|
||||
"docstring": "Build the MkDocs documentation site.\n\nThis function loads the MkDocs configuration and runs the MkDocs\nbuild command to generate the final static documentation site.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
"path": "docforge.cli.mkdocs_utils.build_wiki_nav_block",
|
||||
"signature": "<bound method Function.signature of Function('build_wiki_nav_block', 124, 147)>",
|
||||
"docstring": "Build the re-rooted navigation block for a wiki site.\n\nThe wiki navigation derived from the wiki file structure is re-rooted\nrelative to the wiki directory itself by stripping the leading ``wiki/``\nscope component.\n\nArgs:\n wiki_dir (Path):\n Path to the hand-written wiki directory, for example ``docs/wiki``.\n\nReturns:\n list[dict[str, Any]]:\n Navigation entries relative to the wiki directory.\n\nRaises:\n click.FileError:\n If the wiki directory does not exist."
|
||||
},
|
||||
"load_spec_icon": {
|
||||
"name": "load_spec_icon",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.load_spec_icon",
|
||||
"signature": "<bound method Function.signature of Function('load_spec_icon', 150, 169)>",
|
||||
"docstring": "Load the theme icon mapping from a navigation specification.\n\nArgs:\n nav_file (Path):\n Path to the navigation specification file.\n\nReturns:\n dict[str, str] | None:\n The icon mapping, or ``None`` when the specification file is\n absent or cannot be parsed."
|
||||
},
|
||||
"generate_site_config": {
|
||||
"name": "generate_site_config",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_site_config",
|
||||
"signature": "<bound method Function.signature of Function('generate_site_config', 201, 282)>",
|
||||
"docstring": "Generate a per-kind `mkdocs.{kind}.yml` configuration file.\n\nThe configuration is created by merging the shared ``mkdocs.common.yml``\ntemplate with the fragment contributed by the kind (``lib``, ``api``, or\n``wiki``). Both ``docs_dir`` and ``site_dir`` are written relative to the\nconfiguration file's directory: the kind's sources when expressed as a\nsibling path (for example ``lib``) and the per-kind site output (for\nexample ``../site/lib``).\n\nArgs:\n kind (str):\n Documentation kind, one of ``lib``, ``api``, or ``wiki``.\n\n kind_root (Path):\n Directory scoped to the kind (for example ``docs/lib``) that\n serves as the MkDocs ``docs_dir``.\n\n nav_block (list[dict[str, Any]]):\n Re-rooted navigation entries for the kind's site.\n\n out (Path):\n Destination path where the generated ``mkdocs.{kind}.yml`` file\n is written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n docs_dir (str):\n MkDocs ``docs_dir`` value, relative to the configuration\n file's directory.\n\n site_dir (str):\n MkDocs ``site_dir`` value, relative to the configuration\n file's directory.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template\n that replaces the built-in templates entirely.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n theme_icon (dict[str, str] | None):\n Optional mapping of theme icon entries injected as\n ``theme.icon``."
|
||||
},
|
||||
"build_configs": {
|
||||
"name": "build_configs",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.build_configs",
|
||||
"signature": "<bound method Function.signature of Function('build_configs', 409, 430)>",
|
||||
"docstring": "Build the MkDocs documentation site for every given configuration.\n\nEach configuration file is loaded and built in turn, producing the\nper-kind static sites (``site/lib``, ``site/api``, ``site/wiki``).\n\nArgs:\n yml_paths (Iterable[Path]):\n Configuration files to build, in order.\n\nRaises:\n click.ClickException:\n If a configuration file does not exist."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.serve",
|
||||
"signature": "<bound method Function.signature of Function('serve', 337, 357)>",
|
||||
"signature": "<bound method Function.signature of Function('serve', 433, 453)>",
|
||||
"docstring": "Start an MkDocs development server with live reload.\n\nThe server watches documentation files and automatically reloads\nthe site when changes are detected.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,8 @@
|
||||
"module": "docforge.cli.mkdocs_utils",
|
||||
"content": {
|
||||
"path": "docforge.cli.mkdocs_utils",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A single generated `mkdocs.yml` serves lib, api, and wiki content with\n merged navigation. Wiki navigation, when enabled, precedes every other\n group and its `index.md` becomes the site `Home`.\n\n---",
|
||||
"docstring": "# Summary\n\nUtilities for working with MkDocs in the doc-forge CLI.\n\n---\n\nNotes:\n - A separate `mkdocs.{kind}.yml` configuration and build is emitted per\n enabled kind (lib, api, wiki), each scoped to its own `docs_dir` and\n written into its own `site_dir` (`site/lib`, `site/api`, `site/wiki`).\n - Navigation blocks are re-rooted per kind: the wiki navigation drops its\n leading `wiki/` scope and the resolved nav spec drops its `lib/` scope.\n\n---",
|
||||
"objects": {
|
||||
"os": {
|
||||
"name": "os",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.os",
|
||||
"signature": "<bound method Alias.signature of Alias('os', 'os')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Iterable": {
|
||||
"name": "Iterable",
|
||||
"kind": "alias",
|
||||
@@ -32,6 +25,20 @@
|
||||
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
|
||||
"docstring": null
|
||||
},
|
||||
"Any": {
|
||||
"name": "Any",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.Any",
|
||||
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
|
||||
"docstring": null
|
||||
},
|
||||
"cast": {
|
||||
"name": "cast",
|
||||
"kind": "alias",
|
||||
"path": "docforge.cli.mkdocs_utils.cast",
|
||||
"signature": "<bound method Alias.signature of Alias('cast', 'typing.cast')>",
|
||||
"docstring": null
|
||||
},
|
||||
"click": {
|
||||
"name": "click",
|
||||
"kind": "alias",
|
||||
@@ -147,28 +154,49 @@
|
||||
"name": "generate_sources",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_sources",
|
||||
"signature": "<bound method Function.signature of Function('generate_sources', 34, 83)>",
|
||||
"signature": "<bound method Function.signature of Function('generate_sources', 36, 85)>",
|
||||
"docstring": "Generate MkDocs Markdown sources for a Python module.\n\nThis function introspects the specified module, builds the internal\ndocumentation model, and renders Markdown documentation files for\nuse with MkDocs.\n\nArgs:\n module (str):\n Python module import path used as the entry point for\n documentation generation.\n\n docs_dir (Path):\n Directory where the generated Markdown files will be written.\n\n project_name (str | None):\n Optional override for the project name used in documentation metadata.\n\n module_is_source (bool | None):\n If True, treat the specified module directory as the project root\n rather than a nested module.\n\n readme_dir (Path | None):\n Directory where the generated README.md should be written. If not\n provided, defaults to the parent of ``docs_dir``."
|
||||
},
|
||||
"generate_config": {
|
||||
"name": "generate_config",
|
||||
"build_lib_nav": {
|
||||
"name": "build_lib_nav",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_config",
|
||||
"signature": "<bound method Function.signature of Function('generate_config', 86, 186)>",
|
||||
"docstring": "Generate an `mkdocs.yml` configuration file.\n\nThe configuration is created by combining a template configuration\nwith a navigation structure derived from the docforge navigation\nspecification (and, when a wiki directory is provided, from the wiki\nfile structure).\n\nThe ``docs_dir`` is always written relative to the MkDocs root and is\nexpected to be the shared documentation parent (for example ``docs``),\nwith generated sources nested under ``lib/`` or ``api/`` subdirectories\nand hand-written wiki content under a ``wiki/`` subdirectory.\n\nArgs:\n docs_dir (Path):\n Shared documentation root used as the MkDocs ``docs_dir``.\n\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template.\n If not provided, built-in templates are merged; the provided\n template replaces the built-in templates entirely.\n\n out (Path):\n Destination path where the generated `mkdocs.yml` file will be written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n modes (Iterable[str] | None):\n Documentation modes to enable. Each mode contributes its own\n built-in template fragment (for example ``lib``, ``api``, or\n ``wiki``), merged on top of the shared ``mkdocs.common.yml``\n template.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n wiki_dir (Path | None):\n Optional path to a hand-written wiki directory (for example\n ``docs/wiki``). When provided, the site navigation is derived\n from the wiki file structure and placed before the navigation\n groups defined in ``nav_file``.\n\nRaises:\n click.FileError:\n If the navigation specification, template, or wiki directory\n cannot be found."
|
||||
"path": "docforge.cli.mkdocs_utils.build_lib_nav",
|
||||
"signature": "<bound method Function.signature of Function('build_lib_nav', 88, 121)>",
|
||||
"docstring": "Build the re-rooted navigation block for a lib site.\n\nThe navigation specification is resolved against the shared documentation\nroot and every resulting path is re-rooted relative to the ``lib``\nsubdirectory by stripping its leading ``lib/`` scope component.\n\nArgs:\n nav_file (Path):\n Path to the `docforge.nav.yml` navigation specification.\n\n docs_root (Path):\n Shared documentation root containing the ``lib`` sources.\n\nReturns:\n tuple[list[dict[str, Any]], dict[str, str] | None]:\n The re-rooted navigation block and the optional theme icon\n mapping from the specification.\n\nRaises:\n click.FileError:\n If the navigation specification cannot be found."
|
||||
},
|
||||
"build": {
|
||||
"name": "build",
|
||||
"build_wiki_nav_block": {
|
||||
"name": "build_wiki_nav_block",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.build",
|
||||
"signature": "<bound method Function.signature of Function('build', 313, 334)>",
|
||||
"docstring": "Build the MkDocs documentation site.\n\nThis function loads the MkDocs configuration and runs the MkDocs\nbuild command to generate the final static documentation site.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
"path": "docforge.cli.mkdocs_utils.build_wiki_nav_block",
|
||||
"signature": "<bound method Function.signature of Function('build_wiki_nav_block', 124, 147)>",
|
||||
"docstring": "Build the re-rooted navigation block for a wiki site.\n\nThe wiki navigation derived from the wiki file structure is re-rooted\nrelative to the wiki directory itself by stripping the leading ``wiki/``\nscope component.\n\nArgs:\n wiki_dir (Path):\n Path to the hand-written wiki directory, for example ``docs/wiki``.\n\nReturns:\n list[dict[str, Any]]:\n Navigation entries relative to the wiki directory.\n\nRaises:\n click.FileError:\n If the wiki directory does not exist."
|
||||
},
|
||||
"load_spec_icon": {
|
||||
"name": "load_spec_icon",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.load_spec_icon",
|
||||
"signature": "<bound method Function.signature of Function('load_spec_icon', 150, 169)>",
|
||||
"docstring": "Load the theme icon mapping from a navigation specification.\n\nArgs:\n nav_file (Path):\n Path to the navigation specification file.\n\nReturns:\n dict[str, str] | None:\n The icon mapping, or ``None`` when the specification file is\n absent or cannot be parsed."
|
||||
},
|
||||
"generate_site_config": {
|
||||
"name": "generate_site_config",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.generate_site_config",
|
||||
"signature": "<bound method Function.signature of Function('generate_site_config', 201, 282)>",
|
||||
"docstring": "Generate a per-kind `mkdocs.{kind}.yml` configuration file.\n\nThe configuration is created by merging the shared ``mkdocs.common.yml``\ntemplate with the fragment contributed by the kind (``lib``, ``api``, or\n``wiki``). Both ``docs_dir`` and ``site_dir`` are written relative to the\nconfiguration file's directory: the kind's sources when expressed as a\nsibling path (for example ``lib``) and the per-kind site output (for\nexample ``../site/lib``).\n\nArgs:\n kind (str):\n Documentation kind, one of ``lib``, ``api``, or ``wiki``.\n\n kind_root (Path):\n Directory scoped to the kind (for example ``docs/lib``) that\n serves as the MkDocs ``docs_dir``.\n\n nav_block (list[dict[str, Any]]):\n Re-rooted navigation entries for the kind's site.\n\n out (Path):\n Destination path where the generated ``mkdocs.{kind}.yml`` file\n is written.\n\n site_name (str):\n Display name for the generated documentation site.\n\n docs_dir (str):\n MkDocs ``docs_dir`` value, relative to the configuration\n file's directory.\n\n site_dir (str):\n MkDocs ``site_dir`` value, relative to the configuration\n file's directory.\n\n template (Path | None):\n Optional path to a fully custom MkDocs configuration template\n that replaces the built-in templates entirely.\n\n site_description (str | None):\n Optional site description written into the configuration.\n\n site_author (str | None):\n Optional site author written into the configuration.\n\n theme_icon (dict[str, str] | None):\n Optional mapping of theme icon entries injected as\n ``theme.icon``."
|
||||
},
|
||||
"build_configs": {
|
||||
"name": "build_configs",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.build_configs",
|
||||
"signature": "<bound method Function.signature of Function('build_configs', 409, 430)>",
|
||||
"docstring": "Build the MkDocs documentation site for every given configuration.\n\nEach configuration file is loaded and built in turn, producing the\nper-kind static sites (``site/lib``, ``site/api``, ``site/wiki``).\n\nArgs:\n yml_paths (Iterable[Path]):\n Configuration files to build, in order.\n\nRaises:\n click.ClickException:\n If a configuration file does not exist."
|
||||
},
|
||||
"serve": {
|
||||
"name": "serve",
|
||||
"kind": "function",
|
||||
"path": "docforge.cli.mkdocs_utils.serve",
|
||||
"signature": "<bound method Function.signature of Function('serve', 337, 357)>",
|
||||
"signature": "<bound method Function.signature of Function('serve', 433, 453)>",
|
||||
"docstring": "Start an MkDocs development server with live reload.\n\nThe server watches documentation files and automatically reloads\nthe site when changes are detected.\n\nArgs:\n mkdocs_yml (Path):\n Path to the `mkdocs.yml` configuration file.\n\nRaises:\n click.ClickException:\n If the configuration file does not exist."
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -67,40 +67,32 @@ plugins:
|
||||
show_object_full_path: false
|
||||
show_symbol_type_heading: true
|
||||
site_name: docforge
|
||||
docs_dir: docs
|
||||
docs_dir: lib
|
||||
site_dir: ../site/lib
|
||||
nav:
|
||||
- Home: wiki/index.md
|
||||
- Overview: wiki/01_overview.md
|
||||
- Architecture: wiki/02_architecture.md
|
||||
- Conventions: wiki/03_conventions.md
|
||||
- Iterative Workflow: wiki/04_iterative_workflow.md
|
||||
- Development:
|
||||
- Environment: wiki/05_development/01_environment.md
|
||||
- Quality Gates: wiki/05_development/02_quality_gates.md
|
||||
- Gsdfc Guide: wiki/05_development/03_gsdfc_guide.md
|
||||
- Mcp Guide: wiki/05_development/04_mcp_guide.md
|
||||
- Home: index.md
|
||||
- Loaders:
|
||||
- lib/loaders/index.md
|
||||
- lib/loaders/griffe_loader.md
|
||||
- loaders/index.md
|
||||
- loaders/griffe_loader.md
|
||||
- Models:
|
||||
- lib/models/index.md
|
||||
- lib/models/module.md
|
||||
- lib/models/object.md
|
||||
- lib/models/project.md
|
||||
- models/index.md
|
||||
- models/module.md
|
||||
- models/object.md
|
||||
- models/project.md
|
||||
- Navigation:
|
||||
- lib/nav/index.md
|
||||
- lib/nav/spec.md
|
||||
- lib/nav/resolver.md
|
||||
- lib/nav/mkdocs.md
|
||||
- nav/index.md
|
||||
- nav/spec.md
|
||||
- nav/resolver.md
|
||||
- nav/mkdocs.md
|
||||
- Renderers:
|
||||
- lib/renderers/index.md
|
||||
- lib/renderers/base.md
|
||||
- lib/renderers/mkdocs_renderer.md
|
||||
- lib/renderers/mcp_renderer.md
|
||||
- renderers/index.md
|
||||
- renderers/base.md
|
||||
- renderers/mkdocs_renderer.md
|
||||
- renderers/mcp_renderer.md
|
||||
- CLI:
|
||||
- lib/cli/index.md
|
||||
- lib/cli/main.md
|
||||
- lib/cli/commands.md
|
||||
- lib/cli/api_utils.md
|
||||
- lib/cli/mcp_utils.md
|
||||
- lib/cli/mkdocs_utils.md
|
||||
- cli/index.md
|
||||
- cli/main.md
|
||||
- cli/commands.md
|
||||
- cli/api_utils.md
|
||||
- cli/mcp_utils.md
|
||||
- cli/mkdocs_utils.md
|
||||
64
docs/mkdocs.wiki.yml
Normal file
64
docs/mkdocs.wiki.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
theme:
|
||||
name: material
|
||||
palette:
|
||||
- scheme: slate
|
||||
primary: deep purple
|
||||
accent: cyan
|
||||
font:
|
||||
text: Inter
|
||||
code: JetBrains Mono
|
||||
features:
|
||||
- navigation.sections
|
||||
- navigation.expand
|
||||
- navigation.top
|
||||
- navigation.instant
|
||||
- navigation.tracking
|
||||
- navigation.indexes
|
||||
- content.code.copy
|
||||
- content.code.annotate
|
||||
- content.tabs.link
|
||||
- content.action.edit
|
||||
- search.highlight
|
||||
- search.share
|
||||
- search.suggest
|
||||
icon:
|
||||
logo: material/file-document-multiple
|
||||
repo: fontawesome/brands/github
|
||||
markdown_extensions:
|
||||
- pymdownx.superfences
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.highlight:
|
||||
linenums: true
|
||||
anchor_linenums: true
|
||||
line_spans: __span
|
||||
pygments_lang_class: true
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
- tables
|
||||
- footnotes
|
||||
- pymdownx.caret
|
||||
- pymdownx.tilde
|
||||
- pymdownx.mark
|
||||
extra_css:
|
||||
- https://unpkg.com/dracula-prism/dist/css/dracula-prism.css
|
||||
plugins:
|
||||
- search
|
||||
site_name: docforge
|
||||
docs_dir: wiki
|
||||
site_dir: ../site/wiki
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Overview: 01_overview.md
|
||||
- Architecture: 02_architecture.md
|
||||
- Conventions: 03_conventions.md
|
||||
- Iterative Workflow: 04_iterative_workflow.md
|
||||
- Development:
|
||||
- Environment: 05_development/01_environment.md
|
||||
- Quality Gates: 05_development/02_quality_gates.md
|
||||
- Gsdfc Guide: 05_development/03_gsdfc_guide.md
|
||||
- Mcp Guide: 05_development/04_mcp_guide.md
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
`docforge` turns GSDFC-compliant Python docstrings into maintainable reference
|
||||
documentation. It never edits source docstrings; it reads them, renders them,
|
||||
and assembles a single MkDocs site from all available material.
|
||||
and assembles documentation sites from all available material.
|
||||
|
||||
## What it generates
|
||||
|
||||
@@ -13,16 +13,17 @@ and assembles a single MkDocs site from all available material.
|
||||
| `wiki` | Hand-written markdown | `docs/wiki/**` (unchanged) |
|
||||
| `mcp` | GSDFC docstrings + renderers | `docs/mcp/**` structured JSON |
|
||||
|
||||
## Combined build
|
||||
## Per-kind MkDocs builds
|
||||
|
||||
One `mkdocs.yml` and one MkDocs build serve all kinds:
|
||||
Each enabled site kind produces its own MkDocs configuration and build:
|
||||
|
||||
1. Wiki navigation is derived from the `docs/wiki/` file structure.
|
||||
2. Generated library/API navigation is appended after it.
|
||||
3. The wiki `index.md` becomes the site `Home`.
|
||||
1. `--mkdocs` (lib) writes `docs/mkdocs.lib.yml` and builds `site/lib/`.
|
||||
2. `--api` writes `docs/mkdocs.api.yml` and builds `site/api/`.
|
||||
3. `--wiki` writes `docs/mkdocs.wiki.yml` and builds `site/wiki/`.
|
||||
|
||||
Hand-written wiki content is never overwritten or regenerated — only its
|
||||
navigation is derived automatically.
|
||||
Every site is self-contained (own theme assets and search index) with
|
||||
navigation derived or scoped to that kind. Hand-written wiki content is never
|
||||
overwritten or regenerated — only its navigation is derived automatically.
|
||||
|
||||
## MCP bundle
|
||||
|
||||
|
||||
@@ -35,6 +35,6 @@ file structure via `build_wiki_nav`.
|
||||
|
||||
- `commands.py` — the `build` command and its `--mkdocs` / `--api` / `--wiki`
|
||||
/ `--mcp` modes
|
||||
- `mkdocs_utils.py` — config generation (`mkdocs.yml`) including merged
|
||||
wiki + lib + api navigation
|
||||
- `mkdocs_utils.py` — per-kind config generation (`docs/mkdocs.{lib,api,wiki}.yml`)
|
||||
with navigation re-rooted to each kind's `docs_dir`
|
||||
- `api_utils.py` — OpenAPI loading and API docs generation
|
||||
@@ -8,7 +8,7 @@ A docs build runs through the CLI in a single pass.
|
||||
# Library reference only
|
||||
doc-forge build --mkdocs --module docforge
|
||||
|
||||
# Wiki + library combined (single MkDocs build)
|
||||
# Wiki + library (each an independent MkDocs build)
|
||||
doc-forge build --wiki --mkdocs --module docforge
|
||||
|
||||
# Wiki only — no module required
|
||||
@@ -18,21 +18,26 @@ doc-forge build --wiki --site-name docforge
|
||||
doc-forge build --mcp --module docforge
|
||||
```
|
||||
|
||||
## What a combined build does
|
||||
## What a build does
|
||||
|
||||
1. Validates the requested modes (`--mkdocs`, `--api`, `--wiki`, `--mcp`).
|
||||
2. Generates library sources under `docs/lib/**` with `MkDocsRenderer`.
|
||||
3. Generates API sources under `docs/api/**` when `--api` is given.
|
||||
4. Derives wiki navigation from `docs/wiki/**`.
|
||||
5. Writes `mkdocs.yml` with merged navigation — wiki first, generated groups
|
||||
appended, and the wiki `Home` replacing any spec `Home` entry.
|
||||
6. Runs `mkdocs build` once and emits the site.
|
||||
4. Derives the wiki navigation from `docs/wiki/**`.
|
||||
5. Writes one MkDocs config per site kind (`docs/mkdocs.{lib,api,wiki}.yml`),
|
||||
re-rooting navigation paths to each kind's `docs_dir`.
|
||||
6. Runs `mkdocs build` once per config, emitting self-contained sites
|
||||
`site/lib/`, `site/api/`, and `site/wiki/`.
|
||||
|
||||
## Explore the site
|
||||
## Explore the sites
|
||||
|
||||
```bash
|
||||
doc-forge build --wiki --mkdocs --module docforge
|
||||
doc-forge serve --mkdocs --mkdocs-yml mkdocs.yml
|
||||
doc-forge serve --wiki # serves site preview from docs/mkdocs.wiki.yml
|
||||
doc-forge serve --lib
|
||||
doc-forge serve --api
|
||||
# or target any config directly:
|
||||
doc-forge serve --mkdocs --mkdocs-yml docs/mkdocs.wiki.yml
|
||||
```
|
||||
|
||||
## Serve the MCP bundle
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
`docforge` is an internal documentation tool that generates reference
|
||||
documentation from Google-Styled Doc-Forge Convention (GSDFC) docstrings and
|
||||
assembles it into a single MkDocs site, alongside hand-written wiki pages and
|
||||
assembles it into per-kind MkDocs sites, alongside hand-written wiki pages and
|
||||
OpenAPI-based API docs.
|
||||
|
||||
---
|
||||
@@ -11,7 +11,7 @@ OpenAPI-based API docs.
|
||||
|
||||
- 🧪 GSDFC docstring extraction via Griffe
|
||||
- 🧭 Auto-derived navigation for hand-written wiki pages
|
||||
- 🗂 Combined MkDocs build: wiki first, then generated library/API reference
|
||||
- 🗂 Independent MkDocs builds per kind (lib, api, wiki) into `site/{kind}`
|
||||
- 🔌 Material MkDocs theming out of the box
|
||||
- 📦 MCP structured documentation resources
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import json
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from docforge.cli.main import cli
|
||||
@@ -55,8 +55,10 @@ def test_api_build_full_flow(
|
||||
index = (api_dir / "index.md").read_text(encoding="utf-8")
|
||||
assert '<swagger-ui src="openapi.json"/>' in index
|
||||
|
||||
config = (cwd / "mkdocs.yml").read_text(encoding="utf-8")
|
||||
assert "docs_dir: docs" in config
|
||||
config = (cwd / "docs" / "mkdocs.api.yml").read_text(encoding="utf-8")
|
||||
assert "docs_dir: api" in config
|
||||
assert "site_dir: ../site/api" in config
|
||||
assert "- API Reference: index.md" in config
|
||||
assert "site_name: Aetoskia Auth Server" in config
|
||||
assert "site_description: Auth docs" in config
|
||||
assert "site_author: Aetoskia Dev Team" in config
|
||||
@@ -90,10 +92,9 @@ def test_api_build_rejects_site_name_override(cli_runner):
|
||||
assert "cannot be overridden" in result.output
|
||||
|
||||
|
||||
def test_api_build_combined_with_mkdocs_allows_site_name_for_lib(
|
||||
def test_api_build_combined_with_mkdocs_emits_separate_configs(
|
||||
cli_runner, mock_mkdocs_build, mock_mkdocs_load_config
|
||||
):
|
||||
# site_name is accepted when --mkdocs is also present (lib mode owns it)
|
||||
with cli_runner.isolated_filesystem():
|
||||
cwd = Path.cwd()
|
||||
|
||||
@@ -105,13 +106,7 @@ def test_api_build_combined_with_mkdocs_allows_site_name_for_lib(
|
||||
spec_path = _write_spec(cwd)
|
||||
|
||||
nav_file = cwd / "docforge.nav.yml"
|
||||
nav_file.write_text(
|
||||
"home: lib/testpkg/index.md\n"
|
||||
"groups:\n"
|
||||
" API:\n"
|
||||
" - api/index.md\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
nav_file.write_text("home: lib/testpkg/index.md\ngroups: {}\n")
|
||||
|
||||
result = cli_runner.invoke(
|
||||
cli,
|
||||
@@ -128,7 +123,20 @@ def test_api_build_combined_with_mkdocs_allows_site_name_for_lib(
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
|
||||
config = (cwd / "mkdocs.yml").read_text(encoding="utf-8")
|
||||
assert "docs_dir: docs" in config
|
||||
assert "swagger-ui-tag" in config
|
||||
assert "mkdocstrings" in config
|
||||
lib_config = cwd / "docs" / "mkdocs.lib.yml"
|
||||
api_config = cwd / "docs" / "mkdocs.api.yml"
|
||||
assert lib_config.exists()
|
||||
assert api_config.exists()
|
||||
|
||||
lib_text = lib_config.read_text(encoding="utf-8")
|
||||
assert "docs_dir: lib" in lib_text
|
||||
assert "site_dir: ../site/lib" in lib_text
|
||||
assert "Home: testpkg/index.md" in lib_text
|
||||
|
||||
api_text = api_config.read_text(encoding="utf-8")
|
||||
assert "docs_dir: api" in api_text
|
||||
assert "site_dir: ../site/api" in api_text
|
||||
assert "- API Reference: index.md" in api_text
|
||||
assert "site_name: Aetoskia Auth Server" in api_text
|
||||
assert "swagger-ui-tag" in api_text
|
||||
assert "mkdocstrings" in lib_text
|
||||
|
||||
@@ -20,10 +20,6 @@ def test_mkdocs_build_full_flow(
|
||||
nav_file = cwd / "docforge.nav.yml"
|
||||
nav_file.write_text("home: lib/testpkg/index.md\ngroups: {}\n")
|
||||
|
||||
# We need to create a dummy testpkg/index.md for nav resolution if it's there
|
||||
# But generate_sources will create it.
|
||||
# Wait, the current logic runs generate_sources first, THEN generate_config.
|
||||
|
||||
result = cli_runner.invoke(
|
||||
cli,
|
||||
[
|
||||
@@ -33,16 +29,19 @@ def test_mkdocs_build_full_flow(
|
||||
"testpkg",
|
||||
"--site-name",
|
||||
"Test Site",
|
||||
"--mkdocs-yml",
|
||||
"mkdocs.yml",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert mock_mkdocs_build() is True
|
||||
assert (cwd / "mkdocs.yml").exists()
|
||||
|
||||
config = cwd / "docs" / "mkdocs.lib.yml"
|
||||
assert config.exists()
|
||||
assert (cwd / "docs" / "lib" / "testpkg" / "mod.md").exists()
|
||||
assert "docs_dir: docs" in (cwd / "mkdocs.yml").read_text()
|
||||
content = config.read_text(encoding="utf-8")
|
||||
assert "docs_dir: lib" in content
|
||||
assert "site_dir: ../site/lib" in content
|
||||
assert "Home: testpkg/index.md" in content
|
||||
|
||||
|
||||
def test_mkdocs_build_missing_module_fails(cli_runner):
|
||||
@@ -66,7 +65,7 @@ def test_mkdocs_build_without_site_name_uses_module_as_default_full_flow(
|
||||
(pkg / "__init__.py").write_text("")
|
||||
(pkg / "mod.py").write_text("def f(): ...\n")
|
||||
|
||||
# Create nav spec expected by generate_config
|
||||
# Create nav spec expected by build_lib_nav
|
||||
nav_file = cwd / "docforge.nav.yml"
|
||||
nav_file.write_text(
|
||||
"home: lib/testpkg/index.md\ngroups: {}\n",
|
||||
@@ -75,25 +74,18 @@ def test_mkdocs_build_without_site_name_uses_module_as_default_full_flow(
|
||||
|
||||
result = cli_runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"build",
|
||||
"--mkdocs",
|
||||
"--module",
|
||||
"testpkg",
|
||||
"--mkdocs-yml",
|
||||
"mkdocs.yml",
|
||||
],
|
||||
["build", "--mkdocs", "--module", "testpkg"],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert mock_mkdocs_build() is True
|
||||
|
||||
# MkDocs config must exist
|
||||
mkdocs_yml = cwd / "mkdocs.yml"
|
||||
assert mkdocs_yml.exists()
|
||||
# The per-kind MkDocs config must exist
|
||||
config = cwd / "docs" / "mkdocs.lib.yml"
|
||||
assert config.exists()
|
||||
|
||||
# Site name must default to module name
|
||||
content = mkdocs_yml.read_text()
|
||||
content = config.read_text(encoding="utf-8")
|
||||
assert "site_name: testpkg" in content
|
||||
|
||||
# Docs must be generated under the nested docs/lib dir
|
||||
|
||||
@@ -23,22 +23,22 @@ def test_wiki_only_build_requires_no_module(
|
||||
"--wiki",
|
||||
"--site-name",
|
||||
"Wiki Site",
|
||||
"--mkdocs-yml",
|
||||
"mkdocs.yml",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert mock_mkdocs_build() is True
|
||||
assert (cwd / "mkdocs.yml").exists()
|
||||
config = cwd / "docs" / "mkdocs.wiki.yml"
|
||||
assert config.exists()
|
||||
|
||||
content = (cwd / "mkdocs.yml").read_text(encoding="utf-8")
|
||||
assert "docs_dir: docs" in content
|
||||
assert "Home: wiki/index.md" in content
|
||||
assert "Overview: wiki/01_overview.md" in content
|
||||
content = config.read_text(encoding="utf-8")
|
||||
assert "docs_dir: wiki" in content
|
||||
assert "site_dir: ../site/wiki" in content
|
||||
assert "Home: index.md" in content
|
||||
assert "Overview: 01_overview.md" in content
|
||||
|
||||
|
||||
def test_wiki_combined_with_mkdocs_keeps_lib_nav(
|
||||
def test_wiki_and_mkdocs_emit_separate_configs(
|
||||
cli_runner,
|
||||
mock_mkdocs_build,
|
||||
mock_mkdocs_load_config,
|
||||
@@ -70,9 +70,7 @@ def test_wiki_combined_with_mkdocs_keeps_lib_nav(
|
||||
"--module",
|
||||
"testpkg",
|
||||
"--site-name",
|
||||
"Combined Site",
|
||||
"--mkdocs-yml",
|
||||
"mkdocs.yml",
|
||||
"Split Site",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -80,11 +78,16 @@ def test_wiki_combined_with_mkdocs_keeps_lib_nav(
|
||||
assert mock_mkdocs_build() is True
|
||||
assert (cwd / "docs" / "lib" / "testpkg" / "mod.md").exists()
|
||||
|
||||
content = (cwd / "mkdocs.yml").read_text(encoding="utf-8")
|
||||
assert "docs_dir: docs" in content
|
||||
assert "Home: wiki/index.md" in content
|
||||
# Wiki home replaces the lib home entry
|
||||
assert "Home: lib/testpkg/index.md" not in content
|
||||
lib_config = (cwd / "docs" / "mkdocs.lib.yml").read_text(encoding="utf-8")
|
||||
wiki_config = (cwd / "docs" / "mkdocs.wiki.yml").read_text(encoding="utf-8")
|
||||
|
||||
assert "docs_dir: lib" in lib_config
|
||||
assert "site_dir: ../site/lib" in lib_config
|
||||
assert "Home: testpkg/index.md" in lib_config
|
||||
|
||||
assert "docs_dir: wiki" in wiki_config
|
||||
assert "site_dir: ../site/wiki" in wiki_config
|
||||
assert "Home: index.md" in wiki_config
|
||||
|
||||
|
||||
def test_wiki_without_module_flag_ok(
|
||||
@@ -122,8 +125,6 @@ def test_missing_wiki_dir_errors(cli_runner, mock_mkdocs_build):
|
||||
"S",
|
||||
"--wiki-dir",
|
||||
"docs/wiki",
|
||||
"--mkdocs-yml",
|
||||
"mkdocs.yml",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
79
tests/cli/test_mkdocs_utils.py
Normal file
79
tests/cli/test_mkdocs_utils.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import pytest
|
||||
from click.exceptions import FileError
|
||||
|
||||
from docforge.cli.mkdocs_utils import (
|
||||
_strip_scope,
|
||||
build_lib_nav,
|
||||
build_wiki_nav_block,
|
||||
load_spec_icon,
|
||||
)
|
||||
|
||||
|
||||
def test_strip_scope_nested_entries():
|
||||
block = [
|
||||
{"Home": "wiki/index.md"},
|
||||
{
|
||||
"Development": [
|
||||
{"Environment": "wiki/05_development/01_environment.md"},
|
||||
"wiki/05_development/02_quality_gates.md",
|
||||
]
|
||||
},
|
||||
]
|
||||
stripped = _strip_scope(block, "wiki")
|
||||
assert stripped == [
|
||||
{"Home": "index.md"},
|
||||
{
|
||||
"Development": [
|
||||
{"Environment": "05_development/01_environment.md"},
|
||||
"05_development/02_quality_gates.md",
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def test_strip_scope_leaves_unscoped_paths():
|
||||
block = [{"Other": "static/pages.md"}]
|
||||
assert _strip_scope(block, "lib") == [{"Other": "static/pages.md"}]
|
||||
|
||||
|
||||
def test_build_lib_nav_reroots_group_paths(tmp_path):
|
||||
docs = tmp_path / "docs"
|
||||
lib = docs / "lib" / "testpkg"
|
||||
lib.mkdir(parents=True)
|
||||
(lib / "index.md").write_text("# Pkg", encoding="utf-8")
|
||||
(lib / "mod.md").write_text("# Mod", encoding="utf-8")
|
||||
|
||||
nav_file = tmp_path / "docforge.nav.yml"
|
||||
nav_file.write_text(
|
||||
"home: lib/testpkg/index.md\n"
|
||||
"groups:\n"
|
||||
" Reference:\n"
|
||||
" - lib/testpkg/mod.md\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
block, icon = build_lib_nav(nav_file, docs)
|
||||
assert block == [{"Home": "testpkg/index.md"}, {"Reference": ["testpkg/mod.md"]}]
|
||||
assert icon is None
|
||||
|
||||
|
||||
def test_build_lib_nav_missing_spec_raises(tmp_path):
|
||||
with pytest.raises(FileError):
|
||||
build_lib_nav(tmp_path / "missing.yml", tmp_path)
|
||||
|
||||
|
||||
def test_build_wiki_nav_block_reroots_entries(tmp_path):
|
||||
wiki = tmp_path / "docs" / "wiki"
|
||||
wiki.mkdir(parents=True)
|
||||
(wiki / "index.md").write_text("# Home", encoding="utf-8")
|
||||
(wiki / "01_overview.md").write_text("# Overview", encoding="utf-8")
|
||||
|
||||
block = build_wiki_nav_block(wiki)
|
||||
assert block == [{"Home": "index.md"}, {"Overview": "01_overview.md"}]
|
||||
|
||||
|
||||
def test_load_spec_icon(tmp_path):
|
||||
nav_file = tmp_path / "docforge.nav.yml"
|
||||
nav_file.write_text("home: index.md\nicon:\n logo: material/code-tags\n")
|
||||
assert load_spec_icon(nav_file) == {"logo": "material/code-tags"}
|
||||
assert load_spec_icon(tmp_path / "missing.yml") is None
|
||||
Reference in New Issue
Block a user