Plate 编辑器 Date 与 Media/Embed 扩展共识计划:源契约优先的架构升级实战指南
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
本文围绕 Plate(基于 Slate 的富文本编辑器,集成 AI 与 shadcn/ui)仓库中的 Date 与 Media/Embed 扩展共识计划 展开,系统讲解该计划如何将date节点与media/embed节点从"散落的字符串与隐式解析"升级为"显式、可往返、由 Plate 自主定标的源契约(source-canonical contract)"。读完本文,你将掌握:为什么toDateString()不是合格的长期数据格式、如何设计YYYY-MM-DD规范日期值与双读(dual-read)Markdown 线格式、媒体嵌入的信任边界(trust boundary)如何显式化,以及一套从契约决策、代码实现、测试覆盖到文档法(law)同步的完整落地路径。
计划定位:一份已经"部分兑现"的共识性架构计划
先明确该文档在仓库中的位置与状态。文档自述Status为:date 半程在历史意义上已经关闭(historical for the date half),media/embed半程仍在为活跃通道(active lane)提供背景上下文。因此这份文件有两个用途:
- 作为"窄契约(narrow contract)最终胜出"的历史理由记录;
- 作为 Lane 4 media/embed 后续工作的活动背景材料。
对照当前仓库源码,计划的 date 半程核心内容已经落地:例如 insertDate.ts 已通过normalizeDateValue写入规范值,dateValue.ts 已实现YYYY-MM-DD规范化、toDateString()旧格式兼容与无时区漂移解析。也就是说,这篇文章既是计划本身的解析,也是"计划如何演化为现实"的源码级印证。
任务定义:补齐 date 与 media/embed 两个通道的剩余扩展
计划的原始任务(Task)很明确:为文档描述中剩余的date与media/embed扩展批次创建真正的实施计划,并且必须扎根于当前的 law(行为规范文档)、research(研究文档)与 runtime(运行时源码),而不是凭空设计。
两条通道必须一起完成,而不是只做相对容易的 media 通道。原因在于:仓库的决策纪律要求"契约、代码、测试、文档四者同步更新",任何一条通道若只做表面修补,都会让另外一条通道的 schema 决策失去参照。
仓库现状(Repo Grounding):四份文档与六处源码共同定义的基线
计划用"现状即约束"的方式锚定实施范围,任何新契约都必须与以下基线兼容。这体现了 Plate 文档体系里"law(行为规范)—protocol(协议矩阵)—parity(对齐矩阵)—research(研究决策)—runtime(运行时代码)"五层互锁的方法论。
行为规范(law)层
- markdown-editing-spec.md 仍将
date锁定为node.date上的单一纯字符串载荷,Markdown 往返形态为纯<date>value</date>; - editor-protocol-matrix.md 将更丰富的 date 载荷标记为
deferred(延后),当前渲染行为仅标记为specified(已规定但未全面实现); - markdown-parity-matrix.md 将
Date与Media embed的窄契约标记为locked,更丰富的扩展仍停留在 feature-gap 行。
研究决策(research)层
- 既有扩展说明明确指出media 的扩展基础比 date 更坚实,见 2026-04-09-editor-spec-date-media-expansion.md;
- date 的开放问题文档承认:当前仓库尚无正当理由引入更丰富的载荷,见
docs/research/open-questions/date-mdx-payload-contract.md; - media 决策文档要求:更丰富的 media 应从创作(authoring)与路径策略(path-policy)、信任边界出发,而非仅仅追加新的 provider 字段,见
docs/research/decisions/media-authoring-follows-the-image-path-policy-family.md。
运行时(runtime)层
计划记录的历史现状(部分已被后续实现改变,但作为设计动因仍具参考价值):
- date 曾以
new Date().toDateString()存储,demo 渲染器从日历回写toDateString()(date-node.tsx、date-node-static.tsx); - Markdown 规则曾将 date 序列化为纯子文本
<date>元素(defaultRules.ts); - media/embed 规范化曾分散在多个原始字符串助手与提交时变更中:
parseIframeUrl.ts(packages/media/src/lib/media-embed/parseIframeUrl.ts)、parseVideoUrl.ts、parseTwitterUrl.ts,以及 submitFloatingMedia.ts; - markdown media 流规则在 mediaRules.ts 中为
audio/file/video保留属性,但 embed 特有的丰富元数据尚未一等公民化。
这些基线共同回答了"为什么不能继续在旧形态上叠加行为":在模糊的数据之上继续增加行为,只会产生更多没有 law 支撑的行为。
需求摘要:五条硬约束与四条硬性非目标
计划对本次扩展批次的全局要求可以归纳为五条:
- 双通道并行收尾:同时完成 date 与 media/embed,不允许只做容易的 media 通道;
- 源真值显式且可往返:source truth 必须显式化,并且能通过 Markdown/MDX 无损往返;
- 外部证据薄弱处由 Plate 自主决策:契约决策权归 Plate 自身,不等待外部标准;
- 渲染/UI 工作收敛:只做直接由源契约推导出的渲染行为,不为 UI 发明新规则;
- 四件套同步:代码、测试、editor-behavior law、面向用户的文档必须一起更新。
同时保持四条硬性非目标(non-goals),任何方案都不得触碰:
- 不允许任意脚本嵌入(no arbitrary script embeds);
- 不支持 PDF 嵌入(no PDF embed support);
- 不做重 locale / 重 timezone 的日期 UX;
- 不开 preview-first 的产品通道。
方案选型:RALPLAN-DR 给出的三个选项与推荐
计划使用 RALPLAN-DR 方法做决策,先立原则,再比较选项。
五条设计原则
- 规范载荷优先于渲染便利(Canonical payload beats render convenience);
- 在共享功能包中规范化,而非在应用级 demo 渲染器中;
- Markdown 规则应往返一个刻意的 schema,而非偶然的原始字符串;
- 嵌入输入的信任边界必须显式并被负向测试覆盖;
- 渲染行为可以派生自规范数据,但无权重新定义 schema。
选项对比
| 选项 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| A:源契约增强 + 窄渲染跟进 | date 引入机器可读规范节点值(保留旧数据读兼容、派生渲染标签、与 Markdown 线格式迁移解耦);media/embed 引入规范化元数据 + 显式 allowlist/信任边界,只持久化编辑面真正需要的来源信息 | 长期架构最优;存储契约与渲染标签诚实分离;为未来 AI/streaming 兼容铺路;给 Markdown 规则明确的往返对象 | 触及多个包;需要谨慎的旧数据读兼容;现在就要做真正的 schema 决策 |
| B:保持现有节点形态,仅修补渲染器/解析器 | date 保持单一原始字符串;media 保持url+ 运行时推断 | 即时 diff 小;近期协调成本低 | 锁死糟糕的toDateString()契约;media 元数据/来源信息继续隐式;行为变多但 law 没有变好 |
| C:UI 先行扩展 | 先做更丰富的选择器语义、更宽的嵌入 chrome、更多 provider 行为与预览行为 | 用户可见变化"炫目" | 顺序错误;违反非目标;最容易产生假 law 与 schema 漂移 |
推荐结论:选择选项 A,但 date 节点迁移要比"完整字段重命名"更窄。具体含义:
date获得规范机器可读值 + 派生渲染标签;media/embed获得显式规范化元数据 + 信任边界处理,provenance(来源信息)只在确实帮助编辑时才持久化;- 渲染器只表达这些契约,不得发明额外的产品 law。
Date 契约决策:规范日历日字符串 + 双读 Markdown 线格式
计划为@platejs/date设计了一个 Plate 自有的新契约,核心要点如下。
规范节点值
- 保留现有节点字段名
date; - 收窄其语义为规范的
YYYY-MM-DD日历日字符串; - inline void 节点其余部分保持不变。
推荐的规范节点值:
{ date: "2026-03-23"; }Markdown / MDX 线格式决策
本批次采用**双读(dual-read)**策略:
- 读取两种形态:
- 旧式子文本形态:
<date>2026-03-23</date> - 带属性形态:
<date value="2026-03-23" />
- 旧式子文本形态:
- 写入形态保持显式且保守:本批次 writer 仍输出规范的子文本形态;
- 带属性形态仅作读取兼容,不是本批次的默认序列化输出。
兼容性行为
- 读取旧式纯子文本
<date>...</date>输入; - 只将两类安全旧形态规范化为
node.date:- 规范的
YYYY-MM-DD; - 旧的 Plate 风格
Date.prototype.toDateString()输出(形如Mon Mar 23 2026);
- 规范的
- 若旧式子文本无法安全规范化,则通过显式 Markdown 回退路径保留原文,而不是物化一个更丰富的
date节点; - 停止从插入操作或日历 UI 写入新的
toDateString()值。
有限渲染行为
- 从规范
date派生当前相对标签(Today/Yesterday/Tomorrow)与长日期标签; - 将
YYYY-MM-DD解析为无时区漂移的日历日,而不是依赖裸new Date(node.date); - 若在 Markdown 回退路径之外遇到非规范
date节点,按字面回退文本渲染,而不是臆造一个解析日。
明确排除(Out)
- 重 locale / 重 timezone 的序列化语义;
- display-vs-value 分离的序列化语义;
- 超出"写入规范值"的独立选择器产品 law。
源码印证:契约如何在@platejs/date中落地
计划执行后,packages/date/src/lib/utils/dateValue.ts 已成为该契约的共享实现,可以直接对照阅读:
CANONICAL_DATE_REGEX(/^\d{4}-\d{2}-\d{2}$/)与LEGACY_DATE_REGEX(/^[A-Z][a-z]{2} [A-Z][a-z]{2} \d{2} \d{4}$/)分别识别两类安全形态;formatDateValue(date)将Date格式化为规范YYYY-MM-DD;parseCanonicalDateValue(value)用**本地时区正午(hour 12)**构造Date并逐项校验年/月/日,从而避免时区漂移导致的日期错位;normalizeDateValue(value)统一处理Date与字符串输入:规范形态直接通过,toDateString()旧形态转换为规范值,无法规范化的输入落入rawDate字段;getDateDisplayLabel({ date, now, rawDate })负责渲染标签派生:有rawDate时返回原文,否则按日历日比较输出Today/Yesterday/Tomorrow,其余走toLocaleDateString长格式。
而 insertDate.ts 的插入默认值已改为normalizeDateValue(date ?? new Date()),随后通过editor.tf.insertNodes写入带children: [{ text: '' }]的空子文本 inline void 节点——这正是"新写入只产出规范值"的实现证据。
Media / Embed 契约决策:结构化规范化元数据 + 显式信任边界
计划为@platejs/media设计了一个更丰富的规范化嵌入契约。
字段设计
- 必选:
url:规范的渲染/嵌入 URL;
- 可选:
provider:规范化的 provider slug;id:规范化的 provider 资源 id;sourceUrl:当编辑面需要保留一个与url不同的用户可见 URL 时,保存规范的用户/来源侧 URL。
仅规范化(不序列化)的元数据
sourceKind可以存在于共享规范化助手与测试中;- 除非出现第二个持久化消费者,否则
sourceKind不需要在本批次成为序列化的 markdown/文档字段。
推荐边界
- allowlist 片段提取保持显式;
- 绝不把任意脚本标记存储为规范节点载荷;
- 不扩展到 PDF iframe 或任意脚本嵌入。
有限渲染行为
- 渲染器可直接使用规范化元数据,无需重新解析原始输入;
- 编辑面在可用时应保留
sourceUrl,而不是只把 provider 的嵌入 URL 泄漏给用户。
源码印证:结构化契约与信任边界如何落地
packages/media/src/lib/media/parseMediaUrl.ts 实现了计划所要求的"单一显式结构化契约":
EmbedUrlData类型即契约本身:{ id?, provider?, sourceKind?, sourceUrl?, url? },其中sourceKind取值为'allowlisted_snippet' | 'iframe' | 'url';parseMediaUrl(url, { urlParsers })依次尝试各个 parser,并在返回前做XSS 加固:只允许http:与https:协议,其余协议直接拒绝——这就是信任边界的代码表达;- parseIframeUrl.ts 退位为"信任边界助手"而非整个契约:它负责从粘贴的完整 iframe 代码中提取
src、识别 Twitter/X status URL,本身不构成 schema; - BaseMediaEmbedPlugin.ts 将
parseIframeUrl注册为options.transformUrl,并把media_embed声明为{ isElement: true, isVoid: true },HTML 反序列化只接受IFRAME节点的src; - submitFloatingMedia.ts 是"提交即消费契约"的示范:先跑
isUrl校验与可选的transformUrl,再用parseMediaUrl+[parseTwitterUrl, parseVideoUrl]规范化,最后editor.tf.setNodes一次性写入id、provider、sourceUrl、url——提交路径不再在应用代码里临时解析原始输入。
可测试验收标准:九条契约级的完成定义
计划的验收标准直接映射到代码与测试,是"契约优先"方法论中最可操作的部分:
- 新 date 写入与可安全规范化的旧 date 读取,都存储规范机器可读的
date值; - 日期插入与 demo 日历编辑写入规范值,而非
toDateString(); - Markdown date 规则双读旧式子文本与带属性 date 元素,本批次写回规范子文本;
- 规范 date 渲染使用无时区漂移的日历日解析;不可规范化的旧式 markdown 日期输入走显式非日期回退路径;既有非规范
date节点用字面渲染回退,而非被静默重解释; - media 嵌入把受支持的 URL / iframe / allowlist 片段输入规范化为
@platejs/media拥有的显式共享元数据字段; - 任意脚本片段继续被拒绝,PDF iframe 片段继续不受支持;
- 更丰富的
media_embed元数据通过显式 markdown/MDX 规则与测试往返,而非隐藏的回退行为; - date 渲染器对规范日显示行为有显式覆盖,而不只是包级 transform 测试;
markdown-editing-spec.md、editor-protocol-matrix.md、markdown-parity-matrix.md、重新打开的扩展说明与公开文档描述同一套边界。
实施步骤:八步从契约到交付
计划给出了八步实施顺序,每步都明确到文件与交付物。这里结合当前仓库源码逐条展开。
第 1 步:先在代码中锁定 date 契约
涉及文件:insertDate.ts、packages/date/src/lib/**下的新规范化/序列化助手、packages/date导出的日期类型。
工作内容:
- 添加
@platejs/date拥有的共享日期规范化助手; - 将插入默认值从
toDateString()改为规范date; - 在足够长的窗口内保留旧形态读兼容,避免破坏旧文档;
- 显式定义旧式子文本值无法安全规范化时的 Markdown 回退分支;
- 把 Markdown 线格式迁移与节点契约决策解耦——先改数据语义,再改线格式。
从当前源码看,dateValue.ts正是这一步的产出:规范化、旧格式识别、rawDate回退一应俱全。
第 2 步:让 date 渲染器跟随共享契约
涉及文件:date-node.tsx、date-node-static.tsx。
工作内容:
- 停止把
element.date当作自由格式显示字符串; - 从规范
date派生相对/长标签; - 日历选择写入规范
date; - 规范解析与标签派生路由到共享包助手,而非应用代码中的裸
new Date(element.date); - 为规范日渲染路径与回退路径补充 UI 测试覆盖。
第 3 步:让 Markdown date 规则从"仅子文本"变为"刻意设计"
涉及文件:defaultRules.ts、packages/markdown/src/lib/dateElement.spec.ts。
工作内容:
- 反序列化时同时接受带属性的 date 元素与旧式子文本 date 元素;
- writer 选择保持显式:本批次只输出规范子文本;属性输出仅读兼容,不进 writer;
- 补充四类显式测试:规范子文本形态、带属性读兼容、旧式读兼容、不可规范化旧式 markdown 回退行为。
从当前 defaultRules.ts 的date规则实现看,这一步已经兑现:deserialize优先读value属性,否则取子文本,并通过normalizeDateValue归一;serialize在存在date且无rawDate时输出带value属性的形态,否则回退为子文本。这恰好体现了"读双形态、写保守"的契约精神。
第 4 步:集中 media/embed 规范化与 provenance
涉及文件:parseMediaUrl.ts、parseIframeUrl.ts、parseVideoUrl.ts、parseTwitterUrl.ts、useMediaState.ts、submitFloatingMedia.ts、BaseMediaEmbedPlugin.ts,以及作为消费者而非 schema 所有者的 media-embed-node.tsx。
工作内容:
- 把嵌入规范化提升为
parseMediaUrl拥有的一个显式结构化契约; - 让
parseIframeUrl只做信任边界助手,而非整个契约; - 让 submit/edit/render 路径消费丰富元数据,而不是在应用代码里重新解析原始输入;
- 对非 allowlist 脚本标记与 PDF 保持显式负向行为;
- 持久化 schema 冻结为
url、provider、id,仅当编辑路径确实需要时才加sourceUrl; - 除非出现真正的序列化消费者,否则
sourceKind保持为规范化/调试元数据。
第 5 步:为更丰富的media_embed元数据实现显式 Markdown 所有权
涉及文件:mediaRules.ts 及其旁新增的专用media_embed规则。
工作内容:
- 停止依赖隐式行为处理丰富 embed 元数据;
- 新增专用
media_embedmarkdown 规则,所有权不再可选或藏在回退行为后面; - 只保留属于规范契约的元数据;
- 不序列化不受支持的原始 snippet/script 载荷。
第 6 步:在文档法最终提升前扩展测试
Date 测试:
packages/date/src/lib/transforms/insertDate.spec.tsxpackages/date/src/lib/BaseDatePlugin.spec.tsxpackages/markdown/src/lib/dateElement.spec.ts- 包级 date 助手 spec(即 dateValue.spec.ts)
- 应用渲染器 spec:
apps/www/src/registry/ui/date-node.spec.tsx、apps/www/src/registry/ui/date-node-static.spec.tsx
Media 测试:
packages/media/src/lib/media/parseMediaUrl.spec.tspackages/media/src/lib/media-embed/parseIframeUrl.spec.tspackages/media/src/lib/media-embed/BaseMediaEmbedPlugin.spec.tspackages/media/src/react/media/FloatingMedia/submitFloatingMedia.spec.tspackages/media/src/react/media/useMediaState.spec.ts- 围绕结构化 embed 元数据规范化器的测试
- 显式
media_embedmarkdown 往返 spec,优先放在packages/markdown/src/lib/mediaSurface.spec.ts旁 - 丰富元数据影响预览或编辑路径选择处的渲染器覆盖
第 7 步:代码形态被证明后再补 law/文档
涉及文件:markdown-editing-spec.md、editor-protocol-matrix.md、markdown-parity-matrix.md、2026-04-09-editor-spec-date-media-expansion.md,以及公开文档content/(plugins)/(elements)/date.mdx、content/(plugins)/(elements)/media.mdx、content/(plugins)/(serializing)/markdown.mdx。
工作内容:
- 把 law 从"延后的更丰富契约"更新为"本批次选定的契约";
- 保持非目标显式;
- 记录新的规范序列化形态;
- 保持审计纪律诚实,不虚构外部权威依据。
第 8 步:为包级工作添加 changesets
可能触及的包:@platejs/date、@platejs/media、@platejs/markdown。
风险与缓解:五个已知坑及对策
计划为每个主要风险都预设了缓解措施,这是它区别于普通 todo 清单的关键:
| 风险 | 缓解措施 |
|---|---|
| date 迁移损坏旧内容 | 双读旧式与规范形态;仅在规范化安全时才自动序列化规范形态;补充显式旧式往返测试 |
| 丰富 media 数据再次分散到解析器与 UI | 让一个共享规范化嵌入助手成为唯一所有者;UI 的 submit/render 代码只做消费者,不做临时规范化器 |
| provenance 字段过早成为永久包袱 | sourceUrl按需启用,由编辑流可逆性证明其必要性;没有第二个持久化消费者前,sourceKind不进序列化契约 |
| 嵌入支持悄悄回退到不安全的脚本处理 | 保持窄 allowlist;对任意脚本标记与 PDF 保留负向测试;在 spec、protocol、docs 中声明信任边界 |
| 渲染行为把额外产品 law 偷渡进 schema | 直接从规范date渲染;不允许应用渲染器发明额外序列化字段或显示属性 |
验证步骤:测试、构建、类型检查、lint 与浏览器验证
计划提供了可直接复制的验证命令序列。
定向测试
bun test packages/date/src/lib/transforms/insertDate.spec.tsx \ packages/date/src/lib/BaseDatePlugin.spec.tsx \ packages/markdown/src/lib/dateElement.spec.ts \ packages/media/src/lib/media/parseMediaUrl.spec.ts \ packages/media/src/lib/media-embed/parseIframeUrl.spec.ts \ packages/media/src/lib/media-embed/BaseMediaEmbedPlugin.spec.ts \ packages/media/src/react/media/FloatingMedia/submitFloatingMedia.spec.ts \ packages/media/src/react/media/useMediaState.spec.ts \ packages/markdown/src/lib/mediaSurface.spec.ts \ apps/www/src/registry/ui/media-video-node.spec.tsx随后运行本批次新增的测试文件:
- 包级 date 规范化/格式化助手;
apps/www/src/registry/ui/date-node.spec.tsx与date-node-static.spec.tsx;- 显式
media_embedmarkdown 往返覆盖。
构建
pnpm install pnpm brl pnpm turbo build --filter=./packages/date --filter=./packages/media --filter=./packages/markdown --filter=./apps/www类型检查
pnpm turbo typecheck --filter=./packages/date --filter=./packages/media --filter=./packages/markdown --filter=./apps/www若过滤后的 typecheck 仍遇到未解析的 workspace 包导入,回退方案:
pnpm build pnpm turbo typecheck --filter=./packages/date --filter=./packages/media --filter=./packages/markdown --filter=./apps/wwwLint
pnpm lint:fix浏览器验证
browser-use --connect http://127.0.0.1:9222重点验证 date demo 路径仍满足:
- 规范日渲染无时区漂移;
- 日历编辑写入规范 date 值。
计划同时强调:不可规范化的旧式 markdown 回退与既有非规范date节点渲染器回退必须由显式单元/spec 覆盖,不能假装浏览器 demo 会自动覆盖它们——这是测试纪律的细节要求。
ADR 摘要:为什么这是"最小的真修复"
计划的 ADR 部分浓缩了整个决策:
- 决策:把剩余 date/media 扩展批次做成源契约升级,而非 UI 先行的产品通道;
- 驱动因素:date 存储弱、media/embed 规范化分散且建模不足、仓库已有足够底气做 Plate 自有决策;
- 备选方案:保持现有节点形态只补行为;直接跳到更丰富的 UI/产品面;
- 选择理由:这是能真正修复架构的最小批次,而不是在模糊数据上继续堆行为;
- 后果:现在付出更多包级改动;长期 DX 更干净;未来 AI/streaming 更容易,因为源真值显式;date 节点语义可能先于 Markdown 线格式变化;除非编辑面证明需要,provenance 保持窄。
后续事项(Follow-ups)
- 本批次后重新评估是否值得加入更丰富的 date locale/timezone 语义;
- 本批次后重新评估本地 media 路径策略是否从
specified推进到完全实现。
执行组织:ralph 与 team 两种模式
计划最后给出了执行分工建议,对使用多 Agent 协作执行该批次有直接指导意义。
若通过ralph执行
建议的通道顺序:契约决策与文件所有权确认 → date 实现 → media/embed 实现 → markdown 往返更新 → docs/spec 对齐 → 验证。
建议推理级别(reasoning levels):
- 契约选择 / markdown schema / 信任边界:
xhigh - 代码与测试:
high - docs/spec 同步:
high - 最终验证评审:
high
若通过team执行
建议分工:
- Date 负责人:
packages/date/**、apps/www/src/registry/ui/date-node.tsx、date-node-static.tsx及 date 测试; - Media 负责人:
packages/media/**与 media embed 测试; - Markdown + 文档负责人:
packages/markdown/**、editor-behavior 文档、公开文档、changesets。
启动提示示例:
$team "Execute docs/plans/2026-04-09-date-media-expansion-consensus-plan.md" omx team run docs/plans/2026-04-09-date-media-expansion-consensus-plan.md团队验证路径
- 每个负责人在交接前运行其写入范围的定向测试;
- Markdown/文档负责人在合并后运行跨包 markdown/date/media 测试;
- 最终验证者按仓库要求顺序执行 build → typecheck → lint;
- 最终评审者确认 spec/protocol/parity/公开文档描述一致,且非目标没有越界。
总结:从"模糊数据 + 分散解析"到"显式契约 + 单一所有者"
这份共识计划为编辑器功能扩展提供了一个可复用的方法论模板:先用研究文档锁定问题边界,再用 RALPLAN-DR 在原则指导下比较选项,选定"源契约优先"的窄批次,然后按"代码 → 渲染器 → Markdown 规则 → 测试 → 文档法 → changesets"的顺序推进,最后用明确的验收标准与验证命令收尾。
对照当前仓库源码,date 半程的核心契约(YYYY-MM-DD规范值、toDateString()兼容、无时区漂移解析、双读 Markdown 线格式)已在 dateValue.ts 与 defaultRules.ts 中落地;media 半程的结构化契约(EmbedUrlData、协议白名单信任边界、提交路径统一规范化)已在 parseMediaUrl.ts 与 submitFloatingMedia.ts 中成形。对于正在为编辑器扩展做架构决策的开发者,本文的契约设计、非目标管理与验证纪律均可直接借鉴。
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考