init docforge lib

This commit is contained in:
2026-01-20 18:22:16 +05:30
parent 86a4f8f41a
commit a45725160d
28 changed files with 3486 additions and 0 deletions

210
docforge/model/nav.py Normal file
View File

@@ -0,0 +1,210 @@
"""Navigation structure for doc-forge documentation.
Navigation provides a hierarchical structure for organizing documentation
modules. It is derived automatically from the project structure rather
than being manually authored, ensuring consistency between the
documentation model and the navigation.
The navigation is used by renderers to generate table of contents,
sidebars, and other navigation elements.
"""
from __future__ import annotations
from typing import Dict, List, Optional
class NavEntry:
"""Single navigation entry linking to a module.
A NavEntry represents one item in the documentation navigation,
typically corresponding to a module. It contains a display title
and the module path it links to.
Attributes:
title: The display title for this navigation entry
module: The import path of the module this entry links to
"""
def __init__(self, title: str, module: str) -> None:
"""Initialize a NavEntry.
Args:
title: The display title for this entry
module: The import path of the linked module
Raises:
ValueError: If title or module is empty
"""
if not title:
raise ValueError("NavEntry title cannot be empty")
if not module:
raise ValueError("NavEntry module cannot be empty")
self.title: str = title
self.module: str = module
def __repr__(self) -> str:
"""Return a string representation of the NavEntry.
Returns:
String representation showing title and module
"""
return f"NavEntry(title='{self.title}', module='{self.module}')"
class Navigation:
"""Navigation structure derived from project modules.
Navigation provides an organized hierarchy for browsing documentation.
It is automatically generated from the project's module structure,
ensuring that the navigation always reflects the actual available
documentation.
The navigation can be customized by:
- Changing the order of entries
- Grouping related modules
- Providing custom titles
Attributes:
entries: List of navigation entries in order
"""
def __init__(self) -> None:
"""Initialize an empty Navigation."""
self.entries: List[NavEntry] = []
def add_entry(self, entry: NavEntry) -> None:
"""Add a navigation entry.
Args:
entry: The navigation entry to add
"""
self.entries.append(entry)
def add_entry_by_module(self, module: str, title: Optional[str] = None) -> None:
"""Add a navigation entry for a module.
This is a convenience method that creates a NavEntry from a module
path. If no title is provided, the module name is used as the title.
Args:
module: The import path of the module
title: Optional custom title (defaults to module name)
"""
if title is None:
# Use the last part of the module path as the title
title = module.split('.')[-1].replace('_', ' ').title()
entry = NavEntry(title, module)
self.add_entry(entry)
def get_entry(self, title: str) -> Optional[NavEntry]:
"""Get a navigation entry by title.
Args:
title: The title of the entry to find
Returns:
The NavEntry if found, None otherwise
"""
for entry in self.entries:
if entry.title == title:
return entry
return None
def get_entry_by_module(self, module: str) -> Optional[NavEntry]:
"""Get a navigation entry by module path.
Args:
module: The module path to search for
Returns:
The NavEntry if found, None otherwise
"""
for entry in self.entries:
if entry.module == module:
return entry
return None
def remove_entry(self, title: str) -> bool:
"""Remove a navigation entry by title.
Args:
title: The title of the entry to remove
Returns:
True if entry was removed, False if not found
"""
for i, entry in enumerate(self.entries):
if entry.title == title:
del self.entries[i]
return True
return False
def remove_entry_by_module(self, module: str) -> bool:
"""Remove a navigation entry by module path.
Args:
module: The module path of the entry to remove
Returns:
True if entry was removed, False if not found
"""
for i, entry in enumerate(self.entries):
if entry.module == module:
del self.entries[i]
return True
return False
def reorder_entries(self, titles: List[str]) -> None:
"""Reorder entries based on provided title order.
Entries not mentioned in the titles list will maintain their
relative order and be placed after the specified entries.
Args:
titles: List of titles in the desired order
"""
# Create a mapping of title to entry for quick lookup
entry_map = {entry.title: entry for entry in self.entries}
# Build new ordered list
ordered_entries = []
remaining_entries = list(self.entries)
# Add entries in specified order
for title in titles:
if title in entry_map:
ordered_entries.append(entry_map[title])
# Remove from remaining entries
remaining_entries = [e for e in remaining_entries if e.title != title]
# Add remaining entries in their original order
ordered_entries.extend(remaining_entries)
self.entries = ordered_entries
def is_empty(self) -> bool:
"""Check if navigation has no entries.
Returns:
True if navigation has no entries, False otherwise
"""
return len(self.entries) == 0
def get_module_list(self) -> List[str]:
"""Get list of all module paths in navigation.
Returns:
List of module paths in navigation order
"""
return [entry.module for entry in self.entries]
def __repr__(self) -> str:
"""Return a string representation of the Navigation.
Returns:
String representation showing entry count
"""
return f"Navigation(entries={len(self.entries)})"