jagreehal/effect-analyzer
GitHub: jagreehal/effect-analyzer
Effect-TS 程序的静态分析工具,通过解析源码生成结构可视化图表、复杂度指标和语义差异对比,帮助开发者理解和维护 Effect 代码。
Stars: 22 | Forks: 1
# effect-analyzer
[Effect](https://effect.website/) 程序的静态分析工具。将服务依赖、错误通道、并发和控制流可视化为 Mermaid 图表——无需运行你的代码。
## 为什么需要
Effect 程序功能强大,但其结构——服务依赖、错误拓扑、并发模式——在源代码中很难直接看出来。effect-analyzer 使用 [ts-morph](https://ts-morph.com/) 和 TypeScript 类型检查器解析你的代码,然后生成语义图表和结构化分析。无需运行时,无需埋点。
将其用于**代码审查**、**新手入门**、**架构文档**和 **CI**,以捕捉程序结构上的回归。
## 安装
```
npm install -D effect-analyzer
```
`effect` (>=3.0.0) 是必需的 peer dependency。`ts-morph` 会自动打包。
## 快速开始
```
# 为文件自动选择最佳图表
npx effect-analyze ./src/transfer.ts
# Railway 图(线性 happy path 及 error 分支)
npx effect-analyze ./src/transfer.ts --format mermaid-railway
# 用纯英语解释程序的功能
npx effect-analyze ./src/transfer.ts --format explain
# 比较两个版本
npx effect-analyze HEAD:src/transfer.ts src/transfer.ts --diff
# 审查整个项目
npx effect-analyze ./src --coverage-audit
```
## 你将获得什么
给定一个像这样的 Effect 程序:
```
export const transfer = Effect.gen(function* () {
const repo = yield* AccountRepo
const audit = yield* AuditLog
const balance = yield* repo.getBalance("from-account")
if (balance < 100) {
yield* Effect.fail(new InsufficientFundsError(balance, 100))
}
yield* repo.debit("from-account", 100)
yield* repo.credit("to-account", 100)
yield* audit.record("transfer-complete")
})
```
分析器会生成一个轨道图,显示带有错误分支的正常路径:
```
flowchart LR
A["repo <- AccountRepo"] -->|ok| B["audit <- AuditLog"]
B -->|ok| C["balance <- repo.getBalance"]
C -->|ok| D{"balance < 100"}
D -->|ok| E["repo.debit"]
E -->|ok| F["repo.credit"]
F -->|ok| G["audit.record"]
G -->|ok| Done((Success))
C -.->|err| Err1([AccountNotFound])
D -.->|err| Err2([InsufficientFunds])
```
或者生成一个显示所有控制流路径的流程图:
```
flowchart TB
start((Start))
n2["repo <- AccountRepo"]
n3["audit <- AuditLog"]
n4["balance <- repo.getBalance"]
decision{"balance < 100?"}
n7["Effect.fail(InsufficientFunds)"]
n8["repo.debit"]
n9["repo.credit"]
n10["audit.record"]
end_node((Done))
start --> n2 --> n3 --> n4 --> decision
decision -->|yes| n7
decision -->|no| n8
n7 -.-> end_node
n8 --> n9 --> n10 --> end_node
```
## 功能
### 15+ 种图表类型
自动模式会为你的程序选择最相关的视图,你也可以显式选择:
| 格式 | 显示内容 |
|--------|-------|
| `mermaid-railway` | 带有错误分支的线性正常路径 |
| `mermaid` | 包含所有控制流的完整流程图 |
| `mermaid-services` | 服务依赖图 |
| `mermaid-errors` | 错误传播和处理 |
| `mermaid-concurrency` | 并行和竞速模式 |
| `mermaid-layers` | Layer 组合图 |
| `mermaid-retry` | 重试和超时策略 |
| `mermaid-timeline` | 随时间变化的步骤序列 |
| `mermaid-statechart` | 作为 `stateDiagram-v2` 的状态机 |
| `svg-statechart` | 独立的、XState 风格的 statechart SVG |
| `statechart-html` | 带有 SVG、覆盖率和 XState 导出的本地可视化页面 |
| `xstateconfig` | 用于 [Stately 可视化工具](https://stately.ai/viz)的 `createMachine()` 配置 |
[查看所有格式 →](https://jagreehal.github.io/effect-analyzer/diagrams/all-formats/)
### 无需 XState 的状态机
用纯 Effect 编写确定性状态机——可以是声明式转换表、`Match.when` 转换函数,或嵌套的 `Match.tags` 状态/事件分发——并将它们渲染为 XState 风格的 statecharts。不需要 XState 依赖。请参阅
[`state-machine-conventions.md`](./state-machine-conventions.md) 中的完整约定指南。
```
# 无 flags:默认视图会展示文件中的任何 state machine
npx effect-analyze ./workflow.ts
# 本地 visualizer 页面(diagram + coverage + 可粘贴的 config)。
# 若未指定 -o,它会在 input 旁边生成 workflow.statechart.html
npx effect-analyze ./workflow.ts --format statechart-html
# 适用于 markdown / GitHub 的 stateDiagram-v2
npx effect-analyze ./workflow.ts --format mermaid-statechart
# XState createMachine() config — 粘贴到 stately.ai/viz 即可获得真实的
# interactive visualizer,直接由你的 Effect 代码生成
npx effect-analyze ./workflow.ts --format xstate-config
```
可识别以下结构:
```
// A) declarative transition table
const transitions = {
Triage: {
RefundRequested: { target: 'Refund', guard: 'canRefund' },
AnswerRequested: 'Answered',
},
Refund: { Resolved: 'Answered' },
Answered: {},
} as const;
// B) Match.when transition function
const transition = (state: State, event: Event): State =>
Match.value([state._tag, event._tag] as const).pipe(
Match.when(['Draft', 'Submit'], () => ({ _tag: 'Review' as const })),
Match.orElse(() => state),
);
// C) nested Match.tags with state tags outside and event tags inside
const transitionWithTags = (state: State, event: Event): State =>
Match.value(state).pipe(
Match.tags({
Draft: () =>
Match.value(event).pipe(
Match.tags({
Submit: () => ({ _tag: 'Review' as const }),
}),
),
Review: () => state,
}),
);
```
初始状态从 `@initial ` 注解或 `initial`/`initialState` 声明中读取。表叶子节点可以是字符串、
`{ target, guard }`、`{ to }`,或者是受保护目标的数组。如果处理程序可以返回多个状态,则会变成受保护的(多目标)转换。
#### 完整性检查(感知 Schema)
当 State/Event 类型是可辨识联合或 `Schema` 派生类型时,分析器会读取**已声明的字母表**并根据它检查状态机——将 statechart 从一张图纸变成经过验证的机器:
```
npx effect-analyze ./workflow.ts --format statechart-coverage
```
```
# State machine coverage
1 machine, 2 warnings.
## checkoutTransition(alphabet: schema)
Coverage: 33% (2/6 reachable state×event pairs handled)
- ⚠ Unhandled events: `Cancel` # declared, but no state handles it
- ⚠ Unreachable states: `Cancelled` # declared, but nothing transitions to it
```
它会报告**未处理的事件**、**无法到达的状态**以及**未声明的符号**(偏离了类型的转换)。该命令**在任何发现警告时都会以非零状态退出**,因此它可以作为 CI 门禁使用。
`mermaid-statechart` 和 `svg-statechart` 输出会使用相同的发现进行标注(高亮显示孤立状态,指出未处理的事件)。
在整个目录上运行它以获取摘要表、设置覆盖率下限,或为仪表板输出 JSON:
```
npx effect-analyze ./src --format statechart-coverage # all machines, summary table
npx effect-analyze ./src --format statechart-coverage --min-coverage 60 # fail under 60%
npx effect-analyze ./src --format statechart-coverage --coverage-json # { machines, summary }
```
受保护的(条件)转换会连同其条件一起被捕获,并显示在每个渲染器上(图表中为 `Event [guard]`,XState 配置中为 `{ target, guard }`)。State/Event 字母表可以是可辨识联合、`Schema` 派生类型、`Schema.TaggedClass`/`Schema.TaggedRequest` 联合,或者是普通的字符串字面量联合(`'a' | 'b'`)。
除非存在嵌套的状态/事件结构,否则普通的单层 `Match.tags` 分发会被特意忽略,因为普通的变体处理不具备 statechart 所需的源状态维度。
### 复杂度指标
为每个程序计算六项指标:圈复杂度、认知复杂度、路径数、嵌套深度、并行广度和决策点。
```
npx effect-analyze ./src/transfer.ts --format stats
```
[了解更多 →](https://jagreehal.github.io/effect-analyzer/analysis/complexity/)
### 语义差异对比
在结构层面比较程序的两个版本——不是文本差异,而是步骤、服务和控制流的变化:
```
npx effect-analyze HEAD:src/transfer.ts src/transfer.ts --diff
```
[了解更多 →](https://jagreehal.github.io/effect-analyzer/project/diff/)
### 覆盖率审计
扫描整个项目以了解 Effect 的使用情况,识别复杂的程序,并跟踪分析质量:
```
npx effect-analyze ./src --coverage-audit
```
[了解更多 →](https://jagreehal.github.io/effect-analyzer/project/coverage-audit/)
### 交互式 HTML 查看器
生成一个独立的 HTML 页面,包含搜索、过滤、路径浏览器、复杂度热力图和 6 种颜色主题:
```
import { renderInteractiveHTML } from "effect-analyzer"
const html = renderInteractiveHTML(ir, { theme: "midnight" })
```
[了解更多 →](https://jagreehal.github.io/effect-analyzer/reference/html-viewer/)
### 库 API
使用编程 API 将分析集成到你自己的工具中:
```
import { analyze } from "effect-analyzer"
import { Effect } from "effect"
const ir = await Effect.runPromise(analyze("./src/transfer.ts").single())
console.log(ir.root.programName) // "transfer"
console.log(ir.root.dependencies) // [{ name: "AccountRepo", ... }, ...]
console.log(ir.root.errorTypes) // ["InsufficientFundsError", "AccountNotFoundError"]
```
[完整 API 参考 →](https://jagreehal.github.io/effect-analyzer/reference/api/)
## 可检测内容
| 领域 | 模式 |
|------|----------|
| **程序** | `Effect.gen`、管道链、`Effect.sync`、`Effect.async`、`Effect.promise` |
| **服务** | 通过 `yield*` 调用的 `Context.Tag`、服务方法调用 |
| **Layer** | `Layer.mergeAll`、`Layer.effect`、`Layer.provide`、`Layer.succeed` |
| **错误** | `catchTag`、`catchAll`、`tapError`、`retry`、`timeout` |
| **并发** | `Effect.all`、`Effect.race`、`Effect.fork`、`Fiber.join` |
| **资源** | `acquireRelease`、`ensuring`、`Effect.scoped` |
| **流** | `Stream.fromIterable`、`Stream.mapEffect`、`Stream.runCollect` |
| **控制流** | 位于 generator 内部的 `if/else`、`for..of`、`while`、`try/catch`、`switch` |
| **调度** | `Schedule.recurs`、`Schedule.exponential` |
| **别名** | `const E = Effect`、解构导入、重命名导入 |
## 环境要求
- Node.js 22+
- 带有 `effect` (>=3.0.0) 的 TypeScript 项目
## 文档
完整文档可在 **[jagreehal.github.io/effect-analyzer](https://jagreehal.github.io/effect-analyzer/)** 获取。
## 许可证
MIT
标签:Mermaid, MITM代理, TypeScript, 云安全监控, 代码可视化, 安全专业人员, 安全插件, 架构分析, 自动化攻击, 静态分析