@cj-tech-master/excelts 9.5.4 → 9.5.5

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.
Files changed (767) hide show
  1. package/dist/browser/modules/archive/compression/streaming-compress.browser.js +29 -0
  2. package/dist/browser/modules/archive/compression/streaming-compress.js +9 -0
  3. package/dist/browser/modules/archive/compression/worker-pool/pool.browser.js +26 -1
  4. package/dist/browser/modules/archive/fs/archive-file.d.ts +8 -5
  5. package/dist/browser/modules/archive/fs/archive-file.js +78 -16
  6. package/dist/browser/modules/archive/unzip/stream.browser.js +43 -2
  7. package/dist/browser/modules/excel/chart/chart-ex-builder.js +7 -2
  8. package/dist/browser/modules/excel/chart/chart-ex-renderer.js +4 -9
  9. package/dist/browser/modules/excel/chart/chart-ex-types.d.ts +0 -12
  10. package/dist/browser/modules/excel/chart/chart.d.ts +1 -5
  11. package/dist/browser/modules/excel/chart/chart.js +1 -7
  12. package/dist/browser/modules/excel/chart/types.d.ts +0 -6
  13. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +25 -1
  14. package/dist/browser/modules/excel/stream/workbook-reader.js +9 -0
  15. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +40 -0
  16. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +228 -13
  17. package/dist/browser/modules/excel/utils/string-buf.d.ts +5 -26
  18. package/dist/browser/modules/excel/utils/string-buf.js +4 -81
  19. package/dist/browser/modules/excel/workbook.browser.js +135 -25
  20. package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
  21. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +19 -9
  22. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +32 -8
  23. package/dist/browser/modules/excel/xlsx/xlsx.d.ts +10 -2
  24. package/dist/browser/modules/excel/xlsx/xlsx.js +9 -1
  25. package/dist/browser/modules/pdf/excel-bridge.d.ts +30 -1
  26. package/dist/browser/modules/pdf/excel-bridge.js +32 -0
  27. package/dist/browser/modules/pdf/font/metrics.d.ts +3 -52
  28. package/dist/browser/modules/pdf/font/metrics.js +3 -237
  29. package/dist/browser/modules/pdf/index.d.ts +1 -1
  30. package/dist/browser/modules/pdf/index.js +1 -1
  31. package/dist/browser/modules/pdf/render-layout-to-pdf.d.ts +66 -0
  32. package/dist/browser/modules/pdf/render-layout-to-pdf.js +647 -0
  33. package/dist/browser/modules/pdf/word-bridge.d.ts +80 -12
  34. package/dist/browser/modules/pdf/word-bridge.js +122 -274
  35. package/dist/browser/modules/stream/index.base.d.ts +2 -0
  36. package/dist/browser/modules/stream/index.base.js +2 -1
  37. package/dist/browser/modules/stream/internal/sink-adapter.d.ts +65 -0
  38. package/dist/browser/modules/stream/internal/sink-adapter.js +198 -0
  39. package/dist/browser/modules/stream/pull-stream.d.ts +19 -2
  40. package/dist/browser/modules/stream/pull-stream.js +51 -5
  41. package/dist/browser/modules/stream/types.d.ts +13 -1
  42. package/dist/browser/modules/word/advanced/diff.d.ts +61 -0
  43. package/dist/browser/modules/word/advanced/diff.js +167 -0
  44. package/dist/browser/modules/word/advanced/drawing-shapes.d.ts +269 -0
  45. package/dist/browser/modules/word/advanced/drawing-shapes.js +268 -0
  46. package/dist/browser/modules/word/advanced/field-engine.d.ts +43 -0
  47. package/dist/browser/modules/word/advanced/field-engine.js +1225 -0
  48. package/dist/browser/modules/word/advanced/glossary.d.ts +86 -0
  49. package/dist/browser/modules/word/advanced/glossary.js +79 -0
  50. package/dist/browser/modules/word/advanced/math-convert.d.ts +30 -0
  51. package/dist/browser/modules/word/advanced/math-convert.js +595 -0
  52. package/dist/browser/modules/word/advanced/ole-objects.d.ts +115 -0
  53. package/dist/browser/modules/word/advanced/ole-objects.js +271 -0
  54. package/dist/browser/modules/word/advanced/style-map.d.ts +105 -0
  55. package/dist/browser/modules/word/advanced/style-map.js +322 -0
  56. package/dist/browser/modules/word/advanced/validation.d.ts +56 -0
  57. package/dist/browser/modules/word/advanced/validation.js +1065 -0
  58. package/dist/browser/modules/word/advanced/vba-project.d.ts +91 -0
  59. package/dist/browser/modules/word/advanced/vba-project.js +265 -0
  60. package/dist/browser/modules/word/bridge/excel-bridge.d.ts +127 -0
  61. package/dist/browser/modules/word/bridge/excel-bridge.js +980 -0
  62. package/dist/browser/modules/word/builder/document-handle.d.ts +151 -0
  63. package/dist/browser/modules/word/builder/document-handle.js +664 -0
  64. package/dist/browser/modules/word/builder/paragraph-builders.d.ts +61 -0
  65. package/dist/browser/modules/word/builder/paragraph-builders.js +90 -0
  66. package/dist/browser/modules/word/builder/run-builders.d.ts +374 -0
  67. package/dist/browser/modules/word/builder/run-builders.js +600 -0
  68. package/dist/browser/modules/word/builder/table-builders.d.ts +23 -0
  69. package/dist/browser/modules/word/builder/table-builders.js +45 -0
  70. package/dist/browser/modules/word/constants.d.ts +39 -1
  71. package/dist/browser/modules/word/constants.js +109 -1
  72. package/dist/browser/modules/word/convert/conversion-ir.d.ts +210 -0
  73. package/dist/browser/modules/word/convert/conversion-ir.js +31 -0
  74. package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +39 -0
  75. package/dist/browser/modules/word/convert/docx-to-semantic.js +499 -0
  76. package/dist/browser/modules/word/convert/flat-opc.d.ts +44 -0
  77. package/dist/browser/modules/word/convert/flat-opc.js +385 -0
  78. package/dist/browser/modules/word/convert/html/html-import.d.ts +50 -0
  79. package/dist/browser/modules/word/convert/html/html-import.js +1907 -0
  80. package/dist/{types/modules/word → browser/modules/word/convert/html}/html-renderer.d.ts +14 -1
  81. package/dist/{esm/modules/word → browser/modules/word/convert/html}/html-renderer.js +420 -69
  82. package/dist/browser/modules/word/convert/html/html.d.ts +15 -0
  83. package/dist/browser/modules/word/convert/html/html.js +15 -0
  84. package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +68 -0
  85. package/dist/browser/modules/word/convert/markdown/markdown-import.js +1325 -0
  86. package/dist/browser/modules/word/convert/markdown/markdown-renderer.d.ts +25 -0
  87. package/dist/browser/modules/word/convert/markdown/markdown-renderer.js +634 -0
  88. package/dist/browser/modules/word/convert/markdown/markdown.d.ts +15 -0
  89. package/dist/browser/modules/word/convert/markdown/markdown.js +15 -0
  90. package/dist/browser/modules/word/convert/odt/odt.d.ts +41 -0
  91. package/dist/browser/modules/word/convert/odt/odt.js +1932 -0
  92. package/dist/browser/modules/word/{color-utils.d.ts → core/color-utils.d.ts} +8 -1
  93. package/dist/browser/modules/word/core/color-utils.js +43 -0
  94. package/dist/browser/modules/word/core/internal-utils.d.ts +90 -0
  95. package/dist/browser/modules/word/core/internal-utils.js +209 -0
  96. package/dist/browser/modules/word/core/mapper.d.ts +44 -0
  97. package/dist/browser/modules/word/core/mapper.js +427 -0
  98. package/dist/browser/modules/word/core/opc-paths.d.ts +33 -0
  99. package/dist/browser/modules/word/core/opc-paths.js +48 -0
  100. package/dist/browser/modules/word/core/text-utils.d.ts +38 -0
  101. package/dist/browser/modules/word/core/text-utils.js +202 -0
  102. package/dist/browser/modules/word/core/walker.d.ts +119 -0
  103. package/dist/browser/modules/word/core/walker.js +570 -0
  104. package/dist/browser/modules/word/crypto.d.ts +14 -9
  105. package/dist/browser/modules/word/crypto.js +13 -7
  106. package/dist/browser/modules/word/document-io.d.ts +59 -27
  107. package/dist/browser/modules/word/document-io.js +80 -197
  108. package/dist/browser/modules/word/errors.d.ts +44 -1
  109. package/dist/browser/modules/word/errors.js +54 -2
  110. package/dist/browser/modules/word/excel.d.ts +14 -0
  111. package/dist/browser/modules/word/excel.js +13 -0
  112. package/dist/browser/modules/word/font/font-embed.d.ts +112 -0
  113. package/dist/browser/modules/word/font/font-embed.js +646 -0
  114. package/dist/{esm/modules/word → browser/modules/word/font}/font-obfuscation.js +4 -9
  115. package/dist/browser/modules/word/font/hyphenation.d.ts +65 -0
  116. package/dist/browser/modules/word/font/hyphenation.js +4210 -0
  117. package/dist/browser/modules/word/font/text-shaping.d.ts +58 -0
  118. package/dist/browser/modules/word/font/text-shaping.js +635 -0
  119. package/dist/browser/modules/word/html.d.ts +7 -6
  120. package/dist/browser/modules/word/html.js +6 -5
  121. package/dist/browser/modules/word/incremental-edit.d.ts +123 -0
  122. package/dist/browser/modules/word/incremental-edit.js +361 -0
  123. package/dist/browser/modules/word/index.base.d.ts +194 -10
  124. package/dist/browser/modules/word/index.base.js +138 -29
  125. package/dist/browser/modules/word/layout/layout-constants.d.ts +17 -0
  126. package/dist/browser/modules/word/layout/layout-constants.js +17 -0
  127. package/dist/browser/modules/word/layout/layout-full.d.ts +53 -0
  128. package/dist/browser/modules/word/layout/layout-full.js +1696 -0
  129. package/dist/browser/modules/word/layout/layout-model.d.ts +344 -0
  130. package/dist/browser/modules/word/layout/layout-model.js +16 -0
  131. package/dist/browser/modules/word/layout/layout.d.ts +63 -0
  132. package/dist/browser/modules/word/layout/layout.js +1167 -0
  133. package/dist/browser/modules/word/layout/render-page.d.ts +57 -0
  134. package/dist/browser/modules/word/layout/render-page.js +1238 -0
  135. package/dist/browser/modules/word/markdown.d.ts +14 -0
  136. package/dist/browser/modules/word/markdown.js +13 -0
  137. package/dist/browser/modules/word/patcher.d.ts +62 -0
  138. package/dist/browser/modules/word/patcher.js +537 -0
  139. package/dist/browser/modules/word/query/compat.d.ts +25 -0
  140. package/dist/browser/modules/word/query/compat.js +58 -0
  141. package/dist/browser/modules/word/query/data-binding.d.ts +22 -0
  142. package/dist/browser/modules/word/query/data-binding.js +392 -0
  143. package/dist/browser/modules/word/query/form-fields.d.ts +41 -0
  144. package/dist/browser/modules/word/query/form-fields.js +268 -0
  145. package/dist/browser/modules/word/query/format-search.d.ts +99 -0
  146. package/dist/browser/modules/word/query/format-search.js +329 -0
  147. package/dist/browser/modules/word/query/mail-merge.d.ts +25 -0
  148. package/dist/browser/modules/word/query/mail-merge.js +111 -0
  149. package/dist/browser/modules/word/query/merge.d.ts +50 -0
  150. package/dist/browser/modules/word/query/merge.js +617 -0
  151. package/dist/browser/modules/word/query/replace.d.ts +47 -0
  152. package/dist/browser/modules/word/query/replace.js +301 -0
  153. package/dist/browser/modules/word/query/revisions.d.ts +67 -0
  154. package/dist/browser/modules/word/query/revisions.js +879 -0
  155. package/dist/browser/modules/word/query/search.d.ts +129 -0
  156. package/dist/browser/modules/word/query/search.js +346 -0
  157. package/dist/browser/modules/word/query/split.d.ts +44 -0
  158. package/dist/browser/modules/word/query/split.js +135 -0
  159. package/dist/browser/modules/word/query/style-resolve.d.ts +104 -0
  160. package/dist/browser/modules/word/query/style-resolve.js +368 -0
  161. package/dist/browser/modules/word/reader/chart-parser.d.ts +20 -0
  162. package/dist/browser/modules/word/reader/chart-parser.js +810 -0
  163. package/dist/browser/modules/word/reader/comments-parser.d.ts +26 -0
  164. package/dist/browser/modules/word/reader/comments-parser.js +92 -0
  165. package/dist/browser/modules/word/reader/doc-props-parsers.d.ts +15 -0
  166. package/dist/browser/modules/word/reader/doc-props-parsers.js +190 -0
  167. package/dist/browser/modules/word/reader/docx-reader.d.ts +27 -0
  168. package/dist/browser/modules/word/reader/docx-reader.js +2557 -0
  169. package/dist/browser/modules/word/reader/drawing-helpers.d.ts +27 -0
  170. package/dist/browser/modules/word/reader/drawing-helpers.js +84 -0
  171. package/dist/browser/modules/word/reader/form-field-parser.d.ts +21 -0
  172. package/dist/browser/modules/word/reader/form-field-parser.js +82 -0
  173. package/dist/browser/modules/word/reader/image-parsers.d.ts +11 -0
  174. package/dist/browser/modules/word/reader/image-parsers.js +291 -0
  175. package/dist/browser/modules/word/reader/math-parser.d.ts +12 -0
  176. package/dist/browser/modules/word/reader/math-parser.js +422 -0
  177. package/dist/browser/modules/word/reader/metadata-parsers.d.ts +17 -0
  178. package/dist/browser/modules/word/reader/metadata-parsers.js +87 -0
  179. package/dist/browser/modules/word/reader/numbering-parser.d.ts +13 -0
  180. package/dist/browser/modules/word/reader/numbering-parser.js +166 -0
  181. package/dist/browser/modules/word/reader/paragraph-section-parsers.d.ts +12 -0
  182. package/dist/browser/modules/word/reader/paragraph-section-parsers.js +503 -0
  183. package/dist/browser/modules/word/reader/parse-utils.d.ts +91 -0
  184. package/dist/browser/modules/word/reader/parse-utils.js +249 -0
  185. package/dist/browser/modules/word/reader/properties-parsers.d.ts +21 -0
  186. package/dist/browser/modules/word/reader/properties-parsers.js +332 -0
  187. package/dist/browser/modules/word/reader/reader-context.d.ts +69 -0
  188. package/dist/browser/modules/word/reader/reader-context.js +61 -0
  189. package/dist/browser/modules/word/reader/sdt-helpers.d.ts +29 -0
  190. package/dist/browser/modules/word/reader/sdt-helpers.js +111 -0
  191. package/dist/browser/modules/word/reader/settings-parser.d.ts +8 -0
  192. package/dist/browser/modules/word/reader/settings-parser.js +263 -0
  193. package/dist/browser/modules/word/reader/styles-parser.d.ts +12 -0
  194. package/dist/browser/modules/word/reader/styles-parser.js +147 -0
  195. package/dist/browser/modules/word/reader/table-properties-parsers.d.ts +12 -0
  196. package/dist/browser/modules/word/reader/table-properties-parsers.js +234 -0
  197. package/dist/browser/modules/word/reader/theme-parser.d.ts +8 -0
  198. package/dist/browser/modules/word/reader/theme-parser.js +167 -0
  199. package/dist/browser/modules/word/reader/watermark-parser.d.ts +15 -0
  200. package/dist/browser/modules/word/reader/watermark-parser.js +110 -0
  201. package/dist/browser/modules/word/security/cfb-reader.d.ts +37 -0
  202. package/dist/browser/modules/word/security/cfb-reader.js +410 -0
  203. package/dist/browser/modules/word/{digital-signatures.d.ts → security/digital-signatures.d.ts} +19 -11
  204. package/dist/browser/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
  205. package/dist/browser/modules/word/security/document-protection.d.ts +93 -0
  206. package/dist/browser/modules/word/security/document-protection.js +201 -0
  207. package/dist/{types/modules/word → browser/modules/word/security}/encryption.d.ts +51 -4
  208. package/dist/browser/modules/word/security/encryption.js +602 -0
  209. package/dist/browser/modules/word/security/policy.d.ts +80 -0
  210. package/dist/browser/modules/word/security/policy.js +102 -0
  211. package/dist/browser/modules/word/template/template-chart.d.ts +56 -0
  212. package/dist/browser/modules/word/template/template-chart.js +167 -0
  213. package/dist/browser/modules/word/template/template-datasource.d.ts +154 -0
  214. package/dist/browser/modules/word/template/template-datasource.js +541 -0
  215. package/dist/browser/modules/word/template/template-engine.d.ts +121 -0
  216. package/dist/browser/modules/word/template/template-engine.js +1435 -0
  217. package/dist/browser/modules/word/types.d.ts +224 -25
  218. package/dist/browser/modules/word/units.d.ts +26 -0
  219. package/dist/browser/modules/word/units.js +43 -14
  220. package/dist/browser/modules/word/{writers → writer}/chart-writer.js +164 -23
  221. package/dist/browser/modules/word/writer/checkbox-writer.d.ts +17 -0
  222. package/dist/browser/modules/word/writer/checkbox-writer.js +79 -0
  223. package/dist/{types/modules/word/writers → browser/modules/word/writer}/comment-writer.d.ts +2 -1
  224. package/dist/browser/modules/word/{writers → writer}/comment-writer.js +8 -6
  225. package/dist/browser/modules/word/writer/common-parts.d.ts +57 -0
  226. package/dist/browser/modules/word/writer/common-parts.js +101 -0
  227. package/dist/{types/modules/word → browser/modules/word/writer}/content-types.d.ts +2 -2
  228. package/dist/{esm/modules/word → browser/modules/word/writer}/content-types.js +14 -6
  229. package/dist/browser/modules/word/writer/document-writer.d.ts +24 -0
  230. package/dist/browser/modules/word/writer/document-writer.js +473 -0
  231. package/dist/browser/modules/word/writer/docx-packager.d.ts +35 -0
  232. package/dist/browser/modules/word/writer/docx-packager.js +1515 -0
  233. package/dist/{types/modules/word/writers → browser/modules/word/writer}/footnote-writer.d.ts +3 -2
  234. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/footnote-writer.js +13 -10
  235. package/dist/{types/modules/word/writers → browser/modules/word/writer}/header-footer-writer.d.ts +3 -2
  236. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/header-footer-writer.js +39 -21
  237. package/dist/{types/modules/word/writers → browser/modules/word/writer}/image-writer.d.ts +1 -1
  238. package/dist/browser/modules/word/{writers → writer}/image-writer.js +11 -7
  239. package/dist/browser/modules/word/writer/math-writer.d.ts +20 -0
  240. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/math-writer.js +21 -1
  241. package/dist/browser/modules/word/{writers → writer}/numbering-writer.d.ts +1 -1
  242. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/numbering-writer.js +11 -4
  243. package/dist/browser/modules/word/{writers → writer}/paragraph-writer.d.ts +2 -1
  244. package/dist/browser/modules/word/{writers → writer}/paragraph-writer.js +73 -38
  245. package/dist/browser/modules/word/{writers → writer}/parts-writer.d.ts +3 -3
  246. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/parts-writer.js +91 -12
  247. package/dist/browser/modules/word/writer/reference-scanners.d.ts +42 -0
  248. package/dist/browser/modules/word/writer/reference-scanners.js +111 -0
  249. package/dist/browser/modules/word/writer/relationships.d.ts +52 -0
  250. package/dist/browser/modules/word/writer/relationships.js +117 -0
  251. package/dist/browser/modules/word/writer/render-context.d.ts +124 -0
  252. package/dist/browser/modules/word/writer/render-context.js +46 -0
  253. package/dist/browser/modules/word/{writers → writer}/run-writer.d.ts +10 -1
  254. package/dist/{esm/modules/word/writers → browser/modules/word/writer}/run-writer.js +126 -24
  255. package/dist/browser/modules/word/writer/sdt-writer.d.ts +25 -0
  256. package/dist/browser/modules/word/writer/sdt-writer.js +189 -0
  257. package/dist/browser/modules/word/writer/stream-buf.d.ts +37 -0
  258. package/dist/browser/modules/word/writer/stream-buf.js +73 -0
  259. package/dist/browser/modules/word/writer/streaming-writer.d.ts +344 -0
  260. package/dist/browser/modules/word/writer/streaming-writer.js +1382 -0
  261. package/dist/browser/modules/word/writer/string-buf.d.ts +8 -0
  262. package/dist/browser/modules/word/writer/string-buf.js +7 -0
  263. package/dist/browser/modules/word/{writers → writer}/styles-writer.js +32 -1
  264. package/dist/browser/modules/word/{writers → writer}/table-writer.d.ts +2 -1
  265. package/dist/browser/modules/word/{writers → writer}/table-writer.js +94 -11
  266. package/dist/browser/modules/xml/types.d.ts +22 -0
  267. package/dist/browser/utils/crypto.browser.d.ts +3 -1
  268. package/dist/browser/utils/crypto.browser.js +3 -1
  269. package/dist/browser/utils/crypto.d.ts +4 -1
  270. package/dist/browser/utils/crypto.js +4 -1
  271. package/dist/browser/utils/font-metrics.d.ts +63 -0
  272. package/dist/browser/utils/font-metrics.js +293 -0
  273. package/dist/browser/utils/string-buf.d.ts +42 -0
  274. package/dist/browser/utils/string-buf.js +89 -0
  275. package/dist/browser/utils/theme-colors.d.ts +55 -0
  276. package/dist/browser/utils/theme-colors.js +120 -0
  277. package/dist/cjs/modules/archive/compression/streaming-compress.browser.js +29 -0
  278. package/dist/cjs/modules/archive/compression/streaming-compress.js +9 -0
  279. package/dist/cjs/modules/archive/compression/worker-pool/pool.browser.js +26 -1
  280. package/dist/cjs/modules/archive/fs/archive-file.js +78 -16
  281. package/dist/cjs/modules/archive/unzip/stream.browser.js +43 -2
  282. package/dist/cjs/modules/excel/chart/chart-ex-builder.js +7 -2
  283. package/dist/cjs/modules/excel/chart/chart-ex-renderer.js +4 -9
  284. package/dist/cjs/modules/excel/chart/chart.js +1 -7
  285. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +25 -1
  286. package/dist/cjs/modules/excel/stream/workbook-reader.js +9 -0
  287. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +228 -13
  288. package/dist/cjs/modules/excel/utils/string-buf.js +5 -81
  289. package/dist/cjs/modules/excel/workbook.browser.js +135 -25
  290. package/dist/cjs/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
  291. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +32 -8
  292. package/dist/cjs/modules/excel/xlsx/xlsx.js +9 -1
  293. package/dist/cjs/modules/pdf/excel-bridge.js +33 -0
  294. package/dist/cjs/modules/pdf/font/metrics.js +11 -244
  295. package/dist/cjs/modules/pdf/index.js +2 -1
  296. package/dist/cjs/modules/pdf/render-layout-to-pdf.js +651 -0
  297. package/dist/cjs/modules/pdf/word-bridge.js +155 -274
  298. package/dist/cjs/modules/stream/index.base.js +4 -2
  299. package/dist/cjs/modules/stream/internal/sink-adapter.js +202 -0
  300. package/dist/cjs/modules/stream/pull-stream.js +51 -5
  301. package/dist/cjs/modules/word/advanced/diff.js +170 -0
  302. package/dist/cjs/modules/word/advanced/drawing-shapes.js +279 -0
  303. package/dist/cjs/modules/word/advanced/field-engine.js +1229 -0
  304. package/dist/cjs/modules/word/advanced/glossary.js +87 -0
  305. package/dist/cjs/modules/word/advanced/math-convert.js +599 -0
  306. package/dist/cjs/modules/word/advanced/ole-objects.js +277 -0
  307. package/dist/cjs/modules/word/advanced/style-map.js +329 -0
  308. package/dist/cjs/modules/word/advanced/validation.js +1068 -0
  309. package/dist/cjs/modules/word/advanced/vba-project.js +274 -0
  310. package/dist/cjs/modules/word/bridge/excel-bridge.js +1020 -0
  311. package/dist/cjs/modules/word/builder/document-handle.js +667 -0
  312. package/dist/cjs/modules/word/builder/paragraph-builders.js +109 -0
  313. package/dist/cjs/modules/word/builder/run-builders.js +676 -0
  314. package/dist/cjs/modules/word/builder/table-builders.js +53 -0
  315. package/dist/cjs/modules/word/constants.js +111 -2
  316. package/dist/cjs/modules/word/convert/conversion-ir.js +34 -0
  317. package/dist/cjs/modules/word/convert/docx-to-semantic.js +502 -0
  318. package/dist/cjs/modules/word/convert/flat-opc.js +390 -0
  319. package/dist/cjs/modules/word/convert/html/html-import.js +1910 -0
  320. package/dist/cjs/modules/word/{html-renderer.js → convert/html/html-renderer.js} +420 -69
  321. package/dist/cjs/modules/word/convert/html/html.js +20 -0
  322. package/dist/cjs/modules/word/convert/markdown/markdown-import.js +1329 -0
  323. package/dist/cjs/modules/word/convert/markdown/markdown-renderer.js +637 -0
  324. package/dist/cjs/modules/word/convert/markdown/markdown.js +21 -0
  325. package/dist/cjs/modules/word/convert/odt/odt.js +1936 -0
  326. package/dist/cjs/modules/word/core/color-utils.js +47 -0
  327. package/dist/cjs/modules/word/core/internal-utils.js +219 -0
  328. package/dist/cjs/modules/word/core/mapper.js +430 -0
  329. package/dist/cjs/modules/word/core/opc-paths.js +53 -0
  330. package/dist/cjs/modules/word/core/text-utils.js +210 -0
  331. package/dist/cjs/modules/word/core/walker.js +577 -0
  332. package/dist/cjs/modules/word/crypto.js +19 -8
  333. package/dist/cjs/modules/word/document-io.js +117 -197
  334. package/dist/cjs/modules/word/errors.js +59 -13
  335. package/dist/cjs/modules/word/excel.js +22 -0
  336. package/dist/cjs/modules/word/font/font-embed.js +652 -0
  337. package/dist/cjs/modules/word/{font-obfuscation.js → font/font-obfuscation.js} +4 -9
  338. package/dist/cjs/modules/word/font/hyphenation.js +4216 -0
  339. package/dist/cjs/modules/word/font/text-shaping.js +640 -0
  340. package/dist/cjs/modules/word/html.js +9 -7
  341. package/dist/cjs/modules/word/incremental-edit.js +366 -0
  342. package/dist/cjs/modules/word/index.base.js +370 -137
  343. package/dist/cjs/modules/word/layout/layout-constants.js +20 -0
  344. package/dist/cjs/modules/word/layout/layout-full.js +1699 -0
  345. package/dist/cjs/modules/word/layout/layout-model.js +17 -0
  346. package/dist/cjs/modules/word/layout/layout.js +1170 -0
  347. package/dist/cjs/modules/word/layout/render-page.js +1243 -0
  348. package/dist/cjs/modules/word/markdown.js +19 -0
  349. package/dist/cjs/modules/word/patcher.js +539 -0
  350. package/dist/cjs/modules/word/query/compat.js +61 -0
  351. package/dist/cjs/modules/word/query/data-binding.js +395 -0
  352. package/dist/cjs/modules/word/query/form-fields.js +272 -0
  353. package/dist/cjs/modules/word/query/format-search.js +334 -0
  354. package/dist/cjs/modules/word/query/mail-merge.js +114 -0
  355. package/dist/cjs/modules/word/query/merge.js +620 -0
  356. package/dist/cjs/modules/word/query/replace.js +304 -0
  357. package/dist/cjs/modules/word/query/revisions.js +885 -0
  358. package/dist/cjs/modules/word/query/search.js +361 -0
  359. package/dist/cjs/modules/word/query/split.js +138 -0
  360. package/dist/cjs/modules/word/query/style-resolve.js +374 -0
  361. package/dist/cjs/modules/word/reader/chart-parser.js +814 -0
  362. package/dist/cjs/modules/word/reader/comments-parser.js +96 -0
  363. package/dist/cjs/modules/word/reader/doc-props-parsers.js +194 -0
  364. package/dist/cjs/modules/word/reader/docx-reader.js +2560 -0
  365. package/dist/cjs/modules/word/reader/drawing-helpers.js +90 -0
  366. package/dist/cjs/modules/word/reader/form-field-parser.js +85 -0
  367. package/dist/cjs/modules/word/reader/image-parsers.js +293 -0
  368. package/dist/cjs/modules/word/reader/math-parser.js +424 -0
  369. package/dist/cjs/modules/word/reader/metadata-parsers.js +93 -0
  370. package/dist/cjs/modules/word/reader/numbering-parser.js +168 -0
  371. package/dist/cjs/modules/word/reader/paragraph-section-parsers.js +505 -0
  372. package/dist/cjs/modules/word/reader/parse-utils.js +271 -0
  373. package/dist/cjs/modules/word/reader/properties-parsers.js +338 -0
  374. package/dist/cjs/modules/word/reader/reader-context.js +66 -0
  375. package/dist/cjs/modules/word/reader/sdt-helpers.js +114 -0
  376. package/dist/cjs/modules/word/reader/settings-parser.js +265 -0
  377. package/dist/cjs/modules/word/reader/styles-parser.js +149 -0
  378. package/dist/cjs/modules/word/reader/table-properties-parsers.js +237 -0
  379. package/dist/cjs/modules/word/reader/theme-parser.js +169 -0
  380. package/dist/cjs/modules/word/reader/watermark-parser.js +113 -0
  381. package/dist/cjs/modules/word/security/cfb-reader.js +414 -0
  382. package/dist/cjs/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
  383. package/dist/cjs/modules/word/security/document-protection.js +208 -0
  384. package/dist/cjs/modules/word/security/encryption.js +612 -0
  385. package/dist/cjs/modules/word/security/policy.js +106 -0
  386. package/dist/cjs/modules/word/template/template-chart.js +170 -0
  387. package/dist/cjs/modules/word/template/template-datasource.js +549 -0
  388. package/dist/cjs/modules/word/template/template-engine.js +1430 -0
  389. package/dist/cjs/modules/word/units.js +44 -14
  390. package/dist/cjs/modules/word/{writers → writer}/chart-writer.js +163 -22
  391. package/dist/cjs/modules/word/writer/checkbox-writer.js +82 -0
  392. package/dist/cjs/modules/word/{writers → writer}/comment-writer.js +8 -6
  393. package/dist/cjs/modules/word/writer/common-parts.js +104 -0
  394. package/dist/cjs/modules/word/{content-types.js → writer/content-types.js} +14 -6
  395. package/dist/cjs/modules/word/writer/document-writer.js +478 -0
  396. package/dist/cjs/modules/word/writer/docx-packager.js +1551 -0
  397. package/dist/cjs/modules/word/{writers → writer}/footnote-writer.js +13 -10
  398. package/dist/cjs/modules/word/{writers → writer}/header-footer-writer.js +38 -20
  399. package/dist/cjs/modules/word/{writers → writer}/image-writer.js +11 -7
  400. package/dist/cjs/modules/word/{writers → writer}/math-writer.js +21 -1
  401. package/dist/cjs/modules/word/{writers → writer}/numbering-writer.js +11 -4
  402. package/dist/cjs/modules/word/{writers → writer}/paragraph-writer.js +72 -37
  403. package/dist/cjs/modules/word/{writers → writer}/parts-writer.js +91 -12
  404. package/dist/cjs/modules/word/writer/reference-scanners.js +120 -0
  405. package/dist/cjs/modules/word/writer/relationships.js +124 -0
  406. package/dist/cjs/modules/word/writer/render-context.js +51 -0
  407. package/dist/cjs/modules/word/{writers → writer}/run-writer.js +127 -24
  408. package/dist/cjs/modules/word/writer/sdt-writer.js +192 -0
  409. package/dist/cjs/modules/word/writer/stream-buf.js +76 -0
  410. package/dist/cjs/modules/word/writer/streaming-writer.js +1387 -0
  411. package/dist/cjs/modules/word/writer/string-buf.js +11 -0
  412. package/dist/cjs/modules/word/{writers → writer}/styles-writer.js +32 -1
  413. package/dist/cjs/modules/word/{writers → writer}/table-writer.js +94 -11
  414. package/dist/cjs/utils/crypto.browser.js +3 -1
  415. package/dist/cjs/utils/crypto.js +4 -1
  416. package/dist/cjs/utils/font-metrics.js +303 -0
  417. package/dist/cjs/utils/string-buf.js +92 -0
  418. package/dist/cjs/utils/theme-colors.js +126 -0
  419. package/dist/esm/modules/archive/compression/streaming-compress.browser.js +29 -0
  420. package/dist/esm/modules/archive/compression/streaming-compress.js +9 -0
  421. package/dist/esm/modules/archive/compression/worker-pool/pool.browser.js +26 -1
  422. package/dist/esm/modules/archive/fs/archive-file.js +78 -16
  423. package/dist/esm/modules/archive/unzip/stream.browser.js +43 -2
  424. package/dist/esm/modules/excel/chart/chart-ex-builder.js +7 -2
  425. package/dist/esm/modules/excel/chart/chart-ex-renderer.js +4 -9
  426. package/dist/esm/modules/excel/chart/chart.js +1 -7
  427. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +25 -1
  428. package/dist/esm/modules/excel/stream/workbook-reader.js +9 -0
  429. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +228 -13
  430. package/dist/esm/modules/excel/utils/string-buf.js +4 -81
  431. package/dist/esm/modules/excel/workbook.browser.js +135 -25
  432. package/dist/esm/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
  433. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +32 -8
  434. package/dist/esm/modules/excel/xlsx/xlsx.js +9 -1
  435. package/dist/esm/modules/pdf/excel-bridge.js +32 -0
  436. package/dist/esm/modules/pdf/font/metrics.js +3 -237
  437. package/dist/esm/modules/pdf/index.js +1 -1
  438. package/dist/esm/modules/pdf/render-layout-to-pdf.js +647 -0
  439. package/dist/esm/modules/pdf/word-bridge.js +122 -274
  440. package/dist/esm/modules/stream/index.base.js +2 -1
  441. package/dist/esm/modules/stream/internal/sink-adapter.js +198 -0
  442. package/dist/esm/modules/stream/pull-stream.js +51 -5
  443. package/dist/esm/modules/word/advanced/diff.js +167 -0
  444. package/dist/esm/modules/word/advanced/drawing-shapes.js +268 -0
  445. package/dist/esm/modules/word/advanced/field-engine.js +1225 -0
  446. package/dist/esm/modules/word/advanced/glossary.js +79 -0
  447. package/dist/esm/modules/word/advanced/math-convert.js +595 -0
  448. package/dist/esm/modules/word/advanced/ole-objects.js +271 -0
  449. package/dist/esm/modules/word/advanced/style-map.js +322 -0
  450. package/dist/esm/modules/word/advanced/validation.js +1065 -0
  451. package/dist/esm/modules/word/advanced/vba-project.js +265 -0
  452. package/dist/esm/modules/word/bridge/excel-bridge.js +980 -0
  453. package/dist/esm/modules/word/builder/document-handle.js +664 -0
  454. package/dist/esm/modules/word/builder/paragraph-builders.js +90 -0
  455. package/dist/esm/modules/word/builder/run-builders.js +600 -0
  456. package/dist/esm/modules/word/builder/table-builders.js +45 -0
  457. package/dist/esm/modules/word/constants.js +109 -1
  458. package/dist/esm/modules/word/convert/conversion-ir.js +31 -0
  459. package/dist/esm/modules/word/convert/docx-to-semantic.js +499 -0
  460. package/dist/esm/modules/word/convert/flat-opc.js +385 -0
  461. package/dist/esm/modules/word/convert/html/html-import.js +1907 -0
  462. package/dist/{browser/modules/word → esm/modules/word/convert/html}/html-renderer.js +420 -69
  463. package/dist/esm/modules/word/convert/html/html.js +15 -0
  464. package/dist/esm/modules/word/convert/markdown/markdown-import.js +1325 -0
  465. package/dist/esm/modules/word/convert/markdown/markdown-renderer.js +634 -0
  466. package/dist/esm/modules/word/convert/markdown/markdown.js +15 -0
  467. package/dist/esm/modules/word/convert/odt/odt.js +1932 -0
  468. package/dist/esm/modules/word/core/color-utils.js +43 -0
  469. package/dist/esm/modules/word/core/internal-utils.js +209 -0
  470. package/dist/esm/modules/word/core/mapper.js +427 -0
  471. package/dist/esm/modules/word/core/opc-paths.js +48 -0
  472. package/dist/esm/modules/word/core/text-utils.js +202 -0
  473. package/dist/esm/modules/word/core/walker.js +570 -0
  474. package/dist/esm/modules/word/crypto.js +13 -7
  475. package/dist/esm/modules/word/document-io.js +80 -197
  476. package/dist/esm/modules/word/errors.js +54 -2
  477. package/dist/esm/modules/word/excel.js +13 -0
  478. package/dist/esm/modules/word/font/font-embed.js +646 -0
  479. package/dist/{browser/modules/word → esm/modules/word/font}/font-obfuscation.js +4 -9
  480. package/dist/esm/modules/word/font/hyphenation.js +4210 -0
  481. package/dist/esm/modules/word/font/text-shaping.js +635 -0
  482. package/dist/esm/modules/word/html.js +6 -5
  483. package/dist/esm/modules/word/incremental-edit.js +361 -0
  484. package/dist/esm/modules/word/index.base.js +138 -29
  485. package/dist/esm/modules/word/layout/layout-constants.js +17 -0
  486. package/dist/esm/modules/word/layout/layout-full.js +1696 -0
  487. package/dist/esm/modules/word/layout/layout-model.js +16 -0
  488. package/dist/esm/modules/word/layout/layout.js +1167 -0
  489. package/dist/esm/modules/word/layout/render-page.js +1238 -0
  490. package/dist/esm/modules/word/markdown.js +13 -0
  491. package/dist/esm/modules/word/patcher.js +537 -0
  492. package/dist/esm/modules/word/query/compat.js +58 -0
  493. package/dist/esm/modules/word/query/data-binding.js +392 -0
  494. package/dist/esm/modules/word/query/form-fields.js +268 -0
  495. package/dist/esm/modules/word/query/format-search.js +329 -0
  496. package/dist/esm/modules/word/query/mail-merge.js +111 -0
  497. package/dist/esm/modules/word/query/merge.js +617 -0
  498. package/dist/esm/modules/word/query/replace.js +301 -0
  499. package/dist/esm/modules/word/query/revisions.js +879 -0
  500. package/dist/esm/modules/word/query/search.js +346 -0
  501. package/dist/esm/modules/word/query/split.js +135 -0
  502. package/dist/esm/modules/word/query/style-resolve.js +368 -0
  503. package/dist/esm/modules/word/reader/chart-parser.js +810 -0
  504. package/dist/esm/modules/word/reader/comments-parser.js +92 -0
  505. package/dist/esm/modules/word/reader/doc-props-parsers.js +190 -0
  506. package/dist/esm/modules/word/reader/docx-reader.js +2557 -0
  507. package/dist/esm/modules/word/reader/drawing-helpers.js +84 -0
  508. package/dist/esm/modules/word/reader/form-field-parser.js +82 -0
  509. package/dist/esm/modules/word/reader/image-parsers.js +291 -0
  510. package/dist/esm/modules/word/reader/math-parser.js +422 -0
  511. package/dist/esm/modules/word/reader/metadata-parsers.js +87 -0
  512. package/dist/esm/modules/word/reader/numbering-parser.js +166 -0
  513. package/dist/esm/modules/word/reader/paragraph-section-parsers.js +503 -0
  514. package/dist/esm/modules/word/reader/parse-utils.js +249 -0
  515. package/dist/esm/modules/word/reader/properties-parsers.js +332 -0
  516. package/dist/esm/modules/word/reader/reader-context.js +61 -0
  517. package/dist/esm/modules/word/reader/sdt-helpers.js +111 -0
  518. package/dist/esm/modules/word/reader/settings-parser.js +263 -0
  519. package/dist/esm/modules/word/reader/styles-parser.js +147 -0
  520. package/dist/esm/modules/word/reader/table-properties-parsers.js +234 -0
  521. package/dist/esm/modules/word/reader/theme-parser.js +167 -0
  522. package/dist/esm/modules/word/reader/watermark-parser.js +110 -0
  523. package/dist/esm/modules/word/security/cfb-reader.js +410 -0
  524. package/dist/esm/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
  525. package/dist/esm/modules/word/security/document-protection.js +201 -0
  526. package/dist/esm/modules/word/security/encryption.js +602 -0
  527. package/dist/esm/modules/word/security/policy.js +102 -0
  528. package/dist/esm/modules/word/template/template-chart.js +167 -0
  529. package/dist/esm/modules/word/template/template-datasource.js +541 -0
  530. package/dist/esm/modules/word/template/template-engine.js +1435 -0
  531. package/dist/esm/modules/word/units.js +43 -14
  532. package/dist/esm/modules/word/{writers → writer}/chart-writer.js +164 -23
  533. package/dist/esm/modules/word/writer/checkbox-writer.js +79 -0
  534. package/dist/esm/modules/word/{writers → writer}/comment-writer.js +8 -6
  535. package/dist/esm/modules/word/writer/common-parts.js +101 -0
  536. package/dist/{browser/modules/word → esm/modules/word/writer}/content-types.js +14 -6
  537. package/dist/esm/modules/word/writer/document-writer.js +473 -0
  538. package/dist/esm/modules/word/writer/docx-packager.js +1515 -0
  539. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/footnote-writer.js +13 -10
  540. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/header-footer-writer.js +39 -21
  541. package/dist/esm/modules/word/{writers → writer}/image-writer.js +11 -7
  542. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/math-writer.js +21 -1
  543. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/numbering-writer.js +11 -4
  544. package/dist/esm/modules/word/{writers → writer}/paragraph-writer.js +73 -38
  545. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/parts-writer.js +91 -12
  546. package/dist/esm/modules/word/writer/reference-scanners.js +111 -0
  547. package/dist/esm/modules/word/writer/relationships.js +117 -0
  548. package/dist/esm/modules/word/writer/render-context.js +46 -0
  549. package/dist/{browser/modules/word/writers → esm/modules/word/writer}/run-writer.js +126 -24
  550. package/dist/esm/modules/word/writer/sdt-writer.js +189 -0
  551. package/dist/esm/modules/word/writer/stream-buf.js +73 -0
  552. package/dist/esm/modules/word/writer/streaming-writer.js +1382 -0
  553. package/dist/esm/modules/word/writer/string-buf.js +7 -0
  554. package/dist/esm/modules/word/{writers → writer}/styles-writer.js +32 -1
  555. package/dist/esm/modules/word/{writers → writer}/table-writer.js +94 -11
  556. package/dist/esm/utils/crypto.browser.js +3 -1
  557. package/dist/esm/utils/crypto.js +4 -1
  558. package/dist/esm/utils/font-metrics.js +293 -0
  559. package/dist/esm/utils/string-buf.js +89 -0
  560. package/dist/esm/utils/theme-colors.js +120 -0
  561. package/dist/iife/excelts.iife.js +70692 -70337
  562. package/dist/iife/excelts.iife.js.map +1 -1
  563. package/dist/iife/excelts.iife.min.js +57 -57
  564. package/dist/types/modules/archive/fs/archive-file.d.ts +8 -5
  565. package/dist/types/modules/excel/chart/chart-ex-types.d.ts +0 -12
  566. package/dist/types/modules/excel/chart/chart.d.ts +1 -5
  567. package/dist/types/modules/excel/chart/types.d.ts +0 -6
  568. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +40 -0
  569. package/dist/types/modules/excel/utils/string-buf.d.ts +5 -26
  570. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +19 -9
  571. package/dist/types/modules/excel/xlsx/xlsx.d.ts +10 -2
  572. package/dist/types/modules/pdf/excel-bridge.d.ts +30 -1
  573. package/dist/types/modules/pdf/font/metrics.d.ts +3 -52
  574. package/dist/types/modules/pdf/index.d.ts +1 -1
  575. package/dist/types/modules/pdf/render-layout-to-pdf.d.ts +66 -0
  576. package/dist/types/modules/pdf/word-bridge.d.ts +80 -12
  577. package/dist/types/modules/stream/index.base.d.ts +2 -0
  578. package/dist/types/modules/stream/internal/sink-adapter.d.ts +65 -0
  579. package/dist/types/modules/stream/pull-stream.d.ts +19 -2
  580. package/dist/types/modules/stream/types.d.ts +13 -1
  581. package/dist/types/modules/word/advanced/diff.d.ts +61 -0
  582. package/dist/types/modules/word/advanced/drawing-shapes.d.ts +269 -0
  583. package/dist/types/modules/word/advanced/field-engine.d.ts +43 -0
  584. package/dist/types/modules/word/advanced/glossary.d.ts +86 -0
  585. package/dist/types/modules/word/advanced/math-convert.d.ts +30 -0
  586. package/dist/types/modules/word/advanced/ole-objects.d.ts +115 -0
  587. package/dist/types/modules/word/advanced/style-map.d.ts +105 -0
  588. package/dist/types/modules/word/advanced/validation.d.ts +56 -0
  589. package/dist/types/modules/word/advanced/vba-project.d.ts +91 -0
  590. package/dist/types/modules/word/bridge/excel-bridge.d.ts +127 -0
  591. package/dist/types/modules/word/builder/document-handle.d.ts +151 -0
  592. package/dist/types/modules/word/builder/paragraph-builders.d.ts +61 -0
  593. package/dist/types/modules/word/builder/run-builders.d.ts +374 -0
  594. package/dist/types/modules/word/builder/table-builders.d.ts +23 -0
  595. package/dist/types/modules/word/constants.d.ts +39 -1
  596. package/dist/types/modules/word/convert/conversion-ir.d.ts +210 -0
  597. package/dist/types/modules/word/convert/docx-to-semantic.d.ts +39 -0
  598. package/dist/types/modules/word/convert/flat-opc.d.ts +44 -0
  599. package/dist/types/modules/word/convert/html/html-import.d.ts +50 -0
  600. package/dist/{browser/modules/word → types/modules/word/convert/html}/html-renderer.d.ts +14 -1
  601. package/dist/types/modules/word/convert/html/html.d.ts +15 -0
  602. package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +68 -0
  603. package/dist/types/modules/word/convert/markdown/markdown-renderer.d.ts +25 -0
  604. package/dist/types/modules/word/convert/markdown/markdown.d.ts +15 -0
  605. package/dist/types/modules/word/convert/odt/odt.d.ts +41 -0
  606. package/dist/types/modules/word/{color-utils.d.ts → core/color-utils.d.ts} +8 -1
  607. package/dist/types/modules/word/core/internal-utils.d.ts +90 -0
  608. package/dist/types/modules/word/core/mapper.d.ts +44 -0
  609. package/dist/types/modules/word/core/opc-paths.d.ts +33 -0
  610. package/dist/types/modules/word/core/text-utils.d.ts +38 -0
  611. package/dist/types/modules/word/core/walker.d.ts +119 -0
  612. package/dist/types/modules/word/crypto.d.ts +14 -9
  613. package/dist/types/modules/word/document-io.d.ts +59 -27
  614. package/dist/types/modules/word/errors.d.ts +44 -1
  615. package/dist/types/modules/word/excel.d.ts +14 -0
  616. package/dist/types/modules/word/font/font-embed.d.ts +112 -0
  617. package/dist/types/modules/word/font/hyphenation.d.ts +65 -0
  618. package/dist/types/modules/word/font/text-shaping.d.ts +58 -0
  619. package/dist/types/modules/word/html.d.ts +7 -6
  620. package/dist/types/modules/word/incremental-edit.d.ts +123 -0
  621. package/dist/types/modules/word/index.base.d.ts +194 -10
  622. package/dist/types/modules/word/layout/layout-constants.d.ts +17 -0
  623. package/dist/types/modules/word/layout/layout-full.d.ts +53 -0
  624. package/dist/types/modules/word/layout/layout-model.d.ts +344 -0
  625. package/dist/types/modules/word/layout/layout.d.ts +63 -0
  626. package/dist/types/modules/word/layout/render-page.d.ts +57 -0
  627. package/dist/types/modules/word/markdown.d.ts +14 -0
  628. package/dist/types/modules/word/patcher.d.ts +62 -0
  629. package/dist/types/modules/word/query/compat.d.ts +25 -0
  630. package/dist/types/modules/word/query/data-binding.d.ts +22 -0
  631. package/dist/types/modules/word/query/form-fields.d.ts +41 -0
  632. package/dist/types/modules/word/query/format-search.d.ts +99 -0
  633. package/dist/types/modules/word/query/mail-merge.d.ts +25 -0
  634. package/dist/types/modules/word/query/merge.d.ts +50 -0
  635. package/dist/types/modules/word/query/replace.d.ts +47 -0
  636. package/dist/types/modules/word/query/revisions.d.ts +67 -0
  637. package/dist/types/modules/word/query/search.d.ts +129 -0
  638. package/dist/types/modules/word/query/split.d.ts +44 -0
  639. package/dist/types/modules/word/query/style-resolve.d.ts +104 -0
  640. package/dist/types/modules/word/reader/chart-parser.d.ts +20 -0
  641. package/dist/types/modules/word/reader/comments-parser.d.ts +26 -0
  642. package/dist/types/modules/word/reader/doc-props-parsers.d.ts +15 -0
  643. package/dist/types/modules/word/reader/docx-reader.d.ts +27 -0
  644. package/dist/types/modules/word/reader/drawing-helpers.d.ts +27 -0
  645. package/dist/types/modules/word/reader/form-field-parser.d.ts +21 -0
  646. package/dist/types/modules/word/reader/image-parsers.d.ts +11 -0
  647. package/dist/types/modules/word/reader/math-parser.d.ts +12 -0
  648. package/dist/types/modules/word/reader/metadata-parsers.d.ts +17 -0
  649. package/dist/types/modules/word/reader/numbering-parser.d.ts +13 -0
  650. package/dist/types/modules/word/reader/paragraph-section-parsers.d.ts +12 -0
  651. package/dist/types/modules/word/reader/parse-utils.d.ts +91 -0
  652. package/dist/types/modules/word/reader/properties-parsers.d.ts +21 -0
  653. package/dist/types/modules/word/reader/reader-context.d.ts +69 -0
  654. package/dist/types/modules/word/reader/sdt-helpers.d.ts +29 -0
  655. package/dist/types/modules/word/reader/settings-parser.d.ts +8 -0
  656. package/dist/types/modules/word/reader/styles-parser.d.ts +12 -0
  657. package/dist/types/modules/word/reader/table-properties-parsers.d.ts +12 -0
  658. package/dist/types/modules/word/reader/theme-parser.d.ts +8 -0
  659. package/dist/types/modules/word/reader/watermark-parser.d.ts +15 -0
  660. package/dist/types/modules/word/security/cfb-reader.d.ts +37 -0
  661. package/dist/types/modules/word/{digital-signatures.d.ts → security/digital-signatures.d.ts} +19 -11
  662. package/dist/types/modules/word/security/document-protection.d.ts +93 -0
  663. package/dist/{browser/modules/word → types/modules/word/security}/encryption.d.ts +51 -4
  664. package/dist/types/modules/word/security/policy.d.ts +80 -0
  665. package/dist/types/modules/word/template/template-chart.d.ts +56 -0
  666. package/dist/types/modules/word/template/template-datasource.d.ts +154 -0
  667. package/dist/types/modules/word/template/template-engine.d.ts +121 -0
  668. package/dist/types/modules/word/types.d.ts +224 -25
  669. package/dist/types/modules/word/units.d.ts +26 -0
  670. package/dist/types/modules/word/writer/checkbox-writer.d.ts +17 -0
  671. package/dist/{browser/modules/word/writers → types/modules/word/writer}/comment-writer.d.ts +2 -1
  672. package/dist/types/modules/word/writer/common-parts.d.ts +57 -0
  673. package/dist/{browser/modules/word → types/modules/word/writer}/content-types.d.ts +2 -2
  674. package/dist/types/modules/word/writer/document-writer.d.ts +24 -0
  675. package/dist/types/modules/word/writer/docx-packager.d.ts +35 -0
  676. package/dist/{browser/modules/word/writers → types/modules/word/writer}/footnote-writer.d.ts +3 -2
  677. package/dist/{browser/modules/word/writers → types/modules/word/writer}/header-footer-writer.d.ts +3 -2
  678. package/dist/{browser/modules/word/writers → types/modules/word/writer}/image-writer.d.ts +1 -1
  679. package/dist/types/modules/word/writer/math-writer.d.ts +20 -0
  680. package/dist/types/modules/word/{writers → writer}/numbering-writer.d.ts +1 -1
  681. package/dist/types/modules/word/{writers → writer}/paragraph-writer.d.ts +2 -1
  682. package/dist/types/modules/word/{writers → writer}/parts-writer.d.ts +3 -3
  683. package/dist/types/modules/word/writer/reference-scanners.d.ts +42 -0
  684. package/dist/types/modules/word/writer/relationships.d.ts +52 -0
  685. package/dist/types/modules/word/writer/render-context.d.ts +124 -0
  686. package/dist/types/modules/word/{writers → writer}/run-writer.d.ts +10 -1
  687. package/dist/types/modules/word/writer/sdt-writer.d.ts +25 -0
  688. package/dist/types/modules/word/writer/stream-buf.d.ts +37 -0
  689. package/dist/types/modules/word/writer/streaming-writer.d.ts +344 -0
  690. package/dist/types/modules/word/writer/string-buf.d.ts +8 -0
  691. package/dist/types/modules/word/{writers → writer}/table-writer.d.ts +2 -1
  692. package/dist/types/modules/xml/types.d.ts +22 -0
  693. package/dist/types/utils/crypto.browser.d.ts +3 -1
  694. package/dist/types/utils/crypto.d.ts +4 -1
  695. package/dist/types/utils/font-metrics.d.ts +63 -0
  696. package/dist/types/utils/string-buf.d.ts +42 -0
  697. package/dist/types/utils/theme-colors.d.ts +55 -0
  698. package/package.json +121 -39
  699. package/dist/browser/modules/word/color-utils.js +0 -94
  700. package/dist/browser/modules/word/document.d.ts +0 -657
  701. package/dist/browser/modules/word/document.js +0 -1533
  702. package/dist/browser/modules/word/docx-packager.d.ts +0 -14
  703. package/dist/browser/modules/word/docx-packager.js +0 -822
  704. package/dist/browser/modules/word/docx-reader.d.ts +0 -11
  705. package/dist/browser/modules/word/docx-reader.js +0 -4929
  706. package/dist/browser/modules/word/encryption.js +0 -274
  707. package/dist/browser/modules/word/internal-utils.d.ts +0 -23
  708. package/dist/browser/modules/word/internal-utils.js +0 -54
  709. package/dist/browser/modules/word/namespaces.d.ts +0 -159
  710. package/dist/browser/modules/word/namespaces.js +0 -189
  711. package/dist/browser/modules/word/relationships.d.ts +0 -30
  712. package/dist/browser/modules/word/relationships.js +0 -48
  713. package/dist/browser/modules/word/writers/checkbox-writer.d.ts +0 -9
  714. package/dist/browser/modules/word/writers/checkbox-writer.js +0 -42
  715. package/dist/browser/modules/word/writers/document-writer.d.ts +0 -16
  716. package/dist/browser/modules/word/writers/document-writer.js +0 -461
  717. package/dist/browser/modules/word/writers/math-writer.d.ts +0 -9
  718. package/dist/cjs/modules/word/color-utils.js +0 -97
  719. package/dist/cjs/modules/word/document.js +0 -1645
  720. package/dist/cjs/modules/word/docx-packager.js +0 -825
  721. package/dist/cjs/modules/word/docx-reader.js +0 -4932
  722. package/dist/cjs/modules/word/encryption.js +0 -282
  723. package/dist/cjs/modules/word/internal-utils.js +0 -59
  724. package/dist/cjs/modules/word/namespaces.js +0 -192
  725. package/dist/cjs/modules/word/relationships.js +0 -55
  726. package/dist/cjs/modules/word/writers/checkbox-writer.js +0 -45
  727. package/dist/cjs/modules/word/writers/document-writer.js +0 -465
  728. package/dist/esm/modules/word/color-utils.js +0 -94
  729. package/dist/esm/modules/word/document.js +0 -1533
  730. package/dist/esm/modules/word/docx-packager.js +0 -822
  731. package/dist/esm/modules/word/docx-reader.js +0 -4929
  732. package/dist/esm/modules/word/encryption.js +0 -274
  733. package/dist/esm/modules/word/internal-utils.js +0 -54
  734. package/dist/esm/modules/word/namespaces.js +0 -189
  735. package/dist/esm/modules/word/relationships.js +0 -48
  736. package/dist/esm/modules/word/writers/checkbox-writer.js +0 -42
  737. package/dist/esm/modules/word/writers/document-writer.js +0 -461
  738. package/dist/types/modules/word/document.d.ts +0 -657
  739. package/dist/types/modules/word/docx-packager.d.ts +0 -14
  740. package/dist/types/modules/word/docx-reader.d.ts +0 -11
  741. package/dist/types/modules/word/internal-utils.d.ts +0 -23
  742. package/dist/types/modules/word/namespaces.d.ts +0 -159
  743. package/dist/types/modules/word/relationships.d.ts +0 -30
  744. package/dist/types/modules/word/writers/checkbox-writer.d.ts +0 -9
  745. package/dist/types/modules/word/writers/document-writer.d.ts +0 -16
  746. package/dist/types/modules/word/writers/math-writer.d.ts +0 -9
  747. /package/dist/browser/modules/word/{font-obfuscation.d.ts → font/font-obfuscation.d.ts} +0 -0
  748. /package/dist/browser/modules/word/{writers → writer}/chart-writer.d.ts +0 -0
  749. /package/dist/browser/modules/word/{writers → writer}/section-writer.d.ts +0 -0
  750. /package/dist/browser/modules/word/{writers → writer}/section-writer.js +0 -0
  751. /package/dist/browser/modules/word/{writers → writer}/styles-writer.d.ts +0 -0
  752. /package/dist/browser/modules/word/{writers → writer}/textbox-writer.d.ts +0 -0
  753. /package/dist/browser/modules/word/{writers → writer}/textbox-writer.js +0 -0
  754. /package/dist/browser/modules/word/{writers → writer}/toc-writer.d.ts +0 -0
  755. /package/dist/browser/modules/word/{writers → writer}/toc-writer.js +0 -0
  756. /package/dist/cjs/modules/word/{writers → writer}/section-writer.js +0 -0
  757. /package/dist/cjs/modules/word/{writers → writer}/textbox-writer.js +0 -0
  758. /package/dist/cjs/modules/word/{writers → writer}/toc-writer.js +0 -0
  759. /package/dist/esm/modules/word/{writers → writer}/section-writer.js +0 -0
  760. /package/dist/esm/modules/word/{writers → writer}/textbox-writer.js +0 -0
  761. /package/dist/esm/modules/word/{writers → writer}/toc-writer.js +0 -0
  762. /package/dist/types/modules/word/{font-obfuscation.d.ts → font/font-obfuscation.d.ts} +0 -0
  763. /package/dist/types/modules/word/{writers → writer}/chart-writer.d.ts +0 -0
  764. /package/dist/types/modules/word/{writers → writer}/section-writer.d.ts +0 -0
  765. /package/dist/types/modules/word/{writers → writer}/styles-writer.d.ts +0 -0
  766. /package/dist/types/modules/word/{writers → writer}/textbox-writer.d.ts +0 -0
  767. /package/dist/types/modules/word/{writers → writer}/toc-writer.d.ts +0 -0
