Coverage for src\genesis\parsers\source_aggregator.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-26 14:20 +0800

1from __future__ import annotations 

2 

3from pathlib import Path 

4 

5from genesis.data_models import StructuredSource 

6from genesis.impact.code_parser import CodeParser 

7from genesis.impact.existing_system_explorer import ExistingSystemExplorer 

8from genesis.parsers.excel_parser import ExcelParser 

9from genesis.parsers.rule_doc_parser import RuleDocParser 

10from genesis.parsers.word_template_parser import WordTemplateParser 

11 

12XLSX_EXTS = (".xlsx", ".xls") 

13DOCX_EXT = ".docx" 

14 

15 

16def _validate_path(path: str | Path, allowed_exts: tuple[str, ...]) -> Path: 

17 """校验文件扩展名合法且文件存在(T7 DRY:消除三处重复校验)。 

18 

19 Raises: 

20 ValueError: 扩展名不在 allowed_exts(含无扩展名) 

21 FileNotFoundError: 文件不存在 

22 """ 

23 p = Path(path) 

24 if p.suffix.lower() not in allowed_exts: 

25 raise ValueError(f"不支持的文件类型: {p.suffix or '(无扩展名)'}") 

26 if not p.exists(): 

27 raise FileNotFoundError(str(path)) 

28 return p 

29 

30 

31class SourceParser: 

32 """全量输入门面:Excel 要件定义 + Word 模板 + Word 规则 → StructuredSource。 

33 

34 角色由调用方按 api-design file_type 语义显式传入(requirements/template/ 

35 write_instruction/rules),不做基于文件名的隐式猜测(spec §3.4)。 

36 """ 

37 

38 def __init__(self) -> None: 

39 self._excel = ExcelParser() 

40 

41 def parse( 

42 self, 

43 requirement_paths: list[str | Path] | None = None, 

44 template_path: str | Path | None = None, 

45 write_instruction_paths: list[str | Path] | None = None, 

46 rule_paths: list[str | Path] | None = None, 

47 existing_system_path: str | Path | None = None, 

48 existing_system_language: str | None = None, 

49 ) -> StructuredSource: 

50 """扩展名校验先于存在性校验(不存在的文件若扩展名未知将抛出 ValueError 而非 FileNotFoundError)。 

51 

52 existing_system_path:既有系统源码目录(追加/改修场景)。提供时解析为 

53 ExistingSystemInfo(门控通过 → 进入影响调查);未提供/解析失败 → 保持 None。 

54 existing_system_language:既有系统源码开发语言(如 "java")。默认 None 表示 

55 由 CodeParser 按扩展名自动探测;显式指定时按该语言解析(多语言支持扩展点)。 

56 """ 

57 

58 requirement_paths = requirement_paths or [] 

59 write_instruction_paths = write_instruction_paths or [] 

60 rule_paths = rule_paths or [] 

61 

62 tables = [] 

63 comments = [] 

64 for p in requirement_paths: 

65 path = _validate_path(p, XLSX_EXTS) 

66 result = self._excel.parse(path) 

67 tables.extend(result.tables) 

68 comments.extend(result.comments) 

69 

70 template = None 

71 if template_path is not None: 

72 tpath = _validate_path(template_path, (DOCX_EXT,)) 

73 template = WordTemplateParser().parse(tpath) 

74 

75 rule_docs = [] 

76 for p in [*write_instruction_paths, *rule_paths]: 

77 path = _validate_path(p, (DOCX_EXT,)) 

78 # 做成说明书与记入规则均为 Type A 写入规则 → write(api-design §2.2) 

79 rule_docs.append(RuleDocParser().parse(path, category="write")) 

80 

81 existing_system = None 

82 if existing_system_path is not None: 

83 code = CodeParser().parse(existing_system_path, language=existing_system_language) 

84 existing_system = ExistingSystemExplorer().explore(code) 

85 

86 return StructuredSource( 

87 tables=tables, 

88 template=template, 

89 rule_docs=rule_docs, 

90 image_analyses=[], 

91 existing_system=existing_system, 

92 comments=comments, 

93 )