""" 主验证器 协调各子验证器,执行完整的 YAML 文件验证。 """ from pathlib import Path from loaders.yaml_loader import load_yaml_file, validate_presentation_yaml, YAMLError from validators.result import ValidationResult, ValidationIssue from validators.geometry import GeometryValidator from validators.resource import ResourceValidator from core.elements import create_element class Validator: """主验证器""" # 幻灯片尺寸映射(英寸) SLIDE_SIZES = { "16:9": (10, 5.625), "4:3": (10, 7.5), } def __init__(self): """初始化验证器""" pass def validate(self, yaml_path: Path, template_dir: Path = None) -> ValidationResult: """ 验证 YAML 文件 Args: yaml_path: YAML 文件路径 template_dir: 模板文件目录(可选) Returns: 验证结果 """ errors = [] warnings = [] infos = [] # 1. 加载 YAML try: data = load_yaml_file(yaml_path) validate_presentation_yaml(data, str(yaml_path)) except YAMLError as e: errors.append(ValidationIssue( level="ERROR", message=str(e), location="", code="YAML_ERROR" )) return ValidationResult( valid=False, errors=errors, warnings=warnings, infos=infos ) except Exception as e: errors.append(ValidationIssue( level="ERROR", message=f"加载 YAML 文件失败: {str(e)}", location="", code="YAML_LOAD_ERROR" )) return ValidationResult( valid=False, errors=errors, warnings=warnings, infos=infos ) # 获取幻灯片尺寸 size_str = data.get('metadata', {}).get('size', '16:9') slide_width, slide_height = self.SLIDE_SIZES.get(size_str, (10, 5.625)) # 初始化子验证器 geometry_validator = GeometryValidator(slide_width, slide_height) resource_validator = ResourceValidator( yaml_dir=yaml_path.parent, template_dir=template_dir ) # 2. 验证每个幻灯片 slides = data.get('slides', []) for slide_index, slide_data in enumerate(slides, start=1): # 验证模板 template_issues = resource_validator.validate_template(slide_data, slide_index) self._categorize_issues(template_issues, errors, warnings, infos) # 验证元素 elements = slide_data.get('elements', []) for elem_index, elem_dict in enumerate(elements, start=1): # 3. 元素级验证 try: element = create_element(elem_dict) # 调用元素的 validate() 方法 if hasattr(element, 'validate'): elem_issues = element.validate() # 填充位置信息 for issue in elem_issues: issue.location = f"幻灯片 {slide_index}, 元素 {elem_index}" self._categorize_issues(elem_issues, errors, warnings, infos) # 4. 几何验证 geom_issues = geometry_validator.validate_element( element, slide_index, elem_index ) self._categorize_issues(geom_issues, errors, warnings, infos) # 5. 资源验证(图片) if elem_dict.get('type') == 'image': img_issues = resource_validator.validate_image( element, slide_index, elem_index ) self._categorize_issues(img_issues, errors, warnings, infos) except ValueError as e: # 元素创建失败(__post_init__ 中的验证) errors.append(ValidationIssue( level="ERROR", message=str(e), location=f"幻灯片 {slide_index}, 元素 {elem_index}", code="ELEMENT_VALIDATION_ERROR" )) except Exception as e: errors.append(ValidationIssue( level="ERROR", message=f"验证元素时出错: {str(e)}", location=f"幻灯片 {slide_index}, 元素 {elem_index}", code="ELEMENT_VALIDATION_ERROR" )) # 返回验证结果 return ValidationResult( valid=len(errors) == 0, errors=errors, warnings=warnings, infos=infos ) def _categorize_issues(self, issues: list, errors: list, warnings: list, infos: list): """ 将问题按级别分类 Args: issues: 问题列表 errors: 错误列表 warnings: 警告列表 infos: 提示列表 """ for issue in issues: if issue.level == "ERROR": errors.append(issue) elif issue.level == "WARNING": warnings.append(issue) elif issue.level == "INFO": infos.append(issue)