Compare commits

...

5 Commits

Author SHA1 Message Date
a9eaaa6023 docs: 新增项目文档并更新开发规则
- 新增品牌命名、商业化策略、SDK视觉噪音处理、可视化库设计和系统架构文档
- 更新开发规则,明确禁止主动修改项目源代码文件
- 所有文档均为中文编写,用于记录项目设计讨论和决策
2026-02-18 00:18:35 +08:00
4929ca496b feat: 新增 GraphTracer 并重构 ArrayTracer 的初始化方式
- 新增 GraphTracer 及其类型定义,支持图的创建和操作命令
- 重构 ArrayTracer 的 create 函数,使用 walker/commit 模式替代直接的 array 参数,提高灵活性
- 更新类型导出和命令联合类型以包含 GraphTracer
- 调整示例代码以使用新的初始化方式
2026-02-14 01:30:30 +08:00
9d5a46129e refactor(tracer-context): 移除自动输出指令序列的逻辑
移除 process.on('exit') 中的自动输出逻辑,改为通过 dump 方法手动获取指令序列。
2026-02-13 20:57:27 +08:00
305a9c7dc3 docs: 添加开发规则文档
- 新增开发规则文档,明确代码修改前的讨论流程
- 规范API设计时的多语言兼容性考虑范围
- 文档包含C、C++、Java等主流编程语言支持要求
2026-02-10 09:23:32 +08:00
a3328b8617 fix(array-tracer): 修正创建命令中数组参数的必填性
将 `ArrayTracerCreateCommand.params.array` 从可选参数改为必填参数,以匹配实际实现逻辑。
同时更新 `createArrayTracer` 函数,确保在未提供 `array` 时使用空数组作为默认值,保持向后兼容性。
2026-02-08 23:29:24 +08:00
16 changed files with 540 additions and 18 deletions

View File

@@ -0,0 +1,47 @@
# Structrail 品牌命名解读
## 1. 命名构成
- **项目名称**Structrail
- **构词方式**`Struct` + `t` + `rail` (共享字母 `t` 的混成词)
- **核心双关**
- Struct **Trail** (数据轨迹)
- Struct **Rail** (结构轨道)
## 2. 核心释义Struct Trail (数据轨迹)
这是最贴切且最具动态感的解释,直接映射了项目的核心价值——**可视化数据结构的演变过程**。
* **与 Tracer (跟踪器) 的呼应**
* 核心组件 `Tracer` 的作用是记录数据结构的变化。
* 每一次变化都在时间维度上留下了一个 `Trail` (痕迹/足迹)。
* 用户通过 `Tracer` 追踪到了数据的 `Trail`
* **Time Travel (时间旅行) 的隐喻**
* `Trail` 暗示了一条可以沿着往返的小径。
* 支持“上一步”、“下一步”的操作,就像沿着留下的面包屑 (breadcrumbs) 在历史轨迹中穿梭。
* 用户可以随时回溯,查看数据在某一时刻的状态。
* **Debugging (调试) 的本质**
* 算法执行的过程,本质上就是数据状态在时间流中留下的一条长长的轨迹。
* 调试就是沿着这条轨迹寻找异常点。
## 3. 双关释义Struct Rail (结构轨道)
作为第二层含义,`Rail` 为项目增添了稳固感和基础设施的韵味。
* **规范与引导 (On the Rails)**
* `Rail` 暗示了“轨道”,意味着代码在既定的逻辑轨道上运行。
* 可视化的目的之一是确保算法逻辑“在正轨上” (Stay on the rails),帮助用户发现何时“脱轨” (Off the rails)。
* **基础设施感 (Infrastructure)**
**Ruby on Rails* 一样,`Rail` 给人一种坚实底座的感觉。
* 暗示 Structrail 是承载算法运行、支撑可视化功能的坚实平台。
## 4. 结论与建议
建议以 **Struct Trail** 作为品牌叙事的核心,强调“追踪”、“轨迹”和“时间旅行”的概念,同时保留 **Struct Rail** 作为一种有趣的双关解读,暗示平台的稳定性和规范性。
**Slogan 构思:**
> **Structrail**: Visualize the **trail** of your data structures.
> (Structrail可视化你数据结构的轨迹。)

View File

