feat(parser): support table and TOC
This commit is contained in:
parent
e90cc2b639
commit
6c6cfc3baf
|
@ -1,7 +1,7 @@
|
||||||
import type Token from 'markdown-it/lib/token'
|
import type Token from 'markdown-it/lib/token'
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
import type { ISectionOptions, IStylesOptions, Table, TableOfContents } from 'docx'
|
import type { ISectionOptions, IStylesOptions, Table } from 'docx'
|
||||||
import { AlignmentType, BorderStyle, Document, Footer, Header, LevelFormat, Packer, PageNumber, Paragraph, SectionType, TextRun, convertInchesToTwip } from 'docx'
|
import { AlignmentType, BorderStyle, Document, Footer, Header, LevelFormat, Packer, PageNumber, Paragraph, SectionType, StyleLevel, TableOfContents, TextRun, convertInchesToTwip } from 'docx'
|
||||||
import type { IMarkdownReportConfig } from '@md-report/types'
|
import type { IMarkdownReportConfig } from '@md-report/types'
|
||||||
import { StyleId } from '@md-report/types'
|
import { StyleId } from '@md-report/types'
|
||||||
import { sliceParagraph, sliceSection } from './utils'
|
import { sliceParagraph, sliceSection } from './utils'
|
||||||
|
@ -27,7 +27,80 @@ export function parse(props: { markdown: string; config: IMarkdownReportConfig }
|
||||||
export function parseDocument(tokens: Token[], styles: IStylesOptions): Document {
|
export function parseDocument(tokens: Token[], styles: IStylesOptions): Document {
|
||||||
// Variables.
|
// Variables.
|
||||||
let pos = 0
|
let pos = 0
|
||||||
const sections: ISectionOptions[] = []
|
const sections: ISectionOptions[] = [{
|
||||||
|
properties: {
|
||||||
|
type: SectionType.NEXT_PAGE,
|
||||||
|
page: {
|
||||||
|
margin: {
|
||||||
|
top: convertInchesToTwip(1),
|
||||||
|
bottom: convertInchesToTwip(1),
|
||||||
|
left: convertInchesToTwip(1.25),
|
||||||
|
right: convertInchesToTwip(1.25),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
default: new Header({
|
||||||
|
children: [new Paragraph({
|
||||||
|
style: StyleId.header,
|
||||||
|
border: {
|
||||||
|
bottom: {
|
||||||
|
color: 'auto',
|
||||||
|
style: BorderStyle.SINGLE,
|
||||||
|
size: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
text: '111',
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
even: new Header({
|
||||||
|
children: [new Paragraph({
|
||||||
|
style: StyleId.header,
|
||||||
|
border: {
|
||||||
|
bottom: {
|
||||||
|
color: 'auto',
|
||||||
|
style: BorderStyle.SINGLE,
|
||||||
|
size: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
text: '222',
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: new Footer({
|
||||||
|
children: [new Paragraph({
|
||||||
|
style: StyleId.footer,
|
||||||
|
children: [new TextRun({
|
||||||
|
children: [PageNumber.CURRENT],
|
||||||
|
})],
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
even: new Footer({
|
||||||
|
children: [new Paragraph({
|
||||||
|
style: StyleId.footer,
|
||||||
|
children: [new TextRun({
|
||||||
|
children: [PageNumber.CURRENT],
|
||||||
|
})],
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
new TableOfContents('TOC', {
|
||||||
|
stylesWithLevels: [
|
||||||
|
new StyleLevel(StyleId.h1, 1),
|
||||||
|
new StyleLevel(StyleId.h2, 2),
|
||||||
|
new StyleLevel(StyleId.h3, 3),
|
||||||
|
new StyleLevel(StyleId.h4, 4),
|
||||||
|
new StyleLevel(StyleId.h5, 5),
|
||||||
|
new StyleLevel(StyleId.h6, 6),
|
||||||
|
],
|
||||||
|
useAppliedParagraphOutlineLevel: true,
|
||||||
|
hyperlink: true,
|
||||||
|
headingStyleRange: '1-3',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}]
|
||||||
// Split and parse sections.
|
// Split and parse sections.
|
||||||
while (pos < tokens.length) {
|
while (pos < tokens.length) {
|
||||||
const { tokens: section, offset } = sliceSection(tokens.slice(pos))
|
const { tokens: section, offset } = sliceSection(tokens.slice(pos))
|
||||||
|
@ -148,6 +221,9 @@ export function parseDocument(tokens: Token[], styles: IStylesOptions): Document
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
features: {
|
||||||
|
updateFields: true,
|
||||||
|
},
|
||||||
evenAndOddHeaderAndFooters: true,
|
evenAndOddHeaderAndFooters: true,
|
||||||
styles,
|
styles,
|
||||||
sections,
|
sections,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { sliceInlineText } from './utils'
|
||||||
|
|
||||||
export function parseInline(props: { tokens: Token[]; style?: StyleId; headingLevel?: number; isUL?: boolean; isOL?: boolean }): Paragraph {
|
export function parseInline(props: { tokens: Token[]; style?: StyleId; headingLevel?: number; isUL?: boolean; isOL?: boolean }): Paragraph {
|
||||||
// Props.
|
// Props.
|
||||||
const { tokens, style = StyleId.normal, headingLevel = 0, isOL = false, isUL = false } = props
|
const { tokens, style = StyleId.p, headingLevel = 0, isOL = false, isUL = false } = props
|
||||||
const { children: childrenTokens, level } = tokens[0]
|
const { children: childrenTokens, level } = tokens[0]
|
||||||
if (!childrenTokens)
|
if (!childrenTokens)
|
||||||
return new Paragraph({})
|
return new Paragraph({})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type Token from 'markdown-it/lib/token'
|
import type Token from 'markdown-it/lib/token'
|
||||||
import type { IBorderOptions } from 'docx'
|
import type { IBorderOptions } from 'docx'
|
||||||
import { BorderStyle, Math, MathRun, Paragraph, Table, TableCell, TableRow, TextRun } from 'docx'
|
import { BorderStyle, Math, MathRun, Paragraph, Table, TableCell, TableRow, TextRun, WidthType } from 'docx'
|
||||||
import { StyleId } from '@md-report/types'
|
import { StyleId } from '@md-report/types'
|
||||||
import { MathBlockRegExp, sliceTableRow } from './utils'
|
import { MathBlockRegExp, sliceTableRow } from './utils'
|
||||||
import { parseInline } from './inline'
|
import { parseInline } from './inline'
|
||||||
|
@ -44,6 +44,10 @@ export function parseTable(tokens: Token[]): Table {
|
||||||
export function parseTableRow(tokens: Token[]): TableRow {
|
export function parseTableRow(tokens: Token[]): TableRow {
|
||||||
const cells: Token[] = tokens.filter(token => token.type === 'inline')
|
const cells: Token[] = tokens.filter(token => token.type === 'inline')
|
||||||
const children: TableCell[] = cells.map(cell => new TableCell({
|
const children: TableCell[] = cells.map(cell => new TableCell({
|
||||||
|
width: {
|
||||||
|
size: 1 / cells.length,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
children: [parseInline({
|
children: [parseInline({
|
||||||
tokens: [cell],
|
tokens: [cell],
|
||||||
style: StyleId.table,
|
style: StyleId.table,
|
||||||
|
|
|
@ -36,9 +36,12 @@ export function sliceParagraph(tokens: Token[]): SliceResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sliceTableRow(tokens: Token[]): SliceResult {
|
export function sliceTableRow(tokens: Token[]): SliceResult {
|
||||||
let offset = 0
|
let offset = 1
|
||||||
while (tokens[offset]?.type !== 'tr_open')
|
while (offset < tokens.length) {
|
||||||
|
if (tokens[offset].type === 'tr_open')
|
||||||
|
break
|
||||||
offset++
|
offset++
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
tokens: tokens.slice(0, offset),
|
tokens: tokens.slice(0, offset),
|
||||||
offset,
|
offset,
|
||||||
|
|
Loading…
Reference in New Issue