GEML block types, illustrated · page 5 of 5 · spec 1.0 · 中文

GEML Blocks Illustrated · embed

An embed stands where other content belongs: src= names a section, a block or a run of prose in another document (or this one), and at render time that content appears here. It has no body of its own; what it has is a set of rules about what to take, how, and what must never be taken: part= selects which part of a heading, the embedded document is parsed as a document in its own right, the target must be .geml, schemes are restricted, cycles are errors. Inline it has a small sibling, ![[#id]]. All of this is measured here, together with two drafts: GEP-0010's use of embed for translation, and GEP-0011's leaf-value coordinates as projection targets.

Board

11 rules, each with its source and status

Specified written into the specification. GEP draft defined by a proposal, not yet in the spec. Observed not specified; what the reference implementation does today. No implementation gap was found on this page.

Specified 9 GEP draft 1 Observed 1
RuleSourceStatus
1src= names the content: a document, optionally with a fragment. No src is an embed-missing-src error; a body is ignored with an ignored-embed-body warning. src= is reference-checked like any reference: a fragment that does not exist is an unresolved-reference error.§3 · §5 · A.2Specified
2A fragment naming a heading selects the whole section: the heading and every block up to the next heading of the same or higher level. Naming a block selects that block. Naming a prose address (#budget-before-detail) selects that run of prose. No fragment selects the whole document.§3 · §4Specified
3part= applies to heading targets: head the heading line alone, body everything under it, intro up to the first subheading, whole the default. head and body partition whole. The same words as geml get --head/--body/--intro. On a non-heading target the whole target stands; an unknown value is a bad-embed-part warning and the whole target stands, because quietly selecting nothing is the failure §8.2 exists to prevent.§3 · A.3Specified
4The embedded document is parsed as a document in its own right and the target selected from the result — never spliced as text. Its meta, references, relative-path base and external data resolve against itself; in a chain, each document is the base for the next.§3Specified
5The target must be .geml: anything else is an embed-target-not-geml error and its bytes are never parsed as GEML. Only http, https, mailto and tel schemes are allowed; any other is refused when building the model and the attribute blanked (unsafe-embed-scheme error), ignoring U+0000–U+0020 in the scheme check. Cross-document resolution is confined to --root, symlinks resolved first, failing closed.§3 · §9.4 · §9.5 · A.2Specified
6A chain returning to a document already being expanded is a transclusion-cycle error; the chain is reported and never followed.§9.3 · A.2Specified
7Inline projection ![[#id]] / ![[doc.geml#id]]: the target must be a single-paragraph text block, whose inlines are inserted into the sentence; ![alt](doc.geml), embedding a document with media syntax, is a media-target-is-document error. ! is the projection prefix; a bare […] navigates.§5.1 · §5.2 · B.4Specified
8Rendering: a block embed expands into section.transclusion id data-src with the content verbatim; an inline projection is span.transclusion-inline data-src.--to htmlObserved
9Coordinates: in this document's model an embed is a raw block with an empty body and no addressable units inside, so #embedB[1]["col"] does not resolve, for reading or writing, and the error names the same coordinate on the embed's source. The converse is allowed for two shapes: a leaf value — ![[a.geml#vars["version"]]] yields 1.4 — and a whole row, inline as its cells joined by ", " on one line, as an embed a one-row table under the header; a whole column may not.§5.2 · GEP-0011Specified
10Translation projection: translate-to= is admitted by the geml-translator/v1 profile; on meta it is the document default, on an embed it overrides, none holds one block back; translator= is reserved until there is a second engine. A translated document contains nothing but embeds, so ids, order and every non-prose byte have one home. Without the profile it is an unknown-attribute warning.GEP-0010GEP draft
11External data and media src are fetched by the renderer at render time; the renderer treats them as untrusted, may confine them to the same origin and may require opt-in.§9.4Specified
part=

Embedding a section, or part of one

One heading target, five ways to take it. a.geml on the left is the source; b.geml embeds it.

whole · head · intro · body · unknown part Specified
GEML · a.geml (source)
=== meta
title = "Source A"
version = "1.4"
===
# Budget {#budget}
Lead-in paragraph of the budget section.
## Detail {#detail}
Detail paragraph.
=== table {#tbl format=csv}
Item,Cost
Hosting,120
===
=== text {#para}
One paragraph of prose to project inline.
===
=== data {#vars}
{"version": "1.4", "owner": "docs"}
===
GEML · b.geml (embedding)
=== embed {#whole src=a.geml#budget}
===
=== embed {#head src=a.geml#budget part=head}
===
=== embed {#intro src=a.geml#budget part=intro}
===
=== embed {#body src=a.geml#budget part=body}
===
=== embed {#odd src=a.geml#budget part=sideways}
===
--to html --root .
warning: embed: `part=sideways` is not `whole`, `head`, `body` or
  `intro`; the whole target stands (line 13)
section.transclusion #whole data-src="a.geml#budget"

Budget

Lead-in paragraph of the budget section.

Detail

Detail paragraph.

+ table #tbl, text #para, data #vars — the section runs to end of document
#head · part=head

Budget

#intro · part=intro

Lead-in paragraph of the budget section.

#body · part=body

Lead-in paragraph of the budget section.

Detail

Detail paragraph.

+ everything after, without the heading line
#odd · part=sideways → same as whole

Budget

…
A section
§3: a fragment naming a heading selects the whole section, from the heading up to the next heading of the same or higher level. #budget is an H1 with no other H1 after it, so the section runs to the end and includes #tbl, #para and #vars.
part=
A document assembled out of embeds should not hand-write its own headings — that is the drift it exists to remove — so it must be able to take just the body or just the head. The three words are exactly those of geml get --head/--body/--intro; a document address and a command-line selector do not each invent a vocabulary.
Unknown value
Not unknown-attribute, since the key is defined and only the value is not; the whole target stands rather than nothing, because quietly selecting nothing is the failure §8.2 guards against.
Base

The embedded document stands alone; prose and whole documents embed too

Relative paths, meta and external data resolve against the source document. The embedding side decides only where the result appears.

A prose address, a whole document, a block in this document Specified
GEML · b2.geml and from b.geml
=== embed {#lead src=a.geml#budget-before-detail}   %% the prose address §4 derives
===
=== embed {#all src=a.geml}                        %% no fragment: the whole document
===
=== embed {#local src=#b-local}                     %% a block in this document
===
=== text {#b-local}
Local text embedded above.
===
geml check · --to htmlok: no diagnostics
<section class="transclusion" id="lead" data-src="a.geml#budget-before-detail">
  <p>Lead-in paragraph of the budget section.
<section class="transclusion" id="all" data-src="a.geml">
  <h1>Budget … <h2>Detail … table, text, data, all of it
Inside a.gemlResolves against
=== table {src=rows.csv}a.geml's directory, not b.geml's
{{version}}a.geml's meta: 1.4
[[#detail]]a.geml's id space
a chain a → b → ceach document is the base for the next
Rule
§3: the document src= names must be parsed as a document in its own right, the target then selected from the result — never a run of text spliced in. So rows.csv inside a.geml resolves against a.geml's directory, exactly as when a.geml is opened on its own. The embedding side decides only where the result appears.
Prose
#budget-before-detail is the address §4 derives for prose between two blocks: container #budget, next block #detail, nothing before. That it can be embedded is what keeps prose from being lost when a document is assembled out of embeds.
Failures

Six failures, plus a cycle

Five errors and two warnings, matching A.2 row for row.

The second half of b.geml · c1.geml ↔ c2.geml Specified
GEML
=== embed {#nosrc}                              ← no src
===
=== embed {#withbody src=a.geml#tbl}
this body is ignored
===
=== embed {#md src=notes.md}                  ← not .geml
===
=== embed {#js src=javascript:alert(1)}
===
=== embed {#gone src=a.geml#nope}              ← fragment does not exist
===
Inline: … and media ![pic](a.geml).               ← a document embedded with media syntax

%% c1.geml embeds c2.geml#c2; c2.geml embeds c1.geml#c1
geml check --root .5 error 2 warning
error: embed: missing `src=` (line 22)
warning: embed body is ignored; the target lives in `src=` (line 24)
error: embed: `notes.md` is not a GEML document; `src=` names a `.geml`
  file (optionally with a #fragment) (line 27)
error: embed: `src=javascript:alert(1)` names a disallowed URL scheme (line 29)
error: unresolved reference `a.geml#nope` (line 31)
error: `![](a.geml)` projects a GEML document, which is not media: for
  block content use `=== embed {src=a.geml}`, for a phrase use
  `![[a.geml]]` (line 33)

c1.geml
error: transclusion cycle: c1.geml → c2.geml → c1.geml → c2.geml (line 5)
error
No src names no content; the bytes of a non-.geml file are never parsed as GEML; a disallowed scheme is blanked while building the model, so no consumer ever sees it; a missing fragment is an error like any reference; media syntax on a document is the wrong position; a cycle reports the whole chain and stops.
warning
A body that was written is merely ignored — the content lives in src; an unknown part, see the previous section.
Confinement
§9.4: resolution is confined to --root, symlinks are resolved before the boundary is judged, and with no root nothing resolves (unresolvable-document). Every probe runs with --root ..
Inline

Inline projection, leaf-value coordinates, and coordinates that do not pass through an embed

![[…]] puts a phrase or one value into a sentence. GEP-0011 draws two lines: what may be a target, and whether a coordinate can reach through an embed.

A single-paragraph text, a leaf value, and reaching through Specified
GEML · end of b.geml
Inline: ![[a.geml#para]] and a leaf value ![[a.geml#vars["version"]]].
Row through embed: [[#tbl]] but not #tbl[1]["Item"].
geml get
$ geml get b.geml '#tbl[1]["Item"]'            #tbl is an embed in b
error: `#tbl[1]["Item"]`: `embed` carries no addressable units inside
  it — a coordinate needs a table, a `data` block, or `meta` (GEP 0011);
  address it on the embed's source instead: `a.geml#tbl[1]["Item"]`
$ geml get --root . a.geml '#tbl[1]["Item"]'   read it on the source
Hosting
--to html --root .

Inline: One paragraph of prose to project inline. and a leaf value 1.4.

The first is span.transclusion-inline data-src="a.geml#para"; the second is the one leaf ["version"] of data block #vars.
Targets
§5.2: an inline projection's target is a text block of exactly one paragraph, or a coordinate naming a leaf value or a whole row of a table or view (#tickets[2], #tickets[summary]) — inline, a row is its cells joined by ", " on one line; as an embed, a one-row table under the header. A whole column, or a value-tree node holding more nodes, is not: it is as many values as it has members. A row index is positional, like a cell's; when "which row" is really a predicate, project from a view whose where= selects it.
Not through
In this document's model an embed is a raw block with an empty body whose target resolves at render time, so #tbl[1]["Item"] does not resolve in b.geml. Writing through it would edit another document from this one, breaking §6's one-source rule; reading through it would make one value depend on two moving parts. The error names the address that does resolve, the same coordinate on the embed's source: a.geml#tbl[1]["Item"].
Translation

A translated document contains nothing but embeds

GEP-0010: a translation is a projection along the language axis, the same shape as the .md projection along the format axis. The profile is registered; the spec has not taken it in.

translate-to=: a default on meta, an override on an embed, none to hold back GEP draft
GEML · tr.geml
=== meta
title = "translated"
profile = "geml-translator/v1"
translate-to = "zh"                      %% the document default
===
=== embed {src=a.geml#budget}               %% inherits zh
===
=== embed {src=a.geml#tbl translate-to=none}  %% this one is not translated
===
GEML · tr-noprofile.geml
=== embed {src=a.geml#budget translate-to=zh}   %% no profile declared
===
geml check --root .
tr.geml
ok: no diagnostics

tr-noprofile.geml
warning: unknown attribute `translate-to` for block type `embed` (line 4)
Shape
A translated document holds embeds and nothing else. Ids, order and every non-prose byte have exactly one home, so drift is not detected — it is impossible. This is the same relationship GEP-0006 gives A.geml projecting to A.md, moved to the language axis.
One key
translate-to is the default on meta, an override on an embed, and none holds one block back. Not lang, because code {lang=} says what a body already is, while this says what to do — two value spaces and two word classes cannot share a key. translator= is reserved: with one engine, a key choosing an engine would "parse, do nothing, and read as supported".
Admission
§8.6: a profile admits attribute key names only; the document model does not change. With the profile declared and recognized, the key stops warning; how a processor obtains a translator is implementation-defined, and one that cannot is still conformant.
Evidence

Probe files and measured output

All run with the repository's current build, node geml-parser/dist/geml.js, with --root .. The probes live under emb/ in the session scratch directory.

ProbeCoverscheck resultWhere on this page
a.geml · b.geml · notes.mdwhole section, head, intro, body, unknown part, block target, same-document target, no src, body, non-geml, disallowed scheme, missing fragment, media on a document, inline projection, leaf-value projection5 error 2 warningpart=, Failures, Inline
b2.gemla prose-address target, a whole-document target0 diagnosticsBase
c1.geml · c2.gemltwo documents embedding each other1 error transclusion-cycleFailures
tr.geml · tr-noprofile.gemltranslate-to with and without the profile0 diagnostics / 1 warningTranslation
get b.geml '#tbl[1]["Item"]'a coordinate through an embederror naming a.geml#tbl[1]["Item"]Inline