@@ -0,0 +1,1515 @@
1
+ /**
2
+ * DOCX Module - Packager
3
+ *
4
+ * Assembles a DocxDocument model into a DOCX ZIP package using the
5
+ * archive and XML modules. Supports all parts including comments,
6
+ * custom properties, document background, hyperlink relationships,
7
+ * and per-header/footer relationship files.
8
+ */
9
+ import { zip } from "../../archive/create-archive.js";
10
+ import { XmlWriter } from "../../xml/writer.js";
11
+ import { ContentType, RelType, PartPath, STD_DOC_ATTRIBUTES } from "../constants.js";
12
+ import { sanitizeMediaFileName, sanitizeUrl } from "../core/internal-utils.js";
13
+ import { getFileExt, getPartRelsPath } from "../core/opc-paths.js";
14
+ import { isRun } from "../core/text-utils.js";
15
+ import { walkBlocks } from "../core/walker.js";
16
+ import { DocxWriteError } from "../errors.js";
17
+ import { resolveSecurityPolicy } from "../security/policy.js";
18
+ import { renderChartPart } from "./chart-writer.js";
19
+ import { renderComments, renderCommentsExtended } from "./comment-writer.js";
20
+ import { createContentTypes, addContentTypeDefault, addContentTypeOverride, addImageContentTypeDefaults, renderContentTypes } from "./content-types.js";
21
+ import { renderDocument } from "./document-writer.js";
22
+ import { renderFootnotes, renderEndnotes } from "./footnote-writer.js";
23
+ import { renderHeader, renderFooter, renderWatermarkHeader } from "./header-footer-writer.js";
24
+ import { renderNumbering } from "./numbering-writer.js";
25
+ import { renderSettings, renderFontTable, renderCoreProperties, renderAppProperties, renderCustomProperties, renderWebSettings, renderPeople, renderTheme } from "./parts-writer.js";
26
+ import { collectChartsFromHeaderFooter, collectHyperlinksFromHeaderFooter, collectImageRidsFromContent, scanChildrenForHyperlinks, scanChildrenForImages } from "./reference-scanners.js";
27
+ import { createRelationships, addRelationship, addRelationshipWithId, getRelationshipCount, renderRelationships } from "./relationships.js";
28
+ import { createIdGenerators, createRenderContext } from "./render-context.js";
29
+ import { renderStyles } from "./styles-writer.js";
30
+ /** Render XML to string using XmlWriter. */
31
+ function renderXml(renderFn) {
32
+ const writer = new XmlWriter();
33
+ renderFn(writer);
34
+ return writer.xml;
35
+ }
36
+ /**
37
+ * Walk the document and return the highest `id` used on any
38
+ * `StructuredDocumentTag`. Used to seed the SDT id generator so that
39
+ * auto-assigned ids start strictly above any author-supplied ones — a
40
+ * collision would silently break repeating-section / data-binding linkage
41
+ * because Word matches SDTs by id.
42
+ */
43
+ function scanMaxSdtId(doc) {
44
+ let max = 0;
45
+ const visit = (blocks) => {
46
+ for (const block of blocks) {
47
+ if (block.type === "sdt") {
48
+ const id = block.properties?.id;
49
+ if (typeof id === "number" && Number.isFinite(id) && id > max) {
50
+ max = id;
51
+ }
52
+ // SDT.content is (Paragraph | Run | Table)[]. Recurse into its
53
+ // tables to find nested SDTs.
54
+ for (const c of block.content) {
55
+ if (c.type === "table") {
56
+ visit([c]);
57
+ }
58
+ }
59
+ }
60
+ else if (block.type === "table") {
61
+ for (const row of block.rows) {
62
+ for (const cell of row.cells) {
63
+ visit(cell.content);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ };
69
+ visit(doc.body);
70
+ if (doc.headers) {
71
+ for (const [, h] of doc.headers) {
72
+ visit(h.content.children);
73
+ }
74
+ }
75
+ if (doc.footers) {
76
+ for (const [, f] of doc.footers) {
77
+ visit(f.content.children);
78
+ }
79
+ }
80
+ return max;
81
+ }
82
+ /**
83
+ * Recursively collect hyperlinks with a URL (no `rId` yet) from body content.
84
+ */
85
+ function collectHyperlinks(body) {
86
+ const links = [];
87
+ walkBlocks(body, {
88
+ enterParagraph(p) {
89
+ scanChildrenForHyperlinks(p.children, links);
90
+ }
91
+ });
92
+ return links;
93
+ }
94
+ /** Infer a content type for an opaque part based on its file extension. */
95
+ function inferContentType(ext) {
96
+ const map = {
97
+ xml: "application/xml",
98
+ rels: "application/vnd.openxmlformats-package.relationships+xml",
99
+ png: "image/png",
100
+ jpeg: "image/jpeg",
101
+ jpg: "image/jpeg",
102
+ gif: "image/gif",
103
+ bmp: "image/bmp",
104
+ tiff: "image/tiff",
105
+ tif: "image/tiff",
106
+ svg: "image/svg+xml",
107
+ webp: "image/webp",
108
+ emf: "image/x-emf",
109
+ wmf: "image/x-wmf",
110
+ odttf: "application/vnd.openxmlformats-officedocument.obfuscatedFont",
111
+ ttf: "application/x-font-ttf",
112
+ otf: "application/x-font-otf",
113
+ bin: "application/vnd.openxmlformats-officedocument.oleObject",
114
+ vml: "application/vnd.openxmlformats-officedocument.vmlDrawing"
115
+ };
116
+ return map[ext];
117
+ }
118
+ /** Resolve the main document part content type based on docType. */
119
+ function resolveDocumentContentType(doc) {
120
+ switch (doc.docType) {
121
+ case "template":
122
+ return ContentType.Template;
123
+ case "macroEnabledDocument":
124
+ return ContentType.DocumentMacroEnabled;
125
+ case "macroEnabledTemplate":
126
+ return ContentType.TemplateMacroEnabled;
127
+ default:
128
+ return ContentType.Document;
129
+ }
130
+ }
131
+ /**
132
+ * Package a DocxDocument model into a DOCX ZIP file.
133
+ * Returns the ZIP bytes as Uint8Array.
134
+ *
135
+ * This function does NOT modify the input `doc` object. Internally it creates
136
+ * shallow copies of mutable structures (images, headers, footers, etc.) to
137
+ * assign relationship IDs without polluting the caller's model.
138
+ */
139
+ export async function packageDocx(doc, optionsOrCompressionLevel) {
140
+ const options = typeof optionsOrCompressionLevel === "number"
141
+ ? { compressionLevel: optionsOrCompressionLevel }
142
+ : (optionsOrCompressionLevel ?? {});
143
+ // Create a working copy so we never mutate the caller's doc
144
+ const workDoc = shallowCopyDocForPackaging(doc);
145
+ return _packageDocxInner(workDoc, options);
146
+ }
147
+ /**
148
+ * Create a shallow working copy of the document parts that packageDocx still
149
+ * mutates (header/footer/altChunk/hyperlink rId injection). Binary data
150
+ * (Uint8Array) is shared, not cloned. The image table is intentionally NOT
151
+ * cloned: packaging never rewrites image rIds anymore — collisions are now
152
+ * handled via a render-context remap (see `imageRemap` below).
153
+ */
154
+ function shallowCopyDocForPackaging(doc) {
155
+ // Shallow-copy body so we can wrap floating images / altChunks without
156
+ // touching the caller's array.
157
+ const body = doc.body.map(item => {
158
+ if (item.type === "floatingImage" || item.type === "altChunk") {
159
+ return { ...item };
160
+ }
161
+ return item;
162
+ });
163
+ // Shallow-copy headers/footers maps (their `rId` is still assigned in place
164
+ // for backward compatibility with downstream relationship lookups).
165
+ const headers = doc.headers
166
+ ? new Map(Array.from(doc.headers.entries()).map(([k, v]) => [k, { ...v }]))
167
+ : undefined;
168
+ const footers = doc.footers
169
+ ? new Map(Array.from(doc.footers.entries()).map(([k, v]) => [k, { ...v }]))
170
+ : undefined;
171
+ // Sanitize media/font file names. The fileName attribute eventually
172
+ // becomes a ZIP entry name (`word/media/...`, `word/fonts/...`); a
173
+ // hostile DOCX read in via `readDocx` could carry a fileName like
174
+ // `../../etc/passwd.png`, which without sanitisation would produce a
175
+ // ZIP entry that escapes the package root when consumers naively
176
+ // unpack it (zipslip). Allocate fresh leaf names that are unique
177
+ // within their respective collections so two attacker-supplied names
178
+ // sanitising to the same string don't collide and silently overwrite
179
+ // each other.
180
+ const sanitizeImages = (images) => {
181
+ if (!images || images.length === 0) {
182
+ return images;
183
+ }
184
+ const usedNames = new Set();
185
+ let mutated = false;
186
+ const result = images.map(img => {
187
+ const safe = uniqueSanitizedName(img.fileName, usedNames, "image.bin");
188
+ if (safe !== img.fileName) {
189
+ mutated = true;
190
+ return { ...img, fileName: safe };
191
+ }
192
+ return img;
193
+ });
194
+ return mutated ? result : images;
195
+ };
196
+ const sanitizeFonts = (fonts) => {
197
+ if (!fonts || fonts.length === 0) {
198
+ return fonts;
199
+ }
200
+ const usedNames = new Set();
201
+ let mutated = false;
202
+ const result = fonts.map(ef => {
203
+ const safe = uniqueSanitizedName(ef.fileName, usedNames, "font.bin");
204
+ if (safe !== ef.fileName) {
205
+ mutated = true;
206
+ return { ...ef, fileName: safe };
207
+ }
208
+ return ef;
209
+ });
210
+ return mutated ? result : fonts;
211
+ };
212
+ return {
213
+ ...doc,
214
+ body,
215
+ headers,
216
+ footers,
217
+ images: sanitizeImages(doc.images),
218
+ embeddedFonts: sanitizeFonts(doc.embeddedFonts)
219
+ };
220
+ }
221
+ /**
222
+ * Returns the sanitised leaf name. If the cleaned form would collide
223
+ * with an entry already in `used`, a numeric suffix is appended until
224
+ * unique. The chosen name is added to `used`.
225
+ */
226
+ function uniqueSanitizedName(raw, used, fallback) {
227
+ let candidate = sanitizeMediaFileName(raw, fallback);
228
+ if (used.has(candidate)) {
229
+ const dot = candidate.lastIndexOf(".");
230
+ const stem = dot >= 0 ? candidate.slice(0, dot) : candidate;
231
+ const ext = dot >= 0 ? candidate.slice(dot) : "";
232
+ let n = 2;
233
+ while (used.has(`${stem}_${n}${ext}`)) {
234
+ n++;
235
+ }
236
+ candidate = `${stem}_${n}${ext}`;
237
+ }
238
+ used.add(candidate);
239
+ return candidate;
240
+ }
241
+ async function _packageDocxInner(doc, options) {
242
+ const archive = zip({ level: options.compressionLevel ?? 6 });
243
+ const securityPolicy = resolveSecurityPolicy(options.securityPolicy);
244
+ const rawXmlPolicy = securityPolicy.rawXmlPolicy;
245
+ // Managers
246
+ const contentTypes = createContentTypes();
247
+ const packageRels = createRelationships();
248
+ const documentRels = createRelationships();
249
+ // --- Package relationships ---
250
+ addRelationship(packageRels, RelType.OfficeDocument, "word/document.xml");
251
+ addRelationship(packageRels, RelType.CoreProperties, "docProps/core.xml");
252
+ addRelationship(packageRels, RelType.ExtendedProperties, "docProps/app.xml");
253
+ // Custom properties
254
+ const hasCustomProps = doc.customProperties && doc.customProperties.length > 0;
255
+ if (hasCustomProps) {
256
+ addRelationship(packageRels, RelType.CustomProperties, "docProps/custom.xml");
257
+ }
258
+ // --- Document relationships ---
259
+ addRelationship(documentRels, RelType.Styles, "styles.xml");
260
+ addRelationship(documentRels, RelType.Settings, "settings.xml");
261
+ addRelationship(documentRels, RelType.FontTable, "fontTable.xml");
262
+ addRelationship(documentRels, RelType.Theme, "theme/theme1.xml");
263
+ // Numbering
264
+ const hasNumbering = (doc.abstractNumberings && doc.abstractNumberings.length > 0) ||
265
+ (doc.numberingInstances && doc.numberingInstances.length > 0);
266
+ if (hasNumbering) {
267
+ addRelationship(documentRels, RelType.Numbering, "numbering.xml");
268
+ }
269
+ // Footnotes & Endnotes
270
+ const hasFootnotes = doc.footnotes && doc.footnotes.length > 0;
271
+ const hasEndnotes = doc.endnotes && doc.endnotes.length > 0;
272
+ if (hasFootnotes) {
273
+ addRelationship(documentRels, RelType.Footnotes, "footnotes.xml");
274
+ }
275
+ if (hasEndnotes) {
276
+ addRelationship(documentRels, RelType.Endnotes, "endnotes.xml");
277
+ }
278
+ // Comments
279
+ const hasComments = doc.comments && doc.comments.length > 0;
280
+ if (hasComments) {
281
+ addRelationship(documentRels, RelType.Comments, "comments.xml");
282
+ }
283
+ // Images
284
+ //
285
+ // The model's `image.rId` is the authoritative reference: it is what every
286
+ // inline/floating drawing in the body uses, so the easiest way to keep
287
+ // r:embed and the .rels file in sync is to register relationships under that
288
+ // exact id. If a model rId happens to clash with a previously-registered
289
+ // relationship in this same .rels file (e.g. styles → "rId1" while a model
290
+ // image also asks for "rId1"), we fall back to allocating a fresh rId and
291
+ // record the substitution in `imageRemap`. Writers consult that map via
292
+ // ctx.imageRIdRemap when emitting r:embed so the body and the .rels file
293
+ // stay consistent.
294
+ //
295
+ // For SVG with raster fallback, the model rId points at the PNG fallback
296
+ // resource (so r:embed on a:blip targets a raster image — the legacy wire
297
+ // shape Word readers expect). We additionally register the SVG itself
298
+ // under a secondary rId. We then surface that secondary rId on the
299
+ // inline/floating image's `svgRId` field — but only on shallow copies that
300
+ // live inside the work doc, so the caller's input model is never mutated.
301
+ const imageExtensions = new Set();
302
+ const imageRemap = new Map(); // model rId -> registered rId (only set on collision)
303
+ const imageByRid = new Map(); // model rId -> ImageDef
304
+ const svgFallbacks = [];
305
+ // For each main image rId that has a SVG fallback, the secondary rId
306
+ // pointing at the SVG file. Used to populate svgRId on inline/floating
307
+ // image content when the source model didn't already provide one.
308
+ const imageSvgRIdMap = new Map();
309
+ if (doc.images) {
310
+ for (const img of doc.images) {
311
+ if (img.rId) {
312
+ imageByRid.set(img.rId, img);
313
+ }
314
+ // Index alias rIds so that header/footer-local references resolve to
315
+ // the same ImageDef. Aliases live in their own .rels id space, so when
316
+ // we register them later we use the alias rId verbatim.
317
+ if (img.aliasRIds) {
318
+ for (const alias of img.aliasRIds) {
319
+ if (!imageByRid.has(alias)) {
320
+ imageByRid.set(alias, img);
321
+ }
322
+ }
323
+ }
324
+ }
325
+ const registerImageRel = (modelRId, target) => {
326
+ if (!modelRId) {
327
+ return addRelationship(documentRels, RelType.Image, target);
328
+ }
329
+ // OOXML / OPC permits any xs:ID as a Relationship Id, but
330
+ // Microsoft Word enforces the conventional `rId<N>` shape and
331
+ // rejects the package when it encounters anything else (e.g. the
332
+ // `__img_<N>` placeholders our builders emit). Allocate a fresh
333
+ // canonical rId whenever the model id departs from that pattern,
334
+ // and remap content references through `imageRIdRemap`.
335
+ const isCanonicalRId = /^rId\d+$/.test(modelRId);
336
+ if (!isCanonicalRId || documentRels.hasId(modelRId)) {
337
+ const newId = addRelationship(documentRels, RelType.Image, target);
338
+ imageRemap.set(modelRId, newId);
339
+ return newId;
340
+ }
341
+ addRelationshipWithId(documentRels, modelRId, RelType.Image, target);
342
+ return modelRId;
343
+ };
344
+ for (const img of doc.images) {
345
+ const oldRid = img.rId;
346
+ if (img.mediaType === "svg" && img.fallbackData) {
347
+ // Main rId points at the PNG fallback (the raster image consumed by
348
+ // a:blip).
349
+ const baseName = img.fileName.replace(/\.[^.]+$/, "");
350
+ const fallbackFileName = `${baseName}_fallback.png`;
351
+ registerImageRel(oldRid, `media/${fallbackFileName}`);
352
+ imageExtensions.add("png");
353
+ // Secondary rId for the actual SVG; auto-allocated.
354
+ const svgRId = addRelationship(documentRels, RelType.Image, `media/${img.fileName}`);
355
+ if (oldRid) {
356
+ imageSvgRIdMap.set(oldRid, svgRId);
357
+ }
358
+ const ext = getFileExt(img.fileName);
359
+ if (ext) {
360
+ imageExtensions.add(ext);
361
+ }
362
+ svgFallbacks.push({ fallbackFileName, data: img.fallbackData });
363
+ }
364
+ else {
365
+ registerImageRel(oldRid, `media/${img.fileName}`);
366
+ const ext = getFileExt(img.fileName);
367
+ if (ext) {
368
+ imageExtensions.add(ext);
369
+ }
370
+ }
371
+ }
372
+ }
373
+ // Populate svgRId on inline/floating image content nodes for SVG fallbacks.
374
+ // We only mutate shallow copies inside the working doc — never the caller's
375
+ // input. This is invisible to readers that already supplied svgRId.
376
+ if (imageSvgRIdMap.size > 0) {
377
+ const populateSvg = (target) => {
378
+ if (target.svgRId) {
379
+ return;
380
+ }
381
+ const svgRId = imageSvgRIdMap.get(target.rId);
382
+ if (svgRId) {
383
+ target.svgRId = svgRId;
384
+ }
385
+ };
386
+ // Walk the work-doc body. Floating images and altChunks were shallow-copied
387
+ // by shallowCopyDocForPackaging; for paragraphs we lazily clone the run
388
+ // content nodes that carry inline SVG references.
389
+ const processBody = (blocks) => {
390
+ return blocks.map(block => {
391
+ if (block.type === "floatingImage") {
392
+ if (imageSvgRIdMap.has(block.rId)) {
393
+ populateSvg(block);
394
+ }
395
+ return block;
396
+ }
397
+ if (block.type === "paragraph") {
398
+ let paragraphCopied = null;
399
+ let childrenCopied = null;
400
+ for (let i = 0; i < block.children.length; i++) {
401
+ const child = block.children[i];
402
+ if (!isRun(child)) {
403
+ continue;
404
+ }
405
+ const run = child;
406
+ let runCopied = null;
407
+ let contentCopied = null;
408
+ for (let j = 0; j < run.content.length; j++) {
409
+ const c = run.content[j];
410
+ if (c.type !== "image" || !c.rId) {
411
+ continue;
412
+ }
413
+ if (!imageSvgRIdMap.has(c.rId) || c.svgRId) {
414
+ continue;
415
+ }
416
+ if (!contentCopied) {
417
+ contentCopied = [...run.content];
418
+ }
419
+ const cloned = { ...c };
420
+ populateSvg(cloned);
421
+ contentCopied[j] = cloned;
422
+ }
423
+ if (contentCopied) {
424
+ runCopied = { ...run, content: contentCopied };
425
+ if (!childrenCopied) {
426
+ childrenCopied = [...block.children];
427
+ }
428
+ childrenCopied[i] = runCopied;
429
+ }
430
+ }
431
+ if (childrenCopied) {
432
+ paragraphCopied = { ...block, children: childrenCopied };
433
+ return paragraphCopied;
434
+ }
435
+ return block;
436
+ }
437
+ if (block.type === "table") {
438
+ const newRows = block.rows.map(row => ({
439
+ ...row,
440
+ cells: row.cells.map(cell => ({
441
+ ...cell,
442
+ content: processBody(cell.content)
443
+ }))
444
+ }));
445
+ return { ...block, rows: newRows };
446
+ }
447
+ return block;
448
+ });
449
+ };
450
+ doc.body = processBody(doc.body);
451
+ // Same treatment for header/footer content (each is essentially a body
452
+ // fragment). headers/footers maps were shallow-copied by
453
+ // shallowCopyDocForPackaging, so swapping `content.children` is safe.
454
+ const rewriteHeaderFooter = (defs) => {
455
+ if (!defs) {
456
+ return;
457
+ }
458
+ for (const [, def] of defs) {
459
+ const newChildren = processBody(def.content.children);
460
+ if (newChildren !== def.content.children) {
461
+ def.content = {
462
+ ...def.content,
463
+ children: newChildren
464
+ };
465
+ }
466
+ }
467
+ };
468
+ rewriteHeaderFooter(doc.headers);
469
+ rewriteHeaderFooter(doc.footers);
470
+ // Footnotes and endnotes carry their own paragraph lists.
471
+ const rewriteNotes = (notes) => {
472
+ if (!notes || notes.length === 0) {
473
+ return notes;
474
+ }
475
+ let changed = false;
476
+ const out = notes.map(note => {
477
+ const newContent = processBody(note.content);
478
+ if (newContent === note.content) {
479
+ return note;
480
+ }
481
+ changed = true;
482
+ return { ...note, content: newContent };
483
+ });
484
+ return changed ? out : notes;
485
+ };
486
+ const newFootnotes = rewriteNotes(doc.footnotes);
487
+ if (newFootnotes !== doc.footnotes) {
488
+ doc.footnotes = newFootnotes;
489
+ }
490
+ const newEndnotes = rewriteNotes(doc.endnotes);
491
+ if (newEndnotes !== doc.endnotes) {
492
+ doc.endnotes = newEndnotes;
493
+ }
494
+ }
495
+ // Hyperlinks (external).
496
+ // We register relationships under the model's existing rId where possible,
497
+ // and stash newly-allocated rIds on a WeakMap keyed by the Hyperlink object
498
+ // so the renderer can look them up without us writing onto the caller's
499
+ // model. The map lives on the render context.
500
+ //
501
+ // Body, footnotes, endnotes, headers and footers each render against a
502
+ // *different* OPC part, so each part has its own .rels namespace. Using one
503
+ // WeakMap is fine because Hyperlink objects are unique by identity, but the
504
+ // **registration** has to happen against the correct rel manager — we register
505
+ // body hyperlinks into documentRels here, and footnote/endnote/header/footer
506
+ // hyperlinks into their own rel managers below.
507
+ const hyperlinkRIds = new WeakMap();
508
+ const hyperlinks = collectHyperlinks(doc.body);
509
+ for (const link of hyperlinks) {
510
+ if (link.url) {
511
+ // Sanitize: drop dangerous schemes (javascript:, vbscript:, data:, …)
512
+ // before they reach document.xml.rels. The renderer will simply emit
513
+ // the surrounding `<w:hyperlink>` without an `r:id`, which keeps the
514
+ // inner runs but does not produce a clickable target.
515
+ const safe = sanitizeUrl(link.url);
516
+ if (!safe) {
517
+ continue;
518
+ }
519
+ const rId = addRelationship(documentRels, RelType.Hyperlink, safe, "External");
520
+ hyperlinkRIds.set(link, rId);
521
+ }
522
+ }
523
+ // Footnotes/endnotes have independent .rels parts. Build them lazily so we
524
+ // only emit a footnotes.xml.rels file when there's something to register.
525
+ const footnoteRels = createRelationships();
526
+ const endnoteRels = createRelationships();
527
+ const registerNoteHyperlinks = (notes, rels) => {
528
+ if (!notes) {
529
+ return;
530
+ }
531
+ for (const note of notes) {
532
+ const links = [];
533
+ for (const p of note.content) {
534
+ scanChildrenForHyperlinks(p.children, links);
535
+ }
536
+ for (const link of links) {
537
+ if (link.url) {
538
+ const safe = sanitizeUrl(link.url);
539
+ if (!safe) {
540
+ continue;
541
+ }
542
+ const rId = addRelationship(rels, RelType.Hyperlink, safe, "External");
543
+ hyperlinkRIds.set(link, rId);
544
+ }
545
+ }
546
+ }
547
+ };
548
+ registerNoteHyperlinks(doc.footnotes, footnoteRels);
549
+ registerNoteHyperlinks(doc.endnotes, endnoteRels);
550
+ // Footnotes/endnotes may also reference images. Register those references
551
+ // using the same model rId that the run content emits so footnotes.xml's
552
+ // r:embed resolves locally.
553
+ const registerNoteImages = (notes, rels) => {
554
+ if (!notes || !doc.images) {
555
+ return;
556
+ }
557
+ const seen = new Set();
558
+ for (const note of notes) {
559
+ for (const p of note.content) {
560
+ const rIds = new Set();
561
+ scanChildrenForImages(p.children, rIds);
562
+ for (const oldRid of rIds) {
563
+ if (seen.has(oldRid)) {
564
+ continue;
565
+ }
566
+ seen.add(oldRid);
567
+ const img = imageByRid.get(oldRid);
568
+ if (img) {
569
+ addRelationshipWithId(rels, oldRid, RelType.Image, `media/${img.fileName}`);
570
+ // SVG fallback: also register the secondary svg rId locally if the
571
+ // model knows it (or if we allocated it). For notes we look up the
572
+ // already-allocated svgRId from imageSvgRIdMap if present.
573
+ const svgRId = imageSvgRIdMap.get(oldRid);
574
+ if (svgRId && !rels.hasId(svgRId)) {
575
+ addRelationshipWithId(rels, svgRId, RelType.Image, `media/${img.fileName}`);
576
+ }
577
+ }
578
+ }
579
+ }
580
+ }
581
+ };
582
+ registerNoteImages(doc.footnotes, footnoteRels);
583
+ registerNoteImages(doc.endnotes, endnoteRels);
584
+ // Comments have their own .rels part (word/_rels/comments.xml.rels).
585
+ // Hyperlinks/images referenced from inside comment content must register
586
+ // here, not in document.xml.rels — otherwise readers can't resolve them.
587
+ const commentRels = createRelationships();
588
+ if (doc.comments && doc.comments.length > 0) {
589
+ const commentBodies = doc.comments.map(c => ({ content: c.content }));
590
+ registerNoteHyperlinks(commentBodies, commentRels);
591
+ registerNoteImages(commentBodies, commentRels);
592
+ }
593
+ // Process altChunk body items: register relationship and prepare data part.
594
+ // We never mutate the chunk objects — the rId is published via a WeakMap
595
+ // that the renderer reads through the WordRenderContext. This matters for
596
+ // altChunks nested inside tables / SDTs which the shallow body copy did
597
+ // not (and intentionally cannot cheaply) clone.
598
+ const altChunkRIds = new WeakMap();
599
+ const altChunks = [];
600
+ collectAltChunks(doc.body, altChunks);
601
+ altChunks.forEach((chunk, i) => {
602
+ const fileName = chunk.fileName ?? `afchunk${i + 1}.html`;
603
+ // Register relationship for the alt chunk
604
+ const rId = addRelationship(documentRels, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk", fileName);
605
+ altChunkRIds.set(chunk, rId);
606
+ // Register content type
607
+ const ct = chunk.contentType ?? "text/html";
608
+ addContentTypeOverride(contentTypes, `/word/${fileName}`, ct);
609
+ // Write data to archive
610
+ if (chunk.data) {
611
+ archive.add(`word/${fileName}`, chunk.data);
612
+ }
613
+ });
614
+ // Headers
615
+ //
616
+ // For each header in the model we allocate a fresh document-level rId and
617
+ // (re)write the rId on the header definition. Two maps are also produced
618
+ // for later sectionProperties rewiring:
619
+ // - headerKeyToNewRid: keyed by the model's `headers` Map key (typically
620
+ // the original rId from a round-trip, or "default"/"first"/"even" from
621
+ // the builder).
622
+ // - headerOldRidToNewRid: keyed by any rId that previously identified
623
+ // this header (the map key, the value's pre-existing `rId` field) so
624
+ // references that still hold the old rId can be remapped.
625
+ let headerIndex = 1;
626
+ const headerRelManagers = new Map();
627
+ const headerKeyToNewRid = new Map();
628
+ const headerOldRidToNewRid = new Map();
629
+ // Map header `type` ("default" | "first" | "even") to its new rId, if the
630
+ // model only has one header per type. Used to fill in references that
631
+ // were created with a placeholder rId="" by callers that didn't yet know
632
+ // the rId (typical builder usage).
633
+ const headerTypeToNewRid = new Map();
634
+ if (doc.headers) {
635
+ for (const [key, headerDef] of doc.headers) {
636
+ const rId = addRelationship(documentRels, RelType.Header, `header${headerIndex}.xml`);
637
+ const oldRid = headerDef.rId;
638
+ headerDef.rId = rId;
639
+ headerKeyToNewRid.set(key, rId);
640
+ if (key) {
641
+ headerOldRidToNewRid.set(key, rId);
642
+ }
643
+ if (oldRid && oldRid !== rId) {
644
+ headerOldRidToNewRid.set(oldRid, rId);
645
+ }
646
+ // Heuristic: if the map key looks like a header type rather than an
647
+ // rId, also expose it via headerTypeToNewRid so empty-rId references
648
+ // ({ type: "default", rId: "" }) can be resolved by type.
649
+ if (key === "default" || key === "first" || key === "even" || key === "odd") {
650
+ // Last writer wins if the caller provided multiple headers with the
651
+ // same type — that's already an ambiguous model.
652
+ headerTypeToNewRid.set(key, rId);
653
+ }
654
+ // Create per-header relationship state for images and hyperlinks.
655
+ // Header/footer .rels is its own id space, so we register images using
656
+ // the model rId — that's also what the body XML emits via r:embed
657
+ // (header/footer XML never goes through imageRemap because the local
658
+ // .rels is independent from the document .rels).
659
+ const hRels = createRelationships();
660
+ const imgRids = collectImageRidsFromContent(headerDef.content);
661
+ if (imgRids.size > 0 && doc.images) {
662
+ for (const oldRid of imgRids) {
663
+ const img = imageByRid.get(oldRid);
664
+ if (img) {
665
+ addRelationshipWithId(hRels, oldRid, RelType.Image, `media/${img.fileName}`);
666
+ // SVG fallback: register the secondary svg rId locally too so
667
+ // asvg:svgBlip in header XML resolves against this part's .rels.
668
+ const svgRId = imageSvgRIdMap.get(oldRid);
669
+ if (svgRId && !hRels.hasId(svgRId)) {
670
+ addRelationshipWithId(hRels, svgRId, RelType.Image, `media/${img.fileName}`);
671
+ }
672
+ }
673
+ }
674
+ }
675
+ // Hyperlinks in header
676
+ const hLinks = collectHyperlinksFromHeaderFooter(headerDef.content);
677
+ for (const link of hLinks) {
678
+ if (link.url) {
679
+ const safe = sanitizeUrl(link.url);
680
+ if (!safe) {
681
+ continue;
682
+ }
683
+ const linkRId = addRelationship(hRels, RelType.Hyperlink, safe, "External");
684
+ hyperlinkRIds.set(link, linkRId);
685
+ }
686
+ }
687
+ if (getRelationshipCount(hRels) > 0) {
688
+ headerRelManagers.set(key, hRels);
689
+ }
690
+ headerIndex++;
691
+ }
692
+ }
693
+ // Footers
694
+ let footerIndex = 1;
695
+ const footerRelManagers = new Map();
696
+ const footerKeyToNewRid = new Map();
697
+ const footerOldRidToNewRid = new Map();
698
+ const footerTypeToNewRid = new Map();
699
+ if (doc.footers) {
700
+ for (const [key, footerDef] of doc.footers) {
701
+ const rId = addRelationship(documentRels, RelType.Footer, `footer${footerIndex}.xml`);
702
+ const oldRid = footerDef.rId;
703
+ footerDef.rId = rId;
704
+ footerKeyToNewRid.set(key, rId);
705
+ if (key) {
706
+ footerOldRidToNewRid.set(key, rId);
707
+ }
708
+ if (oldRid && oldRid !== rId) {
709
+ footerOldRidToNewRid.set(oldRid, rId);
710
+ }
711
+ if (key === "default" || key === "first" || key === "even" || key === "odd") {
712
+ footerTypeToNewRid.set(key, rId);
713
+ }
714
+ // Create per-footer relationship state for images and hyperlinks.
715
+ const fRels = createRelationships();
716
+ const imgRids = collectImageRidsFromContent(footerDef.content);
717
+ if (imgRids.size > 0 && doc.images) {
718
+ for (const oldRid of imgRids) {
719
+ const img = imageByRid.get(oldRid);
720
+ if (img) {
721
+ addRelationshipWithId(fRels, oldRid, RelType.Image, `media/${img.fileName}`);
722
+ // SVG fallback: register the secondary svg rId locally too.
723
+ const svgRId = imageSvgRIdMap.get(oldRid);
724
+ if (svgRId && !fRels.hasId(svgRId)) {
725
+ addRelationshipWithId(fRels, svgRId, RelType.Image, `media/${img.fileName}`);
726
+ }
727
+ }
728
+ }
729
+ }
730
+ // Hyperlinks in footer
731
+ const fLinks = collectHyperlinksFromHeaderFooter(footerDef.content);
732
+ for (const link of fLinks) {
733
+ if (link.url) {
734
+ const safe = sanitizeUrl(link.url);
735
+ if (!safe) {
736
+ continue;
737
+ }
738
+ const linkRId = addRelationship(fRels, RelType.Hyperlink, safe, "External");
739
+ hyperlinkRIds.set(link, linkRId);
740
+ }
741
+ }
742
+ if (getRelationshipCount(fRels) > 0) {
743
+ footerRelManagers.set(key, fRels);
744
+ }
745
+ footerIndex++;
746
+ }
747
+ }
748
+ // Watermark header (auto-generated if doc.watermark is set)
749
+ let watermarkHeaderIndex;
750
+ let watermarkHeaderRels;
751
+ let watermarkHeaderRId;
752
+ if (doc.watermark) {
753
+ // Use next header index
754
+ const wmHdrIdx = headerIndex;
755
+ watermarkHeaderRId = addRelationship(documentRels, RelType.Header, `header${wmHdrIdx}.xml`);
756
+ watermarkHeaderIndex = wmHdrIdx;
757
+ // If image watermark, add image relationship in header .rels.
758
+ // Watermark .rels live in their own id space, but Word still expects
759
+ // the conventional `rId<N>` form. Allocate a fresh canonical id
760
+ // (preferring an `addRelationship` auto-allocation) when the model
761
+ // supplied a non-canonical id like `__img_1`.
762
+ if (doc.watermark.type === "image") {
763
+ const wmRels = createRelationships();
764
+ const wmRId = doc.watermark.rId;
765
+ const img = imageByRid.get(wmRId);
766
+ if (img) {
767
+ const isCanonical = /^rId\d+$/.test(wmRId);
768
+ if (isCanonical) {
769
+ addRelationshipWithId(wmRels, wmRId, RelType.Image, `media/${img.fileName}`);
770
+ }
771
+ else {
772
+ // Allocate a fresh rId<N> in the header .rels and remap the
773
+ // model id so the header writer emits the right r:embed.
774
+ const allocated = addRelationship(wmRels, RelType.Image, `media/${img.fileName}`);
775
+ imageRemap.set(wmRId, allocated);
776
+ }
777
+ }
778
+ watermarkHeaderRels = wmRels;
779
+ }
780
+ headerIndex++;
781
+ }
782
+ // --- Content Types ---
783
+ addImageContentTypeDefaults(contentTypes, imageExtensions);
784
+ // Determine main document content type based on docType
785
+ const mainDocContentType = resolveDocumentContentType(doc);
786
+ addContentTypeOverride(contentTypes, PartPath.Document, mainDocContentType);
787
+ addContentTypeOverride(contentTypes, PartPath.Styles, ContentType.Styles);
788
+ addContentTypeOverride(contentTypes, PartPath.Settings, ContentType.Settings);
789
+ addContentTypeOverride(contentTypes, PartPath.FontTable, ContentType.FontTable);
790
+ addContentTypeOverride(contentTypes, PartPath.Theme, ContentType.Theme);
791
+ if (hasNumbering) {
792
+ addContentTypeOverride(contentTypes, PartPath.Numbering, ContentType.Numbering);
793
+ }
794
+ if (hasFootnotes) {
795
+ addContentTypeOverride(contentTypes, PartPath.Footnotes, ContentType.Footnotes);
796
+ }
797
+ if (hasEndnotes) {
798
+ addContentTypeOverride(contentTypes, PartPath.Endnotes, ContentType.Endnotes);
799
+ }
800
+ if (hasComments) {
801
+ addContentTypeOverride(contentTypes, PartPath.Comments, ContentType.Comments);
802
+ }
803
+ headerIndex = 1;
804
+ if (doc.headers) {
805
+ for (const [,] of doc.headers) {
806
+ addContentTypeOverride(contentTypes, PartPath.header(headerIndex), ContentType.Header);
807
+ headerIndex++;
808
+ }
809
+ }
810
+ footerIndex = 1;
811
+ if (doc.footers) {
812
+ for (const [,] of doc.footers) {
813
+ addContentTypeOverride(contentTypes, PartPath.footer(footerIndex), ContentType.Footer);
814
+ footerIndex++;
815
+ }
816
+ }
817
+ if (watermarkHeaderIndex !== undefined) {
818
+ addContentTypeOverride(contentTypes, PartPath.header(watermarkHeaderIndex), ContentType.Header);
819
+ }
820
+ addContentTypeOverride(contentTypes, PartPath.CoreProps, ContentType.CoreProperties);
821
+ addContentTypeOverride(contentTypes, PartPath.AppProps, ContentType.ExtendedProperties);
822
+ if (hasCustomProps) {
823
+ addContentTypeOverride(contentTypes, PartPath.CustomProps, ContentType.CustomProperties);
824
+ }
825
+ // --- Generate & add parts to archive ---
826
+ // Note: [Content_Types].xml and _rels/.rels are serialized LAST so that any
827
+ // relationships/content types registered during content rendering (e.g.
828
+ // thumbnails, chart parts, alt chunks) are included.
829
+ // word/_rels/document.xml.rels is also deferred to include chart relationships.
830
+ // Build an effective doc that:
831
+ // (a) rewires sectionProperties header/footer references so their rId
832
+ // values match the document.xml.rels entries we just generated; and
833
+ // (b) includes the auto-generated watermark header reference.
834
+ // The caller's input doc is never mutated.
835
+ //
836
+ // Reference resolution order for each entry:
837
+ // 1. If `rId` is already a registered document-level header/footer rId,
838
+ // keep it as-is.
839
+ // 2. Otherwise try `headerOldRidToNewRid[rId]` (round-trip with the
840
+ // original rId still present, or the headers map keyed by old rId).
841
+ // 3. Otherwise fall back to `headerTypeToNewRid[type]` — this covers the
842
+ // common builder pattern where users add a header by `type` and use
843
+ // `rId: ""` as a placeholder.
844
+ // Same logic for footers.
845
+ const allowedHeaderRids = new Set(headerKeyToNewRid.values());
846
+ const allowedFooterRids = new Set(footerKeyToNewRid.values());
847
+ function resolveHeaderRef(ref) {
848
+ if (ref.rId && allowedHeaderRids.has(ref.rId)) {
849
+ return ref;
850
+ }
851
+ const remapped = ref.rId ? headerOldRidToNewRid.get(ref.rId) : undefined;
852
+ if (remapped) {
853
+ return { ...ref, rId: remapped };
854
+ }
855
+ const byType = headerTypeToNewRid.get(ref.type);
856
+ if (byType) {
857
+ return { ...ref, rId: byType };
858
+ }
859
+ // No header part matches this reference. Drop it rather than emit a
860
+ // dangling r:id that no .rels entry resolves.
861
+ return null;
862
+ }
863
+ function resolveFooterRef(ref) {
864
+ if (ref.rId && allowedFooterRids.has(ref.rId)) {
865
+ return ref;
866
+ }
867
+ const remapped = ref.rId ? footerOldRidToNewRid.get(ref.rId) : undefined;
868
+ if (remapped) {
869
+ return { ...ref, rId: remapped };
870
+ }
871
+ const byType = footerTypeToNewRid.get(ref.type);
872
+ if (byType) {
873
+ return { ...ref, rId: byType };
874
+ }
875
+ return null;
876
+ }
877
+ function rewireSectionRefs(sect) {
878
+ let next = sect;
879
+ let mutated = false;
880
+ if (sect.headers) {
881
+ const resolved = sect.headers
882
+ .map(resolveHeaderRef)
883
+ .filter((r) => r !== null);
884
+ if (resolved.length !== sect.headers.length ||
885
+ resolved.some((r, i) => r !== sect.headers[i])) {
886
+ next = { ...next, headers: resolved };
887
+ mutated = true;
888
+ }
889
+ }
890
+ if (sect.footers) {
891
+ const resolved = sect.footers
892
+ .map(resolveFooterRef)
893
+ .filter((r) => r !== null);
894
+ if (resolved.length !== sect.footers.length ||
895
+ resolved.some((r, i) => r !== sect.footers[i])) {
896
+ next = { ...next, footers: resolved };
897
+ mutated = true;
898
+ }
899
+ }
900
+ return mutated ? next : sect;
901
+ }
902
+ // Snapshot top-level sectionProperties (and apply rewiring). May be
903
+ // undefined when the document has no top-level section properties — we
904
+ // only synthesize one if there are headers/footers/watermark to reference.
905
+ let topLevelSect = doc.sectionProperties
906
+ ? rewireSectionRefs(doc.sectionProperties)
907
+ : undefined;
908
+ // Auto-fill: if the model has headers/footers but no top-level reference
909
+ // was authored at all, synthesize references for each header/footer type
910
+ // so the section actually picks them up. This only fires when the section
911
+ // has zero header (or zero footer) refs — explicit author intent ("only
912
+ // first-page header is referenced") is preserved.
913
+ if (doc.headers &&
914
+ doc.headers.size > 0 &&
915
+ (!topLevelSect?.headers || topLevelSect.headers.length === 0)) {
916
+ const synthesized = [];
917
+ for (const [type, rId] of headerTypeToNewRid) {
918
+ synthesized.push({ type: type, rId });
919
+ }
920
+ if (synthesized.length > 0) {
921
+ topLevelSect = { ...(topLevelSect ?? {}), headers: synthesized };
922
+ }
923
+ }
924
+ if (doc.footers &&
925
+ doc.footers.size > 0 &&
926
+ (!topLevelSect?.footers || topLevelSect.footers.length === 0)) {
927
+ const synthesized = [];
928
+ for (const [type, rId] of footerTypeToNewRid) {
929
+ synthesized.push({ type: type, rId });
930
+ }
931
+ if (synthesized.length > 0) {
932
+ topLevelSect = { ...(topLevelSect ?? {}), footers: synthesized };
933
+ }
934
+ }
935
+ // Apply watermark reference (added after rewiring so its rId is preserved).
936
+ if (watermarkHeaderIndex !== undefined && watermarkHeaderRId) {
937
+ const existingHeaders = topLevelSect?.headers ? [...topLevelSect.headers] : [];
938
+ existingHeaders.push({ type: "default", rId: watermarkHeaderRId });
939
+ topLevelSect = { ...(topLevelSect ?? {}), headers: existingHeaders };
940
+ }
941
+ // Rewire sectionProperties embedded in body paragraphs (mid-document
942
+ // section breaks). Only rebuild the body array if any paragraph's section
943
+ // properties were actually rewritten.
944
+ const sectionRefRewriteNeeded = doc.body.some(item => item.type === "paragraph" &&
945
+ item.properties?.sectionProperties &&
946
+ ((item.properties.sectionProperties.headers &&
947
+ item.properties.sectionProperties.headers.length > 0) ||
948
+ (item.properties.sectionProperties.footers &&
949
+ item.properties.sectionProperties.footers.length > 0)));
950
+ let effectiveBody = doc.body;
951
+ if (sectionRefRewriteNeeded) {
952
+ effectiveBody = doc.body.map(item => {
953
+ if (item.type !== "paragraph" || !item.properties?.sectionProperties) {
954
+ return item;
955
+ }
956
+ const rewired = rewireSectionRefs(item.properties.sectionProperties);
957
+ if (rewired === item.properties.sectionProperties) {
958
+ return item;
959
+ }
960
+ return {
961
+ ...item,
962
+ properties: { ...item.properties, sectionProperties: rewired }
963
+ };
964
+ });
965
+ }
966
+ // Always rebuild effectiveDoc when we rewired anything, otherwise keep the
967
+ // original reference to avoid spurious shallow copies.
968
+ const docNeedsCopy = topLevelSect !== doc.sectionProperties || effectiveBody !== doc.body;
969
+ const effectiveDoc = docNeedsCopy
970
+ ? {
971
+ ...doc,
972
+ ...(topLevelSect !== undefined ? { sectionProperties: topLevelSect } : {}),
973
+ body: effectiveBody
974
+ }
975
+ : doc;
976
+ // Collect charts and register relationships BEFORE rendering document.xml.
977
+ // Body charts go into document.xml.rels; charts that live inside a header
978
+ // or footer must be registered against THAT part's own .rels file (they
979
+ // are referenced from header{N}.xml / footer{N}.xml, not document.xml).
980
+ const charts = [];
981
+ collectCharts(doc.body, charts);
982
+ const chartRIds = [];
983
+ const renderCtxChartRIds = new Map();
984
+ charts.forEach(chartContent => {
985
+ const num = chartRIds.length + 1;
986
+ const rId = addRelationship(documentRels, RelType.Chart, `charts/chart${num}.xml`);
987
+ chartRIds.push(rId);
988
+ renderCtxChartRIds.set(chartContent, rId);
989
+ });
990
+ // Register header charts against each header's own .rels.
991
+ if (doc.headers) {
992
+ for (const [key, headerDef] of doc.headers) {
993
+ const headerCharts = [];
994
+ collectChartsFromHeaderFooter(headerDef.content, headerCharts);
995
+ if (headerCharts.length === 0) {
996
+ continue;
997
+ }
998
+ const hRels = headerRelManagers.get(key) ?? createRelationships();
999
+ for (const chartContent of headerCharts) {
1000
+ const num = chartRIds.length + 1;
1001
+ const rId = addRelationship(hRels, RelType.Chart, `charts/chart${num}.xml`);
1002
+ chartRIds.push(rId);
1003
+ renderCtxChartRIds.set(chartContent, rId);
1004
+ // Also push into the global charts[] so chart{num}.xml + .rels are
1005
+ // emitted later (chart parts themselves live under word/charts/, not
1006
+ // co-located with the header).
1007
+ charts.push(chartContent);
1008
+ }
1009
+ headerRelManagers.set(key, hRels);
1010
+ }
1011
+ }
1012
+ // Same for footers.
1013
+ if (doc.footers) {
1014
+ for (const [key, footerDef] of doc.footers) {
1015
+ const footerCharts = [];
1016
+ collectChartsFromHeaderFooter(footerDef.content, footerCharts);
1017
+ if (footerCharts.length === 0) {
1018
+ continue;
1019
+ }
1020
+ const fRels = footerRelManagers.get(key) ?? createRelationships();
1021
+ for (const chartContent of footerCharts) {
1022
+ const num = chartRIds.length + 1;
1023
+ const rId = addRelationship(fRels, RelType.Chart, `charts/chart${num}.xml`);
1024
+ chartRIds.push(rId);
1025
+ renderCtxChartRIds.set(chartContent, rId);
1026
+ charts.push(chartContent);
1027
+ }
1028
+ footerRelManagers.set(key, fRels);
1029
+ }
1030
+ }
1031
+ // Collect ChartEx items and register relationships
1032
+ const chartExItems = [];
1033
+ collectChartExItems(doc.body, chartExItems);
1034
+ const chartExRIds = [];
1035
+ chartExItems.forEach(cxContent => {
1036
+ const num = chartExRIds.length + 1;
1037
+ const rId = addRelationship(documentRels, RelType.ChartEx, `charts/chartEx${num}.xml`);
1038
+ chartExRIds.push(rId);
1039
+ renderCtxChartRIds.set(cxContent, rId);
1040
+ });
1041
+ // Create render context for document serialization. The id generators
1042
+ // are seeded so any auto-assigned id (e.g. SDT) starts above the maximum
1043
+ // value the caller already used in the model — otherwise an SDT without
1044
+ // an explicit `id` would collide with an existing one and break
1045
+ // dataBinding / repeating section linkage.
1046
+ const renderCtx = createRenderContext({
1047
+ securityPolicy,
1048
+ chartRIds: renderCtxChartRIds,
1049
+ imageRIdRemap: imageRemap,
1050
+ hyperlinkRIds,
1051
+ altChunkRIds,
1052
+ ids: createIdGenerators({
1053
+ sdtId: scanMaxSdtId(doc) + 1
1054
+ })
1055
+ });
1056
+ // word/_rels/document.xml.rels — deferred until after all document-level
1057
+ // relationships have been registered (VBA, webSettings, people, charts, etc.)
1058
+ // word/document.xml
1059
+ archive.add(PartPath.Document, renderXml(xml => renderDocument(xml, effectiveDoc, renderCtx)));
1060
+ // word/styles.xml
1061
+ archive.add(PartPath.Styles, renderXml(xml => renderStyles(xml, doc.docDefaults, doc.styles)));
1062
+ // word/settings.xml
1063
+ archive.add(PartPath.Settings, renderXml(xml => renderSettings(xml, doc.settings, rawXmlPolicy)));
1064
+ // word/fontTable.xml
1065
+ archive.add(PartPath.FontTable, renderXml(xml => renderFontTable(xml, doc.fonts)));
1066
+ // word/fonts/*.odttf (embedded fonts)
1067
+ if (doc.embeddedFonts && doc.embeddedFonts.length > 0) {
1068
+ const fontTableRels = createRelationships();
1069
+ const usedRIds = new Set();
1070
+ // Collect rIds referenced in fontTable
1071
+ if (doc.fonts) {
1072
+ for (const font of doc.fonts) {
1073
+ if (font.embedRegular) {
1074
+ usedRIds.add(font.embedRegular);
1075
+ }
1076
+ if (font.embedBold) {
1077
+ usedRIds.add(font.embedBold);
1078
+ }
1079
+ if (font.embedItalic) {
1080
+ usedRIds.add(font.embedItalic);
1081
+ }
1082
+ if (font.embedBoldItalic) {
1083
+ usedRIds.add(font.embedBoldItalic);
1084
+ }
1085
+ }
1086
+ }
1087
+ for (const ef of doc.embeddedFonts) {
1088
+ const partPath = `word/fonts/${ef.fileName}`;
1089
+ // De-dup: two EmbeddedFont entries with the same (rId, fileName) are
1090
+ // the same physical file (typical when callers reuse helpers like
1091
+ // `embedFontFamily` and store the same FontDef across runs). Skip
1092
+ // the duplicate to avoid an `archive.add` overwrite race and a
1093
+ // `Duplicate relationship ID` from `addRelationshipWithId`.
1094
+ if (fontTableRels.hasId(ef.rId)) {
1095
+ continue;
1096
+ }
1097
+ archive.add(partPath, ef.data);
1098
+ // Register relationship from fontTable.xml. We always emit the
1099
+ // relationship (even when no FontDef references it directly) so
1100
+ // the embedded font part doesn't end up orphaned in the package.
1101
+ addRelationshipWithId(fontTableRels, ef.rId, RelType.Font, `fonts/${ef.fileName}`);
1102
+ void usedRIds;
1103
+ // Register content type for .odttf / .ttf
1104
+ const ext = getFileExt(ef.fileName);
1105
+ if (ext === "odttf") {
1106
+ addContentTypeDefault(contentTypes, "odttf", ContentType.ObfuscatedFont);
1107
+ }
1108
+ else if (ext === "ttf") {
1109
+ addContentTypeDefault(contentTypes, "ttf", "application/x-font-ttf");
1110
+ }
1111
+ else if (ext === "otf") {
1112
+ addContentTypeDefault(contentTypes, "otf", "application/x-font-otf");
1113
+ }
1114
+ }
1115
+ // Write fontTable.xml.rels
1116
+ archive.add("word/_rels/fontTable.xml.rels", renderXml(xml => renderRelationships(fontTableRels, xml)));
1117
+ }
1118
+ // Custom XML parts (for SDT data binding)
1119
+ if (doc.customXmlParts && doc.customXmlParts.length > 0) {
1120
+ doc.customXmlParts.forEach((part, i) => {
1121
+ const num = i + 1;
1122
+ const itemPath = `word/customXml/item${num}.xml`;
1123
+ const propsPath = `word/customXml/itemProps${num}.xml`;
1124
+ // Write the XML content
1125
+ archive.add(itemPath, part.xmlContent);
1126
+ // Write itemProps*.xml
1127
+ const propsXml = renderXml(xml => {
1128
+ xml.openXml(STD_DOC_ATTRIBUTES);
1129
+ xml.openNode("ds:datastoreItem", {
1130
+ "ds:itemID": `{${part.itemId}}`,
1131
+ "xmlns:ds": "http://schemas.openxmlformats.org/officeDocument/2006/customXml"
1132
+ });
1133
+ if (part.schemaReferences && part.schemaReferences.length > 0) {
1134
+ xml.openNode("ds:schemaRefs");
1135
+ for (const uri of part.schemaReferences) {
1136
+ xml.leafNode("ds:schemaRef", { "ds:uri": uri });
1137
+ }
1138
+ xml.closeNode();
1139
+ }
1140
+ else {
1141
+ xml.leafNode("ds:schemaRefs");
1142
+ }
1143
+ xml.closeNode();
1144
+ });
1145
+ archive.add(propsPath, propsXml);
1146
+ // Write item rels (links itemN.xml → itemPropsN.xml)
1147
+ const itemRels = createRelationships();
1148
+ addRelationship(itemRels, RelType.CustomXmlProps, `itemProps${num}.xml`);
1149
+ archive.add(`word/customXml/_rels/item${num}.xml.rels`, renderXml(xml => renderRelationships(itemRels, xml)));
1150
+ // Register content types
1151
+ addContentTypeOverride(contentTypes, `/word/customXml/itemProps${num}.xml`, "application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
1152
+ // Add to document rels
1153
+ addRelationship(documentRels, RelType.CustomXml, `customXml/item${num}.xml`);
1154
+ });
1155
+ }
1156
+ // word/theme/theme1.xml
1157
+ archive.add(PartPath.Theme, renderXml(xml => renderTheme(xml, doc.theme, rawXmlPolicy)));
1158
+ // word/numbering.xml
1159
+ if (hasNumbering) {
1160
+ archive.add(PartPath.Numbering, renderXml(xml => renderNumbering(xml, doc.abstractNumberings, doc.numberingInstances, doc.numPicBullets, rawXmlPolicy)));
1161
+ }
1162
+ // word/footnotes.xml + footnotes.xml.rels
1163
+ if (hasFootnotes) {
1164
+ archive.add(PartPath.Footnotes,
1165
+ // Footnotes are an independent OPC part — their r:id values must
1166
+ // resolve against word/_rels/footnotes.xml.rels, not document.xml.rels.
1167
+ renderXml(xml => renderFootnotes(xml, doc.footnotes, { imageRemap: new Map(), hyperlinkRIds, rawXmlPolicy })));
1168
+ if (getRelationshipCount(footnoteRels) > 0) {
1169
+ archive.add("word/_rels/footnotes.xml.rels", renderXml(xml => renderRelationships(footnoteRels, xml)));
1170
+ }
1171
+ }
1172
+ // word/endnotes.xml + endnotes.xml.rels
1173
+ if (hasEndnotes) {
1174
+ archive.add(PartPath.Endnotes, renderXml(xml => renderEndnotes(xml, doc.endnotes, { imageRemap: new Map(), hyperlinkRIds, rawXmlPolicy })));
1175
+ if (getRelationshipCount(endnoteRels) > 0) {
1176
+ archive.add("word/_rels/endnotes.xml.rels", renderXml(xml => renderRelationships(endnoteRels, xml)));
1177
+ }
1178
+ }
1179
+ // word/comments.xml + comments.xml.rels
1180
+ if (hasComments) {
1181
+ archive.add(PartPath.Comments,
1182
+ // Comments live in their own OPC part; pass helpers so embedded
1183
+ // hyperlinks/images render with the right r:id (the rels manager
1184
+ // below registered them under their model-original id).
1185
+ renderXml(xml => renderComments(xml, doc.comments, { imageRemap: new Map(), hyperlinkRIds, rawXmlPolicy })));
1186
+ if (getRelationshipCount(commentRels) > 0) {
1187
+ archive.add("word/_rels/comments.xml.rels", renderXml(xml => renderRelationships(commentRels, xml)));
1188
+ }
1189
+ // word/commentsExtended.xml (for done/parentId)
1190
+ const hasExtended = doc.comments.some(c => c.done !== undefined || c.parentId !== undefined);
1191
+ if (hasExtended) {
1192
+ const extXml = renderXml(xml => renderCommentsExtended(xml, doc.comments));
1193
+ archive.add(PartPath.CommentsExtended, extXml);
1194
+ addRelationship(documentRels, RelType.CommentsExtended, "commentsExtended.xml");
1195
+ addContentTypeOverride(contentTypes, `/${PartPath.CommentsExtended}`, ContentType.CommentsExtended);
1196
+ }
1197
+ }
1198
+ // Headers
1199
+ headerIndex = 1;
1200
+ if (doc.headers) {
1201
+ let hIdx = 0;
1202
+ const keys = [...doc.headers.keys()];
1203
+ for (const [, headerDef] of doc.headers) {
1204
+ archive.add(PartPath.header(headerIndex),
1205
+ // Header .rels is independent from document .rels — pass an empty
1206
+ // imageRemap so we never rewrite r:embed against the document remap.
1207
+ renderXml(xml => renderHeader(xml, headerDef.content, {
1208
+ imageRemap: new Map(),
1209
+ hyperlinkRIds,
1210
+ rawXmlPolicy
1211
+ })));
1212
+ // Header .rels file
1213
+ const hKey = keys[hIdx];
1214
+ const hRels = headerRelManagers.get(hKey);
1215
+ if (hRels && getRelationshipCount(hRels) > 0) {
1216
+ archive.add(`word/_rels/header${headerIndex}.xml.rels`, renderXml(xml => renderRelationships(hRels, xml)));
1217
+ }
1218
+ headerIndex++;
1219
+ hIdx++;
1220
+ }
1221
+ }
1222
+ // Footers
1223
+ footerIndex = 1;
1224
+ if (doc.footers) {
1225
+ let fIdx = 0;
1226
+ const keys = [...doc.footers.keys()];
1227
+ for (const [, footerDef] of doc.footers) {
1228
+ archive.add(PartPath.footer(footerIndex),
1229
+ // Footer .rels is independent from document .rels.
1230
+ renderXml(xml => renderFooter(xml, footerDef.content, {
1231
+ imageRemap: new Map(),
1232
+ hyperlinkRIds,
1233
+ rawXmlPolicy
1234
+ })));
1235
+ // Footer .rels file
1236
+ const fKey = keys[fIdx];
1237
+ const fRels = footerRelManagers.get(fKey);
1238
+ if (fRels && getRelationshipCount(fRels) > 0) {
1239
+ archive.add(`word/_rels/footer${footerIndex}.xml.rels`, renderXml(xml => renderRelationships(fRels, xml)));
1240
+ }
1241
+ footerIndex++;
1242
+ fIdx++;
1243
+ }
1244
+ }
1245
+ // Watermark header
1246
+ if (watermarkHeaderIndex !== undefined && doc.watermark) {
1247
+ // For image watermarks the model rId may have been remapped onto a
1248
+ // canonical `rId<N>` form when registering the watermark .rels (so
1249
+ // Word accepts the package). Pass the remapped value through so the
1250
+ // VML shape's r:id attribute matches the .rels entry.
1251
+ const watermarkImageRId = doc.watermark.type === "image"
1252
+ ? (imageRemap.get(doc.watermark.rId) ?? doc.watermark.rId)
1253
+ : undefined;
1254
+ archive.add(PartPath.header(watermarkHeaderIndex), renderXml(xml => renderWatermarkHeader(xml, doc.watermark, watermarkImageRId)));
1255
+ if (watermarkHeaderRels && getRelationshipCount(watermarkHeaderRels) > 0) {
1256
+ archive.add(`word/_rels/header${watermarkHeaderIndex}.xml.rels`, renderXml(xml => renderRelationships(watermarkHeaderRels, xml)));
1257
+ }
1258
+ }
1259
+ // Media / images
1260
+ if (doc.images) {
1261
+ for (const img of doc.images) {
1262
+ archive.add(PartPath.media(img.fileName), img.data);
1263
+ }
1264
+ }
1265
+ // SVG fallback PNG files
1266
+ for (const fb of svgFallbacks) {
1267
+ archive.add(PartPath.media(fb.fallbackFileName), fb.data);
1268
+ }
1269
+ // docProps/core.xml
1270
+ archive.add(PartPath.CoreProps, renderXml(xml => renderCoreProperties(xml, doc.coreProperties)));
1271
+ // docProps/app.xml
1272
+ archive.add(PartPath.AppProps, renderXml(xml => renderAppProperties(xml, doc.appProperties)));
1273
+ // docProps/custom.xml
1274
+ if (hasCustomProps) {
1275
+ archive.add(PartPath.CustomProps, renderXml(xml => renderCustomProperties(xml, doc.customProperties)));
1276
+ }
1277
+ // word/webSettings.xml
1278
+ if (doc.webSettings) {
1279
+ archive.add(PartPath.WebSettings, renderXml(xml => renderWebSettings(xml, doc.webSettings, rawXmlPolicy)));
1280
+ addRelationship(documentRels, RelType.WebSettings, "webSettings.xml");
1281
+ addContentTypeOverride(contentTypes, `/${PartPath.WebSettings}`, ContentType.WebSettings);
1282
+ }
1283
+ // word/people.xml
1284
+ if (doc.people && doc.people.length > 0) {
1285
+ archive.add(PartPath.People, renderXml(xml => renderPeople(xml, doc.people)));
1286
+ addRelationship(documentRels, RelType.People, "people.xml");
1287
+ addContentTypeOverride(contentTypes, `/${PartPath.People}`, ContentType.People);
1288
+ }
1289
+ // docProps/thumbnail
1290
+ if (doc.thumbnail) {
1291
+ const ext = doc.thumbnail.contentType === "image/jpeg"
1292
+ ? "jpeg"
1293
+ : doc.thumbnail.contentType === "image/png"
1294
+ ? "png"
1295
+ : "wmf";
1296
+ const thumbPath = `docProps/thumbnail.${ext}`;
1297
+ archive.add(thumbPath, doc.thumbnail.data);
1298
+ // Package rels: target is relative to package root (docProps/thumbnail.jpeg)
1299
+ addRelationship(packageRels, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", thumbPath);
1300
+ addContentTypeDefault(contentTypes, ext, doc.thumbnail.contentType);
1301
+ }
1302
+ // word/vbaProject.bin (macro-enabled documents)
1303
+ if (doc.vbaProject) {
1304
+ archive.add("word/vbaProject.bin", doc.vbaProject);
1305
+ addRelationship(documentRels, RelType.VbaProject, "vbaProject.bin");
1306
+ addContentTypeOverride(contentTypes, "/word/vbaProject.bin", ContentType.VbaProject);
1307
+ }
1308
+ // Write opaque (unrecognized) parts for round-trip preservation.
1309
+ //
1310
+ // Opaque parts are written as-is into the ZIP. Their paths must not
1311
+ // collide with parts the packager itself produces — otherwise we either
1312
+ // emit a duplicate ZIP entry (Word may pick whichever it sees first, but
1313
+ // the produced package is no longer well-formed) or we silently overwrite
1314
+ // the semantic part. Round-trip via `readDocx` already excludes parts
1315
+ // that were consumed; collisions in practice come from callers that
1316
+ // construct opaqueParts by hand. Reject the most dangerous overlaps with
1317
+ // a clear error.
1318
+ if (doc.opaqueParts) {
1319
+ // Exact-path reservations: any well-known core part the packager always
1320
+ // emits, plus the parts we have already added during this run (headers,
1321
+ // footers, charts, embedded fonts, etc).
1322
+ const reservedExact = new Set([
1323
+ PartPath.ContentTypes,
1324
+ PartPath.PackageRels,
1325
+ PartPath.Document,
1326
+ PartPath.DocumentRels,
1327
+ PartPath.Styles,
1328
+ "word/_rels/styles.xml.rels",
1329
+ PartPath.Settings,
1330
+ PartPath.FontTable,
1331
+ "word/_rels/fontTable.xml.rels",
1332
+ PartPath.Numbering,
1333
+ PartPath.Footnotes,
1334
+ "word/_rels/footnotes.xml.rels",
1335
+ PartPath.Endnotes,
1336
+ "word/_rels/endnotes.xml.rels",
1337
+ PartPath.Comments,
1338
+ "word/_rels/comments.xml.rels",
1339
+ PartPath.CommentsExtended,
1340
+ PartPath.People,
1341
+ PartPath.WebSettings,
1342
+ PartPath.Theme,
1343
+ PartPath.CoreProps,
1344
+ PartPath.AppProps,
1345
+ PartPath.CustomProps,
1346
+ PartPath.Thumbnail,
1347
+ "word/vbaProject.bin",
1348
+ "word/_rels/vbaProject.bin.rels"
1349
+ ]);
1350
+ // Headers/footers we are emitting in this run.
1351
+ if (doc.headers) {
1352
+ let i = 1;
1353
+ for (const _entry of doc.headers) {
1354
+ void _entry;
1355
+ reservedExact.add(PartPath.header(i));
1356
+ reservedExact.add(PartPath.headerRels(i));
1357
+ i++;
1358
+ }
1359
+ }
1360
+ if (doc.footers) {
1361
+ let i = 1;
1362
+ for (const _entry of doc.footers) {
1363
+ void _entry;
1364
+ reservedExact.add(PartPath.footer(i));
1365
+ reservedExact.add(PartPath.footerRels(i));
1366
+ i++;
1367
+ }
1368
+ }
1369
+ // Charts emitted by this run.
1370
+ for (let i = 1; i <= charts.length; i++) {
1371
+ reservedExact.add(`word/charts/chart${i}.xml`);
1372
+ reservedExact.add(`word/charts/_rels/chart${i}.xml.rels`);
1373
+ }
1374
+ for (let i = 1; i <= chartExItems.length; i++) {
1375
+ reservedExact.add(`word/charts/chartEx${i}.xml`);
1376
+ }
1377
+ // Image media: each image has a deterministic media path.
1378
+ if (doc.images) {
1379
+ for (const img of doc.images) {
1380
+ if (img.fileName) {
1381
+ reservedExact.add(`word/media/${img.fileName}`);
1382
+ }
1383
+ }
1384
+ }
1385
+ // Embedded fonts.
1386
+ if (doc.embeddedFonts) {
1387
+ for (const ef of doc.embeddedFonts) {
1388
+ if (ef.fileName) {
1389
+ reservedExact.add(`word/fonts/${ef.fileName}`);
1390
+ }
1391
+ }
1392
+ }
1393
+ for (const part of doc.opaqueParts) {
1394
+ if (reservedExact.has(part.path)) {
1395
+ throw new DocxWriteError(`Opaque part path "${part.path}" conflicts with a part the packager ` +
1396
+ `is emitting itself. Move the data into the corresponding model ` +
1397
+ `field (e.g. doc.styles, doc.headers, doc.images) or rename the ` +
1398
+ `opaque part.`);
1399
+ }
1400
+ // Honour `preserveOleObjects`: drop OLE binaries before they reach
1401
+ // the ZIP. The relationships that referenced them remain in the
1402
+ // owning part's .rels, but no payload will be written.
1403
+ if (!securityPolicy.preserveOleObjects &&
1404
+ (part.path.startsWith("word/embeddings/") ||
1405
+ (part.path.endsWith(".bin") && part.path.includes("embed")))) {
1406
+ continue;
1407
+ }
1408
+ // Honour `dropSignaturesOnModify`: any digital-signature part lives
1409
+ // under `_xmlsignatures/`. Once the document has been re-serialised
1410
+ // the signature would no longer match the new bytes, so by default
1411
+ // we drop these parts entirely. The corresponding sigOrigin
1412
+ // relationship from `_rels/.rels` is also gone — packageRels is
1413
+ // rebuilt from scratch, so the dangling reference disappears too.
1414
+ if (securityPolicy.dropSignaturesOnModify && part.path.startsWith("_xmlsignatures/")) {
1415
+ continue;
1416
+ }
1417
+ archive.add(part.path, part.data);
1418
+ // Register content type: explicit > inferred by extension > skip
1419
+ const ext = getFileExt(part.path);
1420
+ if (part.contentType) {
1421
+ addContentTypeOverride(contentTypes, `/${part.path}`, part.contentType);
1422
+ }
1423
+ else if (ext) {
1424
+ // Infer from common extensions so [Content_Types].xml isn't incomplete
1425
+ const inferred = inferContentType(ext);
1426
+ if (inferred) {
1427
+ addContentTypeOverride(contentTypes, `/${part.path}`, inferred);
1428
+ }
1429
+ }
1430
+ // Write part relationships if any
1431
+ if (part.relationships && part.relationships.length > 0) {
1432
+ const partRels = createRelationships();
1433
+ for (const rel of part.relationships) {
1434
+ addRelationshipWithId(partRels, rel.id, rel.type, rel.target, rel.targetMode);
1435
+ }
1436
+ const relsPath = getPartRelsPath(part.path);
1437
+ archive.add(relsPath, renderXml(xml => renderRelationships(partRels, xml)));
1438
+ }
1439
+ }
1440
+ }
1441
+ // Write chart parts (rIds already registered earlier)
1442
+ const chartEmbedPromises = [];
1443
+ charts.forEach((chartContent, i) => {
1444
+ const num = i + 1;
1445
+ const chartPath = `word/charts/chart${num}.xml`;
1446
+ // Register chart part
1447
+ archive.add(chartPath, renderXml(xml => renderChartPart(xml, chartContent.chart)));
1448
+ // Register content type
1449
+ addContentTypeOverride(contentTypes, `/word/charts/chart${num}.xml`, ContentType.Chart);
1450
+ // Embed xlsx workbook if requested
1451
+ if (chartContent.chart.embedWorkbook) {
1452
+ const xlsxPath = `word/embeddings/Microsoft_Excel_Worksheet${num}.xlsx`;
1453
+ // Create chart .rels file referencing the embedded xlsx
1454
+ const chartRels = createRelationships();
1455
+ addRelationship(chartRels, RelType.Package, `../embeddings/Microsoft_Excel_Worksheet${num}.xlsx`);
1456
+ archive.add(`word/charts/_rels/chart${num}.xml.rels`, renderXml(xml => renderRelationships(chartRels, xml)));
1457
+ // Register xlsx content type
1458
+ addContentTypeOverride(contentTypes, `/${xlsxPath}`, ContentType.Xlsx);
1459
+ // Generate and add xlsx asynchronously via Excel module (dynamic import)
1460
+ const promise = import("../bridge/excel-bridge.js").then(async ({ generateChartEmbeddedXlsx }) => {
1461
+ const xlsxData = await generateChartEmbeddedXlsx(chartContent.chart.series);
1462
+ archive.add(xlsxPath, xlsxData);
1463
+ });
1464
+ chartEmbedPromises.push(promise);
1465
+ }
1466
+ });
1467
+ // Wait for all embedded xlsx files to be generated
1468
+ if (chartEmbedPromises.length > 0) {
1469
+ await Promise.all(chartEmbedPromises);
1470
+ }
1471
+ // Write ChartEx parts (cx:chartSpace XML)
1472
+ chartExItems.forEach((cxContent, i) => {
1473
+ const num = i + 1;
1474
+ const cxPath = `word/charts/chartEx${num}.xml`;
1475
+ archive.add(cxPath, cxContent.chartExXml);
1476
+ addContentTypeOverride(contentTypes, `/${cxPath}`, ContentType.ChartEx);
1477
+ });
1478
+ // LAST: Write [Content_Types].xml, _rels/.rels, and word/_rels/document.xml.rels
1479
+ // after all parts have registered their content types and relationships.
1480
+ // Validate relationships before serializing (catch duplicate IDs, missing TargetMode, etc.)
1481
+ const docRelErrors = documentRels.validate();
1482
+ const pkgRelErrors = packageRels.validate();
1483
+ if (docRelErrors.length > 0 || pkgRelErrors.length > 0) {
1484
+ const allErrors = [...pkgRelErrors, ...docRelErrors];
1485
+ throw new DocxWriteError(`OPC relationship validation failed:\n${allErrors.join("\n")}`);
1486
+ }
1487
+ archive.add(PartPath.DocumentRels, renderXml(xml => renderRelationships(documentRels, xml)));
1488
+ archive.add(PartPath.ContentTypes, renderXml(xml => renderContentTypes(contentTypes, xml)));
1489
+ archive.add(PartPath.PackageRels, renderXml(xml => renderRelationships(packageRels, xml)));
1490
+ return archive.bytes();
1491
+ }
1492
+ /** Recursively collect altChunks from body content. */
1493
+ function collectAltChunks(body, out) {
1494
+ walkBlocks(body, {
1495
+ visitAltChunk(chunk) {
1496
+ out.push(chunk);
1497
+ }
1498
+ });
1499
+ }
1500
+ /** Recursively collect chart contents from body content. */
1501
+ function collectCharts(body, out) {
1502
+ walkBlocks(body, {
1503
+ visitChart(chart) {
1504
+ out.push(chart);
1505
+ }
1506
+ });
1507
+ }
1508
+ /** Recursively collect ChartEx contents from body content. */
1509
+ function collectChartExItems(body, out) {
1510
+ walkBlocks(body, {
1511
+ visitChartEx(chart) {
1512
+ out.push(chart);
1513
+ }
1514
+ });
1515
+ }