Slate v2 `core.ts` 彻底解剖实战:一方法一文件的引擎级代码拓扑重构方案

📅 发布时间:2026/9/16 11:26:22
Slate v2 `core.ts` 彻底解剖实战:一方法一文件的引擎级代码拓扑重构方案
Slate v2core.ts彻底解剖实战一方法一文件的引擎级代码拓扑重构方案【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate本文基于 docs/plans/2026-04-10-slate-v2-core-ts-complete-dissection-plan.md 展开。该文档是 plate 仓库中 Slate v2 引擎对core.ts单体文件进行的“彻底解剖”计划把所有值得独立成路径的公共/核心行为拆到src/core/*本仓库中落地为src/internal/*与src/interfaces/*让core.ts不再隐藏主要导出运行时行为、删除死的兼容路径并以“一方法一文件”的拓扑维护引擎公共面。读完本文你将掌握这套代码解剖的目标、治理规则、决策矩阵、四阶段执行顺序、逐片验证流程与完成判定标准并能对照当前仓库packages/slate/src的实际结构确认拆分的落地结果。背景为什么必须对core.ts做“彻底”解剖Slate 早期将引擎核心运行时逻辑集中在一个core.ts大文件中事务入口、ref 重定位、脏路径处理、规范化、快照发布、fragment 容器插入栈等行为全部交织在同一主体内。这种“omnibus 文件”带来的问题在引擎重写方向上会被持续放大公共/核心行为没有独立归属路径改动一处牵动全局文件树与真实所有权不一致core.ts成为“隐藏的真正所有者”死掉的兼容路径以“假所有权”的形式被保留维护者难以判断哪些逻辑还活着跨路径共享的基础代码变成偶然的“万能文件”而不是被显式声明的内部支撑模块。该计划的Goal非常明确完成对core.ts的解剖而不是半途而废。其终态end state有三条每个值得拥有独立路径的公共/核心行为都落在src/core/下的独立文件里core.ts不再隐藏任何主要的导出运行时行为死的兼容路径被直接删除而不是作为“假所有权”保留跨多个路径文件共享的 helper/基础设施代码可以继续共享但必须被显式当作内部支撑internal support而不是偶然的 omnibus 所有者。治理规则只保留能强化“更好引擎方向”的漂移解剖不是机械的文件搬家。文档给出了一条Governing Rule治理规则只保留能强化更好引擎方向的漂移其余一律回退。所谓“更好引擎方向”共五条data-model-first数据模型优先operation- and collaboration-friendly面向操作与协作友好transaction-first engine semantics事务优先的引擎语义React-optimized runtime面向 React 优化的运行时explicit adapters later显式适配器后置。对于packages/slate/src/**的具体适用规则是公共/核心表面代码保持one-file-per-method 拓扑一方法一文件如果某项漂移不能明确支持上述更好引擎方向就回退它当某个路径被设定为“真实所有者”时绝不允许留下假包装fake wrapper伪装所有权绝不为了“让文件树看起来眼熟”而发明死的兼容文件。当前状态盘点已经抽出与已经剪除的路径文档将解剖进度分为三类逐文件登记。这是理解整个拆分工作的“存量账本”也是后续任何切片slice都必须对照更新的基准。已抽入真实src/core/*所有者的文件公共/核心运行时表面中以下行为已拥有独立所有权文件行为说明apply.tsapply(editor, op)入口其余逻辑委托给withTransaction(...)、getState(...)、applyOperation(...)get-dirty-paths.ts脏路径收集本地 path helpers 直接后代收集替代旧Path.levels/Path.ancestors/Node.nodes命名空间调用get-fragment.ts直接从当前快照/树形结构切片 fragment不再委托Node.fragment(editor, selection)normalize-node.ts收窄为当前模型explicit通道、直接子节点校验、inline 兼容后代收集、局部fallbackElement处理should-normalize.ts删除旧的initialDirtyPathsLength最大迭代守卫仅保留当前默认return trueget-current-node.ts/get-current-selection.ts/get-current-marks.ts/get-current-children.ts/get-current-range-for-path.ts/get-current-index.ts/get-current-replace-epoch.ts当前运行时读取面此前全部埋在core.ts内get-snapshot.ts/replace-snapshot.ts快照读取与替换replaceSnapshot(editor, input)subscribe.tssubscribe(editor, listener)订阅面set-current-marks.tssetCurrentMarks(editor, marks)get-range-refs.ts/range-ref.tsgetRangeRefs(editor)与rangeRef(editor, range, affinity)initialize-editor.tsinitializeEditor(editor)初始化面已抽入显式内部支撑模块的文件这些文件仍被多个路径文件共享但它们本身不是用户视角下的“行为名”因此作为显式 internal support 存在path-helpers.ts路径/点比较、range 边界解析、path-key 生成node-helpers.ts节点克隆、属性拷贝、后代切片、path→node 遍历draft-helpers.tsdraft 克隆、draft-index 创建、快照物化、draft 子节点遍历transaction-helpers.ts规范化入口收集、自定义 normalizer 循环、已创建 range-ref 发布、快照发布fragment-rebase-helpers.ts折叠插入 rebase、range 替换 rebase、move-target 调整、scratch-editorinsert_fragment模拟fragment-helpers.tsremove-node 选择回退、混合 inline/block 容器分析、fragment slice/split、insertFragment*执行栈。已作为死路径剪除的文件batch-dirty-paths.tsupdate-dirty-paths.ts这两条路径只在当前引擎重新使用它们时才允许恢复否则视为死的兼容路径。仍直接留在core.ts中的内容按文档记录core.ts中仅剩共享类型声明与INTERNAL状态不再有任何主要导出运行时行为主体。决策矩阵哪些该共享、哪些该成为真实所有者文档的Decision Matrix把待处理项分成两类避免“为了美学把每个微小 helper 都拆成文件”的反模式。A 类应成为显式内部共享模块而不是留在core.ts这些逻辑仍被多个已抽出路径文件需要但它们不是评审者视角下的行为名混合 inline 与 block 容器的 fragment 支持fragment slice/split helpersinsert-fragment rebasing helpersscratch-editor fragment 模拟。推荐去向packages/slate/src/core/下一个显式内部支撑文件工作名即fragment-helpers.ts。规则明确警告如果只是把每个微小 helper 拆成独立文件而没有任何语义增益就不要拆。B 类剩余的、真实的导出核心所有者该 tranche 已全部完成共四个文件get-state.ts内部状态查找抽出后的核心文件直接调用step-current-point.tsbefore(...)/after(...)跨受支持顶层文本块的 point 步进apply-operation.ts事务 draft 上的原始 operation 应用仍是apply(...)下的独立步骤with-transaction.ts事务进入/退出、显式规范化设置、发布时序。执行顺序四个阶段的解耦策略解剖被拆成四个阶段每个阶段解决一类问题Phase 1冻结当前 tranche保持已抽出文件全绿测试通过除非当前引擎真的再次使用否则不重开任何死路径任何路径状态变化时立即同步更新pr-description.md本仓库对应文件为 docs/slate-v2-draft/references/pr-description.md它是面向维护者的 drift 登记册。Phase 2把导出的运行时所有者移出core.ts按此顺序执行get-state.ts→step-current-point.ts→apply-operation.ts→with-transaction.ts。理由这四者正是让core.ts仍像“真正所有者”的导出运行时件优先移动它们能在不强迫先把每个微小 helper 单独成文件的前提下获得最大的“真相收益”。Phase 3从core.ts中雕出内部共享 helpers状态文档记录时path helpers、node helpers、draft/snapshot helpers、transaction publish helpers、fragment rebasing/simulation helpers、混合 inline/block fragment helpers、fragment slice/split helpers、fragment insertion helpers 均已完成。规则按连贯的职责分组避免“每个琐碎 helper 一个文件”的无意义碎片化保持 import 简单、明显。Phase 4压平core.ts完成态判定core.ts变为显式导出表面不再是引擎的真正居所不存在兜底的export *每个 re-export 都指向真实的 owner/support 文件。明确禁止的事项What not to do文档用负面清单锁死边界不要恢复batch-dirty-paths.ts、update-dirty-paths.ts这类死路径除非当前引擎真的再次使用它们不要为了达成审美理想而逐个抽取微小 helper不要为公共/核心行为名留下假包装fake wrappers不要在路径文件存在后仍把core.ts当作秘密的真正所有者。每个提取切片的验证规则文档强调“切片必须有验证”每个 slice 都要执行五步读取目标文件的精确 git diff确认新 owner 文件包含真实逻辑而不是 shim 桩对受影响文件及其直接调用者重跑一次窄范围 TypeScript 探针tsc --noEmit --skipLibCheck --target es2022 --module esnext --moduleResolution bundler ...在pr-description.md中记录具体的 old-vs-current 文件漂移如果某个路径经核查并非当前真实概念就剪掉它而不是保留成“兼容剧场”compatibility theater。完成判定标准解剖只有在以下条件全部满足时才宣告完成core.ts不再包含任何主要导出运行时行为主体每个存活的导出src/core/*路径都是真实所有者死的兼容路径全部消失pr-description.md逐文件具体解释了存活的漂移维护者文档中不再有任何一行仍在使用假的 “owns logic” 填充语。当前仓库的落地印证从计划到packages/slate/src解剖计划在本仓库已经落地为实际的目录结构。对照 packages/slate/src/index.ts 可以看到包的导出表面由create-editor、slate-dom、types、interfaces、slate-history、utils组成不存在一个居中承担全部运行时行为的core.ts。具体印证点包括一方法一文件拓扑运行时方法各自拥有独立文件。例如编辑器查询面在 packages/slate/src/internal/editor/ 下有getMarks.ts、getFragment.ts、normalizeNode.ts、normalizeEditor.ts、above.ts、getPointBefore.ts等转换面在 packages/slate/src/internal/transforms/ 下有deleteText.ts、insertFragment.ts、insertNodes.ts、setSelection.ts、mergeNodes.ts等扩展转换面在 packages/slate/src/internal/transforms-extension/ 下有toggleBlock.ts、toggleMark.ts、duplicateNodes.ts等。显式导出表面而非export *create-editor.ts通过bindFirst把每个独立模块的方法装配到 editor 实例见 packages/slate/src/create-editor.ts例如getMarks: bindFirst(getMarks, editor)、insertFragment: bindFirst(insertFragment, editor)、setSelection: bindFirst(setSelection, editor)与计划“每个 re-export 指向真实 owner 文件”的 Phase 4 终态一致。从internal/transforms/setSelection.ts的源码可以看到薄包装形态setSelection内部委托给从slate导入的setSelection as setSelectionBase路径文件负责所有权、实现留在内核。接口命名空间拆分类型与守卫由 packages/slate/src/interfaces/ 下的path.ts、point.ts、range.ts、location.ts、node.ts、text.ts、element.ts、operation.ts等分别持有编辑器 API 形状集中在 packages/slate/src/interfaces/editor/editor-api.ts其中显式列出fragment、getDirtyPaths、getFragment、setNormalizing、shouldNormalize等当前运行时表面方法。测试佐证packages/slate/src/create-editor.spec.ts 验证了“方法所有权与实例装配”这一解剖的直接结果——例如expect(editor.getMarks).toBe(editor.api.marks)、expect(editor.insertText).toBe(editor.tf.insertText)以及withHistory包装后editor.undo/redo/apply与editor.tf的对应关系。漂移登记册文档要求同步维护的pr-description.md在本仓库对应为 docs/slate-v2-draft/references/pr-description.md其中逐文件登记了packages/slate的 121 个变更根/源文件与 1048 个删除测试文件的归属理由并明确写着core.ts“被缩减为共享核心类型、INTERNAL状态与显式 re-export文件树终于与运行时逻辑的真实所在位置一致”正是本计划 Phase 4 终态的注脚。对后续维护者的实践启示这套解剖方案的价值不在于“把大文件拆小”本身而在于它建立了一套可重复的判定闭环治理规则决定是否允许漂移 → 决策矩阵决定文件归属真实 owner 还是内部 support→ 四阶段顺序控制解耦节奏 → 五步验证规则保证每个切片都有 diff、类型探针与登记册背书 → 完成标准防止半途而废。对本仓库的 Slate v2 引擎而言它意味着任何新加的公共/核心方法都应直接落在自己的路径文件中共享基础设施必须显式声明为 internal support而任何无法证明自己还活着的兼容路径都应被剪除而非收藏。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考