Component Contracts (Class Interfaces)
This document defines the strict Python interfaces and class contracts for the core components of the Universal Documentation Engine (UDE) to ensure loose coupling and modular extensibility.
Strict Portability Principle: Physical file and directory paths must never be hardcoded inside any of the component classes or engine implementation code. All paths must be loaded from configurations as relative paths (relative to the configuration file location) and resolved dynamically to absolute paths by the UDE Orchestrator at startup before being passed to components.
Exception Hierarchy
All custom errors in UDE inherit from a unified base exception to enable robust CLI error reporting.
:::note v1.0 Correction (GAP-02)
The base class is UdeException (not UdeError) in line with Python naming conventions. CollectorError is present in the v1.0 codebase (engine/ude/interfaces.py) and covers collector lifecycle failures. All five subclasses below are the authoritative v1.0 hierarchy.
:::
class UdeException(Exception):
"""Base exception for all Universal Documentation Engine errors."""
pass
class ParserError(UdeException):
"""Raised when parsing fails or input files are corrupted."""
pass
class RendererError(UdeException):
"""Raised when template compilation or output generation fails."""
pass
class CollectorError(UdeException):
"""Raised when the collector lifecycle fails (e.g. Doxygen subprocess errors)."""
pass
class ValidationError(UdeException):
"""Raised when the Intermediate Representation fails Pydantic schema validation."""
pass
class EnvironmentError(UdeException):
"""Raised when required software binaries (e.g. Doxygen) or configurations are missing."""
pass
Collector Interface (Preprocessing / Ingestion)
The Collector component is responsible for retrieving, compiling, or organizing the raw source files into a unified format for ingestion. For example, compiling C++ headers into Doxygen XML in a temporary directory, and cleaning it up after parsing.
from abc import ABC, abstractmethod
from pathlib import Path
class BaseCollector(ABC):
"""Abstract base class for all preprocessing and ingestion data collectors."""
@abstractmethod
def validate_environment(self, config_path: Path) -> None:
"""
Performs pre-flight checks on software binaries, configurations, and source paths.
Args:
config_path: Path to the target's configuration schema.
Raises:
EnvironmentError: If required software (e.g. Doxygen) or paths are missing.
"""
pass
@abstractmethod
def collect(self, config_path: Path) -> Path:
"""
Preprocesses or gathers the target code resources.
Creates temporary folders/structures if required.
Args:
config_path: Path to the target's configuration schema.
Returns:
Path to the directory containing files prepared for the Parser.
"""
pass
@abstractmethod
def cleanup(self, temp_path: Path) -> None:
"""
Cleans up any temporary directories, files, or system artifacts created.
Args:
temp_path: Path returned by the collect() method.
"""
pass
Concrete Implementations
In Version 1.0, all supported SDK languages (C++, C#, Java, Python) use Doxygen as the unified preprocessing and XML-extraction backend. Therefore, the single collector implementation used is DoxygenXmlCollector.
DoxygenXmlCollector
- Responsibilities:
validate_environment():- Verifies Python is installed, executable, and accessible on system PATH.
- Verifies that the
doxygenbinary is installed and executable (checks system PATH and paths specified inude_global.json). - Ensures that the
Doxyfileexists. - Verifies that the source directories (
src_dir) specified in the config exist, are accessible, and contain the required raw source code files matching the target language (e.g., C++ headers.h/.hpp, C#.csfiles, Java.javafiles, or Python.pyfiles) needed for Doxygen XML compilation.
- Runs
doxygen Doxyfileas a subprocess inside the project target directory. - Directs Doxygen XML output to an isolated temporary directory.
- Deletes the entire temporary XML folder recursively during the
cleanupphase inside afinallyblock for all languages.
NativeSourceCollector (Deferred to v3.0+)
- Responsibilities:
validate_environment():- Verifies Python is installed, executable, and accessible on system PATH.
- Verifies that the source directories (
src_dir) specified in the config actually exist, are accessible, and contain the required raw source code files needed for parsing.
- Simply returns the absolute path to the local source directory directly (e.g.
src_dir). - Performs no preprocessing actions and has a no-op
cleanup()phase.
Parser Interface
The Parser component is responsible for reading static source analysis files (e.g., Doxygen XML) and returning a fully populated and validated ProjectCatalog.
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Optional
from .data_model import ProjectCatalog
class BaseParser(ABC):
"""Abstract base class for all documentation parser frontends."""
def __init__(self, ignore_internal: bool = True, ignore_cond: bool = True):
"""
Args:
ignore_internal: If True, blocks marked \internal will be flagged as ignored.
ignore_cond: If True, blocks enclosed in \cond/\endcond will be ignored.
"""
self.ignore_internal = ignore_internal
self.ignore_cond = ignore_cond
@abstractmethod
def parse(self, input_dir: Path, cache_dir: Optional[Path] = None) -> ProjectCatalog:
"""
Parses raw code analysis output from input_dir and constructs the IR model.
Args:
input_dir: Path to the directory containing analysis source files (e.g. XMLs).
cache_dir: Optional path to the target `<sdk>_<lang>` directory where `.build_cache.json.gz` is stored.
Returns:
A validated ProjectCatalog root model.
Raises:
ParserError: If files are missing, unreadable, or invalid.
ValidationError: If the constructed data violates the IR Pydantic schema.
"""
pass
Concrete Implementation: DoxygenXmlParser
- Inherits from:
BaseParser - Responsibilities:
- Locates
index.xmlininput_dirto map namespaces, classes, structs, and globals. - Parses compound XML files (e.g.,
class*.xml,namespace*.xml) using optimized XML streaming (lxmlorxml.etree). - Detects ignore comments (such as
DOM-IGNORE-BEGIN/DOM-IGNORE-END,@cond, and@internal) to mark entities asis_ignored = True. - Parses method signatures, parameters, return types, variables, and type aliases.
- Translates Doxygen XML tags (e.g.,
<para>,<parameterlist>) into normalized CommonMark Markdown blocks inside the descriptions.
- Locates
Renderer Interface
The Renderer component accepts a validated ProjectCatalog IR and converts it into physical documentation files using Jinja2 templates.
class BaseRenderer(ABC):
"""Abstract base class for all documentation rendering backends."""
def __init__(self, templates_dir: Optional[Path] = None):
"""
Args:
templates_dir: Optional path to custom Jinja2 templates.
If None, default built-in templates are utilized.
"""
self.templates_dir = templates_dir
@abstractmethod
def render(self, catalog: ProjectCatalog, output_dir: Path, cache_dir: Optional[Path] = None) -> None:
"""
Renders the ProjectCatalog IR into the target output directory.
Args:
catalog: The validated ProjectCatalog IR data.
output_dir: Target directory path where output files will be created.
cache_dir: Optional path to the target `<sdk>_<lang>` directory where `.build_cache.json.gz` is stored.
Raises:
RendererError: If directory creation, template compiling, or rendering fails.
"""
pass
Concrete Implementations
The v1.0 codebase provides 16 concrete renderer classes following the naming pattern <Lang><Output><ID>Renderer. Each class is instantiated via a factory __new__ pattern that selects the correct concrete class based on the configured language and output format.
| Lang | HtmlDefault | HugoDefault | HtmlLegacy | HugoLegacy |
|---|---|---|---|---|
| Cpp | CppHtmlDefaultRenderer | CppHugoDefaultRenderer | CppHtmlLegacyRenderer | CppHugoLegacyRenderer |
| Cs | CsHtmlDefaultRenderer | CsHugoDefaultRenderer | CsHtmlLegacyRenderer | CsHugoLegacyRenderer |
| Java | JavaHtmlDefaultRenderer | JavaHugoDefaultRenderer | JavaHtmlLegacyRenderer | JavaHugoLegacyRenderer |
| Py | PyHtmlDefaultRenderer | PyHugoDefaultRenderer | PyHtmlLegacyRenderer | PyHugoLegacyRenderer |
Dimensions:
- Lang (
Cpp/Cs/Java/Py): determined by the_api_<lang>suffix of the target project folder. - Output (
Html/Hugo): selects static HTML offline output or Hugo-tailored Markdown output. - ID (
Default/Legacy):Defaultproduces the current modern layout;Legacyproduces output structurally compatible with the Docomatic documentation tool.
Each of the 16 classes loads its dedicated sidebar/TOC configuration from SidebarStructures/default/toc_<RendererClassName>.json. All 16 files must be present (REQ-FUN-50).
Default Renderers (Html/Hugo)
- Key Tasks:
- Compile the IR hierarchy into flat-mapped
.htmlfiles (HtmlDefault) or Hugo-structured.mdfiles with YAML/TOML front-matter (HugoDefault). - Apply language-specific flat-mapping rules to generate safe, cross-platform filenames (e.g.,
::→__for C++,.→_for Java/Python). - Group entities into virtual folder nodes (Classes, Methods, Enumerations) and prune empty groups.
- Embed the complete TOC tree in
nav_data.jsaswindow.UDE_NAV_DATA(HTML output). - Inject user-defined
catalog_linksfrom config into the navigation tree.
- Compile the IR hierarchy into flat-mapped
Legacy Renderers (HtmlLegacy/HugoLegacy)
- Key Tasks:
- Produce output structurally aligned with the Docomatic legacy documentation tool format (HTML Legacy only; Hugo Legacy produces structurally equivalent Markdown but is not bound by Docomatic visual conventions).
- Full Docomatic HTML visual compatibility validation is planned for v3.0+ (GAP-29).
Incremental Caching System
To minimize execution time and prevent unnecessary file writes during local development and CI/CD runs, UDE implements a two-level caching system (Parsing Cache and Rendering Cache) using a unified cache file .build_cache.json.gz stored inside the <sdk>_<lang> directory.
1. Incremental Parsing Cache
The parsing caching system operates as follows:
- Storage Location:
<sdk>_<lang>/.build_cache.json.gz(automatically created, read, and updated). - Metadata Tracked:
file_path: Relative or absolute path to the input XML file (e.g.,class_od_gi_context.xml).last_modified: File modification timestamp (float).sha256: SHA-256 content hash of the input XML file.parsed_entities: List of generated IR entities mapped to this input file.
- Process Flow:
- At startup, the Orchestrator checks if
"incremental": trueis enabled inude_config.json. - If enabled, the Orchestrator reads and decompresses
<sdk>_<lang>/.build_cache.json.gz. - The
BaseParserprocesses input XML files from the temporary directory. For each XML file:- It calculates the SHA-256 hash or checks the modification timestamp.
- If the file exists in the cache and the hash/timestamp matches, it loads the previously parsed entities directly from the cached IR, skipping XML parsing entirely.
- If the file is new or has been modified, it performs full XML parsing, extracts the entities, and updates the cache record.
- The updated cache is compressed and saved back to
<sdk>_<lang>/.build_cache.json.gz.
- At startup, the Orchestrator checks if
2. Incremental Rendering Cache
The rendering caching system optimizes disk operations and avoids rewriting static documentation files:
- Storage Location: Shared inside
<sdk>_<lang>/.build_cache.json.gz. - Metadata Tracked:
output_file: Path to the generated output file (e.g.,namespaces/od_gi_context/_index.md).entity_hash: Content/signature hash of the corresponding IR entity.template_hash: SHA-256 hash of the Jinja2 template file used to render this entity.
- Process Flow:
- The Orchestrator checks if
"incremental": trueis enabled for the renderer. - When
BaseRenderer.render()is invoked, for each entity in theProjectCatalog:- It determines the target output filepath.
- It computes the composite hash (entity data hash + template file hash).
- It compares this composite hash against the cached record in
.build_cache.json.gz. - If the hash matches and the output file physically exists on disk in
output_dir, the renderer skips writing to disk, leaving the file untouched. - If the hash does not match, or if the file is missing from the disk, the renderer executes template compilation, writes the rendered content to
output_dir, and updates the cache record.
- This ensures that only modified API entities trigger physical disk I/O, which keeps Hugo's incremental build fast and keeps Git commits of static documentation extremely clean.
- The Orchestrator checks if