feat: 根目录文档、脚本、gitignore

This commit is contained in:
2026-10-08 16:15:33 +08:00
commit e98660ce4e
284 changed files with 26838 additions and 0 deletions
@@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""
docmap 输出质量验证脚本
检查生成的文档是否符合规范要求
检查项分两级:
- 失败项(failed):结构/内容缺失,退出码非零
- 警告项(warning):可疑但不阻断(如 stateDiagram、模糊表述),不影响退出码
"""
import re
import sys
from datetime import datetime
from pathlib import Path
from dataclasses import dataclass
from typing import List
# 模糊表述"等"的白名单(合理用法,不算模糊)
DENG_WHITELIST = [
"等于", "等待", "对等", "等级", "等同", "同等", "均等",
"不等", "稍等", "优等", "劣等", "等比", "等值",
]
@dataclass
class ValidationResult:
passed: bool
message: str
file: str = ""
warning: bool = False # True 表示警告项,不计入失败、不影响退出码
class DocmapValidator:
def __init__(self, outputs_dir: str):
self.outputs_dir = Path(outputs_dir)
self.results: List[ValidationResult] = []
def validate(self) -> List[ValidationResult]:
"""执行所有验证"""
self.results = []
# 检查目录结构
self._check_directory_structure()
# 验证架构文档
self._validate_architecture_doc()
# 验证模块文档
self._validate_module_docs()
# 验证能力模型
self._validate_capability_doc()
return self.results
def _check_directory_structure(self):
"""检查输出目录结构"""
if not self.outputs_dir.exists():
self.results.append(ValidationResult(
False, "输出目录不存在", str(self.outputs_dir)
))
return
# 检查必需文件
required_files = ["01-产品整体架构.md", "03-系统能力模型.md"]
for f in required_files:
path = self.outputs_dir / f
if not path.exists():
self.results.append(ValidationResult(
False, f"缺少必需文件: {f}", str(self.outputs_dir)
))
# 检查模块目录
module_dir = self.outputs_dir / "02-功能模块"
if not module_dir.exists():
self.results.append(ValidationResult(
False, "缺少功能模块目录", str(self.outputs_dir)
))
def _validate_architecture_doc(self):
"""验证架构文档"""
doc_path = self.outputs_dir / "01-产品整体架构.md"
if not doc_path.exists():
return
content = doc_path.read_text(encoding='utf-8')
# 检查 7 个必需章节
required_sections = [
"产品定位",
"系统整体架构",
"业务架构图",
"核心业务流程",
"数据架构",
"权限与角色体系",
"系统扩展点分析"
]
for section in required_sections:
if section not in content:
self.results.append(ValidationResult(
False, f"缺少章节: {section}", str(doc_path)
))
# 检查 Mermaid 图(至少 2 个)
mermaid_count = content.count("```mermaid")
if mermaid_count < 2:
self.results.append(ValidationResult(
False, f"Mermaid 图数量不足: 需要至少 2 个,实际 {mermaid_count} 个", str(doc_path)
))
else:
self.results.append(ValidationResult(
True, f"Mermaid 图数量: {mermaid_count} 个", str(doc_path)
))
# 检查模糊表述(警告项,不阻断)
fuzzy_patterns = [r"等情况", r"等多种", r"其他相关", r"等等", r"诸如此类"]
for pattern in fuzzy_patterns:
matches = re.findall(pattern, content)
if matches:
self.results.append(ValidationResult(
False, f"发现模糊表述 '{pattern}': 出现 {len(matches)} 次",
str(doc_path), warning=True
))
def _validate_module_docs(self):
"""验证模块文档"""
module_dir = self.outputs_dir / "02-功能模块"
if not module_dir.exists():
return
module_files = list(module_dir.glob("*.md"))
if not module_files:
self.results.append(ValidationResult(
False, "功能模块目录为空", str(module_dir)
))
return
for module_file in module_files:
content = module_file.read_text(encoding='utf-8')
# 检查功能清单表格
if "| 功能名称 |" not in content and "|功能名称|" not in content:
self.results.append(ValidationResult(
False, "缺少功能清单表格", str(module_file)
))
# 检查状态流转 Mermaid(警告项,不阻断:无状态机的模块可豁免)
if "```mermaid" not in content or "stateDiagram" not in content:
self.results.append(ValidationResult(
False, "缺少状态流转 Mermaid 图", str(module_file), warning=True
))
# 检查模糊表述"等"(警告项,不阻断;白名单词不算命中)
hit_lines = []
for lineno, line in enumerate(content.split('\n'), 1):
stripped = line
for word in DENG_WHITELIST:
stripped = stripped.replace(word, "")
if "等" in stripped:
hit_lines.append(lineno)
if hit_lines:
self.results.append(ValidationResult(
False,
f"可能包含模糊表述 '等'(行: {', '.join(map(str, hit_lines))})",
str(module_file), warning=True
))
def _validate_capability_doc(self):
"""验证能力模型文档"""
doc_path = self.outputs_dir / "03-系统能力模型.md"
if not doc_path.exists():
return
content = doc_path.read_text(encoding='utf-8')
# 检查能力依赖关系图
if "```mermaid" not in content:
self.results.append(ValidationResult(
False, "缺少能力依赖关系图", str(doc_path)
))
# 检查平台级/业务定制能力区分
if "平台级能力" not in content or "业务定制能力" not in content:
self.results.append(ValidationResult(
False, "缺少平台级/业务定制能力区分", str(doc_path)
))
def generate_report(self) -> str:
"""生成验证报告"""
passed = [r for r in self.results if r.passed]
warnings = [r for r in self.results if not r.passed and r.warning]
failed = [r for r in self.results if not r.passed and not r.warning]
report = ["# docmap 输出质量验证报告\n"]
report.append(f"**验证时间:** {datetime.now().isoformat()}\n")
report.append(f"**输出目录:** {self.outputs_dir}\n")
report.append(f"**通过项:** {len(passed)}\n")
report.append(f"**警告项:** {len(warnings)}\n")
report.append(f"**失败项:** {len(failed)}\n\n")
if failed:
report.append("## ❌ 失败项\n")
for r in failed:
report.append(f"- **{r.file}**: {r.message}\n")
report.append("\n")
if warnings:
report.append("## ⚠️ 警告项(不阻断)\n")
for r in warnings:
report.append(f"- **{r.file}**: {r.message}\n")
report.append("\n")
if passed:
report.append("## ✅ 通过项\n")
for r in passed:
report.append(f"- **{r.file}**: {r.message}\n")
return "\n".join(report)
def main():
if len(sys.argv) < 2:
print("Usage: python validate_output.py <outputs_directory>")
sys.exit(1)
outputs_dir = sys.argv[1]
validator = DocmapValidator(outputs_dir)
validator.validate()
report = validator.generate_report()
print(report)
# 保存报告
report_path = Path(outputs_dir).parent / "validation_report.md"
report_path.write_text(report, encoding='utf-8')
print(f"\n报告已保存: {report_path}")
# 仅失败项影响退出码;警告项不阻断
failed = [r for r in validator.results if not r.passed and not r.warning]
sys.exit(1 if failed else 0)
if __name__ == "__main__":
main()