Corpus 2e1: the carve-out escapes and the claimed line #19

Merged
lilleman merged 2 commits from carve-outs into main 2026-08-26 22:29:41 +02:00
5 changed files with 43 additions and 37 deletions
Showing only changes of commit 8d1d96a2ee - Show all commits
+1 -1
View File
@@ -4,7 +4,7 @@ One directory per contract kind, each landing with its milestone:
- `round-trip/``<name>.json` + `<name>.md`: the markdown `adfToMarkdown` must emit for that - `round-trip/``<name>.json` + `<name>.md`: the markdown `adfToMarkdown` must emit for that
document, byte for byte, and that `markdownToAdf` must read back to it (AGENTS.md §2). Grouped 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/``<name>.md` + `<name>.json`: markdown input, and the document - `normalization/``<name>.md` + `<name>.json`: markdown input, and the document
`markdownToAdf` must build from it. One-way; the markdown is not canonical. `markdownToAdf` must build from it. One-way; the markdown is not canonical.
- `errors/``<name>.md`: markdown input that must not convert. A `<name>.error` beside it - `errors/``<name>.md`: markdown input that must not convert. A `<name>.error` beside it
@@ -5,33 +5,6 @@
"panelType": "info" "panelType": "info"
}, },
"content": [ "content": [
{
"content": [
{
"text": ":::",
"type": "text"
}
],
"type": "paragraph"
},
{
"content": [
{
"text": "::: x",
"type": "text"
}
],
"type": "paragraph"
},
{
"content": [
{
"text": "::",
"type": "text"
}
],
"type": "paragraph"
},
{ {
"content": [ "content": [
{ {
@@ -64,6 +37,33 @@
} }
], ],
"type": "blockquote" "type": "blockquote"
},
{
"content": [
{
"text": ":::",
"type": "text"
}
],
"type": "paragraph"
},
{
"content": [
{
"text": "::: x",
"type": "text"
}
],
"type": "paragraph"
},
{
"content": [
{
"text": "::",
"type": "text"
}
],
"type": "paragraph"
} }
], ],
"type": "panel" "type": "panel"
@@ -1,13 +1,13 @@
:::panel info :::panel info
- \:::
> \:::
\::: \:::
\::: x \::: x
\:: \::
- \:::
> \:::
::: :::
\::: \:::
+3 -1
View File
@@ -86,7 +86,8 @@ function fenceNestingFault(markdown: string): string | undefined {
const run = colons[1]?.length ?? 0 const run = colons[1]?.length ?? 0
const enclosing = open[open.length - 1] const enclosing = open[open.length - 1]
if (colons[2] === '') { 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() open.pop()
continue 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\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\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('::::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('::::panel info\n- - :::panel warning\n B\n :::\n::::'), undefined)
assert.equal(fenceNestingFault(':::tableCell\n```text\n:::::::panel warning\n:::\n```\n:::'), undefined) assert.equal(fenceNestingFault(':::tableCell\n```text\n:::::::panel warning\n:::\n```\n:::'), undefined)
}) })
+8 -4
View File
@@ -84,8 +84,8 @@ detail is settled at its own milestone.
attribute fallback 2e owes, since the reservation leaves that node no other spelling attribute fallback 2e owes, since the reservation leaves that node no other spelling
whatever 1d decides for its `localId`. whatever 1d decides for its `localId`.
- [ ] **2e — Carve-outs and combinations.** Fixtures and emitter together, into - [ ] **2e — Carve-outs and combinations.** Fixtures and emitter together, into
`corpus/round-trip/combinations/` — the documents that cross what 2a2d isolated. `corpus/round-trip/combinations/`.
- [ ] **2e1 — The carve-outs and the claimed line.** The directory opens: the three carve-outs - [ ] **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 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 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. 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: 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 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 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 - [ ] **2f — The attributes CommonMark cannot hold.** 1d's settled answer: the block nodes
CommonMark spells — `blockquote`, `bulletList`, `codeBlock`, `heading`, `listItem`, CommonMark spells — `blockquote`, `bulletList`, `codeBlock`, `heading`, `listItem`,
`orderedList`, `paragraph`, `rule` — get directive sections in `spec/flavour.md` carrying `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 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 — 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 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/`, `src/` gets its hierarchy at the same split — `adf/`,
`markdown/`, `html/`, the grammar module shared inside `markdown/` — while the rename is `markdown/`, `html/`, the grammar module shared inside `markdown/` — while the rename is
still mechanical. Three files do not move whole: `block-directives.ts` and still mechanical. Three files do not move whole: `block-directives.ts` and