feat(turndown-plugin-gfm): adopt MD060 compact style for table cells

Style compact avoids extra padding with a single space around cell
content:

| Character | Meaning |
| --- | --- |
| Y | Yes |
| N | No |

Closes #8795
This commit is contained in:
Zexin Yuan 2026-02-26 23:35:38 +08:00
parent 8d233e66e1
commit 9e653a87b8
No known key found for this signature in database
3 changed files with 21 additions and 18 deletions

View File

@ -179,10 +179,10 @@ describe("Markdown export", () => {
> [!IMPORTANT]
> This is a very important information.
>${space}
> | | |
> | | |
> | --- | --- |
> | 1 | 2 |
> | 3 | 4 |
> | 1 | 2 |
> | 3 | 4 |
> [!CAUTION]
> This is a caution.
@ -374,10 +374,10 @@ describe("Markdown export", () => {
</figure>
`;
const expected = trimIndentation`\
| | |
| | |
| --- | --- |
| Hi | there |
| Hi | there |`;
| Hi | there |
| Hi | there |`;
expect(markdownExportService.toMarkdown(html)).toBe(expected);
});

View File

@ -96,7 +96,8 @@ rules.table = {
var columnCount = tableColCount(node);
var emptyHeader = ''
if (columnCount && !secondLineIsDivider) {
emptyHeader = '|' + ' |'.repeat(columnCount) + '\n' + '|'
// MD060 compact style: 2 spaces between pipes for empty cells
emptyHeader = '|' + ' |'.repeat(columnCount) + '\n' + '|'
for (var columnIndex = 0; columnIndex < columnCount; ++columnIndex) {
emptyHeader += ' ' + getBorder(getColumnAlignment(node, columnIndex)) + ' |';
}
@ -157,13 +158,15 @@ function isFirstTbody (element) {
)
}
// Format table cells following MD060 compact style:
// Each cell has 1 space padding on left and right (prefix + content + ' |').
// Empty cells result in 2 spaces between pipes (1 left + 1 right padding).
function cell (content, node = null, index = null) {
if (index === null) index = indexOf.call(node.parentNode.childNodes, node)
var prefix = ' '
if (index === 0) prefix = '| '
let filteredContent = content.trim().replace(/\n\r/g, '<br>').replace(/\n/g, "<br>");
filteredContent = filteredContent.replace(/\|+/g, '\\|')
while (filteredContent.length < 3) filteredContent += ' ';
if (node) filteredContent = handleColSpan(filteredContent, node, ' ');
return prefix + filteredContent + ' |'
}
@ -259,7 +262,7 @@ function nodeParentTable(node) {
function handleColSpan(content, node, emptyChar) {
const colspan = node.getAttribute('colspan') || 1;
for (let i = 1; i < colspan; i++) {
content += ' | ' + emptyChar.repeat(3);
content += ' |' + emptyChar;
}
return content
}

View File

@ -141,11 +141,11 @@
</div>
<pre class="expected">| Column 1 | Column 2 | Column 3 | Column 4 |
| --- | --- | --- | --- |
| | Row 1, Column 2 | Row 1, Column 3 | Row 1, Column 4 |
| Row 2, Column 1 | | Row 2, Column 3 | Row 2, Column 4 |
| Row 3, Column 1 | Row 3, Column 2 | | Row 3, Column 4 |
| Row 4, Column 1 | Row 4, Column 2 | Row 4, Column 3 | |
| | | | Row 5, Column 4 |</pre>
| | Row 1, Column 2 | Row 1, Column 3 | Row 1, Column 4 |
| Row 2, Column 1 | | Row 2, Column 3 | Row 2, Column 4 |
| Row 3, Column 1 | Row 3, Column 2 | | Row 3, Column 4 |
| Row 4, Column 1 | Row 4, Column 2 | Row 4, Column 3 | |
| | | | Row 5, Column 4 |</pre>
</div>
<div class="case" data-name="empty rows">
@ -174,7 +174,7 @@
<pre class="expected">| Heading 1 | Heading 2 |
| --- | --- |
| Row 1 | Row 1 |
| | |
| | |
| Row 3 | Row 3 |</pre>
</div>
@ -259,7 +259,7 @@
<tbody><tr><th>Heading</th></tr></tbody>
</table>
</div>
<pre class="expected">| |
<pre class="expected">| |
| --- |
| Heading |
| --- |</pre>
@ -272,7 +272,7 @@
<tr><td>Row 2 Cell 1</td><td>Row 2 Cell 2</td></tr>
</table>
</div>
<pre class="expected">| | |
<pre class="expected">| | |
| --- | --- |
| Row 1 Cell 1 | Row 1 Cell 2 |
| Row 2 Cell 1 | Row 2 Cell 2 |</pre>
@ -291,7 +291,7 @@
</tr>
</table>
</div>
<pre class="expected">| | |
<pre class="expected">| | |
| --- | --- |
| Heading | Not a heading |
| Heading | Not a heading |</pre>