From 5ccf910c2ec1c5dca406da528c3d0442c168d4db Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Fri, 7 Nov 2025 12:07:25 +0800 Subject: [PATCH 1/5] fix: removing unnecessary empty paragraph check --- src/core/render/compiler/blockquote.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/core/render/compiler/blockquote.js b/src/core/render/compiler/blockquote.js index 5f00951de..e249623b9 100644 --- a/src/core/render/compiler/blockquote.js +++ b/src/core/render/compiler/blockquote.js @@ -20,17 +20,10 @@ export const blockquoteCompiler = ({ renderer }) => token[key] = token[key].replace(calloutMark, '').trimStart(); }); - // Remove empty paragraph - if (tokens.length > 1 && !token.raw.trim()) { - tokens = tokens.slice(1); - } - openTag = `
`; closeTag = `
`; } const body = this.parser.parse(tokens); - const html = `${openTag}${body}${closeTag}`; - - return html; + return `${openTag}${body}${closeTag}`; }); From 8245bda775e1bafa718d3bfccbb53bc779acc963 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Tue, 11 Nov 2025 14:15:39 +0800 Subject: [PATCH 2/5] feat: enhance blockquoteCompiler to support callouts with empty lines --- src/core/render/compiler/blockquote.js | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/render/compiler/blockquote.js b/src/core/render/compiler/blockquote.js index e249623b9..5cafc66ee 100644 --- a/src/core/render/compiler/blockquote.js +++ b/src/core/render/compiler/blockquote.js @@ -1,27 +1,37 @@ 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]; + + if (firstParagraph) { + // Check if the paragraph starts with a callout like [!TIP] or [!NOTE] + const calloutData = firstParagraph.raw.match(/^(\[!(\w+)\])/); + + 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, '').trimStart();} + if (t.text) {t.text = t.text.replace(calloutMark, '').trimStart();} + }); + } - // Remove callout mark from tokens - ['raw', 'text'].forEach(key => { - token[key] = token[key].replace(calloutMark, '').trimStart(); - }); + // If the first paragraph is now empty after removing [!TIP], remove it + if (!firstParagraph.raw.trim()) { + tokens.splice(firstParagraphIndex, 1); + } - openTag = `
`; - closeTag = `
`; + openTag = `
`; + closeTag = `
`; + } } const body = this.parser.parse(tokens); From b5f180c2bbb67975358b52bbb1f3129a4c4ddd8d Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Tue, 11 Nov 2025 14:17:59 +0800 Subject: [PATCH 3/5] fix: lint --- src/core/render/compiler/blockquote.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/core/render/compiler/blockquote.js b/src/core/render/compiler/blockquote.js index 5cafc66ee..2bc1bce82 100644 --- a/src/core/render/compiler/blockquote.js +++ b/src/core/render/compiler/blockquote.js @@ -16,11 +16,17 @@ export const blockquoteCompiler = ({ renderer }) => const calloutType = calloutData[2].toLowerCase(); // "tip" // Remove the callout mark from the paragraph raw text - firstParagraph.raw = firstParagraph.raw.replace(calloutMark, '').trimStart(); + 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, '').trimStart();} - if (t.text) {t.text = t.text.replace(calloutMark, '').trimStart();} + if (t.raw) { + t.raw = t.raw.replace(calloutMark, '').trimStart(); + } + if (t.text) { + t.text = t.text.replace(calloutMark, '').trimStart(); + } }); } From f313859a8f45bad3fcde8b7ae296d31ba11cdc6f Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Wed, 12 Nov 2025 11:04:47 +0800 Subject: [PATCH 4/5] fix: remove unnecessary trimming of callout marks in blockquote processing --- src/core/render/compiler/blockquote.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/render/compiler/blockquote.js b/src/core/render/compiler/blockquote.js index 2bc1bce82..8fc2607e1 100644 --- a/src/core/render/compiler/blockquote.js +++ b/src/core/render/compiler/blockquote.js @@ -22,10 +22,10 @@ export const blockquoteCompiler = ({ renderer }) => if (firstParagraph.tokens && firstParagraph.tokens.length > 0) { firstParagraph.tokens.forEach(t => { if (t.raw) { - t.raw = t.raw.replace(calloutMark, '').trimStart(); + t.raw = t.raw.replace(calloutMark, ''); } if (t.text) { - t.text = t.text.replace(calloutMark, '').trimStart(); + t.text = t.text.replace(calloutMark, ''); } }); } From 44dae254a7828a4238580f23c75e8477e6e58b3e Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Wed, 12 Nov 2025 11:24:23 +0800 Subject: [PATCH 5/5] test: update snapshot --- test/integration/render.test.js | 35 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) 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)', () => {