From fb9a87640bacd9a6ecbcab484682a0808502f16f Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Fri, 9 Oct 2026 15:17:24 +0200 Subject: [PATCH] Answer stability round 1: tasksAsText takes the tasks and returns the items, numberedPastMarkers spells the bullets itself, the spec alternates bullet lists alone, and the migration row says the markers alternate --- MIGRATION.md | 2 +- spec/flavour.md | 4 ++-- src/markdown/portable/adf-to-portable-markdown.ts | 14 ++++---------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 5c9d2bb..fde60fb 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -65,7 +65,7 @@ function migrateMarkdown(stored: string) { | the `adf` code fence and `:adf{json="…"}` | the `adf:` code fence, its JSON without `type`, and `!adf:carry{json="…"}` | | `\:` keeps a directive literal | `\!adf:` keeps a directive literal | | `:adf{json="…"}` carrying a link for its `collection`, `id` or `occurrenceKey` | `!adf:link[text]{attrs}` | -| `::listBreak` between two lists of a kind | no separator, the second list's marker changed: `* ` for `- `, `1)` for `1.` | +| `::listBreak` between two lists of a kind | no separator, the second list's marker changed: `* ` for `- `, `1)` for `1.`, alternating | A colon run and `:name[` are plain text now, and `adf` an ordinary code block language; text holding an unescaped `!adf:` and a code fence whose info string opens `adf:` are claimed instead. diff --git a/spec/flavour.md b/spec/flavour.md index 1b6e8cd..084c42e 100644 --- a/spec/flavour.md +++ b/spec/flavour.md @@ -19,8 +19,8 @@ normalizes to it through the round-trip. single tilde or a run of three or more is literal text — and block structure resolves before inline, so a `~~~` line opens a CommonMark tilde code fence. - Bullet lists `- `; ordered lists incrementing `1.` `2.` `3.`, the first number the node's - `order` attribute. A bullet or task list right after a bullet or task list takes `* `, and an - ordered list right after an ordered one `1)`, since CommonMark starts a new list where the + `order` attribute. A bullet list right after a bullet list takes `* `, and an ordered list + right after an ordered one `1)`, since CommonMark starts a new list where the bullet character or the delimiter changes; the list after that takes `- ` or `1.` again. An item text of asterisks and spaces that would read as a rule after `* ` opens with a backslash, `* \**`. Continuation lines align with the first character diff --git a/src/markdown/portable/adf-to-portable-markdown.ts b/src/markdown/portable/adf-to-portable-markdown.ts index 0f17918..82e4238 100644 --- a/src/markdown/portable/adf-to-portable-markdown.ts +++ b/src/markdown/portable/adf-to-portable-markdown.ts @@ -136,23 +136,17 @@ function portableSequence(blocks: readonly AdfNode[], reduction: Reduction): Res function numberedPastMarkers(list: AdfNode): AdfNode { const order = nodeAttrs(list)['order'] if (list.type !== 'orderedList' || typeof order !== 'number' || order + nodeContent(list).length - 1 <= largestListMarker) return list - return numberedAsText(list) -} - -function numberedAsText(list: AdfNode): AdfNode { - const order = Number(nodeAttrs(list)['order']) return { content: nodeContent(list).map((item, offset) => itemOf(marked(nodeContent(item), `${order + offset}.`))), type: 'bulletList' } } // A task keeps its marker as text; a list item stands as one, and anything else nests in the item before it. -function tasksAsText(list: AdfNode): AdfNode { - if (list.type !== 'taskList') return list +function tasksAsText(tasks: readonly AdfNode[]): AdfNode[] { const items: AdfNode[] = [] - for (const child of nodeContent(list)) { + for (const child of tasks) { const previous = isTaskItem(child) || child.type === 'listItem' ? undefined : items.pop() items.push(itemOf(previous === undefined ? taskAsText(child) : [...nodeContent(previous), child])) } - return { content: items, type: 'bulletList' } + return items } function taskAsText(child: AdfNode): readonly AdfNode[] { @@ -271,7 +265,7 @@ function reduceTaskList(node: AdfNode, reduction: Reduction): Result for (const block of standsAlone ? [{ content: blocks, type: 'listItem' }] : blocks) tasks.push(block) } if (regular) return success(splitTaskList({ content: tasks, type: 'taskList' })) - return success(listOf(nodeContent(tasksAsText({ content: tasks, type: 'taskList' })), 'bulletList')) + return success(listOf(tasksAsText(tasks), 'bulletList')) } function reduceTask(task: AdfNode, at: Reduction): Result {