Skip to content

Commit 1cd9f7e

Browse files
committed
add better support for tables
1 parent 9b8884e commit 1cd9f7e

File tree

38 files changed

+16535
-6113
lines changed

38 files changed

+16535
-6113
lines changed

libs/jast/jast-util-to-texast/src/lib/handlers/table.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ const visit = origVisit as any
1212
export function table(j: J, table: Table) {
1313
let columns: string[] = []
1414
let hasCols = false
15+
16+
let numberOfRows = 0
17+
1518
// tables can be def'd in terms of cols or rows
1619
// TODO: [jast-util-to-texast] Store information about column alignment in tabular
1720
visit(
@@ -20,15 +23,28 @@ export function table(j: J, table: Table) {
2023
(node: Col | Tr) => {
2124
if (node.name === 'col') {
2225
hasCols = true
23-
columns.push('c')
26+
columns.push('l')
27+
28+
// TODO: [jast-util-to-texast] Check whether col how multirow elements
29+
numberOfRows = node.children.length
30+
2431
return
2532
}
2633

2734
if (hasCols) return
35+
36+
numberOfRows += 1
37+
2838
let tempCols: string[] = []
2939

3040
node?.children?.forEach((child) => {
31-
isElement(child) && child.name === 'td' && tempCols.push('c')
41+
if (!isElement(child)) return
42+
43+
if (child.name !== 'td') return
44+
45+
for (let i = 0; i < (child?.attributes?.colspan ?? 1); i++) {
46+
tempCols.push('l')
47+
}
3248
})
3349
// Just make the table as wide as it needs to be, overfull tables
3450
// error out while underfull ones are fine
@@ -39,12 +55,16 @@ export function table(j: J, table: Table) {
3955
)
4056

4157
const colAlignment = columns.join(` ${j.columnSeparator ? '|' : ''} `)
58+
4259
const colAlignArg: CommandArg = {
4360
type: 'commandArg',
4461
children: [{ type: 'text', value: colAlignment }],
4562
}
4663

64+
j.numberOfRows = numberOfRows
4765
const contents = all(j, table)
66+
j.rowNumber = 0
67+
j.numberOfRows = 0
4868
contents.unshift(colAlignArg)
4969

5070
return { type: 'environment', name: 'tabular', children: contents }
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// based on https://github.com/syntax-tree/hast-util-to-mdast/blob/main/lib/handlers/em
22

33
import { Td } from 'jast-types'
4+
import { TableCell } from 'texast'
45
import { all } from '../all'
56
import { J, Node } from '../types'
67

78
export function td(j: J, node: Td) {
8-
return j(node, 'tableCell', all(j, node))
9+
const { colspan, style, valign } = node.attributes
10+
return j(node, 'tableCell', { span: colspan }, all(j, node)) as TableCell
911
}

libs/jast/jast-util-to-texast/src/lib/handlers/tr.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// based on https://github.com/syntax-tree/hast-util-to-mdast/blob/main/lib/handlers/em
22

33
import { Tr } from 'jast-types'
4-
import { AlignmentTab, Linebreak } from 'texast'
4+
import { AlignmentTab, Command, Linebreak, Text } from 'texast'
55
import { all } from '../all'
66
import { J, Node } from '../types'
77

88
export function tr(j: J, node: Tr) {
9+
j.rowNumber += 1
910
const contentsNoTabs = all(j, node)
1011
// too many alignment tabs
1112
const contents = contentsNoTabs
@@ -17,5 +18,47 @@ export function tr(j: J, node: Tr) {
1718
.slice(1)
1819

1920
contents.push({ type: 'linebreak', value: '\\' } as Linebreak)
21+
if (
22+
node.children.every(
23+
(child) =>
24+
child.type === 'element' &&
25+
child.name === 'td' &&
26+
child.attributes.style?.includes('border-bottom')
27+
)
28+
) {
29+
const commandName = j.booktabs
30+
? j.rowNumber === j.numberOfRows
31+
? 'bottomrule'
32+
: 'midrule'
33+
: 'hline'
34+
contents.push(
35+
...[
36+
{ type: 'text', value: ' ' } as Text,
37+
{
38+
type: 'command',
39+
name: commandName,
40+
children: [],
41+
} as Command,
42+
]
43+
)
44+
}
45+
46+
if (
47+
j.rowNumber === 1 &&
48+
node.children.every(
49+
(child) =>
50+
child.type === 'element' &&
51+
child.name === 'td' &&
52+
child.attributes.style?.includes('border-top')
53+
)
54+
) {
55+
const commandName = j.booktabs ? 'toprule' : 'hline'
56+
contents.unshift({
57+
type: 'command',
58+
name: commandName,
59+
children: [],
60+
} as Command)
61+
}
62+
2063
return j(node, 'tableRow', contents)
2164
}

libs/jast/jast-util-to-texast/src/lib/jast-util-to-texast.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ export function toTexast(
9191
bibname: options.bibname || 'bibliography',
9292
columnSeparator: !!options.columnSeparator,
9393
footnotes: [],
94+
booktabs: options.booktabs ?? true,
95+
rowNumber: 0,
96+
numberOfRows: 0,
9497
citationAnalyzer:
9598
options.citationAnalyzer || ((node: Node) => 'autocite'),
9699
} as Context

libs/jast/jast-util-to-texast/src/lib/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface Options {
3737
italics?: 'emph' | 'textit'
3838
bibname?: string
3939
columnSeparator?: boolean
40+
booktabs?: boolean
4041
documentClass?: {
4142
options?: string[]
4243
name: string
@@ -63,6 +64,7 @@ export interface Context {
6364
document: boolean | undefined
6465
checked: string
6566
unchecked: string
67+
booktabs: boolean
6668
quotes: Array<string>
6769
italics: string
6870
documentClass: {
@@ -73,6 +75,8 @@ export interface Context {
7375
bibname: string
7476
columnSeparator: boolean
7577
footnotes: TexastContent[]
78+
rowNumber: number
79+
numberOfRows: number
7680
citationAnalyzer: (node: Node) => string
7781
}
7882

libs/ooxast/ooxast-util-citations/src/lib/ooxast-util-citations.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { visit } from 'unist-util-visit'
1+
import { visitParents } from 'unist-util-visit-parents'
22
import { P, R, T, Text, Root } from 'ooxast'
33
import { getPStyle } from 'ooxast-util-get-style'
44
import { parseTextCite } from 'parse-text-cite'
55
import { Node } from 'unist'
6-
import { convertElement } from 'xast-util-is-element'
6+
import { convertElement, isElement } from 'xast-util-is-element'
77
import { select } from 'xast-util-select'
88
import { toString } from 'xast-util-to-string'
99
import { select as unistSelect } from 'unist-util-select'
@@ -37,8 +37,16 @@ export function findCitations(
3737

3838
let references = false
3939
let citationCounter = 1
40-
visit(tree, isP, (p: P) => {
41-
if (references) return
40+
visitParents(tree, isP, (p: P, ancestors: Node[]) => {
41+
if (
42+
ancestors.some((parent) => isElement(parent) && /tbl/.test(parent.name))
43+
) {
44+
return
45+
}
46+
47+
if (references) {
48+
return
49+
}
4250

4351
if (getPStyle(p)?.toLowerCase()?.includes('heading')) {
4452
if (

libs/ooxast/ooxast-util-to-jast/src/lib/handlers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { document } from './document'
1212
import { r } from './r'
1313
import { tr } from './tr'
1414
import { drawing } from './drawing'
15+
import { tc } from './tc'
1516

1617
export const handlers = {
1718
p,
@@ -26,6 +27,7 @@ export const handlers = {
2627
instrText: citation,
2728
tbl,
2829
tr,
30+
tc,
2931
article: ignore,
3032
xml: ignore,
3133
instruction: ignore,

libs/ooxast/ooxast-util-to-jast/src/lib/handlers/tc.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,56 @@ import { Tc } from 'ooxast'
44
import { Td } from 'jast-types'
55
import { getPr } from 'ooxast-util-properties'
66

7+
const createStyle = (
8+
name: string,
9+
style: Record<string, boolean | string | Record<string, string>>
10+
) =>
11+
Object.entries(style)
12+
?.map(
13+
([key, val]) =>
14+
`${name}${key?.at(0)?.toUpperCase()}${key?.slice(1)}: ${
15+
val?.val ? val.val : `${val}`
16+
}`
17+
)
18+
.join('; ')
19+
720
export function tc(j: J, node: Tc): Td {
821
const properties = getPr(node)
9-
return j(node, 'td', all(j, node))
22+
23+
const { tcBorders, gridSpan, vAlign, shd } = properties
24+
25+
const shdStyle =
26+
shd && typeof shd === 'object'
27+
? `background-color: ${shd.fill}; color: ${shd.color}`
28+
: ''
29+
30+
const borderStyle =
31+
tcBorders && typeof tcBorders === 'object'
32+
? Object.entries(tcBorders)
33+
?.map(
34+
([border, values]) =>
35+
`border-${border}: ${values.sz}px ${
36+
values.val?.includes('dash') ? 'dashed' : 'solid'
37+
} #${values.color}`
38+
)
39+
?.join('; ')
40+
: ''
41+
42+
// const borderStyle =
43+
// tcBorders && typeof tcBorders === 'object'
44+
// ? createStyle('border', tcBorders)
45+
// : ''
46+
47+
const style = [shdStyle, borderStyle].join('; ')
48+
49+
const jatsProps = {
50+
...(gridSpan && gridSpan.val && +gridSpan.val > 1
51+
? { colspan: gridSpan.val }
52+
: {}),
53+
...(shdStyle ?? borderStyle ? { style } : {}),
54+
55+
...(vAlign && vAlign?.val !== 'top' ? { valign: vAlign.val } : {}),
56+
}
57+
58+
return j(node, 'td', jatsProps, all(j, node)) as Td
1059
}

libs/ooxast/ooxast-util-to-jast/src/lib/handlers/tr.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ import { Td } from 'jast-types'
44
import { all } from '../all'
55

66
export function tr(j: J, tr: Row) {
7-
const rowcontents = all(j, tr)
8-
const celldRowContents: Td[] = []
9-
for (const cell of rowcontents) {
10-
celldRowContents.push({
11-
type: 'element',
12-
name: 'td',
13-
attributes: {},
14-
// @ts-expect-error
15-
children: cell?.children || [cell],
16-
})
17-
}
18-
return j(tr, 'tr', celldRowContents)
7+
const rowContents = all(j, tr)
8+
// const celldRowContents: Td[] = []
9+
// for (const cell of rowcontents) {
10+
// celldRowContents.push({
11+
// type: 'element',
12+
// name: 'td',
13+
// attributes: {},
14+
// // @ts-expect-error
15+
// children: cell?.children || [cell],
16+
// })
17+
// }
18+
return j(tr, 'tr', rowContents)
1919
}

libs/ooxast/ooxast/src/lib/ooxml/wordprocessingml/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3979,7 +3979,7 @@ export type TcPr = TcPrInner & {
39793979
children: RequiredMap<TcPrMap>[]
39803980
}
39813981

3982-
export interface TcPrMap {
3982+
export interface TcPrMap extends TcPrBase {
39833983
tcPrChange?: TcPrChange
39843984
}
39853985

0 commit comments

Comments
 (0)