fix(writer): map_template consumes real ParsedTemplate sections (positional section ids)
This commit is contained in:
@@ -1,22 +1,36 @@
|
|||||||
"""模板 → 有序章节规格映射(Phase 5)。"""
|
"""模板 → 有序章节规格映射(Phase 5)。
|
||||||
|
|
||||||
|
真实 ParsedTemplate.sections 为 ChapterMarker 列表;章节由 type=="heading" 起,
|
||||||
|
紧随其后的 type=="placeholder" 且形如 `section:<id>` 的标记归属该章,
|
||||||
|
用于确定 chapter_id 与 section_placeholder(语言无关、按文档顺序)。
|
||||||
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from genesis.data_models import ParsedTemplate
|
||||||
from genesis.writer.models import ChapterSpec
|
from genesis.writer.models import ChapterSpec
|
||||||
|
|
||||||
|
_SECTION_RE = re.compile(r"^section:(.+)$")
|
||||||
|
|
||||||
def map_template(parsed) -> list[ChapterSpec]:
|
|
||||||
"""按模板 Heading 层级顺序产出有序章节列表。
|
|
||||||
|
|
||||||
`parsed.chapters` 为 WordTemplateParser 产出的章节标记列表,
|
def map_template(parsed: ParsedTemplate) -> list[ChapterSpec]:
|
||||||
每项含 chapter_id / title / section_placeholder 属性。
|
|
||||||
"""
|
|
||||||
specs: list[ChapterSpec] = []
|
specs: list[ChapterSpec] = []
|
||||||
for ch in getattr(parsed, "chapters", []):
|
idx = 0
|
||||||
specs.append(
|
current: ChapterSpec | None = None
|
||||||
ChapterSpec(
|
for ch in getattr(parsed, "sections", []):
|
||||||
chapter_id=getattr(ch, "chapter_id", ""),
|
t = getattr(ch, "type", None)
|
||||||
title=getattr(ch, "title", ""),
|
if t == "heading":
|
||||||
section_placeholder=getattr(ch, "section_placeholder", None),
|
idx += 1
|
||||||
|
current = ChapterSpec(
|
||||||
|
chapter_id=f"chapter_{idx}", title=getattr(ch, "name", ""), section_placeholder=None
|
||||||
)
|
)
|
||||||
)
|
specs.append(current)
|
||||||
|
elif t == "placeholder" and current is not None:
|
||||||
|
m = _SECTION_RE.match(getattr(ch, "name", ""))
|
||||||
|
if m:
|
||||||
|
sid = m.group(1)
|
||||||
|
current.section_placeholder = getattr(ch, "name", "")
|
||||||
|
if current.chapter_id.startswith("chapter_"):
|
||||||
|
current.chapter_id = sid
|
||||||
return specs
|
return specs
|
||||||
|
|||||||
@@ -1,17 +1,32 @@
|
|||||||
from types import SimpleNamespace
|
from genesis.data_models import ChapterMarker, ParsedTemplate
|
||||||
from genesis.writer.template_mapper import map_template
|
|
||||||
from genesis.writer.models import ChapterSpec
|
from genesis.writer.models import ChapterSpec
|
||||||
|
from genesis.writer.template_mapper import map_template
|
||||||
|
|
||||||
|
|
||||||
def _fake_parsed():
|
def _parsed():
|
||||||
ch1 = SimpleNamespace(chapter_id="intro", title="はじめに", section_placeholder="{{section:introduction}}")
|
sections = [
|
||||||
ch2 = SimpleNamespace(chapter_id="db_design", title="DB 設計", section_placeholder=None)
|
ChapterMarker(type="heading", name="はじめに", level=1),
|
||||||
return SimpleNamespace(chapters=[ch1, ch2])
|
ChapterMarker(type="placeholder", name="section:introduction", level=0),
|
||||||
|
ChapterMarker(type="heading", name="DB 設計", level=1),
|
||||||
|
ChapterMarker(type="placeholder", name="section:db_design", level=0),
|
||||||
|
ChapterMarker(type="bookmark", name="bm1", level=0),
|
||||||
|
]
|
||||||
|
return ParsedTemplate(file_name="t.docx", sections=sections, placeholders={"section:introduction": "x"}, styles={})
|
||||||
|
|
||||||
|
|
||||||
def test_map_template_ordered():
|
def test_map_template_ordered_and_assigns_ids():
|
||||||
specs = map_template(_fake_parsed())
|
specs = map_template(_parsed())
|
||||||
assert [s.chapter_id for s in specs] == ["intro", "db_design"]
|
assert [s.title for s in specs] == ["はじめに", "DB 設計"]
|
||||||
assert specs[0].section_placeholder == "{{section:introduction}}"
|
assert specs[0].chapter_id == "introduction"
|
||||||
assert specs[1].section_placeholder is None
|
assert specs[0].section_placeholder == "section:introduction"
|
||||||
|
assert specs[1].chapter_id == "db_design"
|
||||||
|
assert specs[1].section_placeholder == "section:db_design"
|
||||||
assert all(isinstance(s, ChapterSpec) for s in specs)
|
assert all(isinstance(s, ChapterSpec) for s in specs)
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_template_falls_back_without_placeholder():
|
||||||
|
sections = [ChapterMarker(type="heading", name="附録", level=1)]
|
||||||
|
parsed = ParsedTemplate(file_name="t.docx", sections=sections, placeholders={}, styles={})
|
||||||
|
specs = map_template(parsed)
|
||||||
|
assert specs[0].chapter_id == "chapter_1"
|
||||||
|
assert specs[0].section_placeholder is None
|
||||||
|
|||||||
Reference in New Issue
Block a user