From 9f4b9774dd55b56685aad9fff3ae2f97b32a8eeb Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Mon, 24 Aug 2026 13:33:04 +0200 Subject: [PATCH] Pin block separation, the image guard's media, and the attribute and boundary cases the corpus missed --- .../round-trip/block-nodes/image-boundary.json | 16 ++++++++++++++++ corpus/round-trip/block-nodes/image-boundary.md | 4 ++++ corpus/round-trip/block-nodes/layout.json | 1 + corpus/round-trip/block-nodes/layout.md | 2 +- corpus/round-trip/block-nodes/media-single.json | 4 ++++ corpus/round-trip/block-nodes/media-single.md | 4 ++-- .../round-trip/block-nodes/table-directive.json | 5 ++++- corpus/round-trip/block-nodes/table-directive.md | 4 ++-- corpus/round-trip/block-nodes/table-pipe.json | 11 ++++++++++- corpus/round-trip/block-nodes/table-pipe.md | 2 +- spec/flavour.md | 12 +++++++----- todo.md | 11 ++++++++--- 12 files changed, 60 insertions(+), 16 deletions(-) diff --git a/corpus/round-trip/block-nodes/image-boundary.json b/corpus/round-trip/block-nodes/image-boundary.json index 15b2b86..9267159 100644 --- a/corpus/round-trip/block-nodes/image-boundary.json +++ b/corpus/round-trip/block-nodes/image-boundary.json @@ -58,6 +58,22 @@ } ], "type": "mediaSingle" + }, + { + "attrs": { + "layout": "center" + }, + "content": [ + { + "attrs": { + "collection": "contentId-98237", + "id": "01a03389-e4eb-76a1-9eae-e8b7a01f4787", + "type": "file" + }, + "type": "media" + } + ], + "type": "mediaSingle" } ], "type": "doc", diff --git a/corpus/round-trip/block-nodes/image-boundary.md b/corpus/round-trip/block-nodes/image-boundary.md index 3148474..5d44004 100644 --- a/corpus/round-trip/block-nodes/image-boundary.md +++ b/corpus/round-trip/block-nodes/image-boundary.md @@ -12,3 +12,7 @@ Taken from Kiruna. :::mediaSingle {layout=center} ::media {height=480 type=external url="https://example.com/plan.png" width=640} ::: + +:::mediaSingle {layout=center} +::media {collection=contentId-98237 id=01a03389-e4eb-76a1-9eae-e8b7a01f4787 type=file} +::: diff --git a/corpus/round-trip/block-nodes/layout.json b/corpus/round-trip/block-nodes/layout.json index 7e50794..8405400 100644 --- a/corpus/round-trip/block-nodes/layout.json +++ b/corpus/round-trip/block-nodes/layout.json @@ -7,6 +7,7 @@ "content": [ { "attrs": { + "localId": "01a03389-a5fb-747d-b418-e91f1b161e7f", "width": 50 }, "content": [ diff --git a/corpus/round-trip/block-nodes/layout.md b/corpus/round-trip/block-nodes/layout.md index fa83e92..12d73a5 100644 --- a/corpus/round-trip/block-nodes/layout.md +++ b/corpus/round-trip/block-nodes/layout.md @@ -1,5 +1,5 @@ ::::layoutSection {localId=01a033cc-4b60-7b5e-85f4-34f27f039e9a} -:::layoutColumn {width=50} +:::layoutColumn {localId=01a03389-a5fb-747d-b418-e91f1b161e7f width=50} Left. ::: :::layoutColumn {valign=top width=50} diff --git a/corpus/round-trip/block-nodes/media-single.json b/corpus/round-trip/block-nodes/media-single.json index b9275ab..87e61d3 100644 --- a/corpus/round-trip/block-nodes/media-single.json +++ b/corpus/round-trip/block-nodes/media-single.json @@ -15,6 +15,9 @@ "type": "media" }, { + "attrs": { + "localId": "01a03389-670b-7331-ae60-0446747ace7a" + }, "content": [ { "text": "The moon, at night.", @@ -37,6 +40,7 @@ "attrs": { "alt": "Torque chart", "height": 480, + "localId": "01a03389-8683-7c05-bfbb-457bcdb0ced3", "type": "external", "url": "https://example.com/torque.png", "width": 640 diff --git a/corpus/round-trip/block-nodes/media-single.md b/corpus/round-trip/block-nodes/media-single.md index 999543b..1a8c575 100644 --- a/corpus/round-trip/block-nodes/media-single.md +++ b/corpus/round-trip/block-nodes/media-single.md @@ -1,10 +1,10 @@ ::::mediaSingle {layout=center width=50} ::media {collection=MediaServicesSample id=4478e39c-cf9b-41d1-ba92-68589487cd75 type=file} -:::caption +:::caption {localId=01a03389-670b-7331-ae60-0446747ace7a} The moon, at night. ::: :::: :::mediaSingle {layout=wrap-right width="33.33" widthType=percentage} -::media {alt="Torque chart" height=480 type=external url="https://example.com/torque.png" width=640} +::media {alt="Torque chart" height=480 localId=01a03389-8683-7c05-bfbb-457bcdb0ced3 type=external url="https://example.com/torque.png" width=640} ::: diff --git a/corpus/round-trip/block-nodes/table-directive.json b/corpus/round-trip/block-nodes/table-directive.json index bcfa4d5..0280c0f 100644 --- a/corpus/round-trip/block-nodes/table-directive.json +++ b/corpus/round-trip/block-nodes/table-directive.json @@ -2,6 +2,7 @@ "content": [ { "attrs": { + "displayMode": "fixed", "isNumberColumnEnabled": true, "layout": "default", "localId": "01a0339e-c34f-7658-9d98-eb059401b7ab", @@ -41,7 +42,9 @@ "content": [ { "attrs": { - "background": "#deebff" + "background": "#deebff", + "localId": "01a03389-c573-72a6-a036-6cd9c6865301", + "rowspan": 2 }, "content": [ { diff --git a/corpus/round-trip/block-nodes/table-directive.md b/corpus/round-trip/block-nodes/table-directive.md index 59408b2..b070153 100644 --- a/corpus/round-trip/block-nodes/table-directive.md +++ b/corpus/round-trip/block-nodes/table-directive.md @@ -1,11 +1,11 @@ -:::::table {isNumberColumnEnabled=true layout=default localId=01a0339e-c34f-7658-9d98-eb059401b7ab width=760} +:::::table {displayMode=fixed isNumberColumnEnabled=true layout=default localId=01a0339e-c34f-7658-9d98-eb059401b7ab width=760} ::::tableRow :::tableHeader {colspan=2 colwidth="[340,420]"} Assembly ::: :::: ::::tableRow {localId=01a033a9-d034-7466-b916-68643be958ff} -:::tableCell {background="#deebff"} +:::tableCell {background="#deebff" localId=01a03389-c573-72a6-a036-6cd9c6865301 rowspan=2} Bolt M8 ::: :::tableCell {valign=top} diff --git a/corpus/round-trip/block-nodes/table-pipe.json b/corpus/round-trip/block-nodes/table-pipe.json index 515cad6..e0cb469 100644 --- a/corpus/round-trip/block-nodes/table-pipe.json +++ b/corpus/round-trip/block-nodes/table-pipe.json @@ -56,7 +56,16 @@ { "content": [ { - "text": "Grade 8.8", + "text": "Grade ", + "type": "text" + }, + { + "marks": [ + { + "type": "code" + } + ], + "text": "8.8", "type": "text" } ], diff --git a/corpus/round-trip/block-nodes/table-pipe.md b/corpus/round-trip/block-nodes/table-pipe.md index 5d04f78..f69b148 100644 --- a/corpus/round-trip/block-nodes/table-pipe.md +++ b/corpus/round-trip/block-nodes/table-pipe.md @@ -1,6 +1,6 @@ | Part | Note | | --- | --- | -| Bolt M8 | Grade 8.8 | +| Bolt M8 | Grade `8.8` | | Nut \| washer | Sold as a pair | | Washer M8 | 100 pcs:hardBreak{}zinc-plated | | Spare | | diff --git a/spec/flavour.md b/spec/flavour.md index 537931e..b601f69 100644 --- a/spec/flavour.md +++ b/spec/flavour.md @@ -42,8 +42,9 @@ normalizes to it through the round-trip. the leading delimiter of a construct that would otherwise open, re-scan from there, and repeat — with the opener literal the closer parses as text, so `*not emphasis*` is `\*not emphasis*`, one backslash. -- Blocks separated by one blank line, no trailing whitespace outside a code block's content, - single trailing newline; a document with no blocks is the empty string. +- Blocks separated by one blank line — at document level, and between CommonMark blocks; two + directive blocks inside a container take none. No trailing whitespace outside a code block's + content, single trailing newline; a document with no blocks is the empty string. ## Directives @@ -198,9 +199,10 @@ The moon, at night. **The CommonMark image.** A paragraph whose entire inline content is one image `![alt](url)` is a `mediaSingle` with attrs exactly `{"layout":"center"}` holding an `external` `media` — `url` from the destination, `alt` the description's plain-text content when non-empty. `adfToMarkdown` -emits the image form for exactly that shape — those attrs and no others, no marks, no caption. -An image amid other text, or one carrying a title, is a named error: `mediaInline` carries a -media `collection` + `id`, never a URL, and no media node carries a title. +emits the image form for exactly that shape — those attrs and no others, no marks, no caption, +and a `media` carrying nothing beyond `alt`, `type` and `url`. An image amid other text, or one +carrying a title, is a named error: `mediaInline` carries a media `collection` + `id`, never a +URL, and no media node carries a title. ### Tables diff --git a/todo.md b/todo.md index 0fe45a9..1b8b345 100644 --- a/todo.md +++ b/todo.md @@ -38,7 +38,11 @@ detail is settled at its own milestone. read back as href `…/a` plus literal `b)`; title `He said "hi"` emits `[t](u "He said "hi"")`, which holds no title. Two defensible spellings each — angle brackets or a backslash escape, and for titles `'…'` or `(…)` besides — so §8 leaves the - pick here. + pick here. **Also blocked**: block separation is unstated for a CommonMark block beside a + directive block in a container body — a `panel` (`panelType` `info`) whose content is + `paragraph` "A" then a `panel` (`panelType` `warning`) holding "B" spells `A` and + `:::panel warning` either on consecutive lines or with a blank line between. Two defensible + spellings, so §8 leaves the pick here. - [x] **1d1 — The CommonMark subset**: blockquote, bulletList, codeBlock, heading, orderedList, paragraph, rule, listItem, hardBreak, text, code spans, and the `code`, `em`, `link`, `strike` and `strong` marks — one mark per text node; nesting is 1d5's. @@ -51,8 +55,9 @@ detail is settled at its own milestone. - [ ] **1d4 — Opaque carry** (§3): an unknown node in both positions, the reserved `adf` info string, and the `codeBlock` whose language is `adf`. - [ ] **1d5 — Carve-outs and combinations**: the three carve-outs and their escapes, mark - nesting order and the runs a carry breaks, attribute canonicalization, and documents - combining nodes rather than isolating one. + nesting order and the runs a carry breaks, attribute canonicalization, documents + combining nodes rather than isolating one, and a paragraph line inside a container body + shaped like a closing fence (`:::`, `::: x`). - [ ] **1d6 — Input normalization**: one-way markdown→ADF fixtures, not pairs — setext headings, indented code, loose lists, `*`/`+` bullets, entity references, soft wraps. - [ ] **1d7 — Error input**: also one-way, a markdown input per named error, asserting only