diagram is used two ways. One hosts an external DSL: the body goes verbatim to the renderer format= selects, and the processor's only duty is not to interpret it. The other is the built-in geml-chart: the chart is described entirely in attributes and bound to a table or a record array, so the processor can check it piece by piece and a mistyped column name is a build error. A third, geml-code-graph, is interpreted too but takes the opposite stance: the embed carries one attribute and nothing else. All three are measured here; the chart's fifteen checks match A.4 row for row.
Specified written into the specification or an accepted GEP. Observed not specified; what the reference implementation does today. Draft gap something a draft should say and does not. No implementation gap was found on this page.
| Rule | Source | Status | |
|---|---|---|---|
| External DSLs | |||
| 1 | Raw body; format= selects a pluggable renderer (mermaid, graphviz, d2, plantuml …). A processor must expose the renderer registry and must not interpret the body. An unknown format is a warning; the body is kept. | §7 · A.4 | Specified |
| 2 | #id makes the diagram referenceable: [[#flow]], with the caption as link text. | §7 · §5.2 | Specified |
| 3 | No {{key}} interpolation in a raw body; a %% line is body text. | §4 | Specified |
| 4 | The reference implementation's registry knows mermaid, graphviz, d2, plantuml, geml-chart and geml-code-graph. Only mermaid has a bundled engine: it emits pre.mermaid and loads the mermaid module on the page; the other three DSLs emit pre.diagram-src data-format= verbatim with no warning; vega-lite and any unknown name warn. | --to html | Observed |
| Data binding and geml-chart | |||
| 5 | data= takes the three targets a table's src= takes: a csv/tsv or json/jsonl file, #id, doc.geml#id. A table contributes its model (computed columns included); a data block must be a record array, and every column the chart references must be a scalar in every record; a violation is an error. | §7.1 · A.4 | Specified |
| 6 | geml-chart lives entirely in attributes: type is one of five, bar line area pie scatter; channels x (category), y (value; a comma list is several series), series, size; x and y required; rows=data|all|summary. The body should be empty; a non-empty one warns. | §7.1 | Specified |
| 7 | Build-time checks: no data, target not a table, not a record array, no type, unknown type, missing channel, unknown column, unknown rows, non-numeric y, rows=summary with no summary row → error; an unused channel, rows=all with no summary row → warning. | A.4 | Specified |
| 8 | External data is fetched at render time and column checks are deferred to the renderer; http(s) needs renderer opt-in, because fetching a URL discloses the reader's address and time. | §7.1 · §9.4 | Specified |
| 9 | For more (annotations, reference lines, heatmaps) use a hosted DSL: format=vega-lite data=#fy; the body is raw and not column-checked. | §7.1 | Specified |
| 10 | Rendering: geml-chart emits an inline svg.geml-chart role="img" with rect / path / text; no external script. | --to html | Observed |
| geml-code-graph (GEP-0003, accepted; codemap profile §6) | |||
| 11 | geml-code-graph is an interpreted diagram format: a layered method-flow view over a codemap document tree. The embed takes exactly one attribute, src=, naming the codemap's index.geml or one container document; the body is empty, and a non-empty one warns. | GEP-0003 · codemap §6 | Specified |
| 12 | Roots and depth are never authored at the embed: they come from the meta of the document src points at (entry, graph-depth). View configuration travels with the data, so the embed cannot drift; a different root means pointing at a different container document, and method-level drill-down is a click, not an attribute. | GEP-0003 | Specified |
| 13 | A missing src= and an unresolvable src are both warnings: nothing to draw, but the document is not wrong. | A.4 | Specified |
| 14 | Rendering: figure.code-graph > div.cg-mount data-start data-graph, the graph data inlined as JSON and laid out by a page script at draw time; a failed resolution puts a p.render-error in the same figure. | --to html | Observed |
| 15 | data= may name a view as readily as a table, and for a derived column it must: compute=/summary= are a view's, so the column they produce exists only there. Charting §6.1's FY is data=#fy25-report y=FY; aiming the same chart at the base table is chart: column `FY` not found in table. (This was carried here as a draft gap while GEP-0012 said nothing about charts; §7 now settles it in the normative text.) | §7.1 · §6.1 | Specified |
The processor treats them identically: keep the body verbatim. The only difference is whether the renderer has an engine.
=== 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 selects the renderer, the raw body is handed over verbatim, and the processor must expose the registry and never interpret the body. An unknown format is only a warning because nothing was lost — nobody drew it, that is all.data-format; a host can attach its own engine. vega-lite, though §7.1 uses it as an example, is not in the registry and warns. That is the normal state of an open registry, not a gap.{{title}} is not interpolated in a raw body (§4) and reaches the output as written; so does %%.geml-chart: the chart lives in attributes, so it can be checkedFour working examples: bound to a view that derives a computed column, to a record array, to a csv file drawing two series, and with the summary row as an extra point.
=== 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)"} === %% the table holds facts; the view derives FY and the Total row === 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 exists only on the view, so bind there — not to #fy === diagram {#ok2 format=geml-chart data=#recs type=pie x=seg y=fy} === %% record array: keys project to columns === diagram {#ok3 format=geml-chart data=rows.csv type=line x=Segment y="Q1, Q2"} === %% a file; a comma list = two series === diagram {#sumrow format=geml-chart data=#fy-report type=bar x=Segment y=FY rows=all} === %% the summary row as one extra point
format still only selects the renderer, but the whole description is in attributes the processor can read, so column names, the data id and rows are validated against the table at build time. The body stays empty; anything written there is an ignored-diagram-body warning.src= shape. A table contributes its own columns; a view over it contributes the derived ones as well, which is why y=FY has to name #fy-report and not #fy — pointing the chart at the base table is a build error (chart: column `FY` not found in table). A data block must be a non-empty sequence of maps, and every referenced column must be a scalar in every record; unreferenced columns may hold anything. A file is an anonymous table or record source.format=vega-lite data=#fy, raw body, columns unchecked.Eleven errors and four warnings, matching A.4 row for row.
=== diagram {#e1 format=geml-chart type=bar x=Segment y=FY} ← no data === diagram {#e2 format=geml-chart data=#n …} ← #n is a note === diagram {#e3 format=geml-chart data=#badrecs x=seg y=fy} ← record 2 lacks fy === diagram {#e4 format=geml-chart data=#fy-report x=Segment y=FY} ← no type === diagram {#e5 … type=donut …} === diagram {#e6 … type=bar x=Segment} ← no y === diagram {#e7 … y=Nope} === diagram {#w1 … type=bar x=Segment y=FY size=Q1} %% bar does not draw size === diagram {#e8 … rows=everything} === diagram {#w2 … type=bar x=Segment y=FY} this body is ignored === === diagram {#e9 … y=Segment} ← y column is not numeric %% d3: #plain is a view with compute= but no summary= === diagram {#s1 … data=#plain rows=summary} === diagram {#s2 … data=#plain rows=all} === diagram {#cg format=geml-code-graph} %% no src === diagram {#vl format=vega-lite data=#plain} {"mark": "bar", "encoding": {"y": {"field": "Nope"}}} %% columns not checked ===
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 column in the body was not checked, as §7.1 says of hosted DSLs; the warning is that the registry has no renderer for it, not a column error.geml-code-graph: a codemap drawn as a method-flow graphGEP-0003, accepted. Interpreted like geml-chart, but at the other extreme: the embed carries src= and nothing else.
playground/codemap/ and was deleted afterwards; that directory holds the index.geml and one document per container that geml codemap build generated.=== 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} === %% with a fragment: not a target it accepts === 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, the depth its graph-depth; the embed cannot write either, so it cannot drift from the data. A different root means a different container document; method-level detail is a click on a node — interaction, not an attribute.All run with the repository's current build, node geml-parser/dist/geml.js.
| Probe | Covers | check result | Where on this page |
|---|---|---|---|
| d1-diagram.geml | mermaid, graphviz, d2, plantuml, unknown foo, raw not interpolated, caption as link text | 1 warning | External DSLs |
| d2-chart.geml · rows.csv | four working charts; no data, not a table, not a record array, no type, unknown type, missing channel, unknown column, unused channel, unknown rows, non-empty body, non-numeric y | 9 error 2 warning | geml-chart, Checks |
| d3-chart.geml | rows=summary with no summary row, rows=all with none, code-graph without src, vega-lite body unchecked | 1 error 3 warning | Checks |
| playground/codemap/_probe-cg.geml | the real codemap's index, a target with a fragment, a missing document, a non-empty body | 3 warning | geml-code-graph |