zh CN 版本语义说明 - chiba233/yumeDSL GitHub Wiki

版本语义说明

增量解析 | 线性时间复杂度 | 首页

这一页专门收集 “版本升级后,哪些公开语义或可观察行为发生了变化”

它不重复 API 全量说明;字段签名、使用方式、复杂度推导仍以各自主题页为准。这里关注的是:

  • 升级时需要特别留意的行为差异
  • 同一个 API 在不同版本里的契约变化
  • 合法输入之外,错误恢复 / 降级策略上用户可观察到的差异

Compatibility notes

这些属于“升级时常被问到,但不一定只和增量解析相关”的兼容性说明。具体 API 细节请直接看各自链接页面:

主题 自哪个版本开始 说明
同名标签同时支持 inline + block/raw 早于 1.0.7 这一能力在 1.0.7 之前已经存在;1.0.7 修的是 inline $$tag(...)$$ 关闭时误用 block 归一化规则吞掉后续换行的 bug。见 DSL 语法 / 编写标签处理器
createParser 的 partial override 深合并 1.0.11+ API 参考 / DslContext
declareMultilineTags 支持 inline form(MultilineForm: "inline" 1.0.14+ 处理器辅助函数
隐式 inline shorthand name(...) 1.3.0+ DSL 语法 / 错误处理

onError 版本语义(1.1.x

这一组不是性能,而是兼容性补充。下面的结论基于同一套 fixture,对比 parseRichText / stripRichText 两个 API 在 onError 回调里收到的错误码序列。

行为组 版本
A 1.1.01.1.5
B 1.1.1
C 1.1.21.1.31.1.4

这说明 1.1.x 内部的 onError 语义并不是单调演进,而是至少出现过两次漂移。 后续兼容性判断现在统一以 1.1.2 / 1.1.3 / 1.1.4 这一组作为 onError 基准。

主要差异可以直接概括成三段:

  • 1.1.01.1.5 同组:在 parseRichText / stripRichText 上更容易把 block 退化路径报成 INLINE_NOT_CLOSED
  • 1.1.1 是单独一组:相比 1.1.21.1.4,它少报了 [Block/Unknown] 文本混入未知 block 这一类 BLOCK_CLOSE_MALFORMED
  • 1.1.2 / 1.1.3 / 1.1.4 同组:这三版的 onError 语义一致,也是后续兼容性判断采用的基线

补充一组最终镜像版本横向对比(1.1.10 / 1.2.7 / 1.3.9 / 1.4.1 / 当前工作区):

  • parseRichText / stripRichTextonError 错误码序列在这组版本里保持一致

增量解析 / diff 版本时间线

版本 变化点 接入影响
1.2.0 首次引入 parseIncremental 与 low-level 更新辅助能力 增量 structural 缓存能力首次可用
1.2.1 新增 createIncrementalSession(...) 与 auto 自适应策略 推荐从手动 low-level 切到 session-first
1.2.2 新增右侧复用 seam probe、安全指纹校验、内部全量重建统计路径 内部正确性更稳,但可能更保守
1.2.3 移除 low-level updater 公开导出,精简 session-only 类型 公共接入改为 session-first
1.2.4 右侧 zone 惰性 delta 平移;签名有界采样;纯 inline zone 切分(softZoneNodeCap);低 zone 守卫 头部编辑性能大幅改善;纯 inline 文档增量可用
1.2.5 cloneParseOptions 延后;全量重建复用 position tracker;findDirtyRange 单遍扫描 full rebuild 路径常数开销减少
1.3.8 新增 applyEditWithDiff(...);顶层 diff 支持多段稳定岛;内部加入路径感知 ops 调用方可以直接消费结构化 diff
1.3.9 TokenDiffResult 新增 isNoop;保守 diff 的空树 no-op 语义明确;紧预算场景下的 diff 仍更偏向细粒度 set-text 调用方可以明确区分“发生编辑但结构未变”和“普通非空 diff”;如果上层强依赖细粒度 diff,这一版更接近旧风格
1.4.0 增量接入面按 stable 合约描述;session 回退语义与 diff 预期按稳定版本面说明;默认 session diff 带硬预算与局部 dirty-window 细化 1.3.x 集成可直接升级到 1.4.x,但应按稳定契约理解 session-first 行为;默认 worst-case 会更早粗化、更容易收敛成保守 splice
1.4.1 深层未闭合 inline 的增量编辑不再落入极慢 EOF 恢复路径;full parse / dirty-window reparse / seam probe 的 EOF 恢复语义统一 编辑器场景下删除大量尾部 )$$ 不再容易卡住;整文档路径与增量路径的恢复行为保持一致
1.4.2 extractText(singleToken) 修复;createEasySyntax({ closeMiddle }) 真正参与 close 派生;新增 filterTokens helper / convenience API 的运行时行为与类型说明对齐;不涉及增量解析路径变化
1.4.3 主循环快速文本跳跃(findNextBoundaryChar,charCodeAt 边界码比较);转义 token 首字符分桶;getTagCloserTypeWithCache 大帧缓存;ParseFrame 瘦身 纯内部常数优化,不影响增量解析公开语义;full parse 吞吐量提升
1.4.4 修复深层 shorthand 闭合归属回归:ParseFrame 新增 ancestorEndTagOwnerIndex,shorthand 在 close 冲突时重新会向最近祖先 full-form endTag 让位。与此同时,损坏 shorthand 的恢复语义被收紧:一旦 shorthand 降级,就按文本处理,不再通过 owner-chain recovery 把已经退化成文本的 shorthand 头重新补回结构;EOF 未闭合时父帧从 argStart 重扫。渲染器新增文本合并缓冲与 raw 转义惰性分配扫描 深层 shorthand 输入(如 =bold<bold<bold<...>>>>>>=)重新不会抢祖先 full-form 闭合;损坏 shorthand 在 parseStructural 里的结果形状比 1.4.3 更粗、更接近纯文本;渲染器在文本密集和 raw 密集文档上吞吐量提升;不涉及增量解析公开语义变化
1.4.5 修复 inline(blockTag) 的 render-position 末尾映射:当 inline 标签被声明为 blockTag(forms: ["inline"])并消费了 close 后首个换行时,token position.end 现在会和 raw / block 一样覆盖该被消费换行;LF 与 CRLF 都按实际宽度计入(+1 / +2 parseRichText 里 inline(blockTag) token 的 position 现在与“已消费换行”的渲染语义一致;和下一个文本 token 的 position.start 严格对齐;不涉及公开 API 变更,不影响增量解析公开语义

公开类型 / API 面变化

这一节专门记录“运行时行为可能没变,但公开导出、回调签名、配置项或 TypeScript 可见类型变了”的升级注意点。

修改已存在的公开面

版本 修改点 接入影响
0.1.4 ParseError.codestring 收窄到 ErrorCode 如果你在上层穷举、序列化或 pattern-match 错误码,可以改成按联合字面量处理
0.1.7 TextToken 增加 index signature([key: string]: unknown handler 附加字段从“运行时可见”变成“类型也可见”
1.0.0 移除 ParseOptions.mode = "highlight" 旧代码如果还传 "highlight",升级到 1.0+ 需要改用 parseStructural
1.0.4 TagHandler 旧回调签名增加可选 ctx?;多组已有 utility/helper 也增加 ctx? 旧 handler 仍可用,但如果你自己声明函数类型或做 wrapper,需要把新参数纳入
1.0.6 ParserBaseOptions 增加 baseOffset? / tracker? substring / slice 场景可以把位置信息映射回原文;如果你包装过 ParserBaseOptions,需要同步字段
1.0.8 withSyntax / withCreateId / withTagNameConfig / getSyntax 改为接受显式 { suppressDeprecation?: boolean } 旧 ambient-state helper 的公开签名发生兼容式扩展
1.0.14 MultilineFormraw | block 扩展为 raw | block | inline 如果你自己声明或穷举 MultilineForm,升级时要把 "inline" 一并纳入
1.1.0 Parser.print() 支持 per-call PrintOptions override;deriveBlockTags / resolveBlockTags 参数类型从 Record<string, unknown> 收窄到 Record<string, TagHandler> 如果你自己包装 print 或直接调用这两个 helper,需要按新签名收口
1.2.3 移除旧 low-level updater root 导出;IncrementalDocument 不再暴露 optionsFingerprint 增量接入面收敛到 session-first;依赖旧 low-level 导出/字段的代码需要迁移
1.2.4 IncrementalSessionOptions 增加 softZoneNodeCap? 纯 inline 文档的 zone 粒度第一次变成调用方可调参数
1.3.5 createEasyStableId 增加 disambiguationScope?: "parse" | "lifetime",且默认语义改为 parse-scoped reset 共用一个 stable-id generator 跨多次 parse 的默认 ID 语义发生变化
1.3.9 TokenDiffResult 增加 isNoop 下游可以直接区分“发生编辑但结构未变”和普通 diff
1.4.0 IncrementalSessionOptions 增加 diff?,引入 IncrementalDiffRefinementOptions diff 预算化细化策略进入调用方可见配置层
1.4.x IncrementalDocument.zones / tree 改为 readonly 如果以前会直接修改快照数组,升级后会有类型错误
1.4.2 createEasySyntax 参数类型从 Partial<SyntaxInput> 扩展为 Partial<SyntaxInput> & { closeMiddle?: string } 新增可选字段,向后兼容;不传 closeMiddle 时行为不变;传入时会参与 rawClose / blockClose 派生,但不会泄漏到运行时返回对象上

新增公开面

版本 新增项 接入意义
0.1.5 createParser()Parser 预绑定 parser 配置成为正式公开入口
0.1.8 allowFormsTagFormcreateSimpleInlineHandlerscreateSimpleBlockHandlerscreateSimpleRawHandlersdeclareMultilineTagscreatePassthroughTags tag form 过滤与批量 helper 首次进入公开面
0.1.12 tagNameTagNameConfigDEFAULT_TAG_NAMEcreateTagNameConfigMultilineFormBlockTagInputBlockTagLookup 自定义 tag 名字符集和 multiline 配置类型进入公开面
0.1.180.1.19 parseStructural(...)parser.structural()ParserBaseOptionsStructuralNodeStructuralParseOptions structural parse 成为正式公开入口
1.0.2 trackPositionsSourcePositionSourceSpanTextToken.position?StructuralNode.position? 源码位置跟踪进入公开结果面
1.0.5 createPipeHandlers(...)createTextToken(...)PipeArgs convenience readers pipe helper 接入面重组完成
1.0.9 createEasyStableId(options?)EasyStableIdOptions stable ID 生成器进入正式公开面
1.0.15 buildZones(...)Zone zone 级结构缓存首次有正式 helper 与类型
1.1.0 NarrowTokenNarrowDraftNarrowTokenUnioncreateTokenGuard token 类型收窄工具进入公开面
1.2.0 parseIncrementalupdateIncrementaltryUpdateIncremental 增量 structural 更新能力首次进入公开面
1.2.1 createIncrementalSession(...) 及 session 结果类型/策略配置 session-first 编辑器接入面首次出现
1.3.0 implicitInlineShorthandInlineShorthandOptionimplicitInlineShorthand?: trueSHORTHAND_NOT_CLOSED shorthand 配置、节点标记和专属错误码进入公开面
1.3.8 applyEditWithDiff(...)IncrementalSessionApplyWithDiffResultTokenDiffResultStructuralDiffOpStructuralDiffPathStructuralDiffPathSegment session diff 从根级 patch 升级为结构化 diff 接口
1.4.2 filterTokens(...) mapTokens 保留/删除的快捷方式,支持类型谓词收窄;语义是树裁剪,不是 flat filter

Bug fix(公开可观察行为)

版本 修复项 可观察影响
1.0.7 同名标签同时支持 inline 与 block/raw 时,inline $$tag(...)$$ 关闭不再误吞后续换行 这是已有能力上的修复,不是首次支持该能力
1.3.1 括号不配平时不再让整棵标签树一起退化成纯文本 非法输入下,恢复结果更局部、更符合用户直觉
1.4.1 深层未闭合 inline 的增量编辑不再落入极慢 EOF 恢复路径,且 full / incremental 恢复语义统一 编辑器里删除大量尾部 )$$ 不再容易卡住;整文档与增量路径恢复结果一致
1.4.2 extractText(singleToken) 不再返回空字符串;createEasySyntax({ closeMiddle }) 真正参与 close 派生 helper / convenience API 的运行时行为与类型说明对齐,且 closeMiddle 仍是输入侧字段,不会出现在返回配置对象上
1.4.4 深层嵌套 shorthand 不再抢占祖先 full-form endTag 闭合;同时损坏 shorthand 的恢复语义改为“降级即文本”,不再通过 owner recovery 把已经退化成文本的 shorthand 头重新拆挂回结构 输入如 =bold<bold<bold<...>>>>>>= 重新不会错误抢闭合;parseStructural 在未闭合 / 损坏 shorthand 上的 text node 分段方式会与 1.4.3 不同,更接近“整段文本 + 父容器重扫”的结果
1.4.5 inline(blockTag) close 后消费的首个换行现在会并入 inline token 的 position.end(与 raw / block 的渲染位置语义对齐) 之前该换行会被消费但不属于任何 token 的 render span;现在 inline(blockTag) 的 render span 会覆盖它,LF / CRLF 都按真实宽度映射

1.4.5inline(blockTag) 的尾换行 position 语义对齐

1.4.5 修复的是一个“渲染行为与位置映射分叉”的问题:

  • raw(blockTag) / block(blockTag) 早已把 close 后被消费的首个换行并入 token position.end
  • inline(blockTag) 之前虽然也会消费该换行,但 token position 仍停在 inline close 末尾。

因此在 parseRichText(...) 结果里,会出现“换行被消费了,但不属于任何 token render span”的空洞。

1.4.5 之后:

  • blockTags: [{ tag, forms: ["inline"] }] 声明的标签,inline token 的 position.end 会覆盖被消费换行;
  • LF 计入 +1,CRLF 计入 +2
  • position.end 与下一个文本 token 的 position.start 对齐。

最小例子:

  • 输入:$$bold(x)$$\nbar
    • 旧:inline span 约为 [0, 10),下一个 text 从 11 开始,中间有“已消费但未归属”的 \n
    • 新:inline span 约为 [0, 11),下一个 text 从 11 开始

升级判断:

  • 这是 公开可观察行为修复(position 映射),不是 API 扩展;
  • 主要影响依赖 trackPositions 的编辑器 / 高亮 / source-map 对齐逻辑;
  • 只影响声明了 forms: ["inline"] 的 blockTag inline 形态,不改变普通 inline 语义。

1.4.4parseStructural 在损坏 inline / shorthand 上的文本分段变化

这是 1.4.4 相比 1.4.3 一个容易在行为对比脚本里看到、但不属于新 bug 的变化。

当前规则是:

  • full-form 才是真正的结构容器
  • shorthand 只是语法糖
  • 一旦 shorthand / inline 在恢复中降级,就不再保留额外结构恢复权
  • 最近仍然合法的 full-form 父作用域从 argStart 重扫并决定最终结构

因此在 parseStructural(...) 的返回树里,未闭合或损坏的 inline / shorthand 现在更容易表现为更粗的 text 合并,而不是像 1.4.3 那样拆成“tag 头一段 text + 正文一段 text”。

典型例子:

  • $$bold(hello
    • 1.4.3["$$bold(", "hello"]
    • 1.4.4["$$bold(hello"]
  • before $$bold(hello) after
    • 1.4.3["before ", "$$bold(", "hello) after"]
    • 1.4.4["before ", "$$bold(hello) after"]

这表示的是恢复模型变更后的 AST 形状差异,不是内容丢失;parseStructural 的文本值仍覆盖同一段源码。

1.4.4 升级时应该怎么理解

可以把 1.4.4 的语义变化收成四条:

  1. 修回了深层 shorthand 的闭合归属
    • 深层 shorthand 不再错误抢走祖先 full-form 的闭合 token。
  2. 收紧了损坏 shorthand 的恢复权
    • shorthand 一旦降级,就按文本处理;
    • 不再通过 owner recovery 把已经退化成文本的 shorthand 头重新补回结构。
  3. parseStructural 的 AST 形状因此变粗
    • 主要体现在未闭合 / 损坏 inline、shorthand 上的 text node 分段方式;
    • 相比 1.4.3,更接近“整段文本 + 父容器从 argStart 重扫”的结果。
  4. 这不是公共 API 扩展,也不是合法输入语义漂移
    • 合法输入下的结构结果不应因此改变;
    • 这次变化集中在错误恢复 / 降级路径的可观察行为。

对升级方最重要的判断是:

  • 如果你依赖的是 合法输入parseRichText / stripRichText / parseStructural 输出,1.4.4 不是一版新的语法改写。
  • 如果你依赖的是 损坏输入下 parseStructural 的 text node 分段形状,那么 1.4.4 相比 1.4.3有意语义变化
  • 如果你使用的是 incremental session,公开 session 合约没有新增字段或模式变化;但当某次编辑回退到 full parse / full-fallback 时,最终拿到的 structural tree 会遵循这套新的恢复语义。

1.4.1:EOF 未闭合 inline 恢复语义

1.4.1 对一个很具体、但在编辑器场景里很容易遇到的行为做了调整:

  • 输入在 EOF 处留下未闭合 inline
  • 且内部已经成功解析出一部分子内容
  • 以前恢复逻辑会更偏向“把整段尾巴重新并回一个 text”
  • 现在会保留已经解析出的那部分尾部内容,而不是把它们再并回最内层未闭合标签头

可观察差异(更完整的 EOF 未闭合 inline 例子)

输入
$$bold(hello text("$$bold(hello") text("$$bold("), text("hello")
$$bold($$italic(hello text("$$italic(hello") text("$$italic("), text("hello")
$$bold($$italic($$code(x text("$$code(x") text("$$code("), text("x")
$$bold(hello $$italic(world text("$$bold(hello "), text("$$italic(world") text("$$bold("), text("hello "), text("$$italic("), text("world")
$$bold(a $$italic(b $$code(c)$$ d text("$$bold(a "), text("$$italic(b "), inline(code, 1ch), text(" d") text("$$bold("), text("a "), text("$$italic("), text("b "), inline(code, 1ch), text(" d")
$$bold(text)$$$$italic(unclosed inline(bold, 1ch), text("$$italic(unclosed") inline(bold, 1ch), text("$$italic("), text("unclosed")

这意味着什么

  • 合法输入没有变化:这个差异只发生在 EOF 处存在未闭合 inline 的恢复路径上。
  • 错误恢复粒度更细:已经成功解析出来的尾部内容不会再被一股脑并回最内层未闭合标签头。
  • 全量 / 增量一致1.4.1 之前最需要担心的是整文档路径和增量脏区路径可能走不同恢复语义;现在这点被收敛了。
  • 最终镜像版本分组很清楚1.1.10 / 1.2.7 / 1.3.9 共享旧形状,1.4.1+ 共享新形状

升级建议

如果你的上层逻辑会对非法输入的恢复树形状做精确断言(例如某些 editor test fixture、错误恢复快照测试、或依赖“整段合并成一个 text”的兼容层),升级到 1.4.1 时需要重新核对这些断言。

如果你的上层只依赖合法输入语义,或者只把非法输入当作“编辑中的暂时中间态”,通常不需要额外改动。

⚠️ **GitHub.com Fallback** ⚠️