@@ -0,0 +1,51 @@
# StructRail 商业化策略与产品规划
## 1. 核心愿景
打造一个支持主流编程语言、具备“时间旅行”调试能力的算法可视化生态平台。不仅仅是展示算法,更是理解和调试算法的工具。
## 2. 商业模式:基于运行成本的 Freemium 模型
鉴于 Web 平台的技术特性,采用“低成本服务免费引流,高成本服务付费增值”的策略。
### 2.1 免费层 (Client-side / Web Native)
利用浏览器端计算能力Web Worker / WASM提供零边际成本的服务。
- **支持语言**JavaScript, TypeScript, 以及未来通过 WASM 支持的 Python/C++ (Web版)。
- **运行环境**:用户浏览器本地运行,无服务器计算成本。
- **目标用户**:初学者、前端开发者、开源社区贡献者。
- **价值**:作为“引流款”,通过开源和免费使用获取最大流量和技术声誉。
### 2.2 会员/增值层 (Server-side / Cloud Native)
利用云端沙箱Docker/K8s提供高性能、多语言的运行环境。
- **支持语言**Java, Go, C#, C++ (完整版) 等重型或依赖特定运行时环境的语言。
- **运行环境**:云端高性能沙箱,保障安全与隔离。
- **服务限制**
- **普通用户**:每日有限次数的云端运行额度(如 10 次/天)。
- **会员用户**:无限次云端运行,优先调度高性能实例。
- **高级功能**
- **时间旅行调试 (Time Travel Debugging)**:针对复杂算法的深度调试能力。
- **云端存储**:保存并分享私有算法库。
- **高清导出**:生成 60fps 算法演示视频(面向内容创作者)。
## 3. SDK 开源策略
**策略核心SDK 全面开源,不卖代码,卖“运行环境”与“服务”。**
- **全语言开源 (MIT License)**:将 TS, Java, C++, Python 等所有语言的 SDK 代码开源。
- **目的**
- **简历与声誉**:展示多语言架构设计能力和协议通用性,提升项目技术含金量。
- **生态共建**:降低社区参与门槛,鼓励开发者修复 Bug 或贡献新语言支持。
- **标准确立**:推动 Tracer Protocol 成为事实上的算法可视化标准。
## 4. 目标用户与场景分层
| 用户群体 | 核心痛点 | 解决方案 | 商业化路径 |
| :--- | :--- | :--- | :--- |
| **学生/求职者** | 理解算法难,刷题调试难 | 可视化题解 + 调试器 | 会员订阅 (解锁 Java/C++ 调试) |
| **教育机构/高校** | 教学抽象,作业批改难 | 交互式课件 + 作业系统 | 企业版 SaaS (ToB) |
| **内容创作者** | 制作动画成本高 | 脚本生成视频 + 自定义皮肤 | 工具付费/素材付费 |
## 5. 技术壁垒 (Moat)
- **协议生态**:语言无关的 Tracer Protocol形成内容护城河。
- **混合运行时架构 (Hybrid Runtime)**:前端轻量级运行 + 后端重型沙箱,优化成本结构。
- **WebAssembly 应用**:探索将 Python/C++ 移植到前端运行,进一步降低服务端压力并提升免费用户体验。
---
*本文档基于 2026-02-16 的对话讨论整理。*

View File

