#!/usr/bin/env python3 from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path SCRIPT_DIR = Path(__file__).resolve().parent API_ROOT = SCRIPT_DIR.parent if SCRIPT_DIR.name == "_tools" else SCRIPT_DIR REPO_ROOT = API_ROOT.parents[1] INCLUDE_ROOT = REPO_ROOT / "engine" / "include" / "XCEngine" DOC_ROOT = API_ROOT / "XCEngine" DESCRIPTION_MAP = { "XCEngine": "与 `engine/include/XCEngine` 平行的 API 文档根目录。", "XCEngine/Audio": "音频系统、混音器、效果器与后端接口。", "XCEngine/Components": "组件系统与游戏对象 API。", "XCEngine/Core": "基础类型、事件、IO、容器与数学基础设施。", "XCEngine/Core/Asset": "资源句柄、资源管理器、异步加载与依赖图。", "XCEngine/Core/Containers": "字符串、数组和哈希表等核心容器。", "XCEngine/Core/IO": "资源路径、归档与虚拟文件系统。", "XCEngine/Core/Math": "向量、矩阵、几何体与变换数学类型。", "XCEngine/Debug": "日志、Profiler 与调试集成接口。", "XCEngine/Input": "输入状态查询、输入事件与平台接入接口。", "XCEngine/Memory": "分配器与内存管理。", "XCEngine/Platform": "窗口、时钟、文件系统和平台抽象。", "XCEngine/Platform/Windows": "Windows 平台窗口与输入接入实现。", "XCEngine/Resources": "具体资源类型及其加载器。", "XCEngine/Resources/AudioClip": "音频资源与音频加载器。", "XCEngine/Resources/Material": "材质资源与材质加载器。", "XCEngine/Resources/Mesh": "网格资源、导入设置与网格加载器。", "XCEngine/Resources/Shader": "着色器资源与着色器加载器。", "XCEngine/Resources/Texture": "纹理资源、导入设置与纹理加载器。", "XCEngine/RHI": "渲染硬件抽象层及其后端。", "XCEngine/RHI/D3D12": "DirectX 12 后端 public headers。", "XCEngine/RHI/OpenGL": "OpenGL 后端 public headers。", "XCEngine/Scene": "场景与场景管理器 API。", "XCEngine/Threading": "线程封装、同步原语和任务系统。", } @dataclass class DirInfo: include_dir: Path doc_dir: Path relative: str namespace: str type_label: str description: str def to_namespace(relative: str) -> str: if relative == "XCEngine": return "XCEngine" return "::".join(relative.split("/")) def get_type_label(relative: str) -> str: if relative == "XCEngine": return "module-root" if relative.count("/") == 1: return "module" return "submodule" def get_description(relative: str) -> str: return DESCRIPTION_MAP.get(relative, "与当前 public headers 平行的文档目录节点。") def iter_include_dirs() -> list[DirInfo]: dirs = [INCLUDE_ROOT] dirs.extend(path for path in sorted(INCLUDE_ROOT.rglob("*")) if path.is_dir()) items: list[DirInfo] = [] for include_dir in dirs: relative = "XCEngine" if include_dir != INCLUDE_ROOT: relative = "XCEngine/" + include_dir.relative_to(INCLUDE_ROOT).as_posix() doc_dir = DOC_ROOT if include_dir == INCLUDE_ROOT else DOC_ROOT / include_dir.relative_to(INCLUDE_ROOT) items.append( DirInfo( include_dir=include_dir, doc_dir=doc_dir, relative=relative, namespace=to_namespace(relative), type_label=get_type_label(relative), description=get_description(relative), ) ) return items def relative_link(source: Path, target: Path) -> str: return os.path.relpath(target, source.parent).replace("\\", "/") def dir_index_name(doc_dir: Path) -> str: return f"{doc_dir.name}.md" def dir_index_path(doc_dir: Path) -> Path: return doc_dir / dir_index_name(doc_dir) def header_doc_page_name(header_name: str) -> str: stem = Path(header_name).stem return f"{stem}/{stem}.md" def build_dir_index(info: DirInfo) -> str: include_headers = sorted(path.name for path in info.include_dir.glob("*.h")) child_dirs = sorted(path.name for path in info.include_dir.iterdir() if path.is_dir()) index_path = dir_index_path(info.doc_dir) title = info.relative.split("/")[-1] if info.relative == "XCEngine": title = "XCEngine API 平行目录" lines: list[str] = [] lines.append(f"# {title}") lines.append("") lines.append(f"**命名空间**: `{info.namespace}`") lines.append("") lines.append(f"**类型**: `{info.type_label}`") lines.append("") lines.append(f"**描述**: {info.description}") lines.append("") lines.append("## 概览") lines.append("") lines.append( f"该目录与 `{info.relative}` 对应的 public headers 保持平行,用于承载唯一的 canonical API 文档入口。" ) lines.append("") if child_dirs: lines.append("## 子目录") lines.append("") for child in child_dirs: lines.append(f"- [{child}]({child}/{child}.md)") lines.append("") if include_headers: lines.append("## 头文件") lines.append("") for header in include_headers: page_name = header_doc_page_name(header) page_path = info.doc_dir / Path(page_name) if page_path.exists(): lines.append(f"- [{Path(header).stem}]({page_name}) - `{header}`") else: lines.append(f"- `{header}`") lines.append("") lines.append("## 相关文档") lines.append("") if info.relative == "XCEngine": lines.append("- [API 总索引](../main.md)") lines.append("- [API 文档重构状态](../_meta/rebuild-status.md)") else: lines.append(f"- [上级目录](../{info.doc_dir.parent.name}.md)") lines.append(f"- [API 总索引]({relative_link(index_path, API_ROOT / 'main.md')})") return "\n".join(lines).rstrip() + "\n" def main() -> int: DOC_ROOT.mkdir(parents=True, exist_ok=True) infos = iter_include_dirs() for info in infos: info.doc_dir.mkdir(parents=True, exist_ok=True) dir_index_path(info.doc_dir).write_text(build_dir_index(info), encoding="utf-8") print(f"Generated {len(infos)} directory index files under {DOC_ROOT}") return 0 if __name__ == "__main__": raise SystemExit(main())