Skip to content

Commit 1c2cb7b

Browse files
committed
Fix support for passing just a table row, cell
1 parent 6aabc56 commit 1c2cb7b

File tree

6 files changed

+196
-64
lines changed

6 files changed

+196
-64
lines changed

lib/handlers/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {paragraph} from './paragraph.js'
1818
import {root} from './root.js'
1919
import {strong} from './strong.js'
2020
import {table} from './table.js'
21+
import {tableRow} from './table-row.js'
22+
import {tableCell} from './table-cell.js'
2123
import {text} from './text.js'
2224
import {thematicBreak} from './thematic-break.js'
2325

@@ -42,6 +44,8 @@ export const handlers = {
4244
root,
4345
strong,
4446
table,
47+
tableCell,
48+
tableRow,
4549
text,
4650
thematicBreak,
4751
toml: ignore,

lib/handlers/list-item.js

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* @typedef {import('hast').ElementContent} ElementContent
44
* @typedef {import('hast').Properties} Properties
55
* @typedef {import('mdast').Content} Content
6-
* @typedef {import('mdast').List} List
76
* @typedef {import('mdast').ListItem} ListItem
87
* @typedef {import('mdast').Parent} Parent
98
* @typedef {import('mdast').Root} Root

lib/handlers/table-cell.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @typedef {import('hast').Element} Element
3+
* @typedef {import('mdast').TableCell} TableCell
4+
* @typedef {import('../index.js').H} H
5+
*/
6+
7+
import {all} from '../traverse.js'
8+
9+
/**
10+
* Turn an mdast `tableCell` node into hast.
11+
*
12+
* @param {H} h
13+
* Info passed around.
14+
* @param {TableCell} node
15+
* mdast node.
16+
* @returns {Element}
17+
* hast node.
18+
*/
19+
export function tableCell(h, node) {
20+
// Note: this function is normally not called: see `table-row` for how rows
21+
// and their cells are compiled.
22+
/** @type {Element} */
23+
const result = {
24+
type: 'element',
25+
tagName: 'td', // Assume body cell.
26+
properties: {},
27+
children: all(h, node)
28+
}
29+
h.patch(node, result)
30+
return h.applyData(node, result)
31+
}

lib/handlers/table-row.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @typedef {import('hast').Properties} Properties
3+
* @typedef {import('hast').Element} Element
4+
* @typedef {import('hast').ElementContent} ElementContent
5+
* @typedef {import('mdast').Content} Content
6+
* @typedef {import('mdast').Parent} Parent
7+
* @typedef {import('mdast').Root} Root
8+
* @typedef {import('mdast').TableRow} TableRow
9+
* @typedef {import('../index.js').H} H
10+
*/
11+
12+
/**
13+
* @typedef {Root | Content} Nodes
14+
* @typedef {Extract<Nodes, Parent>} Parents
15+
*/
16+
17+
import {wrap} from '../wrap.js'
18+
import {all} from '../traverse.js'
19+
20+
/**
21+
* Turn an mdast `tableRow` node into hast.
22+
*
23+
* @param {H} h
24+
* Info passed around.
25+
* @param {TableRow} node
26+
* mdast node.
27+
* @param {Parents | null | undefined} parent
28+
* Parent of `node`.
29+
* @returns {Element}
30+
* hast node.
31+
*/
32+
export function tableRow(h, node, parent) {
33+
const siblings = parent ? parent.children : undefined
34+
// Generate a body row when without parent.
35+
const rowIndex = siblings ? siblings.indexOf(node) : 1
36+
const tagName = rowIndex === 0 ? 'th' : 'td'
37+
const align = parent && parent.type === 'table' ? parent.align : undefined
38+
const length = align ? align.length : node.children.length
39+
let cellIndex = -1
40+
/** @type {Array<ElementContent>} */
41+
const cells = []
42+
43+
while (++cellIndex < length) {
44+
// Note: can also be undefined.
45+
const cell = node.children[cellIndex]
46+
/** @type {Properties} */
47+
const properties = {}
48+
const alignValue = align ? align[cellIndex] : undefined
49+
50+
if (alignValue) {
51+
properties.align = alignValue
52+
}
53+
54+
/** @type {Element} */
55+
let result = {type: 'element', tagName, properties, children: []}
56+
57+
if (cell) {
58+
result.children = all(h, cell)
59+
h.patch(cell, result)
60+
result = h.applyData(node, result)
61+
}
62+
63+
cells.push(result)
64+
}
65+
66+
/** @type {Element} */
67+
const result = {
68+
type: 'element',
69+
tagName: 'tr',
70+
properties: {},
71+
children: wrap(cells, true)
72+
}
73+
h.patch(node, result)
74+
return h.applyData(node, result)
75+
}

lib/handlers/table.js

+12-57
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/**
22
* @typedef {import('hast').Element} Element
3-
* @typedef {import('hast').ElementContent} ElementContent
43
* @typedef {import('mdast').Table} Table
5-
* @typedef {import('mdast').TableCell} TableCell
64
* @typedef {import('../index.js').H} H
75
*/
86

@@ -21,78 +19,35 @@ import {all} from '../traverse.js'
2119
* hast node.
2220
*/
2321
export function table(h, node) {
24-
let index = -1
25-
const align = node.align || []
22+
const rows = all(h, node)
23+
const firstRow = rows.shift()
2624
/** @type {Array<Element>} */
27-
const rows = []
28-
29-
while (++index < node.children.length) {
30-
const row = node.children[index]
31-
const tagName = index === 0 ? 'th' : 'td'
32-
const length = node.align ? align.length : row.children.length
33-
let cellIndex = -1
34-
/** @type {Array<ElementContent>} */
35-
const cells = []
36-
37-
while (++cellIndex < length) {
38-
// Note: can also be undefined.
39-
const cell = row.children[cellIndex]
40-
41-
/** @type {Element} */
42-
let result = {
43-
type: 'element',
44-
tagName,
45-
properties: {align: align[cellIndex]},
46-
children: []
47-
}
48-
49-
if (cell) {
50-
result.children = all(h, cell)
51-
h.patch(cell, result)
52-
result = h.applyData(node, result)
53-
}
54-
55-
cells.push(result)
56-
}
25+
const tableContent = []
5726

27+
if (firstRow) {
5828
/** @type {Element} */
59-
const result = {
29+
const head = {
6030
type: 'element',
61-
tagName: 'tr',
31+
tagName: 'thead',
6232
properties: {},
63-
children: wrap(cells, true)
33+
children: wrap([firstRow], true)
6434
}
65-
h.patch(row, result)
66-
rows.push(h.applyData(row, result))
67-
}
68-
69-
// Always one row:
70-
/** @type {Element} */
71-
const head = {
72-
type: 'element',
73-
tagName: 'thead',
74-
properties: {},
75-
children: wrap([rows[0]], true)
35+
h.patch(node.children[0], head)
36+
tableContent.push(head)
7637
}
77-
h.patch(node.children[0], head)
7838

79-
const tableContent = [head]
80-
81-
if (rows.length > 1) {
39+
if (rows.length > 0) {
8240
/** @type {Element} */
8341
const body = {
8442
type: 'element',
8543
tagName: 'tbody',
8644
properties: {},
87-
children: wrap(rows.slice(1), true)
45+
children: wrap(rows, true)
8846
}
8947

9048
const start = pointStart(node.children[1])
9149
const end = pointEnd(node.children[node.children.length - 1])
92-
if (start.line && end.line) {
93-
body.position = {start, end}
94-
}
95-
50+
if (start.line && end.line) body.position = {start, end}
9651
tableContent.push(body)
9752
}
9853

test/table.js

+74-6
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,9 @@ test('Table', (t) => {
7878
u('text', '\n'),
7979
u('element', {tagName: 'tr', properties: {}}, [
8080
u('text', '\n'),
81-
u('element', {tagName: 'th', properties: {align: undefined}}, [
82-
u('text', 'a')
83-
]),
81+
u('element', {tagName: 'th', properties: {}}, [u('text', 'a')]),
8482
u('text', '\n'),
85-
u('element', {tagName: 'th', properties: {align: undefined}}, [
86-
u('text', 'b')
87-
]),
83+
u('element', {tagName: 'th', properties: {}}, [u('text', 'b')]),
8884
u('text', '\n')
8985
]),
9086
u('text', '\n')
@@ -94,5 +90,77 @@ test('Table', (t) => {
9490
'should not add a `tbody` if w/o second row'
9591
)
9692

93+
t.deepEqual(
94+
toHast({type: 'table', children: []}),
95+
{
96+
type: 'element',
97+
tagName: 'table',
98+
properties: {},
99+
children: [{type: 'text', value: '\n'}]
100+
},
101+
'should handle a table node w/o rows'
102+
)
103+
104+
t.deepEqual(
105+
toHast({
106+
type: 'tableRow',
107+
children: [
108+
{type: 'tableCell', children: [{type: 'text', value: 'a'}]},
109+
{type: 'tableCell', children: [{type: 'text', value: 'b'}]}
110+
]
111+
}),
112+
{
113+
type: 'element',
114+
tagName: 'tr',
115+
properties: {},
116+
children: [
117+
{type: 'text', value: '\n'},
118+
{
119+
type: 'element',
120+
tagName: 'td',
121+
properties: {},
122+
children: [{type: 'text', value: 'a'}]
123+
},
124+
{type: 'text', value: '\n'},
125+
{
126+
type: 'element',
127+
tagName: 'td',
128+
properties: {},
129+
children: [{type: 'text', value: 'b'}]
130+
},
131+
{type: 'text', value: '\n'}
132+
]
133+
},
134+
'should handle a table row node w/ cells'
135+
)
136+
137+
t.deepEqual(
138+
toHast({type: 'tableRow', children: []}),
139+
{
140+
type: 'element',
141+
tagName: 'tr',
142+
properties: {},
143+
children: [{type: 'text', value: '\n'}]
144+
},
145+
'should handle a table row node w/o cells'
146+
)
147+
148+
t.deepEqual(
149+
toHast({type: 'tableCell', children: [{type: 'text', value: 'a'}]}),
150+
{
151+
type: 'element',
152+
tagName: 'td',
153+
properties: {},
154+
children: [{type: 'text', value: 'a'}]
155+
},
156+
'should handle a table cell node w/ children'
157+
)
158+
159+
t.deepEqual(
160+
toHast({type: 'tableCell', children: []}),
161+
{type: 'element', tagName: 'td', properties: {}, children: []},
162+
'should handle a table cell node w/o children'
163+
)
164+
97165
t.end()
98166
})

0 commit comments

Comments
 (0)