diagram 有两种用法。一种是装外部 DSL:正文原样交给 format= 选的渲染器,处理器只负责不解释它。另一种是内置的 geml-chart:图完全由属性描述、绑到一张表或一个记录数组上,所以处理器能逐条校验,一个打错的列名就是构建错误。这一页把两种都实测一遍,十几条校验逐条对上 A.4。
规范已定 规范或已接受的 GEP 写死的。实测 规范不规定、参考实现今天这样做。草案缺口 草案该说而没说的。实现偏差本页未发现。
| 规则 | 出处 | 状态 | |
|---|---|---|---|
| 外部 DSL | |||
| 1 | raw 体,format= 选一个可插拔渲染器(mermaid、graphviz、d2、plantuml…)。处理器必须暴露渲染器注册表,不得解释正文。未知 format 是 warning,正文保留。 | §7 · A.4 | 规范已定 |
| 2 | #id 让图可引用:[[#flow]],链接文字取 caption。 | §7 · §5.2 | 规范已定 |
| 3 | raw 体不做 {{key}} 插值,%% 行是正文。 | §4 | 规范已定 |
| 4 | 参考实现的注册表认识 mermaid、graphviz、d2、plantuml、geml-chart、geml-code-graph。只有 mermaid 有内置引擎:输出 pre.mermaid 并在页面引入 mermaid 模块脚本;其余三个 DSL 输出 pre.diagram-src data-format= 原文,不 warning;vega-lite 和任何未知名字 warning。 | --to html | 实测 |
| 数据绑定与 geml-chart | |||
| 5 | data= 三种目标同 table 的 src=:csv/tsv 或 json/jsonl 文件、#id、doc.geml#id。目标是 table 时贡献其模型(含计算列);是 data 块时必须是记录数组,图引用的列在每条记录里必须是标量;违规 error。 | §7.1 · A.4 | 规范已定 |
| 6 | geml-chart 全在属性里:type 五选一 bar line area pie scatter;通道 x(类目)、y(值,逗号列表即多系列)、series、size;x、y 必填;rows=data|all|summary。正文应为空,非空 warning。 | §7.1 | 规范已定 |
| 7 | 构建时校验:缺 data、目标非表、非记录数组、缺 type、未知 type、缺通道、未知列、未知 rows、y 列非数、rows=summary 无汇总行 → error;未用通道、rows=all 无汇总行 → warning。 | A.4 | 规范已定 |
| 8 | 外部数据渲染时取,列校验推迟到渲染器;http(s) 需渲染器 opt-in,因为取 URL 会泄露读者地址和时间。 | §7.1 · §9.4 | 规范已定 |
| 9 | 要更多(标注、参考线、热力图)用宿主 DSL:format=vega-lite data=#fy,正文 raw、不做列校验。 | §7.1 | 规范已定 |
| 10 | 渲染:geml-chart 输出内联 svg.geml-chart role="img",rect / path / text;不依赖外部脚本。 | --to html | 实测 |
| geml-code-graph(GEP-0003 已接受,codemap profile §6) | |||
| 11 | geml-code-graph 是一种被解释的 diagram 格式:把一份 codemap 文档树画成分层的方法流图。嵌入点只有一个属性 src=,指向 codemap 的 index.geml 或某个容器文档;正文为空,非空 warning。 | GEP-0003 · codemap §6 | 规范已定 |
| 12 | 根和深度从不在嵌入点写:来自 src 所指文档的 meta(entry、graph-depth)。视图配置随数据走,嵌入点不可能漂移;换根就是指向另一个容器文档,方法级下钻是点击交互,不是属性。 | GEP-0003 | 规范已定 |
| 13 | 缺 src=、src 解析不到都是 warning:画不出东西,文档没错。 | A.4 | 规范已定 |
| 14 | 渲染:figure.code-graph > div.cg-mount data-start data-graph,图数据内联成 JSON,布局在绘制时由页面脚本完成;解析失败时同一 figure 里是 p.render-error。 | --to html | 实测 |
| 15 | data= 可以指 view,就像指 table 一样;而画派生列时必须指 view:compute=/summary= 是 view 的属性,它们产出的列只存在于 view 上。画 §6.1 的 FY 就是 data=#fy25-report y=FY;把同一张图指向基表会得到 chart: column `FY` not found in table。(GEP-0012 正文未提图表时,这条曾记为草案缺口;§7 已在规范正文里定下。) | §7.1 · §6.1 | 规范已定 |
处理器对它们做的事完全一样:原样保留。差别只在渲染器有没有引擎。
=== diagram {#flow format=mermaid caption="Review flow"} graph LR A[Draft] --> B{Review} B -->|ok| C[Publish] === === diagram {#gv format=graphviz} digraph { a -> b } === === diagram {#d2 format=d2} a -> b === === diagram {#pu format=plantuml} @startuml a -> b @enduml === === diagram {#odd format=foo} anything at all, {{title}} is not interpolated in raw === See [[#flow]].
warning: no registered renderer for diagram format `foo`; body kept raw (line 21)
0 error(s), 1 warning(s)
See Review flow.
format 选渲染器,正文 raw 原样交过去,处理器必须暴露注册表、不得解释正文。未知 format 只是 warning,因为正文没有丢,只是没有人画它。data-format 的原文;宿主可以自己接引擎。vega-lite 虽然 §7.1 拿它举例,注册表里却没有,会 warning。这是「注册表开放」的正常状态,不是偏差。{{title}} 在 raw 体里不插值(§4),原样进了输出;%% 也一样。geml-chart:图全在属性里,所以能校验四个成功的例子:绑一个派生出计算列的 view、绑一个记录数组、绑一个 csv 文件画两条线、把汇总行当额外一点。
=== table {#fy format=csv} Segment,Q1,Q2 Cloud,124.5,131.2 Hardware,88.1,84.6 === === view {#fy-report src=#fy compute="FY = Q1 + Q2" summary="Segment = 'Total'; FY = sum(FY)"} === %% 表装事实;view 派生出 FY 与 Total 行 === data {#recs} [{"seg": "Cloud", "fy": 255.7}, {"seg": "Hardware", "fy": 172.7}] === === diagram {#ok format=geml-chart data=#fy-report type=bar x=Segment y=FY caption="FY revenue"} === %% FY 只存在于 view 上,所以绑 view,不是绑 #fy === diagram {#ok2 format=geml-chart data=#recs type=pie x=seg y=fy} === %% 记录数组:键投影成列 === diagram {#ok3 format=geml-chart data=rows.csv type=line x=Segment y="Q1, Q2"} === %% 文件;逗号列表 = 两个系列 === diagram {#sumrow format=geml-chart data=#fy-report type=bar x=Segment y=FY rows=all} === %% 汇总行作为额外一点
format 仍只选渲染器,但图的全部描述在属性里,处理器读得懂,所以列名、data 的 id、rows 都能在构建时对着表校验。正文留空;写了东西是 ignored-diagram-body warning。src= 同形。table 只贡献自己的列,它上面的 view 才把派生列一并贡献出来——所以 y=FY 必须指 #fy-report 而不是 #fy;把图绑到基表上是构建错误(chart: column `FY` not found in table)。data 块必须是非空的 map 序列,被引用的列每条记录都得是标量;没引用的列随便。文件是匿名表或匿名记录源。format=vega-lite data=#fy,正文 raw、不校验列。十一个 error、四个 warning,与 A.4 逐条对上。
=== diagram {#e1 format=geml-chart type=bar x=Segment y=FY} ← 没有 data === diagram {#e2 format=geml-chart data=#n …} ← #n 是 note === diagram {#e3 format=geml-chart data=#badrecs x=seg y=fy} ← 第 2 条记录缺 fy === diagram {#e4 format=geml-chart data=#fy-report x=Segment y=FY} ← 没有 type === diagram {#e5 … type=donut …} === diagram {#e6 … type=bar x=Segment} ← 缺 y === diagram {#e7 … y=Nope} === diagram {#w1 … type=bar x=Segment y=FY size=Q1} %% bar 不画 size === diagram {#e8 … rows=everything} === diagram {#w2 … type=bar x=Segment y=FY} this body is ignored === === diagram {#e9 … y=Segment} ← y 列不是数 %% d3:#plain 是个有 compute= 但没有 summary= 的 view === diagram {#s1 … data=#plain rows=summary} === diagram {#s2 … data=#plain rows=all} === diagram {#cg format=geml-code-graph} %% 没有 src === diagram {#vl format=vega-lite data=#plain} {"mark": "bar", "encoding": {"y": {"field": "Nope"}}} %% 不校验列 ===
warning: geml-chart body is ignored; the chart spec lives in attributes (line 45) error: geml-chart: missing `data=#id` (line 27) error: geml-chart: data target `#n` is not a table (line 29) error: geml-chart: column `fy` is missing or non-scalar in record 2 (line 31) error: chart: missing `type` (line 33) error: chart: unknown type `donut` (supported: bar, line, area, pie, scatter; use format=vega-lite for others) (line 35) error: chart: missing required channel `y` (line 37) error: chart: column `Nope` not found in table (line 39) warning: chart: `size` is ignored for type `bar` (line 41) error: chart: unknown rows scope `everything` (data|all|summary) (line 43) error: chart: non-numeric value in a y column (line 48) d3-chart.geml warning: geml-code-graph: missing `src=` (nothing to render) (line 12) warning: no registered renderer for diagram format `vega-lite`; body kept raw (line 14) error: chart: rows=summary but the table has no summary row (line 8) warning: chart: rows=all but the table has no summary row; using data rows (line 10)
Nope 列没有被检查,符合 §7.1「宿主 DSL 的正文 raw 且不做列校验」;那条 warning 是注册表里没有它的渲染器,不是列错。geml-code-graph:把一份 codemap 画成方法流图GEP-0003 已接受。它和 geml-chart 一样是被解释的格式,但走到了另一个极端:嵌入点只有 src=,别的什么都不能写。
playground/codemap/ 里跑,跑完删除;那里有 geml codemap build 生成的 index.geml 和每个容器一份的文档。=== diagram {#g format=geml-code-graph src=index.geml caption="Repo graph"} === === diagram {#g2 format=geml-code-graph src=geml-parser--chart.ts.geml#chart} === %% 带片段:不是它认的目标 === diagram {#g3 format=geml-code-graph src=nowhere.geml} === === diagram {#g4 format=geml-code-graph src=index.geml} body here is ignored ===
warning: geml-code-graph: cannot resolve document `geml-parser--chart.ts.geml#chart` (line 7) warning: geml-code-graph: cannot resolve document `nowhere.geml` (line 9) warning: geml-code-graph body is ignored; the embed is configured by `src=` alone (line 11) 0 error(s), 3 warning(s) exit 0 <figure class="code-graph" id="g"><div class="cg-mount" data-start="…" data-graph="{…}"> <figure class="code-graph" id="g2"><p class="render-error">… <figure class="code-graph" id="g3"><p class="render-error">…
entry,深度是 graph-depth,嵌入点写不了这些,所以嵌入点不可能和数据漂移。想换根就指向另一个容器文档;想看方法级细节就点节点,那是交互不是属性。全部用仓库内当前构建 node geml-parser/dist/geml.js 跑出。
| 探针 | 覆盖 | check 结果 | 页面里对应 |
|---|---|---|---|
| d1-diagram.geml | mermaid、graphviz、d2、plantuml、未知 foo、raw 不插值、caption 自动文字 | 1 warning | 外部 DSL |
| d2-chart.geml · rows.csv | 四个成功例;缺 data、非表、非记录数组、缺 type、未知 type、缺通道、未知列、未用通道、未知 rows、正文非空、y 非数 | 9 error 2 warning | geml-chart、校验 |
| d3-chart.geml | rows=summary 无汇总行、rows=all 无汇总行、code-graph 缺 src、vega-lite 正文不校验 | 1 error 3 warning | 校验 |
| playground/codemap/_probe-cg.geml | 指向真实 codemap 的 index、带片段的目标、不存在的文档、非空正文 | 3 warning | geml-code-graph |