Files
doc-forge/mcp_docs/modules/docforge.cli.mkdocs_utils.json
Vishesh 'ironeagle' Bangotra 22fceef020 Flatten MkDocs Structure + --module-is-source Support (#4)
# Merge Request: Flatten MkDocs Structure + `--module-is-source` Support

## Summary

This MR introduces structural improvements to the MkDocs generation pipeline to:

1. Ensure a root `docs/index.md` always exists
2. Flatten documentation structure (remove `docs/<module>/` nesting by default)
3. Add support for `--module-is-source` to treat the module as the documentation root
4. Align navigation (`docforge.nav.yml`) with the new flat layout
5. Regenerate MCP artifacts to reflect updated signatures and docstrings

This resolves static hosting issues (e.g., Nginx 403 due to missing `site/index.html`) and makes each generated MkDocs site deployable as a standalone static website.

---

## Motivation

Previously, documentation was generated under:

```
docs/<module>/...
```

Which resulted in:

```
site/<module>/index.html
```

When deployed at `/libs/<project>/`, this caused:

* Missing `site/index.html`
* Nginx returning 403 for root access
* Inconsistent static hosting behavior

This MR corrects the architecture so each MkDocs build is a valid static site with a root entry point.

---

## Key Changes

### 1️⃣ Flattened Docs Structure

**Before**

```
docs/docforge/index.md
```

**After**

```
docs/index.md
```

All documentation paths were updated accordingly:

* `docs/docforge/cli/...` → `docs/cli/...`
* `docs/docforge/models/...` → `docs/models/...`
* `docs/docforge/renderers/...` → `docs/renderers/...`

Navigation updated to match the flat layout.

---

### 2️⃣ Root Index Enforcement

`MkDocsRenderer` now guarantees:

* `docs/index.md` is always created
* Parent `index.md` files are auto-generated if missing
* Parent indexes link to child modules (idempotent behavior)

This ensures:

```
site/index.html
```

Always exists after `mkdocs build`.

---

### 3️⃣ New CLI Flag: `--module-is-source`

Added option:

```
--module-is-source
```

Behavior:

* Treats the provided module as the documentation root
* Removes the top-level module folder from generated paths
* Prevents redundant nesting when the module corresponds to the source root

Updated components:

* `cli.commands.build`
* `mkdocs_utils.generate_sources`
* `MkDocsRenderer.generate_sources`
* Stub files (`.pyi`)
* MCP JSON artifacts

---

### 4️⃣ Navigation Spec Update

`docforge.nav.yml` updated:

**Before**

```yaml
home: docforge/index.md
```

**After**

```yaml
home: index.md
```

All group paths adjusted to remove `docforge/` prefix.

---

### 5️⃣ MkDocs Config Update

`mkdocs.yml` updated to:

* Move `site_name` below theme/plugins
* Use flat navigation paths
* Point Home to `index.md`

---

### 6️⃣ MCP Artifact Regeneration

Updated:

* Function signatures (new parameter)
* Docstrings (reflect `module_is_source`)
* Renderer metadata
* Line numbers

Ensures MCP output matches updated API.

---

## Architectural Outcome

Each project now produces a **valid standalone static site**:

```
site/
  index.html
  assets/
  search/
```

Safe for deployment under:

```
/libs/<project>/
```

No Nginx rewrites required.
No directory-index issues.
No nested-site ambiguity.

---

## Backward Compatibility

* Existing CLI usage remains valid
* `--module-is-source` is optional
* Navigation spec format unchanged (only paths adjusted)

---

## Deployment Impact

After merge:

* Each library can be deployed independently
* Sites can be merged under a shared root without internal conflicts
* Static hosting is predictable and production-safe

---

## Testing

* Verified MkDocs build produces `site/index.html`
* Verified navigation renders correctly
* Verified parent index generation is idempotent
* Regenerated MCP docs and validated schema consistency

---

## Result

The documentation compiler now:

* Produces structurally correct static sites
* Supports flat and source-root modes
* Eliminates 403 root issues
* Scales cleanly across multiple repositories

This aligns doc-forge with proper static-site architectural invariants.

Reviewed-on: #4
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
2026-02-21 16:16:36 +00:00

148 lines
8.8 KiB
JSON

{
"module": "docforge.cli.mkdocs_utils",
"content": {
"path": "docforge.cli.mkdocs_utils",
"docstring": null,
"objects": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MkDocsRenderer": {
"name": "MkDocsRenderer",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.renderers.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files.\n module_is_source: Module is the source folder and to be treated as the root folder."
}
}
},
"load_nav_spec": {
"name": "load_nav_spec",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.nav.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
},
"resolve_nav": {
"name": "resolve_nav",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.nav.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
},
"MkDocsNavEmitter": {
"name": "MkDocsNavEmitter",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.nav.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": {
"emit": {
"name": "emit",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
}
}
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.generate_sources",
"signature": "<bound method Function.signature of Function('generate_sources', 9, 33)>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n docs_dir: Directory where the generated Markdown files will be written.\n module_is_source: Module is the source folder and to be treated as the root folder."
},
"generate_config": {
"name": "generate_config",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.generate_config",
"signature": "<bound method Function.signature of Function('generate_config', 35, 69)>",
"docstring": "Generate an mkdocs.yml configuration file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template (overrides built-in).\n out: Path where the final mkdocs.yml will be written.\n site_name: The display name for the documentation site."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.build",
"signature": "<bound method Function.signature of Function('build', 71, 84)>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.serve",
"signature": "<bound method Function.signature of Function('serve', 86, 97)>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}
}
}
}