1
0

feat: 实现模板库metadata和跨域字体引用系统

实现了统一的metadata结构和字体作用域系统,支持文档和模板库之间的单向字体引用。

主要变更:
- 模板库必须包含metadata字段(包括size、fonts、fonts_default)
- 实现文档和模板库的size一致性校验
- 实现字体作用域系统(文档可引用模板库字体,反之不可)
- 实现跨域循环引用检测
- 实现fonts_default级联规则(模板库→文档→系统默认)
- 添加错误代码常量(SIZE_MISMATCH、FONT_NOT_FOUND等)
- 更新文档和开发者指南

测试覆盖:
- 新增33个测试(单元测试20个,集成测试13个)
- 所有457个测试通过

Breaking Changes:
- 模板库文件必须包含metadata字段
- 模板库metadata.size为必填字段
- 文档和模板库的size必须一致

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 18:12:05 +08:00
parent f1aae96a04
commit 98098dc911
25 changed files with 2794 additions and 141 deletions

View File

@@ -87,9 +87,43 @@ def validate_presentation_yaml(data, file_path=""):
f"不支持字符串或条件表达式"
)
# 验证 metadata 字段(如果存在)
if 'metadata' in data:
validate_metadata(data['metadata'], file_path, context="文档")
# 验证 templates 字段(内联模板)
validate_templates_yaml(data, file_path)
def validate_metadata(metadata, file_path, context="文档"):
"""
验证 metadata 结构(统一用于文档和模板库)
Args:
metadata: metadata 字典
file_path: 文件路径(用于错误消息)
context: 上下文描述("文档""模板库"
Raises:
YAMLError: 结构验证失败
"""
if not isinstance(metadata, dict):
raise YAMLError(f"{file_path}: metadata 必须是字典对象")
# size 必填
if "size" not in metadata:
raise YAMLError(f"{file_path}: {context} metadata 缺少必填字段 'size'")
size = metadata["size"]
if size not in ["16:9", "4:3"]:
raise YAMLError(
f"{file_path}: metadata.size 必须是 '16:9''4:3',当前值: {size}"
)
# 其他字段可选version, author, description, fonts, fonts_default
# fonts 和 fonts_default 的详细验证在字体主题系统中处理
def validate_template_yaml(data, file_path=""):
"""
验证模板 YAML 结构vars, elements
@@ -185,6 +219,30 @@ def validate_template_library_yaml(data, file_path=""):
if not isinstance(data, dict):
raise YAMLError(f"{file_path}: 模板库文件必须是一个字典对象")
# 验证必需的 metadata 字段
if 'metadata' not in data:
raise YAMLError(f"{file_path}: 模板库必须包含 metadata 字段")
validate_metadata(data['metadata'], file_path, context="模板库")
# 验证模板库 fonts_default 只能引用模板库内部字体
metadata = data['metadata']
if 'fonts_default' in metadata and metadata['fonts_default']:
fonts_default = metadata['fonts_default']
# fonts_default 必须是引用格式
if not isinstance(fonts_default, str) or not fonts_default.startswith("@"):
raise YAMLError(
f"{file_path}: 模板库 fonts_default 必须是引用格式(@xxx当前值: {fonts_default}"
)
# fonts_default 引用的配置必须存在于模板库 fonts 中
font_name = fonts_default[1:]
template_fonts = metadata.get('fonts', {})
if font_name not in template_fonts:
raise YAMLError(
f"{file_path}: 模板库 fonts_default 只能引用模板库内部的字体配置,"
f"'{fonts_default}' 不存在于模板库 metadata.fonts 中"
)
# 验证必需的 templates 字段
if 'templates' not in data:
raise YAMLError(f"{file_path}: 缺少必需字段 'templates'")