# magic-api-ts **Repository Path**: yutel/magic-api-ts ## Basic Information - **Project Name**: magic-api-ts - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2026-08-16 - **Last Updated**: 2026-09-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于 magic-api 的 TS 类型增强 > 在 **magic-api 2.2.2** 的脚本编辑器(magic-editor)里,为 `magic-script` 语言叠加了一套 **TypeScript 风格的类型系统 + WebStorm 风格编辑体验**: > 类型补全、实时类型检查、一键快速修复、语义着色、inlay 参数名、CodeLens 引用统计、实时模板、符号导航等。 > --- ## 目录 1. [功能总览](#一功能总览) 2. [TS 类型系统](#二ts-类型系统) 3. [智能补全](#三智能补全) 4. [实时类型检查(波浪线报错)](#四实时类型检查波浪线报错) 5. [快速修复(Ctrl + Enter)](#五快速修复ctrl--enter) 6. [hover 类型提示与 Ctrl+点击 跳转](#六hover-类型提示与-ctrl点击-跳转) 7. [WebStorm 风格编辑体验](#七webstorm-风格编辑体验) 8. [意图操作(Code Action)](#八意图操作code-action) 9. [错误波浪线增强](#九错误波浪线增强) 10. [性能优化](#十性能优化) 11. [快捷键速查](#十一快捷键速查) 12. [Go 风格错误处理(err :=)](#十二go-风格错误处理err-) 13. [Debug 调试内嵌提示](#十三debug-调试内嵌提示) --- ## 一、功能总览 编辑器在 `magic-script` 语言上叠加了一套**前端类型系统** + **WebStorm 风格编辑体验**,整体链路: **① 输入即提示(补全)** - `type` 字段值 / lambda 参数 / 返回类型 → 类型补全 - 对象字面量 `return {` / `const x = {` → 字段名补全(含嵌套递归) - `import '@type/xxx' as asd` → 模块类型补全(`asd.Demo`) **② 实时校验(doValidate)** - 类型检查:结构比较、any 通配、数组、返回类型 - 语法检查:缺逗号等 → 波浪线 + 错误列表 **③ 一键修复(Ctrl + Enter)** - 插入逗号 / 创建缺失字段 / 移除注解 **④ hover 与跳转** - hover 查看结构 / Ctrl+点击跳转模块类型 **核心能力一句话**:写 `magic-script` 就像写 TS —— 有类型、有提示、有检查、有修复,还有 WebStorm 式的编辑手感。 --- ## 二、TS 类型系统 ### 2.1 `type` 类型定义 用 `type` 关键字定义**结构化类型**(字段 + 类型),是整套类型系统的基础: ```javascript type Address = { city: string, zip: string } type Demo = { name: string, age: number, address: Address, // 引用同文件类型 test?: string, // 可选字段(?:) data: Data | null // 联合类型(|) } ``` **示例效果**: - 给 `address` 字段补全时,提示 `Address`、`string`、`number` 等 - 定义 `type Demo` 支持**泛型**与默认值 ### 2.2 引入类型模块(`import '@type/...'`) magic-api 把类型资源放在 `@type` 下,用 import 引入后即可当类型用: ```javascript import '@type/demo/Demo' as Demo // 写法一:直接作为类型注解 const config: Demo = { name: "张三", age: 18, address: { city: "北京", zip: "100000" } } // 写法二:as 断言(Cast) const data = { ... } as Demo ``` > 类型模块别名必须以大写字母开头(`import ... as demo` → 会爆红提示改为 `Demo`)。 ### 2.3 可选字段 / 泛型 / 默认值 ```javascript // 泛型:T 默认是 Address type Box = { value: T, label?: string // 可选字段,赋值时可省略 } // 实例化 const b1: Box = { value: { city: "上海", zip: "200000" } } const b2: Box = { value: "hello" } ``` --- ## 三、智能补全 ### 3.1 type 字段值类型补全 光标停在类型字段值位置,**只提示类型名**(不混入变量/方法噪音): ```javascript type Demo = { name: █ // ← Alt + / 提示:string / number / boolean / Address / Demo... } ``` ### 3.2 对象字面量字段补全(含嵌套) 在 `return {` 或 `const x = {` 里,自动补全已知类型的字段,**嵌套递归**: ```javascript const config: Demo = { █ // ← 提示:name / age / address / test / data address: { █ // ← 进入嵌套,提示:city / zip } } ``` ### 3.3 模块类型补全 ```javascript import '@type/testType/TestTs' as asd const config: asd.█ = {} // ← 提示:Demo、Address、Other... ``` ### 3.4 lambda 参数 / 返回类型补全 ```javascript const fn = (val: █ // ← 提示:string / number / 自定义类型 const fn = (val: string): █ => // ← 提示:TestTs.Demo 等返回类型 ``` ### 3.5 变量 / 函数补全带文档 补全项附带**类型说明**(documentation),悬停补全项右侧显示类型结构。 ### 3.6 实时模板(Live Templates) 输入缩写自动补全代码片段(WebStorm 风格): | 缩写 | 生成 | |---|---| | `log` / `logd` / `loge` / `logt` | `log.info` / `log.debug` / `log.error` / `log.trace` | | `try` / `tryf` | `try { } catch (e) { }` / `try { } finally { }` | | `for` / `forin` / `fori` | for 循环 / for-in / 带索引的 for | | `if` / `ife` | `if` / `if-else` | | `db` / `json` / `list` / `map` / `sw` | 常用结构 | **示例**:输入 `try` 后回车: ```javascript try { █ } catch (e) { █ } ``` --- ## 四、实时类型检查(波浪线报错) 输入过程中**实时校验**,错误标红色波浪线,未使用标黄色: ```javascript // 缺少必填字段 → 爆红 const obj: Demo = { name: "张三" // ← 缺少属性:age、address } // 字段类型不匹配 → 爆红 const obj2: Demo = { name: 123, // ← 变量「name」类型不匹配:期望 string,实际 number age: 18 } ``` 支持的结构比较:**精确结构、any 通配、数组与混合数组、函数返回类型**。 ```javascript // any 通配:任意类型都兼容 type Loose = { id: any } const ok: Loose = { id: { anything: true } } // ✓ 不报错 // 数组类型检查 type List = { items: string[] } const bad: List = { items: [1, 2] } // ← 期望 string[],实际 number[] // 缺逗号 → 爆红「缺少逗号」 const x = { a: 1 b: 2 } // ← Expected ',', but got 'b' ``` --- ## 五、快速修复(Ctrl + Enter) 把光标放在错误上按 `Ctrl + Enter`,一键修复: | 错误 | 修复动作 | |---|---| | 缺逗号 | 自动插入逗号 | | 缺少必填字段 | 一键补全所有缺失字段(含嵌套) | | 返回类型不匹配 | 创建缺失字段 / 移除返回类型注解 | | 变量类型不匹配 | 移除类型注解 | | 未使用变量/导入 | 一键移除 | **示例**:光标在 `obj` 的 `name` 行按 Ctrl+Enter: ```javascript const obj: Demo = { name: "张三" } // ↓ 一键补全后 const obj: Demo = { name: "张三", age: null, address: { city: null, zip: null } } ``` --- ## 六、hover 类型提示与 Ctrl+点击 跳转 ### 6.1 hover 显示类型结构 悬停变量/字段,弹出**类型结构**(多行格式化 + 命名类型展开): ```javascript const config: Demo = { ... } // hover config → { name: string, age: number, address: Address, data?: Data } ``` ### 6.2 命名类型引用点击就地展开 hover 里出现**可点击的类型名**(如 `Address`),点击**就地展开**结构,不用跳走: ```javascript // hover 到 config.address 时: // address: Address ← 可点击,点击展开 { city: string, zip: string } ``` ### 6.3 Ctrl + 点击 跳转 - `import '@type/demo/Demo' as Demo` → Ctrl+点击路径打开类型资源 - 本地定义 `type` / `const` → Ctrl+点击跳转定义 - 字段引用 → Ctrl+点击查看引用 / 跳转 --- ## 七、WebStorm 风格编辑体验 ### 7.1 语义着色(semantic tokens) 基于 AST 精确区分类型/函数/字段/参数(Monarch 词法无法可靠区分函数调用与成员字段): ```javascript import '@type/demo/Demo' as Demo // Demo → 类型色(加粗) import '@/func/func1' as func1 // func1 → 函数色 const config: Demo = { // config → 变量色 name: null, // name → 字段色 ... } const fn = (a, b) => a + b // a/b → 参数色(斜体) const list = db.select(...) // db/log/map → 内置函数(斜体) ``` | 语义 | 示例 | 效果 | |---|---|---| | 类型 | `Demo`、`type` 注解、`as Demo` | 类型色 + 加粗 | | 函数 | `func1(...)`、`@/` import 别名 | 函数色 | | 字段 | 对象属性 `name:`、成员 `.address` | 字段色 | | 参数 | lambda `(a, b)` | 参数色 + 斜体 | | 内置函数 | `db`/`log`/`map`/`list` | 斜体 | ### 7.2 inlay 参数名提示 函数调用实参前**淡色显示形参名**: ```javascript func1(a: 123, b: 1, c: "123") // ^ ^ ^ ← 参数名提示 ``` ### 7.3 参数提示自动触发 输入 `(` 自动弹出函数签名 + 参数类型 + 返回类型,无需手动按快捷键。 ### 7.4 CodeLens(引用数 / 调用次数) 类型/函数/变量定义处显示统计,**点击「N 个引用」跳转到下一个引用位置**: ```javascript 2 个引用 被调用 2 次 2 个引用 import '@type/demo/Demo' as Demo import '@/func/func1' as func1 const config: Demo = ... ``` - 未使用的变量 → 「未使用」;未调用的函数 → 「未调用」 ### 7.5 符号导航(Ctrl + Shift + O) 弹出文档符号列表(类型定义 + 顶层变量),输入过滤、点击跳转: ``` config (variable) Base (class) Demo (class) ``` > 面包屑(breadcrumbs)monaco standalone 不支持,用符号导航替代。 ### 7.6 括号彩虹色 / 引导线 / sticky 标题 - 括号彩虹配色 + 括号/缩进引导线 - 滚动时顶部固定显示结构标题(sticky scroll) --- ## 八、意图操作(Code Action) ### 8.1 Surround with 选中一段代码,包裹进控制结构: ```javascript // 选中 `list.forEach(...)`,选 Surround with try-catch: try { list.forEach(...) } catch (e) { █ } ``` 支持:`if` / `try-catch` / `for` / `while`。 ### 8.2 提取变量 ```javascript // 选中表达式 `config.name.toUpperCase()`,选「提取变量」: const extracted = config.name.toUpperCase() ``` ### 8.3 生成 log.info 光标在变量上,一键插入调试日志: ```javascript // 光标在 config 上: log.info("config: {}", config) ``` --- ## 九、错误波浪线增强 - **所有语法错误**红色波浪线(缺逗号、缺少括号等,显示原始错误消息) - 类型错误红色、未使用警告黄色 - 悬停错误显示详情 **示例**: ```javascript const x = { a: 1 b: 2 } // ← 红色波浪线「缺少逗号」 const unused = 1 // ← 黄色警告「未使用的变量」 ``` --- ## 十、性能优化 | 优化 | 说明 | |---|---| | AST 单槽缓存 | 同一脚本内容复用解析结果(`script-cache.js`) | | 类型模块 fetch 节流 | 2 秒内不重复拉取类型模块 | | 校验防抖 | 输入后 250ms 才触发全量校验 | | 编辑中容错 | 未闭合字符串等解析失败不抛错(语义着色临时降级),语法错误仍由校验标记波浪线 | --- ## 十一、快捷键速查 | 快捷键 | 功能 | |---|---| | `Alt + /` | 触发代码补全 | | `Ctrl + Enter` | 快速修复光标处错误 | | `Ctrl + Shift + O` | 符号导航(类型/变量列表) | | `Ctrl + 点击` | 跳转模块类型 / 本地定义 / 资源 | | `Alt + 1` | 光标变量下方插入 log 调试 | | `Ctrl + Alt + L` | 格式化文档(含 SQL 三引号) | | `Ctrl + F8` | 跳转到下一个错误 | | `F2` | 重命名变量 | | hover | 查看类型结构 / 命名类型点击展开 | --- ## 十二、Go 风格错误处理(err :=) 新增 Go 风格的错误处理语法:`const tmpData, err := db.select(...)`。`err` 是错误对象(Java `Exception`,无错误时为 `null`),**使用前必须处理**(否则编辑器红色波浪线报错,运行时也会抛出「错误未处理」异常)。 ### 12.1 基本用法 ```javascript // 查询用户列表:出错时 err 非空,必须处理 const list, err := db.select(""" select * from t_user """) if (err) { log.error("查询用户失败: {}", err.getMessage()) return err } return list ``` **执行语义**: - `:=` 正常执行 → `err = null`;执行抛异常 → `err` = 异常对象,脚本**暂停**等待处理 - `if (err)` / `else if (err)` / `return err` / `throw err`(仅裸变量)视为「已处理」 ### 12.2 校验规则 | 场景 | 效果 | |---|---| | `if (err) { ... }` | ✓ 已处理,不报错 | | `return err` / `throw err` | ✓ 已处理 | | `try { const d, e := ... } catch(x) {}` | ✓ try 内视为已处理(catch 兜底) | | 未处理直接结束 / 继续使用 | ✗ 报「错误变量「err」必须被处理」 | | 同名 err 未处理再次 `:=` | ✗ 报「上一次的错误还未处理,不能再次赋值」 | ### 12.3 更多示例 ```javascript // 更新数据:失败则抛出错误中断 const n, err := db.update(""" update t_user set name = ${name} where id = ${id} """) if (err) { throw err } return n // 多次数据库操作,各自检查错误 const a, err1 := db.select(""" select * from t_a """) if (err1) { return err1 } const b, err2 := db.select(""" select * from t_b """) if (err2) { return err2 } return { a: a, b: b } ``` > `:=` 兼容 `: =`(带空格)写法;`err` 变量有独立的语义着色(变量色),补全 `err.` 提示 `Exception` 完整方法(`getMessage` / `printStackTrace` 等)。 --- ## 十三、Debug 调试内嵌提示 断点调试时,在编辑器**行尾**实时显示变量当前值(IDEA 风格,灰色 inlay、无 `//` 前缀): ```javascript const data = [1, 2, 3, 4] data = [1, 2, 3, 4] ← 变量声明行:行尾显示当前值 const obj = { name: "张三", age: 18 } obj = {...} const ccc = item item = 1, ccc = 1 ← 断点命中行:显示该行引用的变量值 ``` **说明**: - **变量声明行** → 行尾显示该变量当前值(`const a = [1,2,3,4]` → `a = [1,2,3,4]`) - **断点命中行** → 行尾显示该行引用的变量值(`const ccc = item` → `item = 1, ccc = 1`) - 数组/对象显示概要(`[1,2,3,4]` / `[...(n)]` / `{...}`),**hover 内嵌值展开完整格式化 JSON** - 断点继续 / 恢复执行后自动清除内嵌提示 --- ## 十四、2026-08-24 新增:Java 源码查看 & 编辑器协同 & 依赖收集工具 > 日期:**2026-08-24**。本批新增/修复功能记录。 ### 14.1 Ctrl + Click 查看 Java 类源码(只读) 在 magic-script 编辑器里,**Ctrl + 点击** Java 类名 / 方法名即可查看对应 **Java 源码**(只读 tab,不可编辑): - **类名跳转**:`import java.util.HashMap` 点 `HashMap`、任意 classpath 中的类名 → 打开源码 - **方法跳转**:`对象.方法名(` / 本类方法 / 父类方法 → 定位到源码中的方法声明行 - **无限嵌套**:源码内继续 Ctrl + 点击可逐层深入(类、方法、import 类) - **JDK 源码**:`HashMap`、`String` 等 JDK 类也能看(后端自动读取运行 JDK 的 `src.zip`) - **变量方法**:`const map = new HashMap()` 后点 `map.put(` 也能跳转(局部变量类型推断) - **拼写纠错补全**:输入 `hasmap` 会提示 `HashMap`(编辑距离 ≤1)并自动补 `import java.util.HashMap` **依赖(后端需配置 `magic-api.source-libs`)**: - 后端 `magic-api` 模块 `JavaSourceService` + `POST /magic/web/class/source` 接口 - 在应用配置 `application.yaml` 的 `magic-api` 下配置 **`source-libs`**,指向收集好的 lib 目录(含 `-sources.jar`): ```yaml magic-api: source-libs: ./jarLib/magic-test-web/lib # 本地示例(注意 source-libs 是 magic-api 下的配置项) # 服务器示例:/opt/magic-api/jarLib/magic-test-web/lib # 未配置则不启用「查看 Java 源码」 ``` - 用下方 `collect-libs.bat` 把依赖 jar + 源码 jar 收集到该目录 - JDK 源码(`HashMap`、`String` 等)由后端自动读取运行 JDK 的 `src.zip`(`java.home/lib/src.zip`),无需配置 ### 14.2 编辑器协同(两个用户同时编辑) 同一脚本支持**多个用户同时编辑**,实时同步内容与光标: - **实时双向同步**:A 输入/删除,B(C…)立即看到,无需刷新 - **并发冲突收敛**:两人在同一位置同时编辑 → OT / Yjs CRDT 自动合并,最终内容一致 - **远程光标**:每个协作者显示彩色光标 + 用户名标签(离开自动消失) - **保存即重置**:任一人 Ctrl+S 保存后,所有协作者以磁盘内容重新对齐(缓冲自愈) - **未保存内容可见**:第二人打开文件即可看到第一人尚未保存的修改 - **断线重连恢复**:WebSocket 重连 / 服务器重启后自动重新加入协同,不丢失编辑 **架构**: - 后端 `MagicCoWriteWebSocketHandler`(`/magic/web/cowrite`,按文件 id 分房间的纯中继) - 前端 `magic-html-ts/src/scripts/editor/co-write.js`(Yjs:Y.Doc + Y.Text + Awareness) - 编辑器 `magic-monaco-editor.vue` 绑定模型、`magic-script-editor.vue` 管理加入/离开生命周期 - 光标同步为**前端自实现**(content widget + 用户名标签,色板 10 色) > 说明:协同状态为服务端内存态(单机部署),保存(Ctrl+S)后以磁盘为权威并通知所有参与者重新对齐。 ### 14.3 collect-libs.bat —— 收集 Maven 运行依赖 jar(含源码) > 用途:把某 Maven 项目的运行时依赖 jar(含 `-sources.jar`)平铺复制到 > `magic-api-server\jarLib\<项目名>\lib`,供后端「查看 Java 源码」使用。 **用法**(双击运行,或在命令行执行): ``` collect-libs.bat 弹出系统窗口选择 pom.xml collect-libs.bat -Pom <路径> 直接指定 pom.xml(跳过弹窗) collect-libs.bat -Pom <路径> -Clean 复制前清空 lib 中的旧 jar collect-libs.bat -h 查看帮助 ``` **交互流程**: 1. 未指定 `-Pom` 时,弹出**系统文件选择窗口**,选择要收集的 Maven 项目的 `pom.xml` 2. 脚本自动定位 Maven(项目 `mvnw` → PATH → `MAVEN_HOME/M2_HOME` → `~\.m2\wrapper\dists` → 常见目录) 3. 自动解析项目 `artifactId`(XML 解析)作为输出目录名 4. 调 `mvn dependency:build-classpath` 解析 runtime 依赖 5. 把二进制 jar 和对应 `-sources.jar` 平铺复制到 `jarLib\<项目名>\lib` 6. 生成 `jars-list.txt` 清单(含无源码 / 本地缺失列表) **示例**: ``` D:\...\magic-api-server> collect-libs.bat (弹出窗口选择 magic-test-web\pom.xml) 输出目录:D:\...\magic-api-server\jarLib\magic-test-web\lib ``` **服务器部署**:把 `jarLib\<项目名>\lib` 复制到服务器,配置 `magic-api.source-libs` 指向它即可;JDK 源码由后端自动读取 `java.home/lib/src.zip`。 **相关文件**: - `collect-libs.bat`:主脚本(UTF-8 带 BOM 编码,cmd 靠 BOM 识别中文) - `pick-pom.ps1`:辅助脚本,负责弹窗选择 pom.xml - `collect-libs.ps1`:旧版 PowerShell 脚本(已被 bat 替代,可删除)