D2 v0.6.1 版本深度解析:Globs 懒求值重写与网格连线等关键能力升级
【免费下载链接】d2D2 is a modern diagram scripting language that turns text to diagrams.项目地址: https://gitcode.com/GitHub_Trending/d2/d2
D2 是一款"用文本描述即得图"的现代图表脚本语言。v0.6.1 是 0.6 系列中承上启下的一个版本,其核心工作是globs(通配符批量样式规则)机制的彻底重写——从"只对声明位置之上的对象生效一次"改为"全图懒求值、与声明位置无关",同时为网格(grid)图引入了顶层单元格之间的连线能力,并落地了 UTF-16 文件自动识别、Markdown/箭头font-color等一批实用改进。读完本文,你将掌握 globs 新语义的用法与边界、网格连线的编写方法,以及 0.6.1 带来的全部特性、改进与 Bug 修复清单,并可直接对照源码验证每一项行为。
版本定位:0.6 系列"almost finalized"的里程碑
根据官方 changelog(ci/release/changelogs/v0.6.1.md),globs 功能在该版本经历了一次重大重写,官方用词是 "almost finalized"(几乎定稿)。同时官方明确预告:0.6 系列还会再发布一个版本,为 globs 增加 filters(过滤器)能力。因此 v0.6.1 可以理解为 globs 从"可用"走向"稳定"的关键一跃。
Globs 重写:从"只向上生效一次"到"全图懒求值"
旧行为(Before):位置敏感,必须放在最底部
在 v0.6.1 之前,globs 只会在声明位置之上的所有 shapes 和 connections 上求值一次。也就是说,如果你想把图中所有对象都染成红色,必须把 glob 规则放到文件最后一行,否则它看不到后面声明的对象:
x y *.style.fill: red这种设计要求作者必须把全局样式规则集中放在文件末尾,一旦新增对象忘了追加到 glob 之后,样式就会失效,心智负担较重。
新行为(Now):声明位置无关,全图生效
v0.6.1 起,同样的效果可以这样写,glob 放在文件顶部同样作用于之后声明的所有对象:
*.style.fill: red x y无论 glob 声明在对象之前还是之后,它都会作用于全图。这一变化的底层实现是globs 的懒求值(lazily-evaluated)(对应 changelog Improvements 中的 [Globs are lazily-evaluated])。
源码视角:懒求值如何实现
从源码结构看,globs 的匹配与求值逻辑集中在 d2ir/pattern.go:
multiGlob/_doubleGlob/_tripleGlob:处理**(递归 glob)与***(跨 board 递归 glob)等模式的字段收集逻辑;matchPattern:实现具体的通配符匹配算法——*匹配任意(可为空)字符串,匹配不区分大小写,并优先匹配最早出现的位置,以给后续通配符留出最大的后缀搜索空间;- 递归 glob 遍历时会跳过
classes、vars等定义类字段(见skipDoubleGlobSubtree),避免 glob 在定义生效前就改动其内容。
而"声明位置无关"的行为由 d2ir/lazy_glob_scheduler_test.go 中的测试用例直接印证:
TestLazyGlobsCanBeginAfterOrdinaryFields:*.style.fill: red夹在before与after之间,两者最终都拿到style.fill = red;TestLazyGlobsCanBeginInsideNestedScope:glob 声明在嵌套作用域container: { ... }内部时,只作用于该作用域内的before/after,不会逃逸到外层或兄弟节点(outside、sibling均不受影响),可见 glob 的作用域边界是受控的;TestLazyGlobsIntroducedByImportPreserveClasses:通过...@defs导入的 glob 同样参与懒求值,且不会破坏被导入文件中的classes定义。
也就是说,v0.6.1 的 globs 具备三个新特性:位置无关、作用域受控、可经 import 引入。如果你在升级后发现旧文件末尾的 glob 可以上移到更合理的位置,或想利用 import 注入全局样式,现在都是安全可行的。
网格图:顶层单元格之间支持简单连线
v0.6.1 的另一个重磅能力是grid(网格)图可以在顶层单元格之间建立简单连接。这让网格图从"纯排版容器"进化为"可表达流程关系的图表"。
实测用例:simple_grid_edges.d2
仓库在 e2etests/testdata/files/simple_grid_edges.d2 提供了一个完整的端到端用例,展示了网格连线与 globs、classes 的协同用法。其核心骨架如下:
grid-rows: 4 grid-columns: 5 horizontal-gap: 20 vertical-gap: 5 *.class: [text; blue] 0,0: { label: "npm i -g\n@forge/cli" style: { fill: "#30304c" ... } } ... 0,0 -> 2,0 -> 2,1 -> 2,2 -> 2,3 -> 2,4: { class: arrow } 2,1 -> 0,1: { class: arrow style.stroke: "#cecece" } 2,4 -> 0,4: Yes { class: arrow style.font-size: 10 } 2,4 -> 4,4: No { class: arrow style.font-size: 10 }要点:
- 单元格用
行,列坐标寻址,如0,0、2,1; - 连线语法与普通 D2 一致:
来源 -> 目标,来源/目标直接写单元格坐标即可; - 支持链式连线(
0,0 -> 2,0 -> 2,1 -> ...)、带标签的连线(2,4 -> 0,4: Yes)以及按连线覆盖样式(style.stroke、style.font-size); - 文件顶部还使用
*.class: [text; blue]这种 glob + class 组合,配合文件末尾classes:块定义arrow、note、empty等类,验证了 0.6.1 两大利好(新 globs + 网格连线)可以无缝协同。
从源码结构看,网格单元与最近单元格的解析逻辑位于 d2graph/grid_diagram.go(如ClosestGridCell用于在嵌套结构中回溯最近的网格单元),说明连线最终会被解析到对应的网格单元格对象上。注意 changelog 的描述是"simple connections between top-level cells",即顶层单元格之间的连接,嵌套更深的结构不在本次范围内。
新特性(Features)
v0.6.1 共落地两项新特性:
- UTF-16 文件自动检测与支持。此前 D2 源码文件只按 UTF-8 处理,v0.6.1 起解析器(d2parser/parse.go)会自动识别 UTF-16 编码(含 BOM),无需手动转码。仓库中的 d2parser/utf16_gen.go 即用于生成 UTF-16 测试输入(使用 LittleEndian + BOM 编码器),并在 d2parser/parse_test.go 中验证解析正确性。Windows 上使用记事本等工具保存的 UTF-16 文件现在可以直接编译。
- 网格图顶层单元格之间支持简单连接(见上一节),对应 E2E 用例 e2etests/testdata/files/simple_grid_edges.d2。
改进(Improvements)
v0.6.1 包含五项体验与能力改进:
| 改进项 | 说明 |
|---|---|
| Globs 懒求值 | globs 不再依赖声明位置,且作用域受控、可被 import 引入,实现集中在 d2ir/pattern.go |
| LaTeX 支持 MathJax 的 ASM 扩展 | LaTeX 块渲染能力增强,相关实现可参考 d2svgimport/mathjax_text.go |
font-color支持 Markdown | 之前font-color只作用于纯文本标签,现在 Markdown 标签的文字颜色也可以被统一控制,相关场景见 d2scenebuild/markdown.go |
font-color支持箭头(arrowheads) | 箭头尖端的颜色现在可随font-color一并调整,与标签颜色保持一致 |
| CLI 失败信息包含输入路径 | 当 CLI 执行失败时,错误信息会附带具体的输入文件路径,便于在多文件或 CI 场景下快速定位问题,相关入口见 d2cli/main.go |
Bug 修复清单(Bugfixes)
v0.6.1 修复了一批影响面较广的问题,按功能域归类如下:
格式化(d2 fmt)
d2 fmt现在会格式化所有作为参数传入的文件,而不是只格式化第一个"尚未格式化"的文件(贡献者 @maxbrunet)。如果你在 CI 中批量执行d2 fmt file1.d2 file2.d2 ...,此版本起每个文件都会得到一致的格式化处理,相关实现见 d2cli/fmt.go。- 修复变量替换(variable substitution)出现在字符串中间时
d2 fmt格式化不正确的问题。
Markdown 渲染
- 修复混合元素块(例如同时包含
em和strong的文本)中最后一个元素被裁剪的问题,相关渲染链路见 d2scenebuild/markdown.go。
编译器与解析
- 对非 blockstring 的空标签(如
x: ""之外的裸空值写法)新增编译器错误提示,避免静默吞掉非法输入。 - 修复空嵌套网格(empty nested grid)导致的崩溃问题。
- 修复某些 shape ID 无法与 dagre 布局器配合工作的问题(影响使用 dagre 布局的用户,见 d2plugin/plugin_dagre.go)。
布局与渲染
- 修复某些情况下多个 constant
near对象相互重叠的问题(near定位相关逻辑见 d2layouts/d2near/layout.go)。 - 修复 code shape(代码块形状)渲染时缺少 font-size 调整的问题。
升级与使用建议
- Globs 语义变化:v0.6.1 改变了 globs 的求值语义,旧文件末尾的全局 glob 依然可用,但你可以放心地把它们移动到文件顶部或更符合阅读顺序的位置;同时注意嵌套作用域内的 glob 不会逃逸出当前作用域。
- 预留的下一步:官方明确 0.6 系列还会有一个版本为 globs 增加 filters(过滤器)能力,这意味着当前版本是"无过滤 globs"的最终形态,样式批量应用已可放心使用。
- 网格连线的适用范围:目前仅支持顶层单元格之间的简单连接;更复杂的跨层连接需等待后续版本。
v0.6.1 以 globs 重写和网格连线为核心,配合 UTF-16 支持、Markdown/箭头配色与一批格式化、渲染修复,是 0.6 系列向稳定形态收敛的关键版本。以上所有行为均可在 ci/release/changelogs/v0.6.1.md 及文中引用的源码、测试与 E2E 用例中得到验证。
【免费下载链接】d2D2 is a modern diagram scripting language that turns text to diagrams.项目地址: https://gitcode.com/GitHub_Trending/d2/d2
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考