diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec3350d..8873feb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,8 +6,6 @@
CommonMark reads it: `- a` then `* b`, `1. a` then `1) b`. `adfToLosslessMarkdown` gives a list
right after one of its kind the other marker, `* ` or `1)`, in place of the `::listBreak`
separator. Convert stored markdown per `MIGRATION.md`.
-- **Breaking:** two lists a link reference definition parts read as two lists, as CommonMark
- reads them, where they read as one; see `MIGRATION.md`.
- **Breaking:** each call names the markdown it reads or writes. `adfToMarkdown` and `markdownToAdf`
are now `adfToLosslessMarkdown` and `losslessMarkdownToAdf`. A bot's or a model's markdown reads
in `portableMarkdownToAdf`, and markdown known to be strict CommonMark in the new
@@ -58,6 +56,8 @@
`losslessMarkdownToAdf` refuses a directive mark wrapping only hard breaks as
`unsupported-node-shape`. `adfToLosslessMarkdown` writes a hard break holding marks as
`!adf:carry{json="…"}`. See `MIGRATION.md`.
+- **Breaking:** two lists a link reference definition parts read as two lists, as CommonMark
+ reads them, where `0.1.0` read one; see `MIGRATION.md`.
- `adfToLosslessMarkdown` and `adfToPortableMarkdown` write text holding a long run of `*`, `_`, `~`
or backticks, or a heading ending in a long run of `#`, in time linear in the run: a run of 20000
`*` took seconds before, and now takes milliseconds.
@@ -79,16 +79,16 @@
- Fix a cyclic document, in which an object holds itself: `adfToLosslessMarkdown` and
`adfToPortableMarkdown` refuse it as `not-an-adf-document` and `isAdfDocument` returns `false`,
where all three hung.
-- The README opens with what the package does and for whom, and `package.json` carries search
- keywords.
-- The source moves to [github.com/larvit/adf-codec](https://github.com/larvit/adf-codec), where
- issues and pull requests go.
- Add `adfToPortableMarkdown` and `portableMarkdownToAdf`, a lossy pair converting ADF to and from
markdown GitHub, GitLab and Obsidian render: alerts, callouts, task lists, `==highlights==` and
pipe tables. A task item keeps its paragraphs, then its nested task lists; the rest of the item,
such as an image or a code block, stands after the task list.
- Spell `rule`'s `color`, `style` and `weight`, `layoutSection`'s `columnRuleStyle` and a link's
`collection`, `id` and `occurrenceKey` directly where they rode the opaque carry.
+- The README opens with what the package does and for whom, and `package.json` carries search
+ keywords.
+- The source moves to [github.com/larvit/adf-codec](https://github.com/larvit/adf-codec), where
+ issues and pull requests go.
## 0.1.0
diff --git a/README.md b/README.md
index d6a73cc..a847a8b 100644
--- a/README.md
+++ b/README.md
@@ -239,8 +239,8 @@ Serves Goals 1, 4 and 5.
without a delimiter row, is an error result; each can be kept literal (`spec/flavour.md`).
- A document any reader built, written back with `adfToLosslessMarkdown`, takes the library's
canonical spelling, which round-trips byte-identically.
-- Six CommonMark spellings parse without an error and build a document the reference
- implementation renders differently. Four because ADF holds no node for what it renders:
+- These CommonMark spellings parse without an error and build a document the reference
+ implementation renders differently, where ADF holds no node for what it renders:
- An empty link text reads as its destination, `[](/url)` as `/url` linked to `/url`, and `[]()`
as nothing. A link text holding only hard breaks reads the same, followed by its hard breaks.
- An image reads as an image only alone in its paragraph. Anywhere else — beside other text, in
@@ -253,11 +253,12 @@ Serves Goals 1, 4 and 5.
- An image's title becomes its caption when the image stays an image, and its link's title when
it becomes linked alt text. Inside another link, the title is dropped.
- And two more: a shortcut reference matching its definition only under Unicode case folding
- stays unresolved, and a link whose text holds an autolink keeps the inner link and leaves the
- outer brackets literal text, which the spec requires and the reference itself breaks, nesting one
- `` in the other. `corpus/commonmark-spec/exceptions.json` pins the first four `node-model`
- where the suite reaches them and the fifth `pending`; the suite holds no example of the last.
+ And these: a shortcut reference matching its definition only under Unicode case folding stays
+ unresolved, and a link whose text holds an autolink keeps the inner link and leaves the outer
+ brackets literal text, which the spec requires and the reference itself breaks, nesting one ``
+ in the other. `corpus/commonmark-spec/exceptions.json` pins the spellings ADF holds no node for
+ `node-model` where the suite reaches them, and the case-folded reference `pending`; the suite
+ holds no example of a link holding an autolink.
- Not every document converts back: `adfToLosslessMarkdown` refuses a document nesting past 500
levels, and the node shapes the `unsupported-node-shape` row lists. Show the refusal and keep the
document read-only; saving markdown you could not produce is the loss the round-trip exists to
diff --git a/src/markdown/parse/blocks.ts b/src/markdown/parse/blocks.ts
index 8301004..a5abe84 100644
--- a/src/markdown/parse/blocks.ts
+++ b/src/markdown/parse/blocks.ts
@@ -75,8 +75,8 @@ type ContainerStack = {
type Walk = ParsedBlocks & {
claims: Claims
- // The block a paragraph of link reference definitions alone last closed after, which ends a list as any block does.
- definedAfter: Block | undefined
+ // The last block before a paragraph of link reference definitions alone, which ends a list as any block does.
+ endedByDefinitions: Block | undefined
leaf: OpenLeaf | undefined
leafOpeners: Map>
position: SourcePosition
@@ -91,8 +91,8 @@ export function parseBlocks(markdown: string, claims: Claims): ParsedBlocks {
const walk: Walk = {
blocks: [],
claims,
- definedAfter: undefined,
definitions: new Map(),
+ endedByDefinitions: undefined,
leaf: undefined,
leafOpeners: new Map(),
position: { line: 1, offset: 0 },
@@ -249,12 +249,12 @@ function openContainer(walk: Walk, start: ContainerStart): void {
walk.stack.push({ blocks, indentation: start.indentation, kind: 'item', list })
}
-// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list.
+// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list, unless definitions ended it.
function openedList(walk: Walk, start: Extract): ListBlock {
if (!start.fresh) return start.list
const blocks = currentBlocks(walk)
const previous = blocks.at(-1)
- if ((previous?.kind === 'bulletList' || previous?.kind === 'orderedList') && previous !== walk.definedAfter && continuesList(previous, start.list)) return previous
+ if ((previous?.kind === 'bulletList' || previous?.kind === 'orderedList') && previous !== walk.endedByDefinitions && continuesList(previous, start.list)) return previous
blocks.push(start.list)
return start.list
}
@@ -466,7 +466,8 @@ function closeLeaf(walk: Walk): void {
if (leaf === undefined) return
if (leaf.kind === 'paragraph') {
const paragraph = takeParagraph(walk)
- if (paragraph !== undefined) currentBlocks(walk).push(bareTableFault(paragraph, walk.claims) ?? paragraph)
+ if (paragraph === undefined) walk.endedByDefinitions = currentBlocks(walk).at(-1)
+ else currentBlocks(walk).push(bareTableFault(paragraph, walk.claims) ?? paragraph)
return
}
walk.leaf = undefined
@@ -517,10 +518,7 @@ function takeParagraph(walk: Walk): Extract | unde
if (leaf?.kind !== 'paragraph') return undefined
walk.leaf = undefined
const text = readLinkDefinitions(walk.definitions, leaf.lines.join('\n'))
- if (text === '') {
- walk.definedAfter = currentBlocks(walk).at(-1)
- return undefined
- }
+ if (text === '') return undefined
const kept = leaf.positions[leaf.lines.length - text.split('\n').length]
return { kind: 'paragraph', position: kept ?? leaf.position, text }
}
diff --git a/todo.md b/todo.md
index b21ac48..a59c61f 100644
--- a/todo.md
+++ b/todo.md
@@ -6,7 +6,7 @@
`Bar = 9`
-`Next ID = 98`
+`Next ID = 99`
| Goal | W |
|---|---|
@@ -35,6 +35,7 @@
| 96 | 0.2.1 | defect | **Read and write a text holding many unclosed backtick runs, or many `