1
0
Files
PPTX/openspec/changes/archive/2026-03-02-add-template-dir-parameter/design.md
lanyuanxiaoyao cd7988cbd5 feat: initial implementation of html2pptx with OpenSpec documentation
Add core Python script (yaml2pptx.py) for converting YAML to PowerPoint:
- Element rendering: text, image, shape, table, chart
- Template system with placeholders
- PPTX generation with python-pptx

OpenSpec workflow setup:
- 3 archived changes: browser-preview, template-dir-cli, yaml-to-pptx
- 7 main specifications covering all core modules
- Config and documentation structure

30 files changed, 4984 insertions(+)
2026-03-02 14:28:25 +08:00

202 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
当前 `yaml2pptx.py` 脚本的模板系统使用硬编码的相对路径 `templates_dir='templates'` 作为默认值。这导致脚本只能在包含 templates 目录的特定位置运行,限制了可移植性。
**当前实现**184-196行
```python
def __init__(self, template_file, templates_dir='templates'):
template_path = Path(template_file)
if not template_path.is_absolute() and not template_path.exists():
template_path = Path(templates_dir) / f"{template_file}.yaml"
```
**问题**
1. 默认值 `'templates'` 是相对于当前工作目录CWD不够明确
2. 先检查当前目录是否存在同名文件,可能导致意外行为
3. 没有验证模板名称,允许路径遍历(如 `../other/template`
4. 错误提示不够清晰
**约束**
- 脚本使用 Python 3.8+,通过 uv 运行
- 必须支持 Mac 和 Windows 平台
- 使用 pathlib.Path 处理路径(已在代码中使用)
- 保持向后兼容:不使用模板的用户不受影响
## Goals / Non-Goals
**Goals:**
- 支持通过 `--template-dir` 参数明确指定模板目录
- 移除隐式默认行为,使用模板时必须明确指定目录
- 添加模板名称验证,防止路径遍历
- 提供清晰的错误提示,告知用户查找位置和失败原因
- 确保跨平台兼容性Mac 和 Windows
**Non-Goals:**
- 不支持多个模板目录搜索路径
- 不支持模板目录的嵌套子目录
- 不改变模板文件格式或渲染逻辑
- 不影响不使用模板的纯自定义幻灯片
## Decisions
### 决策 1: 移除默认 templates_dir要求明确指定
**选择**: `templates_dir=None`,使用模板时必须通过 `--template-dir` 指定
**理由**:
- **明确性**: 避免"默认在哪里找"的困惑
- **可移植性**: 脚本可以在任何位置运行
- **统一性**: 所有模板都从同一个明确的位置加载
**替代方案**:
- 方案 A: 默认为源 YAML 文件目录下的 templates/
- ✗ 仍然是隐式行为,不够明确
- ✗ 如果 YAML 文件和模板不在同一位置,仍然会失败
- 方案 B: 支持多个搜索路径(如 `--template-dir dir1:dir2`
- ✗ 增加复杂度,违背"简单统一"的设计原则
- ✗ 可能导致模板命名冲突
### 决策 2: 使用 pathlib.Path 处理所有路径操作
**选择**: 统一使用 `pathlib.Path` 进行路径拼接、验证和存在性检查
**理由**:
- **跨平台**: Path 自动处理 Mac`/`)和 Windows`\`)的路径分隔符
- **安全性**: Path 对象避免了字符串拼接的错误
- **一致性**: 代码中已经在使用 Path
**实现**:
```python
# 路径拼接(跨平台)
template_path = Path(templates_dir) / f"{template_file}.yaml"
# 存在性检查
if not template_path.exists():
raise YAMLError(...)
```
### 决策 3: 模板名称验证 - 禁止路径分隔符
**选择**: 检查模板名称中是否包含 `/``\`,如果包含则报错
**理由**:
- **安全性**: 防止路径遍历攻击(如 `../../etc/passwd`
- **简单性**: 只支持一层目录,逻辑清晰
- **跨平台**: 同时检查两种路径分隔符
**实现**:
```python
if '/' in template_file or '\\' in template_file:
raise YAMLError(
f"模板名称不能包含路径分隔符: {template_file}\n"
f"模板名称应该是纯文件名,如: 'title-slide'"
)
```
**替代方案**:
- 方案 A: 使用 `os.path.sep` 只检查当前平台的分隔符
- ✗ 在 Windows 上创建的 YAML 文件可能包含 `/`,在 Mac 上会被忽略
- ✗ 不够严格,可能导致跨平台问题
- 方案 B: 使用正则表达式验证文件名格式
- ✗ 过度设计,简单的字符串检查已足够
### 决策 4: 改进错误提示 - 三层信息
**选择**: 错误信息包含三层:问题描述、查找位置、解决建议
**理由**:
- **可调试性**: 用户能快速定位问题
- **可操作性**: 提供明确的解决方案
**实现**:
```python
# 未指定 template_dir
raise YAMLError(
f"未指定模板目录,无法加载模板: {template_file}\n"
f"请使用 --template-dir 参数指定模板目录"
)
# 模板文件不存在
raise YAMLError(
f"模板文件不存在: {template_file}\n"
f"查找位置: {templates_dir}\n"
f"期望文件: {template_path}\n"
f"提示: 请检查模板名称和模板目录是否正确"
)
```
### 决策 5: 参数传递链 - 从 CLI 到 Template
**选择**: `main() → Presentation() → Template()`
**理由**:
- **清晰性**: 参数传递路径明确
- **最小改动**: 只需修改参数默认值和传递方式
**实现**:
```python
# parse_args: 添加参数
parser.add_argument('--template-dir', type=str, default=None)
# main: 传递给 Presentation
pres = Presentation(input_path, templates_dir=args.template_dir)
# Presentation.__init__: 传递给 Template
def __init__(self, pres_file, templates_dir=None):
self.templates_dir = templates_dir
# Template.__init__: 使用参数
def __init__(self, template_file, templates_dir=None):
if templates_dir is None:
raise YAMLError(...)
```
## Risks / Trade-offs
### 风险 1: 破坏性变更影响现有用户
**风险**: 现有使用模板的用户升级后脚本会报错
**缓解**:
- 提供清晰的错误信息,告知用户需要添加 `--template-dir` 参数
- 在文档中明确标注为破坏性变更
- 错误信息中包含使用示例
### 风险 2: 相对路径的解析基准
**风险**: 用户可能不清楚相对路径是相对于哪里
**决策**: 相对路径相对于当前工作目录CWD这是命令行工具的标准行为
**缓解**:
- 在帮助信息中说明
- 错误信息中显示完整的绝对路径
### 风险 3: Windows 路径中的反斜杠
**风险**: Windows 用户可能在命令行中输入 `C:\templates`shell 可能需要转义
**缓解**:
- Python 的 argparse 会正确处理
- 用户可以使用正斜杠 `C:/templates`Windows 支持)
- 在文档中提供 Windows 示例
### 权衡 1: 灵活性 vs 简单性
**权衡**: 不支持多模板目录搜索路径,牺牲了灵活性
**理由**:
- 大多数用户只需要一个模板目录
- 如果需要多个来源,可以使用符号链接或复制文件
- 保持逻辑简单,易于理解和维护
### 权衡 2: 向后兼容 vs 明确性
**权衡**: 破坏性变更,不向后兼容
**理由**:
- 隐式默认行为是问题的根源
- 明确性比兼容性更重要
- 影响范围可控(只影响使用模板的用户)
- 修复成本低(只需添加一个参数)