diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd5552..14c8f07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,9 +55,9 @@ when the label runs over 999 characters, where it read them as a link or a definition. CommonMark caps a label at 999 characters, an escape counting as two. - Every reader leaves a link or a definition literal when its unbracketed destination holds a `(` - that is neither escaped nor closed by a `)` before the space ending the destination, where it - read it as a link: `[a](b(c "t")` is now text, as in CommonMark. Markdown the writers wrote reads - as before, since they escape such a parenthesis. + that is neither escaped nor closed, as CommonMark requires: `[a](b(c "t")` is now text, where it + read as a link to `b(c`. Markdown the writers wrote reads as before, since they escape such a + parenthesis. - The README compares the package with seven other ADF converters, each checked against its published version. diff --git a/src/markdown/commonmark/link-syntax.test.ts b/src/markdown/commonmark/link-syntax.test.ts index 10fc996..7455326 100644 --- a/src/markdown/commonmark/link-syntax.test.ts +++ b/src/markdown/commonmark/link-syntax.test.ts @@ -28,7 +28,7 @@ test('an unbracketed destination ends at its first unmatched `)`', () => { assert.deepEqual(targets('[a](b\\)c)'), [{ destination: 'b)c', length: 6 }]) }) -test('a destination holding an unbalanced unescaped `(` at a space or the end reads as none', () => { +test('an unbracketed destination with an unescaped `(` still open where it stops reads as none', () => { assert.deepEqual(targets('[a](b(c "t")'), [undefined]) assert.deepEqual(targets('[a](b(c "t") [d](e)'), [undefined, { destination: 'e', length: 3 }]) assert.deepEqual(targets('[a](b(c) "t")'), [{ destination: 'b(c)', length: 10, title: 't' }]) diff --git a/src/markdown/commonmark/link-syntax.ts b/src/markdown/commonmark/link-syntax.ts index bcaba70..627d8a9 100644 --- a/src/markdown/commonmark/link-syntax.ts +++ b/src/markdown/commonmark/link-syntax.ts @@ -72,7 +72,7 @@ export function targetMemo(text: string): TargetMemo { return { destinationEnds: undefined, tails: new Map(), text } } -// `ends[start]` is where an unbracketed destination from `start` stops, filled in one pass for every start a target can have: just after a `(`, a space or a control character, and 0, where `readDestination`'s run begins. At a stop only the innermost open start has its parentheses balanced, so the starts below it keep no end. +// `ends[start]` is where an unbracketed destination from `start` stops, for every start a target can have: just after a `(`, a space or a control character, and 0, where `readDestination`'s run begins. A destination stops at a space, a control character or the end of the text. Of the starts on the `open` stack only the innermost has its parentheses balanced there, so every start below it keeps 0, which reads as no destination. function destinationEnds(text: string): Int32Array { const ends = new Int32Array(text.length + 1) let open = [0]