Plate Autoformat 运行时对齐与扩展:从 insertText 规则引擎到 feature 插件 inputRules 的架构演进
Plate Autoformat 运行时对齐与扩展从 insertText 规则引擎到 feature 插件 inputRules 的架构演进【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plateAutoformat自动格式化一直是富文本编辑器中最“好用但也最容易被误解”的能力用户敲下#、**、-时希望立即得到结构化结果而编辑器工程团队则需要在“哪一行代码拥有这条规则”上达成共识。本文以 docs/plans/2026-04-10-autoformat-runtime-alignment-and-extension-plan.md 为核心骨架讲解 Plate 项目如何把混杂在应用层app kit里的 autoformat 规则重新对齐到共享包与 feature 插件的边界上谁拥有 block shorthand、谁拥有 mark closure、谁拥有文本替换、谁负责 Enter 耦合的“后续键”流程以及最终落地为inputRules声明式运行时。读完本文你将掌握这套所有权划分模型、五个工作流与五个积压切片的内容并能对照 packages/autoformat/CHANGELOG.md 的迁移映射完成旧规则到新运行时的手工迁移。一、问题框架运行时里混着的三种形态计划文档开门见山地指出editor-behavior 规范下文简称“law”已经变得诚实但运行时仍然把三种不同形状的东西混在同一个引擎里干净的单词触发 shorthand例如#转标题、**闭合加粗这类行为platejs/autoformat包原本就建模得很好当前 app-kit 的怪癖例如依赖规则数组顺序、依赖自定义format回调才能工作的行为Typora 式 follow-up-key 流程例如输入$$之后再按 Enter 才触发块级数学这类行为本质上根本不是“单词触发的 autoformat”。如果不先把边界画清楚就把所有东西硬塞进platejs/autoformat包结果只会“重新发明一个更大的应用局部规则堆”原文re-invent a bigger pile of app-local rules。这正是这份计划存在的理由在动手改代码之前先完成所有权与运行时的对齐。二、需求摘要与明确非目标计划对本次工作定义了 7 条硬性要求运行时与最新编写的 autoformat law 对齐block、mark、text-substitution 三个家族在代码与测试中保持彼此独立在共享包或 helper 能干净持有行为的地方减少 app-kit 中的“民俗代码”folklore不假装所有 Typora 式触发都属于当前仅支持insertText的 autoformat 引擎保留现有的 invalid-match、转义escaping与代码块 gating 行为在触发重叠处显式声明优先级precedence增加足够测试使未来新增规则不会在无意中重排或破坏既有行为。同时计划明确列出 5 条非目标防止范围膨胀不从头重开整个 editor-behavior law不把每一个可选输入辅助面强行塞进 core-major 发布门禁不在本计划中解决搜索/查找替换、工具栏命令或斜杠菜单插入不指望一次性在所有地方做到 Typora 级完美不把 Enter 耦合的提升promotion当作又一个文本触发规则。三、关键决策不是所有“autoformat”都属于platejs/autoformat整份计划的核心结论只有一句话所有权必须显式划分。划分结果如下。A.platejs/autoformat拥有的单词触发single-keystroke的insertText驱动的 block shorthand单词触发的 markdown 定界符 mark 闭合单词触发的文本替换可逆文本替换原enableUndoOnDelete见下文落地后的内置化说明显式的规则优先级与上下文 gating。B. 邻近共享 input-rule / key 行为拥有的$$后按 Enter 的块级数学提升Typora 式代码围栏或主题分隔线随 Enter 触发如果决定改为这种形态而不是保留当前的即时转换任何依赖“超过当前插入字符与局部文本匹配”的流程。这类行为可以放在platejs/autoformat下的共享 input-rule 基础设施里、platejs/core的 key 行为里或归属的功能包如 code-block、math 包里但绝不能放进普通AutoformatPlugin的派发循环。四、计划落地后的仓库现状Status: Executed计划文档开头标注的状态是Executed已执行并给出了关闭后的所有权归属清单共享包拥有heading shorthand、inline mark autoformat、text substitution显式应用层拥有current-kit 行为blockquote wrap、list 与 condensed todo shorthand、code-block gating、immediate code-fence promotion、immediate HR insertion不在普通 autoformat 家族内link automd后续邻近 input-rule 跟进Enter 拥有的 code-fence 或 HR 提升。在当前的 packages/autoformat/src/plugin.ts 中可以看到这一落地的直接证据AutoformatPlugin现在是一个惰性兼容插件源码注释明确写道“故意不活跃intentionally inert”并指引开发者把规则注册到拥有该功能的 feature 插件上platejs/basic-nodesHeadingRules、BlockquoteRules、mark 规则platejs/code-blockCodeBlockRulesplatejs/list/platejs/list-classic列表规则工厂局部文本替换createTextSubstitutionInputRule。4.1 从旧AutoformatRule到新inputRules的迁移映射packages/autoformat/CHANGELOG.md 的 53.0.0 版本条目完整记录了旧规则到新规则工厂的一一映射这是把计划落成代码的“对照表”摘录核心几组基础块platejs/basic-nodes旧规则新规则{ match: # ..###### , mode: block, type: KEYS.h1..h6 }HxPlugin.configure({ inputRules: [HeadingRules.markdown()] }){ match: , mode: block, type: KEYS.blockquote }BlockquotePlugin.configure({ inputRules: [BlockquoteRules.markdown()] }){ match: [---, —-, ___ ], mode: block, type: KEYS.hr }HorizontalRulePlugin.configure({ inputRules: [HorizontalRuleRules.markdown({ variant: - }), ...] })基础 markplatejs/basic-nodes旧规则新规则拥有插件{ match: **, mode: mark, type: KEYS.bold }BoldRules.markdown({ variant: * })BoldPlugin{ match: __, mode: mark, type: KEYS.underline }UnderlineRules.markdown()UnderlinePlugin{ match: , mode: mark, type: KEYS.code }CodeRules.markdown()CodePlugin{ match: ~~, mode: mark, type: KEYS.strikethrough }StrikethroughRules.markdown()StrikethroughPlugin{ match: , mode: mark, type: KEYS.highlight }HighlightRules.markdown({ variant: })HighlightPlugin{ match: ***, mode: mark, type: [bold, italic] }MarkComboRules.markdown({ variant: boldItalic })BoldPlugin代码块platejs/code-block{ match: , mode: block, type: KEYS.codeBlock, ... }→CodeBlockPlugin.configure({ inputRules: [CodeBlockRules.markdown({ on: match })] })。列表platejs/list/platejs/list-classic旧规则新规则{ match: [- , * ], mode: block, format: toggleList(...) }BulletedListRules.markdown({ variant: - })、BulletedListRules.markdown({ variant: * }){ match: /^\d\.$|^\d\)$/, matchByRegex: true, ... }OrderedListRules.markdown({ variant: . })、OrderedListRules.markdown({ variant: ) }){ match: [] , mode: block, ... }TaskListRules.markdown({ checked: false }){ match: [x] , mode: block, ... }TaskListRules.markdown({ checked: true })数学platejs/math行内$…$→MathRules.markdown({ variant: $ })块级$$…$$→MathRules.markdown({ on: break, variant: $$ })——注意这里on: break正是计划中“Enter 耦合提升不属于普通 autoformat 家族”论断的代码体现。链接platejs/linktextmarkdown →LinkRules.markdown()粘贴/空格/回车自动链接 →LinkRules.autolink({ variant: paste | space | break })。这与计划 Slice 4“把 link automd 留在链接/源录入车道”一致。自定义规则旧AutoformatRule对象没有直接替代品改用createRuleFactory自建规则家族import { createRuleFactory } from platejs; const MyRules { markdown: createRuleFactory({ type: blockMatch, match: !! , format: my-block, }), }; MyPlugin.configure({ inputRules: [MyRules.markdown()] });4.2 文本替换的新写法旧的符号替换表箭头、分数、法律符号、数学运算符、智能引号等迁移为本地createSlatePlugin上的createTextSubstitutionInputRuleimport { createSlatePlugin, createTextSubstitutionInputRule, KEYS, } from platejs; const isTextSubstitutionBlocked (editor) editor.api.some({ match: { type: [editor.getType(KEYS.codeBlock)] } }); const ShortcutsPlugin createSlatePlugin({ key: shortcuts, inputRules: [ createTextSubstitutionInputRule({ enabled: ({ editor }) !isTextSubstitutionBlocked(editor), patterns: [ { format: →, match: - }, { format: ⇒, match: }, { format: ½, match: 1/2 }, { format: ™, match: [(tm), (TM)] }, { format: [“, ”], match: }, ], }), ], });注意enabled回调中通过editor.api.some({ match: { type: [codeBlock] } })实现的代码块 gating——这正是计划反复强调“保留 code-block gating 行为”的落地形态旧选项enableUndoOnDelete被移除因为在规则插入的节点上按 Backspace 恢复源文本已成为内置默认行为。在应用注册表侧apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx 中的AutoformatKit把 13 组文本替换族打包成一个插件autoformatShortcuts箭头arrows、比较符comparisons、等号equality、分数fractions、法律符号legal / legalHtml、运算符operators、标点punctuation、智能引号smartQuotes、下标数字/符号subscriptNumbers / subscriptSymbols、上标数字/符号superscriptNumbers / superscriptSymbols全部通过同一个createAutoformatTextSubstitutionRulehelper 统一注入isTextSubstitutionBlockedgating。五、五个推荐工作流计划把执行拆成五个并行/串行的工作流Workstream每个都有明确目标、实现单元与主文件。Workstream 1运行时真值表Runtime Truth Table目标停止抽象争论“什么是 autoformat、什么是当前 kit 行为”用测试把当前实际行为钉死。覆盖的行包括标题、含嵌套引号进入的 blockquote、无序/有序列表 shorthand、condensed todo shorthand、代码围栏触发、HR 触发、mark 闭合、invalid mark 用例、智能引号/标点/符号、代码块 gating。同时要求测试命名与 markdown-editing-spec.md 中的 spec ID 对齐。计划列出的主文件当前仓库中platejs/autoformat已重构原lib/下实现已迁移到platejs/core的 input-rules 运行时测试文件相应落在各自 feature 包内如packages/basic-nodes/src/lib/BaseMarkInputRules.spec.tsx、packages/basic-nodes/src/lib/BaseHeadingInputRules.spec.tsx、packages/basic-nodes/src/lib/BaseBlockquoteInputRules.spec.tsx、packages/code-block/src/lib/BaseCodeBlockPlugin.inputRules.spec.tsx、packages/list/src/lib/inputRules.spec.tsx、packages/math/src/lib/inputRules.spec.tsx以及计划指定的应用集成测试apps/www/src/__tests__/package-integration/autoformat/blockquote.slow.tsx、apps/www/src/__tests__/package-integration/autoformat/list.slow.tsx。为什么放第一位先锁行为再动所有权让后续规范化是“显式的”而不是“意外的”。Workstream 2共享包边界Shared Package Boundaries目标把明显共享的行为从应用民俗中搬进共享包但只搬“共享包 API 能干净持有”的部分。提升为共享规则族headings、list shorthand、常见 mark 闭合、智能引号/标点/法律/箭头/数学符号表保持显式应用级blockquote wrap 语义、condensed todo shorthand、immediate code-fence promotion、immediate HR insertion。主文件packages/autoformat/src/lib/rules/**、apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx。交付物是“包拥有的规则表”与“应用拥有的产品决策”之间的干净拆分。Workstream 3Autoformat 引擎扩展目标只在“当前引擎形状确实是阻塞点”的地方扩展platejs/autoformat。列出的候选扩展点显式规则家族元数据block shorthand / mark autoformat / text substitution / 可选产品专属家族显式优先级——停止依赖数组静默顺序解决这类冲突给query/format回调传递更丰富的上下文——当前块 owner、最近容器、是否命中块起始匹配、可选的 feature flags/profile 选项block shorthand 的共享 helper 路径——retag block、wrap container、build list item / restart number、insert new owned block包表面更好的当前契约文档——包保证什么、刻意不建模什么。同时强调约束不要一次性膨胀成完整的 profile 引擎重写只落地让所有权与优先级显式化的最小扩展集。从当前仓库形态看这一工作流的最终走向是“把引擎能力下沉到platejs/core的 input-rules 运行时、并在各 feature 包以*Rules工厂形态暴露”而不是在platejs/autoformat里继续堆配置。Workstream 4邻近输入规则车道Neighboring Input-Rule Lane目标处理那些“本质上不是单词触发 autoformat”的用例候选面包括$$ Enter 的块级数学提升、 Enter 的代码围栏提升若未来选择 Typora 风格、Enter 触发的主题分隔线若未来选择该形态。推荐做法除非出现极小的共享接缝否则不要放进platejs/autoformat的第一轮扩展而是作为所属车道platejs/autoformat的共享 input-rule 运行时、core key 行为、code-block 包、math 包的邻近 key/input 规则来设计与实现复用同一套 spec ID 与家族命名但不伪装包所有权。原因很简单当前AutoformatPlugin围绕“一个插入字符 局部文本匹配”构建而 Enter 耦合的提升是另一类交互。Workstream 5公开文档与面向用户的契约目标让公开的/docs/autoformat故事与新 law/runtime 同步。需要更新的内容包括三个家族、可选的 profile-adjacent 性质、当前 app-kit 行为中哪些是包级、哪些是应用级在“Plate 自有 shorthand非通用 markdown 惯例”处添加重叠警告包 API 变化时同步包文档与示例。落地后的公开文档位于 content/docs/(plugins)/(functionality)/autoformat.mdx/(functionality)/autoformat.mdx)页面标题即“Markdown shortcuts and text substitutions powered by input rules”其特性清单明确写着“由理解它们的 feature 插件拥有 markdown 快捷方式”“无隐藏默认快捷行为”与计划的“包级/应用级边界诚实化”目标一一对应。六、即时积压切片Immediate Backlog Slices计划强调这些是“按顺序执行的切片”不是松散的后续事项Slice 1运行时真值表锁定——为所有已规范的 block/mark/text 行写 truth-table 测试、为这类重叠触发写优先级测试、提供 code-block gating 证明理由在测试锁死当前行为之前不做任何规范化或包抽取。Slice 2共享 Autoformat 边界清理——把明显共享的规则表/helper 移入稳定的包级导出目标行是 block shorthand 标题/列表、常见 mark 闭合、智能引号/标点/符号表。Slice 3文本替换权威性收尾——智能引号、em dash、省略号、角引号保持在“主流输入规范 当前测试”的强地基上箭头、法律符号、分数、运算符替换、unicode 上下标 shorthand 则显式标注为“较薄的本地契约”除非出现更强外部权威目标行EDIT-PROFILE-AUTOFMT-TEXT-001至004。Slice 4Link Automd 车道——把text留在普通 autoformat 家族之外要么作为 link/source-entry 面的产品化功能上线要么保持延期但包接缝与文档边界都要诚实不冒充当前 autoformat 支持目标行EDIT-INTERACT-LINK-AUTOMD-001。Slice 5当前 kit 规范化——[]/[x]保持为 Plate 自有的 condensed todo 便利除非产品主动收窄immediate code-fence promotion 与 immediate HR insertion 作为当前 kit 偏差向 Enter 拥有的邻近 input-rule 车道规范化目标行EDIT-PROFILE-AUTOFMT-BLOCK-004至006。七、验收标准与测试计划验收标准每一条已规范的 autoformat 行都能用“共享包当前契约 / 显式应用产品选择 / 邻近 input-rule 车道”之一描述重叠触发优先级在代码与测试中显式invalid-match 护栏保持覆盖code-block gating 保持覆盖公开 autoformat 文档不再暗示所有 shorthand 行为是一个通用包特性如果保留 condensed todo shorthand、immediate code-fence promotion 等当前偏差计划/结果必须显式说明而不是把它们当成 markdown 标准。测试计划包测试packages/autoformat/src/lib/AutoformatPlugin.spec.tsx、packages/autoformat/src/lib/transforms/*.spec.ts、packages/autoformat/src/lib/__tests__/withAutoformat/**/*.spec.tsx对应到当前仓库即各 feature 包的*InputRules.spec.tsx与platejs/core的createTextSubstitutionInputRule.spec.ts、createRuleFactory.spec.ts等。新增或扩展优先级冲突测试、家族元数据/优先级测试若引入、更丰富的 query/context 测试若引入、代表性文本替换的 undo-on-delete 测试。应用集成测试apps/www/src/__tests__/package-integration/autoformat/blockquote.slow.tsx、list.slow.tsx并新增三条当前 kit 代码围栏行为、当前 kit HR 行为、当前 kit 代码块 gating。文档验证代码形态定型后重读 standards/spec/protocol/parity/audit 文档并按真实运行时重读/docs/autoformat与示例。八、风险与缓解风险缓解过度设计包架构文档已想要 profile-aware 重写但现在全做会爆炸范围把 profile-aware 重写当作方向而非即时范围只落地当前家族所有权与优先级所需的最小扩展集“规范化”时破坏现有 app-kit 行为app kit 已发布真实行为即使有怪癖先锁 truth-table 测试再逐行显式决策地规范化把 autoformat 与 Enter 拥有的提升混为一谈最容易犯的概念性错误insertText驱动与Enter驱动分工作流要求每一行显式声明所有权符号替换的权威性薄弱部分符号表目前主要是本地契约显式标注为较薄权威不当作通用 markdown/编辑器真理来过度推销九、推荐执行排序锁定运行时 truth-table 测试把明显共享的规则表/helper 从应用民俗中搬出若测试证明确实需要再在platejs/autoformat增加显式优先级与更丰富的 query/context 支持Enter 耦合提升作为后续车道除非自然出现微小共享接缝最后同步公开文档——等运行时边界真实落定后再写。计划还提供了两条可直接执行的命令面向仓库内部工作流$ralplan --consensus --direct docs/plans/2026-04-10-autoformat-runtime-alignment-and-extension-plan.md $ralph Execute docs/plans/2026-04-10-autoformat-runtime-alignment-and-extension-plan.md十、从源码看新运行时input-rules 函数族计划执行后运行时核心落在 packages/core/src/lib/plugins/input-rules/createInputRules.ts它按“目标事件 匹配 应用”三段式建模与计划的三家族划分一一对应createBlockStartInputRuleblock shorthand通过matchBlockStart取块起始区间与文本支持字符串精确匹配与正则匹配apply阶段按wrap/toggle/setNodes三种模式处理——其中wrap模式对应计划强调的“blockquote 必须包裹嵌套引用”这类容器规则区别于普通的 flat block retag。createMarkInputRulemark closure通过getMarkMatch在选区前寻找起始定界符与可选的结束定界符skipInvalid: true跳过无效匹配并通过isPreviousCharacterEmpty要求定界符前为空字符apply阶段删除定界符、addMark施加格式并removeMarks收尾——这就是计划中“invalid-mark guardrails 保持覆盖”的代码级实现。createBlockFenceInputRule代码围栏on: match走insertText目标、以围栏最后一个字符为 triggeron: break走insertBreak目标——后者的存在直接印证了计划“Enter 耦合提升属于邻近车道”的结论代码块与数学包的on: break配置正是该车道的落地。createTextSubstitutionInputRule文本替换compilePatternsByTrigger预先按 trigger 字符建索引resolveTextSubstitution依次尝试同 trigger 的候选 pattern这正是“重叠触发优先级显式化”的实现位置applyTextSubstitution支持format为字符串或[起始, 结束]配对智能引号[“, ”]即此形态matchDelimitedInline则提供定界符内联匹配的独立路径。从packages/autoformat/src/plugin.ts的注释、packages/autoformat/CHANGELOG.md的 53.0.0 迁移说明、以及 apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx 的AutoformatKit实现可以看出这份计划不是停留在纸面的蓝图而是已经闭环执行的架构决策。旧的AutoformatPlugin规则引擎被 feature 插件自带的inputRules声明式运行时取代platejs/autoformat退化为惰性兼容导出而文本替换、代码块 gating、undo-on-delete 等能力以更小、更内聚的工厂函数沉淀在platejs/core与各 feature 包中——这正是“运行时对齐 扩展”计划的最终交付物。延伸阅读markdown-editing-spec.md把 autoformat 视为三个 profile-adjacent 家族的规范依据editor-protocol-matrix.mdblock shorthand、inline mark、text substitution、undo-on-delete、code-block gating 的协议行markdown-parity-matrix.md这些表面作为可选 current-kit 行为、不进入 core-major 门禁的奇偶校验markdown-shorthand-and-inline-autoformat.md 与 input-autoformat-lanes.mdTypora 与 Milkdown 的权威性研究autoformat-families-are-profile-adjacent-input-assist-surfaces.md 与 text-substitution-autoformat-authority.md所有权拆分与文本替换权威性blockquote-autoformat-must-wrap-nested-quotes.mdwrapper/container 规则不能当作 flat block retag 的最强应用侧教训【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →