diff --git a/packages/comark/src/internal/parse/tree.ts b/packages/comark/src/internal/parse/tree.ts index db37c4f3..62640668 100644 --- a/packages/comark/src/internal/parse/tree.ts +++ b/packages/comark/src/internal/parse/tree.ts @@ -606,7 +606,11 @@ const processors: Record = { if (frameTag !== null && frameTag.toLowerCase() === closeTag) break idx-- } - if (idx < 0) return { nextIndex: start + 1, node: undefined } + if (idx < 0) { + // HTML parsers read a stray `
` as `
` + const node: Node | undefined = closeTag === 'br' ? ['br', makeHtmlAttrs({}, false)] : undefined + return { nextIndex: start + 1, node } + } let closed: Node | undefined while (state.htmlStack.length > idx) { diff --git a/packages/comark/test/html-block.test.ts b/packages/comark/test/html-block.test.ts index e1176705..f519535f 100644 --- a/packages/comark/test/html-block.test.ts +++ b/packages/comark/test/html-block.test.ts @@ -474,4 +474,51 @@ describe('stray HTML close tags', () => { expect(result.nodes).toEqual([['p', {}, ' orphan']]) }) + + it('reads a stray `
` as a line break', async () => { + const result = await parseMarkdown('**Experimental feature**
\nEnable View Transitions.') + + expect(result.nodes).toEqual([ + [ + 'p', + {}, + ['strong', {}, 'Experimental feature'], + ['br', { $: { html: 1, block: 0 } }], + 'Enable View Transitions.', + ], + ]) + }) + + it('reads a lone `
` as a block `
`', async () => { + const result = await parseMarkdown('
') + + expect(result.nodes).toEqual([['br', { $: { html: 1, block: 1 } }]]) + expect(result.nodes).toEqual((await parseMarkdown('
')).nodes) + }) + + it('reads a `
` line between paragraphs as a block `
`', async () => { + const result = await parseMarkdown('before\n\n
\n\nafter') + + expect(result.nodes).toEqual([ + ['p', {}, 'before'], + ['br', { $: { html: 1, block: 1 } }], + ['p', {}, 'after'], + ]) + }) + + it('reads a lone `
` as a block `
` when markdown: false', async () => { + const result = await parseMarkdown('
', { + plugins: [html({ markdown: false })], + }) + + expect(result.nodes).toEqual([['br', { $: { html: 1, block: 1 } }]]) + }) + + it('keeps a stray `
` inside the open inline element', async () => { + const result = await parseMarkdown('a
b
') + + expect(result.nodes).toEqual([ + ['span', { $: { html: 1, block: 0 } }, 'a', ['br', { $: { html: 1, block: 0 } }], 'b'], + ]) + }) })