@lkaopremier/html-to-docx 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|