Skip to content

Commit c619227

Browse files
committed
fix(table): Fix cell alignment in serialized markdown
Table cells with lists or code blocks are hardcoded to left alignment though, as everything else would break markdown parsing later. Signed-off-by: Jonas <[email protected]>
1 parent 2791e96 commit c619227

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

src/nodes/Table/markdown.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { createMarkdownSerializer } from '../../extensions/Markdown.js'
1010
type Cell = {
1111
md: string
1212
lines: string[]
13+
nodeTypes: Set<string>
1314
align: string
1415
}
1516

@@ -37,7 +38,23 @@ function rowToMarkdown(
3738
while (cell.lines.length < row.length) cell.lines.push('')
3839
// Normalize lines in cell to have the same length
3940
cell.lines.forEach((line, lineIdx) => {
40-
cell.lines[lineIdx] = line.padEnd(columnWidths[cellIdx])
41+
// Node types with enforced left-alignment
42+
if (['listItem', 'taskItem', 'codeBlock'].some(nodeType => cell.nodeTypes.has(nodeType))) {
43+
cell.lines[lineIdx] = line.padEnd(columnWidths[cellIdx])
44+
return
45+
}
46+
47+
// Pad according to alignment
48+
if (cell.align === 'center') {
49+
const spaces = Math.max(columnWidths[cellIdx] - line.length, 0)
50+
const spacesStart = line.length + Math.floor(spaces / 2)
51+
const spacesEnd = line.length + Math.ceil(spaces / 2)
52+
cell.lines[lineIdx] = line.padStart(spacesStart).padEnd(spacesEnd)
53+
} else if (cell.align === 'right') {
54+
cell.lines[lineIdx] = line.padStart(columnWidths[cellIdx])
55+
} else {
56+
cell.lines[lineIdx] = line.padEnd(columnWidths[cellIdx])
57+
}
4158
})
4259
return cell
4360
})
@@ -80,6 +97,7 @@ function headerRowToMarkdown(
8097
// No space padding next to pipes in horizontal separator
8198
state.write('|')
8299
row.cells.forEach((cell, cellIdx) => {
100+
// Separator alignment
83101
const separatorWidth = columnWidths[cellIdx] + 2
84102
let separator = ''
85103
switch (cell.align) {
@@ -123,17 +141,24 @@ function tableToMarkdown(state: MarkdownSerializerState, node: Node) {
123141
const cellNodes = row.node.content.content
124142
cellNodes.forEach((node, cellIdx) => {
125143
columnWidths[cellIdx] = columnWidths[cellIdx] ?? 0
144+
145+
// Serialize cell content with all child nodes and split lines
126146
const md = serializer.serialize(node)
147+
const nodeTypes = new Set<string>();
148+
node.descendants((descendant) => {
149+
nodeTypes.add(descendant.type.name)
150+
})
127151
const lines = md.split(/\r?\n/).map((line) => {
128152
// Escape pipe character
129153
line = line.replace(/\|/, '\\$&')
130154
return line.trim()
131155
})
156+
132157
row.length = Math.max(row.length, lines.length)
133158
const lineLength = Math.max(...lines.map((line) => line.length))
134159
columnWidths[cellIdx] = Math.max(columnWidths[cellIdx], lineLength)
135160
const align = node.attrs?.textAlign ?? ''
136-
row.cells.push({ md, lines, align })
161+
row.cells.push({ md, lines, nodeTypes, align })
137162
})
138163
})
139164

src/tests/nodes/Table.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@ describe('Table extension', () => {
5050
)
5151

5252
const complexTable = `
53-
| #| header1 | header2 |
54-
|--:|-------------------|---------------|
55-
| 1| list: | code: | \\
53+
| # | header1 | header2 |
54+
|--:|------------------:|---------------|
55+
| 1 | list: | code: | \\
5656
| | | | \\
5757
| | * item1 | \`\`\`js | \\
5858
| | * item2 | const x = '1' | \\
5959
| | | \`\`\` | \\
6060
| | ![alt](/test.png) | |
61-
| 2| cell3 | cell4 |
62-
| 3| | cell5 |
63-
`
61+
| 2 | cell3 | cell4 |
62+
| 3 | | cell5 |
63+
`.trimStart()
6464
expect(markdownThroughEditor(complexTable)).toBe(complexTable)
6565
})
6666

0 commit comments

Comments
 (0)