Flavour spec 1b: block node syntaxes #4

Merged
lilleman merged 3 commits from flavour-blocks into main 2026-08-24 09:39:09 +02:00
4 changed files with 18 additions and 12 deletions
Showing only changes of commit af146a5425 - Show all commits
+3 -2
View File
@@ -19,7 +19,8 @@ The other direction is a canonical fixpoint, not byte-identity: human markdown n
back yields the library's canonical spelling, and that spelling round-trips byte-identically.
"Equals" is structural equality over editor-normal ADF — adjacent text nodes with identical marks
merged, JSON number semantics — the only domain markdown can restore.
merged, JSON number semantics, an empty attrs object, marks array or content array the absent
key — the only domain markdown can restore.
Round-trip equality is a property tested over a corpus, not a claim made in prose.
@@ -36,7 +37,7 @@ Round-trip equality is a property tested over a corpus, not a claim made in pros
- Directives, one grammar for everything markdown lacks: `:::panel info``:::` blocks,
`:mention[@Mikael]{id=5b10a2}` inline. Prior art: CommonMark's generic-directives proposal.
- Plain CommonMark is a subset, with carve-outs (`spec/flavour.md`): literal text shaped like a
directive or a pipe table is claimed.
directive or a pipe table is claimed — plus one image gap.
- Tables: one header row plus plain inline cells → pipe table; anything richer → directive form.
- Identity-bearing nodes carry their ids in attributes; a document is only portable within its
site — accepted.
+3 -2
View File
@@ -40,8 +40,9 @@ isAdfDocument(v: unknown): v is AdfDocument
attributes.
- Plain CommonMark is valid input to `markdownToAdf`, with two carve-outs — literal text
matching directive or pipe-table syntax is claimed (escapable — `spec/flavour.md`) — and one
gap: an image title has no ADF home (an error result). Converting back yields the library's
canonical spelling, which round-trips byte-identically.
gap: a CommonMark image fits only as its own title-less paragraph; mid-text and titled images
are error results. Converting back yields the library's canonical spelling, which round-trips
byte-identically.
- Foreign HTML maps a documented element set; an unmappable element is an error, never a silent
drop. Well-formed HTML only — no tag-soup recovery.
- The emitted formats are semver surface (AGENTS.md §8).
+10 -7
View File
@@ -3,7 +3,8 @@
The grammar of the extended markdown `adfToMarkdown` emits and `markdownToAdf` parses. Plain
CommonMark is a subset with two carve-outs: literal text that matches directive syntax below or
opens a pipe table is claimed by the flavour (escape the `:` or `|` to keep it literal) — and
one gap: an image title has no ADF home (a named error). The emitted form is contract
one gap: a CommonMark image fits only as its own title-less paragraph — mid-text and titled
images are named errors (ADF has a slot for neither). The emitted form is contract
(AGENTS.md §8). Per-node syntaxes build on this grammar in the sections below (inline nodes and
marks: todo.md 1c).
@@ -125,8 +126,8 @@ payloads hold; the type stays string and any value round-trips verbatim. Values
type: strings verbatim, numbers and booleans in canonical JSON spelling — quoted where not bare
(`width="33.33"`) — and `json` values as the inline carry's serialization (compact, keys
sorted), quoted. `markdownToAdf` emits `attrs`, `content` and `marks` keys only when non-empty;
editor-normal ADF (AGENTS.md §2) also reads an empty attrs object, marks array or content array
as the absent key — the grammar's empty-`{attrs}` omission already collapses the two spellings.
editor-normal ADF reads an empty attrs object, marks array or content array as the absent key
(AGENTS.md §2) — the grammar's empty-`{attrs}` omission already collapses the two spellings.
Marks on a block node ride the reserved attribute key `marks` — the node's marks array as a
`json` value: `::::layoutSection {marks="[{\"attrs\":{\"mode\":\"wide\"},\"type\":\"breakout\"}]"}`.
@@ -194,8 +195,9 @@ One header row plus plain inline cells is a pipe table; anything richer is the d
(AGENTS.md §4). Precisely: a table emits as a pipe table exactly when the `table`, every row
and every cell carry no attrs and no marks, the first row is all `tableHeader` and the rest all
`tableCell`, every row has the header's cell count, and every cell holds exactly one attr-less,
mark-less paragraph — an empty cell holds one empty paragraph. A pipe table parses back to
exactly that shape.
mark-less paragraph — an empty cell holds one empty paragraph — with no `|` in a code span:
backslash escapes are inert there, so pipe form cannot spell that pipe and the table takes the
directive form. A pipe table parses back to exactly that shape.
```
| Part | Qty |
@@ -207,8 +209,9 @@ Claiming at block level, symmetric with directives: a line opening with an unesc
claimed and must parse as part of a pipe table, else it is a named error — escape the pipe
(`\|`) to keep it literal text. A pipe table is a header row, a delimiter row whose cells are
runs of one or more `-` (canonical `---`), and body rows; rows follow code-fence indentation.
Cells split on unescaped `|` before inline parsing; each cell is the inline content of one
paragraph, trimmed; canonical form pads cells with single spaces and ends rows with `|`
Cells split on unescaped `|` before inline parsing`\|` stays in the cell text, and the
inline layer's ordinary CommonMark escaping yields the pipe; each cell is the inline content of
one paragraph, trimmed; canonical form pads cells with single spaces and ends rows with `|`
(optional in input). Named errors: a delimiter or body row whose cell count differs from the
header's, and an alignment colon in the delimiter row — ADF holds no column alignment. In a
pipe cell a hard break is `:hardBreak{}`, a literal `|` is `\|`, and `|` inside a quoted
+2 -1
View File
@@ -16,7 +16,8 @@ detail is settled at its own milestone.
lists, layout, extensions, syncBlock.
- [ ] **1c — Inline node syntaxes and marks** in `spec/flavour.md`: mention, emoji, status, date,
inlineCard, mediaInline; underline, subsup, textColor, border; the spelling for text nodes
whose whitespace CommonMark cannot hold (literal newlines, leading or trailing spaces).
whose whitespace CommonMark cannot hold (literal newlines, leading or trailing spaces)
escape-based, never literal, since pipe cells trim and pad.
- [ ] **1d — Corpus start** (§10): checked-in ADF ↔ canonical-markdown fixture pairs per spec'd
node.
- [ ] **2 — `adfToMarkdown`.** First real code — decide here where §10's coverage check lives.