Skip empty doc files and prune dead type-index entries
- render_header() returns "" when a header has no documented content (no /** */ comments on any class, property, function, enum, or delegate) - generate.py skips writing those files and tracks which were written - type-index.txt is filtered to only include types from written files, preventing dead entries that would cause get_class_overview to fail - Summary line now reports how many files were skipped Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,7 @@ Typical query flow: `search_types` → `get_class_overview` → `get_member` (~3
|
|||||||
- Deprecated functions excluded from output (`not f.is_deprecated` in visibility filter).
|
- Deprecated functions excluded from output (`not f.is_deprecated` in visibility filter).
|
||||||
- Enums with no value descriptions use compact inline format (`Values: A, B, C`) instead of a table.
|
- Enums with no value descriptions use compact inline format (`Values: A, B, C`) instead of a table.
|
||||||
- Placeholder descriptions (`------//`) filtered by `_PLACEHOLDER_RE` in `_fn_body()`.
|
- Placeholder descriptions (`------//`) filtered by `_PLACEHOLDER_RE` in `_fn_body()`.
|
||||||
|
- Headers with no documented content: `render_header()` returns `""`, `generate.py` skips writing the file and filters those types from `type-index.txt` to avoid dead entries.
|
||||||
|
|
||||||
## Critical Gotchas
|
## Critical Gotchas
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ Generates compact, agent-readable Markdown documentation from Unreal Engine C++
|
|||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
1. **Parse** — `docgen/ue_parser.py` scans UE headers into dataclasses using a position-based scanner (handles nested braces, macros, delegates, namespaces).
|
1. **Parse** — `docgen/ue_parser.py` scans UE headers into dataclasses using a position-based scanner (handles nested braces, macros, delegates, namespaces).
|
||||||
2. **Render** — `docgen/ue_markdown.py` emits one `.md` per header: only items with C++ doc comments, no deprecated functions, compact enum format.
|
2. **Render** — `docgen/ue_markdown.py` emits one `.md` per header: only items with C++ doc comments, no deprecated functions, compact enum format. Headers with no documented content produce no output file.
|
||||||
3. **Index** — `docgen/generate.py` produces `type-index.txt`: a flat `TypeName: path/to/File.md` lookup for instant type resolution.
|
3. **Index** — `docgen/generate.py` produces `type-index.txt`: a flat `TypeName: path/to/File.md` lookup for instant type resolution. Only types from files that were actually written are indexed.
|
||||||
4. **Serve** — `ue_mcp_server.py` exposes the docs to Claude as callable MCP tools.
|
4. **Serve** — `ue_mcp_server.py` exposes the docs to Claude as callable MCP tools.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ def main():
|
|||||||
|
|
||||||
# --- Pass 2: render all ---
|
# --- Pass 2: render all ---
|
||||||
success = 0
|
success = 0
|
||||||
|
skipped = 0
|
||||||
|
written_mds: set[str] = set()
|
||||||
for h, base, parsed in parsed_list:
|
for h, base, parsed in parsed_list:
|
||||||
print(f"Rendering {h} ...")
|
print(f"Rendering {h} ...")
|
||||||
current_md = _md_rel(h, base)
|
current_md = _md_rel(h, base)
|
||||||
@@ -143,13 +145,20 @@ def main():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
md = render_header(parsed, type_index=type_index, current_md=current_md)
|
md = render_header(parsed, type_index=type_index, current_md=current_md)
|
||||||
|
if not md:
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
out_path.write_text(md, encoding='utf-8')
|
out_path.write_text(md, encoding='utf-8')
|
||||||
|
written_mds.add(current_md)
|
||||||
success += 1
|
success += 1
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f" ERROR rendering {h}: {exc}", file=sys.stderr)
|
print(f" ERROR rendering {h}: {exc}", file=sys.stderr)
|
||||||
|
|
||||||
|
# Remove type-index entries whose files were not written (no documented content)
|
||||||
|
type_index = {name: path for name, path in type_index.items() if path in written_mds}
|
||||||
write_type_index(type_index, output_dir)
|
write_type_index(type_index, output_dir)
|
||||||
print(f"\nGenerated {success}/{len(parsed_list)} files + type-index.txt in {output_dir}/")
|
print(f"\nGenerated {success}/{len(parsed_list)} files "
|
||||||
|
f"({skipped} skipped — no documented content) + type-index.txt in {output_dir}/")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -361,14 +361,13 @@ def _render_namespace(ns: NamespaceInfo) -> str:
|
|||||||
def render_header(parsed: ParsedHeader,
|
def render_header(parsed: ParsedHeader,
|
||||||
type_index: dict[str, str] = None,
|
type_index: dict[str, str] = None,
|
||||||
current_md: str = "") -> str:
|
current_md: str = "") -> str:
|
||||||
|
"""
|
||||||
|
Render a ParsedHeader to Markdown. Returns empty string if the header
|
||||||
|
has no documented content (so callers can skip writing the file).
|
||||||
|
"""
|
||||||
if type_index is None:
|
if type_index is None:
|
||||||
type_index = {}
|
type_index = {}
|
||||||
|
|
||||||
lines = []
|
|
||||||
lines.append(f"# `{parsed.filename}`")
|
|
||||||
lines.append(f"**Module**: `{parsed.module_name}`")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
sections = []
|
sections = []
|
||||||
|
|
||||||
d_sec = _render_delegates(parsed.delegates)
|
d_sec = _render_delegates(parsed.delegates)
|
||||||
@@ -400,6 +399,13 @@ def render_header(parsed: ParsedHeader,
|
|||||||
ff_lines.append(_render_ff_compact(fn))
|
ff_lines.append(_render_ff_compact(fn))
|
||||||
sections.append('\n'.join(ff_lines))
|
sections.append('\n'.join(ff_lines))
|
||||||
|
|
||||||
lines.append('\n\n---\n\n'.join(sections))
|
if not sections:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
f"# `{parsed.filename}`",
|
||||||
|
f"**Module**: `{parsed.module_name}`",
|
||||||
|
"",
|
||||||
|
'\n\n---\n\n'.join(sections),
|
||||||
|
]
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
|
|||||||
Reference in New Issue
Block a user