From bb449259d3406d76f2ad584abfb7d7beec108ea9 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:36:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(docs):=20=E6=B7=BB=E5=8A=A0=20VitePress=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90=E6=8A=80=E8=83=BD=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 .claude/skills 目录及完整的文档生成技能系统 - 添加批量 API 文档生成脚本支持模块化文档创建 - 添加 API 文档、功能指南和教程生成模板与示例 - 添加 C# XML 注释解析和代码示例生成工具 - 添加文档验证和导航更新脚本确保质量 - 更新 .gitignore 配置排除本地设置文件 --- .claude/skills/README.md | 469 ++++++++++++++++++ .../_shared/scripts/generate-examples.sh | 38 ++ .../_shared/scripts/parse-csharp-xml.sh | 48 ++ .../_shared/scripts/update-vitepress-nav.sh | 42 ++ .claude/skills/vitepress-api-doc/SKILL.md | 210 ++++++++ .../examples/class-example.md | 252 ++++++++++ .../examples/enum-example.md | 193 +++++++ .../examples/interface-example.md | 290 +++++++++++ .claude/skills/vitepress-api-doc/template.md | 37 ++ .claude/skills/vitepress-batch-api/SKILL.md | 364 ++++++++++++++ .../scripts/batch-generate.sh | 87 ++++ .../skills/vitepress-doc-generator/SKILL.md | 52 ++ .../vitepress-doc-generator/template.md | 0 .claude/skills/vitepress-guide/SKILL.md | 256 ++++++++++ .../vitepress-guide/examples/guide-example.md | 283 +++++++++++ .claude/skills/vitepress-guide/template.md | 34 ++ .claude/skills/vitepress-tutorial/SKILL.md | 253 ++++++++++ .../examples/tutorial-example.md | 347 +++++++++++++ .claude/skills/vitepress-tutorial/template.md | 42 ++ .claude/skills/vitepress-validate/SKILL.md | 297 +++++++++++ .../scripts/validate-all.sh | 109 ++++ .../scripts/validate-code-blocks.sh | 64 +++ .../scripts/validate-frontmatter.sh | 57 +++ .../scripts/validate-links.sh | 85 ++++ .gitignore | 2 +- 25 files changed, 3910 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/README.md create mode 100644 .claude/skills/_shared/scripts/generate-examples.sh create mode 100644 .claude/skills/_shared/scripts/parse-csharp-xml.sh create mode 100644 .claude/skills/_shared/scripts/update-vitepress-nav.sh create mode 100644 .claude/skills/vitepress-api-doc/SKILL.md create mode 100644 .claude/skills/vitepress-api-doc/examples/class-example.md create mode 100644 .claude/skills/vitepress-api-doc/examples/enum-example.md create mode 100644 .claude/skills/vitepress-api-doc/examples/interface-example.md create mode 100644 .claude/skills/vitepress-api-doc/template.md create mode 100644 .claude/skills/vitepress-batch-api/SKILL.md create mode 100644 .claude/skills/vitepress-batch-api/scripts/batch-generate.sh create mode 100644 .claude/skills/vitepress-doc-generator/SKILL.md create mode 100644 .claude/skills/vitepress-doc-generator/template.md create mode 100644 .claude/skills/vitepress-guide/SKILL.md create mode 100644 .claude/skills/vitepress-guide/examples/guide-example.md create mode 100644 .claude/skills/vitepress-guide/template.md create mode 100644 .claude/skills/vitepress-tutorial/SKILL.md create mode 100644 .claude/skills/vitepress-tutorial/examples/tutorial-example.md create mode 100644 .claude/skills/vitepress-tutorial/template.md create mode 100644 .claude/skills/vitepress-validate/SKILL.md create mode 100644 .claude/skills/vitepress-validate/scripts/validate-all.sh create mode 100644 .claude/skills/vitepress-validate/scripts/validate-code-blocks.sh create mode 100644 .claude/skills/vitepress-validate/scripts/validate-frontmatter.sh create mode 100644 .claude/skills/vitepress-validate/scripts/validate-links.sh diff --git a/.claude/skills/README.md b/.claude/skills/README.md new file mode 100644 index 0000000..c76819b --- /dev/null +++ b/.claude/skills/README.md @@ -0,0 +1,469 @@ +# VitePress 文档生成 Skills 系统 + +为 GFramework 项目提供自动化的 VitePress 文档生成能力。 + +## 概述 + +这是一套专门为 GFramework 项目设计的文档生成 skills,能够根据 C# 源代码自动生成高质量的 VitePress 文档。系统采用模块化设计,每个 skill 专注于特定的文档生成任务。 + +## 可用 Skills + +### 1. vitepress-api-doc - API 文档生成 + +为单个 C# 文件生成 API 参考文档。 + +**用途**: +- 类、接口、枚举的 API 文档 +- 方法、属性、事件的详细说明 +- 基于 XML 注释生成文档 + +**调用方式**: +```bash +/vitepress-api-doc +``` + +**示例**: +```bash +/vitepress-api-doc GFramework.Core/architecture/Architecture.cs +``` + +**输出位置**:`docs/zh-CN/api-reference/<模块>/<文件名>.md` + +[详细文档](./vitepress-api-doc/SKILL.md) + +--- + +### 2. vitepress-guide - 功能指南生成 + +生成功能模块的使用指南文档。 + +**用途**: +- 核心功能模块的使用说明 +- 设计模式和架构概念 +- 最佳实践和常见问题 + +**调用方式**: +```bash +/vitepress-guide <主题> <目标模块> +``` + +**示例**: +```bash +/vitepress-guide "事件系统" Core +/vitepress-guide "IoC 容器" Core +``` + +**输出位置**:`docs/zh-CN/<模块>/<主题>.md` + +[详细文档](./vitepress-guide/SKILL.md) + +--- + +### 3. vitepress-tutorial - 分步教程生成 + +生成分步教程文档,适合初学者学习。 + +**用途**: +- 框架入门教程 +- 功能实现教程 +- 问题解决方案 + +**调用方式**: +```bash +/vitepress-tutorial <教程主题> +``` + +**示例**: +```bash +/vitepress-tutorial "创建第一个 System" +/vitepress-tutorial "使用事件系统" +``` + +**输出位置**:`docs/zh-CN/tutorials/<主题>.md` + +[详细文档](./vitepress-tutorial/SKILL.md) + +--- + +### 4. vitepress-batch-api - 批量 API 文档生成 + +为整个模块批量生成 API 文档。 + +**用途**: +- 初始化模块文档 +- 更新整个模块的文档 +- 快速生成大量文档 + +**调用方式**: +```bash +/vitepress-batch-api <模块名> +``` + +**示例**: +```bash +/vitepress-batch-api Core +/vitepress-batch-api Godot +``` + +**输出位置**:`docs/zh-CN/api-reference/<模块>/` + +[详细文档](./vitepress-batch-api/SKILL.md) + +--- + +### 5. vitepress-validate - 文档验证 + +验证文档的质量和规范性。 + +**用途**: +- Frontmatter 格式验证 +- 内部链接有效性检查 +- 代码块语法验证 +- 标点符号规范检查 + +**调用方式**: +```bash +/vitepress-validate <文件或目录路径> +``` + +**示例**: +```bash +/vitepress-validate docs/zh-CN/api-reference/core/architecture.md +/vitepress-validate docs/zh-CN/ +``` + +[详细文档](./vitepress-validate/SKILL.md) + +--- + +## 快速开始 + +### 1. 生成单个 API 文档 + +```bash +# 为 Architecture 类生成文档 +/vitepress-api-doc GFramework.Core/architecture/Architecture.cs +``` + +### 2. 批量生成模块文档 + +```bash +# 为整个 Core 模块生成文档 +/vitepress-batch-api Core +``` + +### 3. 生成功能指南 + +```bash +# 生成事件系统使用指南 +/vitepress-guide "事件系统" Core +``` + +### 4. 生成教程 + +```bash +# 生成创建 Model 的教程 +/vitepress-tutorial "创建第一个 Model" +``` + +### 5. 验证文档 + +```bash +# 验证生成的文档 +/vitepress-validate docs/zh-CN/api-reference/core/ +``` + +## 工作流程 + +### 典型工作流程 + +```mermaid +graph TD + A[开始] --> B{文档类型?} + B -->|API 文档| C[/vitepress-api-doc] + B -->|功能指南| D[/vitepress-guide] + B -->|教程| E[/vitepress-tutorial] + C --> F[/vitepress-validate] + D --> F + E --> F + F --> G{验证通过?} + G -->|是| H[完成] + G -->|否| I[修复问题] + I --> F +``` + +### 推荐流程 + +1. **初始化模块文档** + ```bash + /vitepress-batch-api Core + ``` + +2. **生成功能指南** + ```bash + /vitepress-guide "IoC 容器" Core + /vitepress-guide "事件系统" Core + ``` + +3. **生成教程** + ```bash + /vitepress-tutorial "创建第一个 Model" + /vitepress-tutorial "使用命令系统" + ``` + +4. **验证所有文档** + ```bash + /vitepress-validate docs/zh-CN/ + ``` + +## 目录结构 + +``` +.claude/skills/ +├── README.md # 本文件 +├── _shared/ # 共享资源 +│ └── scripts/ # 共享脚本 +│ ├── update-vitepress-nav.sh # 更新导航配置 +│ ├── parse-csharp-xml.sh # 解析 XML 注释 +│ └── generate-examples.sh # 生成代码示例 +│ +├── vitepress-api-doc/ # API 文档生成 +│ ├── SKILL.md # Skill 说明 +│ ├── template.md # 文档模板 +│ └── examples/ # 示例文档 +│ ├── class-example.md +│ ├── interface-example.md +│ └── enum-example.md +│ +├── vitepress-guide/ # 功能指南生成 +│ ├── SKILL.md +│ ├── template.md +│ └── examples/ +│ └── guide-example.md +│ +├── vitepress-tutorial/ # 教程生成 +│ ├── SKILL.md +│ ├── template.md +│ └── examples/ +│ └── tutorial-example.md +│ +├── vitepress-batch-api/ # 批量 API 文档生成 +│ ├── SKILL.md +│ └── scripts/ +│ └── batch-generate.sh +│ +└── vitepress-validate/ # 文档验证 + ├── SKILL.md + └── scripts/ + ├── validate-frontmatter.sh + ├── validate-links.sh + ├── validate-code-blocks.sh + └── validate-all.sh +``` + +## 设计原则 + +### 1. 单一职责 + +每个 skill 专注于一个特定任务: +- `vitepress-api-doc` - 单文件 API 文档 +- `vitepress-guide` - 功能指南 +- `vitepress-tutorial` - 分步教程 +- `vitepress-batch-api` - 批量生成 +- `vitepress-validate` - 质量验证 + +### 2. 模块化设计 + +- 共享脚本放在 `_shared/scripts/` +- 每个 skill 独立维护 +- 可以单独使用或组合使用 + +### 3. 基于源代码 + +- 仅使用 XML 注释,不添加 AI 补充 +- 保持文档与代码同步 +- 代码示例由 AI 自动生成 + +### 4. 质量保证 + +- 所有生成的文档都应通过验证 +- 遵循 VitePress 规范 +- 保持一致的文档风格 + +## 文档规范 + +### Frontmatter 格式 + +```yaml +--- +title: 文档标题 +description: 简短描述(1-2 句话) +outline: deep # 可选 +--- +``` + +### 代码块标记 + +- C# 代码使用 `csharp` +- Bash 脚本使用 `bash` +- JSON 使用 `json` +- YAML 使用 `yaml` + +### 泛型符号转义 + +在正文中使用 HTML 实体: +- `List` → `List<T>` +- 代码块内保持原样 + +### 中文标点符号 + +- 中文句子使用全角标点:,。!? +- 英文句子使用半角标点:,.!? +- 代码周围使用半角符号 + +## 共享脚本 + +### update-vitepress-nav.sh + +更新 VitePress 侧边栏导航配置。 + +**用法**: +```bash +.claude/skills/_shared/scripts/update-vitepress-nav.sh <文件路径> <标题> +``` + +### parse-csharp-xml.sh + +解析 C# XML 文档注释。 + +**用法**: +```bash +.claude/skills/_shared/scripts/parse-csharp-xml.sh +``` + +### generate-examples.sh + +生成代码示例。 + +**用法**: +```bash +.claude/skills/_shared/scripts/generate-examples.sh <类型名> <命名空间> +``` + +## 最佳实践 + +### 1. 文档生成顺序 + +1. 先生成 API 文档(基础) +2. 再生成功能指南(概念) +3. 最后生成教程(实践) + +### 2. 保持文档同步 + +- 修改代码后及时更新文档 +- 使用单文件生成更新特定文档 +- 定期批量验证所有文档 + +### 3. 质量控制 + +- 生成后立即验证 +- 修复所有错误和警告 +- 确保链接有效 + +### 4. 版本控制 + +- 将生成的文档提交到 Git +- 在 PR 中包含文档更新 +- 保持文档与代码版本一致 + +## 故障排除 + +### 问题:生成的文档缺少内容 + +**原因**:源代码缺少 XML 注释 + +**解决方案**: +1. 在源代码中添加 XML 注释 +2. 重新生成文档 + +### 问题:验证失败 + +**原因**:文档格式不符合规范 + +**解决方案**: +1. 查看验证错误信息 +2. 根据提示修复问题 +3. 重新验证 + +### 问题:链接损坏 + +**原因**:文件路径错误或文件不存在 + +**解决方案**: +1. 检查链接的目标文件是否存在 +2. 修正文件路径 +3. 重新验证 + +### 问题:批量生成速度慢 + +**原因**:文件数量多 + +**解决方案**: +1. 使用 `--parallel` 选项(如果支持) +2. 分批生成 +3. 仅生成修改的文件 + +## 扩展开发 + +### 添加新 Skill + +1. 在 `.claude/skills/` 下创建新目录 +2. 创建 `SKILL.md` 说明文档 +3. 创建必要的模板和脚本 +4. 在本 README 中添加说明 + +### 修改现有 Skill + +1. 更新 `SKILL.md` 文档 +2. 修改模板或脚本 +3. 更新示例文档 +4. 测试修改后的功能 + +## 贡献指南 + +### 报告问题 + +在 GitHub Issues 中报告问题,包含: +- 使用的 skill 名称 +- 输入参数 +- 预期结果 +- 实际结果 +- 错误信息 + +### 提交改进 + +1. Fork 项目 +2. 创建功能分支 +3. 提交修改 +4. 创建 Pull Request + +## 版本历史 + +- v1.0.0 (2025-01-XX) - 初始版本 + - 5 个核心 skills + - 3 个共享脚本 + - 完整的文档和示例 + +## 许可证 + +与 GFramework 项目保持一致。 + +## 联系方式 + +如有问题或建议,请通过以下方式联系: +- GitHub Issues +- 项目讨论区 + +--- + +**注意**:本 skills 系统专为 GFramework 项目设计,使用前请确保了解项目结构和文档规范。 diff --git a/.claude/skills/_shared/scripts/generate-examples.sh b/.claude/skills/_shared/scripts/generate-examples.sh new file mode 100644 index 0000000..8de7f7c --- /dev/null +++ b/.claude/skills/_shared/scripts/generate-examples.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# 生成代码示例辅助脚本 +# 用法: generate-examples.sh <类型> <类名> + +set -e + +TYPE="$1" # class/interface/enum +CLASS_NAME="$2" + +if [ -z "$TYPE" ] || [ -z "$CLASS_NAME" ]; then + echo "用法: $0 <类型> <类名>" + echo "类型: class, interface, enum" + exit 1 +fi + +echo "生成 $CLASS_NAME 的示例代码..." +echo "类型: $TYPE" + +# 注意: 此脚本仅输出提示信息 +# 实际的示例代码生成由 AI 根据 API 签名和现有教程风格完成 + +case "$TYPE" in + class) + echo "提示: 为类生成示例,包括实例化、方法调用、属性访问" + ;; + interface) + echo "提示: 为接口生成示例,包括实现类和使用方式" + ;; + enum) + echo "提示: 为枚举生成示例,包括值比较和 switch 语句" + ;; + *) + echo "错误: 不支持的类型: $TYPE" + exit 1 + ;; +esac + +exit 0 diff --git a/.claude/skills/_shared/scripts/parse-csharp-xml.sh b/.claude/skills/_shared/scripts/parse-csharp-xml.sh new file mode 100644 index 0000000..7656caa --- /dev/null +++ b/.claude/skills/_shared/scripts/parse-csharp-xml.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# 解析 C# XML 文档注释 +# 用法: parse-csharp-xml.sh + +set -e + +FILE_PATH="$1" + +if [ -z "$FILE_PATH" ]; then + echo "用法: $0 " + exit 1 +fi + +if [ ! -f "$FILE_PATH" ]; then + echo "错误: 文件不存在: $FILE_PATH" + exit 1 +fi + +echo "解析 C# XML 文档注释: $FILE_PATH" + +# 提取 summary 标签内容 +echo "=== Summary ===" +grep -A 5 "/// " "$FILE_PATH" | grep "///" | sed 's/.*\/\/\/\s*//' | sed 's///g' | sed 's/<\/summary>//g' || echo "未找到 summary" + +# 提取 param 标签内容 +echo "" +echo "=== Parameters ===" +grep "/// " "$FILE_PATH" | sed 's/.*\/\/\/\s*//' | sed 's///g' | sed 's/<\/returns>//g' || echo "未找到 returns" + +# 提取 exception 标签内容 +echo "" +echo "=== Exceptions ===" +grep "/// " "$FILE_PATH" | grep "///" | sed 's/.*\/\/\/\s*//' || echo "未找到 example" + +echo "" +echo "解析完成" + +exit 0 diff --git a/.claude/skills/_shared/scripts/update-vitepress-nav.sh b/.claude/skills/_shared/scripts/update-vitepress-nav.sh new file mode 100644 index 0000000..2ce6946 --- /dev/null +++ b/.claude/skills/_shared/scripts/update-vitepress-nav.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# 更新 VitePress 侧边栏配置 +# 用法: update-vitepress-nav.sh <文档路径> <文档标题> + +set -e + +DOC_PATH="$1" +DOC_TITLE="$2" +CONFIG_FILE="docs/.vitepress/config.mts" + +if [ -z "$DOC_PATH" ] || [ -z "$DOC_TITLE" ]; then + echo "用法: $0 <文档路径> <文档标题>" + echo "示例: $0 /zh-CN/api-reference/core/architecture.md Architecture" + exit 1 +fi + +if [ ! -f "$CONFIG_FILE" ]; then + echo "错误: 找不到 VitePress 配置文件: $CONFIG_FILE" + exit 1 +fi + +# 提取模块名称(core/game/godot/source-generators) +MODULE=$(echo "$DOC_PATH" | grep -oP '(?<=/zh-CN/)[^/]+' | head -1) + +if [ -z "$MODULE" ]; then + echo "错误: 无法从路径中提取模块名称: $DOC_PATH" + exit 1 +fi + +echo "正在更新 VitePress 配置..." +echo " 模块: $MODULE" +echo " 路径: $DOC_PATH" +echo " 标题: $DOC_TITLE" + +# 注意: 此脚本仅输出提示信息 +# 实际的配置更新由 AI 直接编辑 config.mts 文件完成 +# 因为 TypeScript 配置文件的复杂性,使用脚本解析和修改容易出错 + +echo "提示: 请手动更新 $CONFIG_FILE 中的侧边栏配置" +echo "或者让 AI 使用 Edit 工具直接修改配置文件" + +exit 0 diff --git a/.claude/skills/vitepress-api-doc/SKILL.md b/.claude/skills/vitepress-api-doc/SKILL.md new file mode 100644 index 0000000..f7bc7b6 --- /dev/null +++ b/.claude/skills/vitepress-api-doc/SKILL.md @@ -0,0 +1,210 @@ +# VitePress API 文档生成 + +为单个 C# 类、接口或枚举生成符合 VitePress 标准的 API 参考文档。 + +## 用途 + +此 skill 用于从 C# 源代码文件自动生成结构化的 API 文档,包括: +- 类型概述和命名空间信息 +- 构造函数、方法、属性的详细说明 +- 基于 XML 文档注释的描述 +- 自动生成的使用示例 +- 相关类型的交叉引用 + +## 调用方式 + +```bash +/vitepress-api-doc +``` + +**示例**: +```bash +/vitepress-api-doc GFramework.Core/architecture/Architecture.cs +``` + +## 工作流程 + +1. **读取源代码文件** + - 验证文件存在且为 C# 文件 + - 读取完整的源代码内容 + +2. **解析代码结构** + - 提取命名空间、类名、访问修饰符 + - 识别类型(class/interface/enum/struct) + - 解析继承关系和实现的接口 + - 提取所有公共成员(构造函数、方法、属性、事件、字段) + +3. **提取 XML 文档注释** + - 解析 `/// ` 标签(类型和成员描述) + - 解析 `/// ` 标签(参数说明) + - 解析 `/// ` 标签(返回值说明) + - 解析 `/// ` 标签(异常说明) + - 解析 `/// ` 标签(示例代码) + - 解析 `/// ` 标签(交叉引用) + +4. **生成 Markdown 文档** + - 根据 `template.md` 填充内容 + - 转义泛型符号(`` → `<T>`) + - 生成使用示例(基于 API 签名) + - 添加相关文档链接 + +5. **确定输出路径** + - 根据命名空间确定模块(Core/Game/Godot/SourceGenerators) + - 输出到 `docs/zh-CN/api-reference/<模块>/<类名>.md` + +6. **更新 VitePress 配置** + - 调用共享脚本 `update-vitepress-nav.sh` + - 在侧边栏配置中添加新文档条目 + +7. **验证文档质量** + - 检查 Frontmatter 格式 + - 验证内部链接 + - 确保代码块语法正确 + +## 输出规范 + +### Frontmatter 格式 + +```yaml +--- +title: 类名 +description: 从 XML 提取的简短描述 +outline: deep +--- +``` + +### 文档结构 + +1. **标题**:使用类名作为一级标题 +2. **概述**:XML summary 内容 +3. **命名空间和程序集信息** +4. **继承链**(如果适用) +5. **构造函数**(如果有) +6. **公共方法**(按字母顺序) +7. **公共属性**(按字母顺序) +8. **公共事件**(如果有) +9. **使用示例**(自动生成) +10. **另请参阅**(相关类型链接) + +### 代码块格式 + +所有 C# 代码块必须使用: +```markdown +\`\`\`csharp +// 代码内容 +\`\`\` +``` + +### 泛型符号转义 + +- `List` → `List<T>` +- `Dictionary` → `Dictionary<K, V>` +- `IEnumerable` → `IEnumerable<T>` + +### 内部链接格式 + +- 相对路径:`[Architecture](./architecture.md)` +- 绝对路径:`[Core 架构](/zh-CN/core/architecture)` +- 锚点链接:`[构造函数](#构造函数)` + +## 前置条件 + +1. 项目必须有 VitePress 配置文件(`docs/.vitepress/config.mts`) +2. 目标 C# 文件必须存在且可读 +3. C# 文件必须包含 XML 文档注释(`///`) +4. 文件必须包含至少一个公共类型 + +## 配置选项 + +### 自动检测模块 + +根据命名空间自动确定模块: +- `GFramework.Core.*` → `core` +- `GFramework.Game.*` → `game` +- `GFramework.Godot.*` → `godot` +- `GFramework.SourceGenerators.*` → `source-generators` + +### 示例生成策略 + +- **基本用法**:最简单的 API 调用 +- **常见场景**:实际应用案例 +- **高级用法**:复杂配置(如果适用) + +## 示例输出 + +参考 `examples/` 目录中的示例文档: +- `class-example.md` - 类文档示例 +- `interface-example.md` - 接口文档示例 +- `enum-example.md` - 枚举文档示例 + +## 注意事项 + +1. **仅使用 XML 注释**:不对缺失的注释进行 AI 补充 +2. **仅提取公共成员**:忽略 `internal`、`private`、`protected` 成员 +3. **保持文档同步**:文档内容直接来源于代码,确保准确性 +4. **遵循项目风格**:参考现有文档的格式和术语 + +## 相关 Skills + +- `/vitepress-validate` - 验证生成的文档质量 +- `/vitepress-batch-api` - 批量生成整个模块的 API 文档 + +## 技术细节 + +### XML 注释标签映射 + +| XML 标签 | Markdown 输出 | +|---------|--------------| +| `` | 概述章节 | +| `` | 参数列表 | +| `` | 返回值说明 | +| `` | 异常列表 | +| `` | 示例代码块 | +| `` | 内部链接 | +| `` | 备注章节 | + +### 成员签名格式 + +**方法**: +```markdown +### MethodName + +描述内容 + +**签名**: +\`\`\`csharp +public ReturnType MethodName(ParamType param) +\`\`\` + +**参数**: +- `param` (ParamType): 参数说明 + +**返回值**: +- (ReturnType): 返回值说明 +``` + +**属性**: +```markdown +### PropertyName + +描述内容 + +**类型**:`PropertyType` + +**访问**:get / set +``` + +## 故障排除 + +### 问题:找不到 XML 注释 +**解决方案**:确保 C# 文件包含 `///` 注释,而不是 `//` 或 `/* */` + +### 问题:泛型符号显示错误 +**解决方案**:VitePress 配置中已包含 `safeGenericEscapePlugin`,确保正确转义 + +### 问题:侧边栏未更新 +**解决方案**:检查 `update-vitepress-nav.sh` 脚本是否正确执行 + +## 版本历史 + +- v1.0.0 - 初始版本,支持类、接口、枚举的文档生成 diff --git a/.claude/skills/vitepress-api-doc/examples/class-example.md b/.claude/skills/vitepress-api-doc/examples/class-example.md new file mode 100644 index 0000000..c536120 --- /dev/null +++ b/.claude/skills/vitepress-api-doc/examples/class-example.md @@ -0,0 +1,252 @@ +--- +title: Architecture +description: 架构基类,提供系统、模型、工具等组件的注册与管理功能。专注于生命周期管理、初始化流程控制和架构阶段转换。 +outline: deep +--- + +# Architecture + +## 概述 + +架构基类,提供系统、模型、工具等组件的注册与管理功能。专注于生命周期管理、初始化流程控制和架构阶段转换。 + +**命名空间**:`GFramework.Core.architecture` +**程序集**:`GFramework.Core` +**继承**:`Object` → `Architecture` +**实现**:`IArchitecture` + +## 构造函数 + +### Architecture + +创建架构实例。 + +**签名**: +```csharp +public Architecture( + IArchitectureConfiguration? configuration = null, + IEnvironment? environment = null, + IArchitectureServices? services = null, + IArchitectureContext? context = null +) +``` + +**参数**: +- `configuration` (IArchitectureConfiguration?): 架构配置对象,为 null 时使用默认配置 +- `environment` (IEnvironment?): 环境配置对象,为 null 时使用默认环境 +- `services` (IArchitectureServices?): 架构服务对象,为 null 时创建新实例 +- `context` (IArchitectureContext?): 架构上下文对象,为 null 时创建新实例 + +## 公共方法 + +### Initialize + +同步初始化架构,阻塞当前线程直到初始化完成。 + +**签名**: +```csharp +public void Initialize() +``` + +**特点**: +- 阻塞式初始化 +- 适用于简单场景或控制台应用 +- 初始化失败时抛出异常并进入 `FailedInitialization` 阶段 + +### InitializeAsync + +异步初始化架构,返回 Task 以便调用者可以等待初始化完成。 + +**签名**: +```csharp +public async Task InitializeAsync() +``` + +**返回值**: +- (Task): 表示异步初始化操作的任务 + +**特点**: +- 非阻塞式初始化 +- 支持异步组件初始化 +- 适用于需要异步加载资源的场景 + +### InstallModule + +安装架构模块,用于扩展架构功能。 + +**签名**: +```csharp +public IArchitectureModule InstallModule(IArchitectureModule module) +``` + +**参数**: +- `module` (IArchitectureModule): 要安装的模块实例 + +**返回值**: +- (IArchitectureModule): 返回安装的模块实例 + +### RegisterSystem + +注册系统组件到架构中。 + +**签名**: +```csharp +public void RegisterSystem(TSystem system) where TSystem : ISystem +``` + +**类型参数**: +- `TSystem`: 系统类型,必须实现 ISystem 接口 + +**参数**: +- `system` (TSystem): 要注册的系统实例 + +### RegisterModel + +注册模型组件到架构中。 + +**签名**: +```csharp +public void RegisterModel(TModel model) where TModel : IModel +``` + +**类型参数**: +- `TModel`: 模型类型,必须实现 IModel 接口 + +**参数**: +- `model` (TModel): 要注册的模型实例 + +### RegisterUtility + +注册工具组件到架构中。 + +**签名**: +```csharp +public void RegisterUtility(TUtility utility) where TUtility : IUtility +``` + +**类型参数**: +- `TUtility`: 工具类型,必须实现 IUtility 接口 + +**参数**: +- `utility` (TUtility): 要注册的工具实例 + +### SendCommand + +发送并执行命令。 + +**签名**: +```csharp +public void SendCommand(ICommand command) +``` + +**参数**: +- `command` (ICommand): 要执行的命令实例 + +### SendCommand<TResult> + +发送并执行带返回值的命令。 + +**签名**: +```csharp +public TResult SendCommand(ICommand command) +``` + +**类型参数**: +- `TResult`: 命令返回值类型 + +**参数**: +- `command` (ICommand<TResult>): 要执行的命令实例 + +**返回值**: +- (TResult): 命令执行结果 + +## 公共属性 + +### CurrentPhase + +获取当前架构的阶段。 + +**类型**:`ArchitecturePhase` +**访问**:get + +### Context + +获取架构上下文,提供对架构服务的访问。 + +**类型**:`IArchitectureContext` +**访问**:get + +### IsReady + +获取一个布尔值,指示当前架构是否处于就绪状态。 + +**类型**:`bool` +**访问**:get + +## 使用示例 + +### 基本用法 + +```csharp +// 1. 定义你的架构(继承 Architecture 基类) +public class GameArchitecture : Architecture +{ + protected override void Init() + { + // 注册 Model + RegisterModel(new PlayerModel()); + RegisterModel(new InventoryModel()); + + // 注册 System + RegisterSystem(new GameplaySystem()); + RegisterSystem(new SaveSystem()); + + // 注册 Utility + RegisterUtility(new StorageUtility()); + RegisterUtility(new TimeUtility()); + } +} + +// 2. 创建并初始化架构 +var architecture = new GameArchitecture(); +architecture.Initialize(); + +// 3. 等待架构就绪 +await architecture.WaitUntilReadyAsync(); +``` + +### 异步初始化 + +```csharp +var architecture = new GameArchitecture(); +await architecture.InitializeAsync(); // 异步等待初始化完成 + +// 检查架构是否已就绪 +if (architecture.IsReady) +{ + Console.WriteLine("架构已就绪,可以开始游戏"); +} +``` + +### 使用自定义配置 + +```csharp +var config = new ArchitectureConfiguration +{ + ArchitectureProperties = new ArchitectureProperties + { + StrictPhaseValidation = true, // 启用严格阶段验证 + AllowLateRegistration = false // 禁止就绪后注册组件 + } +}; + +var architecture = new GameArchitecture(configuration: config); +architecture.Initialize(); +``` + +## 另请参阅 + +- [IArchitecture](./iarchitecture.md) - 架构接口 +- [ArchitecturePhase](./architecture-phase.md) - 架构阶段枚举 +- [IArchitectureModule](./iarchitecture-module.md) - 架构模块接口 +- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/examples/enum-example.md b/.claude/skills/vitepress-api-doc/examples/enum-example.md new file mode 100644 index 0000000..dac3a06 --- /dev/null +++ b/.claude/skills/vitepress-api-doc/examples/enum-example.md @@ -0,0 +1,193 @@ +--- +title: ArchitecturePhase +description: 架构阶段枚举,定义了架构生命周期的各个阶段。 +outline: deep +--- + +# ArchitecturePhase + +## 概述 + +架构阶段枚举,定义了架构生命周期的各个阶段。 + +**命名空间**:`GFramework.Core.Abstractions.enums` +**程序集**:`GFramework.Core.Abstractions` +**基础类型**:`Enum` + +## 枚举值 + +### None + +初始阶段,架构尚未开始初始化。 + +**值**:`0` + +### BeforeUtilityInit + +工具初始化前阶段。 + +**值**:`1` + +### AfterUtilityInit + +工具初始化后阶段。 + +**值**:`2` + +### BeforeModelInit + +模型初始化前阶段。 + +**值**:`3` + +### AfterModelInit + +模型初始化后阶段。 + +**值**:`4` + +### BeforeSystemInit + +系统初始化前阶段。 + +**值**:`5` + +### AfterSystemInit + +系统初始化后阶段。 + +**值**:`6` + +### Ready + +就绪状态,架构已完全初始化并可以使用。 + +**值**:`7` + +### FailedInitialization + +初始化失败状态。 + +**值**:`8` + +### Destroying + +正在销毁阶段。 + +**值**:`9` + +### Destroyed + +已销毁阶段。 + +**值**:`10` + +## 使用示例 + +### 检查架构阶段 + +```csharp +var architecture = new GameArchitecture(); +architecture.Initialize(); + +// 检查架构是否已就绪 +if (architecture.CurrentPhase == ArchitecturePhase.Ready) +{ + Console.WriteLine("架构已就绪,可以开始游戏"); +} +``` + +### 监听阶段变化 + +```csharp +public class PhaseMonitor : IArchitectureLifecycle +{ + public void OnPhase(ArchitecturePhase phase, IArchitecture architecture) + { + switch (phase) + { + case ArchitecturePhase.BeforeUtilityInit: + Console.WriteLine("开始初始化工具"); + break; + case ArchitecturePhase.AfterUtilityInit: + Console.WriteLine("工具初始化完成"); + break; + case ArchitecturePhase.BeforeModelInit: + Console.WriteLine("开始初始化模型"); + break; + case ArchitecturePhase.AfterModelInit: + Console.WriteLine("模型初始化完成"); + break; + case ArchitecturePhase.BeforeSystemInit: + Console.WriteLine("开始初始化系统"); + break; + case ArchitecturePhase.AfterSystemInit: + Console.WriteLine("系统初始化完成"); + break; + case ArchitecturePhase.Ready: + Console.WriteLine("架构就绪"); + break; + case ArchitecturePhase.FailedInitialization: + Console.WriteLine("架构初始化失败"); + break; + case ArchitecturePhase.Destroying: + Console.WriteLine("架构正在销毁"); + break; + case ArchitecturePhase.Destroyed: + Console.WriteLine("架构已销毁"); + break; + } + } +} + +// 注册监听器 +var architecture = new GameArchitecture(); +architecture.RegisterLifecycleHook(new PhaseMonitor()); +architecture.Initialize(); +``` + +### 等待特定阶段 + +```csharp +public async Task WaitForReady(IArchitecture architecture) +{ + while (architecture.CurrentPhase != ArchitecturePhase.Ready) + { + if (architecture.CurrentPhase == ArchitecturePhase.FailedInitialization) + { + throw new Exception("架构初始化失败"); + } + + await Task.Delay(100); + } + + Console.WriteLine("架构已就绪"); +} +``` + +## 阶段转换顺序 + +正常初始化流程的阶段转换顺序: + +1. `None` → `BeforeUtilityInit` +2. `BeforeUtilityInit` → `AfterUtilityInit` +3. `AfterUtilityInit` → `BeforeModelInit` +4. `BeforeModelInit` → `AfterModelInit` +5. `AfterModelInit` → `BeforeSystemInit` +6. `BeforeSystemInit` → `AfterSystemInit` +7. `AfterSystemInit` → `Ready` + +销毁流程的阶段转换顺序: + +1. `Ready` → `Destroying` +2. `Destroying` → `Destroyed` + +异常流程: + +- 任何阶段 → `FailedInitialization`(初始化过程中发生异常) + +## 另请参阅 + +- [Architecture](./architecture.md) - 架构基类 +- [IArchitectureLifecycle](./iarchitecture-lifecycle.md) - 生命周期钩子接口 +- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/examples/interface-example.md b/.claude/skills/vitepress-api-doc/examples/interface-example.md new file mode 100644 index 0000000..80e3efc --- /dev/null +++ b/.claude/skills/vitepress-api-doc/examples/interface-example.md @@ -0,0 +1,290 @@ +--- +title: IArchitecture +description: 架构接口,定义了框架的核心功能契约。 +outline: deep +--- + +# IArchitecture + +## 概述 + +架构接口,定义了框架的核心功能契约。 + +**命名空间**:`GFramework.Core.Abstractions.architecture` +**程序集**:`GFramework.Core.Abstractions` +**实现类**:[Architecture](./architecture.md) + +## 公共方法 + +### RegisterSystem<TSystem> + +注册系统组件到架构中。 + +**签名**: +```csharp +void RegisterSystem(TSystem system) where TSystem : ISystem +``` + +**类型参数**: +- `TSystem`: 系统类型,必须实现 ISystem 接口 + +**参数**: +- `system` (TSystem): 要注册的系统实例 + +### RegisterModel<TModel> + +注册模型组件到架构中。 + +**签名**: +```csharp +void RegisterModel(TModel model) where TModel : IModel +``` + +**类型参数**: +- `TModel`: 模型类型,必须实现 IModel 接口 + +**参数**: +- `model` (TModel): 要注册的模型实例 + +### RegisterUtility<TUtility> + +注册工具组件到架构中。 + +**签名**: +```csharp +void RegisterUtility(TUtility utility) where TUtility : IUtility +``` + +**类型参数**: +- `TUtility`: 工具类型,必须实现 IUtility 接口 + +**参数**: +- `utility` (TUtility): 要注册的工具实例 + +### GetModel<T> + +从容器中获取已注册的模型。 + +**签名**: +```csharp +T GetModel() where T : class, IModel +``` + +**类型参数**: +- `T`: 模型类型 + +**返回值**: +- (T): 模型实例 + +### GetSystem<T> + +从容器中获取已注册的系统。 + +**签名**: +```csharp +T GetSystem() where T : class, ISystem +``` + +**类型参数**: +- `T`: 系统类型 + +**返回值**: +- (T): 系统实例 + +### GetUtility<T> + +从容器中获取已注册的工具。 + +**签名**: +```csharp +T GetUtility() where T : class, IUtility +``` + +**类型参数**: +- `T`: 工具类型 + +**返回值**: +- (T): 工具实例 + +### SendCommand + +发送并执行命令。 + +**签名**: +```csharp +void SendCommand(ICommand command) +``` + +**参数**: +- `command` (ICommand): 要执行的命令实例 + +### SendCommand<TResult> + +发送并执行带返回值的命令。 + +**签名**: +```csharp +TResult SendCommand(ICommand command) +``` + +**类型参数**: +- `TResult`: 命令返回值类型 + +**参数**: +- `command` (ICommand<TResult>): 要执行的命令实例 + +**返回值**: +- (TResult): 命令执行结果 + +### SendQuery<TResult> + +发送并执行查询。 + +**签名**: +```csharp +TResult SendQuery(IQuery query) +``` + +**类型参数**: +- `TResult`: 查询返回值类型 + +**参数**: +- `query` (IQuery<TResult>): 要执行的查询实例 + +**返回值**: +- (TResult): 查询结果 + +### SendEvent<T> + +发送事件(无参数)。 + +**签名**: +```csharp +void SendEvent() where T : new() +``` + +**类型参数**: +- `T`: 事件类型,必须有无参构造函数 + +### SendEvent<T> + +发送事件(带参数)。 + +**签名**: +```csharp +void SendEvent(T e) +``` + +**类型参数**: +- `T`: 事件类型 + +**参数**: +- `e` (T): 事件实例 + +### RegisterEvent<T> + +注册事件监听器。 + +**签名**: +```csharp +IUnRegister RegisterEvent(Action onEvent) +``` + +**类型参数**: +- `T`: 事件类型 + +**参数**: +- `onEvent` (Action<T>): 事件处理回调 + +**返回值**: +- (IUnRegister): 用于注销事件的对象 + +### UnRegisterEvent<T> + +注销事件监听器。 + +**签名**: +```csharp +void UnRegisterEvent(Action onEvent) +``` + +**类型参数**: +- `T`: 事件类型 + +**参数**: +- `onEvent` (Action<T>): 要注销的事件处理回调 + +## 公共属性 + +### CurrentPhase + +获取当前架构的阶段。 + +**类型**:`ArchitecturePhase` +**访问**:get + +### Context + +获取架构上下文。 + +**类型**:`IArchitectureContext` +**访问**:get + +## 使用示例 + +### 在 Controller 中使用 + +```csharp +public class GameController : IController +{ + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + public void Start() + { + // 获取 Model + var playerModel = this.GetModel(); + + // 发送命令 + this.SendCommand(new StartGameCommand()); + + // 发送查询 + var score = this.SendQuery(new GetScoreQuery()); + + // 注册事件 + this.RegisterEvent(OnPlayerDied); + } + + private void OnPlayerDied(PlayerDiedEvent e) + { + // 处理玩家死亡事件 + } +} +``` + +### 实现自定义架构 + +```csharp +public class GameArchitecture : Architecture +{ + // 单例访问 + public static IArchitecture Interface { get; private set; } + + protected override void Init() + { + Interface = this; + + // 注册组件 + RegisterModel(new PlayerModel()); + RegisterSystem(new GameplaySystem()); + RegisterUtility(new StorageUtility()); + } +} +``` + +## 另请参阅 + +- [Architecture](./architecture.md) - 架构基类实现 +- [IModel](./imodel.md) - 模型接口 +- [ISystem](./isystem.md) - 系统接口 +- [IUtility](./iutility.md) - 工具接口 +- [架构组件](/zh-CN/core/architecture) - 架构使用指南 diff --git a/.claude/skills/vitepress-api-doc/template.md b/.claude/skills/vitepress-api-doc/template.md new file mode 100644 index 0000000..2df3a4c --- /dev/null +++ b/.claude/skills/vitepress-api-doc/template.md @@ -0,0 +1,37 @@ +--- +title: {{CLASS_NAME}} +description: {{XML_SUMMARY}} +outline: deep +--- + +# {{CLASS_NAME}} + +## 概述 + +{{XML_SUMMARY}} + +**命名空间**:`{{NAMESPACE}}` +**程序集**:`{{ASSEMBLY}}` +{{INHERITANCE_CHAIN}} + +## 构造函数 + +{{CONSTRUCTORS}} + +## 公共方法 + +{{PUBLIC_METHODS}} + +## 公共属性 + +{{PUBLIC_PROPERTIES}} + +{{PUBLIC_EVENTS}} + +## 使用示例 + +{{AUTO_GENERATED_EXAMPLES}} + +## 另请参阅 + +{{RELATED_TYPES}} diff --git a/.claude/skills/vitepress-batch-api/SKILL.md b/.claude/skills/vitepress-batch-api/SKILL.md new file mode 100644 index 0000000..98ecb5c --- /dev/null +++ b/.claude/skills/vitepress-batch-api/SKILL.md @@ -0,0 +1,364 @@ +# VitePress 批量 API 文档生成 + +为整个模块批量生成 API 参考文档,提高文档生成效率。 + +## 用途 + +此 skill 用于批量生成模块的 API 文档,适用于: +- 初始化模块文档 +- 更新整个模块的文档 +- 为新模块快速生成文档 +- 重新生成所有 API 文档 + +## 调用方式 + +```bash +/vitepress-batch-api <模块名> +``` + +**示例**: +```bash +/vitepress-batch-api Core +/vitepress-batch-api Game +/vitepress-batch-api Godot +/vitepress-batch-api SourceGenerators +``` + +## 工作流程 + +1. **扫描模块目录** + - 根据模块名确定源代码目录 + - 递归扫描所有 C# 文件 + +2. **过滤目标文件** + - 仅包含公共类型(public class/interface/enum/struct) + - 排除内部类型(internal) + - 排除生成的代码(*.g.cs、*.Designer.cs) + - 排除测试文件(*.Tests.cs) + +3. **批量生成文档** + - 为每个类型调用 `/vitepress-api-doc` + - 显示进度信息 + - 收集生成结果 + +4. **生成模块索引页** + - 创建 `index.md` 列出所有 API + - 按类别分组(类、接口、枚举) + - 添加简短描述 + +5. **批量更新导航** + - 在 VitePress 配置中添加所有新文档 + - 保持字母顺序 + - 更新模块索引 + +6. **生成摘要报告** + - 统计生成的文档数量 + - 列出成功和失败的文件 + - 提供验证建议 + +## 输出规范 + +### 模块索引页格式 + +```markdown +--- +title: Core API 参考 +description: GFramework.Core 模块的 API 参考文档 +--- + +# Core API 参考 + +## 概述 + +GFramework.Core 是框架的核心模块,提供架构基础、依赖注入、事件系统等核心功能。 + +## 类 + +- [Architecture](./architecture.md) - 架构基类 +- [ArchitectureConfiguration](./architecture-configuration.md) - 架构配置 +- [IocContainer](./ioc-container.md) - IoC 容器 + +## 接口 + +- [IArchitecture](./iarchitecture.md) - 架构接口 +- [IModel](./imodel.md) - 模型接口 +- [ISystem](./isystem.md) - 系统接口 + +## 枚举 + +- [ArchitecturePhase](./architecture-phase.md) - 架构阶段 +``` + +### 目录结构 + +``` +docs/zh-CN/api-reference/ +├── core/ +│ ├── index.md # 模块索引 +│ ├── architecture.md +│ ├── iarchitecture.md +│ └── ... +├── game/ +│ ├── index.md +│ └── ... +└── godot/ + ├── index.md + └── ... +``` + +## 模块映射 + +### 源代码目录映射 + +| 模块名 | 源代码目录 | 输出目录 | +|--------|-----------|---------| +| Core | `GFramework.Core/` | `docs/zh-CN/api-reference/core/` | +| Game | `GFramework.Game/` | `docs/zh-CN/api-reference/game/` | +| Godot | `GFramework.Godot/` | `docs/zh-CN/api-reference/godot/` | +| SourceGenerators | `GFramework.SourceGenerators/` | `docs/zh-CN/api-reference/source-generators/` | + +### 命名空间映射 + +- `GFramework.Core.*` → Core 模块 +- `GFramework.Game.*` → Game 模块 +- `GFramework.Godot.*` → Godot 模块 +- `GFramework.SourceGenerators.*` → SourceGenerators 模块 + +## 过滤规则 + +### 包含的文件 + +- 公共类(public class) +- 公共接口(public interface) +- 公共枚举(public enum) +- 公共结构体(public struct) + +### 排除的文件 + +- 内部类型(internal) +- 生成的代码(`*.g.cs`、`*.Designer.cs`) +- 测试文件(`*.Tests.cs`、`*Test.cs`) +- 临时文件(`*.tmp.cs`) +- 编译器生成的文件(`AssemblyInfo.cs`) + +### 排除的类型 + +- 编译器生成的类型(`<>c__DisplayClass`) +- 匿名类型 +- 嵌套的私有类型 + +## 批量处理脚本 + +### batch-generate.sh + +```bash +#!/bin/bash +# 批量生成 API 文档 +# 用法: batch-generate.sh <模块名> + +set -e + +MODULE="$1" + +if [ -z "$MODULE" ]; then + echo "用法: $0 <模块名>" + echo "可用模块: Core, Game, Godot, SourceGenerators" + exit 1 +fi + +# 确定源代码目录 +case "$MODULE" in + Core) + SOURCE_DIR="GFramework.Core" + ;; + Game) + SOURCE_DIR="GFramework.Game" + ;; + Godot) + SOURCE_DIR="GFramework.Godot" + ;; + SourceGenerators) + SOURCE_DIR="GFramework.SourceGenerators" + ;; + *) + echo "错误: 未知的模块: $MODULE" + exit 1 + ;; +esac + +if [ ! -d "$SOURCE_DIR" ]; then + echo "错误: 源代码目录不存在: $SOURCE_DIR" + exit 1 +fi + +echo "==========================================" +echo "批量生成 $MODULE 模块的 API 文档" +echo "==========================================" +echo "" + +# 查找所有 C# 文件 +FILES=$(find "$SOURCE_DIR" -name "*.cs" -type f \ + ! -name "*.g.cs" \ + ! -name "*.Designer.cs" \ + ! -name "*Test.cs" \ + ! -name "*.Tests.cs" \ + ! -name "AssemblyInfo.cs") + +FILE_COUNT=$(echo "$FILES" | wc -l) +echo "找到 $FILE_COUNT 个文件" +echo "" + +GENERATED=0 +SKIPPED=0 +FAILED=0 + +for FILE in $FILES; do + echo "处理: $FILE" + + # 检查是否包含公共类型 + if ! grep -q "public \(class\|interface\|enum\|struct\)" "$FILE"; then + echo " ⊘ 跳过(无公共类型)" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + # 调用 vitepress-api-doc(由 AI 执行) + # /vitepress-api-doc "$FILE" + + if [ $? -eq 0 ]; then + echo " ✓ 生成成功" + GENERATED=$((GENERATED + 1)) + else + echo " ✗ 生成失败" + FAILED=$((FAILED + 1)) + fi + + echo "" +done + +echo "==========================================" +echo "批量生成完成" +echo "==========================================" +echo "总文件数: $FILE_COUNT" +echo "生成成功: $GENERATED" +echo "跳过: $SKIPPED" +echo "失败: $FAILED" +echo "" + +if [ $FAILED -eq 0 ]; then + echo "✓ 所有文档生成成功" + exit 0 +else + echo "✗ 部分文档生成失败" + exit 1 +fi +``` + +## 配置选项 + +### 过滤选项 + +```bash +# 包含内部类型 +/vitepress-batch-api Core --include-internal + +# 包含生成的代码 +/vitepress-batch-api Core --include-generated + +# 自定义过滤规则 +/vitepress-batch-api Core --exclude "*.Tests.cs" --exclude "*.g.cs" +``` + +### 输出选项 + +```bash +# 指定输出目录 +/vitepress-batch-api Core --output docs/zh-CN/api-reference/core/ + +# 覆盖现有文档 +/vitepress-batch-api Core --force + +# 仅生成索引页 +/vitepress-batch-api Core --index-only +``` + +### 并行处理 + +```bash +# 并行生成(加快速度) +/vitepress-batch-api Core --parallel 4 +``` + +## 进度显示 + +### 实时进度 + +``` +======================================== +批量生成 Core 模块的 API 文档 +======================================== + +找到 45 个文件 + +[1/45] 处理: GFramework.Core/architecture/Architecture.cs + ✓ 生成成功 + +[2/45] 处理: GFramework.Core/architecture/IArchitecture.cs + ✓ 生成成功 + +[3/45] 处理: GFramework.Core/command/Command.cs + ⊘ 跳过(无公共类型) + +... + +[45/45] 处理: GFramework.Core/utility/Utility.cs + ✓ 生成成功 + +======================================== +批量生成完成 +======================================== +总文件数: 45 +生成成功: 38 +跳过: 5 +失败: 2 + +✗ 部分文档生成失败 + +失败的文件: +- GFramework.Core/internal/InternalClass.cs (缺少 XML 注释) +- GFramework.Core/legacy/LegacyClass.cs (解析错误) +``` + +## 前置条件 + +1. 模块源代码目录存在 +2. 源代码文件包含 XML 文档注释 +3. 有足够的磁盘空间存储生成的文档 + +## 相关 Skills + +- `/vitepress-api-doc` - 单文件 API 文档生成 +- `/vitepress-validate` - 验证生成的文档 +- `/vitepress-guide` - 生成功能指南 + +## 最佳实践 + +1. **首次生成**:使用批量生成快速创建所有文档 +2. **增量更新**:修改代码后使用单文件生成更新对应文档 +3. **定期验证**:批量生成后运行验证确保质量 +4. **版本控制**:将生成的文档提交到版本控制系统 + +## 故障排除 + +### 问题:部分文件生成失败 +**解决方案**:检查失败文件的 XML 注释是否完整,手动修复后重新生成 + +### 问题:生成速度慢 +**解决方案**:使用 `--parallel` 选项启用并行处理 + +### 问题:生成的文档过多 +**解决方案**:使用过滤选项排除不需要的文件 + +## 版本历史 + +- v1.0.0 - 初始版本,支持批量 API 文档生成 diff --git a/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh b/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh new file mode 100644 index 0000000..1d4750d --- /dev/null +++ b/.claude/skills/vitepress-batch-api/scripts/batch-generate.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# 批量生成 API 文档 +# 用法: batch-generate.sh <模块名> + +set -e + +MODULE="$1" + +if [ -z "$MODULE" ]; then + echo "用法: $0 <模块名>" + echo "可用模块: Core, Game, Godot, SourceGenerators" + exit 1 +fi + +# 确定源代码目录 +case "$MODULE" in + Core) + SOURCE_DIR="GFramework.Core" + ;; + Game) + SOURCE_DIR="GFramework.Game" + ;; + Godot) + SOURCE_DIR="GFramework.Godot" + ;; + SourceGenerators) + SOURCE_DIR="GFramework.SourceGenerators" + ;; + *) + echo "错误: 未知的模块: $MODULE" + exit 1 + ;; +esac + +if [ ! -d "$SOURCE_DIR" ]; then + echo "错误: 源代码目录不存在: $SOURCE_DIR" + exit 1 +fi + +echo "==========================================" +echo "批量生成 $MODULE 模块的 API 文档" +echo "==========================================" +echo "" + +# 查找所有 C# 文件 +FILES=$(find "$SOURCE_DIR" -name "*.cs" -type f \ + ! -name "*.g.cs" \ + ! -name "*.Designer.cs" \ + ! -name "*Test.cs" \ + ! -name "*.Tests.cs" \ + ! -name "AssemblyInfo.cs") + +FILE_COUNT=$(echo "$FILES" | wc -l) +echo "找到 $FILE_COUNT 个文件" +echo "" + +GENERATED=0 +SKIPPED=0 +FAILED=0 + +for FILE in $FILES; do + echo "处理: $FILE" + + # 检查是否包含公共类型 + if ! grep -q "public \(class\|interface\|enum\|struct\)" "$FILE"; then + echo " ⊘ 跳过(无公共类型)" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + # 注意: 实际的文档生成由 AI 调用 /vitepress-api-doc 完成 + # 此脚本仅用于扫描和过滤文件 + + echo " → 待生成" + GENERATED=$((GENERATED + 1)) + echo "" +done + +echo "==========================================" +echo "扫描完成" +echo "==========================================" +echo "总文件数: $FILE_COUNT" +echo "待生成: $GENERATED" +echo "跳过: $SKIPPED" +echo "" + +exit 0 diff --git a/.claude/skills/vitepress-doc-generator/SKILL.md b/.claude/skills/vitepress-doc-generator/SKILL.md new file mode 100644 index 0000000..5c28e58 --- /dev/null +++ b/.claude/skills/vitepress-doc-generator/SKILL.md @@ -0,0 +1,52 @@ +--- +name: vitepress-doc-generator +description: Generate standardized VitePress documentation from source code. +disable-model-invocation: true +--- + +# Role + +You are a technical documentation generator specialized in VitePress. + +# Objective + +Analyze the provided code context and generate a structured VitePress-compatible Markdown document. + +# Output Requirements + +1. Output MUST be valid Markdown only. +2. Include frontmatter: + +--- +title: +outline: deep +--- + +3. No explanations. +4. No conversational text. +5. No emoji. +6. Use Chinese. +7. Use structured headings. + +# Required Structure + +# 模块概述 +- 模块职责 +- 设计目标 + +# 核心类说明 +## 类名 +### 职责 +### 主要方法 +### 依赖关系 + +# 设计模式分析 +# 可扩展性说明 +# 使用示例(如适用) + +# Self-Validation + +Before returning output, verify: +- Frontmatter exists +- All required sections exist +- No extra commentary text \ No newline at end of file diff --git a/.claude/skills/vitepress-doc-generator/template.md b/.claude/skills/vitepress-doc-generator/template.md new file mode 100644 index 0000000..e69de29 diff --git a/.claude/skills/vitepress-guide/SKILL.md b/.claude/skills/vitepress-guide/SKILL.md new file mode 100644 index 0000000..b2539ef --- /dev/null +++ b/.claude/skills/vitepress-guide/SKILL.md @@ -0,0 +1,256 @@ +# VitePress 功能指南生成 + +生成功能模块的使用指南文档,包括概念说明、用法示例和最佳实践。 + +## 用途 + +此 skill 用于生成结构化的功能指南文档,适用于: +- 核心功能模块的使用说明 +- 设计模式和架构概念 +- 系统功能的详细介绍 +- 最佳实践和常见问题 + +## 调用方式 + +```bash +/vitepress-guide <主题> <目标模块> +``` + +**示例**: +```bash +/vitepress-guide "事件系统" Core +/vitepress-guide "IoC 容器" Core +/vitepress-guide "Godot 节点扩展" Godot +``` + +## 工作流程 + +1. **收集需求** + - 询问用户指南主题 + - 确定目标受众(初学者/进阶/专家) + - 了解重点内容(概念/用法/最佳实践) + +2. **搜索相关资源** + - 搜索相关代码文件 + - 查找现有文档 + - 识别相关类型和接口 + +3. **生成指南结构** + - 根据 `template.md` 创建文档框架 + - 填充概述和核心概念 + - 添加基本用法和高级用法 + - 补充最佳实践和常见问题 + +4. **生成代码示例** + - 基本用法示例(最简单的场景) + - 常见场景示例(实际应用) + - 高级用法示例(复杂配置) + +5. **确定输出路径** + - 保存到 `docs/zh-CN/<模块>/` + - 文件名使用小写加连字符(如 `event-system.md`) + +6. **更新导航配置** + - 在 VitePress 侧边栏中添加新指南 + +## 输出规范 + +### Frontmatter 格式 + +```yaml +--- +title: 指南标题 +description: 简短描述(1-2 句话) +--- +``` + +### 文档结构 + +1. **概述**:功能的简介和用途 +2. **核心概念**:关键概念和术语解释 +3. **基本用法**:最简单的使用方式 +4. **高级用法**:复杂场景和配置 +5. **最佳实践**:推荐的使用方式 +6. **常见问题**:FAQ 和故障排除 + +### 章节示例 + +**概述**: +```markdown +## 概述 + +事件系统提供了一种松耦合的组件间通信机制。通过事件,不同的组件可以在不直接引用彼此的情况下进行交互。 + +**主要特性**: +- 类型安全的事件 +- 自动内存管理 +- 支持事件优先级 +- 线程安全 +``` + +**核心概念**: +```markdown +## 核心概念 + +### 事件类型 + +事件是一个普通的 C# 类,用于携带事件数据: + +\`\`\`csharp +public class PlayerDiedEvent +{ + public int PlayerId { get; set; } + public string Reason { get; set; } +} +\`\`\` + +### 事件发送 + +通过架构发送事件: + +\`\`\`csharp +this.SendEvent(new PlayerDiedEvent +{ + PlayerId = 1, + Reason = "Fall damage" +}); +\`\`\` + +### 事件监听 + +注册事件监听器: + +\`\`\`csharp +this.RegisterEvent(OnPlayerDied); +\`\`\` +``` + +## 模板变量 + +- `{{GUIDE_TITLE}}` - 指南标题 +- `{{GUIDE_DESCRIPTION}}` - 简短描述 +- `{{OVERVIEW}}` - 概述内容 +- `{{CORE_CONCEPTS}}` - 核心概念 +- `{{BASIC_USAGE}}` - 基本用法 +- `{{ADVANCED_USAGE}}` - 高级用法 +- `{{BEST_PRACTICES}}` - 最佳实践 +- `{{FAQ}}` - 常见问题 + +## 示例输出 + +参考 `examples/guide-example.md`,该示例基于现有的 IoC 容器文档创建。 + +## 内容要求 + +### 概述部分 +- 1-2 段简介 +- 列出主要特性(3-5 个) +- 说明适用场景 + +### 核心概念部分 +- 使用三级标题(###)分隔不同概念 +- 每个概念包含简短说明和代码示例 +- 解释关键术语 + +### 基本用法部分 +- 提供完整的可运行示例 +- 从最简单的场景开始 +- 逐步增加复杂度 +- 包含必要的 using 语句 + +### 高级用法部分 +- 展示复杂场景 +- 说明配置选项 +- 提供性能优化建议 + +### 最佳实践部分 +- 使用编号列表 +- 每条实践包含简短说明 +- 提供正反示例(✓ 推荐 / ✗ 不推荐) + +### 常见问题部分 +- 使用问答格式 +- 提供具体的解决方案 +- 包含相关链接 + +## 写作风格 + +### 语气 +- 友好、专业 +- 使用第二人称("你") +- 避免过于技术化的术语 + +### 代码示例 +- 完整且可运行 +- 包含注释说明关键步骤 +- 使用有意义的变量名 +- 遵循项目代码风格 + +### 格式 +- 使用 Markdown 标准格式 +- 代码块使用语法高亮 +- 重要内容使用粗体或引用块 +- 适当使用列表和表格 + +## 配置选项 + +### 目标受众 + +```bash +# 初学者(更多解释,简单示例) +/vitepress-guide "事件系统" Core --audience beginner + +# 进阶(平衡解释和示例) +/vitepress-guide "事件系统" Core --audience intermediate + +# 专家(简洁说明,复杂示例) +/vitepress-guide "事件系统" Core --audience expert +``` + +### 重点内容 + +```bash +# 侧重概念 +/vitepress-guide "事件系统" Core --focus concepts + +# 侧重用法 +/vitepress-guide "事件系统" Core --focus usage + +# 侧重最佳实践 +/vitepress-guide "事件系统" Core --focus best-practices +``` + +## 前置条件 + +1. 了解指南主题的基本概念 +2. 能够访问相关代码文件 +3. 了解项目的代码风格和术语 + +## 相关 Skills + +- `/vitepress-api-doc` - 生成 API 参考文档 +- `/vitepress-tutorial` - 生成分步教程 +- `/vitepress-validate` - 验证生成的文档 + +## 最佳实践 + +1. **先搜索后编写**:查看现有文档和代码,保持一致性 +2. **使用真实示例**:基于项目实际代码创建示例 +3. **保持简洁**:每个章节聚焦一个主题 +4. **提供完整代码**:确保示例可以直接运行 +5. **添加交叉引用**:链接到相关的 API 文档和其他指南 + +## 故障排除 + +### 问题:不确定指南应该包含哪些内容 +**解决方案**:参考 `examples/guide-example.md` 和现有的指南文档 + +### 问题:代码示例过于复杂 +**解决方案**:将复杂示例拆分为多个简单示例,逐步增加复杂度 + +### 问题:概念解释不清晰 +**解决方案**:使用类比、图表或分步说明来辅助解释 + +## 版本历史 + +- v1.0.0 - 初始版本,支持功能指南生成 diff --git a/.claude/skills/vitepress-guide/examples/guide-example.md b/.claude/skills/vitepress-guide/examples/guide-example.md new file mode 100644 index 0000000..d76d01d --- /dev/null +++ b/.claude/skills/vitepress-guide/examples/guide-example.md @@ -0,0 +1,283 @@ +--- +title: IoC 容器使用指南 +description: IoC(控制反转)容器提供了轻量级的依赖注入功能,用于管理框架中各种组件的注册和获取。 +--- + +# IoC 容器使用指南 + +## 概述 + +IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC 容器,可以实现组件间的解耦,便于测试和维护。 + +IoC 容器是 GFramework 架构的核心组件之一,为整个框架提供依赖管理和组件解析服务。 + +**主要特性**: +- 类型安全的依赖管理 +- 支持单例和多实例注册 +- 线程安全操作 +- 容器冻结保护 +- 自动接口注册 + +## 核心概念 + +### 依赖注入 + +依赖注入是一种设计模式,通过容器管理对象的创建和依赖关系,而不是在代码中直接创建对象。 + +```csharp +// 不使用依赖注入 +public class GameController +{ + private PlayerModel model = new PlayerModel(); // 硬编码依赖 +} + +// 使用依赖注入 +public class GameController : IController +{ + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + public void Start() + { + var model = this.GetModel(); // 从容器获取 + } +} +``` + +### 容器注册 + +在架构初始化时,将组件注册到容器中: + +```csharp +public class GameArchitecture : Architecture +{ + protected override void Init() + { + // 注册 Model + RegisterModel(new PlayerModel()); + + // 注册 System + RegisterSystem(new GameplaySystem()); + + // 注册 Utility + RegisterUtility(new StorageUtility()); + } +} +``` + +### 容器解析 + +通过扩展方法从容器中获取已注册的组件: + +```csharp +// 在 Controller 中 +var playerModel = this.GetModel(); +var gameplaySystem = this.GetSystem(); +var storageUtility = this.GetUtility(); +``` + +## 基本用法 + +### 注册组件 + +```csharp +var container = new IocContainer(); + +// 注册单例(一个类型只能有一个实例) +container.RegisterSingleton(new PlayerModel()); + +// 注册多实例(一个类型可以有多个实例) +container.RegisterPlurality(new Goblin()); +container.RegisterPlurality(new Orc()); +container.RegisterPlurality(new Dragon()); +``` + +### 获取组件 + +```csharp +// 获取单例 +var playerModel = container.Get(); + +// 获取多实例集合 +var enemies = container.GetAll(); // 返回 List +``` + +### 在架构中使用 + +```csharp +public class GameArchitecture : Architecture +{ + protected override void Init() + { + // 注册组件 + RegisterModel(new PlayerModel()); + RegisterModel(new InventoryModel()); + RegisterSystem(new GameplaySystem()); + } +} + +// 在 Controller 中使用 +public class GameController : IController +{ + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + public void Start() + { + // 通过扩展方法获取组件 + var playerModel = this.GetModel(); + var inventoryModel = this.GetModel(); + var gameplaySystem = this.GetSystem(); + } +} +``` + +## 高级用法 + +### 容器冻结 + +容器在架构初始化完成后会被冻结,防止运行时修改: + +```csharp +var container = new IocContainer(); +container.Register(new PlayerModel()); + +// 冻结容器 +container.Freeze(); + +// 以下操作会抛出 InvalidOperationException +// container.Register(new GameSystem()); +``` + +### 多实例管理 + +```csharp +// 注册多个同类型实例 +container.RegisterPlurality(new Sword()); +container.RegisterPlurality(new Bow()); +container.RegisterPlurality(new Staff()); + +// 获取所有实例 +var allWeapons = container.GetAll(); +foreach (var weapon in allWeapons) +{ + weapon.Attack(); +} +``` + +### 接口自动注册 + +注册实例时,容器会自动将其注册到所有实现的接口: + +```csharp +public class PlayerModel : IModel, IPlayerModel, IDisposable +{ + // ... +} + +// 注册实例 +container.Register(new PlayerModel()); + +// 可以通过任何接口获取 +var model1 = container.Get(); +var model2 = container.Get(); +var model3 = container.Get(); +// 以上三个变量指向同一个实例 +``` + +### 线程安全操作 + +容器的所有操作都是线程安全的: + +```csharp +// 多线程环境下安全使用 +Parallel.For(0, 100, i => +{ + var model = container.Get(); + model.DoSomething(); +}); +``` + +## 最佳实践 + +1. **使用接口注册**:优先使用接口类型注册,而不是具体类型 + ```csharp + ✓ container.Register(new PlayerModel()); + ✗ container.Register(new PlayerModel()); + ``` + +2. **单例 vs 多实例**:根据需求选择合适的注册方式 + - 单例:全局唯一的服务(如配置、管理器) + - 多实例:可以有多个实例的对象(如敌人、道具) + +3. **避免循环依赖**:组件之间不应该相互依赖 + ```csharp + ✗ System A 依赖 System B,System B 又依赖 System A + ✓ 使用事件系统进行通信,避免直接依赖 + ``` + +4. **在 Init 中注册**:所有组件应该在架构的 `Init()` 方法中注册 + ```csharp + protected override void Init() + { + // 在这里注册所有组件 + RegisterModel(new PlayerModel()); + RegisterSystem(new GameplaySystem()); + } + ``` + +5. **使用扩展方法**:通过扩展方法获取组件,代码更简洁 + ```csharp + ✓ var model = this.GetModel(); + ✗ var model = this.GetArchitecture().GetModel(); + ``` + +6. **不要在运行时注册**:容器冻结后不应该再注册新组件 + ```csharp + ✗ 在游戏运行时动态注册组件 + ✓ 在架构初始化时注册所有需要的组件 + ``` + +## 常见问题 + +### 问题:如何判断使用单例还是多实例? + +**解答**: +- 使用单例(`RegisterSingleton`):全局唯一的服务,如 PlayerModel、GameConfiguration +- 使用多实例(`RegisterPlurality`):可以有多个实例的对象,如 Enemy、Weapon + +### 问题:容器冻结后如何添加新组件? + +**解答**: +容器冻结是为了保护架构稳定性。如果需要动态添加组件,应该: +1. 在架构初始化时预先注册所有可能需要的组件 +2. 使用对象池模式管理动态对象 +3. 考虑使用工厂模式创建临时对象 + +### 问题:如何处理组件的生命周期? + +**解答**: +- 实现 `IDisposable` 接口的组件会在架构销毁时自动释放 +- 架构会按注册的逆序销毁组件 +- 不需要手动管理组件的生命周期 + +### 问题:可以在容器中注册值类型吗? + +**解答**: +可以,但会发生装箱。建议将值类型包装在类中: +```csharp +// 不推荐 +container.Register(42); + +// 推荐 +public class GameConfig +{ + public int MaxPlayers { get; set; } = 42; +} +container.Register(new GameConfig()); +``` + +## 相关文档 + +- [架构组件](/zh-CN/core/architecture) - 架构基础 +- [Model 层](/zh-CN/core/model) - 数据模型 +- [System 层](/zh-CN/core/system) - 业务系统 +- [Utility 工具类](/zh-CN/core/utility) - 工具类 diff --git a/.claude/skills/vitepress-guide/template.md b/.claude/skills/vitepress-guide/template.md new file mode 100644 index 0000000..3f7fbd7 --- /dev/null +++ b/.claude/skills/vitepress-guide/template.md @@ -0,0 +1,34 @@ +--- +title: {{GUIDE_TITLE}} +description: {{GUIDE_DESCRIPTION}} +--- + +# {{GUIDE_TITLE}} + +## 概述 + +{{OVERVIEW}} + +## 核心概念 + +{{CORE_CONCEPTS}} + +## 基本用法 + +{{BASIC_USAGE}} + +## 高级用法 + +{{ADVANCED_USAGE}} + +## 最佳实践 + +{{BEST_PRACTICES}} + +## 常见问题 + +{{FAQ}} + +## 相关文档 + +{{RELATED_DOCS}} diff --git a/.claude/skills/vitepress-tutorial/SKILL.md b/.claude/skills/vitepress-tutorial/SKILL.md new file mode 100644 index 0000000..99e9b9d --- /dev/null +++ b/.claude/skills/vitepress-tutorial/SKILL.md @@ -0,0 +1,253 @@ +# VitePress 教程生成 + +生成分步教程文档,适合初学者学习框架功能。 + +## 用途 + +此 skill 用于生成结构化的分步教程,适用于: +- 框架入门教程 +- 功能实现教程 +- 最佳实践演示 +- 问题解决方案 + +## 调用方式 + +```bash +/vitepress-tutorial <教程主题> +``` + +**示例**: +```bash +/vitepress-tutorial "创建第一个 System" +/vitepress-tutorial "实现自定义命令" +/vitepress-tutorial "使用事件系统" +``` + +## 工作流程 + +1. **收集需求** + - 询问用户教程主题 + - 确定学习目标 + - 了解前置知识要求 + +2. **设计教程步骤** + - 将任务分解为 3-7 个步骤 + - 每步聚焦一个具体任务 + - 确保步骤之间逻辑连贯 + +3. **生成教程内容** + - 根据 `template.md` 创建文档框架 + - 为每步编写详细说明和代码 + - 添加完整的可运行代码 + - 说明预期结果 + +4. **确定输出路径** + - 保存到 `docs/zh-CN/tutorials/` + - 文件名使用小写加连字符 + +5. **更新导航配置** + - 在 VitePress 侧边栏中添加新教程 + +## 输出规范 + +### Frontmatter 格式 + +```yaml +--- +title: 教程标题 +description: 简短描述(1 句话说明学习内容) +--- +``` + +### 文档结构 + +1. **学习目标**:完成教程后能够掌握的技能 +2. **前置条件**:需要的前置知识和环境 +3. **步骤 1-N**:分步说明(3-7 步) +4. **完整代码**:汇总所有代码 +5. **运行结果**:预期输出和效果 +6. **下一步**:后续学习建议 + +### 步骤格式 + +每个步骤应包含: +- 步骤标题(简短、动词开头) +- 步骤说明(为什么要这样做) +- 代码示例(完整且可运行) +- 代码解释(关键部分的说明) + +**示例**: +```markdown +## 步骤 1:创建 Model 类 + +首先,我们需要创建一个 Model 来存储玩家数据。Model 负责管理应用的数据和状态。 + +\`\`\`csharp +using GFramework.Core.Abstractions.model; +using GFramework.Core.Abstractions.property; + +public class PlayerModel : IModel +{ + // 玩家名称(可绑定属性) + public BindableProperty Name { get; } = new("Player"); + + // 玩家生命值 + public BindableProperty Health { get; } = new(100); + + // 玩家金币 + public BindableProperty Gold { get; } = new(0); + + public void Init() { } +} +\`\`\` + +**代码说明**: +- `BindableProperty` 是可绑定属性,值变化时会自动通知监听者 +- `Init()` 方法在 Model 注册到架构时被调用 +- 使用属性初始化器设置默认值 +``` + +## 模板变量 + +- `{{TUTORIAL_TITLE}}` - 教程标题 +- `{{TUTORIAL_DESCRIPTION}}` - 简短描述 +- `{{LEARNING_OBJECTIVES}}` - 学习目标 +- `{{PREREQUISITES}}` - 前置条件 +- `{{STEP_N_TITLE}}` - 步骤标题 +- `{{STEP_N_CONTENT}}` - 步骤内容 +- `{{FULL_CODE}}` - 完整代码 +- `{{EXPECTED_OUTPUT}}` - 预期输出 +- `{{NEXT_STEPS}}` - 下一步建议 + +## 示例输出 + +参考 `examples/tutorial-example.md`,该示例基于现有的教程文档创建。 + +## 内容要求 + +### 学习目标 +- 使用列表格式 +- 3-5 个具体的学习目标 +- 使用"能够..."句式 + +**示例**: +```markdown +## 学习目标 + +完成本教程后,你将能够: +- 创建自定义的 Model 类 +- 在架构中注册 Model +- 从 Controller 中访问 Model +- 使用可绑定属性管理数据 +``` + +### 前置条件 +- 列出必需的知识 +- 说明环境要求 +- 提供相关文档链接 + +**示例**: +```markdown +## 前置条件 + +- 已安装 GFramework.Core NuGet 包 +- 了解 C# 基础语法 +- 阅读过[架构概览](/zh-CN/getting-started) +``` + +### 步骤内容 +- 每步 100-300 字说明 +- 包含完整的代码示例 +- 解释关键代码的作用 +- 使用注释标注重要部分 + +### 完整代码 +- 汇总所有步骤的代码 +- 确保可以直接复制运行 +- 包含必要的 using 语句 +- 添加文件结构说明 + +### 运行结果 +- 描述预期的输出 +- 如果有界面,提供截图或描述 +- 说明如何验证结果正确 + +### 下一步 +- 推荐 2-3 个后续教程 +- 提供相关文档链接 +- 建议进阶学习方向 + +## 写作风格 + +### 语气 +- 友好、鼓励性 +- 使用第二人称("你") +- 避免假设读者已有高级知识 + +### 步骤说明 +- 使用主动语态 +- 步骤标题使用动词开头 +- 说明"为什么"而不仅是"怎么做" + +### 代码示例 +- 完整且可运行 +- 包含详细注释 +- 使用有意义的变量名 +- 遵循项目代码风格 + +## 配置选项 + +### 教程难度 + +```bash +# 初学者(更多解释,简单示例) +/vitepress-tutorial "创建第一个 System" --level beginner + +# 中级(平衡解释和复杂度) +/vitepress-tutorial "实现自定义命令" --level intermediate + +# 高级(简洁说明,复杂示例) +/vitepress-tutorial "架构模块开发" --level advanced +``` + +### 步骤数量 + +```bash +# 指定步骤数量(3-7 步) +/vitepress-tutorial "使用事件系统" --steps 5 +``` + +## 前置条件 + +1. 了解教程主题的基本概念 +2. 能够访问相关代码文件 +3. 了解目标受众的知识水平 + +## 相关 Skills + +- `/vitepress-api-doc` - 生成 API 参考文档 +- `/vitepress-guide` - 生成功能指南 +- `/vitepress-validate` - 验证生成的文档 + +## 最佳实践 + +1. **从简单开始**:第一步应该是最简单的操作 +2. **逐步增加复杂度**:每步在前一步基础上增加新内容 +3. **提供完整代码**:确保每步的代码都可以运行 +4. **解释关键概念**:不要假设读者已经了解所有术语 +5. **测试教程**:确保按照步骤操作能够得到预期结果 + +## 故障排除 + +### 问题:步骤过多,教程太长 +**解决方案**:将教程拆分为多个小教程,或合并相似的步骤 + +### 问题:代码示例不完整 +**解决方案**:在"完整代码"章节提供所有文件的完整代码 + +### 问题:读者反馈步骤不清晰 +**解决方案**:增加更多说明,使用截图或图表辅助 + +## 版本历史 + +- v1.0.0 - 初始版本,支持分步教程生成 diff --git a/.claude/skills/vitepress-tutorial/examples/tutorial-example.md b/.claude/skills/vitepress-tutorial/examples/tutorial-example.md new file mode 100644 index 0000000..ef628b3 --- /dev/null +++ b/.claude/skills/vitepress-tutorial/examples/tutorial-example.md @@ -0,0 +1,347 @@ +--- +title: 创建第一个 Model +description: 学习如何创建和使用 Model 来管理应用数据 +--- + +# 创建第一个 Model + +## 学习目标 + +完成本教程后,你将能够: +- 理解 Model 在架构中的作用 +- 创建自定义的 Model 类 +- 在架构中注册 Model +- 从 Controller 中访问 Model +- 使用可绑定属性管理数据 + +## 前置条件 + +- 已安装 GFramework.Core NuGet 包 +- 了解 C# 基础语法 +- 阅读过[架构概览](/zh-CN/getting-started) + +## 步骤 1:创建 Model 类 + +首先,我们需要创建一个 Model 来存储玩家数据。Model 负责管理应用的数据和状态。 + +```csharp +using GFramework.Core.Abstractions.model; +using GFramework.Core.Abstractions.property; + +namespace MyGame.Models +{ + /// + /// 玩家数据模型 + /// + public class PlayerModel : IModel + { + // 玩家名称(可绑定属性) + public BindableProperty Name { get; } = new("Player"); + + // 玩家生命值 + public BindableProperty Health { get; } = new(100); + + // 玩家金币 + public BindableProperty Gold { get; } = new(0); + + // 玩家等级 + public BindableProperty Level { get; } = new(1); + + /// + /// Model 初始化方法 + /// + public void Init() + { + // 在这里可以进行初始化操作 + // 例如:从配置文件加载默认值 + } + } +} +``` + +**代码说明**: +- `IModel` 接口标识这是一个数据模型 +- `BindableProperty` 是可绑定属性,值变化时会自动通知监听者 +- `Init()` 方法在 Model 注册到架构时被调用 +- 使用属性初始化器设置默认值 + +## 步骤 2:在架构中注册 Model + +创建架构类并注册 Model: + +```csharp +using GFramework.Core.architecture; +using MyGame.Models; + +namespace MyGame +{ + /// + /// 游戏架构 + /// + public class GameArchitecture : Architecture + { + // 单例访问点 + public static IArchitecture Interface { get; private set; } + + /// + /// 初始化架构 + /// + protected override void Init() + { + Interface = this; + + // 注册 Model + RegisterModel(new PlayerModel()); + } + } +} +``` + +**代码说明**: +- 继承 `Architecture` 基类 +- 在 `Init()` 方法中注册 Model +- 提供静态属性 `Interface` 用于全局访问架构 + +## 步骤 3:创建 Controller 访问 Model + +创建 Controller 来使用 Model: + +```csharp +using GFramework.Core.Abstractions.architecture; +using GFramework.Core.Abstractions.controller; +using GFramework.Core.extensions; +using MyGame.Models; + +namespace MyGame.Controllers +{ + /// + /// 游戏控制器 + /// + public class GameController : IController + { + /// + /// 获取架构实例 + /// + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + /// + /// 初始化玩家数据 + /// + public void InitializePlayer() + { + // 获取 PlayerModel + var playerModel = this.GetModel(); + + // 设置玩家数据 + playerModel.Name.Value = "勇者"; + playerModel.Health.Value = 100; + playerModel.Gold.Value = 50; + playerModel.Level.Value = 1; + + // 监听属性变化 + playerModel.Health.RegisterOnValueChanged(health => + { + Console.WriteLine($"玩家生命值变化: {health}"); + + if (health <= 0) + { + Console.WriteLine("玩家死亡!"); + } + }); + } + + /// + /// 玩家受到伤害 + /// + public void TakeDamage(int damage) + { + var playerModel = this.GetModel(); + playerModel.Health.Value -= damage; + } + + /// + /// 玩家获得金币 + /// + public void AddGold(int amount) + { + var playerModel = this.GetModel(); + playerModel.Gold.Value += amount; + } + } +} +``` + +**代码说明**: +- 实现 `IController` 接口 +- 通过 `this.GetModel()` 扩展方法获取 Model +- 使用 `.Value` 访问和修改属性值 +- 使用 `RegisterOnValueChanged` 监听属性变化 + +## 步骤 4:初始化并使用架构 + +在程序入口点初始化架构: + +```csharp +using MyGame; +using MyGame.Controllers; + +// 1. 创建并初始化架构 +var architecture = new GameArchitecture(); +architecture.Initialize(); + +// 2. 等待架构就绪 +await architecture.WaitUntilReadyAsync(); + +// 3. 创建 Controller 并使用 +var gameController = new GameController(); + +// 初始化玩家 +gameController.InitializePlayer(); + +// 玩家受到伤害 +gameController.TakeDamage(20); +// 输出: 玩家生命值变化: 80 + +// 玩家获得金币 +gameController.AddGold(100); +``` + +**代码说明**: +- 创建架构实例并调用 `Initialize()` +- 使用 `WaitUntilReadyAsync()` 等待架构就绪 +- 创建 Controller 实例并调用方法 + +## 完整代码 + +### PlayerModel.cs + +```csharp +using GFramework.Core.Abstractions.model; +using GFramework.Core.Abstractions.property; + +namespace MyGame.Models +{ + public class PlayerModel : IModel + { + public BindableProperty Name { get; } = new("Player"); + public BindableProperty Health { get; } = new(100); + public BindableProperty Gold { get; } = new(0); + public BindableProperty Level { get; } = new(1); + + public void Init() { } + } +} +``` + +### GameArchitecture.cs + +```csharp +using GFramework.Core.architecture; +using MyGame.Models; + +namespace MyGame +{ + public class GameArchitecture : Architecture + { + public static IArchitecture Interface { get; private set; } + + protected override void Init() + { + Interface = this; + RegisterModel(new PlayerModel()); + } + } +} +``` + +### GameController.cs + +```csharp +using GFramework.Core.Abstractions.architecture; +using GFramework.Core.Abstractions.controller; +using GFramework.Core.extensions; +using MyGame.Models; + +namespace MyGame.Controllers +{ + public class GameController : IController + { + public IArchitecture GetArchitecture() => GameArchitecture.Interface; + + public void InitializePlayer() + { + var playerModel = this.GetModel(); + playerModel.Name.Value = "勇者"; + playerModel.Health.Value = 100; + playerModel.Gold.Value = 50; + playerModel.Level.Value = 1; + + playerModel.Health.RegisterOnValueChanged(health => + { + Console.WriteLine($"玩家生命值变化: {health}"); + if (health <= 0) + { + Console.WriteLine("玩家死亡!"); + } + }); + } + + public void TakeDamage(int damage) + { + var playerModel = this.GetModel(); + playerModel.Health.Value -= damage; + } + + public void AddGold(int amount) + { + var playerModel = this.GetModel(); + playerModel.Gold.Value += amount; + } + } +} +``` + +### Program.cs + +```csharp +using MyGame; +using MyGame.Controllers; + +var architecture = new GameArchitecture(); +architecture.Initialize(); +await architecture.WaitUntilReadyAsync(); + +var gameController = new GameController(); +gameController.InitializePlayer(); +gameController.TakeDamage(20); +gameController.AddGold(100); +``` + +## 运行结果 + +运行程序后,你将看到以下输出: + +``` +玩家生命值变化: 100 +玩家生命值变化: 80 +``` + +**验证步骤**: +1. 程序成功启动,没有异常 +2. 控制台输出生命值变化信息 +3. 玩家数据正确更新 + +## 下一步 + +恭喜!你已经学会了如何创建和使用 Model。接下来可以学习: + +- [创建第一个 System](/zh-CN/tutorials/create-first-system) - 学习如何创建业务逻辑层 +- [使用命令系统](/zh-CN/tutorials/use-command-system) - 学习如何封装操作 +- [使用事件系统](/zh-CN/tutorials/use-event-system) - 学习组件间通信 + +## 相关文档 + +- [Model 层](/zh-CN/core/model) - Model 详细说明 +- [属性系统](/zh-CN/core/property) - 可绑定属性详解 +- [架构组件](/zh-CN/core/architecture) - 架构基础 +- [Controller 层](/zh-CN/core/controller) - Controller 详细说明 diff --git a/.claude/skills/vitepress-tutorial/template.md b/.claude/skills/vitepress-tutorial/template.md new file mode 100644 index 0000000..f29ab93 --- /dev/null +++ b/.claude/skills/vitepress-tutorial/template.md @@ -0,0 +1,42 @@ +--- +title: {{TUTORIAL_TITLE}} +description: {{TUTORIAL_DESCRIPTION}} +--- + +# {{TUTORIAL_TITLE}} + +## 学习目标 + +{{LEARNING_OBJECTIVES}} + +## 前置条件 + +{{PREREQUISITES}} + +## 步骤 1:{{STEP_1_TITLE}} + +{{STEP_1_CONTENT}} + +## 步骤 2:{{STEP_2_TITLE}} + +{{STEP_2_CONTENT}} + +## 步骤 3:{{STEP_3_TITLE}} + +{{STEP_3_CONTENT}} + +## 完整代码 + +{{FULL_CODE}} + +## 运行结果 + +{{EXPECTED_OUTPUT}} + +## 下一步 + +{{NEXT_STEPS}} + +## 相关文档 + +{{RELATED_DOCS}} diff --git a/.claude/skills/vitepress-validate/SKILL.md b/.claude/skills/vitepress-validate/SKILL.md new file mode 100644 index 0000000..2596c39 --- /dev/null +++ b/.claude/skills/vitepress-validate/SKILL.md @@ -0,0 +1,297 @@ +# VitePress 文档验证 + +验证 VitePress 文档的质量和规范性,确保文档符合项目标准。 + +## 用途 + +此 skill 用于验证 Markdown 文档的格式和内容,包括: +- Frontmatter 格式正确性 +- 内部链接有效性 +- 代码块语法标记 +- 标题层级结构 +- 中文标点符号规范 +- 泛型符号转义 + +## 调用方式 + +```bash +# 验证单个文件 +/vitepress-validate <文件路径> + +# 验证整个目录 +/vitepress-validate <目录路径> + +# 验证所有文档 +/vitepress-validate docs/zh-CN/ +``` + +**示例**: +```bash +/vitepress-validate docs/zh-CN/api-reference/core/architecture.md +/vitepress-validate docs/zh-CN/core/ +``` + +## 验证项 + +### 1. Frontmatter 验证 + +**检查项**: +- YAML 语法正确性 +- 必需字段存在(`title`、`description`) +- 字段值类型正确 +- `outline` 字段值有效(`deep`、`[2,3]` 等) + +**示例**: +```yaml +--- +title: Architecture # 必需 +description: 架构基类说明 # 必需 +outline: deep # 可选,但值必须有效 +--- +``` + +### 2. 内部链接验证 + +**检查项**: +- 相对路径链接指向的文件存在 +- 绝对路径链接格式正确 +- 锚点链接对应的标题存在 +- 没有损坏的链接 + +**有效链接格式**: +- `[文本](./file.md)` - 相对路径 +- `[文本](/zh-CN/core/architecture)` - 绝对路径 +- `[文本](#标题)` - 锚点链接 +- `[文本](./file.md#标题)` - 组合链接 + +### 3. 代码块验证 + +**检查项**: +- 代码块有语法标记(```csharp、```bash 等) +- C# 代码块使用 `csharp` 标记(不是 `cs` 或 `c#`) +- 代码块正确闭合 +- 没有未闭合的反引号 + +**正确格式**: +```markdown +\`\`\`csharp +public class Example { } +\`\`\` +``` + +**错误格式**: +```markdown +\`\`\`cs // 应该使用 csharp +public class Example { } +\`\`\` +``` + +### 4. 标题层级验证 + +**检查项**: +- 标题层级不跳级(不能从 `#` 直接跳到 `###`) +- 每个文档只有一个一级标题(`#`) +- 标题层级递增合理 + +**正确示例**: +```markdown +# 一级标题 +## 二级标题 +### 三级标题 +## 另一个二级标题 +``` + +**错误示例**: +```markdown +# 一级标题 +### 三级标题 ❌ 跳过了二级标题 +``` + +### 5. 中文标点符号验证 + +**检查项**: +- 中文句子使用全角标点(,。!?) +- 英文句子使用半角标点(,.!?) +- 代码和技术术语周围使用半角符号 +- 括号使用规范 + +**规范示例**: +- "这是一个示例。" ✓(中文全角句号) +- "This is an example." ✓(英文半角句号) +- "`Architecture` 类提供了..." ✓(代码周围半角) + +### 6. 泛型符号验证 + +**检查项**: +- 泛型符号正确转义(`` → `<T>`) +- 仅在代码块外转义 +- 代码块内保持原样 + +**正确示例**: +```markdown +`List<T>` 是一个泛型类。 + +\`\`\`csharp +List items = new List(); // 代码块内不转义 +\`\`\` +``` + +## 验证脚本 + +### validate-frontmatter.sh + +验证 Frontmatter 格式。 + +**用法**: +```bash +.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh <文件路径> +``` + +### validate-links.sh + +验证内部链接有效性。 + +**用法**: +```bash +.claude/skills/vitepress-validate/scripts/validate-links.sh <文件路径> +``` + +### validate-code-blocks.sh + +验证代码块语法。 + +**用法**: +```bash +.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh <文件路径> +``` + +### validate-all.sh + +执行所有验证。 + +**用法**: +```bash +.claude/skills/vitepress-validate/scripts/validate-all.sh <文件或目录路径> +``` + +## 输出格式 + +### 验证通过 + +``` +✓ docs/zh-CN/core/architecture.md + - Frontmatter: 通过 + - 内部链接: 通过 + - 代码块: 通过 + - 标题层级: 通过 + - 标点符号: 通过 + - 泛型符号: 通过 +``` + +### 验证失败 + +``` +✗ docs/zh-CN/core/architecture.md + - Frontmatter: 失败 + × 缺少必需字段: description + - 内部链接: 失败 + × 损坏的链接: ./missing-file.md (第 45 行) + - 代码块: 警告 + ⚠ 使用了 'cs' 标记,建议使用 'csharp' (第 78 行) + - 标题层级: 通过 + - 标点符号: 警告 + ⚠ 中文句子使用了半角句号 (第 102 行) + - 泛型符号: 失败 + × 未转义的泛型符号: List (第 120 行) +``` + +## 修复建议 + +验证失败时,skill 会提供具体的修复建议: + +**示例**: +``` +修复建议: +1. 在 Frontmatter 中添加 description 字段 +2. 修复或删除损坏的链接: ./missing-file.md +3. 将代码块标记从 'cs' 改为 'csharp' +4. 将第 102 行的半角句号改为全角句号 +5. 将第 120 行的 List 改为 List<T> +``` + +## 配置选项 + +### 严格模式 + +启用严格模式时,警告也会导致验证失败。 + +```bash +/vitepress-validate --strict docs/zh-CN/ +``` + +### 忽略特定检查 + +```bash +# 忽略标点符号检查 +/vitepress-validate --ignore-punctuation docs/zh-CN/ + +# 忽略多个检查 +/vitepress-validate --ignore-punctuation --ignore-generics docs/zh-CN/ +``` + +## 集成到工作流 + +### 生成后自动验证 + +```bash +# 1. 生成 API 文档 +/vitepress-api-doc GFramework.Core/architecture/Architecture.cs + +# 2. 自动验证生成的文档 +/vitepress-validate docs/zh-CN/api-reference/core/architecture.md +``` + +### 批量验证 + +```bash +# 验证所有 API 文档 +/vitepress-validate docs/zh-CN/api-reference/ + +# 验证所有文档 +/vitepress-validate docs/zh-CN/ +``` + +## 退出代码 + +- `0` - 所有验证通过 +- `1` - 存在错误 +- `2` - 仅存在警告(非严格模式下仍返回 0) + +## 相关 Skills + +- `/vitepress-api-doc` - 生成 API 文档后自动验证 +- `/vitepress-guide` - 生成指南文档后自动验证 +- `/vitepress-tutorial` - 生成教程文档后自动验证 + +## 最佳实践 + +1. **生成后立即验证**:每次生成文档后立即运行验证 +2. **定期批量验证**:定期验证所有文档,确保一致性 +3. **修复所有错误**:不要忽略验证错误,及时修复 +4. **关注警告**:警告虽不致命,但应该重视并修复 +5. **使用严格模式**:在 CI/CD 中使用严格模式确保质量 + +## 故障排除 + +### 问题:误报泛型符号错误 +**解决方案**:确保泛型符号在代码块外正确转义,代码块内保持原样 + +### 问题:中文标点符号检查过于严格 +**解决方案**:使用 `--ignore-punctuation` 选项,或手动调整规则 + +### 问题:链接验证失败但文件确实存在 +**解决方案**:检查文件路径大小写,确保路径完全匹配 + +## 版本历史 + +- v1.0.0 - 初始版本,支持 6 项基本验证 diff --git a/.claude/skills/vitepress-validate/scripts/validate-all.sh b/.claude/skills/vitepress-validate/scripts/validate-all.sh new file mode 100644 index 0000000..63467cf --- /dev/null +++ b/.claude/skills/vitepress-validate/scripts/validate-all.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# 执行所有验证 +# 用法: validate-all.sh <文件或目录路径> + +set -e + +TARGET="$1" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -z "$TARGET" ]; then + echo "用法: $0 <文件或目录路径>" + exit 1 +fi + +if [ ! -e "$TARGET" ]; then + echo "错误: 路径不存在: $TARGET" + exit 1 +fi + +echo "==========================================" +echo "VitePress 文档验证" +echo "==========================================" +echo "" + +# 收集所有 Markdown 文件 +if [ -f "$TARGET" ]; then + FILES=("$TARGET") +elif [ -d "$TARGET" ]; then + mapfile -t FILES < <(find "$TARGET" -name "*.md" -type f) +else + echo "错误: 无效的路径: $TARGET" + exit 1 +fi + +if [ ${#FILES[@]} -eq 0 ]; then + echo "未找到 Markdown 文件" + exit 0 +fi + +echo "找到 ${#FILES[@]} 个文件" +echo "" + +TOTAL_ERRORS=0 +TOTAL_WARNINGS=0 +PASSED_FILES=0 +FAILED_FILES=0 + +for FILE in "${FILES[@]}"; do + echo "验证: $FILE" + echo "----------------------------------------" + + FILE_ERRORS=0 + FILE_WARNINGS=0 + + # 1. Frontmatter 验证 + if bash "$SCRIPT_DIR/validate-frontmatter.sh" "$FILE" 2>&1 | grep -q "✗"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + + # 2. 链接验证 + if bash "$SCRIPT_DIR/validate-links.sh" "$FILE" 2>&1 | grep -q "✗"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + + # 3. 代码块验证 + OUTPUT=$(bash "$SCRIPT_DIR/validate-code-blocks.sh" "$FILE" 2>&1) + if echo "$OUTPUT" | grep -q "✗"; then + FILE_ERRORS=$((FILE_ERRORS + 1)) + fi + if echo "$OUTPUT" | grep -q "⚠"; then + FILE_WARNINGS=$((FILE_WARNINGS + 1)) + fi + + # 统计结果 + if [ $FILE_ERRORS -eq 0 ]; then + echo "✓ 验证通过" + PASSED_FILES=$((PASSED_FILES + 1)) + else + echo "✗ 验证失败($FILE_ERRORS 个错误)" + FAILED_FILES=$((FAILED_FILES + 1)) + fi + + if [ $FILE_WARNINGS -gt 0 ]; then + echo "⚠ $FILE_WARNINGS 个警告" + fi + + TOTAL_ERRORS=$((TOTAL_ERRORS + FILE_ERRORS)) + TOTAL_WARNINGS=$((TOTAL_WARNINGS + FILE_WARNINGS)) + + echo "" +done + +echo "==========================================" +echo "验证摘要" +echo "==========================================" +echo "总文件数: ${#FILES[@]}" +echo "通过: $PASSED_FILES" +echo "失败: $FAILED_FILES" +echo "总错误数: $TOTAL_ERRORS" +echo "总警告数: $TOTAL_WARNINGS" +echo "" + +if [ $TOTAL_ERRORS -eq 0 ]; then + echo "✓ 所有验证通过" + exit 0 +else + echo "✗ 验证失败" + exit 1 +fi diff --git a/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh b/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh new file mode 100644 index 0000000..938753c --- /dev/null +++ b/.claude/skills/vitepress-validate/scripts/validate-code-blocks.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# 验证代码块语法 +# 用法: validate-code-blocks.sh <文件路径> + +set -e + +FILE="$1" + +if [ -z "$FILE" ]; then + echo "用法: $0 <文件路径>" + exit 1 +fi + +if [ ! -f "$FILE" ]; then + echo "错误: 文件不存在: $FILE" + exit 1 +fi + +echo "验证代码块语法: $FILE" + +ERROR_COUNT=0 +WARNING_COUNT=0 + +# 检查未闭合的代码块 +OPEN_COUNT=$(grep -c '^```' "$FILE" || true) +if [ $((OPEN_COUNT % 2)) -ne 0 ]; then + echo "✗ 错误: 存在未闭合的代码块" + ERROR_COUNT=$((ERROR_COUNT + 1)) +fi + +# 检查 C# 代码块标记 +LINE_NUM=0 +while IFS= read -r LINE; do + LINE_NUM=$((LINE_NUM + 1)) + + # 检查是否使用了错误的 C# 标记 + if echo "$LINE" | grep -qE '^```(cs|c#|C#)$'; then + echo "⚠ 警告: 第 $LINE_NUM 行使用了非标准标记,建议使用 'csharp'" + echo " 当前: $LINE" + WARNING_COUNT=$((WARNING_COUNT + 1)) + fi + + # 检查代码块是否有语言标记 + if echo "$LINE" | grep -qE '^```$'; then + # 检查下一行是否是代码(简单启发式:不是空行且不是 ```) + NEXT_LINE=$(sed -n "$((LINE_NUM + 1))p" "$FILE") + if [ -n "$NEXT_LINE" ] && ! echo "$NEXT_LINE" | grep -qE '^```'; then + echo "⚠ 警告: 第 $LINE_NUM 行的代码块缺少语言标记" + WARNING_COUNT=$((WARNING_COUNT + 1)) + fi + fi +done < "$FILE" + +# 输出结果 +if [ $ERROR_COUNT -eq 0 ] && [ $WARNING_COUNT -eq 0 ]; then + echo "✓ 代码块验证通过" + exit 0 +elif [ $ERROR_COUNT -eq 0 ]; then + echo "⚠ 代码块验证通过(有 $WARNING_COUNT 个警告)" + exit 0 +else + echo "✗ 代码块验证失败($ERROR_COUNT 个错误,$WARNING_COUNT 个警告)" + exit 1 +fi diff --git a/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh b/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh new file mode 100644 index 0000000..306da13 --- /dev/null +++ b/.claude/skills/vitepress-validate/scripts/validate-frontmatter.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# 验证 Frontmatter 格式 +# 用法: validate-frontmatter.sh <文件路径> + +set -e + +FILE="$1" + +if [ -z "$FILE" ]; then + echo "用法: $0 <文件路径>" + exit 1 +fi + +if [ ! -f "$FILE" ]; then + echo "错误: 文件不存在: $FILE" + exit 1 +fi + +echo "验证 Frontmatter: $FILE" + +# 检查是否有 Frontmatter +if ! grep -q "^---$" "$FILE"; then + echo "✗ 错误: 文件缺少 Frontmatter" + exit 1 +fi + +# 提取 Frontmatter 内容(第一个 --- 到第二个 --- 之间) +FRONTMATTER=$(sed -n '/^---$/,/^---$/p' "$FILE" | sed '1d;$d') + +if [ -z "$FRONTMATTER" ]; then + echo "✗ 错误: Frontmatter 为空" + exit 1 +fi + +# 检查必需字段: title +if ! echo "$FRONTMATTER" | grep -q "^title:"; then + echo "✗ 错误: 缺少必需字段: title" + exit 1 +fi + +# 检查必需字段: description +if ! echo "$FRONTMATTER" | grep -q "^description:"; then + echo "✗ 错误: 缺少必需字段: description" + exit 1 +fi + +# 检查 outline 字段值(如果存在) +if echo "$FRONTMATTER" | grep -q "^outline:"; then + OUTLINE_VALUE=$(echo "$FRONTMATTER" | grep "^outline:" | sed 's/outline:\s*//') + if [ "$OUTLINE_VALUE" != "deep" ] && [ "$OUTLINE_VALUE" != "false" ] && ! echo "$OUTLINE_VALUE" | grep -qE '^\[.*\]$'; then + echo "⚠ 警告: outline 字段值可能无效: $OUTLINE_VALUE" + echo " 有效值: deep, false, [2,3]" + fi +fi + +echo "✓ Frontmatter 验证通过" +exit 0 diff --git a/.claude/skills/vitepress-validate/scripts/validate-links.sh b/.claude/skills/vitepress-validate/scripts/validate-links.sh new file mode 100644 index 0000000..7f42ab7 --- /dev/null +++ b/.claude/skills/vitepress-validate/scripts/validate-links.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# 验证内部链接有效性 +# 用法: validate-links.sh <文件路径> + +set -e + +FILE="$1" +BASE_DIR="docs/zh-CN" + +if [ -z "$FILE" ]; then + echo "用法: $0 <文件路径>" + exit 1 +fi + +if [ ! -f "$FILE" ]; then + echo "错误: 文件不存在: $FILE" + exit 1 +fi + +echo "验证内部链接: $FILE" + +# 获取文件所在目录 +FILE_DIR=$(dirname "$FILE") + +# 提取所有 Markdown 链接 +LINKS=$(grep -oP '\[([^\]]+)\]\(([^)]+)\)' "$FILE" | grep -oP '\(([^)]+)\)' | sed 's/[()]//g' || true) + +if [ -z "$LINKS" ]; then + echo "✓ 未找到链接" + exit 0 +fi + +ERROR_COUNT=0 + +while IFS= read -r LINK; do + # 跳过外部链接 + if [[ "$LINK" =~ ^https?:// ]]; then + continue + fi + + # 跳过锚点链接(仅 #开头) + if [[ "$LINK" =~ ^# ]]; then + continue + fi + + # 移除锚点部分 + LINK_PATH=$(echo "$LINK" | sed 's/#.*//') + + # 跳过空路径 + if [ -z "$LINK_PATH" ]; then + continue + fi + + # 处理相对路径 + if [[ "$LINK_PATH" =~ ^\. ]]; then + TARGET="$FILE_DIR/$LINK_PATH" + # 处理绝对路径 + elif [[ "$LINK_PATH" =~ ^/ ]]; then + TARGET="docs$LINK_PATH" + # 如果没有扩展名,尝试添加 .md + if [[ ! "$TARGET" =~ \. ]]; then + TARGET="$TARGET.md" + fi + else + TARGET="$FILE_DIR/$LINK_PATH" + fi + + # 规范化路径 + TARGET=$(realpath -m "$TARGET" 2>/dev/null || echo "$TARGET") + + # 检查文件是否存在 + if [ ! -f "$TARGET" ] && [ ! -d "$TARGET" ]; then + echo "✗ 损坏的链接: $LINK" + echo " 目标不存在: $TARGET" + ERROR_COUNT=$((ERROR_COUNT + 1)) + fi +done <<< "$LINKS" + +if [ $ERROR_COUNT -eq 0 ]; then + echo "✓ 内部链接验证通过" + exit 0 +else + echo "✗ 发现 $ERROR_COUNT 个损坏的链接" + exit 1 +fi diff --git a/.gitignore b/.gitignore index d56f69b..cff1d66 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ riderModule.iml GFramework.sln.DotSettings.user .idea/ .opencode.json -.claude/ \ No newline at end of file +.claude/settings.local.json \ No newline at end of file