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:
@@ -66,13 +66,15 @@ class Template:
|
||||
self.elements = self.data.get('elements', [])
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, template_data, template_name, base_dir=None):
|
||||
def from_data(cls, template_data, template_name, base_dir=None, scope="document", font_resolver=None):
|
||||
"""从字典创建模板(内联模板或外部模板)
|
||||
|
||||
Args:
|
||||
template_data: 模板数据字典
|
||||
template_name: 模板名称
|
||||
base_dir: 资源路径解析的基础目录(外部模板使用模板库文件所在目录,内联模板使用文档目录)
|
||||
scope: 作用域("document" 或 "template")
|
||||
font_resolver: 字体解析器(用于解析字体引用)
|
||||
|
||||
Returns:
|
||||
Template 对象
|
||||
@@ -80,6 +82,8 @@ class Template:
|
||||
obj = cls.__new__(cls)
|
||||
obj.data = template_data
|
||||
obj.base_dir = base_dir # 保存 base_dir 用于资源路径解析
|
||||
obj.scope = scope # 保存作用域
|
||||
obj.font_resolver = font_resolver # 保存字体解析器
|
||||
|
||||
# 初始化条件评估器
|
||||
obj._condition_evaluator = ConditionEvaluator()
|
||||
@@ -231,6 +235,37 @@ class Template:
|
||||
# 深度解析元素中的所有变量引用
|
||||
rendered_elem = self.resolve_element(elem, vars_values)
|
||||
|
||||
# 解析字体引用(如果有 font_resolver)
|
||||
if self.font_resolver and isinstance(rendered_elem, dict):
|
||||
# 处理普通元素的 font 字段
|
||||
if 'font' in rendered_elem:
|
||||
font_config = rendered_elem['font']
|
||||
# 如果是字符串引用或字典,使用 FontResolver 解析
|
||||
if isinstance(font_config, (str, dict)):
|
||||
try:
|
||||
resolved_font = self.font_resolver.resolve_font(font_config)
|
||||
rendered_elem['font'] = resolved_font
|
||||
except ValueError as e:
|
||||
raise YAMLError(f"字体解析失败: {str(e)}")
|
||||
elif rendered_elem.get('type') in ['text', 'table']:
|
||||
# 元素未定义 font,使用 fonts_default(如果有)
|
||||
if self.font_resolver.fonts_default:
|
||||
try:
|
||||
resolved_font = self.font_resolver.resolve_font(None)
|
||||
rendered_elem['font'] = resolved_font
|
||||
except ValueError as e:
|
||||
raise YAMLError(f"字体解析失败: {str(e)}")
|
||||
|
||||
# 处理表格元素的 header_font 字段
|
||||
if rendered_elem.get('type') == 'table' and 'header_font' in rendered_elem:
|
||||
header_font_config = rendered_elem['header_font']
|
||||
if isinstance(header_font_config, (str, dict)):
|
||||
try:
|
||||
resolved_header_font = self.font_resolver.resolve_font(header_font_config)
|
||||
rendered_elem['header_font'] = resolved_header_font
|
||||
except ValueError as e:
|
||||
raise YAMLError(f"表格 header_font 解析失败: {str(e)}")
|
||||
|
||||
# 如果是图片元素且有相对路径,解析为绝对路径
|
||||
if isinstance(rendered_elem, dict) and rendered_elem.get('type') == 'image':
|
||||
src = rendered_elem.get('src')
|
||||
|
||||
Reference in New Issue
Block a user