diff --git a/src/core/render/compiler/blockquote.js b/src/core/render/compiler/blockquote.js index 5f00951de..8fc2607e1 100644 --- a/src/core/render/compiler/blockquote.js +++ b/src/core/render/compiler/blockquote.js @@ -1,36 +1,45 @@ export const blockquoteCompiler = ({ renderer }) => (renderer.blockquote = function ({ tokens }) { - const calloutData = - tokens[0].type === 'paragraph' && - // 0: Match "[!TIP] My Title" - // 1: Mark "[!TIP]" - // 2: Type "TIP" - tokens[0].raw.match(/^(\[!(\w+)\])/); - let openTag = '
'; let closeTag = '
'; - if (calloutData) { - const calloutMark = calloutData[1]; // "[!TIP]" - const calloutType = calloutData[2].toLowerCase(); // "tip" - const token = tokens[0].tokens[0]; + // Find the first paragraph token in the blockquote + const firstParagraphIndex = tokens.findIndex(t => t.type === 'paragraph'); + const firstParagraph = tokens[firstParagraphIndex]; - // Remove callout mark from tokens - ['raw', 'text'].forEach(key => { - token[key] = token[key].replace(calloutMark, '').trimStart(); - }); + if (firstParagraph) { + // Check if the paragraph starts with a callout like [!TIP] or [!NOTE] + const calloutData = firstParagraph.raw.match(/^(\[!(\w+)\])/); - // Remove empty paragraph - if (tokens.length > 1 && !token.raw.trim()) { - tokens = tokens.slice(1); - } + if (calloutData) { + const calloutMark = calloutData[1]; // "[!TIP]" + const calloutType = calloutData[2].toLowerCase(); // "tip" + + // Remove the callout mark from the paragraph raw text + firstParagraph.raw = firstParagraph.raw + .replace(calloutMark, '') + .trimStart(); + if (firstParagraph.tokens && firstParagraph.tokens.length > 0) { + firstParagraph.tokens.forEach(t => { + if (t.raw) { + t.raw = t.raw.replace(calloutMark, ''); + } + if (t.text) { + t.text = t.text.replace(calloutMark, ''); + } + }); + } - openTag = `
`; - closeTag = `
`; + // If the first paragraph is now empty after removing [!TIP], remove it + if (!firstParagraph.raw.trim()) { + tokens.splice(firstParagraphIndex, 1); + } + + openTag = `
`; + closeTag = `
`; + } } const body = this.parser.parse(tokens); - const html = `${openTag}${body}${closeTag}`; - - return html; + return `${openTag}${body}${closeTag}`; }); diff --git a/test/integration/render.test.js b/test/integration/render.test.js index ff8182779..22442ebcc 100644 --- a/test/integration/render.test.js +++ b/test/integration/render.test.js @@ -15,41 +15,46 @@ describe('render', function () { test('caution', () => { const output = window.marked('> [!CAUTION]\n> Text'); - expect(output).toMatchInlineSnapshot( - `"

Text

"`, - ); + expect(output).toMatchInlineSnapshot(` +"

+Text

" +`); }); test('important', () => { const output = window.marked('> [!IMPORTANT]\n> Text'); - expect(output).toMatchInlineSnapshot( - `"

Text

"`, - ); + expect(output).toMatchInlineSnapshot(` +"

+Text

" +`); }); test('note', () => { const output = window.marked('> [!NOTE]\n> Text'); - expect(output).toMatchInlineSnapshot( - `"

Text

"`, - ); + expect(output).toMatchInlineSnapshot(` +"

+Text

" +`); }); test('tip', () => { const output = window.marked('> [!TIP]\n> Text'); - expect(output).toMatchInlineSnapshot( - `"

Text

"`, - ); + expect(output).toMatchInlineSnapshot(` +"

+Text

" +`); }); test('warning', () => { const output = window.marked('> [!WARNING]\n> Text'); - expect(output).toMatchInlineSnapshot( - `"

Text

"`, - ); + expect(output).toMatchInlineSnapshot(` +"

+Text

" +`); }); test('important (legacy)', () => {