@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,1382 @@
1
+ /**
2
+ * DOCX Module - Streaming Writer
3
+ *
4
+ * A DOCX generator that serializes body content incrementally and pushes it
5
+ * through a streaming compression pipeline. Uses the same streaming ZIP
6
+ * infrastructure as the Excel module:
7
+ *
8
+ * - `Zip` (StreamingZip) — streams ZIP entries to output
9
+ * - `ZipDeflate` — per-entry deflate compression
10
+ * - `StreamBuf` — event-driven pipe from XML to ZIP
11
+ * - `StringBuf` — efficient XML string builder with buffer reuse
12
+ *
13
+ * Data flow with sink (true end-to-end streaming):
14
+ * ```
15
+ * add(paragraph) → XML → StreamBuf → ZipDeflate → Zip
16
+ * ↓ (per-chunk callback)
17
+ * await SinkAdapter.write(chunk)
18
+ * ↓
19
+ * user-supplied WritableStream /
20
+ * Node Writable / duck-typed sink
21
+ * ```
22
+ *
23
+ * Memory profile:
24
+ * - Body model is never retained: each element is serialised and
25
+ * compressed as it arrives, so peak per-element memory is
26
+ * O(largest_single_element).
27
+ * - When `options.sink` is provided, compressed bytes are pushed
28
+ * into the sink as soon as they are produced (with backpressure
29
+ * awaited via {@link SinkAdapter}). Total writer-side memory then
30
+ * stays O(largest_part) regardless of final DOCX size.
31
+ * - When `options.sink` is omitted, compressed bytes accumulate in
32
+ * `_outputChunks` and `finalize()` returns the assembled
33
+ * `Uint8Array`. Total memory is O(compressed_docx_size).
34
+ */
35
+ import { Zip, ZipDeflate } from "../../archive/zip/stream.js";
36
+ import { SinkAdapter } from "../../stream/internal/sink-adapter.js";
37
+ import { xmlEncodeAttr } from "../../xml/encode.js";
38
+ import { XmlWriter } from "../../xml/writer.js";
39
+ import { ContentType, RelType, PartPath, DOCUMENT_NAMESPACES, STD_DOC_ATTRIBUTES } from "../constants.js";
40
+ import { sanitizeMediaFileName, sanitizeUrl, utf8Encoder } from "../core/internal-utils.js";
41
+ import { getFileExt, getPartRelsPath } from "../core/opc-paths.js";
42
+ import { walkBlocks } from "../core/walker.js";
43
+ import { DocxWriteError } from "../errors.js";
44
+ import { renderChartPart } from "./chart-writer.js";
45
+ import { renderComments, renderCommentsExtended } from "./comment-writer.js";
46
+ import { buildCommonAuxiliaryParts } from "./common-parts.js";
47
+ import { createContentTypes, addContentTypeDefault, addContentTypeOverride, addImageContentTypeDefaults, renderContentTypes } from "./content-types.js";
48
+ import { renderBodyContent } from "./document-writer.js";
49
+ import { renderHeader, renderFooter, renderWatermarkHeader } from "./header-footer-writer.js";
50
+ import { collectChartsFromHeaderFooter, collectHyperlinksFromHeaderFooter, collectHyperlinksFromNotes, collectImageRidsFromContent, collectImageRidsFromNotes } from "./reference-scanners.js";
51
+ import { createRelationships, addRelationship, addRelationshipWithId, getRelationshipCount, renderRelationships } from "./relationships.js";
52
+ import { createRenderContext } from "./render-context.js";
53
+ import { renderSectionProperties } from "./section-writer.js";
54
+ import { StreamBuf } from "./stream-buf.js";
55
+ import { StringBuf } from "./string-buf.js";
56
+ // Per-instance StringBuf is created in the constructor (see _xmlBuffer field below).
57
+ // Previously this was a module-level singleton which caused data races with concurrent instances.
58
+ const EMPTY_U8 = new Uint8Array(0);
59
+ // =============================================================================
60
+ // Streaming DOCX Writer
61
+ // =============================================================================
62
+ /**
63
+ * Streaming DOCX writer. Body elements are serialized to XML and compressed
64
+ * into the ZIP pipeline as they arrive, so the body **model** is not retained
65
+ * after each `add()`.
66
+ *
67
+ * When constructed with `options.sink`, compressed bytes are pushed into
68
+ * the sink as soon as the ZIP layer produces them, with backpressure
69
+ * awaited via {@link SinkAdapter}; in this mode peak memory is
70
+ * O(largest_part) and `finalize()` resolves to a zero-length
71
+ * `Uint8Array` (the bytes are already in the sink). Without a sink,
72
+ * compressed bytes accumulate in `_outputChunks` and `finalize()`
73
+ * returns the assembled `Uint8Array` (peak memory
74
+ * O(compressed_docx_size)).
75
+ *
76
+ * Use {@link addAsync} (instead of {@link add}) when driving the sink
77
+ * variant to obtain true end-to-end backpressure: each call awaits all
78
+ * pending sink writes before resolving.
79
+ */
80
+ export class StreamingDocxWriter {
81
+ constructor(options = {}) {
82
+ this._elementCount = 0;
83
+ this._finalized = false;
84
+ // Per-instance XML buffer (avoids module-level singleton data race)
85
+ this._xmlBuffer = new StringBuf({ size: 65536 });
86
+ /** Compressed-byte accumulator used when no `sink` is supplied. */
87
+ this._outputChunks = [];
88
+ /**
89
+ * Promise chain serialising every sink write. The `Zip` callback fires
90
+ * synchronously, so we queue chunks via `.then(...)` and let
91
+ * `addAsync` / `finalize` await the chain.
92
+ */
93
+ this._pendingDrain = Promise.resolve();
94
+ this._headerWritten = false;
95
+ /**
96
+ * Whether the previously-written body element was a `<w:tbl>`. Tracked
97
+ * so we can insert a separator `<w:p>` between adjacent tables — Word
98
+ * rejects (and silently merges) two `<w:tbl>` blocks that share no
99
+ * paragraph between them per ECMA-376 §17.13.5.34.
100
+ */
101
+ this._prevWasTable = false;
102
+ /**
103
+ * First error reported by the underlying ZIP stream (compression failure,
104
+ * write-after-end, etc.). Stored synchronously by the `Zip` callback and
105
+ * surfaced from `finalize()` so callers receive a rejection instead of an
106
+ * indefinitely-pending promise.
107
+ */
108
+ this._streamError = null;
109
+ /** Charts encountered in body content; rendered to `word/charts/chartN.xml` at finalize time. */
110
+ this._bodyCharts = [];
111
+ /** ChartEx items encountered in body content. */
112
+ this._bodyChartEx = [];
113
+ /**
114
+ * Per-chart sequence numbers fixed at registration time. Both classes
115
+ * use independent monotonic counters; the writer emits
116
+ * `word/charts/chart{n}.xml` for the regular chart family and
117
+ * `word/charts/chartEx{n}.xml` for the chartEx family.
118
+ *
119
+ * The previous scheme used `chartCount + chartExCount + 1` as the
120
+ * sequence number for both classes, which made the rId path encoded in
121
+ * documentRels disagree with the path used at finalize when the writer
122
+ * iterated the two arrays separately. The result was relationships
123
+ * pointing at non-existent chart parts.
124
+ */
125
+ this._chartNum = new WeakMap();
126
+ this._nextChartSeq = 0;
127
+ this._nextChartExSeq = 0;
128
+ /** Hyperlink object identities already registered (to keep one rId per object). */
129
+ this._registeredHyperlinks = new WeakSet();
130
+ /** Image rIds already registered to documentRels (avoid duplicates). */
131
+ this._registeredImageRIds = new Set();
132
+ /** header map key → newly allocated rId. Populated by `_allocateHeaderFooterRIds`. */
133
+ this._headerKeyToRid = new Map();
134
+ /** footer map key → newly allocated rId. */
135
+ this._footerKeyToRid = new Map();
136
+ // Sanitize image/font file names up-front. They get embedded into
137
+ // ZIP entry paths and into rels Target attributes; a hostile name
138
+ // (e.g. `../../etc/passwd.png` from a round-tripped untrusted DOCX)
139
+ // would otherwise produce a zipslip-shaped output. Mirrors what
140
+ // `packageDocx` does in `shallowCopyDocForPackaging`.
141
+ const sanitized = sanitizeStreamingOptions(options);
142
+ this._options = sanitized;
143
+ this._initZip();
144
+ }
145
+ /** Set a progress callback. */
146
+ onProgress(cb) {
147
+ this._onProgress = cb;
148
+ return this;
149
+ }
150
+ /**
151
+ * Add a single body element. The element is immediately serialized to XML
152
+ * and pushed into the ZIP compression pipeline. After this call, the element
153
+ * can be garbage collected — it is not retained.
154
+ */
155
+ add(element) {
156
+ if (this._finalized) {
157
+ throw new DocxWriteError("StreamingDocxWriter: cannot add elements after finalize()");
158
+ }
159
+ // Sink-mode early failure: if a previous chunk already failed to
160
+ // reach the sink, surface that immediately rather than letting the
161
+ // caller keep streaming work that will be discarded. Buffered mode
162
+ // keeps the legacy behaviour of deferring all error reporting to
163
+ // `finalize()` because there is no live consumer that could be
164
+ // disrupted by silent queueing.
165
+ if (this._sinkAdapter && this._streamError) {
166
+ throw new DocxWriteError(`StreamingDocxWriter: sink already failed (${this._streamError.message})`, { cause: this._streamError });
167
+ }
168
+ // Write document.xml header on first element
169
+ if (!this._headerWritten) {
170
+ this._writeDocumentHeader();
171
+ this._headerWritten = true;
172
+ }
173
+ // Register any chart/hyperlink/image references this element introduces
174
+ // BEFORE serializing it, so the per-element renderBodyContent call has a
175
+ // populated WordRenderContext (chart rIds, hyperlink rIds, image remap).
176
+ this._registerElementReferences(element);
177
+ // ECMA-376 §17.13.5.34: a `<w:tbl>` must be followed by a paragraph
178
+ // (or section break) before the next `<w:tbl>` may begin. When the
179
+ // caller streams two adjacent tables we synthesise an empty
180
+ // separator paragraph between them so Word does not collapse them
181
+ // into a single malformed tbl.
182
+ if (element.type === "table" && this._prevWasTable) {
183
+ this._writeSeparatorParagraph();
184
+ }
185
+ // Serialize this single element to XML and push to stream
186
+ this._writeBodyElement(element);
187
+ this._elementCount++;
188
+ this._prevWasTable = element.type === "table";
189
+ if (this._onProgress && this._elementCount % (this._options.chunkSize ?? 1000) === 0) {
190
+ this._onProgress({ elementsWritten: this._elementCount, phase: "body" });
191
+ }
192
+ return this;
193
+ }
194
+ /** Add multiple body elements at once. */
195
+ addMany(elements) {
196
+ for (const el of elements) {
197
+ this.add(el);
198
+ }
199
+ return this;
200
+ }
201
+ /**
202
+ * Async variant of {@link add}. After serialising the element, awaits
203
+ * any pending writes to the configured `sink` so callers driving large
204
+ * input get true end-to-end backpressure rather than letting the
205
+ * sink-write queue grow unbounded inside the writer.
206
+ *
207
+ * Without `options.sink` this is equivalent to `add` (resolving
208
+ * synchronously after element serialisation).
209
+ *
210
+ * Throws if the sink reports an error: previous queued writes whose
211
+ * rejection was captured into `_streamError` surface here.
212
+ */
213
+ async addAsync(element) {
214
+ this.add(element);
215
+ if (this._sinkAdapter) {
216
+ await this._pendingDrain;
217
+ if (this._streamError) {
218
+ throw new DocxWriteError(`StreamingDocxWriter: sink write failed (${this._streamError.message})`, { cause: this._streamError });
219
+ }
220
+ }
221
+ return this;
222
+ }
223
+ /**
224
+ * Async variant of {@link addMany}. Awaits `addAsync` for each element
225
+ * so backpressure is honoured between every body element.
226
+ */
227
+ async addManyAsync(elements) {
228
+ for (const el of elements) {
229
+ await this.addAsync(el);
230
+ }
231
+ return this;
232
+ }
233
+ /** Add a paragraph with simple text content. */
234
+ addText(content, properties) {
235
+ return this.add({
236
+ type: "paragraph",
237
+ children: [{ content: [{ type: "text", text: content }] }],
238
+ properties
239
+ });
240
+ }
241
+ /** Get the count of body elements written so far. */
242
+ get elementCount() {
243
+ return this._elementCount;
244
+ }
245
+ /**
246
+ * Finalize the document.
247
+ *
248
+ * - Without `options.sink`: returns the assembled `Uint8Array`
249
+ * containing the full DOCX file.
250
+ * - With `options.sink`: drains any pending sink writes, calls
251
+ * `sink.end()`, and resolves to a zero-length `Uint8Array`. The
252
+ * DOCX bytes have already been delivered to the sink — the empty
253
+ * return is a sentinel signalling "writer is done; consumer keeps
254
+ * the data".
255
+ */
256
+ async finalize() {
257
+ if (this._finalized) {
258
+ throw new DocxWriteError("StreamingDocxWriter: already finalized");
259
+ }
260
+ this._finalized = true;
261
+ if (this._onProgress) {
262
+ this._onProgress({ elementsWritten: this._elementCount, phase: "finalizing" });
263
+ }
264
+ // If no elements were added, still write a minimal document
265
+ if (!this._headerWritten) {
266
+ this._writeDocumentHeader();
267
+ }
268
+ // Allocate header/footer rIds NOW so the section properties we render
269
+ // into document.xml can use the same rIds the auxiliary parts will
270
+ // register later. Without this the section refs and the .rels file
271
+ // would disagree and Word treats the references as dangling.
272
+ this._allocateHeaderFooterRIds();
273
+ // Write document.xml footer (close </w:body></w:document>)
274
+ this._writeDocumentFooter();
275
+ // End the document.xml stream → finalizes its ZIP entry
276
+ await this._endStream(this._documentStream);
277
+ // Add all auxiliary parts (styles, settings, etc.)
278
+ await this._addAuxiliaryParts();
279
+ // Finalize the ZIP archive. Any compression errors during the trailing
280
+ // central-directory write are reported via the `Zip` callback into
281
+ // `_streamError`; surface them as a rejection.
282
+ this._zip.end();
283
+ // In sink mode the Zip callback queued every chunk onto _pendingDrain;
284
+ // wait for that promise chain to complete before declaring the writer
285
+ // finished. In buffered mode this is a no-op (resolved promise).
286
+ await this._pendingDrain;
287
+ if (this._streamError) {
288
+ throw new DocxWriteError(`StreamingDocxWriter: ZIP finalization failed (${this._streamError.message})`, { cause: this._streamError });
289
+ }
290
+ if (this._sinkAdapter) {
291
+ // Close the sink so the consumer knows the byte stream is complete.
292
+ // Errors raised during close (e.g. underlying file system) propagate.
293
+ await this._sinkAdapter.end();
294
+ return EMPTY_U8;
295
+ }
296
+ // Buffered mode: assemble and return the DOCX bytes.
297
+ return this._assembleOutput();
298
+ }
299
+ /** Reset the writer for reuse. */
300
+ /**
301
+ * Reset the writer for reuse.
302
+ *
303
+ * Throws when the writer was constructed with an `options.sink`: a
304
+ * sink can only be `end()`ed once, so reusing the same writer would
305
+ * produce an undefined byte stream. Construct a new writer (with a
306
+ * new sink) for each document instead.
307
+ */
308
+ reset() {
309
+ if (this._sinkAdapter) {
310
+ throw new DocxWriteError("StreamingDocxWriter: reset() is not supported in sink mode; create a new writer instance per document.");
311
+ }
312
+ this._elementCount = 0;
313
+ this._finalized = false;
314
+ this._headerWritten = false;
315
+ this._prevWasTable = false;
316
+ this._outputChunks = [];
317
+ this._bodyCharts.length = 0;
318
+ this._bodyChartEx.length = 0;
319
+ this._nextChartSeq = 0;
320
+ this._nextChartExSeq = 0;
321
+ this._registeredImageRIds.clear();
322
+ this._headerKeyToRid.clear();
323
+ this._footerKeyToRid.clear();
324
+ this._watermarkHeaderRid = undefined;
325
+ // _registeredHyperlinks is a WeakSet; old entries become unreachable
326
+ // along with the body model objects they referenced — no manual clear
327
+ // is necessary. _chartNum is a WeakMap with the same property.
328
+ this._initZip();
329
+ return this;
330
+ }
331
+ // ===========================================================================
332
+ // Private: ZIP infrastructure
333
+ // ===========================================================================
334
+ _initZip() {
335
+ this._outputChunks = [];
336
+ this._streamError = null;
337
+ this._pendingDrain = Promise.resolve();
338
+ if (this._options.sink && !this._sinkAdapter) {
339
+ this._sinkAdapter = new SinkAdapter(this._options.sink);
340
+ }
341
+ this._documentRels = createRelationships();
342
+ this._renderCtx = createRenderContext({
343
+ securityPolicy: this._options.securityPolicy,
344
+ chartRIds: new Map(),
345
+ imageRIdRemap: new Map(),
346
+ hyperlinkRIds: new WeakMap()
347
+ });
348
+ this._zip = new Zip((err, data, _final) => {
349
+ // The ZIP callback reports compression / framing errors out-of-band.
350
+ // Capture only the first error; subsequent callbacks may still be
351
+ // dispatched as the pipeline drains. Surfaced from `finalize()`.
352
+ if (err && !this._streamError) {
353
+ this._streamError = err;
354
+ // Wake up any pending `_endStream` waiter so callers don't hang.
355
+ this._documentStream?.emit("error", err);
356
+ }
357
+ if (data && data.length > 0) {
358
+ if (this._sinkAdapter) {
359
+ // The Zip callback runs synchronously and cannot await, so we
360
+ // chain each sink write onto a single drain promise. Producers
361
+ // either:
362
+ // (a) call `addAsync()` / `finalize()` which await the chain,
363
+ // (b) ignore backpressure and let chunks queue in memory until
364
+ // the next await point, capped by the sink's own queueing.
365
+ // First-error capture: a rejected write is collapsed into
366
+ // `_streamError` so subsequent writes are skipped quickly.
367
+ this._pendingDrain = this._pendingDrain.then(() => {
368
+ if (this._streamError) {
369
+ return;
370
+ }
371
+ return this._sinkAdapter.write(data).catch((e) => {
372
+ if (!this._streamError) {
373
+ this._streamError = e instanceof Error ? e : new Error(String(e));
374
+ }
375
+ });
376
+ });
377
+ }
378
+ else {
379
+ this._outputChunks.push(data);
380
+ }
381
+ }
382
+ });
383
+ // Create the document.xml ZIP entry and stream
384
+ const level = this._options.compressionLevel ?? 6;
385
+ this._documentZipFile = new ZipDeflate(PartPath.Document, { level });
386
+ this._zip.add(this._documentZipFile);
387
+ this._documentStream = new StreamBuf({ bufSize: 65536 });
388
+ this._documentStream.on("data", (chunk) => {
389
+ this._documentZipFile.push(chunk);
390
+ });
391
+ this._documentStream.once("finish", () => {
392
+ this._documentZipFile.push(EMPTY_U8, true);
393
+ this._documentStream.emit("zipped");
394
+ });
395
+ }
396
+ _write(text) {
397
+ this._xmlBuffer.reset();
398
+ this._xmlBuffer.addText(text);
399
+ this._documentStream.write(this._xmlBuffer);
400
+ }
401
+ // ===========================================================================
402
+ // Private: Document XML generation
403
+ // ===========================================================================
404
+ _writeDocumentHeader() {
405
+ // XML declaration
406
+ let header = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`;
407
+ header += `<w:document`;
408
+ for (const [key, value] of Object.entries(DOCUMENT_NAMESPACES)) {
409
+ header += ` ${key}="${value}"`;
410
+ }
411
+ header += `>`;
412
+ // Background
413
+ if (this._options.background) {
414
+ const bg = this._options.background;
415
+ header += `<w:background w:color="${xmlEncodeAttr(bg.color ?? "FFFFFF")}"`;
416
+ if (bg.themeColor) {
417
+ header += ` w:themeColor="${xmlEncodeAttr(bg.themeColor)}"`;
418
+ }
419
+ header += `/>`;
420
+ }
421
+ header += `<w:body>`;
422
+ this._write(header);
423
+ }
424
+ _writeBodyElement(element) {
425
+ // Serialize a single body element using the shared renderBodyContent
426
+ // function. We pass the writer's accumulated render context so r:embed,
427
+ // chart and hyperlink rIds resolve correctly. Without this, charts throw
428
+ // "Chart content was not registered with a relationship id" and hyperlink
429
+ // / image references would be missing or wrong.
430
+ const writer = new XmlWriter();
431
+ renderBodyContent(writer, element, this._renderCtx);
432
+ this._write(writer.xml);
433
+ }
434
+ /**
435
+ * Emit an empty `<w:p/>` to separate two adjacent tables. Required by
436
+ * ECMA-376 §17.13.5.34 — Word rejects packages where two `<w:tbl>`
437
+ * elements appear without a paragraph between them.
438
+ */
439
+ _writeSeparatorParagraph() {
440
+ this._write("<w:p/>");
441
+ }
442
+ /**
443
+ * Scan a single body element and register any chart / hyperlink / image
444
+ * references it introduces against the writer's accumulated state. This
445
+ * must run before the element is serialized so the render context already
446
+ * carries the relationships the renderer will look up.
447
+ */
448
+ _registerElementReferences(element) {
449
+ // Direct top-level chart entries
450
+ if (element.type === "chart") {
451
+ this._registerChart(element);
452
+ return;
453
+ }
454
+ if (element.type === "chartEx") {
455
+ this._registerChartEx(element);
456
+ return;
457
+ }
458
+ // For paragraph-like containers we descend with the shared walker so
459
+ // track-change wrappers (InsertedRun / MovedToRun / hyperlink children)
460
+ // are also covered.
461
+ if (element.type === "paragraph" ||
462
+ element.type === "table" ||
463
+ element.type === "sdt" ||
464
+ element.type === "textBox") {
465
+ walkBlocks([element], {
466
+ enterParagraph: para => {
467
+ this._registerParagraphReferences(para);
468
+ },
469
+ enterRun: run => {
470
+ for (const c of run.content) {
471
+ if (c.type === "image" && c.rId) {
472
+ this._registerImageRId(c.rId);
473
+ if (c.svgRId) {
474
+ this._registerImageRId(c.svgRId);
475
+ }
476
+ }
477
+ }
478
+ },
479
+ enterHyperlink: h => {
480
+ this._registerHyperlink(h);
481
+ }
482
+ });
483
+ return;
484
+ }
485
+ if (element.type === "floatingImage" && element.rId) {
486
+ this._registerImageRId(element.rId);
487
+ if (element.svgRId) {
488
+ this._registerImageRId(element.svgRId);
489
+ }
490
+ }
491
+ }
492
+ _registerParagraphReferences(_para) {
493
+ // Per-paragraph property registration is not needed today — image and
494
+ // hyperlink registration is handled by enterRun / enterHyperlink. This
495
+ // hook exists so future paragraph-level relationships (numPicBullet,
496
+ // tabLeader image, …) can be added without changing call sites.
497
+ }
498
+ _registerChart(chart) {
499
+ if (this._renderCtx.chartRIds.has(chart)) {
500
+ return;
501
+ }
502
+ const num = ++this._nextChartSeq;
503
+ const rId = addRelationship(this._documentRels, RelType.Chart, `charts/chart${num}.xml`);
504
+ this._renderCtx.chartRIds.set(chart, rId);
505
+ this._chartNum.set(chart, num);
506
+ this._bodyCharts.push(chart);
507
+ }
508
+ _registerChartEx(chart) {
509
+ if (this._renderCtx.chartRIds.has(chart)) {
510
+ return;
511
+ }
512
+ const num = ++this._nextChartExSeq;
513
+ const rId = addRelationship(this._documentRels, RelType.ChartEx, `charts/chartEx${num}.xml`);
514
+ this._renderCtx.chartRIds.set(chart, rId);
515
+ this._chartNum.set(chart, num);
516
+ this._bodyChartEx.push(chart);
517
+ }
518
+ _registerHyperlink(h) {
519
+ if (!h.url || h.rId || this._registeredHyperlinks.has(h)) {
520
+ return;
521
+ }
522
+ // Drop dangerous schemes (javascript:, vbscript:, data:, file:, …) before
523
+ // they reach document.xml.rels. Mark the link as registered either way so
524
+ // we don't keep re-evaluating it on every flush.
525
+ const safe = sanitizeUrl(h.url);
526
+ if (!safe) {
527
+ this._registeredHyperlinks.add(h);
528
+ return;
529
+ }
530
+ const rId = addRelationship(this._documentRels, RelType.Hyperlink, safe, "External");
531
+ this._renderCtx.hyperlinkRIds.set(h, rId);
532
+ this._registeredHyperlinks.add(h);
533
+ }
534
+ _registerImageRId(rId) {
535
+ if (this._registeredImageRIds.has(rId)) {
536
+ return;
537
+ }
538
+ const img = this._lookupImage(rId);
539
+ if (!img) {
540
+ // Image reference points at a binary the caller did not provide. The
541
+ // previous behaviour was to silently skip and emit an invalid DOCX —
542
+ // see the policy field on StreamingDocxOptions.
543
+ const policy = this._options.missingImagePolicy ?? "throw";
544
+ if (policy === "warn") {
545
+ console.warn(`[StreamingDocxWriter] image rId "${rId}" referenced by content ` +
546
+ `but not present in options.images. Output will be missing this ` +
547
+ `relationship and may not open in Word.`);
548
+ return;
549
+ }
550
+ throw new DocxWriteError(`Streaming writer: image rId "${rId}" referenced by content but ` +
551
+ `not present in options.images. Add the image to options.images, ` +
552
+ `remove the reference, or set missingImagePolicy: "warn" to ` +
553
+ `accept a broken document.`);
554
+ }
555
+ addRelationshipWithId(this._documentRels, rId, RelType.Image, `media/${img.fileName}`);
556
+ this._registeredImageRIds.add(rId);
557
+ }
558
+ _lookupImage(rId) {
559
+ if (!this._options.images) {
560
+ return undefined;
561
+ }
562
+ for (const img of this._options.images) {
563
+ if (img.rId === rId) {
564
+ return img;
565
+ }
566
+ // Round-tripped models may surface alias rIds populated by the
567
+ // reader for header/footer-local references that pointed at the
568
+ // same physical media file. Match those too so a header that uses
569
+ // its own rId still resolves to the binary.
570
+ if (img.aliasRIds && img.aliasRIds.includes(rId)) {
571
+ return img;
572
+ }
573
+ }
574
+ return undefined;
575
+ }
576
+ _writeDocumentFooter() {
577
+ // Word rejects a `<w:body/>` that contains no `<w:p>`. Synthesise an
578
+ // empty paragraph when the caller streamed zero elements so the
579
+ // package opens cleanly. (Bulk packager handles this implicitly via
580
+ // `Document.build`'s default body element list.)
581
+ if (this._elementCount === 0) {
582
+ this._write("<w:p/>");
583
+ }
584
+ // Write final section properties if provided. Header/footer references
585
+ // are rewritten so they refer to the rIds we just allocated in
586
+ // `_allocateHeaderFooterRIds`. References whose target type cannot
587
+ // be resolved (e.g. a custom rId for a header that isn't in the
588
+ // options map) are dropped rather than emitted dangling.
589
+ const sectIn = this._options.sectionProperties;
590
+ let sect = sectIn ? this._rewireSectionRefs(sectIn) : undefined;
591
+ // Auto-fill: if the caller provided headers/footers but no section
592
+ // references, synthesize one per type. Mirrors what the bulk
593
+ // packager does for builder-style usage.
594
+ if (this._options.headers &&
595
+ this._options.headers.size > 0 &&
596
+ (!sect?.headers || sect.headers.length === 0)) {
597
+ const synth = this._synthesizeHeaderRefs();
598
+ if (synth.length > 0) {
599
+ sect = { ...(sect ?? {}), headers: synth };
600
+ }
601
+ }
602
+ if (this._options.footers &&
603
+ this._options.footers.size > 0 &&
604
+ (!sect?.footers || sect.footers.length === 0)) {
605
+ const synth = this._synthesizeFooterRefs();
606
+ if (synth.length > 0) {
607
+ sect = { ...(sect ?? {}), footers: synth };
608
+ }
609
+ }
610
+ // Watermark always needs its own header reference, but Word resolves
611
+ // multiple `<w:headerReference w:type="default">` children
612
+ // implementation-defined, so we replace any existing default-type
613
+ // ref instead of stacking them. (User-supplied first/even refs stay.)
614
+ if (this._watermarkHeaderRid) {
615
+ const headers = sect?.headers ? [...sect.headers] : [];
616
+ const filtered = headers.filter(h => h.type !== "default");
617
+ filtered.push({ type: "default", rId: this._watermarkHeaderRid });
618
+ sect = { ...(sect ?? {}), headers: filtered };
619
+ }
620
+ if (sect) {
621
+ const writer = new XmlWriter();
622
+ renderSectionProperties(writer, sect);
623
+ this._write(writer.xml);
624
+ }
625
+ else {
626
+ // OOXML CT_Body requires a final <w:sectPr> so Word knows the page
627
+ // geometry. When the caller didn't provide one, fall back to the
628
+ // same default that Document.build() uses (US Letter, 1" margins).
629
+ const writer = new XmlWriter();
630
+ renderSectionProperties(writer, {
631
+ pageSize: { width: 12240, height: 15840 },
632
+ margins: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
633
+ });
634
+ this._write(writer.xml);
635
+ }
636
+ // Close body and document
637
+ this._write(`</w:body></w:document>`);
638
+ }
639
+ /**
640
+ * Allocate header/footer relationship IDs deterministically (in the same
641
+ * order auxiliary parts will be emitted). Called once during finalize so
642
+ * `_writeDocumentFooter` and `_addAuxiliaryParts` agree on which rId
643
+ * points at which header/footer XML part.
644
+ */
645
+ _allocateHeaderFooterRIds() {
646
+ if (this._options.headers) {
647
+ let idx = 1;
648
+ for (const [key] of this._options.headers) {
649
+ const rId = addRelationship(this._documentRels, RelType.Header, `header${idx}.xml`);
650
+ this._headerKeyToRid.set(key, rId);
651
+ idx++;
652
+ }
653
+ // Watermark consumes the next header slot.
654
+ if (this._options.watermark) {
655
+ this._watermarkHeaderRid = addRelationship(this._documentRels, RelType.Header, `header${idx}.xml`);
656
+ }
657
+ }
658
+ else if (this._options.watermark) {
659
+ this._watermarkHeaderRid = addRelationship(this._documentRels, RelType.Header, "header1.xml");
660
+ }
661
+ if (this._options.footers) {
662
+ let idx = 1;
663
+ for (const [key] of this._options.footers) {
664
+ const rId = addRelationship(this._documentRels, RelType.Footer, `footer${idx}.xml`);
665
+ this._footerKeyToRid.set(key, rId);
666
+ idx++;
667
+ }
668
+ }
669
+ }
670
+ _rewireSectionRefs(sect) {
671
+ const allowedHeader = new Set(this._headerKeyToRid.values());
672
+ const allowedFooter = new Set(this._footerKeyToRid.values());
673
+ const resolveByTypeHeader = (type) => {
674
+ // Try direct map key match first (e.g. user passed map key === rId).
675
+ // Then fall back to a same-type lookup for the common builder case
676
+ // where keys are "default" / "first" / "even".
677
+ if (this._headerKeyToRid.has(type)) {
678
+ return this._headerKeyToRid.get(type);
679
+ }
680
+ return undefined;
681
+ };
682
+ const resolveByTypeFooter = (type) => {
683
+ if (this._footerKeyToRid.has(type)) {
684
+ return this._footerKeyToRid.get(type);
685
+ }
686
+ return undefined;
687
+ };
688
+ let out = sect;
689
+ if (sect.headers) {
690
+ const resolved = [];
691
+ for (const ref of sect.headers) {
692
+ if (ref.rId && allowedHeader.has(ref.rId)) {
693
+ resolved.push(ref);
694
+ continue;
695
+ }
696
+ if (ref.rId && this._headerKeyToRid.has(ref.rId)) {
697
+ resolved.push({ ...ref, rId: this._headerKeyToRid.get(ref.rId) });
698
+ continue;
699
+ }
700
+ const byType = resolveByTypeHeader(ref.type);
701
+ if (byType) {
702
+ resolved.push({ ...ref, rId: byType });
703
+ }
704
+ // else drop — no matching part part, do not emit dangling rId.
705
+ }
706
+ if (resolved.length !== sect.headers.length ||
707
+ resolved.some((r, i) => r !== sect.headers[i])) {
708
+ out = { ...out, headers: resolved };
709
+ }
710
+ }
711
+ if (sect.footers) {
712
+ const resolved = [];
713
+ for (const ref of sect.footers) {
714
+ if (ref.rId && allowedFooter.has(ref.rId)) {
715
+ resolved.push(ref);
716
+ continue;
717
+ }
718
+ if (ref.rId && this._footerKeyToRid.has(ref.rId)) {
719
+ resolved.push({ ...ref, rId: this._footerKeyToRid.get(ref.rId) });
720
+ continue;
721
+ }
722
+ const byType = resolveByTypeFooter(ref.type);
723
+ if (byType) {
724
+ resolved.push({ ...ref, rId: byType });
725
+ }
726
+ }
727
+ if (resolved.length !== sect.footers.length ||
728
+ resolved.some((r, i) => r !== sect.footers[i])) {
729
+ out = { ...out, footers: resolved };
730
+ }
731
+ }
732
+ return out;
733
+ }
734
+ /**
735
+ * Synthesise section-property header references for every header part
736
+ * the caller registered. Recognised type keys (`default`/`first`/`even`)
737
+ * keep their semantics; any other key (round-tripped rId names from
738
+ * readDocx, custom strings) falls back to `"default"` so the header is
739
+ * actually referenced — without this fallback header parts can sit in
740
+ * the package as dangling content.
741
+ *
742
+ * If multiple keys map to the same logical type, only the first one is
743
+ * kept so we don't emit two `<w:headerReference w:type="default">`
744
+ * children (Word's behaviour with duplicates is implementation-defined).
745
+ */
746
+ _synthesizeHeaderRefs() {
747
+ const out = [];
748
+ const seenTypes = new Set();
749
+ for (const [key, rId] of this._headerKeyToRid) {
750
+ const type = key === "default" || key === "first" || key === "even" ? key : "default";
751
+ if (seenTypes.has(type)) {
752
+ continue;
753
+ }
754
+ seenTypes.add(type);
755
+ out.push({ type, rId });
756
+ }
757
+ return out;
758
+ }
759
+ _synthesizeFooterRefs() {
760
+ const out = [];
761
+ const seenTypes = new Set();
762
+ for (const [key, rId] of this._footerKeyToRid) {
763
+ const type = key === "default" || key === "first" || key === "even" ? key : "default";
764
+ if (seenTypes.has(type)) {
765
+ continue;
766
+ }
767
+ seenTypes.add(type);
768
+ out.push({ type, rId });
769
+ }
770
+ return out;
771
+ }
772
+ // ===========================================================================
773
+ // Private: Auxiliary parts
774
+ // ===========================================================================
775
+ async _addAuxiliaryParts() {
776
+ const level = this._options.compressionLevel ?? 6;
777
+ // Helper: add a complete XML file to the ZIP
778
+ const addXmlFile = (path, renderFn) => {
779
+ const writer = new XmlWriter();
780
+ renderFn(writer);
781
+ const data = utf8Encoder.encode(writer.xml);
782
+ const file = new ZipDeflate(path, { level });
783
+ this._zip.add(file);
784
+ file.push(data, true);
785
+ };
786
+ // Content types and relationships
787
+ const contentTypes = createContentTypes();
788
+ const packageRels = createRelationships();
789
+ // Reuse the document relationships state we have been populating during
790
+ // add() (charts, hyperlinks, images). Adding the standard parts below
791
+ // augments this state.
792
+ const documentRels = this._documentRels;
793
+ // Package relationships
794
+ addRelationship(packageRels, RelType.OfficeDocument, "word/document.xml");
795
+ addRelationship(packageRels, RelType.CoreProperties, "docProps/core.xml");
796
+ addRelationship(packageRels, RelType.ExtendedProperties, "docProps/app.xml");
797
+ // [Content_Types].xml MUST declare every part. The package
798
+ // relationships file references docProps/core.xml + docProps/app.xml
799
+ // even when the caller didn't supply explicit metadata, so we must
800
+ // register their content types up-front; otherwise Word/LibreOffice
801
+ // refuse to open the file (rejected at the OPC layer before any
802
+ // schema validation).
803
+ addContentTypeOverride(contentTypes, `/${PartPath.CoreProps}`, ContentType.CoreProperties);
804
+ addContentTypeOverride(contentTypes, `/${PartPath.AppProps}`, ContentType.ExtendedProperties);
805
+ // Document relationships
806
+ addRelationship(documentRels, RelType.Styles, "styles.xml");
807
+ addRelationship(documentRels, RelType.Settings, "settings.xml");
808
+ addRelationship(documentRels, RelType.FontTable, "fontTable.xml");
809
+ addRelationship(documentRels, RelType.Theme, "theme/theme1.xml");
810
+ // Numbering
811
+ const hasNumbering = (this._options.abstractNumberings && this._options.abstractNumberings.length > 0) ||
812
+ (this._options.numberingInstances && this._options.numberingInstances.length > 0);
813
+ if (hasNumbering) {
814
+ addRelationship(documentRels, RelType.Numbering, "numbering.xml");
815
+ }
816
+ // Footnotes — including their own .rels for in-note hyperlinks/images.
817
+ if (this._options.footnotes && this._options.footnotes.length > 0) {
818
+ addRelationship(documentRels, RelType.Footnotes, "footnotes.xml");
819
+ addContentTypeOverride(contentTypes, `/${PartPath.Footnotes}`, ContentType.Footnotes);
820
+ const fnRels = createRelationships();
821
+ const fnLinks = collectHyperlinksFromNotes(this._options.footnotes);
822
+ for (const link of fnLinks) {
823
+ if (link.url) {
824
+ const safe = sanitizeUrl(link.url);
825
+ if (!safe) {
826
+ continue;
827
+ }
828
+ const linkRId = addRelationship(fnRels, RelType.Hyperlink, safe, "External");
829
+ this._renderCtx.hyperlinkRIds.set(link, linkRId);
830
+ }
831
+ }
832
+ const fnImgs = collectImageRidsFromNotes(this._options.footnotes);
833
+ for (const oldRid of fnImgs) {
834
+ const img = this._lookupImage(oldRid);
835
+ if (img) {
836
+ addRelationshipWithId(fnRels, oldRid, RelType.Image, `media/${img.fileName}`);
837
+ }
838
+ }
839
+ if (getRelationshipCount(fnRels) > 0) {
840
+ addXmlFile(`word/_rels/footnotes.xml.rels`, xml => renderRelationships(fnRels, xml));
841
+ }
842
+ // Footnote XML rendering itself happens in buildCommonAuxiliaryParts.
843
+ }
844
+ // Endnotes — same treatment as footnotes.
845
+ if (this._options.endnotes && this._options.endnotes.length > 0) {
846
+ addRelationship(documentRels, RelType.Endnotes, "endnotes.xml");
847
+ addContentTypeOverride(contentTypes, `/${PartPath.Endnotes}`, ContentType.Endnotes);
848
+ const enRels = createRelationships();
849
+ const enLinks = collectHyperlinksFromNotes(this._options.endnotes);
850
+ for (const link of enLinks) {
851
+ if (link.url) {
852
+ const safe = sanitizeUrl(link.url);
853
+ if (!safe) {
854
+ continue;
855
+ }
856
+ const linkRId = addRelationship(enRels, RelType.Hyperlink, safe, "External");
857
+ this._renderCtx.hyperlinkRIds.set(link, linkRId);
858
+ }
859
+ }
860
+ const enImgs = collectImageRidsFromNotes(this._options.endnotes);
861
+ for (const oldRid of enImgs) {
862
+ const img = this._lookupImage(oldRid);
863
+ if (img) {
864
+ addRelationshipWithId(enRels, oldRid, RelType.Image, `media/${img.fileName}`);
865
+ }
866
+ }
867
+ if (getRelationshipCount(enRels) > 0) {
868
+ addXmlFile(`word/_rels/endnotes.xml.rels`, xml => renderRelationships(enRels, xml));
869
+ }
870
+ }
871
+ // Comments — including their own .rels for in-comment hyperlinks/images.
872
+ if (this._options.comments && this._options.comments.length > 0) {
873
+ addRelationship(documentRels, RelType.Comments, "comments.xml");
874
+ addContentTypeOverride(contentTypes, `/${PartPath.Comments}`, ContentType.Comments);
875
+ // Register hyperlink/image rels BEFORE rendering comments.xml so the
876
+ // emitted r:id values match the per-part .rels we are about to write.
877
+ const cmtRels = createRelationships();
878
+ const commentBodies = this._options.comments.map(c => ({ content: c.content }));
879
+ const cmtLinks = collectHyperlinksFromNotes(commentBodies);
880
+ for (const link of cmtLinks) {
881
+ if (link.url) {
882
+ const safe = sanitizeUrl(link.url);
883
+ if (!safe) {
884
+ continue;
885
+ }
886
+ const linkRId = addRelationship(cmtRels, RelType.Hyperlink, safe, "External");
887
+ this._renderCtx.hyperlinkRIds.set(link, linkRId);
888
+ }
889
+ }
890
+ const cmtImgs = collectImageRidsFromNotes(commentBodies);
891
+ for (const oldRid of cmtImgs) {
892
+ const img = this._lookupImage(oldRid);
893
+ if (img) {
894
+ addRelationshipWithId(cmtRels, oldRid, RelType.Image, `media/${img.fileName}`);
895
+ }
896
+ }
897
+ if (getRelationshipCount(cmtRels) > 0) {
898
+ addXmlFile(`word/_rels/comments.xml.rels`, xml => renderRelationships(cmtRels, xml));
899
+ }
900
+ addXmlFile(PartPath.Comments, xml => renderComments(xml, this._options.comments, {
901
+ imageRemap: this._renderCtx.imageRIdRemap,
902
+ hyperlinkRIds: this._renderCtx.hyperlinkRIds,
903
+ rawXmlPolicy: this._renderCtx.rawXmlPolicy
904
+ }));
905
+ // Also write commentsExtended if any have done/parentId
906
+ const hasExtended = this._options.comments.some(c => c.done != null || c.parentId != null);
907
+ if (hasExtended) {
908
+ addRelationship(documentRels, RelType.CommentsExtended, "commentsExtended.xml");
909
+ addContentTypeOverride(contentTypes, `/${PartPath.CommentsExtended}`, ContentType.CommentsExtended);
910
+ addXmlFile(PartPath.CommentsExtended, xml => renderCommentsExtended(xml, this._options.comments));
911
+ }
912
+ }
913
+ // Headers
914
+ //
915
+ // Each header part has its own .rels file. Image / hyperlink / chart
916
+ // references inside header content must register against THAT part's
917
+ // .rels — they are not document.xml.rels relationships, so we mirror
918
+ // the bulk packager's behaviour here to avoid producing dangling
919
+ // r:embed / r:id values inside header XML.
920
+ //
921
+ // The document-level rId for each header was already allocated during
922
+ // `_allocateHeaderFooterRIds` so that section properties and header
923
+ // parts agree.
924
+ let nextHeaderIdx = 1;
925
+ if (this._options.headers) {
926
+ for (const [, headerDef] of this._options.headers) {
927
+ const headerIdx = nextHeaderIdx++;
928
+ const headerPath = PartPath.header(headerIdx);
929
+ addContentTypeOverride(contentTypes, `/${headerPath}`, ContentType.Header);
930
+ // Register relationships BEFORE rendering the header XML, otherwise
931
+ // the writer cannot resolve the freshly-allocated hyperlink rIds and
932
+ // emits dangling r:id values. addXmlFile() invokes the render
933
+ // callback synchronously, so the order matters.
934
+ const hRels = createRelationships();
935
+ // Images: register every rId referenced inside this header that the
936
+ // caller supplied a binary for. Header XML emits `r:embed` using the
937
+ // model rId, so we register under the same id.
938
+ const imgRids = collectImageRidsFromContent(headerDef.content);
939
+ for (const oldRid of imgRids) {
940
+ const img = this._lookupImage(oldRid);
941
+ if (img) {
942
+ addRelationshipWithId(hRels, oldRid, RelType.Image, `media/${img.fileName}`);
943
+ }
944
+ }
945
+ // Hyperlinks: same scheme as bulk packager — assign a fresh rId per
946
+ // header for any URL-bearing hyperlink and surface it via
947
+ // hyperlinkRIds so the writer emits matching r:id.
948
+ const hLinks = collectHyperlinksFromHeaderFooter(headerDef.content);
949
+ for (const link of hLinks) {
950
+ if (link.url) {
951
+ const safe = sanitizeUrl(link.url);
952
+ if (!safe) {
953
+ continue;
954
+ }
955
+ const linkRId = addRelationship(hRels, RelType.Hyperlink, safe, "External");
956
+ this._renderCtx.hyperlinkRIds.set(link, linkRId);
957
+ }
958
+ }
959
+ // Charts: collect into _bodyCharts so a chart part is generated, and
960
+ // register the rel against the header's own .rels.
961
+ const headerCharts = [];
962
+ collectChartsFromHeaderFooter(headerDef.content, headerCharts);
963
+ for (const chartContent of headerCharts) {
964
+ if (this._renderCtx.chartRIds.has(chartContent)) {
965
+ continue;
966
+ }
967
+ const num = ++this._nextChartSeq;
968
+ const rId = addRelationship(hRels, RelType.Chart, `charts/chart${num}.xml`);
969
+ this._renderCtx.chartRIds.set(chartContent, rId);
970
+ this._chartNum.set(chartContent, num);
971
+ this._bodyCharts.push(chartContent);
972
+ }
973
+ addXmlFile(headerPath, xml => renderHeader(xml, headerDef.content, {
974
+ imageRemap: this._renderCtx.imageRIdRemap,
975
+ hyperlinkRIds: this._renderCtx.hyperlinkRIds,
976
+ rawXmlPolicy: this._renderCtx.rawXmlPolicy
977
+ }));
978
+ if (getRelationshipCount(hRels) > 0) {
979
+ addXmlFile(`word/_rels/header${headerIdx}.xml.rels`, xml => renderRelationships(hRels, xml));
980
+ }
981
+ }
982
+ }
983
+ // Watermark — always rendered as its own header part appended after any
984
+ // user-supplied headers. Its rId was allocated during
985
+ // `_allocateHeaderFooterRIds`.
986
+ if (this._options.watermark) {
987
+ const watermarkIdx = nextHeaderIdx++;
988
+ const watermarkPath = PartPath.header(watermarkIdx);
989
+ addContentTypeOverride(contentTypes, `/${watermarkPath}`, ContentType.Header);
990
+ addXmlFile(watermarkPath, xml => renderWatermarkHeader(xml, this._options.watermark));
991
+ // Image watermarks need a per-header relationship to the image binary.
992
+ if (this._options.watermark.type === "image") {
993
+ const wmRId = this._options.watermark.rId;
994
+ const img = this._lookupImage(wmRId);
995
+ if (img) {
996
+ const wmRels = createRelationships();
997
+ addRelationshipWithId(wmRels, wmRId, RelType.Image, `media/${img.fileName}`);
998
+ addXmlFile(`word/_rels/header${watermarkIdx}.xml.rels`, xml => renderRelationships(wmRels, xml));
999
+ }
1000
+ }
1001
+ }
1002
+ // Footers — document-level rIds already allocated during
1003
+ // `_allocateHeaderFooterRIds`.
1004
+ if (this._options.footers) {
1005
+ let footerIdx = 1;
1006
+ for (const [, footerDef] of this._options.footers) {
1007
+ const footerPath = PartPath.footer(footerIdx);
1008
+ addContentTypeOverride(contentTypes, `/${footerPath}`, ContentType.Footer);
1009
+ // Register relationships BEFORE rendering. addXmlFile() runs the
1010
+ // callback synchronously so any hyperlink rIds the renderer needs
1011
+ // must already be in this._renderCtx.hyperlinkRIds.
1012
+ const fRels = createRelationships();
1013
+ const imgRids = collectImageRidsFromContent(footerDef.content);
1014
+ for (const oldRid of imgRids) {
1015
+ const img = this._lookupImage(oldRid);
1016
+ if (img) {
1017
+ addRelationshipWithId(fRels, oldRid, RelType.Image, `media/${img.fileName}`);
1018
+ }
1019
+ }
1020
+ const fLinks = collectHyperlinksFromHeaderFooter(footerDef.content);
1021
+ for (const link of fLinks) {
1022
+ if (link.url) {
1023
+ const safe = sanitizeUrl(link.url);
1024
+ if (!safe) {
1025
+ continue;
1026
+ }
1027
+ const linkRId = addRelationship(fRels, RelType.Hyperlink, safe, "External");
1028
+ this._renderCtx.hyperlinkRIds.set(link, linkRId);
1029
+ }
1030
+ }
1031
+ const footerCharts = [];
1032
+ collectChartsFromHeaderFooter(footerDef.content, footerCharts);
1033
+ for (const chartContent of footerCharts) {
1034
+ if (this._renderCtx.chartRIds.has(chartContent)) {
1035
+ continue;
1036
+ }
1037
+ const num = ++this._nextChartSeq;
1038
+ const rId = addRelationship(fRels, RelType.Chart, `charts/chart${num}.xml`);
1039
+ this._renderCtx.chartRIds.set(chartContent, rId);
1040
+ this._chartNum.set(chartContent, num);
1041
+ this._bodyCharts.push(chartContent);
1042
+ }
1043
+ addXmlFile(footerPath, xml => renderFooter(xml, footerDef.content, {
1044
+ imageRemap: this._renderCtx.imageRIdRemap,
1045
+ hyperlinkRIds: this._renderCtx.hyperlinkRIds,
1046
+ rawXmlPolicy: this._renderCtx.rawXmlPolicy
1047
+ }));
1048
+ if (getRelationshipCount(fRels) > 0) {
1049
+ addXmlFile(`word/_rels/footer${footerIdx}.xml.rels`, xml => renderRelationships(fRels, xml));
1050
+ }
1051
+ footerIdx++;
1052
+ }
1053
+ }
1054
+ // Custom properties
1055
+ if (this._options.customProperties && this._options.customProperties.length > 0) {
1056
+ addRelationship(packageRels, RelType.CustomProperties, "docProps/custom.xml");
1057
+ addContentTypeOverride(contentTypes, `/${PartPath.CustomProps}`, ContentType.CustomProperties);
1058
+ // XML rendering handled by buildCommonAuxiliaryParts below
1059
+ }
1060
+ // Images. Only register images here that were not already registered
1061
+ // by `_registerImageRId` during add(). For round-tripped models, the
1062
+ // image's `aliasRIds` may have been registered earlier (when a
1063
+ // header/footer body referenced the image under one of those alias
1064
+ // names) — treat any of those aliases as "already registered" so we
1065
+ // don't duplicate the relationship under the canonical rId. Images
1066
+ // supplied via options but never referenced in body content also get
1067
+ // registered (since the user clearly intended them to be part of the
1068
+ // document) but with an anonymous rId.
1069
+ if (this._options.images) {
1070
+ const extensions = new Set();
1071
+ for (const img of this._options.images) {
1072
+ const ext = getFileExt(img.fileName);
1073
+ if (ext) {
1074
+ extensions.add(ext);
1075
+ }
1076
+ const alreadyRegistered = (img.rId && this._registeredImageRIds.has(img.rId)) ||
1077
+ (img.aliasRIds && img.aliasRIds.some(a => this._registeredImageRIds.has(a)));
1078
+ if (alreadyRegistered) {
1079
+ continue;
1080
+ }
1081
+ if (img.rId) {
1082
+ addRelationshipWithId(documentRels, img.rId, RelType.Image, `media/${img.fileName}`);
1083
+ this._registeredImageRIds.add(img.rId);
1084
+ }
1085
+ else {
1086
+ addRelationship(documentRels, RelType.Image, `media/${img.fileName}`);
1087
+ }
1088
+ }
1089
+ addImageContentTypeDefaults(contentTypes, extensions);
1090
+ }
1091
+ // Custom XML parts (for SDT data binding)
1092
+ if (this._options.customXmlParts && this._options.customXmlParts.length > 0) {
1093
+ this._options.customXmlParts.forEach((part, i) => {
1094
+ const num = i + 1;
1095
+ const itemPath = `word/customXml/item${num}.xml`;
1096
+ const propsPath = `word/customXml/itemProps${num}.xml`;
1097
+ // Write the XML content
1098
+ const itemData = utf8Encoder.encode(part.xmlContent);
1099
+ const itemFile = new ZipDeflate(itemPath, { level });
1100
+ this._zip.add(itemFile);
1101
+ itemFile.push(itemData, true);
1102
+ // Write itemProps*.xml
1103
+ const propsWriter = new XmlWriter();
1104
+ propsWriter.openXml(STD_DOC_ATTRIBUTES);
1105
+ propsWriter.openNode("ds:datastoreItem", {
1106
+ "ds:itemID": `{${part.itemId}}`,
1107
+ "xmlns:ds": "http://schemas.openxmlformats.org/officeDocument/2006/customXml"
1108
+ });
1109
+ if (part.schemaReferences && part.schemaReferences.length > 0) {
1110
+ propsWriter.openNode("ds:schemaRefs");
1111
+ for (const uri of part.schemaReferences) {
1112
+ propsWriter.leafNode("ds:schemaRef", { "ds:uri": uri });
1113
+ }
1114
+ propsWriter.closeNode();
1115
+ }
1116
+ else {
1117
+ propsWriter.leafNode("ds:schemaRefs");
1118
+ }
1119
+ propsWriter.closeNode();
1120
+ const propsData = utf8Encoder.encode(propsWriter.xml);
1121
+ const propsFile = new ZipDeflate(propsPath, { level });
1122
+ this._zip.add(propsFile);
1123
+ propsFile.push(propsData, true);
1124
+ // Write item rels (links itemN.xml → itemPropsN.xml)
1125
+ const itemRels = createRelationships();
1126
+ addRelationship(itemRels, RelType.CustomXmlProps, `itemProps${num}.xml`);
1127
+ addXmlFile(`word/customXml/_rels/item${num}.xml.rels`, xml => renderRelationships(itemRels, xml));
1128
+ // Register content types
1129
+ addContentTypeOverride(contentTypes, `/word/customXml/itemProps${num}.xml`, "application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
1130
+ // Add to document rels
1131
+ addRelationship(documentRels, RelType.CustomXml, `customXml/item${num}.xml`);
1132
+ });
1133
+ }
1134
+ // Embedded fonts
1135
+ if (this._options.embeddedFonts && this._options.embeddedFonts.length > 0) {
1136
+ const fontTableRels = createRelationships();
1137
+ for (const ef of this._options.embeddedFonts) {
1138
+ const partPath = `word/fonts/${ef.fileName}`;
1139
+ const fontFile = new ZipDeflate(partPath, { level: 0 });
1140
+ this._zip.add(fontFile);
1141
+ fontFile.push(ef.data, true);
1142
+ // Register relationship from fontTable.xml
1143
+ addRelationshipWithId(fontTableRels, ef.rId, RelType.Font, `fonts/${ef.fileName}`);
1144
+ // Register content type for .odttf / .ttf / .otf
1145
+ const ext = getFileExt(ef.fileName);
1146
+ if (ext === "odttf") {
1147
+ addContentTypeDefault(contentTypes, "odttf", ContentType.ObfuscatedFont);
1148
+ }
1149
+ else if (ext === "ttf") {
1150
+ addContentTypeDefault(contentTypes, "ttf", "application/x-font-ttf");
1151
+ }
1152
+ else if (ext === "otf") {
1153
+ addContentTypeDefault(contentTypes, "otf", "application/x-font-otf");
1154
+ }
1155
+ }
1156
+ // Write fontTable.xml.rels
1157
+ addXmlFile("word/_rels/fontTable.xml.rels", xml => renderRelationships(fontTableRels, xml));
1158
+ }
1159
+ // Opaque (unrecognized) parts for round-trip preservation
1160
+ if (this._options.opaqueParts) {
1161
+ const preserveOle = this._options.securityPolicy?.preserveOleObjects !== false;
1162
+ const dropSignatures = this._options.securityPolicy?.dropSignaturesOnModify !== false;
1163
+ for (const part of this._options.opaqueParts) {
1164
+ // Honour `preserveOleObjects`: skip OLE binaries when disabled.
1165
+ if (!preserveOle &&
1166
+ (part.path.startsWith("word/embeddings/") ||
1167
+ (part.path.endsWith(".bin") && part.path.includes("embed")))) {
1168
+ continue;
1169
+ }
1170
+ // Honour `dropSignaturesOnModify`: signatures cease to be valid the
1171
+ // moment the document is re-serialised, so by default we drop them.
1172
+ if (dropSignatures && part.path.startsWith("_xmlsignatures/")) {
1173
+ continue;
1174
+ }
1175
+ const opaqueFile = new ZipDeflate(part.path, { level });
1176
+ this._zip.add(opaqueFile);
1177
+ opaqueFile.push(part.data, true);
1178
+ // Register content type
1179
+ if (part.contentType) {
1180
+ addContentTypeOverride(contentTypes, `/${part.path}`, part.contentType);
1181
+ }
1182
+ // Write part relationships if any
1183
+ if (part.relationships && part.relationships.length > 0) {
1184
+ const partRels = createRelationships();
1185
+ for (const rel of part.relationships) {
1186
+ addRelationshipWithId(partRels, rel.id, rel.type, rel.target, rel.targetMode);
1187
+ }
1188
+ const relsPath = getPartRelsPath(part.path);
1189
+ addXmlFile(relsPath, xml => renderRelationships(partRels, xml));
1190
+ }
1191
+ }
1192
+ }
1193
+ // Content type overrides
1194
+ addContentTypeOverride(contentTypes, `/${PartPath.Document}`, ContentType.Document);
1195
+ addContentTypeOverride(contentTypes, `/${PartPath.Styles}`, ContentType.Styles);
1196
+ addContentTypeOverride(contentTypes, `/${PartPath.Settings}`, ContentType.Settings);
1197
+ addContentTypeOverride(contentTypes, `/${PartPath.FontTable}`, ContentType.FontTable);
1198
+ addContentTypeOverride(contentTypes, `/${PartPath.Theme}`, ContentType.Theme);
1199
+ if (hasNumbering) {
1200
+ addContentTypeOverride(contentTypes, `/${PartPath.Numbering}`, ContentType.Numbering);
1201
+ }
1202
+ // Write common auxiliary parts (styles, settings, fontTable, theme, numbering, properties)
1203
+ // using the shared builder to avoid duplicating render logic with docx-packager.
1204
+ const commonParts = buildCommonAuxiliaryParts({
1205
+ docDefaults: this._options.docDefaults,
1206
+ styles: this._options.styles,
1207
+ settings: this._options.settings,
1208
+ fonts: this._options.fonts,
1209
+ theme: this._options.theme,
1210
+ abstractNumberings: this._options.abstractNumberings,
1211
+ numberingInstances: this._options.numberingInstances,
1212
+ footnotes: this._options.footnotes,
1213
+ endnotes: this._options.endnotes,
1214
+ coreProperties: this._options.coreProperties,
1215
+ appProperties: this._options.appProperties,
1216
+ customProperties: this._options.customProperties,
1217
+ rawXmlPolicy: this._renderCtx.rawXmlPolicy,
1218
+ // Pass the shared rId tables so in-note hyperlinks (registered earlier
1219
+ // against footnotes.xml.rels / endnotes.xml.rels) resolve to the same
1220
+ // rIds the renderer is about to emit.
1221
+ notesHelpers: {
1222
+ imageRemap: this._renderCtx.imageRIdRemap,
1223
+ hyperlinkRIds: this._renderCtx.hyperlinkRIds,
1224
+ rawXmlPolicy: this._renderCtx.rawXmlPolicy
1225
+ }
1226
+ });
1227
+ for (const part of commonParts) {
1228
+ const data = utf8Encoder.encode(part.content);
1229
+ const file = new ZipDeflate(part.path, { level });
1230
+ this._zip.add(file);
1231
+ file.push(data, true);
1232
+ }
1233
+ // Write images
1234
+ if (this._options.images) {
1235
+ for (const img of this._options.images) {
1236
+ const file = new ZipDeflate(PartPath.media(img.fileName), { level: 0 });
1237
+ this._zip.add(file);
1238
+ file.push(img.data, true);
1239
+ }
1240
+ }
1241
+ // Write chart parts (chartN.xml + content type) for body charts
1242
+ // registered during add(). Use the per-chart sequence number captured
1243
+ // at registration time so the rId target encoded in documentRels and
1244
+ // the actual ZIP entry name agree.
1245
+ for (const chartContent of this._bodyCharts) {
1246
+ const num = this._chartNum.get(chartContent);
1247
+ if (num === undefined) {
1248
+ continue; // shouldn't happen; defensive
1249
+ }
1250
+ const chartPath = `word/charts/chart${num}.xml`;
1251
+ const w = new XmlWriter();
1252
+ renderChartPart(w, chartContent.chart);
1253
+ const data = utf8Encoder.encode(w.xml);
1254
+ const file = new ZipDeflate(chartPath, { level });
1255
+ this._zip.add(file);
1256
+ file.push(data, true);
1257
+ addContentTypeOverride(contentTypes, `/${chartPath}`, ContentType.Chart);
1258
+ }
1259
+ // Write ChartEx parts (raw cx:chartSpace XML preserved on the model)
1260
+ for (const cxContent of this._bodyChartEx) {
1261
+ const num = this._chartNum.get(cxContent);
1262
+ if (num === undefined) {
1263
+ continue;
1264
+ }
1265
+ const cxPath = `word/charts/chartEx${num}.xml`;
1266
+ const data = utf8Encoder.encode(cxContent.chartExXml);
1267
+ const file = new ZipDeflate(cxPath, { level });
1268
+ this._zip.add(file);
1269
+ file.push(data, true);
1270
+ addContentTypeOverride(contentTypes, `/${cxPath}`, ContentType.ChartEx);
1271
+ }
1272
+ // Write document.xml.rels
1273
+ addXmlFile(PartPath.DocumentRels, xml => renderRelationships(documentRels, xml));
1274
+ // Write _rels/.rels
1275
+ addXmlFile(PartPath.PackageRels, xml => renderRelationships(packageRels, xml));
1276
+ // Write [Content_Types].xml
1277
+ addXmlFile(PartPath.ContentTypes, xml => renderContentTypes(contentTypes, xml));
1278
+ }
1279
+ _endStream(stream) {
1280
+ return new Promise((resolve, reject) => {
1281
+ // If a prior callback already reported an error, surface it
1282
+ // synchronously instead of waiting for an event that won't fire.
1283
+ if (this._streamError) {
1284
+ reject(this._streamError);
1285
+ return;
1286
+ }
1287
+ stream.once("zipped", () => resolve());
1288
+ stream.once("error", (err) => reject(err));
1289
+ stream.end();
1290
+ });
1291
+ }
1292
+ _assembleOutput() {
1293
+ if (this._outputChunks.length === 1) {
1294
+ return this._outputChunks[0];
1295
+ }
1296
+ const total = this._outputChunks.reduce((sum, c) => sum + c.length, 0);
1297
+ const result = new Uint8Array(total);
1298
+ let offset = 0;
1299
+ for (const chunk of this._outputChunks) {
1300
+ result.set(chunk, offset);
1301
+ offset += chunk.length;
1302
+ }
1303
+ return result;
1304
+ }
1305
+ }
1306
+ /**
1307
+ * Create a new streaming DOCX writer.
1308
+ *
1309
+ * @example
1310
+ * ```ts
1311
+ * const writer = createDocxStream({
1312
+ * styles: [{ type: "paragraph", styleId: "Normal", name: "Normal" }]
1313
+ * });
1314
+ *
1315
+ * for (let i = 0; i < 100000; i++) {
1316
+ * writer.addText(`Paragraph ${i}`);
1317
+ * }
1318
+ *
1319
+ * const buffer = await writer.finalize();
1320
+ * ```
1321
+ */
1322
+ export function createDocxStream(options) {
1323
+ return new StreamingDocxWriter(options);
1324
+ }
1325
+ /**
1326
+ * Replace any image/font file names in `options` with a leaf form that's
1327
+ * safe to embed into a ZIP entry path. A new options object is returned;
1328
+ * the caller's input is not mutated.
1329
+ *
1330
+ * Names are deduplicated within their respective collection so two
1331
+ * different inputs that sanitise to the same string don't silently
1332
+ * overwrite each other in the output package.
1333
+ */
1334
+ function sanitizeStreamingOptions(options) {
1335
+ let next = options;
1336
+ if (options.images && options.images.length > 0) {
1337
+ const used = new Set();
1338
+ let mutated = false;
1339
+ const images = options.images.map(img => {
1340
+ const safe = uniqueSanitizedName(img.fileName, used, "image.bin");
1341
+ if (safe !== img.fileName) {
1342
+ mutated = true;
1343
+ return { ...img, fileName: safe };
1344
+ }
1345
+ return img;
1346
+ });
1347
+ if (mutated) {
1348
+ next = { ...next, images };
1349
+ }
1350
+ }
1351
+ if (options.embeddedFonts && options.embeddedFonts.length > 0) {
1352
+ const used = new Set();
1353
+ let mutated = false;
1354
+ const embeddedFonts = options.embeddedFonts.map(ef => {
1355
+ const safe = uniqueSanitizedName(ef.fileName, used, "font.bin");
1356
+ if (safe !== ef.fileName) {
1357
+ mutated = true;
1358
+ return { ...ef, fileName: safe };
1359
+ }
1360
+ return ef;
1361
+ });
1362
+ if (mutated) {
1363
+ next = { ...next, embeddedFonts };
1364
+ }
1365
+ }
1366
+ return next;
1367
+ }
1368
+ function uniqueSanitizedName(raw, used, fallback) {
1369
+ let candidate = sanitizeMediaFileName(raw, fallback);
1370
+ if (used.has(candidate)) {
1371
+ const dot = candidate.lastIndexOf(".");
1372
+ const stem = dot >= 0 ? candidate.slice(0, dot) : candidate;
1373
+ const ext = dot >= 0 ? candidate.slice(dot) : "";
1374
+ let n = 2;
1375
+ while (used.has(`${stem}_${n}${ext}`)) {
1376
+ n++;
1377
+ }
1378
+ candidate = `${stem}_${n}${ext}`;
1379
+ }
1380
+ used.add(candidate);
1381
+ return candidate;
1382
+ }