diff --git a/src/genesis/writer/renderer.py b/src/genesis/writer/renderer.py new file mode 100644 index 0000000..27bb670 --- /dev/null +++ b/src/genesis/writer/renderer.py @@ -0,0 +1,25 @@ +"""渲染:ChapterContent 的 ContentBlock 序列 → DocxInjector.Block 序列(Phase 5)。 + +字段塌缩(外视 #6):table.headers/caption、list.items/style 在渲染时显式丢弃, +仅保留 DocxInjector.Block 支持的 (kind, text, level, rows)。 +""" +from __future__ import annotations + +from genesis.writer.docx_injector import Block +from genesis.writer.models import ChapterContent + + +def render_chapter_blocks(content: ChapterContent) -> list[Block]: + out: list[Block] = [] + for b in content.blocks: + if b.type == "heading": + out.append(Block(kind="heading", text=b.text or b.caption or "", level=b.level or 1)) + elif b.type == "table": + out.append(Block(kind="table", text=b.caption or "", rows=b.rows or [])) + elif b.type == "list": + out.append(Block(kind="list", text="\n".join(b.items or []))) + elif b.type == "note": + out.append(Block(kind="note", text=b.text or b.caption or "")) + else: # paragraph 及未知类型 + out.append(Block(kind="paragraph", text=b.text or b.caption or "")) + return out diff --git a/tests/test_docx_injector.py b/tests/test_docx_injector.py index 3b17471..bc9c748 100644 --- a/tests/test_docx_injector.py +++ b/tests/test_docx_injector.py @@ -87,3 +87,11 @@ def test_original_content_style_preserved(tmp_path): # 模板原有段落(尾部固定内容)在注入后仍存在且未被破坏 assert any("尾部固定内容" in p.text for p in out.paragraphs) + + +# ---------- Block 支持 table/list/note 等 kind(renderer 依赖) ---------- + +def test_block_accepts_table_list_note(): + assert Block(kind="table", text="t", rows=[["x"]]).kind == "table" + assert Block(kind="list", text="a\nb").kind == "list" + assert Block(kind="note", text="n").kind == "note" diff --git a/tests/test_phase5_renderer.py b/tests/test_phase5_renderer.py new file mode 100644 index 0000000..c6545d9 --- /dev/null +++ b/tests/test_phase5_renderer.py @@ -0,0 +1,25 @@ +from genesis.writer.renderer import render_chapter_blocks +from genesis.writer.models import ChapterContent, ContentBlock + + +def _content(): + blocks = [ + ContentBlock(block_id="1", type="heading", level=2, text="小節"), + ContentBlock(block_id="2", type="paragraph", text="正文"), + ContentBlock(block_id="3", type="table", caption="表1", rows=[["a", "b"], ["1", "2"]]), + ContentBlock(block_id="4", type="list", items=["項目一", "項目二"]), + ContentBlock(block_id="5", type="note", text="注意"), + ] + return ChapterContent(chapter_id="db_design", version=1, title="DB 設計", blocks=blocks) + + +def test_render_maps_all_block_types(): + out = render_chapter_blocks(_content()) + kinds = [b.kind for b in out] + assert kinds == ["heading", "paragraph", "table", "list", "note"] + # 表:rows 透传 + table = out[2] + assert table.kind == "table" + assert table.rows == [["a", "b"], ["1", "2"]] + # 列表:items 拼接进 text + assert "項目一" in out[3].text and "項目二" in out[3].text