@lkaopremier/html-to-docx 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -0
- package/bin/cli.js +461 -0
- package/package.json +26 -0
- package/src/helper.js +544 -0
- package/src/index.d.ts +39 -0
- package/src/index.js +172 -0
- package/src/tree.js +643 -0
package/src/index.js
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
import {
|
2
|
+
Document,
|
3
|
+
Packer,
|
4
|
+
Paragraph,
|
5
|
+
TextRun,
|
6
|
+
ImageRun,
|
7
|
+
Table,
|
8
|
+
TableRow,
|
9
|
+
TableCell,
|
10
|
+
BorderStyle,
|
11
|
+
LevelFormat,
|
12
|
+
AlignmentType,
|
13
|
+
} from 'docx'
|
14
|
+
import { nodeTree } from './tree.js'
|
15
|
+
import lodash from 'lodash'
|
16
|
+
import { getListItemNumber } from './helper.js'
|
17
|
+
import { decode } from 'html-entities'
|
18
|
+
|
19
|
+
async function transform(lines, option) {
|
20
|
+
if (!option) option = {}
|
21
|
+
|
22
|
+
return await Promise.all(
|
23
|
+
lines
|
24
|
+
.map(async line => {
|
25
|
+
if (line.type === 'list') {
|
26
|
+
if (!option.numbering) option.numbering = []
|
27
|
+
|
28
|
+
const { bullet, ...style } = line.style ?? {}
|
29
|
+
|
30
|
+
const reference = 'list-custom-numbering' + option.numbering.length
|
31
|
+
|
32
|
+
option.numbering.push({
|
33
|
+
reference,
|
34
|
+
levels: [
|
35
|
+
{
|
36
|
+
level: line.style.bullet.level,
|
37
|
+
format: LevelFormat.BULLET,
|
38
|
+
text: `${getListItemNumber(
|
39
|
+
line.style.bullet.format,
|
40
|
+
line.style.bullet.start,
|
41
|
+
)}.`,
|
42
|
+
alignment: AlignmentType.END,
|
43
|
+
style: {
|
44
|
+
run: { ...style, underline: undefined },
|
45
|
+
},
|
46
|
+
},
|
47
|
+
],
|
48
|
+
})
|
49
|
+
|
50
|
+
return new Paragraph({
|
51
|
+
...style,
|
52
|
+
children: [
|
53
|
+
new TextRun({
|
54
|
+
text: decode(line.run[0].content),
|
55
|
+
...style,
|
56
|
+
}),
|
57
|
+
],
|
58
|
+
bullet,
|
59
|
+
numbering: {
|
60
|
+
reference,
|
61
|
+
level: bullet.level,
|
62
|
+
},
|
63
|
+
})
|
64
|
+
} else if (line.type === 'table') {
|
65
|
+
return new Table({
|
66
|
+
...(line.style ?? {}),
|
67
|
+
borders: {
|
68
|
+
bottom: { style: BorderStyle.NONE },
|
69
|
+
left: { style: BorderStyle.NONE },
|
70
|
+
right: { style: BorderStyle.NONE },
|
71
|
+
top: { style: BorderStyle.NONE },
|
72
|
+
insideHorizontal: { style: BorderStyle.NONE },
|
73
|
+
insideVertical: { style: BorderStyle.NONE },
|
74
|
+
},
|
75
|
+
rows: await Promise.all(
|
76
|
+
line.run.map(async row => {
|
77
|
+
const children = await Promise.all(
|
78
|
+
row.run.map(async cell => {
|
79
|
+
return new TableCell({
|
80
|
+
...(cell.style ?? {}),
|
81
|
+
children: await transform(cell.run),
|
82
|
+
})
|
83
|
+
}),
|
84
|
+
)
|
85
|
+
|
86
|
+
return new TableRow({
|
87
|
+
...(row.style ?? {}),
|
88
|
+
children,
|
89
|
+
})
|
90
|
+
}),
|
91
|
+
),
|
92
|
+
})
|
93
|
+
} else {
|
94
|
+
return new Paragraph({
|
95
|
+
...lodash.merge(
|
96
|
+
{
|
97
|
+
spacing: {
|
98
|
+
after: 200,
|
99
|
+
},
|
100
|
+
},
|
101
|
+
line.style ?? {},
|
102
|
+
),
|
103
|
+
children: (line.run ?? []).filter(Boolean).map(item => {
|
104
|
+
switch (item.type) {
|
105
|
+
case 'text':
|
106
|
+
return new TextRun({
|
107
|
+
...(item.style ?? {}),
|
108
|
+
text: decode(item.content),
|
109
|
+
})
|
110
|
+
|
111
|
+
case 'image':
|
112
|
+
return new ImageRun({
|
113
|
+
...(item.style ?? {}),
|
114
|
+
data: item.data,
|
115
|
+
})
|
116
|
+
default:
|
117
|
+
return undefined
|
118
|
+
}
|
119
|
+
}),
|
120
|
+
})
|
121
|
+
}
|
122
|
+
})
|
123
|
+
.filter(Boolean),
|
124
|
+
)
|
125
|
+
}
|
126
|
+
|
127
|
+
async function htmlToDocx(html, options) {
|
128
|
+
const { top, bottom, left, right } = (options ?? {}).margins ?? {}
|
129
|
+
|
130
|
+
return new Promise(async (resolve, reject) => {
|
131
|
+
try {
|
132
|
+
const tree = await nodeTree(html)
|
133
|
+
|
134
|
+
const option = { numbering: [] }
|
135
|
+
|
136
|
+
const sections = await Promise.all(
|
137
|
+
Object.values(tree).map(async sheet => {
|
138
|
+
return {
|
139
|
+
properties: {
|
140
|
+
page: {
|
141
|
+
margin: {
|
142
|
+
top: top,
|
143
|
+
bottom: bottom,
|
144
|
+
left: left,
|
145
|
+
right: right,
|
146
|
+
},
|
147
|
+
}
|
148
|
+
},
|
149
|
+
children: await transform(sheet, option),
|
150
|
+
}
|
151
|
+
}),
|
152
|
+
)
|
153
|
+
|
154
|
+
const config = {
|
155
|
+
numbering: {
|
156
|
+
config: option.numbering ?? [],
|
157
|
+
},
|
158
|
+
}
|
159
|
+
|
160
|
+
const doc = new Document({
|
161
|
+
...config,
|
162
|
+
sections,
|
163
|
+
})
|
164
|
+
|
165
|
+
Packer.toBuffer(doc).then(buffer => resolve(buffer))
|
166
|
+
} catch (error) {
|
167
|
+
reject(error)
|
168
|
+
}
|
169
|
+
})
|
170
|
+
}
|
171
|
+
|
172
|
+
export default htmlToDocx
|