@@ -0,0 +1,53 @@
# SDK 视觉噪音处理策略
## 1. 问题背景
在算法可视化场景中,为了记录数据结构变化,需要在用户算法代码中插入 SDK 调用(如 `tracer.patch()`, `tracer.pick()`)。过多的 SDK 调用代码会产生“视觉噪音”,破坏算法逻辑的连贯性,增加认知负担,与平台“低侵入性”和“原生体验”的设计目标冲突。
## 2. 核心原则
- **原生优先 (Native First)**:尽量利用编程语言特性实现隐式追踪,避免引入非标准的封装数据结构(如避免强制用户使用 `MyArray.set()` 替代 `arr[]`)。
- **显式降噪 (Explicit Reduction)**:在无法隐式追踪的场景下,通过 IDE 的视觉设计弱化 SDK 代码的存在感。
- **可编程性保留**:承认并保留显式调用 SDK 的必要性(用于精细控制动画或处理不支持的语言特性),将其视为“高级功能”而非“噪音”。
## 3. 分级解决方案
### 3.1 Level 1: 隐式追踪 (Implicit Tracing) —— 零侵入
利用现代编程语言的高级特性(代理、重载、魔术方法),拦截原生数据结构的读写操作,自动触发可视化事件。
- **适用场景**
- **JavaScript / TypeScript**: 使用 `Proxy` 对象拦截数组/对象操作。
- **C++**: 使用运算符重载(`operator[]`, `operator=`)封装 `std::vector` 或自定义容器。
- **Python**: 使用魔术方法(`__getitem__`, `__setitem__`)封装 `list`
- **用户体验**
```typescript
// 用户只需在初始化时声明一次
const tracer = new ArrayTracer().watch(arr);
// 后续全是原生代码,无感知
arr[i] = arr[j];
```
### 3.2 Level 2: 显式调用 (Explicit Call) —— 精细控制
对于不支持隐式拦截的语言特性(如 Java 原生数组、C 语言指针),或者用户需要插入非数据结构操作的指令(如 `tracer.delay()`, `tracer.log()`),必须使用显式 SDK 调用。
- **适用场景**
- Java 原生数组 (`int[]`)。
- C 语言指针操作。
- 算法逻辑之外的控制指令(暂停、日志、自定义高亮)。
- **代码规范**
- 保持 SDK 调用独立成行,避免嵌套在复杂逻辑中。
- 命名保持简洁(如 `tracer.patch` 而非 `Visualizer.getInstance().updateElement`)。
### 3.3 Level 3: IDE 视觉降噪 (Visual Noise Reduction)
在 Web IDE 层面通过 UI/UX 设计,将显式 SDK 调用代码“隐形”或“弱化”。
- **幽灵文本 (Ghost Text)**:将检测到的 SDK 调用行渲染为低对比度颜色如浅灰色opacity: 0.5),使视线自然聚焦于算法逻辑。
- **代码折叠 (Code Folding)**
- 提供“专注模式”开关,一键折叠所有 SDK 调用行。
- 在行号区域标记 SDK 调用,鼠标悬停时才高亮显示。
- **分离视图 (Split View) [可选]**
- **算法视图**:仅显示纯算法逻辑(隐藏 SDK 调用)。
- **完整视图**:显示包含 Tracer 调用的完整代码,供调试使用。
## 4. 结论
不应为了消除噪音而发明一套蹩脚的封装 API。正确的路径是
1. **能隐式则隐式**JS/Py/C++ Proxy
2. **不能隐式则显式**Java/C 原生操作)。
3. **显式噪音交给 IDE 处理**(变灰/折叠)。
这种策略既保留了代码的“可编程性”和“原生手感”,又解决了视觉干扰问题。

View File

