- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
导读
本文聚焦 MooTool 跨平台新一代产品线next-macos-native中 JSON 工具的核心设计:一个由 SwiftUI / AppKit 构建的完整 JSON 工作区,以及一套基于系统 JavaScriptCore、运行在独立辅助进程中的 JSON 解析引擎。阅读本文后,你将理解 MooTool 如何在不依赖 Node.js、Electron 与网络服务的条件下,将 Electron 版 JSON 工具的格式化、JSONPath 查询、XML / JavaBean 转换与查找替换能力完整移植到 macOS 原生平台,并掌握其进程隔离、超时控制、三语文案与能力边界的实现细节。该产品线的完整对齐口径见 parity.md,本主题的官方说明见 json-engine.md。
JSON 工作区的界面骨架
MooTool Next 原生版 0.4.0 起,JSON 工具采用与 Electron 版对应的工作区布局,由以下核心区域组成:
- 工具栏:承载格式化、压缩、查找、检查器开关等主要操作;
- 主编辑器:基于原生 NSTextView 的 JSON 正文编辑区;
- 可折叠检查器:用于结构树、路径选择与值预览;
- 查找替换栏:支持 JavaScript 正则语义的查找与替换;
- 路径选择器与转换结果弹窗:展示 JSONPath 查询结果与转换输出。
这一布局明确以 Electron 端的 JsonTool.tsx、JsonToolbar.tsx、JsonInspector.tsx、JsonToolDialogs.tsx 为参照实现,面板顺序与主要操作语义保持一致,但控件全部采用 macOS 原生组件。
在窄编辑区场景下,部分工具栏操作会被收纳进"更多"菜单,检查器通过弹出面板打开;整体交互遵循 macOS 的菜单、分栏与弹窗惯例,而非逐像素复刻 Electron 页面。
操作语义:哪些操作原地生效,哪些进入结果弹窗
JSON 工具的操作按"是否直接修改正文"分为两类,这是理解该工作区行为的关键:
直接更新主编辑器的操作(可撤销/重做,并保存到当前文档):
- 格式化(format):以 2 空格缩进重新序列化正文;
- 压缩(compress):移除所有空白的最紧凑形式;
- 高级格式化(advanced):支持自定义缩进、按键排序、忽略大小写排序与重复键检测;
- 键值互换(swap):仅针对 JSON 对象执行,交换键与值(值必须是可作键的类型);
- 转义 / 反转义(escape / unescape,含 Java 字符串风格的 escapeText / unescapeText)。
在结果弹窗中展示的操作(可复制、导出、使用结果,使用前不替换正文):
- JSONPath 查询(query):路径选择器填入 JSONPath 后执行;
- JSON → XML(jsonToXml);
- JSON → JavaBean(jsonToBean):生成 Java 类源码。
先输入来源、再替换正文的操作:
- XML → JSON(xmlToJson):先在弹窗中粘贴 XML,转换成功后替换主编辑器正文;
- JavaBean → JSON(beanToJson):同样先输入 Java 字段声明源码,再生成 JSON 替换正文。
这些 action 的分发逻辑集中在随包发布的 JSONDispatch.js 的runJSONRequest(payload)中,每个 case 对应一种操作语义,错误信息通过translate()按请求携带的language返回 zh-CN / en-US / ja-JP 三种语言。
查找替换:沿袭 JavaScript 正则语义
查找替换(find / replace / replaceAll)在 JSONTools.js 中实现,与 Electron 版完全同源:
- 支持大小写匹配(
matchCase)、全词匹配(wholeWord,用\b包裹)、正则模式(regex); - 支持向前 / 向后导航、捕获组替换模板与换行替换(
\n、\r、\t); - 正则标志使用
gu/giu,因此matchAll返回的索引是代码点级别的 UTF-16 偏移; - 替换选中区时,仅当选区恰好整体等于唯一匹配时才原地替换该选区;
- 高亮使用 NSTextView 的临时属性实现,不写入文档内容。
在CoreTests.swift中有对应验证:如testJSONNativeFindReplaceUnicodeAndFlags断言item(\d+)正则替换$1\n能正确生成换行、反向查找返回正确起始偏移、非法正则[会抛出错误(见 CoreTests.swift)。
路径选择器:字面路径优先,复杂表达式交给 JSONPath-Plus
路径选择器生成两类路径:
- 字面路径(literal path):如
$.store.books[0]、$["特殊 键名"],由 JSONDispatch.js 的literalPathTokens()解析,逐段保留数字、引号、方括号、反斜杠转义与换行等特殊键名,不做表达式求值; - 复杂表达式:如通配符、递归、筛选、切片、联合查询,交给 JSONPath-Plus 10.4.0 求值;
- 严格 JSON Pointer:以
/开头的路径走pointerQuery(),支持~0(~)与~1(/)转义、数组下标合法性校验与路径存在性校验。
右侧菜单仍可复制 JSON Pointer。结构树节点同时携带pointer(JSON Pointer)与queryPath(JSONPath 形式)两个标识,见 JSONStructure.swift 的JSONTreeNode,测试testJSONNativePathsMatchElectronQueries中$["0"]与$.array[0]的映射关系即由此而来。
独立解析引擎:Swift 宿主 + JavaScriptCore + JS 算法副本
MooTool 原生版没有在 macOS 应用内重写全部 JSON 算法,而是采用"独立解析引擎"架构:
- 算法层:
JSONTools.js是 MooTool 对应纯算法的独立副本,在本产品内维护,并包含 Java 字段名 / 类名冲突处理等原生版修正; - 执行层:系统 [JavaScriptCore] 的
JSContext在随应用打包的MooToolJSONWorker辅助进程中执行这些算法; - 分发层:
JSONDispatch.js负责把 Swift 结构化请求转换为具体算法调用,并统一本地化错误信息; - 宿主层:Swift 侧 JSONEngine.swift 负责请求构造、进程生命周期与结果回传。
三个 Swift target 的关系记录在 Package.swift:MooToolJSONWorker是独立可执行文件,依赖MooToolNextCore;MooToolNextApp是主应用;MooToolNextCore同时被两者依赖,承担算法资源封装。
请求-响应协议
请求由 JSONEngineRequest 描述,核心字段包括:
| 字段 | 默认值 | 说明 |
|---|---|---|
action | 无 | 操作类型(format / compress / advanced / swap / escape / unescape / query / jsonToXml / xmlToJson / beanToJson / jsonToBean / find / replace / replaceAll / duplicates / validate 等) |
input | 无 | 正文输入(最大 10 MB UTF-8) |
path | $ | JSONPath 或 JSON Pointer |
className | Root | JSON → JavaBean 的根类名(最长 240 字符) |
indent | 2 | 高级格式化缩进空格数 |
sortKeys/ignoreCase | false | 排序开关与排序时的大小写不敏感 |
checkDuplicateKeys | true | 高级格式化时是否检测重复键 |
query/replacement | 空 | 查找内容与替换内容(替换最长 1 MB) |
matchCase/wholeWord/regex | false | 查找替换三个标志 |
selectionStart/selectionEnd | 0 | 当前光标 / 选区位置(UTF-16) |
forward | true | 导航方向 |
language | zh-CN | 错误信息语言 |
响应为 JSONEngineReply:value(结果正文)、error(错误信息)、count(命中数)、match/matches(查找定位信息)。
数据传参:JSON 请求文件,而非脚本源码
一个关键的安全设计是:用户输入永远作为数据传入,绝不拼接为脚本源码。
JSONEngine.runWorker会为每次调用创建独立的临时目录(命名前缀为产品ID-json-<UUID>,目录权限 0700、文件权限 0600),把编码后的请求写入input文件,worker 从标准输入读取、结果写入output文件。worker 进程的环境变量被简化为LANG=en_US.UTF-8,不继承 shell 启动路径、注入的运行时路径与用户环境密钥(见 JSONEngine.swift)。
JSONDispatch.js首行注释也明确写着:// Native-product boundary: all caller text is data, never script source.。JSONPath 求值使用eval: 'safe',禁用动态表达式求值,测试 CoreTests.swift 专门断言@.constructor.constructor('return process')()这类注入表达式会被拒绝。辅助进程不向脚本暴露任何原生文件、网络或进程对象。
超时与取消:双层保险
辅助进程的终止由两层机制兜底:
- 父进程 3 秒超时:
JSONEngine.execute(_:timeout:)默认 3 秒,轮询期间一旦超过deadline就对 worker 发送SIGKILL并抛出超时错误(json.engine.timeout); - worker 自身 4 秒硬终止:main.swift 中
signal(SIGALRM, SIG_DFL)后调用alarm(4),即使主应用异常退出,耗时表达式也会在 4 秒后被系统信号终止; - 用户取消:
withTaskCancellationHandler+WorkerCancellation在任务取消时同样SIGKILL终止进行中的进程并抛CancellationError。
输出文件也会被监控,一旦超过 16 MB 即终止本次调用。每次调用结束都会删除临时目录。测试testJSONWorkerTimeoutCancellationAndIsolation用灾难性正则(a+)+$验证了超时与取消路径。
多窗口与文档切换语义:关闭无关窗口不会取消另一窗口的操作;切换文档、恢复工作区或修改正文后,旧的异步结果不会自动覆盖新内容。
依赖与产品边界
查询与 XML 转换依赖两个第三方库,版本与校验信息集中在 parser-versions.json:
| 依赖 | 版本 | 用途 | 发行文件 SHA-256 |
|---|---|---|---|
| JSONPath-Plus | 10.4.0 | JSONPath 查询(含 jsep 表达式解析) | ed2274eecaf6c8209eab8ebf991ef9319e23f4886296a257e84aaa055bfed097 |
| fast-xml-parser | 5.10.1 | XML 解析 / 构建(含 fast-xml-builder、strnum、is-unsafe 等子依赖) | fa2f3be3e78aab26a7a04be70fdceb7dede6981a4d1a0e2ca25c30bcef194f2e |
浏览器发行文件与许可副本全部位于本产品Sources/MooToolNextCore/Resources/,包括jsonpath-plus.js、fast-xml-parser.js、JSONTools.js、JSONDispatch.js、QuickNoteTools.js、ReformatTools.js及各库的 LICENSE 文件。这意味着:
- 构建和运行不读取
nextElectron 源码或node_modules; - 不要求 Node.js、Electron、浏览器或任何网络服务;
- JSON 数据不会发送到远端,所有解析都在本机辅助进程中完成;
- 产物本身随包分发,离线可用。
JSONTools.js是本产品内维护的独立算法副本,与 Electron 版next/src/features/json/jsonTools.ts同源,但针对原生版需求做了一处显著修正:Java 字段名 / 类名冲突处理(详见下文 JavaBean 一节)。
能力边界与限制
为保持与 Electron 版一致的解析语义并保证辅助进程安全,引擎设定如下边界(原文见 json-engine.md 能力边界一节,实现见 JSONEngine.swift 与 JSONDispatch.js):
| 维度 | 限制 |
|---|---|
| 单次正文 | 最多 10 MB(evaluateLocally校验) |
| 请求 / 结果 | 最多 16 MB(编码后二进制大小) |
| JSON 规模 | 最多 10 万节点、128 层(checkShape遍历计数) |
| 结构树 / 查询 / 查找结果 | 最多 2 万项(JSONStructure的nodeLimit与 query / find 的count上限) |
| 父进程超时 | 默认 3 秒 |
| worker 终止计时 | 独立 4 秒(alarm(4)) |
| 替换模板 | 最多 1 MB(UTF-8) |
| JSONPath / 查询文本 | 最多 16 KB(UTF-8) |
| 类名 | 最多 240 字符(UTF-8) |
超过任一限制即返回本地化错误(如json.error.nodeLimit:JSON 最多处理 10 万节点、128 层;json.error.queryTooManyResults:查询结果超过 2 万项)。
JSON 数字语义:JavaScript Number
JSON 数字按 JavaScript 的 Number 语义处理,与 Electron 一致——例如大整数超过Number.MAX_SAFE_INTEGER时精度会丢失。引擎不提供任意精度数字保证,这一行为对齐 Electron 基线,属于有意边界而非缺陷。
XML 转换规则
- 输入使用严格语法校验(
XMLValidator.validate),不接收 DTD 或实体声明(<![DOCTYPE / ENTITY ...]>会直接拒绝,测试用file:///etc/hosts实体注入用例验证); - XML → JSON 的属性使用
@_前缀(如@_enabled),重复元素合并为数组,值的数值 / 布尔推断沿用 fast-xml-parser 的解析行为; - JSON → XML 自动转义特殊字符(如
&转&); - 解析器抛出的英文
msg仍可能透传(如 XML 语法错误的原始消息)。
JavaBean 双向转换规则
JavaBean → JSON(javaBeanToJson):用正则解析字段声明(支持public/protected/private、static/final/transient/volatile修饰符与泛型类型),为每个字段生成示例值(mockJavaValue:String 生成空串、int 生成 0、List 生成空数组等),跳过serialVersionUID。它不执行 Java 代码,也不做完整 Java 编译器级类型分析。
JSON → JavaBean(jsonToBean):生成字段与嵌套类源码,核心逻辑在 JSONTools.js 的buildNativeJavaClass:
- 自动加入
import java.util.List;; - 类型推断:null →
Object、整数 →Long、小数 →Double、布尔 →Boolean、字符串 →String、数组按元素类型推导List<T>; - 混合类型数组使用
Object(List<Object>); - 关键字处理:字段名命中 Java 关键字(
class、new、record等,内置javaKeywords集合)时,转换为合法标识符(如class→classValue); - 命名冲突处理:字段重名追加数字后缀(
a_b与a-b都转成下划线形式时,后者变为a_b2);类名与String、List、Object、Boolean、Long、Double等内置类型冲突时追加数字后缀(Root与List冲突时生成List2,嵌套String类变成String2),逻辑由unique(base, used)与occupiedTypes集合实现; - 嵌套对象生成为
public static class内部类,类名遵循驼峰命名(toPascalCase)。
测试 CoreTests.swift 的testJSONNativeXMLAndJavaConversions与testJSONNativeEscapesAndKeyValueSwap完整覆盖了上述规则,包括{"string":{...},"list":[...],"object":{...}}用类名List时的多层重命名。仓库本机另用javac实际编译辅助进程生成的 Java 文件,覆盖关键字、字段重名、嵌套类型、混合数组和 String/List/Object 命名冲突,确保生成源码可编译。
工作区与文档库边界
- 窗口间同步正文:多个窗口编辑同一文档时正文保持同步;撤销记录属于当前编辑器,其他窗口写入正文时会清理本窗口可能已过期的撤销记录;重启不恢复撤销栈;
- Monaco 尚未移植:Monaco 编辑器的全部快捷操作、折叠和编辑装饰尚未移植到原生版;
- 文档库生态:JSON 文档支持镜像到
json-vault/、FSEvents 监听外部改动、Finder 定位,以及 Vault Git 面板(Diff、丢弃、合并 / 变基与冲突处理),与 Electron 的差异见 parity.md。
验证体系
原生 JSON 引擎的验证分三层:
- 核心测试:
MooToolNextCoreTests对照 Electron 输入输出用例,覆盖通配符、递归、筛选、切片、联合查询、特殊键路径、重复键、XML 拒绝项(DTD / 实体 / 语法错误)、Java 命名、Unicode 查找替换、工作区兼容,以及辅助进程超时和取消(见 CoreTests.swift 的testJSONNativePathsMatchElectronQueries、testJSONNativeXMLAndJavaConversions、testJSONNativeFindReplaceUnicodeAndFlags、testJSONWorkerTimeoutCancellationAndIsolation等用例); - javac 实编译:对
jsonToBean生成的 Java 文件用本机javac实际编译,覆盖关键字、字段重名、嵌套类型、混合数组与命名冲突场景; - 原生验收:发送格式化快捷键并操作实际编辑器,验证原地修改、自动保存、撤销/重做、结果弹窗、使用结果、输入转换及文档切换;再通过新进程检查工作区恢复。界面截图覆盖检查器、查找栏、路径选择器、结果弹窗及深浅色 / 窄窗口。需要说明的是,截图成功不等于所有菜单和系统对话框均已做端到端验证。
小结
MooTool Next 原生版的 JSON 引擎是一套"算法同源、执行隔离、行为对齐"的架构:算法层直接继承 Electron 版的jsonTools.ts逻辑并以JSONTools.js独立维护,执行层利用系统 JavaScriptCore 与独立辅助进程实现离线解析与安全隔离,交互层以 SwiftUI / AppKit 原生控件对齐 Electron 工作区。对于需要移植复杂 Web 工具到桌面原生平台的开发者,其"浏览器发行文件随包分发 + 临时文件传参 + 双层超时 + 三语错误"的组合方案具有直接的参考价值。完整边界说明见 json-engine.md,功能对齐总表见 parity.md。
- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
相关推荐
告别模糊视频:Video2X如何用AI智能提升画质和流畅度
告别模糊视频:Video2X如何用AI智能提升画质和流畅度 你是否曾因模糊的老旧家庭录像而遗憾?是否下载过低分辨率影片却无法享受高清体验?传统视频放大技术只是简
音视频视频处理图像处理人工智能MooTool Next Compose:用 Compose Multiplatform 构建独立桌面工具集的工程实践
MooTool Next Compose:用 Compose Multiplatform 构建独立桌面工具集的工程实践 本文基于仓库中的 next compos
桌面应用开发工具caveman cacheengine:独立运行的 Provider 原生 Prompt Cache 规划器与 Wire 引擎深度解析
caveman cacheengine:独立运行的 Provider 原生 Prompt Cache 规划器与 Wire 引擎深度解析 本文围绕 caveman
人工智能AI 应用AI Agent提示工程开发工具MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考