feat: 根目录文档、脚本、gitignore
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# Code Map 技能
|
||||
|
||||
> 基于 Grep/Read 文本分析 + LLM 语义理解,为代码仓库生成可追溯的 YAML 知识图谱
|
||||
|
||||
**权威定义见 [SKILL.md](SKILL.md)**(含触发条件、分析等级、执行流程)。
|
||||
**执行指引见 [executor.yaml](executor.yaml)**(Agent 按 Phase 0–12 执行)。
|
||||
本文件仅为概览与使用说明。
|
||||
|
||||
## 概述
|
||||
|
||||
Code Map 技能将源代码转化为结构化的 YAML 知识图谱,包含:
|
||||
|
||||
- **符号信息**:类、方法、字段的精确定义和位置
|
||||
- **API 详情**:请求参数、响应字段、错误码
|
||||
- **调用链**:以 API 入口为根的调用图
|
||||
- **交叉引用**:callers/callees、继承、前后端映射
|
||||
- **Mermaid 可视化**:状态机图、调用链图、API 矩阵图等
|
||||
|
||||
分析等级:**L1 快速扫描 / L2 标准分析(默认)/ L3 完整生成**;
|
||||
L4 业务知识提取(公式/决策点/错误/阈值)为可选扩展,详见 SKILL.md。
|
||||
|
||||
平台支持:检测到什么平台分析什么。已验证路径为 Java / Vue / 小程序;
|
||||
Kotlin、Swift 有备用模板(`templates/kotlin-symbol.template.yaml`、
|
||||
`templates/swift-symbol.template.yaml`),仅在检测到对应代码时启用。
|
||||
|
||||
## 使用方式
|
||||
|
||||
```
|
||||
/sn-codemap [<project_path>] [--output <dir>] [--auxiliary <dir>]
|
||||
[--level L1|L2|L3] [--incremental] [--full-rebuild] [--resume]
|
||||
```
|
||||
|
||||
不带参数执行时进入交互式初始化(executor Phase 0)。
|
||||
|
||||
```bash
|
||||
/sn-codemap /path/to/project # 基本用法
|
||||
/sn-codemap /path/to/project --level L3 # 完整生成
|
||||
/sn-codemap /path/to/project --incremental # 强制增量分析
|
||||
/sn-codemap /path/to/project --resume # 断点续跑
|
||||
```
|
||||
|
||||
生成的 `.mmd` 图可在 [Mermaid Live Editor](https://mermaid.live) 预览,
|
||||
或用 `mmdc -i input.mmd -o output.svg` 导出。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
codemap/
|
||||
├── SKILL.md # 技能权威定义(入口)
|
||||
├── executor.yaml # 执行指引(Agent 按 Phase 0–12 执行)
|
||||
├── README.md # 本文件
|
||||
├── workflows/ # 子工作流(被 executor 引用时加载)
|
||||
│ ├── incremental-analysis.yaml # 增量分析(Phase 1/11)
|
||||
│ ├── cache-management.yaml # 结果缓存(Phase 1/11)
|
||||
│ ├── cross-platform-api-mapping.yaml # 跨端 API 识别唯一定义(Phase 6)
|
||||
│ ├── mermaid-generation.yaml # Mermaid 图生成(Phase 8)
|
||||
│ └── unified-domain-model.yaml # 统一业务域模型(Phase 9)
|
||||
├── templates/ # 产物 YAML 模板 + mermaid/ 图模板
|
||||
├── schemas/ # 产物 JSON Schema
|
||||
└── guides/ # LSP/Serena 使用指南(需对应工具可用,否则忽略)
|
||||
```
|
||||
|
||||
## 输出结构
|
||||
|
||||
```
|
||||
codemap/
|
||||
├── _index.yaml # 项目主索引
|
||||
├── _summary.yaml # 分析摘要
|
||||
├── .codemap/state.yaml # 分析状态(增量/断点续跑)
|
||||
├── context/ # 项目背景与技术栈
|
||||
├── symbols/ # 符号索引(按检测到的平台)
|
||||
├── api/ # API 目录与详情(L2 核心、L3 全量)
|
||||
├── dataobjects/ # 数据对象详情
|
||||
├── callchains/ # 调用链
|
||||
├── mapping/ # 前后端/跨端映射
|
||||
├── xrefs/ # 交叉引用(L3)
|
||||
├── graphs/ # Mermaid 图(L3)
|
||||
├── domain-entities/ # 统一业务域模型(L3 多平台)
|
||||
└── formulas/ decisions/ errors/ thresholds/ # L4 可选扩展
|
||||
```
|
||||
|
||||
## 核心原则
|
||||
|
||||
1. **事实优先** - 结构信息必须来自代码(Grep/Read),不能捏造
|
||||
2. **可追溯** - 每个信息都有源码位置引用
|
||||
3. **语义增强** - 在事实基础上,用 LLM 补充业务含义
|
||||
4. **按需加载** - 索引与详情分层存储,按分析等级生成
|
||||
|
||||
## 文件大小管理
|
||||
|
||||
读取任何文件前先 `wc -l` 检查大小:≤500 行直接读,500–2000 行分批读,
|
||||
>2000 行或 >100KB 先用 Grep 定位结构再定点读。详见 executor.yaml
|
||||
`file_size_management` 节。
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 更新内容 |
|
||||
|------|----------|
|
||||
| v4.0 | 彻底重构:对齐执行链路,Phase 连续编号,Grep/Read 主路径,L4 转可选扩展,删除死文件 |
|
||||
| v3.x 及更早 | 历史版本,已被 v4.0 取代 |
|
||||
|
||||
当前版本:v4.0
|
||||
@@ -0,0 +1,236 @@
|
||||
---
|
||||
name: sn-codemap
|
||||
description: 将代码仓库转化为结构化 YAML 知识图谱(符号索引、API 详情、调用链、数据对象、交叉引用,L4 含公式/决策点/错误/阈值等业务知识)。当用户要求"分析项目"、"生成 codemap"、"提取符号/调用链"、"生成完整代码文档"或输入 /sn-codemap、/codemap 时使用。
|
||||
---
|
||||
|
||||
# Code Map 代码知识图谱生成 (sn-codemap)
|
||||
|
||||
## 功能概述
|
||||
|
||||
将代码仓库转化为结构化的 YAML 知识图谱:
|
||||
|
||||
**代码结构**:
|
||||
- 符号信息:类、方法、字段的定义和位置
|
||||
- API 详情:请求参数、响应字段、错误码
|
||||
- 调用链:以 API 入口为根的调用图
|
||||
- 交叉引用:callers/callees、继承关系、前后端映射
|
||||
- 数据对象:Entity/DTO/VO 的字段和关系
|
||||
|
||||
**业务知识(L4 可选扩展)**:
|
||||
- 公式提取:计算逻辑的伪代码和配置依赖
|
||||
- 决策点:if-else 分支和业务判断条件
|
||||
- 错误信息:异常消息和触发条件清单
|
||||
- 阈值常量:业务相关的常量值
|
||||
|
||||
---
|
||||
|
||||
## 加载链路(执行时如何读取本技能)
|
||||
|
||||
1. 触发本技能后,**先加载 `executor.yaml`**,按其中 Phase 0 → Phase 12 的顺序执行。
|
||||
2. `templates/`、`schemas/` 在各 Phase 生成产物时按 executor 中的引用查阅。
|
||||
3. `workflows/` 的 5 个子工作流在 executor 对应 Phase 中被引用时加载。
|
||||
4. `guides/`(lsp-*.md)仅在需要 LSP/Serena 具体操作指引且对应工具可用时查阅,否则忽略。
|
||||
|
||||
---
|
||||
|
||||
## 分析等级(开始时与用户确认)
|
||||
|
||||
| 等级 | 名称 | 产出范围 | 适用场景 |
|
||||
|------|------|----------|----------|
|
||||
| **L1** | 快速扫描 | 技术栈 + 各平台符号索引 + 主索引 | 快速了解项目 |
|
||||
| **L2** | 标准分析 | L1 + API 目录 + 核心数据对象/调用链/前后端映射 | 日常开发 |
|
||||
| **L3** | 完整生成 | L2 全量化 + 交叉引用 + 跨端映射 + Mermaid 图 + 域模型 | 完整文档 |
|
||||
|
||||
等级通过 `--level` 参数或 Phase 0 交互确认,默认 L2。
|
||||
|
||||
### L4 可选扩展(业务知识提取)
|
||||
|
||||
executor.yaml 的执行流程覆盖 L1–L3。L4(formulas / decisions / errors / thresholds
|
||||
业务知识提取)为**按需扩展**:在 L3 完成后,用户可要求提取业务知识,Agent 使用
|
||||
`templates/formula|decision|error|threshold.template.yaml` 模板与
|
||||
`schemas/codemap.formula|decision|error|threshold.schema.json` 进行提取,
|
||||
产出写入 `formulas/`、`decisions/`、`errors/`、`thresholds/` 目录(各含 `_index.yaml`),
|
||||
按 15 个/批 分批处理。
|
||||
|
||||
---
|
||||
|
||||
## 多语言支持(检测到什么平台分析什么)
|
||||
|
||||
技术栈检测(Phase 2)决定分析范围,只分析实际检测到的平台。
|
||||
|
||||
已验证路径:
|
||||
|
||||
| 平台 | 语言 | 分析内容 | 产出目录 |
|
||||
|------|------|----------|----------|
|
||||
| 后端 | Java | Controller, Service, Mapper, Entity | symbols/java/, api/java/, dataobjects/java/, callchains/java/ |
|
||||
| Web 前端 | Vue | 页面组件, API 调用层 | symbols/vue/ |
|
||||
| 小程序 | uni-app | 页面, 组件, API 调用 | symbols/miniapp/ |
|
||||
|
||||
备用路径(仅在检测到对应代码时启用,使用备用模板):
|
||||
|
||||
| 平台 | 备用模板 |
|
||||
|------|----------|
|
||||
| Android (Kotlin) | `templates/kotlin-symbol.template.yaml` |
|
||||
| iOS (Swift) | `templates/swift-symbol.template.yaml` |
|
||||
|
||||
符号分析主路径为 Grep/Glob/Read/Bash;若环境提供 Serena MCP(mcp__serena__*)
|
||||
可用于加速,否则用 Grep/Read 完成,不得因此中断。
|
||||
|
||||
---
|
||||
|
||||
## 输出目录结构(L3 全量示例,按实际检测平台生成)
|
||||
|
||||
```
|
||||
codemap/
|
||||
├── _index.yaml # 项目主索引
|
||||
├── _summary.yaml # 分析摘要
|
||||
├── .codemap/state.yaml # 分析状态(支持增量/断点续跑)
|
||||
│
|
||||
├── context/ # 项目背景
|
||||
│ ├── _project_context.yaml
|
||||
│ └── _tech_stack.yaml
|
||||
│
|
||||
├── symbols/ # 符号索引(按检测到的平台)
|
||||
│ ├── java/_symbols_index.yaml
|
||||
│ ├── vue/_symbols_index.yaml
|
||||
│ └── miniapp/_symbols_index.yaml
|
||||
│
|
||||
├── api/ # API 目录与详情(L2 核心、L3 全量)
|
||||
│ └── java/
|
||||
│ ├── _api_catalog.yaml
|
||||
│ └── {endpoint-name}.yaml
|
||||
│
|
||||
├── dataobjects/ # 数据对象详情(L2 核心、L3 全量)
|
||||
│ └── java/
|
||||
│ ├── _dataobjects_index.yaml
|
||||
│ └── {entity-name}.yaml
|
||||
│
|
||||
├── callchains/ # 调用链(L2 核心流程、L3 全量)
|
||||
│ └── java/
|
||||
│ ├── _callchains_index.yaml
|
||||
│ └── {chain-name}.yaml
|
||||
│
|
||||
├── mapping/ # 前后端/跨端映射
|
||||
│ ├── _frontend_backend_mapping.yaml
|
||||
│ ├── _cross_platform_api_mapping.yaml # L3 多端项目
|
||||
│ └── _api_consumer_matrix.yaml # L3 多端项目
|
||||
│
|
||||
├── xrefs/ # 交叉引用(L3)
|
||||
│ ├── _xrefs_index.yaml
|
||||
│ ├── callers-callees.yaml
|
||||
│ └── inheritance.yaml
|
||||
│
|
||||
├── graphs/ # Mermaid 图(L3)
|
||||
│ ├── _index.yaml
|
||||
│ ├── state-machines/
|
||||
│ └── callchains/
|
||||
│
|
||||
├── domain-entities/ # 统一业务域模型(L3 多平台)
|
||||
│
|
||||
├── formulas/ # 业务公式(L4 可选扩展)
|
||||
├── decisions/ # 决策点(L4 可选扩展)
|
||||
├── errors/ # 错误信息(L4 可选扩展)
|
||||
└── thresholds/ # 阈值常量(L4 可选扩展)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 执行流程(与 executor.yaml 的 Phase 一一对应)
|
||||
|
||||
| Phase | 名称 | 说明 | 主要产出 |
|
||||
|-------|------|------|----------|
|
||||
| 0 | 交互式初始化与参数确认 | 收集代码目录、输出目录、等级 | 分析计划 |
|
||||
| 1 | Git 检测与增量分析判断 | Git 状态、历史状态、增量/全量决策 | 变更清单 |
|
||||
| 2 | 技术栈检测 | 平台与框架检测,决定分析范围 | context/_tech_stack.yaml |
|
||||
| 3 | 辅助文档分析(可选) | SQL、对接文档 | schema/、external/、context/ |
|
||||
| 4 | Java 后端分析 | 符号/API/数据对象/调用链 | symbols/java/、api/java/、dataobjects/java/、callchains/java/ |
|
||||
| 5 | 前端分析 | Vue/小程序页面与 API 调用层 | symbols/vue/、symbols/miniapp/ |
|
||||
| 6 | 前后端映射与跨端 API 分析 | 路径匹配、跨端追踪 | mapping/ |
|
||||
| 7 | 交叉引用生成(L3) | callers/callees、继承 | xrefs/ |
|
||||
| 8 | Mermaid 图生成(L3) | 可视化图 | graphs/ |
|
||||
| 9 | 统一业务域模型(L3 可选) | 跨端实体映射 | domain-entities/ |
|
||||
| 10 | 索引生成 | 主索引与摘要 | _index.yaml、_summary.yaml |
|
||||
| 11 | 状态更新与缓存 | checksum、状态文件 | .codemap/state.yaml |
|
||||
| 12 | 完整性检查与完成报告 | 验证产出、补缺、报告 | 检查报告 |
|
||||
|
||||
---
|
||||
|
||||
## 完整性检查(Phase 12,只检查可兑现项)
|
||||
|
||||
- 核心文件存在:`_index.yaml`、`.codemap/state.yaml`、`context/_tech_stack.yaml`
|
||||
- 符号索引与技术栈检测一致:检测到哪个平台就存在对应的 `symbols/{platform}/_symbols_index.yaml`
|
||||
- 按等级生成的索引文件存在:L2 起 `api/java/_api_catalog.yaml`、`dataobjects/java/_dataobjects_index.yaml`、`callchains/java/_callchains_index.yaml`;L3 增 `xrefs/_xrefs_index.yaml`
|
||||
- API/dataobject 详情文件按等级生成(L2 核心、L3 全量),以索引文件存在为准,不做数量硬指标
|
||||
|
||||
---
|
||||
|
||||
## 上下文管理
|
||||
|
||||
### 文件大小管理
|
||||
|
||||
读取任何文件前先 `wc -l` 检查:≤500 行直接读;500–2000 行分批读;
|
||||
>2000 行或 >100KB 先用 Grep 定位结构再定点读。详细规则见 executor.yaml
|
||||
`file_size_management` 节。
|
||||
|
||||
### 分批执行(大型项目)
|
||||
|
||||
| 内容类型 | 批次大小 |
|
||||
|----------|----------|
|
||||
| 数据对象 | 20 个/批 |
|
||||
| 调用链 | 10 个/批 |
|
||||
| API 详情 | 30 个/批 |
|
||||
| L4 业务知识 | 15 个/批 |
|
||||
|
||||
### 断点续跑
|
||||
|
||||
状态保存在 `.codemap/state.yaml`(增量变更保存在 `.codemap/pending_changes.json`),
|
||||
中断后重新执行 `/sn-codemap --resume` 可继续。
|
||||
|
||||
---
|
||||
|
||||
## 使用场景
|
||||
|
||||
- 用户说"分析项目"、"生成 codemap"
|
||||
- 用户说"提取符号"、"分析调用链"
|
||||
- 用户说"生成完整代码文档"
|
||||
- 直接输入 `/sn-codemap` 或 `/codemap`
|
||||
|
||||
## 命令格式
|
||||
|
||||
```
|
||||
/sn-codemap <project_path> [options]
|
||||
|
||||
选项:
|
||||
--output, -o 输出目录
|
||||
--auxiliary, -a 辅助文档目录
|
||||
--level 分析等级 (L1/L2/L3)
|
||||
--incremental 强制增量分析
|
||||
--full-rebuild 强制全量重建
|
||||
--resume 从上次中断处继续
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 资源清单
|
||||
|
||||
- `executor.yaml` — 执行指引(Agent 按 Phase 0–12 执行,**执行时首先加载**)
|
||||
- `workflows/` — 子工作流(被 executor 对应 Phase 引用时加载):
|
||||
- `incremental-analysis.yaml` — 增量分析:Git diff / checksum 变更检测、影响分析、增量合并(Phase 1/11)
|
||||
- `cache-management.yaml` — 分析结果缓存:checksum 验证、级联失效、淘汰策略(Phase 1/11)
|
||||
- `cross-platform-api-mapping.yaml` — 跨端 API 识别的**唯一定义**:各端调用模式、路径匹配、一致性检查(Phase 6)
|
||||
- `mermaid-generation.yaml` — Mermaid 图生成步骤(Phase 8)
|
||||
- `unified-domain-model.yaml` — 统一业务域模型生成步骤(Phase 9)
|
||||
- `templates/` — 产物 YAML 模板(生成对应产物时查阅;`kotlin-symbol` / `swift-symbol` / `miniapp-page` 为备用模板,仅在检测到对应平台时使用)与 `templates/mermaid/` 图模板
|
||||
- `schemas/` — 产物 JSON Schema(验证产物结构时查阅)
|
||||
- `guides/`(lsp-*.md)— LSP/Serena 工具使用指南;需对应 LSP server 或 Serena MCP 可用,否则忽略
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 更新内容 |
|
||||
|------|----------|
|
||||
| v4.0 | 彻底重构:对齐执行链路(SKILL.md → executor.yaml → workflows/templates/schemas),Phase 重排为连续整数,符号分析主路径改为 Grep/Read/Bash,L4 转可选扩展,多语言收敛为按检测分析,删除无人消费的配置与孤儿文件 |
|
||||
| v3.x 及更早 | 历史版本(LSP/Serena 中心架构、L1–L4 等级、缓存/增量机制引入等),已被 v4.0 取代 |
|
||||
|
||||
当前版本:v4.0
|
||||
@@ -0,0 +1,372 @@
|
||||
# jdtls (Java Language Server) 使用指南
|
||||
|
||||
> 通过 Serena MCP 工具调用 jdtls 进行 Java 代码分析
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 1. 确保 jdtls 已安装
|
||||
|
||||
jdtls 通常通过 VS Code 的 Java 扩展自动安装,或者手动安装:
|
||||
|
||||
```bash
|
||||
# 检查 jdtls 路径
|
||||
which jdtls
|
||||
# 或
|
||||
ls ~/.vscode/extensions/redhat.java-*/server/
|
||||
```
|
||||
|
||||
### 2. 项目结构要求
|
||||
|
||||
jdtls 需要以下文件来识别 Java 项目:
|
||||
|
||||
- Maven: `pom.xml`
|
||||
- Gradle: `build.gradle` 或 `build.gradle.kts`
|
||||
- Eclipse: `.project` 和 `.classpath`
|
||||
|
||||
---
|
||||
|
||||
## 通过 Serena 使用 jdtls
|
||||
|
||||
### 激活项目
|
||||
|
||||
```yaml
|
||||
# Step 1: 激活 Java 项目
|
||||
tool: mcp__serena__activate_project
|
||||
params:
|
||||
project: "/path/to/java/project"
|
||||
|
||||
# 返回: 项目已激活,jdtls 已初始化
|
||||
```
|
||||
|
||||
### 验证配置
|
||||
|
||||
```yaml
|
||||
# 检查当前配置
|
||||
tool: mcp__serena__get_current_config
|
||||
|
||||
# 确认输出包含:
|
||||
# - active_project: /path/to/java/project
|
||||
# - language_server: jdtls
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 符号提取操作
|
||||
|
||||
### 获取文件符号概览
|
||||
|
||||
```yaml
|
||||
# 获取单个文件的符号列表(不含代码体)
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "src/main/java/com/example/OrderController.java"
|
||||
depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员
|
||||
|
||||
# 返回示例:
|
||||
# Classes:
|
||||
# - OrderController (class) [59-1241]
|
||||
# Methods:
|
||||
# - getOrderList (method) [120-145]
|
||||
# - createOrder (method) [150-180]
|
||||
# - updateOrder (method) [185-210]
|
||||
```
|
||||
|
||||
### 查找符号
|
||||
|
||||
```yaml
|
||||
# 按名称模式查找符号
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "OrderController" # 可以是部分名称
|
||||
relative_path: "src/main/java/" # 限定搜索范围
|
||||
include_body: false # 是否包含代码体
|
||||
include_info: true # 是否包含 hover 信息
|
||||
depth: 1 # 包含成员的深度
|
||||
|
||||
# 名称模式规则:
|
||||
# - "OrderController" -> 匹配任何包含此名称的符号
|
||||
# - "controller/OrderController" -> 匹配此路径后缀
|
||||
# - "/com.example.OrderController" -> 精确匹配完整路径
|
||||
# - "OrderController/getOrderList" -> 匹配类中的方法
|
||||
# - "OrderController[0]" -> 匹配重载方法的第一个
|
||||
```
|
||||
|
||||
### 获取符号详情(含代码体)
|
||||
|
||||
```yaml
|
||||
# 获取完整的符号定义(含代码)
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "OrderService/saveOrder"
|
||||
relative_path: "src/main/java/com/example/service/OrderService.java"
|
||||
include_body: true
|
||||
depth: 0
|
||||
|
||||
# 返回包含:
|
||||
# - 方法签名
|
||||
# - Javadoc 注释
|
||||
# - 完整方法体
|
||||
# - 行号范围
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 引用分析操作
|
||||
|
||||
### 查找符号引用
|
||||
|
||||
```yaml
|
||||
# 查找某个符号被哪些地方引用
|
||||
tool: mcp__serena__find_referencing_symbols
|
||||
params:
|
||||
name_path: "OrderService/saveOrder"
|
||||
relative_path: "src/main/java/com/example/service/OrderService.java"
|
||||
include_info: true
|
||||
|
||||
# 返回示例:
|
||||
# References (5 found):
|
||||
# - OrderController.createOrder [180:12-180:35]
|
||||
# snippet: "orderService.saveOrder(dto)"
|
||||
# - OrderController.updateOrder [210:12-210:35]
|
||||
# snippet: "orderService.saveOrder(updated)"
|
||||
# - OrderServiceTest.testSave [45:8-45:30]
|
||||
# snippet: "service.saveOrder(testDto)"
|
||||
```
|
||||
|
||||
### 模式搜索(补充 LSP)
|
||||
|
||||
```yaml
|
||||
# 当 LSP 无法找到时,使用模式搜索
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "orderService\\.save"
|
||||
paths_include_glob: "**/*.java"
|
||||
restrict_search_to_code_files: true
|
||||
context_lines_before: 2
|
||||
context_lines_after: 2
|
||||
|
||||
# 适用场景:
|
||||
# - 动态调用 (反射)
|
||||
# - 字符串拼接的方法名
|
||||
# - 注解中的引用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调用链构建
|
||||
|
||||
### 构建向下调用链 (callee)
|
||||
|
||||
```python
|
||||
# 伪代码: 递归构建调用链
|
||||
|
||||
def build_callee_chain(symbol_path, file_path, depth, max_depth):
|
||||
if depth > max_depth:
|
||||
return None
|
||||
|
||||
# Step 1: 获取方法体
|
||||
symbol = find_symbol(
|
||||
name_path_pattern=symbol_path,
|
||||
relative_path=file_path,
|
||||
include_body=True
|
||||
)
|
||||
|
||||
# Step 2: 在方法体中查找调用
|
||||
# 使用 LSP 或正则匹配
|
||||
calls = extract_method_calls(symbol.body)
|
||||
|
||||
# Step 3: 对每个调用递归
|
||||
callees = []
|
||||
for call in calls:
|
||||
# 尝试定位被调用方法
|
||||
target = find_symbol(
|
||||
name_path_pattern=call.method_name,
|
||||
relative_path=call.potential_file
|
||||
)
|
||||
if target:
|
||||
callees.append({
|
||||
'symbol': target,
|
||||
'evidence': call.location,
|
||||
'children': build_callee_chain(
|
||||
target.path, target.file, depth + 1, max_depth
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
'symbol': symbol,
|
||||
'callees': callees
|
||||
}
|
||||
```
|
||||
|
||||
### 实际操作步骤
|
||||
|
||||
```yaml
|
||||
# 1. 获取入口方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "OrderController/createOrder"
|
||||
relative_path: "src/main/java/com/example/controller/"
|
||||
include_body: true
|
||||
depth: 0
|
||||
|
||||
# 2. 分析方法体中的调用
|
||||
# 从返回的 body 中提取: orderService.saveOrder(dto)
|
||||
|
||||
# 3. 定位被调用方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "OrderService/saveOrder"
|
||||
relative_path: "src/main/java/"
|
||||
include_body: true
|
||||
|
||||
# 4. 查找该方法的引用(验证调用关系)
|
||||
tool: mcp__serena__find_referencing_symbols
|
||||
params:
|
||||
name_path: "OrderService/saveOrder"
|
||||
relative_path: "src/main/java/com/example/service/OrderService.java"
|
||||
|
||||
# 5. 递归处理下一层
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Java 特有处理
|
||||
|
||||
### 注解识别
|
||||
|
||||
```yaml
|
||||
# 常见注解及其语义含义
|
||||
|
||||
API 入口点注解:
|
||||
- "@RestController": REST API 控制器
|
||||
- "@Controller": MVC 控制器
|
||||
- "@RequestMapping": 请求映射
|
||||
- "@GetMapping": GET 请求
|
||||
- "@PostMapping": POST 请求
|
||||
- "@PutMapping": PUT 请求
|
||||
- "@DeleteMapping": DELETE 请求
|
||||
|
||||
服务层注解:
|
||||
- "@Service": 业务服务
|
||||
- "@Component": 通用组件
|
||||
- "@Transactional": 事务方法
|
||||
|
||||
数据层注解:
|
||||
- "@Repository": 数据访问
|
||||
- "@Mapper": MyBatis Mapper
|
||||
- "@Table": JPA 表映射
|
||||
- "@Entity": JPA 实体
|
||||
|
||||
数据对象注解:
|
||||
- "@Data": Lombok 数据类
|
||||
- "@Getter/@Setter": Lombok 访问器
|
||||
- "@Builder": Lombok 构建器
|
||||
```
|
||||
|
||||
### MyBatis Mapper 处理
|
||||
|
||||
```yaml
|
||||
# MyBatis Mapper 接口无法通过 LSP 追踪到 SQL
|
||||
# 需要关联 XML 文件
|
||||
|
||||
# 1. 找到 Mapper 接口
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "OrderMapper"
|
||||
relative_path: "src/main/java/"
|
||||
|
||||
# 2. 查找对应的 XML
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "OrderMapper"
|
||||
paths_include_glob: "**/*.xml"
|
||||
|
||||
# 3. 读取 XML 获取 SQL 定义
|
||||
tool: mcp__serena__list_dir
|
||||
params:
|
||||
relative_path: "src/main/resources/mapper/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LSP SymbolKind 映射
|
||||
|
||||
```yaml
|
||||
# jdtls 返回的 SymbolKind 数值对照
|
||||
|
||||
1: File
|
||||
2: Module
|
||||
3: Namespace
|
||||
4: Package
|
||||
5: Class # 类
|
||||
6: Method # 方法
|
||||
7: Property
|
||||
8: Field # 字段
|
||||
9: Constructor # 构造函数
|
||||
10: Enum # 枚举
|
||||
11: Interface # 接口
|
||||
12: Function # 函数
|
||||
13: Variable # 变量
|
||||
14: Constant # 常量
|
||||
15: String
|
||||
16: Number
|
||||
17: Boolean
|
||||
18: Array
|
||||
19: Object
|
||||
20: Key
|
||||
21: Null
|
||||
22: EnumMember # 枚举值
|
||||
23: Struct
|
||||
24: Event
|
||||
25: Operator
|
||||
26: TypeParameter # 泛型参数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: jdtls 启动慢
|
||||
|
||||
```
|
||||
A: 首次打开项目时,jdtls 需要构建索引。
|
||||
- Maven 项目: 会下载依赖
|
||||
- 大项目: 索引可能需要几分钟
|
||||
建议: 等待 Serena 报告项目就绪
|
||||
```
|
||||
|
||||
### Q: 找不到符号
|
||||
|
||||
```
|
||||
A: 可能原因:
|
||||
1. 项目未正确识别 (缺少 pom.xml 或 build.gradle)
|
||||
2. 编译错误导致索引不完整
|
||||
3. 符号在排除目录中
|
||||
|
||||
解决:
|
||||
1. 确保项目根目录正确
|
||||
2. 先执行 mvn compile 或 gradle build
|
||||
3. 使用 search_for_pattern 作为备选
|
||||
```
|
||||
|
||||
### Q: 引用结果不完整
|
||||
|
||||
```
|
||||
A: jdtls 的 references 可能遗漏:
|
||||
1. 反射调用
|
||||
2. 字符串拼接的方法名
|
||||
3. 动态代理
|
||||
|
||||
解决:
|
||||
使用 search_for_pattern 补充搜索
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **先概览后详细** - 用 `get_symbols_overview` 了解文件结构,再用 `find_symbol` 获取详情
|
||||
2. **限定搜索范围** - 总是传入 `relative_path` 以提高效率
|
||||
3. **分批处理** - 大项目分模块处理,避免一次性加载全部
|
||||
4. **缓存结果** - 符号信息变化不频繁,可以缓存复用
|
||||
5. **结合搜索** - LSP 不足时用 `search_for_pattern` 补充
|
||||
@@ -0,0 +1,548 @@
|
||||
# kotlin-language-server 使用指南
|
||||
|
||||
> 通过 Serena MCP 工具调用 kotlin-language-server 进行 Kotlin/Android 代码分析
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 1. 确保 kotlin-language-server 已安装
|
||||
|
||||
kotlin-language-server 可通过以下方式安装:
|
||||
|
||||
```bash
|
||||
# 通过 Homebrew (macOS)
|
||||
brew install kotlin-language-server
|
||||
|
||||
# 或通过 VS Code Kotlin 扩展
|
||||
# 扩展会自动安装 language server
|
||||
```
|
||||
|
||||
### 2. 项目结构要求
|
||||
|
||||
kotlin-language-server 需要以下文件来识别 Android/Kotlin 项目:
|
||||
|
||||
- Gradle: `build.gradle` 或 `build.gradle.kts`
|
||||
- Settings: `settings.gradle` 或 `settings.gradle.kts`
|
||||
- Android: `app/build.gradle.kts` (通常包含 android {} 配置)
|
||||
|
||||
---
|
||||
|
||||
## 通过 Serena 使用 kotlin-language-server
|
||||
|
||||
### 激活项目
|
||||
|
||||
```yaml
|
||||
# Step 1: 激活 Kotlin/Android 项目
|
||||
tool: mcp__serena__activate_project
|
||||
params:
|
||||
project: "/path/to/android/project"
|
||||
|
||||
# 返回: 项目已激活,kotlin-language-server 已初始化
|
||||
```
|
||||
|
||||
### 验证配置
|
||||
|
||||
```yaml
|
||||
# 检查当前配置
|
||||
tool: mcp__serena__get_current_config
|
||||
|
||||
# 确认输出包含:
|
||||
# - active_project: /path/to/android/project
|
||||
# - language_server: kotlin-language-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 符号提取操作
|
||||
|
||||
### 获取文件符号概览
|
||||
|
||||
```yaml
|
||||
# 获取单个文件的符号列表(不含代码体)
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "app/src/main/java/com/example/ui/home/HomeVm.kt"
|
||||
depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员
|
||||
|
||||
# 返回示例:
|
||||
# Classes:
|
||||
# - HomeVm (class) [28-307]
|
||||
# Properties:
|
||||
# - repository (property) [29-29]
|
||||
# - listeningState (property) [34-34]
|
||||
# - homePolymerization (property) [39-39]
|
||||
# Methods:
|
||||
# - getListeningState (method) [59-74]
|
||||
# - changeListeningState (method) [76-102]
|
||||
# - getHomeInfoData (method) [116-142]
|
||||
```
|
||||
|
||||
### 查找符号
|
||||
|
||||
```yaml
|
||||
# 按名称模式查找符号
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeVm"
|
||||
relative_path: "app/src/main/java/"
|
||||
include_body: false
|
||||
include_info: true
|
||||
depth: 1
|
||||
|
||||
# 名称模式规则 (与 Java 相同):
|
||||
# - "HomeVm" -> 匹配任何包含此名称的符号
|
||||
# - "home/HomeVm" -> 匹配此路径后缀
|
||||
# - "/com.example.HomeVm" -> 精确匹配完整路径
|
||||
# - "HomeVm/getListeningState" -> 匹配类中的方法
|
||||
```
|
||||
|
||||
### 获取符号详情(含代码体)
|
||||
|
||||
```yaml
|
||||
# 获取完整的符号定义(含代码)
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeRepository/getHomeInfoData"
|
||||
relative_path: "app/src/main/java/com/example/ui/home/HomeRepository.kt"
|
||||
include_body: true
|
||||
depth: 0
|
||||
|
||||
# 返回包含:
|
||||
# - 方法签名
|
||||
# - KDoc 注释
|
||||
# - 完整方法体
|
||||
# - 行号范围
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 引用分析操作
|
||||
|
||||
### 查找符号引用
|
||||
|
||||
```yaml
|
||||
# 查找某个符号被哪些地方引用
|
||||
tool: mcp__serena__find_referencing_symbols
|
||||
params:
|
||||
name_path: "HomeRepository/getHomeInfoData"
|
||||
relative_path: "app/src/main/java/com/example/ui/home/HomeRepository.kt"
|
||||
include_info: true
|
||||
|
||||
# 返回示例:
|
||||
# References (2 found):
|
||||
# - HomeVm.getHomeInfoData [117:12-117:42]
|
||||
# snippet: "repository.getHomeInfoData()"
|
||||
```
|
||||
|
||||
### 模式搜索(补充 LSP)
|
||||
|
||||
```yaml
|
||||
# 当 LSP 无法找到时,使用模式搜索
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "repository\\.get"
|
||||
paths_include_glob: "**/*.kt"
|
||||
restrict_search_to_code_files: true
|
||||
context_lines_before: 2
|
||||
context_lines_after: 2
|
||||
|
||||
# 适用场景:
|
||||
# - 协程调用 (withContext, launch)
|
||||
# - 扩展函数调用
|
||||
# - 动态代理
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Kotlin 特有处理
|
||||
|
||||
### Kotlin 特有关键字与结构
|
||||
|
||||
```yaml
|
||||
# Kotlin 特有符号类型
|
||||
data class:
|
||||
pattern: "data class \\w+"
|
||||
description: "Kotlin 数据类,自动生成 equals/hashCode/copy"
|
||||
|
||||
sealed class:
|
||||
pattern: "sealed class \\w+"
|
||||
description: "密封类,限制继承的类型"
|
||||
|
||||
object:
|
||||
pattern: "object \\w+"
|
||||
description: "单例对象声明"
|
||||
|
||||
companion object:
|
||||
pattern: "companion object"
|
||||
description: "伴生对象,类似静态成员"
|
||||
|
||||
suspend fun:
|
||||
pattern: "suspend fun \\w+"
|
||||
description: "协程挂起函数"
|
||||
|
||||
extension function:
|
||||
pattern: "fun \\w+\\.\\w+"
|
||||
description: "扩展函数"
|
||||
```
|
||||
|
||||
### Android MVVM 架构层识别
|
||||
|
||||
```yaml
|
||||
# 根据命名约定和基类识别架构层
|
||||
|
||||
ViewModel 层:
|
||||
naming: "*Vm.kt", "*ViewModel.kt"
|
||||
base_classes:
|
||||
- "ViewModel"
|
||||
- "AndroidViewModel"
|
||||
- "BaseViewModel"
|
||||
annotations:
|
||||
- "@HiltViewModel"
|
||||
key_elements:
|
||||
- "MutableLiveData"
|
||||
- "MutableStateFlow"
|
||||
- "viewModelScope"
|
||||
|
||||
Repository 层:
|
||||
naming: "*Repository.kt"
|
||||
base_classes:
|
||||
- "BaseRepository"
|
||||
key_elements:
|
||||
- "suspend fun"
|
||||
- "Flow<>"
|
||||
- "RetrofitHelper"
|
||||
|
||||
Activity 层:
|
||||
naming: "*Activity.kt"
|
||||
base_classes:
|
||||
- "AppCompatActivity"
|
||||
- "ComponentActivity"
|
||||
- "BaseActivity"
|
||||
key_elements:
|
||||
- "setContentView"
|
||||
- "ViewBinding"
|
||||
|
||||
Fragment 层:
|
||||
naming: "*Fragment.kt"
|
||||
base_classes:
|
||||
- "Fragment"
|
||||
- "DialogFragment"
|
||||
- "BaseFragment"
|
||||
key_elements:
|
||||
- "onCreateView"
|
||||
- "ViewBinding"
|
||||
|
||||
Compose UI:
|
||||
naming: "*Page.kt", "*Compose.kt", "*Screen.kt"
|
||||
annotations:
|
||||
- "@Composable"
|
||||
key_elements:
|
||||
- "remember"
|
||||
- "LaunchedEffect"
|
||||
- "collectAsState"
|
||||
|
||||
Adapter 层:
|
||||
naming: "*Adapter.kt"
|
||||
base_classes:
|
||||
- "RecyclerView.Adapter"
|
||||
- "ListAdapter"
|
||||
- "BaseAdapter"
|
||||
key_elements:
|
||||
- "onCreateViewHolder"
|
||||
- "onBindViewHolder"
|
||||
```
|
||||
|
||||
### Retrofit API 识别
|
||||
|
||||
```yaml
|
||||
# Retrofit 注解识别
|
||||
|
||||
HTTP 方法注解:
|
||||
- "@GET": GET 请求
|
||||
- "@POST": POST 请求
|
||||
- "@PUT": PUT 请求
|
||||
- "@DELETE": DELETE 请求
|
||||
- "@PATCH": PATCH 请求
|
||||
- "@HEAD": HEAD 请求
|
||||
- "@OPTIONS": OPTIONS 请求
|
||||
|
||||
参数注解:
|
||||
- "@Path": 路径参数
|
||||
- "@Query": 查询参数
|
||||
- "@QueryMap": 查询参数 Map
|
||||
- "@Body": 请求体
|
||||
- "@Field": 表单字段
|
||||
- "@FieldMap": 表单字段 Map
|
||||
- "@Part": Multipart 部分
|
||||
- "@Header": 请求头
|
||||
- "@HeaderMap": 请求头 Map
|
||||
- "@Url": 动态 URL
|
||||
|
||||
# 提取示例
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "@(GET|POST|PUT|DELETE|PATCH)\\s*\\([^)]*\\)"
|
||||
paths_include_glob: "**/*Service.kt"
|
||||
|
||||
# 解析端点
|
||||
# @GET("/client-driver/v2/order/getOrderDetail")
|
||||
# fun getOrderDetail(@Query("orderId") orderId: Long?): Observable<BaseResponse<OrderDetailBean>>
|
||||
#
|
||||
# 提取:
|
||||
# method: GET
|
||||
# path: /client-driver/v2/order/getOrderDetail
|
||||
# params: [{name: orderId, type: Long?, annotation: @Query}]
|
||||
# return_type: Observable<BaseResponse<OrderDetailBean>>
|
||||
```
|
||||
|
||||
### Jetpack Compose 识别
|
||||
|
||||
```yaml
|
||||
# Compose 注解和模式
|
||||
|
||||
@Composable:
|
||||
description: "可组合函数,Compose UI 构建块"
|
||||
pattern: "@Composable\\s+(fun|private fun|internal fun)"
|
||||
|
||||
@Preview:
|
||||
description: "预览注解,用于 Android Studio 预览"
|
||||
|
||||
State 管理:
|
||||
patterns:
|
||||
- "remember\\s*\\{"
|
||||
- "mutableStateOf"
|
||||
- "collectAsState"
|
||||
- "LaunchedEffect"
|
||||
- "SideEffect"
|
||||
- "DisposableEffect"
|
||||
|
||||
# 提取 Composable 函数
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "@Composable\\s+fun\\s+\\w+"
|
||||
paths_include_glob: "**/*.kt"
|
||||
```
|
||||
|
||||
### RxJava/Coroutines 模式
|
||||
|
||||
```yaml
|
||||
# RxJava 模式(该项目使用)
|
||||
rx_patterns:
|
||||
- "Observable<"
|
||||
- "subscribeOn"
|
||||
- "observeOn"
|
||||
- "subscribe"
|
||||
- "Schedulers.io()"
|
||||
- "AndroidSchedulers.mainThread()"
|
||||
|
||||
# Coroutines 模式
|
||||
coroutine_patterns:
|
||||
- "suspend fun"
|
||||
- "viewModelScope.launch"
|
||||
- "lifecycleScope.launch"
|
||||
- "withContext"
|
||||
- "async"
|
||||
- "await"
|
||||
- "Flow<"
|
||||
- "StateFlow<"
|
||||
- "SharedFlow<"
|
||||
- "collect"
|
||||
- "collectLatest"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LSP SymbolKind 映射
|
||||
|
||||
```yaml
|
||||
# kotlin-language-server 返回的 SymbolKind 数值对照
|
||||
|
||||
1: File
|
||||
2: Module
|
||||
3: Namespace
|
||||
4: Package
|
||||
5: Class # 类、object
|
||||
6: Method # 方法
|
||||
7: Property # 属性
|
||||
8: Field # 字段
|
||||
9: Constructor # 构造函数
|
||||
10: Enum # 枚举
|
||||
11: Interface # 接口
|
||||
12: Function # 顶层函数
|
||||
13: Variable # 变量
|
||||
14: Constant # 常量 (val)
|
||||
15: String
|
||||
16: Number
|
||||
17: Boolean
|
||||
18: Array
|
||||
19: Object # object 声明
|
||||
20: Key
|
||||
21: Null
|
||||
22: EnumMember # 枚举值
|
||||
23: Struct
|
||||
24: Event
|
||||
25: Operator
|
||||
26: TypeParameter # 泛型参数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调用链构建
|
||||
|
||||
### ViewModel -> Repository 调用链
|
||||
|
||||
```python
|
||||
# 伪代码: 构建 MVVM 调用链
|
||||
|
||||
def build_mvvm_chain(viewmodel_path):
|
||||
# Step 1: 获取 ViewModel 符号
|
||||
vm_symbols = get_symbols_overview(viewmodel_path, depth=2)
|
||||
|
||||
# Step 2: 识别 Repository 依赖
|
||||
# 查找类似: private val repository = HomeRepository()
|
||||
repo_deps = extract_repository_deps(vm_symbols)
|
||||
|
||||
# Step 3: 追踪 Repository 方法调用
|
||||
for method in vm_symbols.methods:
|
||||
# 获取方法体
|
||||
method_body = find_symbol(method.name, include_body=True)
|
||||
|
||||
# 查找 repository.xxx() 调用
|
||||
repo_calls = extract_repo_calls(method_body)
|
||||
|
||||
for call in repo_calls:
|
||||
# 跟踪到 Repository 方法
|
||||
repo_method = find_symbol(f"{repo_deps}/{call.method_name}")
|
||||
|
||||
# Repository 通常调用 RetrofitHelper
|
||||
api_calls = extract_api_calls(repo_method.body)
|
||||
|
||||
return chain
|
||||
```
|
||||
|
||||
### Repository -> API Service 调用链
|
||||
|
||||
```yaml
|
||||
# 实际操作步骤
|
||||
|
||||
# 1. 获取 Repository 方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeRepository/getHomeInfoData"
|
||||
relative_path: "app/src/main/java/"
|
||||
include_body: true
|
||||
|
||||
# 2. 分析方法体中的 API 调用
|
||||
# 从返回的 body 中提取: RetrofitHelper.getDefaultService().getHomeInfoData()
|
||||
|
||||
# 3. 定位 API 接口定义
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "fun getHomeInfoData"
|
||||
paths_include_glob: "**/*Service.kt"
|
||||
|
||||
# 4. 提取端点信息
|
||||
# @GET("/client-driver/v3/info/getHomeInfoData")
|
||||
# fun getHomeInfoData(): Observable<BaseResponse<HomePolymerizationBean>>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: kotlin-language-server 启动慢
|
||||
|
||||
```
|
||||
A: 首次打开项目时,需要构建 Gradle 项目并索引。
|
||||
- 大型 Android 项目可能需要几分钟
|
||||
- 确保 Gradle Daemon 正在运行
|
||||
建议: 先执行 ./gradlew build 预热项目
|
||||
```
|
||||
|
||||
### Q: 找不到 Kotlin 符号
|
||||
|
||||
```
|
||||
A: 可能原因:
|
||||
1. Gradle 配置未正确解析
|
||||
2. 使用了 Kotlin DSL 但 settings.gradle.kts 缺失
|
||||
3. 符号在 generated 目录中
|
||||
4. 项目使用 Kotlin Multiplatform
|
||||
|
||||
解决:
|
||||
1. 确保项目可以正常 Gradle 编译
|
||||
2. 使用 search_for_pattern 作为备选
|
||||
3. 检查 exclude_patterns 配置
|
||||
```
|
||||
|
||||
### Q: 协程/Flow 调用追踪不完整
|
||||
|
||||
```
|
||||
A: 协程的异步特性使得静态分析困难:
|
||||
1. viewModelScope.launch {} 内部调用难以追踪
|
||||
2. Flow 的 collect 在不同协程作用域
|
||||
3. 挂起函数的调用栈可能中断
|
||||
|
||||
解决:
|
||||
使用 search_for_pattern 搜索特定调用模式
|
||||
结合 @Composable 中的 LaunchedEffect 分析
|
||||
```
|
||||
|
||||
### Q: Compose 函数调用关系
|
||||
|
||||
```
|
||||
A: Compose 函数组合特殊:
|
||||
1. @Composable 函数只能被其他 @Composable 调用
|
||||
2. 状态提升模式使数据流向不明显
|
||||
3. remember/LaunchedEffect 的依赖追踪
|
||||
|
||||
解决:
|
||||
1. 先识别所有 @Composable 函数
|
||||
2. 分析函数参数中的回调 lambda
|
||||
3. 追踪 ViewModel 的 StateFlow/LiveData
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **按架构层分析** - 先识别 MVVM 各层文件,再逐层深入
|
||||
2. **Repository 是关键** - Repository 层连接 ViewModel 和 API,是分析重点
|
||||
3. **注解驱动识别** - 利用 @Composable, @GET/@POST 等注解快速分类
|
||||
4. **命名约定优先** - Kotlin/Android 项目通常遵循严格命名约定 (*Vm, *Repository, *Activity)
|
||||
5. **结合 Gradle 分析** - 通过 build.gradle.kts 了解依赖和模块结构
|
||||
6. **注意扩展函数** - Kotlin 扩展函数可能分散在不同文件中
|
||||
|
||||
---
|
||||
|
||||
## 项目特定模式 (chefu_driver_app_android)
|
||||
|
||||
该项目使用的技术栈和模式:
|
||||
|
||||
```yaml
|
||||
架构模式: MVVM
|
||||
ViewModel: *Vm.kt (如 HomeVm, LoginViewMode)
|
||||
Repository: *Repository.kt (如 HomeRepository)
|
||||
Activity: *Activity.kt (如 HomeActivity)
|
||||
Fragment: *Fragment.kt (如 RankDetailFragment)
|
||||
|
||||
网络层: Retrofit + RxJava3
|
||||
ApiService: com.dezhong.driverandroid.net.ApiService
|
||||
Helper: RetrofitHelper.getDefaultService()
|
||||
响应类型: Observable<BaseResponse<T>>
|
||||
|
||||
UI 层:
|
||||
传统: XML + ViewBinding
|
||||
新版: Jetpack Compose (myCompose/ 目录)
|
||||
|
||||
状态管理:
|
||||
ViewModel: MutableLiveData<T>
|
||||
Compose: mutableStateOf, remember
|
||||
|
||||
目录结构:
|
||||
app/src/main/java/com/dezhong/driverandroid/
|
||||
ui/ # 传统 UI (Activity + Fragment + ViewModel)
|
||||
myCompose/ # Compose UI
|
||||
net/ # 网络层
|
||||
base/ # 基类
|
||||
service/ # 后台服务
|
||||
common/ # 通用类
|
||||
```
|
||||
@@ -0,0 +1,880 @@
|
||||
# sourcekit-lsp 使用指南
|
||||
|
||||
> 通过 Serena MCP 工具调用 sourcekit-lsp 进行 Swift/iOS 代码分析
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 1. 确保 sourcekit-lsp 已安装
|
||||
|
||||
sourcekit-lsp 随 Xcode 一起安装,位于 Xcode 工具链中:
|
||||
|
||||
```bash
|
||||
# 验证 sourcekit-lsp 是否可用
|
||||
xcrun sourcekit-lsp --version
|
||||
|
||||
# 或者直接定位
|
||||
xcrun --find sourcekit-lsp
|
||||
|
||||
# 输出示例:
|
||||
# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp
|
||||
```
|
||||
|
||||
### 2. 项目结构要求
|
||||
|
||||
sourcekit-lsp 需要以下文件来识别 iOS/Swift 项目:
|
||||
|
||||
- Xcode 项目: `*.xcodeproj` 或 `*.xcworkspace`
|
||||
- Swift Package: `Package.swift`
|
||||
- CocoaPods: `Podfile` + `*.xcworkspace`
|
||||
- Carthage: `Cartfile`
|
||||
|
||||
**注意**: 对于使用 CocoaPods 的项目,必须先执行 `pod install` 生成 workspace。
|
||||
|
||||
---
|
||||
|
||||
## 通过 Serena 使用 sourcekit-lsp
|
||||
|
||||
### 激活项目
|
||||
|
||||
```yaml
|
||||
# Step 1: 激活 Swift/iOS 项目
|
||||
tool: mcp__serena__activate_project
|
||||
params:
|
||||
project: "/path/to/ios/project"
|
||||
|
||||
# 返回: 项目已激活,sourcekit-lsp 已初始化
|
||||
```
|
||||
|
||||
### 验证配置
|
||||
|
||||
```yaml
|
||||
# 检查当前配置
|
||||
tool: mcp__serena__get_current_config
|
||||
|
||||
# 确认输出包含:
|
||||
# - active_project: /path/to/ios/project
|
||||
# - language_server: sourcekit-lsp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 符号提取操作
|
||||
|
||||
### 获取文件符号概览
|
||||
|
||||
```yaml
|
||||
# 获取单个文件的符号列表(不含代码体)
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "MyApp/ViewModels/HomeViewModel.swift"
|
||||
depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员
|
||||
|
||||
# 返回示例:
|
||||
# Classes:
|
||||
# - HomeViewModel (class) [12-187]
|
||||
# Structs:
|
||||
# - Input (struct) [15-25]
|
||||
# - Output (struct) [27-40]
|
||||
# Properties:
|
||||
# - disposeBag (property) [14-14]
|
||||
# - userService (property) [13-13]
|
||||
# Methods:
|
||||
# - transform(input:) (method) [42-120]
|
||||
# - fetchUserData() (method) [122-150]
|
||||
```
|
||||
|
||||
### 查找符号
|
||||
|
||||
```yaml
|
||||
# 按名称模式查找符号
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeViewModel"
|
||||
relative_path: "MyApp/ViewModels/"
|
||||
include_body: false
|
||||
include_info: true
|
||||
depth: 1
|
||||
|
||||
# 名称模式规则:
|
||||
# - "HomeViewModel" -> 匹配任何包含此名称的符号
|
||||
# - "ViewModels/HomeViewModel" -> 匹配此路径后缀
|
||||
# - "/MyApp.HomeViewModel" -> 精确匹配完整路径
|
||||
# - "HomeViewModel/transform" -> 匹配类中的方法
|
||||
```
|
||||
|
||||
### 获取符号详情(含代码体)
|
||||
|
||||
```yaml
|
||||
# 获取完整的符号定义(含代码)
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeViewModel/fetchUserData"
|
||||
relative_path: "MyApp/ViewModels/HomeViewModel.swift"
|
||||
include_body: true
|
||||
depth: 0
|
||||
|
||||
# 返回包含:
|
||||
# - 方法签名
|
||||
# - 文档注释
|
||||
# - 完整方法体
|
||||
# - 行号范围
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 引用分析操作
|
||||
|
||||
### 查找符号引用
|
||||
|
||||
```yaml
|
||||
# 查找某个符号被哪些地方引用
|
||||
tool: mcp__serena__find_referencing_symbols
|
||||
params:
|
||||
name_path: "UserService/fetchUser"
|
||||
relative_path: "MyApp/Services/UserService.swift"
|
||||
include_info: true
|
||||
|
||||
# 返回示例:
|
||||
# References (3 found):
|
||||
# - HomeViewModel.fetchUserData [45:12-45:35]
|
||||
# snippet: "userService.fetchUser()"
|
||||
# - ProfileViewModel.loadProfile [67:8-67:31]
|
||||
# snippet: "userService.fetchUser()"
|
||||
```
|
||||
|
||||
### 模式搜索(补充 LSP)
|
||||
|
||||
```yaml
|
||||
# 当 LSP 无法找到时,使用模式搜索
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "\.subscribe\(onNext:"
|
||||
paths_include_glob: "**/*.swift"
|
||||
restrict_search_to_code_files: true
|
||||
context_lines_before: 2
|
||||
context_lines_after: 2
|
||||
|
||||
# 适用场景:
|
||||
# - RxSwift 订阅链
|
||||
# - Protocol extension 方法
|
||||
# - 动态类型调用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Swift 特有处理
|
||||
|
||||
### Swift 特有关键字与结构
|
||||
|
||||
```yaml
|
||||
# Swift 特有符号类型
|
||||
struct:
|
||||
pattern: "struct \\w+"
|
||||
description: "Swift 结构体,值类型"
|
||||
|
||||
class:
|
||||
pattern: "class \\w+"
|
||||
description: "Swift 类,引用类型"
|
||||
|
||||
enum:
|
||||
pattern: "enum \\w+"
|
||||
description: "Swift 枚举,支持关联值"
|
||||
|
||||
protocol:
|
||||
pattern: "protocol \\w+"
|
||||
description: "Swift 协议,类似接口"
|
||||
|
||||
extension:
|
||||
pattern: "extension \\w+"
|
||||
description: "Swift 扩展,为类型添加功能"
|
||||
|
||||
typealias:
|
||||
pattern: "typealias \\w+"
|
||||
description: "类型别名"
|
||||
|
||||
@propertyWrapper:
|
||||
pattern: "@\\w+\\s+(var|let)"
|
||||
description: "属性包装器"
|
||||
|
||||
computed_property:
|
||||
pattern: "var \\w+: \\w+ \\{"
|
||||
description: "计算属性"
|
||||
|
||||
lazy_property:
|
||||
pattern: "lazy var \\w+"
|
||||
description: "延迟初始化属性"
|
||||
```
|
||||
|
||||
### iOS MVVM 架构层识别
|
||||
|
||||
```yaml
|
||||
# 根据命名约定和基类识别架构层
|
||||
|
||||
ViewController 层:
|
||||
naming: "*ViewController.swift", "*VC.swift"
|
||||
base_classes:
|
||||
- "UIViewController"
|
||||
- "BaseViewController"
|
||||
- "UITableViewController"
|
||||
- "UICollectionViewController"
|
||||
key_elements:
|
||||
- "viewDidLoad()"
|
||||
- "viewWillAppear(_:)"
|
||||
- "IBOutlet"
|
||||
- "IBAction"
|
||||
|
||||
ViewModel 层:
|
||||
naming: "*ViewModel.swift", "*VM.swift"
|
||||
protocols:
|
||||
- "ViewModelProtocol"
|
||||
- "ViewModelType"
|
||||
key_elements:
|
||||
- "struct Input"
|
||||
- "struct Output"
|
||||
- "func transform(input:)"
|
||||
- "DisposeBag"
|
||||
|
||||
Service 层:
|
||||
naming: "*Service.swift", "*Manager.swift"
|
||||
patterns:
|
||||
- "static let shared"
|
||||
- "func fetch"
|
||||
- "func request"
|
||||
key_elements:
|
||||
- "Observable<"
|
||||
- "Single<"
|
||||
- "Completable"
|
||||
|
||||
Model 层:
|
||||
naming: "*Model.swift", "*Entity.swift", "*Response.swift"
|
||||
markers:
|
||||
- ": Codable"
|
||||
- ": Decodable"
|
||||
- ": Encodable"
|
||||
key_elements:
|
||||
- "enum CodingKeys"
|
||||
- "init(from decoder:)"
|
||||
|
||||
Network 层:
|
||||
naming: "*API.swift", "*Router.swift", "*Target.swift"
|
||||
protocols:
|
||||
- "TargetType"
|
||||
- "URLRequestConvertible"
|
||||
key_elements:
|
||||
- "var baseURL: URL"
|
||||
- "var path: String"
|
||||
- "var method: Moya.Method"
|
||||
|
||||
Coordinator 层:
|
||||
naming: "*Coordinator.swift", "*Navigator.swift"
|
||||
protocols:
|
||||
- "Coordinator"
|
||||
- "CoordinatorType"
|
||||
key_elements:
|
||||
- "var childCoordinators"
|
||||
- "func start()"
|
||||
- "weak var parentCoordinator"
|
||||
|
||||
Extension 层:
|
||||
naming: "*+*.swift"
|
||||
description: "Swift extension 文件 (e.g., String+Extensions.swift)"
|
||||
patterns:
|
||||
- "extension \\w+ \\{"
|
||||
- "extension \\w+: \\w+ \\{"
|
||||
```
|
||||
|
||||
### Moya API 识别
|
||||
|
||||
```yaml
|
||||
# Moya TargetType 枚举识别
|
||||
|
||||
TargetType 协议:
|
||||
description: "Moya 网络请求定义协议"
|
||||
required_properties:
|
||||
- "baseURL: URL"
|
||||
- "path: String"
|
||||
- "method: Moya.Method"
|
||||
- "task: Task"
|
||||
- "headers: [String: String]?"
|
||||
|
||||
# 提取示例
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "case\\s+\\w+.*\\n.*var path"
|
||||
paths_include_glob: "**/*API.swift"
|
||||
multiline: true
|
||||
|
||||
# 解析 Moya Target
|
||||
# enum UserAPI: TargetType {
|
||||
# case login(phone: String, code: String)
|
||||
# case fetchProfile(userId: Int)
|
||||
#
|
||||
# var path: String {
|
||||
# switch self {
|
||||
# case .login:
|
||||
# return "/api/v1/user/login"
|
||||
# case .fetchProfile(let userId):
|
||||
# return "/api/v1/user/\(userId)"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# 提取:
|
||||
# - case: login
|
||||
# path: /api/v1/user/login
|
||||
# method: POST (从 method 属性推断)
|
||||
# params: [phone: String, code: String]
|
||||
#
|
||||
# - case: fetchProfile
|
||||
# path: /api/v1/user/{userId}
|
||||
# method: GET
|
||||
# params: [userId: Int]
|
||||
```
|
||||
|
||||
### Alamofire 请求识别
|
||||
|
||||
```yaml
|
||||
# Alamofire 请求模式
|
||||
|
||||
AF.request:
|
||||
description: "Alamofire 5.x 请求"
|
||||
pattern: "AF\\.request\\("
|
||||
example: |
|
||||
AF.request("https://api.example.com/users",
|
||||
method: .get,
|
||||
parameters: params,
|
||||
encoding: URLEncoding.default)
|
||||
.responseDecodable(of: UserResponse.self) { response in
|
||||
// handle response
|
||||
}
|
||||
|
||||
session.request:
|
||||
description: "Session 实例请求"
|
||||
pattern: "session\\.request\\("
|
||||
|
||||
URLRequestConvertible:
|
||||
description: "自定义请求构建器"
|
||||
protocol: "URLRequestConvertible"
|
||||
method: "asURLRequest() throws -> URLRequest"
|
||||
```
|
||||
|
||||
### RxSwift/RxCocoa 模式
|
||||
|
||||
```yaml
|
||||
# RxSwift 核心类型
|
||||
rx_types:
|
||||
Observable:
|
||||
description: "可观察序列,核心类型"
|
||||
operators: ["map", "flatMap", "filter", "subscribe"]
|
||||
|
||||
Single:
|
||||
description: "单值序列,成功或失败"
|
||||
operators: ["subscribe", "map", "flatMap"]
|
||||
|
||||
Completable:
|
||||
description: "无值序列,仅完成或失败"
|
||||
operators: ["subscribe", "andThen"]
|
||||
|
||||
Maybe:
|
||||
description: "可选单值序列"
|
||||
operators: ["subscribe", "map"]
|
||||
|
||||
Driver:
|
||||
description: "UI 绑定专用,主线程、无错误、共享"
|
||||
from: "asDriver()"
|
||||
|
||||
Signal:
|
||||
description: "类似 Driver,但不重放"
|
||||
from: "asSignal()"
|
||||
|
||||
# RxSwift Subject 类型
|
||||
rx_subjects:
|
||||
PublishSubject:
|
||||
description: "无初始值,只发送新事件"
|
||||
usage: "事件总线"
|
||||
|
||||
BehaviorSubject:
|
||||
description: "有初始值,发送最新值"
|
||||
usage: "状态管理"
|
||||
|
||||
ReplaySubject:
|
||||
description: "缓存指定数量事件"
|
||||
usage: "历史事件回放"
|
||||
|
||||
PublishRelay:
|
||||
description: "PublishSubject 无 error/complete"
|
||||
usage: "UI 事件转发"
|
||||
|
||||
BehaviorRelay:
|
||||
description: "BehaviorSubject 无 error/complete"
|
||||
usage: "状态绑定"
|
||||
|
||||
# 常用操作符
|
||||
rx_operators:
|
||||
transformation:
|
||||
- "map"
|
||||
- "flatMap"
|
||||
- "flatMapLatest"
|
||||
- "compactMap"
|
||||
- "scan"
|
||||
|
||||
filtering:
|
||||
- "filter"
|
||||
- "distinctUntilChanged"
|
||||
- "debounce"
|
||||
- "throttle"
|
||||
- "skip"
|
||||
- "take"
|
||||
|
||||
combining:
|
||||
- "merge"
|
||||
- "combineLatest"
|
||||
- "zip"
|
||||
- "withLatestFrom"
|
||||
- "concat"
|
||||
|
||||
error_handling:
|
||||
- "catchError"
|
||||
- "catchErrorJustReturn"
|
||||
- "retry"
|
||||
- "retryWhen"
|
||||
|
||||
utility:
|
||||
- "do(onNext:)"
|
||||
- "delay"
|
||||
- "observeOn"
|
||||
- "subscribeOn"
|
||||
- "share"
|
||||
- "replay"
|
||||
|
||||
# 提取 RxSwift 模式
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "\\.(map|flatMap|filter|subscribe)\\s*\\{"
|
||||
paths_include_glob: "**/*.swift"
|
||||
```
|
||||
|
||||
### Combine 模式(Swift 原生响应式)
|
||||
|
||||
```yaml
|
||||
# Combine 核心类型
|
||||
combine_types:
|
||||
Publisher:
|
||||
description: "发布者协议"
|
||||
operators: ["map", "flatMap", "sink", "assign"]
|
||||
|
||||
AnyPublisher:
|
||||
description: "类型擦除发布者"
|
||||
usage: "API 返回类型"
|
||||
|
||||
PassthroughSubject:
|
||||
description: "类似 PublishSubject"
|
||||
usage: "事件发送"
|
||||
|
||||
CurrentValueSubject:
|
||||
description: "类似 BehaviorSubject"
|
||||
usage: "状态管理"
|
||||
|
||||
@Published:
|
||||
description: "属性包装器,自动发布变化"
|
||||
usage: "SwiftUI/Combine 状态"
|
||||
|
||||
AnyCancellable:
|
||||
description: "订阅句柄"
|
||||
usage: "生命周期管理"
|
||||
|
||||
# 识别 Combine 使用
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "@Published|PassthroughSubject|CurrentValueSubject|\\.sink\\("
|
||||
paths_include_glob: "**/*.swift"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LSP SymbolKind 映射
|
||||
|
||||
```yaml
|
||||
# sourcekit-lsp 返回的 SymbolKind 数值对照
|
||||
|
||||
1: File
|
||||
2: Module
|
||||
3: Namespace # extension
|
||||
4: Package
|
||||
5: Class # class
|
||||
6: Method # func (instance)
|
||||
7: Property # var/let (instance)
|
||||
8: Field
|
||||
9: Constructor # init
|
||||
10: Enum # enum
|
||||
11: Interface # protocol
|
||||
12: Function # func (top-level/static)
|
||||
13: Variable # var/let (local)
|
||||
14: Constant # let (constant)
|
||||
15: String
|
||||
16: Number
|
||||
17: Boolean
|
||||
18: Array
|
||||
19: Object
|
||||
20: Key
|
||||
21: Null
|
||||
22: EnumMember # enum case
|
||||
23: Struct # struct
|
||||
24: Event
|
||||
25: Operator
|
||||
26: TypeParameter # associated type / generic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调用链构建
|
||||
|
||||
### ViewController -> ViewModel 调用链
|
||||
|
||||
```python
|
||||
# 伪代码: 构建 MVVM 调用链
|
||||
|
||||
def build_mvvm_chain(viewcontroller_path):
|
||||
# Step 1: 获取 ViewController 符号
|
||||
vc_symbols = get_symbols_overview(viewcontroller_path, depth=2)
|
||||
|
||||
# Step 2: 识别 ViewModel 依赖
|
||||
# 查找类似: private let viewModel = HomeViewModel()
|
||||
# 或: private var viewModel: HomeViewModelType!
|
||||
vm_deps = extract_viewmodel_deps(vc_symbols)
|
||||
|
||||
# Step 3: 追踪 ViewModel 绑定
|
||||
for vm in vm_deps:
|
||||
# 获取 ViewModel 定义
|
||||
vm_symbols = get_symbols_overview(vm.file_path, depth=2)
|
||||
|
||||
# 查找 Input/Output 模式
|
||||
if has_input_output_pattern(vm_symbols):
|
||||
input_struct = find_symbol("Input", vm.file_path)
|
||||
output_struct = find_symbol("Output", vm.file_path)
|
||||
transform_method = find_symbol("transform", vm.file_path, include_body=True)
|
||||
|
||||
# 追踪 Service 调用
|
||||
service_calls = extract_service_calls(transform_method.body)
|
||||
|
||||
return chain
|
||||
```
|
||||
|
||||
### ViewModel -> Service -> API 调用链
|
||||
|
||||
```yaml
|
||||
# 实际操作步骤
|
||||
|
||||
# 1. 获取 ViewModel 方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "HomeViewModel/fetchUserData"
|
||||
relative_path: "MyApp/ViewModels/"
|
||||
include_body: true
|
||||
|
||||
# 2. 分析方法体中的 Service 调用
|
||||
# 从返回的 body 中提取: userService.fetchUser()
|
||||
|
||||
# 3. 定位 Service 方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "UserService/fetchUser"
|
||||
relative_path: "MyApp/Services/"
|
||||
include_body: true
|
||||
|
||||
# 4. 分析 Service 中的 API 调用
|
||||
# 从返回的 body 中提取: provider.request(.fetchProfile(userId))
|
||||
|
||||
# 5. 定位 Moya Target
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "case fetchProfile"
|
||||
paths_include_glob: "**/*API.swift"
|
||||
context_lines_after: 10
|
||||
|
||||
# 6. 提取端点信息
|
||||
# case fetchProfile(userId: Int)
|
||||
# path: "/api/v1/user/\(userId)"
|
||||
# method: .get
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 大规模项目处理
|
||||
|
||||
### 项目规模评估
|
||||
|
||||
```bash
|
||||
# 评估 Swift 项目规模
|
||||
find /path/to/project -name "*.swift" -not -path "*/Pods/*" -not -path "*/Carthage/*" | wc -l
|
||||
# 输出: 3602 (文件数)
|
||||
|
||||
find /path/to/project -name "*.swift" -not -path "*/Pods/*" -not -path "*/Carthage/*" -exec wc -l {} + | tail -1
|
||||
# 输出: 424000 (总行数)
|
||||
```
|
||||
|
||||
### 分批处理策略
|
||||
|
||||
```yaml
|
||||
# 大规模项目(424K 行)处理策略
|
||||
|
||||
batch_processing:
|
||||
description: "按模块分批处理,避免内存溢出"
|
||||
|
||||
# Step 1: 按目录分组
|
||||
grouping:
|
||||
- "AppDelegate.swift" # 入口点优先
|
||||
- "**/Coordinator/**/*.swift" # 导航层
|
||||
- "**/ViewModel/**/*.swift" # ViewModel 层
|
||||
- "**/Service/**/*.swift" # Service 层
|
||||
- "**/Network/**/*.swift" # Network 层
|
||||
- "**/Model/**/*.swift" # Model 层
|
||||
- "**/View/**/*.swift" # View 层
|
||||
- "**/Extension/**/*.swift" # Extension 层
|
||||
- "**/*.swift" # 其他
|
||||
|
||||
# Step 2: 批次配置
|
||||
batch_config:
|
||||
batch_size: 100 # 每批 100 个文件
|
||||
parallel_batches: 3 # 最多 3 个并行批次
|
||||
checkpoint_interval: 50 # 每 50 个文件保存检查点
|
||||
|
||||
# Step 3: 内存管理
|
||||
memory_management:
|
||||
release_after_batch: true # 每批处理后释放内存
|
||||
stream_output: true # 流式写入输出文件
|
||||
|
||||
# 处理流程
|
||||
procedure:
|
||||
- step: "scan_and_group"
|
||||
description: "扫描文件并按层分组"
|
||||
|
||||
- step: "process_core_first"
|
||||
description: "优先处理核心文件"
|
||||
files:
|
||||
- "AppDelegate.swift"
|
||||
- "SceneDelegate.swift"
|
||||
- "*Coordinator.swift"
|
||||
|
||||
- step: "batch_process"
|
||||
description: "分批处理各层"
|
||||
for_each_batch: "grouped_files | batch(100)"
|
||||
actions:
|
||||
- "extract_symbols"
|
||||
- "analyze_layer"
|
||||
- "save_checkpoint"
|
||||
|
||||
- step: "merge_results"
|
||||
description: "合并所有批次结果"
|
||||
```
|
||||
|
||||
### Pod 模块边界识别
|
||||
|
||||
```yaml
|
||||
# 分析 Podfile 识别模块边界
|
||||
|
||||
# Step 1: 读取 Podfile
|
||||
tool: Read
|
||||
params:
|
||||
file_path: "/path/to/project/Podfile"
|
||||
|
||||
# Step 2: 提取 Pod 依赖
|
||||
patterns:
|
||||
- "pod '([^']+)'(?:,\\s*'([^']+)')?"
|
||||
- "pod \"([^\"]+)\"(?:,\\s*\"([^\"]+)\")?"
|
||||
|
||||
# Step 3: 分类 Pod
|
||||
categories:
|
||||
networking:
|
||||
- "Alamofire"
|
||||
- "Moya"
|
||||
- "AFNetworking"
|
||||
- "Kingfisher"
|
||||
- "SDWebImage"
|
||||
|
||||
reactive:
|
||||
- "RxSwift"
|
||||
- "RxCocoa"
|
||||
- "RxRelay"
|
||||
- "RxDataSources"
|
||||
- "RxGesture"
|
||||
|
||||
ui:
|
||||
- "SnapKit"
|
||||
- "Masonry"
|
||||
- "MBProgressHUD"
|
||||
- "SVProgressHUD"
|
||||
- "MJRefresh"
|
||||
|
||||
database:
|
||||
- "Realm"
|
||||
- "FMDB"
|
||||
- "GRDB"
|
||||
- "CoreStore"
|
||||
|
||||
analytics:
|
||||
- "Firebase"
|
||||
- "Bugly"
|
||||
- "UMAnalytics"
|
||||
|
||||
testing:
|
||||
- "Quick"
|
||||
- "Nimble"
|
||||
- "RxTest"
|
||||
- "RxBlocking"
|
||||
|
||||
# Step 4: 分析模块边界
|
||||
module_boundaries:
|
||||
description: "识别 Pod 模块边界"
|
||||
analysis:
|
||||
- "哪些模块依赖 RxSwift"
|
||||
- "网络层使用哪个库"
|
||||
- "UI 组件库选型"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: sourcekit-lsp 启动慢
|
||||
|
||||
```
|
||||
A: sourcekit-lsp 首次索引项目可能较慢:
|
||||
- 大型项目(3600+ 文件)可能需要几分钟
|
||||
- 确保 Xcode 和 Command Line Tools 已安装
|
||||
建议: 先执行 xcodebuild 构建项目预热索引
|
||||
|
||||
# 预热命令
|
||||
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Debug build
|
||||
```
|
||||
|
||||
### Q: 找不到 Swift 符号
|
||||
|
||||
```
|
||||
A: 可能原因:
|
||||
1. 项目未正确配置(缺少 xcworkspace)
|
||||
2. CocoaPods 未安装(先执行 pod install)
|
||||
3. 符号在 Pods 目录中(被排除)
|
||||
4. Swift Package 未解析
|
||||
|
||||
解决:
|
||||
1. 确保使用 .xcworkspace 而非 .xcodeproj
|
||||
2. 执行 pod install 生成 workspace
|
||||
3. 使用 search_for_pattern 作为备选
|
||||
4. 对于 SPM 项目,确保 Package.resolved 存在
|
||||
```
|
||||
|
||||
### Q: RxSwift 调用追踪不完整
|
||||
|
||||
```
|
||||
A: RxSwift 的链式调用使得静态分析困难:
|
||||
1. 操作符链可能跨越多行
|
||||
2. 闭包中的调用难以追踪
|
||||
3. 协议扩展方法无法直接定位
|
||||
|
||||
解决:
|
||||
使用 search_for_pattern 搜索特定操作符模式
|
||||
结合 Input/Output 模式分析 ViewModel
|
||||
追踪 DisposeBag 的使用位置
|
||||
```
|
||||
|
||||
### Q: Extension 方法找不到
|
||||
|
||||
```
|
||||
A: Swift extension 方法分散在多个文件中:
|
||||
1. extension 文件通常命名为 Type+Category.swift
|
||||
2. 同一类型可能有多个 extension 文件
|
||||
3. Protocol extension 更难追踪
|
||||
|
||||
解决:
|
||||
1. 先搜索 extension TypeName 识别所有扩展
|
||||
2. 使用 Glob 匹配 *+*.swift 文件
|
||||
3. 分析 Protocol extension 时搜索协议名
|
||||
```
|
||||
|
||||
### Q: Moya Target 解析
|
||||
|
||||
```
|
||||
A: Moya TargetType 是 enum,需要特殊处理:
|
||||
1. case 定义了 API 端点
|
||||
2. path/method/task 等属性需要配合分析
|
||||
3. switch self 模式匹配需要解析
|
||||
|
||||
解决:
|
||||
1. 先提取所有 case 定义
|
||||
2. 分析 path 属性的 switch 语句
|
||||
3. 匹配 case 与 path 的对应关系
|
||||
|
||||
# 示例搜索
|
||||
mcp__serena__search_for_pattern(
|
||||
substring_pattern="case \\w+.*\\n.*path:",
|
||||
paths_include_glob="**/*API.swift",
|
||||
multiline=True,
|
||||
context_lines_after=5
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **按架构层分析** - 先识别 MVVM 各层文件,再逐层深入
|
||||
2. **ViewModel 是关键** - ViewModel 层连接 ViewController 和 Service,是分析重点
|
||||
3. **Input/Output 模式** - 识别 RxSwift MVVM 的标准模式
|
||||
4. **Pod 依赖优先** - 通过 Podfile 快速了解项目技术栈
|
||||
5. **Extension 归类** - 将 extension 文件与原类型关联
|
||||
6. **分批处理大项目** - 424K 行项目必须分批处理
|
||||
|
||||
---
|
||||
|
||||
## 项目特定模式(示例:chefu_driver_app_ios)
|
||||
|
||||
该项目使用的技术栈和模式:
|
||||
|
||||
```yaml
|
||||
架构模式: MVVM + Coordinator
|
||||
ViewController: *ViewController.swift
|
||||
ViewModel: *ViewModel.swift (Input/Output 模式)
|
||||
Service: *Service.swift (单例模式)
|
||||
Coordinator: *Coordinator.swift
|
||||
|
||||
网络层: Moya + RxSwift
|
||||
API 定义: *API.swift (TargetType enum)
|
||||
Provider: MoyaProvider<API>
|
||||
响应类型: Observable<Response>
|
||||
|
||||
响应式框架: RxSwift + RxCocoa
|
||||
ViewModel: Observable/Driver
|
||||
ViewController: DisposeBag, bind/drive
|
||||
|
||||
UI 框架:
|
||||
布局: SnapKit
|
||||
图片: Kingfisher
|
||||
刷新: MJRefresh
|
||||
|
||||
项目规模:
|
||||
文件数: 3,602 Swift 文件
|
||||
代码行数: 约 424,000 行
|
||||
Pod 依赖: 50+ 个 Pod
|
||||
|
||||
目录结构:
|
||||
MyApp/
|
||||
AppDelegate.swift
|
||||
Coordinator/ # 导航协调器
|
||||
Modules/ # 按功能模块划分
|
||||
Home/
|
||||
ViewController/
|
||||
ViewModel/
|
||||
View/
|
||||
Model/
|
||||
Order/
|
||||
...
|
||||
Services/ # 业务服务
|
||||
Network/ # 网络层
|
||||
API/
|
||||
Model/
|
||||
Common/ # 公共组件
|
||||
Base/
|
||||
Extension/
|
||||
Utils/
|
||||
```
|
||||
@@ -0,0 +1,441 @@
|
||||
# TypeScript/Vue Language Server 使用指南
|
||||
|
||||
> 通过 Serena MCP 工具调用 typescript-language-server 和 Volar 进行前端代码分析
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 1. 项目结构要求
|
||||
|
||||
TypeScript 项目需要以下文件:
|
||||
|
||||
- `package.json` - 项目配置
|
||||
- `tsconfig.json` - TypeScript 配置
|
||||
- Vue 项目还需要 `vue.config.js` 或 `vite.config.ts`
|
||||
|
||||
### 2. 依赖安装
|
||||
|
||||
```bash
|
||||
# 确保项目依赖已安装
|
||||
npm install
|
||||
# 或
|
||||
pnpm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 通过 Serena 使用 TypeScript LSP
|
||||
|
||||
### 激活项目
|
||||
|
||||
```yaml
|
||||
# 激活 Vue/TypeScript 项目
|
||||
tool: mcp__serena__activate_project
|
||||
params:
|
||||
project: "/path/to/vue/project"
|
||||
|
||||
# 返回: 项目已激活
|
||||
```
|
||||
|
||||
### 验证配置
|
||||
|
||||
```yaml
|
||||
# 检查当前配置
|
||||
tool: mcp__serena__get_current_config
|
||||
|
||||
# 确认活跃项目正确
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 符号提取操作
|
||||
|
||||
### JavaScript/TypeScript 文件
|
||||
|
||||
```yaml
|
||||
# 获取 API 模块符号
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "src/api/order.js"
|
||||
depth: 1
|
||||
|
||||
# 返回示例:
|
||||
# Functions:
|
||||
# - getOrderList (function) [15-25]
|
||||
# - createOrder (function) [27-40]
|
||||
# - updateOrder (function) [42-55]
|
||||
# - cancelOrder (function) [57-70]
|
||||
```
|
||||
|
||||
### Vue 单文件组件
|
||||
|
||||
```yaml
|
||||
# Vue 文件包含 template + script + style
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "src/views/order/edit/index.vue"
|
||||
depth: 2
|
||||
|
||||
# 返回示例:
|
||||
# Module: index
|
||||
# - data (function) [script]
|
||||
# - methods:
|
||||
# - handleSubmit (method)
|
||||
# - handleCancel (method)
|
||||
# - loadOrderDetail (method)
|
||||
# - computed:
|
||||
# - isEditable (computed)
|
||||
# - watch:
|
||||
# - orderId (watcher)
|
||||
```
|
||||
|
||||
### 查找特定函数
|
||||
|
||||
```yaml
|
||||
# 查找 API 函数
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "getOrderList"
|
||||
relative_path: "src/api/"
|
||||
include_body: true
|
||||
include_info: true
|
||||
|
||||
# 返回:
|
||||
# Function: getOrderList
|
||||
# Location: src/api/order.js:15-25
|
||||
# Body:
|
||||
# export function getOrderList(params) {
|
||||
# return request({
|
||||
# url: '/order/list',
|
||||
# method: 'post',
|
||||
# data: params
|
||||
# })
|
||||
# }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Vue 组件特殊处理
|
||||
|
||||
### 组件 Props 提取
|
||||
|
||||
```yaml
|
||||
# 查找组件的 props 定义
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "props:\\s*\\{"
|
||||
paths_include_glob: "**/*.vue"
|
||||
context_lines_after: 20
|
||||
|
||||
# 或使用符号查找
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "props"
|
||||
relative_path: "src/components/OrderDetail.vue"
|
||||
include_body: true
|
||||
```
|
||||
|
||||
### 组件 Emits 提取
|
||||
|
||||
```yaml
|
||||
# 查找组件的事件定义
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "emits:\\s*\\["
|
||||
paths_include_glob: "**/*.vue"
|
||||
context_lines_after: 5
|
||||
```
|
||||
|
||||
### Composition API (Vue 3)
|
||||
|
||||
```yaml
|
||||
# 查找 setup 函数中的 ref/reactive
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "(const|let)\\s+\\w+\\s*=\\s*(ref|reactive)\\("
|
||||
paths_include_glob: "**/*.vue"
|
||||
|
||||
# 查找 computed
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "const\\s+\\w+\\s*=\\s*computed\\("
|
||||
paths_include_glob: "**/*.vue"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 调用追踪
|
||||
|
||||
### 追踪 API 使用
|
||||
|
||||
```yaml
|
||||
# 1. 找到 API 定义
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "getOrderList"
|
||||
relative_path: "src/api/order.js"
|
||||
include_body: true
|
||||
|
||||
# 2. 查找 API 被哪些组件使用
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "getOrderList\\s*\\("
|
||||
paths_include_glob: "src/views/**/*.vue"
|
||||
context_lines_before: 3
|
||||
context_lines_after: 3
|
||||
|
||||
# 返回示例:
|
||||
# src/views/order/list/index.vue:45
|
||||
# async loadData() {
|
||||
# const res = await getOrderList(this.queryParams)
|
||||
# this.tableData = res.data
|
||||
# }
|
||||
```
|
||||
|
||||
### 追踪组件使用
|
||||
|
||||
```yaml
|
||||
# 查找某个组件被哪里使用
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "<OrderDetailDialog"
|
||||
paths_include_glob: "**/*.vue"
|
||||
|
||||
# 或查找 import 语句
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "import.*OrderDetailDialog.*from"
|
||||
paths_include_glob: "**/*.vue"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调用链构建
|
||||
|
||||
### 前端调用链特点
|
||||
|
||||
前端调用链通常是:
|
||||
|
||||
```
|
||||
页面组件 → 方法 → API 函数 → HTTP 请求 → 后端接口
|
||||
↓
|
||||
子组件 → 事件 → 父组件方法
|
||||
```
|
||||
|
||||
### 构建步骤
|
||||
|
||||
```yaml
|
||||
# 1. 从页面组件开始
|
||||
tool: mcp__serena__get_symbols_overview
|
||||
params:
|
||||
relative_path: "src/views/order/edit/index.vue"
|
||||
depth: 2
|
||||
|
||||
# 2. 找到关键方法
|
||||
tool: mcp__serena__find_symbol
|
||||
params:
|
||||
name_path_pattern: "handleSubmit"
|
||||
relative_path: "src/views/order/edit/index.vue"
|
||||
include_body: true
|
||||
|
||||
# 3. 分析方法体中的调用
|
||||
# - API 调用: createOrder(...)
|
||||
# - 组件方法: this.$refs.form.validate()
|
||||
# - 状态管理: this.$store.dispatch(...)
|
||||
|
||||
# 4. 追踪 API 到后端
|
||||
# 从 API 函数找到 URL: /order/create
|
||||
# 对应后端: OrderController.createOrder
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Vuex/Pinia 状态追踪
|
||||
|
||||
### Vuex Actions 追踪
|
||||
|
||||
```yaml
|
||||
# 1. 找到 dispatch 调用
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "this\\.\\$store\\.dispatch\\(['\"]\\w+['\"]"
|
||||
paths_include_glob: "**/*.vue"
|
||||
|
||||
# 2. 找到 action 定义
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "actions:\\s*\\{"
|
||||
paths_include_glob: "**/store/**/*.js"
|
||||
context_lines_after: 50
|
||||
```
|
||||
|
||||
### Pinia Store 追踪
|
||||
|
||||
```yaml
|
||||
# 1. 找到 store 使用
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "use\\w+Store\\(\\)"
|
||||
paths_include_glob: "**/*.vue"
|
||||
|
||||
# 2. 找到 store 定义
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "defineStore\\("
|
||||
paths_include_glob: "**/stores/**/*.ts"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 路由追踪
|
||||
|
||||
### 找到路由配置
|
||||
|
||||
```yaml
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "path:\\s*['\"].*order"
|
||||
paths_include_glob: "**/router/**/*.{js,ts}"
|
||||
context_lines_before: 2
|
||||
context_lines_after: 5
|
||||
|
||||
# 返回示例:
|
||||
# {
|
||||
# path: '/order/list',
|
||||
# name: 'OrderList',
|
||||
# component: () => import('@/views/order/list/index.vue')
|
||||
# }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## LSP SymbolKind 映射
|
||||
|
||||
```yaml
|
||||
# TypeScript LSP 返回的 SymbolKind
|
||||
|
||||
1: File
|
||||
2: Module # Vue SFC
|
||||
3: Namespace
|
||||
4: Package
|
||||
5: Class # 类
|
||||
6: Method # 方法
|
||||
7: Property # 属性
|
||||
8: Field
|
||||
9: Constructor
|
||||
10: Enum
|
||||
11: Interface # 接口
|
||||
12: Function # 函数
|
||||
13: Variable # 变量 (含 const/let)
|
||||
14: Constant # 常量
|
||||
22: EnumMember
|
||||
26: TypeParameter # 泛型
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 前端特有模式识别
|
||||
|
||||
### API 请求封装识别
|
||||
|
||||
```yaml
|
||||
# axios 封装
|
||||
patterns:
|
||||
- "axios\\.(get|post|put|delete)\\("
|
||||
- "request\\(\\{.*url:"
|
||||
- "\\$http\\.(get|post)"
|
||||
|
||||
# 提取 API 端点
|
||||
tool: mcp__serena__search_for_pattern
|
||||
params:
|
||||
substring_pattern: "url:\\s*['\"]([^'\"]+)['\"]"
|
||||
paths_include_glob: "src/api/**/*.{js,ts}"
|
||||
```
|
||||
|
||||
### 组件通信模式
|
||||
|
||||
```yaml
|
||||
# Props 传递
|
||||
pattern: ":prop-name=\"value\""
|
||||
|
||||
# 事件触发
|
||||
pattern: "@event-name=\"handler\""
|
||||
|
||||
# Provide/Inject
|
||||
pattern: "provide\\(|inject\\("
|
||||
|
||||
# EventBus
|
||||
pattern: "\\$emit\\(|\\$on\\("
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: Vue 文件符号不完整
|
||||
|
||||
```
|
||||
A: Volar 可能需要额外配置
|
||||
1. 确保 @vue/language-server 已安装
|
||||
2. 检查 tsconfig.json 包含 Vue 文件
|
||||
3. 使用 search_for_pattern 补充
|
||||
```
|
||||
|
||||
### Q: JavaScript 文件无类型信息
|
||||
|
||||
```
|
||||
A: 纯 JS 文件缺少类型推断
|
||||
1. 添加 JSDoc 注释
|
||||
2. 转换为 TypeScript
|
||||
3. 依赖运行时信息推断
|
||||
```
|
||||
|
||||
### Q: 动态组件追踪困难
|
||||
|
||||
```
|
||||
A: <component :is="..."> 无法静态分析
|
||||
1. 使用 search_for_pattern 搜索可能的组件名
|
||||
2. 结合运行时日志
|
||||
3. 标记 confidence < 1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **Vue 文件分块分析** - 分别处理 template/script/style
|
||||
2. **API 模块优先** - 先分析 api/ 目录建立端点映射
|
||||
3. **组件依赖图** - 构建组件之间的引用关系
|
||||
4. **路由作为入口** - 从路由配置开始追踪页面
|
||||
5. **状态管理关联** - 将 store 操作与组件关联
|
||||
|
||||
---
|
||||
|
||||
## 与后端关联
|
||||
|
||||
### 建立前后端映射
|
||||
|
||||
```yaml
|
||||
# 从前端 API 找到后端接口
|
||||
|
||||
# 1. 提取前端 API URL
|
||||
frontend_api:
|
||||
file: "src/api/order.js"
|
||||
function: "getOrderList"
|
||||
url: "/order/list"
|
||||
method: "POST"
|
||||
|
||||
# 2. 映射到后端
|
||||
backend_api:
|
||||
file: "OrderController.java"
|
||||
method: "getOrderList"
|
||||
annotation: "@PostMapping(\"/list\")"
|
||||
|
||||
# 3. 建立引用
|
||||
xref:
|
||||
type: "http_call"
|
||||
from: "sym://typescript/src/api/order::getOrderList"
|
||||
to: "sym://java/...::OrderController#getOrderList"
|
||||
evidence:
|
||||
url: "/order/list"
|
||||
method: "POST"
|
||||
```
|
||||
Reference in New Issue
Block a user