1
0
Files
lanyuanxiaoyao 66472cbd86 refactor: restructure CLI with clear subcommand architecture
重构命令行接口,建立清晰的子命令架构,提升用户体验和代码可维护性。

主要变更:
- 移除传统模式,统一使用子命令架构(check/convert/preview)
- 将 preview 从 convert 的标志独立为子命令,职责分离
- 重命名参数:--no-check → --skip-validation
- 新增 --force/-f:convert 命令支持强制覆盖已存在文件
- 新增 --host:preview 命令支持配置主机地址(局域网预览)
- 新增 --no-browser:preview 命令支持不自动打开浏览器
- 优化 --port 默认值:从固定端口改为随机端口(30000-40000)

破坏性变更:
- 不再支持传统模式(yaml2pptx.py input.yaml output.pptx)
- convert 命令不再支持 --preview 参数,需使用 preview 子命令

文档更新:
- 更新 README.md 和 README_DEV.md 的所有使用示例
- 更新命令行选项说明表格
- 新增 CLI 接口规范文档

OpenSpec:
- 创建 cli-interface 规范(新能力)
- 更新 browser-preview-server 规范(修改的能力)
- 归档 refactor-cli-args change(45/45 任务完成)
2026-03-02 18:47:50 +08:00

188 lines
6.7 KiB
Markdown
Raw Permalink 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` 的 CLI 实现存在以下问题:
1. **双模式解析**:同时支持子命令模式(`check`/`convert`)和传统模式(直接参数),导致参数解析逻辑复杂,代码中需要手动检查 `sys.argv[1]` 来决定使用哪种解析器
2. **职责混乱**`convert` 命令通过 `--preview` 标志切换到预览模式,但 convert 和 preview 是完全不同的操作(一个生成文件,一个启动服务器)
3. **参数重复定义**`--template-dir``--preview``--port` 等参数在两个解析器中重复定义
4. **命名不清晰**`--no-check` 是双重否定,不够直观
本次重构的目标是建立清晰的子命令架构,提升代码可维护性和用户体验。
## Goals / Non-Goals
**Goals:**
- 统一使用子命令架构,移除传统模式
- 将 preview 独立为子命令,职责分离
- 简化参数解析逻辑,消除代码重复
- 优化参数命名和默认值
- 新增实用功能(文件覆盖控制、局域网预览、浏览器控制)
**Non-Goals:**
- 不改变核心转换逻辑YAML 解析、PPTX 生成)
- 不改变验证逻辑ERROR/WARNING/INFO 分级)
- 不改变预览服务器的核心功能文件监听、SSE 推送)
- 不考虑向后兼容传统模式(项目未上线)
## Decisions
### 决策 1使用纯子命令架构
**选择:** 移除传统模式,统一使用 `<command> <subcommand>` 结构
**理由:**
- 子命令架构更清晰,每个子命令职责单一
- 避免双模式解析的复杂性
- 符合现代 CLI 工具的设计习惯(如 git、docker
**替代方案:**
- 保留传统模式作为快捷方式:增加维护成本,用户容易混淆
- 使用选项组而非子命令:无法清晰表达互斥的操作模式
### 决策 2preview 独立为子命令
**选择:** 将 preview 从 `convert --preview` 改为独立的 `preview` 子命令
**理由:**
- convert 和 preview 是完全不同的操作:
- convert一次性操作生成文件后退出
- preview长期运行启动服务器监听文件变化
- 独立子命令使参数更清晰preview 特有的 `--port``--host``--no-browser` 不会出现在 convert 中)
- 符合单一职责原则
**替代方案:**
- 保持 `convert --preview`:职责混乱,参数难以组织
- 使用 `serve``watch` 命名preview 更直观,表达预览意图
### 决策 3参数解析使用 argparse 的 subparsers
**选择:** 使用 argparse 的 `add_subparsers()``required=True`
**理由:**
- argparse 是 Python 标准库,无需额外依赖
- subparsers 自动处理子命令路由,无需手动检查 `sys.argv`
- 自动生成帮助信息
**实现结构:**
```python
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command', required=True)
# 每个子命令独立配置
check_parser = subparsers.add_parser('check')
convert_parser = subparsers.add_parser('convert')
preview_parser = subparsers.add_parser('preview')
```
### 决策 4preview 默认使用随机端口30000-40000
**选择:** `--port` 默认值为 None运行时随机选择 30000-40000 范围内的端口
**理由:**
- 避免端口冲突,支持同时运行多个预览实例
- 30000+ 端口通常不被系统服务占用
- 用户可以通过 `--port` 指定固定端口
**替代方案:**
- 固定端口 5000容易冲突不支持多实例
- 完全随机端口1024-65535可能与其他服务冲突
### 决策 5convert 默认不覆盖已存在文件
**选择:** 输出文件已存在时报错,需要 `--force/-f` 强制覆盖
**理由:**
- 避免意外覆盖用户文件
- 符合安全优先原则
- 提供明确的覆盖控制
**替代方案:**
- 默认覆盖:不安全,可能导致数据丢失
- 自动重命名(如 output-1.pptx用户可能不知道生成了多个文件
### 决策 6简化参数移除不必要的选项
**选择:** 移除 `--verbose``--quiet``--strict``--format``--no-watch`
**理由:**
- `--verbose`/`--quiet`:当前输出已经足够简洁,不需要额外控制
- `--strict`:保持原有的 ERROR/WARNING/INFO 分级即可
- `--format`命令行工具主要面向人类用户text 格式足够
- `--no-watch`preview 的核心价值就是实时监听,不需要关闭
**保留的参数:**
- `--template-dir`:所有命令通用
- `--skip-validation`convert 特有,用于快速转换
- `--force/-f`convert 特有,文件覆盖控制
- `--port``--host``--no-browser`preview 特有
## Risks / Trade-offs
### 风险 1破坏性变更影响现有用户
**风险:** 移除传统模式和 `convert --preview` 会导致现有脚本失效
**缓解措施:**
- 项目未上线,无现有用户
- 更新所有文档和示例
- 在错误信息中提示新的使用方式(如检测到 `--preview` 时提示使用 `preview` 子命令)
### 风险 2随机端口可能导致防火墙问题
**风险:** 随机端口可能被防火墙阻止
**缓解措施:**
- 用户可以通过 `--port` 指定固定端口
- 在文档中说明端口范围30000-40000
- 默认 host 为 127.0.0.1,仅本地访问
### 风险 3参数验证逻辑需要重新实现
**风险:** 移除双模式后,参数验证逻辑需要调整
**缓解措施:**
-`main()` 函数中统一验证输入文件存在性
-`handle_convert()` 中验证输出文件覆盖逻辑
-`handle_preview()` 中验证端口合法性
## Migration Plan
### 实施步骤
1. **重构 `parse_args()` 函数**
- 移除双模式检查逻辑
- 使用 `subparsers.add_parser()` 定义三个子命令
- 为每个子命令配置独立的参数
2. **更新 `handle_convert()` 函数**
- 移除 `--preview` 相关逻辑
- 添加输出文件存在性检查(`--force` 控制)
- 保持自动验证逻辑(`--skip-validation` 控制)
3. **创建 `handle_preview()` 函数**
-`handle_convert()` 中提取 preview 逻辑
- 添加随机端口生成逻辑
- 调用 `start_preview_server()` 时传递新参数
4. **更新 `preview/server.py`**
- 修改 `start_preview_server()` 函数签名
- 添加 `host` 参数(默认 127.0.0.1
- 添加 `open_browser` 参数(默认 True
- 更新端口随机生成逻辑30000-40000
5. **更新文档**
- 更新 `README.md` 中的所有使用示例
- 更新命令行选项说明表格
- 添加迁移指南(如果需要)
### 回滚策略
如果发现重大问题,可以:
1. 回退到上一个 commit
2. 保留新的子命令架构,但临时添加传统模式兼容层
3. 通过环境变量或配置文件控制行为
## Open Questions
无待解决的问题。设计已经明确,可以开始实施。