Files
2026Technology-Competition/src/genesis/parsers/source_aggregator.py
T
lhl 916c5beed7 feat(web): 项目级配置 + 会话命名/历史 + 设计文档纳入影响调查
- 会话支持 name/project 字段,上传要件定义后自动命名;前端侧边栏会话历史 + localStorage 恢复,顶部只显示会话名
- 新增 ProjectsStore(SQLite)与 /api/projects CRUD;绑定项目后 _rebuild_source 合并模板/规则/代码库/设计文档,上传区仅要件定义
- StructuredSource.design_docs 与 ImpactReport.design_references;影响调查新增既有设计文档确定性交叉引用(无 LLM)
- 同步更新 docs/design.md §12.7、README、_AI_USAGE_LOG.md;全量测试 558 通过,覆盖率 99.10%
2026-08-27 12:13:28 +08:00

102 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from pathlib import Path
from genesis.data_models import StructuredSource
from genesis.impact.code_parser import CodeParser
from genesis.impact.existing_system_explorer import ExistingSystemExplorer
from genesis.parsers.excel_parser import ExcelParser
from genesis.parsers.rule_doc_parser import RuleDocParser
from genesis.parsers.word_template_parser import WordTemplateParser
XLSX_EXTS = (".xlsx", ".xls")
DOCX_EXT = ".docx"
def _validate_path(path: str | Path, allowed_exts: tuple[str, ...]) -> Path:
"""校验文件扩展名合法且文件存在(T7 DRY:消除三处重复校验)。
Raises:
ValueError: 扩展名不在 allowed_exts(含无扩展名)
FileNotFoundError: 文件不存在
"""
p = Path(path)
if p.suffix.lower() not in allowed_exts:
raise ValueError(f"不支持的文件类型: {p.suffix or '(无扩展名)'}")
if not p.exists():
raise FileNotFoundError(str(path))
return p
class SourceParser:
"""全量输入门面:Excel 要件定义 + Word 模板 + Word 规则 → StructuredSource。
角色由调用方按 api-design file_type 语义显式传入(requirements/template/
write_instruction/rules),不做基于文件名的隐式猜测(spec §3.4)。
"""
def __init__(self) -> None:
self._excel = ExcelParser()
def parse(
self,
requirement_paths: list[str | Path] | None = None,
template_path: str | Path | None = None,
write_instruction_paths: list[str | Path] | None = None,
rule_paths: list[str | Path] | None = None,
existing_system_path: str | Path | None = None,
existing_system_language: str | None = None,
design_doc_paths: list[str | Path] | None = None,
) -> StructuredSource:
"""扩展名校验先于存在性校验(不存在的文件若扩展名未知将抛出 ValueError 而非 FileNotFoundError)。
existing_system_path:既有系统源码目录(追加/改修场景)。提供时解析为
ExistingSystemInfo(门控通过 → 进入影响调查);未提供/解析失败 → 保持 None。
existing_system_language:既有系统源码开发语言(如 "java")。默认 None 表示
由 CodeParser 按扩展名自动探测;显式指定时按该语言解析(多语言支持扩展点)。
"""
requirement_paths = requirement_paths or []
write_instruction_paths = write_instruction_paths or []
rule_paths = rule_paths or []
tables = []
comments = []
for p in requirement_paths:
path = _validate_path(p, XLSX_EXTS)
result = self._excel.parse(path)
tables.extend(result.tables)
comments.extend(result.comments)
template = None
if template_path is not None:
tpath = _validate_path(template_path, (DOCX_EXT,))
template = WordTemplateParser().parse(tpath)
rule_docs = []
for p in [*write_instruction_paths, *rule_paths]:
path = _validate_path(p, (DOCX_EXT,))
# 做成说明书与记入规则均为 Type A 写入规则 → writeapi-design §2.2
rule_docs.append(RuleDocParser().parse(path, category="write"))
existing_system = None
if existing_system_path is not None:
code = CodeParser().parse(existing_system_path, language=existing_system_language)
existing_system = ExistingSystemExplorer().explore(code)
design_docs = []
for p in (design_doc_paths or []):
dpath = _validate_path(p, (DOCX_EXT,))
# 设计文档为 Type A 参考材料(category="design",区别于写入规则)
design_docs.append(RuleDocParser().parse(dpath, category="design"))
return StructuredSource(
tables=tables,
template=template,
rule_docs=rule_docs,
image_analyses=[],
existing_system=existing_system,
comments=comments,
design_docs=design_docs,
)