From 01b2ed4706f658bd3ddf2b4b03e14c895fde00c4 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Thu, 18 Jun 2026 13:22:22 +0100 Subject: [PATCH 1/2] fix: keep a hard break before an attention run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a hard break was immediately followed by an attention run (emphasis or strong) whose inner side is whitespace, the break was turned into text on a round-trip: {type: 'paragraph', children: [ {type: 'break'}, {type: 'strong', children: [{type: 'text', value: ' x'}]} ]} serialized to `\ ** x**`, where the break’s line ending was character-referenced. The attention run asks to encode the character on its outer side (here whitespace, to keep the run forming), and that character happened to be the `\n` of the break, so the break was destroyed. A line ending can never fuse with the following run — the run starts on a new line — so skip the surrounding encoding when the preceding character is a line ending. --- lib/util/container-phrasing.js | 6 +++++- test/index.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/util/container-phrasing.js b/lib/util/container-phrasing.js index 3b4dc46..4f9c4c2 100644 --- a/lib/util/container-phrasing.js +++ b/lib/util/container-phrasing.js @@ -104,7 +104,11 @@ export function containerPhrasing(parent, state, info) { if ( results.length > 0 && encodingInfo.before && - before === results[results.length - 1].slice(-1) + before === results[results.length - 1].slice(-1) && + // A line ending (such as a hard break) is structural: encoding it would + // break the break, and it can’t fuse with the following attention run. + before !== '\n' && + before !== '\r' ) { results[results.length - 1] = results[results.length - 1].slice(0, -1) + diff --git a/test/index.js b/test/index.js index e47facd..24a75d9 100644 --- a/test/index.js +++ b/test/index.js @@ -746,6 +746,22 @@ test('break', async function (t) { assert.equal(to({type: 'break'}), '\\\n') }) + await t.test( + 'should not character-reference a break before an attention run', + async function () { + assert.equal( + to({ + type: 'paragraph', + children: [ + {type: 'break'}, + {type: 'strong', children: [{type: 'text', value: ' x'}]} + ] + }), + '\\\n** x**\n' + ) + } + ) + await t.test( 'should serialize breaks in heading (atx) as a space', async function () { From a88d00173b37ef79fbf5efb84e2f5da75713c031 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Mon, 22 Jun 2026 18:32:45 +0100 Subject: [PATCH 2/2] Remove explanatory comments --- lib/util/container-phrasing.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/util/container-phrasing.js b/lib/util/container-phrasing.js index 4f9c4c2..21a039c 100644 --- a/lib/util/container-phrasing.js +++ b/lib/util/container-phrasing.js @@ -105,8 +105,6 @@ export function containerPhrasing(parent, state, info) { results.length > 0 && encodingInfo.before && before === results[results.length - 1].slice(-1) && - // A line ending (such as a hard break) is structural: encoding it would - // break the break, and it can’t fuse with the following attention run. before !== '\n' && before !== '\r' ) {