@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/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