Fix line endings in nested labels

Closes GH-13.
This commit is contained in:
Titus Wormer 2021-12-04 10:46:32 +01:00
parent ed6c0bbfcd
commit 68d01105ec
No known key found for this signature in database
GPG key ID: E6E581152ED04E2E
2 changed files with 79 additions and 45 deletions

View file

@ -1,6 +1,7 @@
/**
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Token} Token
*/
import {ok as assert} from 'uvu/assert'
@ -35,6 +36,8 @@ export function factoryLabel(
) {
let size = 0
let balance = 0
/** @type {Token|undefined} */
let previous
return start
@ -59,43 +62,28 @@ export function factoryLabel(
}
effects.enter(stringType)
return atBreak(code)
return lineStart(code)
}
/** @type {State} */
function atBreak(code) {
if (code === codes.eof || size > constants.linkReferenceSizeMax) {
return nok(code)
}
if (code === codes.rightSquareBracket && !balance--) {
function lineStart(code) {
if (code === codes.rightSquareBracket && !balance) {
return atClosingBrace(code)
}
if (markdownLineEnding(code)) {
if (disallowEol) {
return nok(code)
}
effects.enter(types.lineEnding)
effects.consume(code)
effects.exit(types.lineEnding)
return atBreak
}
effects.enter(types.chunkText, {contentType: constants.contentTypeText})
return label(code)
const token = effects.enter(types.chunkText, {
contentType: constants.contentTypeText,
previous
})
if (previous) previous.next = token
previous = token
return data(code)
}
/** @type {State} */
function label(code) {
if (
code === codes.eof ||
markdownLineEnding(code) ||
size > constants.linkReferenceSizeMax
) {
effects.exit(types.chunkText)
return atBreak(code)
function data(code) {
if (code === codes.eof || size > constants.linkReferenceSizeMax) {
return nok(code)
}
if (
@ -110,8 +98,33 @@ export function factoryLabel(
return atClosingBrace(code)
}
if (markdownLineEnding(code)) {
if (disallowEol) {
return nok(code)
}
effects.consume(code)
return code === codes.backslash ? labelEscape : label
effects.exit(types.chunkText)
return lineStart
}
effects.consume(code)
return code === codes.backslash ? dataEscape : data
}
/** @type {State} */
function dataEscape(code) {
if (
code === codes.leftSquareBracket ||
code === codes.backslash ||
code === codes.rightSquareBracket
) {
effects.consume(code)
size++
return data
}
return data(code)
}
/** @type {State} */
@ -123,19 +136,4 @@ export function factoryLabel(
effects.exit(type)
return ok
}
/** @type {State} */
function labelEscape(code) {
if (
code === codes.leftSquareBracket ||
code === codes.backslash ||
code === codes.rightSquareBracket
) {
effects.consume(code)
size++
return label
}
return label(code)
}
}

View file

@ -1278,7 +1278,43 @@ test('content', (t) => {
t.equal(
micromark(':abbr[\na\r]', options({abbr})),
'<p><abbr>\na\r</abbr></p>',
'should support EOLs at the edges of a label'
'should support EOLs at the edges of a label (1)'
)
t.equal(
micromark(':abbr[\n]', options({abbr})),
'<p><abbr>\n</abbr></p>',
'should support EOLs at the edges of a label (2)'
)
t.equal(
micromark(':abbr[a\n:abbr[b]\nc]', options({abbr})),
'<p><abbr>a\n<abbr>b</abbr>\nc</abbr></p>',
'should support EOLs around nested directives'
)
t.equal(
micromark(':abbr[:abbr[\n]]', options({abbr})),
'<p><abbr><abbr>\n</abbr></abbr></p>',
'should support EOLs inside nested directives (1)'
)
t.equal(
micromark(':abbr[:abbr[a\nb]]', options({abbr})),
'<p><abbr><abbr>a\nb</abbr></abbr></p>',
'should support EOLs inside nested directives (2)'
)
t.equal(
micromark(':abbr[:abbr[\nb\n]]', options({abbr})),
'<p><abbr><abbr>\nb\n</abbr></abbr></p>',
'should support EOLs inside nested directives (3)'
)
t.equal(
micromark(':abbr[:abbr[\\\n]]', options({abbr})),
'<p><abbr><abbr><br />\n</abbr></abbr></p>',
'should support EOLs inside nested directives (4)'
)
t.equal(