Skip to content

Commit 3512a48

Browse files
xlorneclaude
andcommitted
feat: 添加自动补全、属性面板和工具栏
- 新增基于 ScriptMetadata 的动态类型自动补全(支持变量名和点号链式访问) - 新增右侧属性面板,展示变量、数据类型、字段和方法(支持滚动) - 新增工具栏,包含标题、主题切换和编译测试按钮 - 新增 Groovy 常用语法提示(if/for/while/println 等) - 修复主题切换时代码被重置的 bug(使用 Compartment 热更新) - 添加 CLAUDE.md 开发指南 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent be96b2c commit 3512a48

13 files changed

Lines changed: 1558 additions & 540 deletions

File tree

CLAUDE.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## 项目概述
6+
7+
Script Engine 是一个基于 React + CodeMirror 6 的 Groovy 脚本编辑器组件库,提供语法高亮、动态类型自动补全、属性面板等功能。发布为 npm 包 `@coding-script/script-engine`
8+
9+
**用户全局规则**:使用中文回复。
10+
11+
## 常用命令
12+
13+
```bash
14+
# 在 monorepo 根目录执行
15+
pnpm run build:script-engine # 构建库
16+
pnpm run watch:script-engine # 库 watch 模式(开发时常用)
17+
pnpm run dev:app-pc # 启动演示应用(http://localhost:3000)
18+
pnpm run push:script-engine # 构建并发布到 npm
19+
20+
# 在 packages/script-engine 目录执行
21+
pnpm run build # 构建
22+
pnpm run dev # watch 模式
23+
pnpm run push # 构建 + publish --access public
24+
25+
# 在 apps/app-pc 目录执行
26+
pnpm run dev # 启动开发服务器
27+
pnpm run build # 生产构建
28+
pnpm run preview # 预览生产构建
29+
30+
# 测试(Rstest + happy-dom,目前尚无测试文件)
31+
pnpm run test # 运行测试
32+
pnpm run test:watch # watch 模式
33+
```
34+
35+
## Monorepo 结构
36+
37+
```
38+
pnpm-workspace.yaml: packages/** + apps/**
39+
40+
packages/script-engine/ → 库 @coding-script/script-engine (Rslib, ESM, unbundled)
41+
apps/app-pc/ → 演示应用 @script-example/app-pc (Rsbuild + React, 依赖 antd 6)
42+
```
43+
44+
库通过 `workspace:*` 被演示应用引用。**开发流程**:先在根目录运行 `watch:script-engine`,再运行 `dev:app-pc`
45+
46+
## 关键架构
47+
48+
### 库的构建配置 (`packages/script-engine/rslib.config.ts`)
49+
50+
- **`bundle: false`**:不打包,输出保持模块图结构(tree-shakeable)
51+
- **`format: 'esm'`**:仅 ESM
52+
- **`dts: true`**:生成 `.d.ts` 类型声明
53+
- 路径别名 `@/``src/`(在 tsconfig 和 rslib.config 中都要配置)
54+
55+
### CodeMirror 6 编辑器 (`src/script-code.tsx`)
56+
57+
核心设计原则:**`Compartment` 热更新,避免重建编辑器**
58+
59+
编辑器只在首次挂载和布局属性(`fontSize`/`minHeight`/`maxHeight`/`placeholder`/`readonly`)变化时重建。以下内容通过 Compartment 热更新:
60+
61+
- `themeCompartmentRef`:主题(dark/light)切换 → `buildThemeExtensions(theme)`
62+
- `autocompleteCompartmentRef`:metadata 变化 → `buildAutocompleteExt(metadata)`
63+
64+
**绝对不要**`theme``metadata``value` 放到编辑器创建的 useEffect 依赖数组中,否则会丢失用户已编辑的代码内容。
65+
66+
`onChangeRef` / `metadataRef` 使用 ref 持有回调,避免闭包过期。
67+
68+
### 自动补全 (`src/autocomplete/`)
69+
70+
- `resolve.ts`:纯函数,解析点号链到具体类型
71+
- `resolveVariableType(name, metadata)` → 在 binds/requests 中查找变量
72+
- `resolveMemberType(typeName, memberName, metadata)` → 在类型的 fields/functions 中查找成员
73+
- `resolveChainType(parts, metadata)` → 解析完整链 `["request", "test"]``MyTest` 类型
74+
- `MAX_DEPTH = 20` 防止循环引用
75+
- `completion-source.ts`
76+
- `createGroovyCompletionSource(metadata)`:metadata 驱动 + Groovy 语法(有 metadata 时使用)
77+
- `createGroovyKeywordSource()`:仅 Groovy 语法(无 metadata 时使用)
78+
- 通过 `syntaxTree(context.state).resolveInner()` 检测字符串/注释位置,抑制补全
79+
- 外层 `try/catch` 保证补全失败不崩溃编辑器
80+
- Groovy 语法片段用 `snippet()` API(来自 `@codemirror/autocomplete`)实现 tab-stop 占位符
81+
82+
### 属性面板 (`src/type-panel/`)
83+
84+
纯 React 组件,**不依赖 Ant Design**(antd 仅在演示应用中使用)。
85+
86+
- 使用 CSS-in-JS(React `style` 对象)+ 主题配色 map
87+
- `TypePanel` 固定高度(`minHeight`/`maxHeight` 由编辑器传入),内部可滚动
88+
- 滚动条样式通过 `<style>` 标签一次性注入 DOM(`ensureScrollbarStyle()`
89+
- 展示 metadata 中**所有**类型(包括 Integer/String 等基础类型)
90+
- 滚动容器必须设置 `minHeight: 0`(flex 布局关键修复)
91+
92+
### ScriptMetadata Schema (`src/types/index.ts`)
93+
94+
核心领域模型,描述脚本运行时的可用类型:
95+
96+
```ts
97+
ScriptMetadata {
98+
binds: ScriptBindInfo[] // 注入变量,如 $request(name 含 $ 前缀)
99+
requests: ScriptRequestInfo[] // 函数参数,如 request
100+
returnType?: string
101+
types: Record<string, ScriptTypeInfo> // 所有可用类型(含基础类型)
102+
}
103+
104+
ScriptTypeInfo { dataType, description?, fields[], functions[] }
105+
ScriptFieldInfo { dataType, description?, name }
106+
ScriptFunctionInfo { name, parameters[], description?, returnType? }
107+
```
108+
109+
`metadata` 是动态的(不同脚本有不同 schema),但结构固定。
110+
111+
## 类型导出
112+
113+
`src/index.ts` 必须同时导出组件和类型:
114+
```ts
115+
export * from "./script-code";
116+
export * from "./types";
117+
```
118+
119+
消费者通过 `import type { ScriptMetadata } from '@coding-script/script-engine'` 导入类型。
120+
121+
## 主题
122+
123+
`dark` 和 `light` 两套配色。编辑器主题、自动补全弹窗主题、属性面板主题三者必须同步切换:
124+
125+
- 编辑器:`oneDark` + 自定义 `darkHighlightStyle`
126+
- 弹窗:`buildAutocompleteTooltipTheme(theme)` 注入 `EditorView.theme()`
127+
- 属性面板:`themes[theme]` 配色 map
128+
129+
## 发布
130+
131+
发布到 npm 的 `@coding-script/script-engine` scope,使用 `--access public`。
132+
- 构建后产物在 `packages/script-engine/dist/`
133+
- 仅发布 `dist/` 目录(`package.json` 中 `files: ["dist"]`

0 commit comments

Comments
 (0)