@@ -0,0 +1,109 @@
# Structrail 系统架构设计与技术选型
本文档总结了 Structrail 平台的技术架构决策,包括 Monorepo 策略、服务拆分原则以及前后端架构方案的对比分析。
## 1. 总体架构策略Monorepo (单体仓库)
考虑到 Structrail 项目涉及多语言 SDK、统一的协议定义、前端可视化组件以及后端执行服务我们决定采用 **Monorepo** 架构。
### 核心收益
1. **单一事实来源 (Single Source of Truth)**:协议定义 (`@structrail/protocol`) 作为核心资产被前端、后端、SDK 共同引用。协议变更时,所有依赖方均可即时感知(类型检查报错),避免版本割裂。
2. **原子化提交 (Atomic Commits)**:由于协议变更往往涉及多端修改(如 ArrayTracer 新增指令 -> 前端渲染逻辑更新 -> SDK 实现更新Monorepo 允许在一个 Commit 中完成所有相关修改,保证系统一致性。
3. **统一版本管理**:便于统一管理多语言 SDK 的版本发布节奏。
4. **开发体验**:利用 `pnpm workspace``Turborepo` 等工具,实现高效的依赖管理和增量构建。
## 2. 服务架构设计
Structrail 的业务特性决定了其架构必须采用 **动静分离** 的策略,将轻量级的业务逻辑与重量级的代码执行隔离。
### 2.1 核心服务拆分
| 服务模块 | 职责描述 | 技术特征 |
| :--- | :--- | :--- |
| **Web (业务层)** | 用户界面、题目管理、社区互动、鉴权 | I/O 密集型,重交互,适合快速开发 |
| **API (接口层)** | 业务逻辑处理、数据转发、RPC 服务 | 高并发,低延迟,连接 Web 与 Runner |
| **Runner (执行层)** | 代码编译、沙箱运行、Trace 数据生成 | CPU 密集型,高风险,需独立部署与资源隔离 |
| **Protocol (共享层)** | 核心协议定义、类型声明、常量 | 纯代码库,无运行时依赖 |
### 2.2 架构方案对比
针对 Web 与 API 的实现,我们探讨了两种主流方案。两种方案均可行,且在 Monorepo 下都能实现 **100% 的端到端类型安全**
#### 方案 ANext.js 全栈架构 (SSR 优先)
* **架构描述**Web 与 API 合二为一,直接在 Next.js 的 Server Actions / Route Handlers 中处理业务逻辑,并调用 Runner 服务。
* **优势**
* **开发效率极致**:无 API 胶水层,前后端代码在同一文件中,调用后端函数像调用本地函数一样自然。
* **SSR 支持**:对 SEO 友好,首屏加载快(适合题目详情页、文档页)。
* **生态丰富**Vercel/Next.js 生态拥有大量现成组件。
* **劣势**
* **部署绑定**:较强依赖 Node.js Runtime 或 Vercel 平台。
* **边界模糊**Server Actions 可能导致前后端代码耦合,心智负担较重。
#### 方案 BReact (SPA) + Hono (API) 前后端分离 (CSR + Edge 优先)
* **架构描述**
* **Web**: 纯 React SPA通过 CDN 分发。
* **API**: 独立 Hono 服务,提供 RPC 接口。
* **通信**: 通过 `hono/client` 实现类型安全的 RPC 调用。
* **优势**
* **物理边界清晰**:前端关注 UI 交互,后端关注数据处理,职责分明。
* **部署极其灵活**前端可部署至任何静态托管OSS/Netlify后端可部署至 EdgeCloudflare Workers/Deno或容器。
* **高性能**Hono 基于 Web Standards冷启动快资源占用极低。
* **类型安全**:通过 Monorepo 导出 API 类型 (`AppType`),前端直接引用,实现与 tRPC 类似的开发体验。
* **劣势**
* **SEO 略弱**:纯 SPA 对 SEO 不如 SSR 友好(虽然可以通过预渲染解决)。
* **初期搭建成本**:需配置两个独立应用及通信链路。
### 2.3 结论与推荐
**推荐采用 Monorepo 架构,并根据团队偏好选择方案 A 或 B。**
* 如果更看重 **SEO****快速验证原型**,推荐 **方案 A (Next.js)**
* 如果更看重 **架构清晰度**、**部署灵活性 (Edge)** 和 **前后端解耦**,推荐 **方案 B (React + Hono)**
* *注:考虑到 Structrail 的编辑器交互极其复杂(重客户端逻辑),且 Runner 服务天然适合独立部署,**方案 B** 在长期维护和扩展性上可能更具优势。*
## 3. 建议的项目目录结构
无论选择哪种方案Monorepo 的基础结构应保持一致:
```text
structrail/
├── apps/ # 应用程序(业务层)
│ ├── web/ # [React/Next.js] 平台前端
│ │ └── ... (Visualizer 组件调用)
│ ├── api/ # [Hono/Node] 业务后端 (如果是方案 B)
│ ├── runner/ # [Go/Rust] 代码执行沙箱服务
│ └── docs/ # [VitePress] 文档站点
├── packages/ # 共享库(核心资产)
│ ├── protocol/ # 核心协议定义 (JSON Schema, TS Interfaces)
│ │ ├── index.ts # 导出 Tracer 类型、指令定义
│ │ └── schema.json # 用于校验 Trace 数据的 Schema
│ ├── sdk-ts/ # TypeScript SDK 实现
│ ├── ui/ # 通用 UI 组件库 (可选)
│ └── eslint-config/ # 统一的代码规范配置
├── sdks/ # 多语言 SDK (非 JS/TS 生态)
│ ├── c/ # C 语言 SDK (Makefile)
│ ├── python/ # Python SDK (Poetry)
│ ├── java/ # Java SDK (Maven/Gradle)
│ └── ...
├── tools/ # 工程化脚本
│ └── scripts/ # 批量发布、协议生成脚本
├── package.json # Root package.json
├── pnpm-workspace.yaml # pnpm workspace 配置
└── turbo.json # Turborepo 构建编排配置
```
## 4. 关键技术栈建议
* **包管理器与运行时**: `Bun` (All-in-One 工具链,提供极致的安装速度和高性能运行时)
* 作为包管理器替代 `npm/pnpm`
* 作为脚本执行器替代 `ts-node`
* 作为测试运行器替代 `Jest/Vitest`
* **构建系统**: `Turborepo` (任务编排、远程缓存)
* **前端框架**: `React` (配合 Vite)
* **后端框架**: `Hono` (完美适配 Bun 运行时,性能卓越)
* **Runner 语言**: `Go``Rust` (高性能、并发强、安全性好)
* **API 通信**: `Hono RPC` (如果分离) 或 `Server Actions` (如果全栈)

View File

@@ -0,0 +1,91 @@
# 前端可视化库设计草案 (@structrail/viz)
本文档描述了将平台前端渲染逻辑沉淀为独立可视化库的设计构想。
## 1. 项目定位
我们将“数据生成”Tracer SDK与“数据展示”Visualization Lib完全解耦旨在沉淀一套标准化的、可嵌入的前端可视化引擎。
* **Tracer SDK (后端/客户端)**:负责生成标准化的、语言无关的 JSON 指令流Trace Protocol
* **Visualization Lib (前端)**:负责解析指令流,重建数据状态,并提供交互式的可视化组件。
这套库不仅服务于 StructRail 平台,未来也可被嵌入到博客、电子书或教学文档中,成为算法可视化的基础设施。
## 2. 核心架构 (Architecture)
库的核心遵循 **Player + Store + Renderer** 的分层架构本质上是一个支持时间旅行Time Travel的确定性状态机。
### 2.1 Player (播放器/控制器)
* **职责**:负责解析 Tracer 生成的 JSON 指令流控制播放进度Frame/Step
* **功能**:提供 `play()`, `pause()`, `next()`, `prev()`, `seek(index)` 等 API。
* **特性**:它不关心具体怎么画,只关心“当前是第几步”以及“播放速度”。
### 2.2 Store (状态仓库/沙盒)
* **职责**:负责根据指令重构数据结构的状态。
* **机制**维护一个“影子内存”Shadow Memory
* 当 Player 处于第 0 步时Store 是空的。
* 当收到 `ArrayTracer.create` 指令时Store 里建立一个数组模型。
* 当收到 `patch` 指令时Store 更新对应数组的元素值。
* 当收到 `pick` 指令时Store 标记对应元素为“高亮状态”。
* **输出**:它能在任何时间点,输出一份**只读的、标准化的数据快照 (Snapshot)** 给渲染层。
### 2.3 Renderer (渲染器/组件库)
* **职责**:纯粹的 UI 展示层View遵循 `f(state) => UI` 的原则。
* **实现**:可以使用 React/Vue 组件,也可以是 Canvas/WebGL针对大规模数据
* **特点**:它完全不知道“指令”的存在,它只接收 `Store` 给它的快照。
* 例如:`<ArrayVisualizer data={[1, 2, 3]} highlights={[1]} />`
## 3. 库的形态设计 (API Preview)
如果这个库被开发出来,它在前端项目中的使用方式可能如下(以 React 为例):
```typescript
import { Player, ArrayVisualizer, GraphVisualizer } from '@structrail/viz';
// 1. 载入 Tracer 生成的 JSON 数据
const events = await fetch('algorithm-trace.json');
const player = new Player(events);
// 2. 绑定到 UI
function AlgorithmDemo() {
// 使用 player 的 hook 获取当前帧的数据快照
const snapshot = usePlayerSnapshot(player);
return (
<div>
{/* 播放控制栏 */}
<ControlBar player={player} />
{/* 渲染区域:根据 snapshot 中的数据自动渲染 */}
<div className="canvas">
{snapshot.tracers.map(tracer => {
if (tracer.type === 'array') {
return <ArrayVisualizer key={tracer.id} model={tracer} />
}
if (tracer.type === 'graph') {
return <GraphVisualizer key={tracer.id} model={tracer} />
}
})}
</div>
</div>
);
}
```
## 4. 关键技术挑战 (Technical Challenges)
### 4.1 增量计算与快照管理
* **问题**:如果算法有 100 万步,不能每一步都存一个深拷贝的快照。
* **策略**:使用类似 Git 的机制或 immer.js。Store 只记录关键帧Keyframe的快照中间步骤通过重放指令Replay动态计算。
### 4.2 动画过渡 (Animation)
* **问题**:当从“第 1 步”跳到“第 2 步”时如果只是数据的突变1 -> 2体验很生硬。
* **策略**:渲染层需要比较 `PrevSnapshot``CurrentSnapshot`Diff
* 如果发现数组 index 0 的元素位置变了,它应该生成一个移动动画。
* 这就是为什么我们的 `patch` / `swap` 指令语义很重要,它们对应了不同的动画原语。
### 4.3 自动布局 (Auto-Layout)
* **问题**:后端 Tracer 通常不包含坐标信息(除非我们以后添加坐标指令,但通常不建议耦合 UI 细节)。
* **策略**:前端库需要内置强大的自动布局算法。
* Graph: Force-directed graph (力导向图)
* Tree: Reingold-Tilford 树布局

View File

@@ -0,0 +1,13 @@
# 开发规则
- **严禁主动修改任何项目源代码文件(如 .ts, .js, .c, .h 等)。当前工作仅限于文档编写(.md和方案讨论。所有代码示例仅能在对话中展示不得写入文件。**
- 在考虑API的移植性时需要特别考虑C语言当然各类主流的编程语言要需要纳入考虑范围包括但不限于
- C++
- Java
- C#
- Kotlin
- Python
- Rust
- Go
- Swift
- Dart

View File

@@ -3,22 +3,27 @@ import type { TracerCommand } from '../types';
const createTracerContext = () => {
const commands: TracerCommand[] = [];
if (typeof process !== 'undefined' && typeof process.on === 'function') {
process.on('exit', () => {
if (commands.length > 0) {
console.log(commands);
}
});
}
// if (typeof process !== 'undefined' && typeof process.on === 'function') {
// process.on('exit', () => {
// if (commands.length > 0) {
// console.log(commands);
// }
// });
// }
const getTracerContext = () => {
const command = (command: TracerCommand) => {
commands.push(command);
};
// TODO: 输出指令序列
const dump = () => {
return commands;
};
return {
commands,
command,
dump,
};
};

View File

@@ -9,7 +9,12 @@ const controlTracer = createControlTracer({ description: 'ControlTracer' });
const arrayTracer = createArrayTracer({
description: 'ArrayTracer',
array: [1, 2, 3],
// array: [1, 2, 3],
walker: (commit) => {
commit(1);
commit(2);
commit(3);
},
});
arrayTracer.patch(0, 100);

View File

@@ -1,15 +1,32 @@
import { getTracerContext } from '../context';
import type { JsonValue } from '../types';
interface ArrayTracerCreateOptions<T extends JsonValue[]> {
interface BaseArrayTracerCreateOptions {
description?: string;
array?: T;
}
interface ArrayTracerCreateOptionsFromArray<
T extends JsonValue[],
> extends BaseArrayTracerCreateOptions {
array: T;
walker?: never;
}
interface ArrayTracerCreateOptionsFromWalker<
T extends JsonValue[],
> extends BaseArrayTracerCreateOptions {
array?: never;
walker: (commit: (item: T[number]) => void) => void;
}
type ArrayTracerCreateOptions<T extends JsonValue[]> =
| ArrayTracerCreateOptionsFromArray<T>
| ArrayTracerCreateOptionsFromWalker<T>;
export const createArrayTracer = <T extends JsonValue[]>(
options: ArrayTracerCreateOptions<T>,
) => {
const { description = 'ArrayTracer', array } = options;
const { description, array, walker } = options;
const tracer = crypto.randomUUID();
// 优化:仅维护数组长度作为影子状态,这在 C++/Java 等强类型语言中也极易实现(仅需一个 int 变量)
@@ -31,8 +48,8 @@ export const createArrayTracer = <T extends JsonValue[]>(
tracer: tracer,
action: 'create',
params: {
description: description,
array: array,
description: description ?? 'ArrayTracer',
array: array ?? [],
},
});

View File

@@ -0,0 +1,33 @@
import { getTracerContext } from '../context';
import type { GraphTracerGraph } from '../types';
interface GraphTracerCreateOptions {
description?: string;
graph?: GraphTracerGraph;
}
// 不要了,改为 walker/commit 方案
// TODO: 后续我们会添加创建图的辅助函数
// export const createGraphTracerHelper = () => {};
export const createGraphTracer = (options: GraphTracerCreateOptions) => {
const { description, graph } = options;
const tracer = crypto.randomUUID();
const { command } = getTracerContext();
command({
type: 'GraphTracer',
tracer: tracer,
action: 'create',
params: {
description: description ?? 'GraphTracer',
graph: graph ?? {
directed: false,
weighted: false,
nodes: [],
edges: [],
},
},
});
};

View File

@@ -1,3 +1,4 @@
export * from './array-tracer';
export * from './control-tracer';
export * from './graph-tracer';
export * from './log-tracer';

View File

@@ -8,7 +8,7 @@ type ArrayTracerCreateCommand = BaseArrayTracerCommand & {
action: 'create';
params: {
description: string;
array?: JsonValue[];
array: JsonValue[];
};
};

View File

@@ -1,8 +1,10 @@
import type { ArrayTracerCommand } from './array-tracer';
import type { ControlTracerCommand } from './control-tracer';
import type { GraphTracerCommand } from './graph-tracer';
import type { LogTracerCommand } from './log-tracer';
export type TracerCommand =
| ArrayTracerCommand
| LogTracerCommand
| ControlTracerCommand;
| ControlTracerCommand
| ArrayTracerCommand
| GraphTracerCommand;

View File

@@ -6,7 +6,7 @@ export type JsonValue =
| JsonValue[]
| { [key: string]: JsonValue };
export type TracerType = 'ArrayTracer' | 'LogTracer' | 'ControlTracer';
export type TracerType = 'LogTracer' | 'ControlTracer' | 'ArrayTracer' | 'GraphTracer';
export type TracerId = ReturnType<typeof crypto.randomUUID>;

View File

@@ -0,0 +1,94 @@
import type { BaseTracerCommand, JsonValue } from './common';
export type GraphTracerGraphNode = {
id: string;
value: JsonValue;
};
export type GraphTracerGraphEdge = {
source: string;
target: string;
weight: JsonValue;
};
export type GraphTracerGraph = {
directed: boolean;
weighted: boolean;
nodes: GraphTracerGraphNode[];
edges: GraphTracerGraphEdge[];
};
type BaseGraphTracerCommand = BaseTracerCommand & {
type: 'GraphTracer';
};
type GraphTracerCreateCommand = BaseGraphTracerCommand & {
action: 'create';
params: {
description: string;
graph: GraphTracerGraph;
};
};
type GraphTracerInsertCommand = BaseGraphTracerCommand & {
action: 'insert';
params: {};
};
type GraphTracerRemoveCommand = BaseGraphTracerCommand & {
action: 'remove';
params: {};
};
type GraphTracerUpdateCommand = BaseGraphTracerCommand & {
action: 'update';
params: {};
};
type GraphTracerConnectCommand = BaseGraphTracerCommand & {
action: 'connect';
params: {};
};
type GraphTracerDisconnectCommand = BaseGraphTracerCommand & {
action: 'disconnect';
params: {};
};
type GraphTracerWeightCommand = BaseGraphTracerCommand & {
action: 'weight';
params: {};
};
type GraphTracerVisitCommand = BaseGraphTracerCommand & {
action: 'visit';
params: {};
};
type GraphTracerLeaveCommand = BaseGraphTracerCommand & {
action: 'leave';
params: {};
};
type GraphTracerPickCommand = BaseGraphTracerCommand & {
action: 'pick';
params: {};
};
type GraphTracerDropCommand = BaseGraphTracerCommand & {
action: 'drop';
params: {};
};
export type GraphTracerCommand =
| GraphTracerCreateCommand
| GraphTracerInsertCommand
| GraphTracerRemoveCommand
| GraphTracerUpdateCommand
| GraphTracerConnectCommand
| GraphTracerDisconnectCommand
| GraphTracerWeightCommand
| GraphTracerVisitCommand
| GraphTracerLeaveCommand
| GraphTracerPickCommand
| GraphTracerDropCommand;

View File

@@ -2,4 +2,5 @@ export * from './array-tracer';
export * from './command';
export * from './common';
export * from './control-tracer';
export * from './graph-tracer';
export * from './log-tracer';