From 68d01105ec2c0b6bda90292fb72c7c03a46a0a16 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Sat, 4 Dec 2021 10:46:32 +0100 Subject: [PATCH] Fix line endings in nested labels Closes GH-13. --- dev/lib/factory-label.js | 86 ++++++++++++++++++++-------------------- test/index.js | 38 +++++++++++++++++- 2 files changed, 79 insertions(+), 45 deletions(-) diff --git a/dev/lib/factory-label.js b/dev/lib/factory-label.js index 9db4167..7d1d3d2 100644 --- a/dev/lib/factory-label.js +++ b/dev/lib/factory-label.js @@ -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) + effects.exit(types.chunkText) + return lineStart + } + 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} */ @@ -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) - } } diff --git a/test/index.js b/test/index.js index 45df6b4..75b364a 100644 --- a/test/index.js +++ b/test/index.js @@ -1278,7 +1278,43 @@ test('content', (t) => { t.equal( micromark(':abbr[\na\r]', options({abbr})), '

\na\r

', - '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})), + '

\n

', + 'should support EOLs at the edges of a label (2)' + ) + + t.equal( + micromark(':abbr[a\n:abbr[b]\nc]', options({abbr})), + '

a\nb\nc

', + 'should support EOLs around nested directives' + ) + + t.equal( + micromark(':abbr[:abbr[\n]]', options({abbr})), + '

\n

', + 'should support EOLs inside nested directives (1)' + ) + + t.equal( + micromark(':abbr[:abbr[a\nb]]', options({abbr})), + '

a\nb

', + 'should support EOLs inside nested directives (2)' + ) + + t.equal( + micromark(':abbr[:abbr[\nb\n]]', options({abbr})), + '

\nb\n

', + 'should support EOLs inside nested directives (3)' + ) + + t.equal( + micromark(':abbr[:abbr[\\\n]]', options({abbr})), + '


\n

', + 'should support EOLs inside nested directives (4)' ) t.equal(