""" 验证结果数据结构 定义验证问题和验证结果的数据类。 """ from dataclasses import dataclass, field from typing import List @dataclass class ValidationIssue: """验证问题""" level: str # "ERROR" | "WARNING" | "INFO" message: str location: str # "幻灯片 2, 元素 3" code: str # "ELEMENT_OUT_OF_BOUNDS" @dataclass class ValidationResult: """验证结果""" valid: bool # 是否有 ERROR errors: List[ValidationIssue] = field(default_factory=list) warnings: List[ValidationIssue] = field(default_factory=list) infos: List[ValidationIssue] = field(default_factory=list) def has_errors(self) -> bool: """是否有错误""" return len(self.errors) > 0 def format_output(self) -> str: """格式化为命令行输出""" lines = [] lines.append("🔍 正在检查 YAML 文件...\n") # 错误 if self.errors: lines.append(f"❌ 错误 ({len(self.errors)}):") for issue in self.errors: location_str = f"[{issue.location}] " if issue.location else "" lines.append(f" {location_str}{issue.message}") lines.append("") # 警告 if self.warnings: lines.append(f"⚠️ 警告 ({len(self.warnings)}):") for issue in self.warnings: location_str = f"[{issue.location}] " if issue.location else "" lines.append(f" {location_str}{issue.message}") lines.append("") # 提示 if self.infos: lines.append(f"ℹ️ 提示 ({len(self.infos)}):") for issue in self.infos: location_str = f"[{issue.location}] " if issue.location else "" lines.append(f" {location_str}{issue.message}") lines.append("") # 总结 if not self.errors and not self.warnings and not self.infos: lines.append("验证通过,未发现问题") else: summary_parts = [] if self.errors: summary_parts.append(f"{len(self.errors)} 个错误") if self.warnings: summary_parts.append(f"{len(self.warnings)} 个警告") if self.infos: summary_parts.append(f"{len(self.infos)} 个提示") lines.append(f"检查完成: 发现 {', '.join(summary_parts)}") return "\n".join(lines) # ============= 错误代码常量 ============= # 模板库 metadata 相关错误 ERROR_TEMPLATE_LIBRARY_MISSING_METADATA = "TEMPLATE_LIBRARY_MISSING_METADATA" ERROR_TEMPLATE_LIBRARY_METADATA_MISSING_SIZE = "TEMPLATE_LIBRARY_METADATA_MISSING_SIZE" ERROR_TEMPLATE_LIBRARY_METADATA_INVALID_SIZE = "TEMPLATE_LIBRARY_METADATA_INVALID_SIZE" # Size 一致性错误 ERROR_SIZE_MISMATCH = "SIZE_MISMATCH" # 字体引用相关错误 ERROR_TEMPLATE_FONT_REF_DOC_FORBIDDEN = "TEMPLATE_FONT_REF_DOC_FORBIDDEN" ERROR_TEMPLATE_PARENT_REF_DOC_FORBIDDEN = "TEMPLATE_PARENT_REF_DOC_FORBIDDEN" ERROR_FONT_NOT_FOUND = "FONT_NOT_FOUND" ERROR_CIRCULAR_REFERENCE = "CIRCULAR_REFERENCE" ERROR_FONT_DEFAULT_INVALID = "FONT_DEFAULT_INVALID"