@yinyoudexing/xml2word 0.1.1 → 0.1.2

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/dist/index.cjs CHANGED
@@ -48,6 +48,8 @@ function wrapBodyXml(bodyXml) {
48
48
  <w:body>
49
49
  ${bodyXml}
50
50
  <w:sectPr>
51
+ <w:headerReference w:type="default" r:id="rId6"/>
52
+ <w:footerReference w:type="default" r:id="rId7"/>
51
53
  <w:pgSz w:w="12240" w:h="15840"/>
52
54
  <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
53
55
  <w:cols w:space="708"/>
@@ -136,17 +138,36 @@ function buildContentTypesXml(assets) {
136
138
  defaults.set(ext, asset.contentType);
137
139
  }
138
140
  const defaultLines = [...defaults.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([ext, ct]) => ` <Default Extension="${ext}" ContentType="${ct}"/>`).join("\n");
141
+ const overrides = [
142
+ ' <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>',
143
+ ' <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>',
144
+ ' <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/>',
145
+ ' <Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>',
146
+ ' <Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/>',
147
+ ' <Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>',
148
+ ' <Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/>',
149
+ ' <Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/>'
150
+ ].join("\n");
139
151
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
140
152
  <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
141
153
  ${defaultLines}
142
- <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
154
+ ${overrides}
143
155
  </Types>
144
156
  `;
145
157
  }
146
158
  function buildDocumentRelsXml(assets) {
147
- const relLines = assets.map(
148
- (a) => ` <Relationship Id="${a.relationshipId}" Type="${a.relationshipType}" Target="${a.target}"/>`
149
- ).join("\n");
159
+ const relLines = [
160
+ ' <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>',
161
+ ' <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>',
162
+ ' <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>',
163
+ ' <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>',
164
+ ' <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>',
165
+ ' <Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/>',
166
+ ' <Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/>',
167
+ ...assets.map(
168
+ (a) => ` <Relationship Id="${a.relationshipId}" Type="${a.relationshipType}" Target="${a.target}"/>`
169
+ )
170
+ ].join("\n");
150
171
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
151
172
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
152
173
  ${relLines}
@@ -162,6 +183,15 @@ async function createDocxZipUint8Array(xml, options = {}) {
162
183
  relsFolder?.file(".rels", ROOT_RELS_XML);
163
184
  const wordFolder = zip.folder("word");
164
185
  wordFolder?.file("document.xml", documentXml);
186
+ wordFolder?.file("styles.xml", STYLES_XML);
187
+ wordFolder?.file("settings.xml", SETTINGS_XML);
188
+ wordFolder?.file("fontTable.xml", FONT_TABLE_XML);
189
+ wordFolder?.folder("theme")?.file("theme1.xml", THEME_XML);
190
+ wordFolder?.file("numbering.xml", NUMBERING_XML);
191
+ wordFolder?.file("header1.xml", HEADER1_XML);
192
+ wordFolder?.file("footer1.xml", FOOTER1_XML);
193
+ const wordRelsFolder = wordFolder?.folder("_rels");
194
+ wordRelsFolder?.file("document.xml.rels", buildDocumentRelsXml([]));
165
195
  return zip.generateAsync({ type: "uint8array" });
166
196
  }
167
197
  async function createDocxZipWithAssetsUint8Array(xml, options, assets) {
@@ -173,9 +203,16 @@ async function createDocxZipWithAssetsUint8Array(xml, options, assets) {
173
203
  relsFolder?.file(".rels", ROOT_RELS_XML);
174
204
  const wordFolder = zip.folder("word");
175
205
  wordFolder?.file("document.xml", documentXml);
206
+ wordFolder?.file("styles.xml", STYLES_XML);
207
+ wordFolder?.file("settings.xml", SETTINGS_XML);
208
+ wordFolder?.file("fontTable.xml", FONT_TABLE_XML);
209
+ wordFolder?.folder("theme")?.file("theme1.xml", THEME_XML);
210
+ wordFolder?.file("numbering.xml", NUMBERING_XML);
211
+ wordFolder?.file("header1.xml", HEADER1_XML);
212
+ wordFolder?.file("footer1.xml", FOOTER1_XML);
213
+ const wordRelsFolder = wordFolder?.folder("_rels");
214
+ wordRelsFolder?.file("document.xml.rels", buildDocumentRelsXml(assets));
176
215
  if (assets.length) {
177
- const wordRelsFolder = wordFolder?.folder("_rels");
178
- wordRelsFolder?.file("document.xml.rels", buildDocumentRelsXml(assets));
179
216
  for (const asset of assets) {
180
217
  const targetPath = asset.target.replace(/^\.\//, "");
181
218
  const normalized = targetPath.startsWith("word/") ? targetPath.slice("word/".length) : targetPath;
@@ -184,13 +221,324 @@ async function createDocxZipWithAssetsUint8Array(xml, options, assets) {
184
221
  }
185
222
  return zip.generateAsync({ type: "uint8array" });
186
223
  }
187
- var import_jszip, ROOT_RELS_XML;
224
+ var import_jszip, STYLES_XML, SETTINGS_XML, NUMBERING_XML, HEADER1_XML, FOOTER1_XML, THEME_XML, FONT_TABLE_XML, ROOT_RELS_XML;
188
225
  var init_createDocxZip = __esm({
189
226
  "src/lib/createDocxZip.ts"() {
190
227
  "use strict";
191
228
  import_jszip = __toESM(require("jszip"), 1);
192
229
  init_normalizeDocumentXml();
193
230
  init_validateXml();
231
+ STYLES_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
232
+ <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
233
+ <w:docDefaults>
234
+ <w:rPrDefault>
235
+ <w:rPr>
236
+ <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/>
237
+ <w:sz w:val="28"/>
238
+ <w:szCs w:val="28"/>
239
+ <w:lang w:val="en-US" w:eastAsia="zh-CN"/>
240
+ </w:rPr>
241
+ </w:rPrDefault>
242
+ <w:pPrDefault>
243
+ <w:pPr>
244
+ <w:spacing w:before="0" w:after="160" w:line="360" w:lineRule="auto"/>
245
+ </w:pPr>
246
+ </w:pPrDefault>
247
+ </w:docDefaults>
248
+
249
+ <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
250
+ <w:name w:val="Normal"/>
251
+ <w:qFormat/>
252
+ <w:pPr>
253
+ <w:spacing w:before="0" w:after="160" w:line="360" w:lineRule="auto"/>
254
+ </w:pPr>
255
+ <w:rPr>
256
+ <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/>
257
+ <w:sz w:val="28"/>
258
+ <w:szCs w:val="28"/>
259
+ </w:rPr>
260
+ </w:style>
261
+
262
+ <w:style w:type="paragraph" w:styleId="Heading1">
263
+ <w:name w:val="heading 1"/>
264
+ <w:basedOn w:val="Normal"/>
265
+ <w:next w:val="Normal"/>
266
+ <w:uiPriority w:val="9"/>
267
+ <w:qFormat/>
268
+ <w:pPr>
269
+ <w:keepNext/>
270
+ <w:keepLines/>
271
+ <w:outlineLvl w:val="0"/>
272
+ <w:spacing w:before="240" w:after="120" w:line="360" w:lineRule="auto"/>
273
+ </w:pPr>
274
+ <w:rPr>
275
+ <w:b/>
276
+ <w:sz w:val="44"/>
277
+ <w:szCs w:val="44"/>
278
+ </w:rPr>
279
+ </w:style>
280
+
281
+ <w:style w:type="paragraph" w:styleId="Heading2">
282
+ <w:name w:val="heading 2"/>
283
+ <w:basedOn w:val="Normal"/>
284
+ <w:next w:val="Normal"/>
285
+ <w:uiPriority w:val="9"/>
286
+ <w:qFormat/>
287
+ <w:pPr>
288
+ <w:keepNext/>
289
+ <w:keepLines/>
290
+ <w:outlineLvl w:val="1"/>
291
+ <w:spacing w:before="200" w:after="100" w:line="360" w:lineRule="auto"/>
292
+ </w:pPr>
293
+ <w:rPr>
294
+ <w:b/>
295
+ <w:sz w:val="32"/>
296
+ <w:szCs w:val="32"/>
297
+ </w:rPr>
298
+ </w:style>
299
+
300
+ <w:style w:type="paragraph" w:styleId="Heading3">
301
+ <w:name w:val="heading 3"/>
302
+ <w:basedOn w:val="Normal"/>
303
+ <w:next w:val="Normal"/>
304
+ <w:uiPriority w:val="9"/>
305
+ <w:qFormat/>
306
+ <w:pPr>
307
+ <w:keepNext/>
308
+ <w:keepLines/>
309
+ <w:outlineLvl w:val="2"/>
310
+ <w:spacing w:before="180" w:after="90" w:line="360" w:lineRule="auto"/>
311
+ </w:pPr>
312
+ <w:rPr>
313
+ <w:b/>
314
+ <w:sz w:val="28"/>
315
+ <w:szCs w:val="28"/>
316
+ </w:rPr>
317
+ </w:style>
318
+
319
+ <w:style w:type="paragraph" w:styleId="Heading4">
320
+ <w:name w:val="heading 4"/>
321
+ <w:basedOn w:val="Normal"/>
322
+ <w:next w:val="Normal"/>
323
+ <w:uiPriority w:val="9"/>
324
+ <w:qFormat/>
325
+ <w:pPr>
326
+ <w:keepNext/>
327
+ <w:keepLines/>
328
+ <w:outlineLvl w:val="3"/>
329
+ <w:spacing w:before="160" w:after="80" w:line="360" w:lineRule="auto"/>
330
+ </w:pPr>
331
+ <w:rPr>
332
+ <w:b/>
333
+ <w:sz w:val="24"/>
334
+ <w:szCs w:val="24"/>
335
+ </w:rPr>
336
+ </w:style>
337
+
338
+ <w:style w:type="paragraph" w:styleId="Heading5">
339
+ <w:name w:val="heading 5"/>
340
+ <w:basedOn w:val="Normal"/>
341
+ <w:next w:val="Normal"/>
342
+ <w:uiPriority w:val="9"/>
343
+ <w:qFormat/>
344
+ <w:pPr>
345
+ <w:keepNext/>
346
+ <w:keepLines/>
347
+ <w:outlineLvl w:val="4"/>
348
+ <w:spacing w:before="140" w:after="70" w:line="360" w:lineRule="auto"/>
349
+ </w:pPr>
350
+ <w:rPr>
351
+ <w:b/>
352
+ <w:sz w:val="22"/>
353
+ <w:szCs w:val="22"/>
354
+ </w:rPr>
355
+ </w:style>
356
+
357
+ <w:style w:type="paragraph" w:styleId="Heading6">
358
+ <w:name w:val="heading 6"/>
359
+ <w:basedOn w:val="Normal"/>
360
+ <w:next w:val="Normal"/>
361
+ <w:uiPriority w:val="9"/>
362
+ <w:qFormat/>
363
+ <w:pPr>
364
+ <w:keepNext/>
365
+ <w:keepLines/>
366
+ <w:outlineLvl w:val="5"/>
367
+ <w:spacing w:before="120" w:after="60" w:line="360" w:lineRule="auto"/>
368
+ </w:pPr>
369
+ <w:rPr>
370
+ <w:b/>
371
+ <w:sz w:val="22"/>
372
+ <w:szCs w:val="22"/>
373
+ </w:rPr>
374
+ </w:style>
375
+ </w:styles>
376
+ `;
377
+ SETTINGS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
378
+ <w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
379
+ <w:themeFontLang w:val="en-US" w:eastAsia="zh-CN"/>
380
+ <w:defaultTabStop w:val="720"/>
381
+ <w:compat/>
382
+ </w:settings>
383
+ `;
384
+ NUMBERING_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
385
+ <w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
386
+ <w:abstractNum w:abstractNumId="1">
387
+ <w:multiLevelType w:val="hybridMultilevel"/>
388
+ <w:lvl w:ilvl="0">
389
+ <w:start w:val="1"/>
390
+ <w:numFmt w:val="bullet"/>
391
+ <w:lvlText w:val="\u2022"/>
392
+ <w:lvlJc w:val="left"/>
393
+ <w:pPr><w:ind w:left="720" w:hanging="360"/></w:pPr>
394
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
395
+ </w:lvl>
396
+ <w:lvl w:ilvl="1">
397
+ <w:start w:val="1"/>
398
+ <w:numFmt w:val="bullet"/>
399
+ <w:lvlText w:val="\u25CB"/>
400
+ <w:lvlJc w:val="left"/>
401
+ <w:pPr><w:ind w:left="1440" w:hanging="360"/></w:pPr>
402
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
403
+ </w:lvl>
404
+ <w:lvl w:ilvl="2">
405
+ <w:start w:val="1"/>
406
+ <w:numFmt w:val="bullet"/>
407
+ <w:lvlText w:val="\u25A0"/>
408
+ <w:lvlJc w:val="left"/>
409
+ <w:pPr><w:ind w:left="2160" w:hanging="360"/></w:pPr>
410
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
411
+ </w:lvl>
412
+ </w:abstractNum>
413
+ <w:abstractNum w:abstractNumId="2">
414
+ <w:multiLevelType w:val="hybridMultilevel"/>
415
+ <w:lvl w:ilvl="0">
416
+ <w:start w:val="1"/>
417
+ <w:numFmt w:val="decimal"/>
418
+ <w:lvlText w:val="%1."/>
419
+ <w:lvlJc w:val="left"/>
420
+ <w:pPr><w:ind w:left="720" w:hanging="360"/></w:pPr>
421
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
422
+ </w:lvl>
423
+ <w:lvl w:ilvl="1">
424
+ <w:start w:val="1"/>
425
+ <w:numFmt w:val="decimal"/>
426
+ <w:lvlText w:val="%1.%2."/>
427
+ <w:lvlJc w:val="left"/>
428
+ <w:pPr><w:ind w:left="1440" w:hanging="360"/></w:pPr>
429
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
430
+ </w:lvl>
431
+ <w:lvl w:ilvl="2">
432
+ <w:start w:val="1"/>
433
+ <w:numFmt w:val="decimal"/>
434
+ <w:lvlText w:val="%1.%2.%3."/>
435
+ <w:lvlJc w:val="left"/>
436
+ <w:pPr><w:ind w:left="2160" w:hanging="360"/></w:pPr>
437
+ <w:rPr><w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="FangSong_GB2312" w:cs="Times New Roman"/></w:rPr>
438
+ </w:lvl>
439
+ </w:abstractNum>
440
+ <w:num w:numId="1"><w:abstractNumId w:val="1"/></w:num>
441
+ <w:num w:numId="2"><w:abstractNumId w:val="2"/></w:num>
442
+ </w:numbering>
443
+ `;
444
+ HEADER1_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
445
+ <w:hdr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
446
+ <w:p>
447
+ <w:pPr><w:jc w:val="center"/></w:pPr>
448
+ <w:r><w:t></w:t></w:r>
449
+ </w:p>
450
+ </w:hdr>
451
+ `;
452
+ FOOTER1_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
453
+ <w:ftr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
454
+ <w:p>
455
+ <w:pPr><w:jc w:val="right"/></w:pPr>
456
+ <w:r><w:t>\u7B2C </w:t></w:r>
457
+ <w:r><w:fldChar w:fldCharType="begin"/></w:r>
458
+ <w:r><w:instrText xml:space="preserve"> PAGE </w:instrText></w:r>
459
+ <w:r><w:fldChar w:fldCharType="separate"/></w:r>
460
+ <w:r><w:t>1</w:t></w:r>
461
+ <w:r><w:fldChar w:fldCharType="end"/></w:r>
462
+ <w:r><w:t> \u9875 / \u5171 </w:t></w:r>
463
+ <w:r><w:fldChar w:fldCharType="begin"/></w:r>
464
+ <w:r><w:instrText xml:space="preserve"> NUMPAGES </w:instrText></w:r>
465
+ <w:r><w:fldChar w:fldCharType="separate"/></w:r>
466
+ <w:r><w:t>1</w:t></w:r>
467
+ <w:r><w:fldChar w:fldCharType="end"/></w:r>
468
+ <w:r><w:t> \u9875</w:t></w:r>
469
+ </w:p>
470
+ </w:ftr>
471
+ `;
472
+ THEME_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
473
+ <a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">
474
+ <a:themeElements>
475
+ <a:clrScheme name="Office">
476
+ <a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>
477
+ <a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>
478
+ <a:dk2><a:srgbClr val="1F497D"/></a:dk2>
479
+ <a:lt2><a:srgbClr val="EEECE1"/></a:lt2>
480
+ <a:accent1><a:srgbClr val="4F81BD"/></a:accent1>
481
+ <a:accent2><a:srgbClr val="C0504D"/></a:accent2>
482
+ <a:accent3><a:srgbClr val="9BBB59"/></a:accent3>
483
+ <a:accent4><a:srgbClr val="8064A2"/></a:accent4>
484
+ <a:accent5><a:srgbClr val="4BACC6"/></a:accent5>
485
+ <a:accent6><a:srgbClr val="F79646"/></a:accent6>
486
+ <a:hlink><a:srgbClr val="0000FF"/></a:hlink>
487
+ <a:folHlink><a:srgbClr val="800080"/></a:folHlink>
488
+ </a:clrScheme>
489
+ <a:fontScheme name="Office">
490
+ <a:majorFont>
491
+ <a:latin typeface="Times New Roman"/>
492
+ <a:ea typeface="FangSong_GB2312"/>
493
+ <a:cs typeface="Times New Roman"/>
494
+ </a:majorFont>
495
+ <a:minorFont>
496
+ <a:latin typeface="Times New Roman"/>
497
+ <a:ea typeface="FangSong_GB2312"/>
498
+ <a:cs typeface="Times New Roman"/>
499
+ </a:minorFont>
500
+ </a:fontScheme>
501
+ <a:fmtScheme name="Office">
502
+ <a:fillStyleLst>
503
+ <a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
504
+ <a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"/></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"/></a:gs></a:gsLst><a:lin ang="16200000" scaled="1"/></a:gradFill>
505
+ <a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"/></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"/></a:gs></a:gsLst><a:lin ang="16200000" scaled="1"/></a:gradFill>
506
+ </a:fillStyleLst>
507
+ <a:lnStyleLst>
508
+ <a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>
509
+ <a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>
510
+ <a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>
511
+ </a:lnStyleLst>
512
+ <a:effectStyleLst>
513
+ <a:effectStyle><a:effectLst/></a:effectStyle>
514
+ <a:effectStyle><a:effectLst/></a:effectStyle>
515
+ <a:effectStyle><a:effectLst/></a:effectStyle>
516
+ </a:effectStyleLst>
517
+ <a:bgFillStyleLst>
518
+ <a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
519
+ <a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
520
+ <a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
521
+ </a:bgFillStyleLst>
522
+ </a:fmtScheme>
523
+ </a:themeElements>
524
+ <a:objectDefaults/>
525
+ <a:extraClrSchemeLst/>
526
+ </a:theme>
527
+ `;
528
+ FONT_TABLE_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
529
+ <w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
530
+ <w:font w:name="Times New Roman">
531
+ <w:charset w:val="00"/>
532
+ <w:family w:val="roman"/>
533
+ <w:pitch w:val="variable"/>
534
+ </w:font>
535
+ <w:font w:name="FangSong_GB2312">
536
+ <w:charset w:val="86"/>
537
+ <w:family w:val="auto"/>
538
+ <w:pitch w:val="variable"/>
539
+ </w:font>
540
+ </w:fonts>
541
+ `;
194
542
  ROOT_RELS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
195
543
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
196
544
  <Relationship Id="rId1"
@@ -215,6 +563,12 @@ function shouldPreserveSpace(text) {
215
563
  if (!text) return false;
216
564
  return /^\s/.test(text) || /\s$/.test(text) || /\s{2,}/.test(text);
217
565
  }
566
+ function shouldKeepWhitespaceOnlyRun(text) {
567
+ if (!text) return false;
568
+ if (/\r|\n/.test(text)) return false;
569
+ if (text.includes("\xA0")) return true;
570
+ return /\s{2,}/.test(text);
571
+ }
218
572
  function parseStyleAttribute(style) {
219
573
  if (!style) return {};
220
574
  const normalized = style.replace(/\r/g, "\n");
@@ -434,7 +788,7 @@ function collectInlineRuns(node, inherited, out, result) {
434
788
  const intrinsic = parseIntrinsicImageSizePx(parsed.contentType, parsed.data);
435
789
  const { widthPx, heightPx } = computeImageSizePx(node, intrinsic);
436
790
  const id = result.images.length + 1;
437
- const relationshipId = `rId${id}`;
791
+ const relationshipId = `rId${id + IMAGE_RELATIONSHIP_ID_OFFSET}`;
438
792
  const target = `media/image${id}.${parsed.extension}`;
439
793
  result.images.push({
440
794
  relationshipId,
@@ -457,7 +811,7 @@ function collectInlineRuns(node, inherited, out, result) {
457
811
  const intrinsic = Number.isFinite(bufferW) && bufferW && Number.isFinite(bufferH) && bufferH ? { widthPx: Math.max(1, Math.round(bufferW)), heightPx: Math.max(1, Math.round(bufferH)) } : parseIntrinsicImageSizePx(parsed.contentType, parsed.data);
458
812
  const { widthPx, heightPx } = computeImageSizePx(node, intrinsic);
459
813
  const id = result.images.length + 1;
460
- const relationshipId = `rId${id}`;
814
+ const relationshipId = `rId${id + IMAGE_RELATIONSHIP_ID_OFFSET}`;
461
815
  const target = `media/image${id}.${parsed.extension}`;
462
816
  result.images.push({
463
817
  relationshipId,
@@ -558,9 +912,10 @@ function inferFirstFontSizeHalfPoints(node) {
558
912
  }
559
913
  return void 0;
560
914
  }
561
- function buildParagraphPrXml(node, baseFontHalfPoints, extraInd) {
915
+ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId) {
562
916
  const css = parseStyleAttribute(node.attribs?.style);
563
917
  const parts = [];
918
+ if (pStyleId) parts.push(`<w:pStyle w:val="${escapeXmlText(pStyleId)}"/>`);
564
919
  const align = css["text-align"]?.trim().toLowerCase();
565
920
  const jcVal = align === "center" ? "center" : align === "right" ? "right" : align === "justify" ? "both" : void 0;
566
921
  if (jcVal) parts.push(`<w:jc w:val="${jcVal}"/>`);
@@ -611,9 +966,9 @@ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd) {
611
966
  if (!parts.length) return "";
612
967
  return `<w:pPr>${parts.join("")}</w:pPr>`;
613
968
  }
614
- function buildParagraphXmlFromContainer(node, baseStyle, extraInd, result) {
969
+ function buildParagraphXmlFromContainer(node, baseStyle, extraInd, pStyleId, result) {
615
970
  const baseFontHalfPoints = baseStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;
616
- const pPrXml = buildParagraphPrXml(node, baseFontHalfPoints, extraInd);
971
+ const pPrXml = buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId);
617
972
  const runs = [];
618
973
  const res = result ?? {
619
974
  bodyXml: "",
@@ -632,7 +987,7 @@ function buildParagraphXmlFromContainer(node, baseStyle, extraInd, result) {
632
987
  }
633
988
  const text = token.text;
634
989
  if (!text) continue;
635
- if (!text.trim()) continue;
990
+ if (!text.trim() && !shouldKeepWhitespaceOnlyRun(text)) continue;
636
991
  rXml.push(buildRunXml(token.style, text));
637
992
  }
638
993
  if (!rXml.length) return "";
@@ -652,25 +1007,30 @@ function isExplicitPageBreak(node) {
652
1007
  if (after?.includes("always") || before?.includes("always")) return true;
653
1008
  return false;
654
1009
  }
655
- function buildHeadingBaseStyle(level) {
656
- const size = level === 1 ? 44 : level === 2 ? 32 : level === 3 ? 28 : level === 4 ? 24 : 22;
657
- return { bold: true, fontSizeHalfPoints: size };
658
- }
659
- function buildListBlocks(listNode, ordered, result) {
660
- const items = [];
661
- const stack = [...listNode.children ?? []];
662
- while (stack.length) {
663
- const n = stack.shift();
664
- if (n.type === "tag" && n.name?.toLowerCase() === "li") items.push(n);
665
- }
1010
+ function buildListBlocks(listNode, ordered, level, result) {
1011
+ const liNodes = (listNode.children ?? []).filter(
1012
+ (c) => c.type === "tag" && c.name?.toLowerCase() === "li"
1013
+ );
1014
+ if (!liNodes.length) return [];
666
1015
  const out = [];
667
- for (let i = 0; i < items.length; i++) {
668
- const prefix = ordered ? `${i + 1}. ` : "\u2022 ";
669
- const li = items[i];
1016
+ const numId = ordered ? 2 : 1;
1017
+ const ilvl = Math.max(0, Math.min(8, Math.floor(level)));
1018
+ const leftTwips = 720 * (ilvl + 1);
1019
+ const hangingTwips = 360;
1020
+ for (const li of liNodes) {
1021
+ const nestedLists = [];
670
1022
  const baseStyle = {};
671
1023
  const runs = [];
672
- runs.push({ kind: "text", text: prefix, style: baseStyle });
673
- for (const c of li.children ?? []) collectInlineRuns(c, baseStyle, runs, result);
1024
+ for (const c of li.children ?? []) {
1025
+ if (c.type === "tag") {
1026
+ const tag = c.name?.toLowerCase();
1027
+ if (tag === "ul" || tag === "ol") {
1028
+ nestedLists.push(c);
1029
+ continue;
1030
+ }
1031
+ }
1032
+ collectInlineRuns(c, baseStyle, runs, result);
1033
+ }
674
1034
  const rXml = [];
675
1035
  for (const token of runs) {
676
1036
  if (token.kind === "br") {
@@ -683,18 +1043,143 @@ function buildListBlocks(listNode, ordered, result) {
683
1043
  }
684
1044
  const text = token.text;
685
1045
  if (!text) continue;
686
- if (!text.trim()) continue;
1046
+ if (!text.trim() && !shouldKeepWhitespaceOnlyRun(text)) continue;
687
1047
  rXml.push(buildRunXml(token.style, text));
688
1048
  }
689
- if (!rXml.length) continue;
690
- const pPrXml = buildParagraphPrXml(li, inferFirstFontSizeHalfPoints(li) ?? 28, {
691
- leftTwips: 720,
692
- hangingTwips: 360
693
- });
694
- out.push(`<w:p>${pPrXml}${rXml.join("")}</w:p>`);
1049
+ if (rXml.length) {
1050
+ const baseFontHalfPoints = inferFirstFontSizeHalfPoints(li) ?? 28;
1051
+ const pPrXml = buildParagraphPrXml(
1052
+ li,
1053
+ baseFontHalfPoints,
1054
+ { leftTwips, hangingTwips },
1055
+ void 0
1056
+ );
1057
+ const numPrXml = `<w:numPr><w:ilvl w:val="${ilvl}"/><w:numId w:val="${numId}"/></w:numPr>`;
1058
+ const mergedPPrXml = pPrXml ? pPrXml.replace("<w:pPr>", `<w:pPr>${numPrXml}`) : `<w:pPr>${numPrXml}<w:ind w:left="${leftTwips}" w:hanging="${hangingTwips}"/></w:pPr>`;
1059
+ out.push(`<w:p>${mergedPPrXml}${rXml.join("")}</w:p>`);
1060
+ }
1061
+ for (const nested of nestedLists) {
1062
+ const nestedOrdered = nested.name?.toLowerCase() === "ol";
1063
+ out.push(...buildListBlocks(nested, nestedOrdered, ilvl + 1, result));
1064
+ }
695
1065
  }
696
1066
  return out;
697
1067
  }
1068
+ function parseCellWidthTwips(node) {
1069
+ const css = parseStyleAttribute(node.attribs?.style);
1070
+ const width = parseCssLengthToTwips(css.width, 28);
1071
+ if (typeof width !== "number" || width <= 0) return void 0;
1072
+ return width;
1073
+ }
1074
+ function estimateTextWidthTwips(text, baseFontHalfPoints) {
1075
+ const basePt = baseFontHalfPoints / 2;
1076
+ const cjkRegex = /[\u3400-\u4dbf\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/;
1077
+ let cjk = 0;
1078
+ let latin = 0;
1079
+ let spaces = 0;
1080
+ for (const ch of text) {
1081
+ if (ch === " " || ch === " ") {
1082
+ spaces++;
1083
+ continue;
1084
+ }
1085
+ if (cjkRegex.test(ch)) {
1086
+ cjk++;
1087
+ continue;
1088
+ }
1089
+ latin++;
1090
+ }
1091
+ const cjkTwips = Math.round(basePt * 20);
1092
+ const latinTwips = Math.round(basePt * 11);
1093
+ const spaceTwips = Math.round(basePt * 6);
1094
+ return cjk * cjkTwips + latin * latinTwips + spaces * spaceTwips;
1095
+ }
1096
+ function parseBorderShorthand(value, baseFontHalfPoints) {
1097
+ if (!value) return void 0;
1098
+ const raw = value.trim().toLowerCase();
1099
+ if (!raw) return void 0;
1100
+ if (raw === "none" || raw === "0") return { val: "nil", sz: 0 };
1101
+ const tokens = raw.split(/\s+/).filter(Boolean);
1102
+ if (!tokens.length) return void 0;
1103
+ const css = Object.fromEntries(tokens.map((t, i) => [`${i}`, t]));
1104
+ const widthToken = Object.values(css).find((t) => /^(?:\d+(?:\.\d+)?)(?:px|pt)?$/.test(t));
1105
+ const styleToken = Object.values(css).find(
1106
+ (t) => ["none", "solid", "dashed", "dotted", "double", "hidden"].includes(t)
1107
+ );
1108
+ const colorToken = Object.values(css).find((t) => t.startsWith("#") || t.startsWith("rgb("));
1109
+ const widthTwips = parseCssLengthToTwips(widthToken, baseFontHalfPoints);
1110
+ const sz = (() => {
1111
+ if (typeof widthTwips !== "number") return 4;
1112
+ if (widthTwips <= 0) return 0;
1113
+ return Math.max(2, Math.round(widthTwips * 0.4));
1114
+ })();
1115
+ const val = (() => {
1116
+ if (!styleToken) return "single";
1117
+ if (styleToken === "none" || styleToken === "hidden") return "nil";
1118
+ if (styleToken === "solid") return "single";
1119
+ if (styleToken === "dashed") return "dashed";
1120
+ if (styleToken === "dotted") return "dotted";
1121
+ if (styleToken === "double") return "double";
1122
+ return "single";
1123
+ })();
1124
+ const colorHex = parseCssColorToHex(colorToken);
1125
+ return { val, sz, colorHex };
1126
+ }
1127
+ function buildBorderTag(tag, border, fallbackColorHex) {
1128
+ const b = border ?? { val: "single", sz: 4, colorHex: fallbackColorHex };
1129
+ const color = (b.colorHex ?? fallbackColorHex).toUpperCase();
1130
+ return `<w:${tag} w:val="${b.val}" w:sz="${b.sz}" w:space="0" w:color="${color}"/>`;
1131
+ }
1132
+ function injectTableCellParagraphSpacing(pXml) {
1133
+ if (!pXml.includes("<w:p")) return pXml;
1134
+ if (!pXml.includes("<w:p>")) return pXml;
1135
+ const spacingXml = '<w:spacing w:before="0" w:after="0" w:line="360" w:lineRule="auto"/><w:wordWrap w:val="1"/>';
1136
+ if (pXml.includes("<w:pPr>")) {
1137
+ if (pXml.includes("<w:spacing ")) return pXml;
1138
+ return pXml.replace("<w:pPr>", `<w:pPr>${spacingXml}`);
1139
+ }
1140
+ return pXml.replace("<w:p>", `<w:p><w:pPr>${spacingXml}</w:pPr>`);
1141
+ }
1142
+ function buildTableCellBlocksXml(cell, baseStyle, result) {
1143
+ const children = cell.children ?? [];
1144
+ const hasBlocks = children.some((c) => {
1145
+ if (c.type !== "tag") return false;
1146
+ const tag = c.name?.toLowerCase();
1147
+ return tag === "p" || tag === "ul" || tag === "ol" || tag === "img" || tag === "canvas" || /^h[1-6]$/.test(tag ?? "");
1148
+ });
1149
+ const out = [];
1150
+ if (!hasBlocks) {
1151
+ const p = buildParagraphXmlFromContainer(cell, baseStyle, void 0, void 0, result);
1152
+ if (p) out.push(p);
1153
+ return out.length ? out.map(injectTableCellParagraphSpacing).join("") : "<w:p/>";
1154
+ }
1155
+ for (const c of children) {
1156
+ if (c.type === "tag") {
1157
+ const tag = c.name?.toLowerCase();
1158
+ if (tag === "p") {
1159
+ const p = buildParagraphXmlFromContainer(c, baseStyle, void 0, void 0, result);
1160
+ if (p) out.push(p);
1161
+ continue;
1162
+ }
1163
+ if (tag && /^h[1-6]$/.test(tag)) {
1164
+ const level = Number(tag.slice(1));
1165
+ const p = buildParagraphXmlFromContainer(c, baseStyle, void 0, `Heading${level}`, result);
1166
+ if (p) out.push(p);
1167
+ continue;
1168
+ }
1169
+ if (tag === "ul" || tag === "ol") {
1170
+ out.push(...buildListBlocks(c, tag === "ol", 0, result));
1171
+ continue;
1172
+ }
1173
+ if (tag === "img" || tag === "canvas") {
1174
+ const p = buildParagraphXmlFromSingleInlineNode(c, baseStyle, result);
1175
+ if (p) out.push(p);
1176
+ continue;
1177
+ }
1178
+ }
1179
+ }
1180
+ if (!out.length) return "<w:p/>";
1181
+ return out.map(injectTableCellParagraphSpacing).join("");
1182
+ }
698
1183
  function buildTableXml(tableNode, result) {
699
1184
  const rows = [];
700
1185
  const stack = [...tableNode.children ?? []];
@@ -703,25 +1188,137 @@ function buildTableXml(tableNode, result) {
703
1188
  if (n.type === "tag" && n.name?.toLowerCase() === "tr") rows.push(n);
704
1189
  if (n.children?.length) stack.unshift(...n.children);
705
1190
  }
706
- const rowXml = [];
707
- for (const tr of rows) {
708
- const cells = (tr.children ?? []).filter(
709
- (c) => c.type === "tag" && (c.name === "td" || c.name === "th")
1191
+ const rowCells = rows.map(
1192
+ (tr) => (tr.children ?? []).filter((c) => c.type === "tag" && (c.name === "td" || c.name === "th"))
1193
+ );
1194
+ const colCount = Math.max(0, ...rowCells.map((cells) => cells.length));
1195
+ const maxTableWidthTwips = 9360;
1196
+ const estimatedColWidths = new Array(colCount).fill(0).map((_, i) => {
1197
+ let explicit;
1198
+ let estimated = 0;
1199
+ for (const cells of rowCells) {
1200
+ const cell = cells[i];
1201
+ if (!cell) continue;
1202
+ const w = parseCellWidthTwips(cell);
1203
+ if (typeof w === "number") explicit = explicit ?? w;
1204
+ const text = getTextContent(cell).replace(/\s+/g, " ").trim();
1205
+ if (!text) continue;
1206
+ const baseFontHalfPoints = inferFirstFontSizeHalfPoints(cell) ?? 28;
1207
+ const wTwips = estimateTextWidthTwips(text, baseFontHalfPoints) + 240;
1208
+ estimated = Math.max(estimated, wTwips);
1209
+ }
1210
+ const base = typeof explicit === "number" ? explicit : estimated || Math.round(maxTableWidthTwips / Math.max(1, colCount));
1211
+ return Math.max(720, Math.min(6e3, Math.round(base)));
1212
+ });
1213
+ const normalizedColWidths = (() => {
1214
+ const sum = estimatedColWidths.reduce((a, b) => a + b, 0);
1215
+ if (!sum) return estimatedColWidths;
1216
+ if (sum <= maxTableWidthTwips) return estimatedColWidths;
1217
+ const scaled = estimatedColWidths.map(
1218
+ (w) => Math.max(720, Math.floor(w * maxTableWidthTwips / sum))
710
1219
  );
1220
+ const scaledSum = scaled.reduce((a, b) => a + b, 0);
1221
+ const diff = maxTableWidthTwips - scaledSum;
1222
+ if (diff !== 0 && scaled.length) scaled[scaled.length - 1] = Math.max(720, scaled[scaled.length - 1] + diff);
1223
+ return scaled;
1224
+ })();
1225
+ const tblGrid = `<w:tblGrid>${normalizedColWidths.map((w) => `<w:gridCol w:w="${w}"/>`).join("")}</w:tblGrid>`;
1226
+ const rowXml = [];
1227
+ for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
1228
+ const tr = rows[rowIdx];
1229
+ const cells = rowCells[rowIdx] ?? [];
711
1230
  const cellXml = [];
712
- for (const cell of cells) {
1231
+ for (let i = 0; i < cells.length; i++) {
1232
+ const cell = cells[i];
713
1233
  const isHeader = cell.name === "th";
714
1234
  const baseStyle = isHeader ? { bold: true } : {};
715
- const pXml = buildParagraphXmlFromContainer(cell, baseStyle, void 0, result);
716
- const paragraphs = pXml ? pXml : "<w:p/>";
717
- cellXml.push(
718
- `<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/></w:tcPr>${paragraphs}</w:tc>`
719
- );
1235
+ const paragraphs = buildTableCellBlocksXml(cell, baseStyle, result);
1236
+ const css = parseStyleAttribute(cell.attribs?.style);
1237
+ const widthTwips = parseCellWidthTwips(cell) ?? normalizedColWidths[i];
1238
+ const tcW = typeof widthTwips === "number" ? `<w:tcW w:w="${widthTwips}" w:type="dxa"/>` : `<w:tcW w:w="0" w:type="auto"/>`;
1239
+ const vAlign = (() => {
1240
+ const v = css["vertical-align"]?.trim().toLowerCase();
1241
+ if (!v) return "";
1242
+ if (v === "middle" || v === "center") return '<w:vAlign w:val="center"/>';
1243
+ if (v === "bottom") return '<w:vAlign w:val="bottom"/>';
1244
+ if (v === "top") return '<w:vAlign w:val="top"/>';
1245
+ return "";
1246
+ })();
1247
+ const shd = (() => {
1248
+ const hex = parseCssColorToHex(css["background-color"]);
1249
+ if (!hex) return "";
1250
+ return `<w:shd w:val="clear" w:color="auto" w:fill="${hex}"/>`;
1251
+ })();
1252
+ const noWrap = (() => {
1253
+ const ws = css["white-space"]?.trim().toLowerCase();
1254
+ if (ws?.includes("nowrap")) return "<w:noWrap/>";
1255
+ return "";
1256
+ })();
1257
+ const cellBorder = (() => {
1258
+ const bAll = parseBorderShorthand(css.border, 28);
1259
+ const bTop = parseBorderShorthand(css["border-top"] ?? css.border, 28);
1260
+ const bLeft = parseBorderShorthand(css["border-left"] ?? css.border, 28);
1261
+ const bBottom = parseBorderShorthand(css["border-bottom"] ?? css.border, 28);
1262
+ const bRight = parseBorderShorthand(css["border-right"] ?? css.border, 28);
1263
+ const any = bAll || css.border || css["border-top"] || css["border-left"] || css["border-bottom"] || css["border-right"];
1264
+ if (!any) return "";
1265
+ const fallback = bAll?.colorHex ?? "D9D9D9";
1266
+ return `<w:tcBorders>${buildBorderTag("top", bTop, fallback)}${buildBorderTag(
1267
+ "left",
1268
+ bLeft,
1269
+ fallback
1270
+ )}${buildBorderTag("bottom", bBottom, fallback)}${buildBorderTag(
1271
+ "right",
1272
+ bRight,
1273
+ fallback
1274
+ )}</w:tcBorders>`;
1275
+ })();
1276
+ cellXml.push(`<w:tc><w:tcPr>${tcW}${vAlign}${shd}${noWrap}${cellBorder}</w:tcPr>${paragraphs}</w:tc>`);
720
1277
  }
721
1278
  if (cellXml.length) rowXml.push(`<w:tr>${cellXml.join("")}</w:tr>`);
722
1279
  }
723
- const tblPr = `<w:tblPr><w:tblW w:w="0" w:type="auto"/><w:tblBorders><w:top w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/><w:left w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/><w:bottom w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/><w:right w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/><w:insideH w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/><w:insideV w:val="single" w:sz="4" w:space="0" w:color="D9D9D9"/></w:tblBorders></w:tblPr>`;
724
- const tblGrid = `<w:tblGrid/>`;
1280
+ const tblCss = parseStyleAttribute(tableNode.attribs?.style);
1281
+ const tblAlign = (() => {
1282
+ const ml = tblCss["margin-left"]?.trim().toLowerCase();
1283
+ const mr = tblCss["margin-right"]?.trim().toLowerCase();
1284
+ const m = tblCss.margin?.trim().toLowerCase();
1285
+ if (ml === "auto" && mr === "auto" || (m?.includes("auto") ?? false)) return '<w:tblJc w:val="center"/>';
1286
+ const ta = tblCss["text-align"]?.trim().toLowerCase();
1287
+ if (ta === "center") return '<w:tblJc w:val="center"/>';
1288
+ if (ta === "right") return '<w:tblJc w:val="right"/>';
1289
+ return "";
1290
+ })();
1291
+ const tblBorder = (() => {
1292
+ const border = parseBorderShorthand(tblCss.border, 28);
1293
+ if (tblCss.border) {
1294
+ const fallback2 = border?.colorHex ?? "D9D9D9";
1295
+ return `<w:tblBorders>${buildBorderTag("top", border, fallback2)}${buildBorderTag(
1296
+ "left",
1297
+ border,
1298
+ fallback2
1299
+ )}${buildBorderTag("bottom", border, fallback2)}${buildBorderTag(
1300
+ "right",
1301
+ border,
1302
+ fallback2
1303
+ )}${buildBorderTag("insideH", border, fallback2)}${buildBorderTag(
1304
+ "insideV",
1305
+ border,
1306
+ fallback2
1307
+ )}</w:tblBorders>`;
1308
+ }
1309
+ const fallback = "D9D9D9";
1310
+ return `<w:tblBorders>${buildBorderTag("top", void 0, fallback)}${buildBorderTag(
1311
+ "left",
1312
+ void 0,
1313
+ fallback
1314
+ )}${buildBorderTag("bottom", void 0, fallback)}${buildBorderTag(
1315
+ "right",
1316
+ void 0,
1317
+ fallback
1318
+ )}${buildBorderTag("insideH", void 0, fallback)}${buildBorderTag("insideV", void 0, fallback)}</w:tblBorders>`;
1319
+ })();
1320
+ const tblW = `<w:tblW w:w="${normalizedColWidths.reduce((a, b) => a + b, 0)}" w:type="dxa"/>`;
1321
+ const tblPr = `<w:tblPr>${tblW}<w:tblLayout w:type="fixed"/>${tblAlign}${tblBorder}</w:tblPr>`;
725
1322
  return `<w:tbl>${tblPr}${tblGrid}${rowXml.join("")}</w:tbl>`;
726
1323
  }
727
1324
  function buildParagraphXmlFromSingleInlineNode(node, baseStyle, result) {
@@ -731,7 +1328,7 @@ function buildParagraphXmlFromSingleInlineNode(node, baseStyle, result) {
731
1328
  attribs: { style: "text-align: center;" },
732
1329
  children: [node]
733
1330
  };
734
- return buildParagraphXmlFromContainer(wrapper, baseStyle, void 0, result);
1331
+ return buildParagraphXmlFromContainer(wrapper, baseStyle, void 0, void 0, result);
735
1332
  }
736
1333
  function collectBodyBlocks(node, out, result) {
737
1334
  if (isSkippableSubtree(node)) return;
@@ -742,7 +1339,7 @@ function collectBodyBlocks(node, out, result) {
742
1339
  return;
743
1340
  }
744
1341
  if (tag === "p") {
745
- const pXml = buildParagraphXmlFromContainer(node, {}, void 0, result);
1342
+ const pXml = buildParagraphXmlFromContainer(node, {}, void 0, void 0, result);
746
1343
  if (pXml) out.push(pXml);
747
1344
  return;
748
1345
  }
@@ -753,7 +1350,7 @@ function collectBodyBlocks(node, out, result) {
753
1350
  }
754
1351
  if (tag && /^h[1-6]$/.test(tag)) {
755
1352
  const level = Number(tag.slice(1));
756
- const hXml = buildParagraphXmlFromContainer(node, buildHeadingBaseStyle(level), void 0, result);
1353
+ const hXml = buildParagraphXmlFromContainer(node, {}, void 0, `Heading${level}`, result);
757
1354
  if (hXml) out.push(hXml);
758
1355
  return;
759
1356
  }
@@ -763,7 +1360,7 @@ function collectBodyBlocks(node, out, result) {
763
1360
  return;
764
1361
  }
765
1362
  if (tag === "ul" || tag === "ol") {
766
- out.push(...buildListBlocks(node, tag === "ol", result));
1363
+ out.push(...buildListBlocks(node, tag === "ol", 0, result));
767
1364
  return;
768
1365
  }
769
1366
  }
@@ -826,11 +1423,12 @@ function htmlToWordBodyWithAssets(html) {
826
1423
  }
827
1424
  return result;
828
1425
  }
829
- var import_htmlparser2, PAGE_BREAK_XML;
1426
+ var import_htmlparser2, IMAGE_RELATIONSHIP_ID_OFFSET, PAGE_BREAK_XML;
830
1427
  var init_htmlToWordBodyXml = __esm({
831
1428
  "src/lib/htmlToWordBodyXml.ts"() {
832
1429
  "use strict";
833
1430
  import_htmlparser2 = require("htmlparser2");
1431
+ IMAGE_RELATIONSHIP_ID_OFFSET = 7;
834
1432
  PAGE_BREAK_XML = '<w:p><w:r><w:br w:type="page"/></w:r></w:p>';
835
1433
  }
836
1434
  });