# 源码优先

理解 Markdown、派生字段、组件视图和事务之间的关系。

## 一份持久内容

CodeMirror 文本是编辑器的内容权威。解析器和扩展从源码派生语法范围、字段及呈现；保存时读取当前 Markdown。

| 层 | 负责什么 |
| --- | --- |
| 编辑器核心 | 文本、选区、事务、历史、模式与生命周期 |
| 语法与字段 | 识别当前源码范围，读取字段，校验并编码精确修改 |
| 命令 | 描述源码操作，在一次事务中提交 |
| 组件与主题 | 显示内容、提供交互，通过受控动作请求修改 |
| 宿主应用 | 文件、存储、权限来源、上传服务和业务界面 |

## 从组件操作回到源码

以 `[[todo]]` 为例：语法确认 token 后，`read()` 派生 `{ value: 'todo' }`。组件请求 `{ value: 'done' }`，`patch()` 只替换括号内部的字段，最终源码成为 `[[done]]`。

这种操作与键盘输入共用历史，因此用户可以撤销组件按钮造成的修改。见[自定义节点](/extensions/custom-node)的完整实现。

## 语义与界面分别扩展

`Node.create()`、`Mark.create()` 和 `Extension.create()` 提供声明入口。可以先定义字段和命令，再由应用用 `.extend()` 添加 Vue、React 或原生 DOM 呈现。

这些声明当前不是 ProseMirror schema。`parseHTML`、`renderHTML`、`NodeViewContent` 等接口不能直接从 Tiptap 示例中搬入；请以 [API 参考](/api/editor)和[支持范围](/support)为准。

## 何时保留源码

未知、未闭合或暂时无法呈现的结构保留原文。自定义语法与资源加载也应明确回退行为，不能以隐藏原文代替解析成功。

## 与 AST 编辑器集成时的选择

解析树是可重新计算的索引，不能接替文本成为唯一存档。把 Markdown 转成 ProseMirror JSON、编辑后再序列化会改变可表示范围和原始拼写策略；这属于另一条内容管线，不是 MSFE 的透明内核。

若应用同时有富文本视图和源码优先视图，应明确转换边界、损失政策和每个编辑会话的权威来源，不让两份内容同时自动互相覆盖。当前文档只承诺本编辑器内的单一源码事务流。

## 复杂扩展的一次数据流

1. 用户输入进入 CodeMirror 文本与历史。
2. 增量解析确认语法范围；未确认部分仍显示源码。
3. codec 读取字段，投影描述视觉，组件只呈现收到的属性。
4. 组件操作通过命令或字段 patch 请求精确修改。
5. 编辑器校验当前意图、权限和范围，接受后通知宿主增量变化。
6. 宿主按自己的持久化协议保存 Markdown。

这个分工同时适用于简单状态标记、嵌套容器和异步图表；不同之处在于选择了哪些 [扩展入口](/concepts/extensions)。
