diff --git a/corpus/README.md b/corpus/README.md index 083985b..8aa572c 100644 --- a/corpus/README.md +++ b/corpus/README.md @@ -4,7 +4,7 @@ One directory per contract kind, each landing with its milestone: - `round-trip/` — `.json` + `.md`: the markdown `adfToMarkdown` must emit for that document, byte for byte, and that `markdownToAdf` must read back to it (AGENTS.md §2). Grouped - by node family, `combinations/` holding what crosses them. + by what the fixture exercises. - `normalization/` — `.md` + `.json`: markdown input, and the document `markdownToAdf` must build from it. One-way; the markdown is not canonical. - `errors/` — `.md`: markdown input that must not convert. A `.error` beside it diff --git a/corpus/round-trip/combinations/closing-fence-line.json b/corpus/round-trip/combinations/closing-fence-line.json index 35f33ee..46c8a02 100644 --- a/corpus/round-trip/combinations/closing-fence-line.json +++ b/corpus/round-trip/combinations/closing-fence-line.json @@ -5,33 +5,6 @@ "panelType": "info" }, "content": [ - { - "content": [ - { - "text": ":::", - "type": "text" - } - ], - "type": "paragraph" - }, - { - "content": [ - { - "text": "::: x", - "type": "text" - } - ], - "type": "paragraph" - }, - { - "content": [ - { - "text": "::", - "type": "text" - } - ], - "type": "paragraph" - }, { "content": [ { @@ -64,6 +37,33 @@ } ], "type": "blockquote" + }, + { + "content": [ + { + "text": ":::", + "type": "text" + } + ], + "type": "paragraph" + }, + { + "content": [ + { + "text": "::: x", + "type": "text" + } + ], + "type": "paragraph" + }, + { + "content": [ + { + "text": "::", + "type": "text" + } + ], + "type": "paragraph" } ], "type": "panel" diff --git a/corpus/round-trip/combinations/closing-fence-line.md b/corpus/round-trip/combinations/closing-fence-line.md index 18fbff8..4057703 100644 --- a/corpus/round-trip/combinations/closing-fence-line.md +++ b/corpus/round-trip/combinations/closing-fence-line.md @@ -1,13 +1,13 @@ :::panel info +- \::: + +> \::: + \::: \::: x \:: - -- \::: - -> \::: ::: \::: diff --git a/src/corpus.test.ts b/src/corpus.test.ts index 9b8bf72..33e87d8 100644 --- a/src/corpus.test.ts +++ b/src/corpus.test.ts @@ -86,7 +86,8 @@ function fenceNestingFault(markdown: string): string | undefined { const run = colons[1]?.length ?? 0 const enclosing = open[open.length - 1] if (colons[2] === '') { - if (enclosing !== undefined && run < enclosing) return `${JSON.stringify(line)} is shorter than the ${enclosing} colons it would close` + if (enclosing === undefined) return `${JSON.stringify(line)} closes no open container` + if (run < enclosing) return `${JSON.stringify(line)} is shorter than the ${enclosing} colons it would close` open.pop() continue } @@ -101,6 +102,7 @@ test('the fence nesting check catches a fence a container cannot hold', () => { assert.equal(fenceNestingFault(':::panel info\n- - :::panel warning\n B\n :::\n:::'), '"- - :::panel warning" sits in a container fenced with 3 colons') assert.equal(fenceNestingFault(':::panel info\n10. :::panel warning\n B\n :::\n:::'), '"10. :::panel warning" sits in a container fenced with 3 colons') assert.equal(fenceNestingFault('::::panel info\n:::\n::::'), '":::" is shorter than the 4 colons it would close') + assert.equal(fenceNestingFault('Text\n:::\n'), '":::" closes no open container') assert.equal(fenceNestingFault('::::panel info\n- - :::panel warning\n B\n :::\n::::'), undefined) assert.equal(fenceNestingFault(':::tableCell\n```text\n:::::::panel warning\n:::\n```\n:::'), undefined) }) diff --git a/todo.md b/todo.md index 51abf10..f6722de 100644 --- a/todo.md +++ b/todo.md @@ -84,8 +84,8 @@ detail is settled at its own milestone. attribute fallback 2e owes, since the reservation leaves that node no other spelling whatever 1d decides for its `localId`. - [ ] **2e — Carve-outs and combinations.** Fixtures and emitter together, into - `corpus/round-trip/combinations/` — the documents that cross what 2a–2d isolated. - - [ ] **2e1 — The carve-outs and the claimed line.** The directory opens: the three carve-outs + `corpus/round-trip/combinations/`. + - [ ] **2e1 — The carve-outs and the claimed line.** The three carve-outs and their escapes, and a paragraph line inside a container body shaped like a closing fence (`:::`, `::: x`). Guard `fenceNestingFault`'s bare-run pop here too — a run shorter than the open fence is a fault, not a close — which today's emitter cannot reach. @@ -117,7 +117,8 @@ detail is settled at its own milestone. and it is provable without one. It also settles the emitter's one known approximation: delimiter flanking is exact, but CommonMark's *matching* — the multiple-of-3 rule and the way a run splits across several openers — is not modelled. No reachable violation has been - found by hand; the property test is what decides it. + found by hand; the property test is what decides it, and 2e1's `carve-out-strike` pins a + second backslash only flanking-without-matching emits. - [ ] **2f — The attributes CommonMark cannot hold.** 1d's settled answer: the block nodes CommonMark spells — `blockquote`, `bulletList`, `codeBlock`, `heading`, `listItem`, `orderedList`, `paragraph`, `rule` — get directive sections in `spec/flavour.md` carrying @@ -140,7 +141,10 @@ detail is settled at its own milestone. assumes — CommonMark flanking, as for `*` — which `spec/flavour.md` does not yet pin, and the precedence between a directive and the constructs a raw attribute value opens inside it — a code span, an entity, raw HTML — which one directive alone already reaches until 2e's - escape lands. + escape lands. Whether a claimed line interrupts a paragraph is pinned for the plain case and + unstated for the lazy one: a closing fence on the line after a blockquote's open paragraph is + lazy continuation in CommonMark, which would swallow the fence and leave the container + unclosed. 2e1's `closing-fence-line` orders its blockquote away from that edge meanwhile. `src/` gets its hierarchy at the same split — `adf/`, `markdown/`, `html/`, the grammar module shared inside `markdown/` — while the rename is still mechanical. Three files do not move whole: `block-directives.ts` and