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