@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,1907 @@
1
+ /**
2
+ * DOCX Module - HTML to DOCX Converter
3
+ *
4
+ * Converts an HTML string into DOCX document body content (paragraphs, tables, etc.).
5
+ * Handles common HTML elements: p, h1-h6, strong, em, a, ul, ol, li, table, img, br, span.
6
+ *
7
+ * This is NOT a full HTML rendering engine — it covers the structural elements
8
+ * that map cleanly to WordprocessingML concepts.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { htmlToDocxBody } from "excelts/word/html";
13
+ * import { Document, toBuffer } from "excelts/word";
14
+ *
15
+ * const body = htmlToDocxBody("<h1>Hello</h1><p>World</p>");
16
+ * const h = Document.create();
17
+ * for (const block of body) {
18
+ * Document.addBodyContent(h, block);
19
+ * }
20
+ * const buffer = await toBuffer(Document.build(h));
21
+ * ```
22
+ */
23
+ import { sanitizeUrl } from "../../core/internal-utils.js";
24
+ import { EMU_PER_PX } from "../../units.js";
25
+ /**
26
+ * Convert an HTML string into an array of DOCX body content blocks.
27
+ *
28
+ * Supported elements:
29
+ * - Block: p, div, h1-h6, blockquote, pre, hr
30
+ * - List: ul, ol, li
31
+ * - Table: table, thead, tbody, tr, th, td (colspan, rowspan, border styles)
32
+ * - Inline: strong/b, em/i, u, s/strike/del, a, br, span, sub, sup, code
33
+ * - Images: img (base64 data URLs as InlineImageContent, http(s) as placeholder)
34
+ * - Page break: div with style="page-break-before: always" or class="page-break"
35
+ * - CSS inline styles: font-family, font-size, color, background-color, font-weight,
36
+ * font-style, text-decoration, text-align
37
+ *
38
+ * @param html - The HTML string to convert.
39
+ * @param options - Optional conversion settings.
40
+ * @returns Array of BodyContent blocks.
41
+ */
42
+ export function htmlToDocxBody(html, options) {
43
+ const blocks = [];
44
+ const tokens = tokenize(html);
45
+ // Extract <style> rules and merge with user-provided classStyles
46
+ const extractedStyles = extractStyleRules(tokens);
47
+ const classStyles = {
48
+ ...extractedStyles,
49
+ ...(options?.classStyles ?? {})
50
+ };
51
+ // Seed the inline context with the caller-supplied defaults so plain text
52
+ // runs actually carry the requested font/size. Without this the options
53
+ // were effectively ignored.
54
+ const initialCtx = {};
55
+ if (options?.defaultFont) {
56
+ initialCtx.fontFamily = options.defaultFont;
57
+ }
58
+ if (options?.defaultFontSize !== undefined) {
59
+ initialCtx.fontSize = options.defaultFontSize;
60
+ }
61
+ parseBlocks(tokens, 0, blocks, initialCtx, classStyles);
62
+ return blocks;
63
+ }
64
+ function tokenize(html) {
65
+ const tokens = [];
66
+ // Strip HTML comments, doctype declarations and SGML processing
67
+ // instructions before tokenising — none of them should appear as text
68
+ // in the document body. The previous regex treated `<!doctype html>`
69
+ // as a text node containing `"!doctype html>"`.
70
+ const stripped = html
71
+ .replace(/<!--[\s\S]*?-->/g, "")
72
+ .replace(/<!doctype[^>]*>/gi, "")
73
+ .replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "")
74
+ .replace(/<\?[\s\S]*?\?>/g, "");
75
+ // Match a tag, OR a run of text. Text is anything-up-to-the-next-tag,
76
+ // with the addition that a `<` not followed by a tag-like character is
77
+ // treated as literal text (so "1 < 2" / "a<b" / "<<" survive instead
78
+ // of being silently swallowed).
79
+ const re = /<\/?([a-zA-Z][a-zA-Z0-9]*)((?:\s+[^>]*?)?)\/?\s*>|((?:[^<]|<(?![/a-zA-Z]))+)/g;
80
+ const tagRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)((?:\s+[^>]*?)?)(\/?)\s*>$/;
81
+ let m;
82
+ while ((m = re.exec(stripped)) !== null) {
83
+ const fullMatch = m[0];
84
+ if (m[3] !== undefined) {
85
+ // Text node
86
+ const text = decodeHtmlEntities(m[3]);
87
+ if (text) {
88
+ tokens.push({ type: "text", value: text });
89
+ }
90
+ }
91
+ else {
92
+ const tagMatch = tagRe.exec(fullMatch);
93
+ if (tagMatch) {
94
+ const isClose = tagMatch[1] === "/";
95
+ const tag = tagMatch[2].toLowerCase();
96
+ const attrStr = tagMatch[3];
97
+ const selfClose = tagMatch[4] === "/" || VOID_ELEMENTS.has(tag);
98
+ const attrs = parseHtmlAttrs(attrStr);
99
+ if (isClose) {
100
+ tokens.push({ type: "close", tag, attrs: {} });
101
+ }
102
+ else if (selfClose) {
103
+ tokens.push({ type: "selfclose", tag, attrs });
104
+ }
105
+ else {
106
+ tokens.push({ type: "open", tag, attrs });
107
+ // Raw-text elements: their body must not be parsed as markup. Skip
108
+ // forward to the matching close tag and either capture the body as
109
+ // a single text token (for <style>, which is post-processed by
110
+ // extractStyleRules) or discard it entirely (for <script>, etc.).
111
+ // Without this, embedded scripts would leak into the document body.
112
+ if (RAW_TEXT_ELEMENTS.has(tag)) {
113
+ const closeRe = new RegExp(`</${tag}\\s*>`, "i");
114
+ closeRe.lastIndex = re.lastIndex;
115
+ const startBody = re.lastIndex;
116
+ const closeMatch = closeRe.exec(stripped);
117
+ if (closeMatch) {
118
+ const body = stripped.slice(startBody, closeMatch.index);
119
+ if (RAW_TEXT_PRESERVE_BODY.has(tag)) {
120
+ tokens.push({ type: "text", value: body });
121
+ }
122
+ tokens.push({ type: "close", tag, attrs: {} });
123
+ re.lastIndex = closeMatch.index + closeMatch[0].length;
124
+ }
125
+ else {
126
+ // No closing tag — discard the rest of the input for this
127
+ // raw-text element to avoid emitting markup as text.
128
+ re.lastIndex = stripped.length;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ return tokens;
136
+ }
137
+ /**
138
+ * HTML elements whose body is not parsed as markup. Their content is either
139
+ * preserved (style) for downstream processing or discarded entirely.
140
+ */
141
+ const RAW_TEXT_ELEMENTS = new Set([
142
+ "script",
143
+ "style",
144
+ "noscript",
145
+ "iframe",
146
+ "noframes",
147
+ "textarea",
148
+ "title"
149
+ ]);
150
+ /** Subset of RAW_TEXT_ELEMENTS whose body is kept (as a single text token). */
151
+ const RAW_TEXT_PRESERVE_BODY = new Set(["style"]);
152
+ const VOID_ELEMENTS = new Set([
153
+ "br",
154
+ "hr",
155
+ "img",
156
+ "input",
157
+ "col",
158
+ "area",
159
+ "base",
160
+ "link",
161
+ "meta",
162
+ "source",
163
+ "wbr"
164
+ ]);
165
+ /**
166
+ * Extract simple class rules from `<style>` tokens in the token stream.
167
+ * Only supports simple selectors: `.className { property: value; ... }`
168
+ * Does not support nested rules, media queries, pseudo-classes, combinators, etc.
169
+ * Returns a map of className → inline style string.
170
+ */
171
+ function extractStyleRules(tokens) {
172
+ const result = {};
173
+ let i = 0;
174
+ while (i < tokens.length) {
175
+ const tok = tokens[i];
176
+ if (tok.type === "open" && tok.tag === "style") {
177
+ // Collect text content until </style>
178
+ let cssText = "";
179
+ i++;
180
+ while (i < tokens.length) {
181
+ const inner = tokens[i];
182
+ if (inner.type === "close" && inner.tag === "style") {
183
+ i++;
184
+ break;
185
+ }
186
+ if (inner.type === "text") {
187
+ cssText += inner.value;
188
+ }
189
+ i++;
190
+ }
191
+ // Parse simple class rules: .className { ... }
192
+ const ruleRe = /\.([a-zA-Z_][\w-]*)\s*\{([^}]*)\}/g;
193
+ let ruleMatch;
194
+ while ((ruleMatch = ruleRe.exec(cssText)) !== null) {
195
+ const className = ruleMatch[1];
196
+ const body = ruleMatch[2].trim();
197
+ if (body && !result[className]) {
198
+ result[className] = body;
199
+ }
200
+ }
201
+ continue;
202
+ }
203
+ i++;
204
+ }
205
+ return result;
206
+ }
207
+ function parseHtmlAttrs(str) {
208
+ const attrs = {};
209
+ const re = /([a-zA-Z_][\w-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
210
+ let m;
211
+ while ((m = re.exec(str)) !== null) {
212
+ attrs[m[1].toLowerCase()] = m[2] ?? m[3] ?? m[4] ?? "";
213
+ }
214
+ return attrs;
215
+ }
216
+ function decodeHtmlEntities(text) {
217
+ return text
218
+ .replace(/&amp;/g, "&")
219
+ .replace(/&lt;/g, "<")
220
+ .replace(/&gt;/g, ">")
221
+ .replace(/&quot;/g, '"')
222
+ .replace(/&#39;/g, "'")
223
+ .replace(/&nbsp;/g, "\u00A0")
224
+ .replace(/&#(\d+);/g, (_, n) => safeFromCodePoint(parseInt(n, 10)))
225
+ .replace(/&#x([a-fA-F0-9]+);/g, (_, n) => safeFromCodePoint(parseInt(n, 16)))
226
+ .replace(/&([a-zA-Z]+);/g, (match, name) => HTML_ENTITIES[name] ?? match);
227
+ }
228
+ /**
229
+ * Convert a numeric character reference to a string. Uses fromCodePoint so
230
+ * astral characters (e.g. emoji like &#128512;) are encoded as a proper
231
+ * surrogate pair instead of a single invalid UTF-16 unit. Out-of-range or
232
+ * non-finite values fall back to the Unicode replacement character.
233
+ */
234
+ function safeFromCodePoint(cp) {
235
+ if (!Number.isFinite(cp) || cp < 0 || cp > 0x10ffff) {
236
+ return "\uFFFD";
237
+ }
238
+ // Surrogate halves are not valid scalar values.
239
+ if (cp >= 0xd800 && cp <= 0xdfff) {
240
+ return "\uFFFD";
241
+ }
242
+ return String.fromCodePoint(cp);
243
+ }
244
+ /** Common HTML named entities mapped to their Unicode characters. */
245
+ const HTML_ENTITIES = {
246
+ // Punctuation & Typography
247
+ mdash: "\u2014",
248
+ ndash: "\u2013",
249
+ hellip: "\u2026",
250
+ laquo: "\u00AB",
251
+ raquo: "\u00BB",
252
+ lsquo: "\u2018",
253
+ rsquo: "\u2019",
254
+ ldquo: "\u201C",
255
+ rdquo: "\u201D",
256
+ sbquo: "\u201A",
257
+ bdquo: "\u201E",
258
+ bull: "\u2022",
259
+ middot: "\u00B7",
260
+ prime: "\u2032",
261
+ Prime: "\u2033",
262
+ oline: "\u203E",
263
+ iquest: "\u00BF",
264
+ iexcl: "\u00A1",
265
+ sect: "\u00A7",
266
+ para: "\u00B6",
267
+ dagger: "\u2020",
268
+ Dagger: "\u2021",
269
+ permil: "\u2030",
270
+ // Symbols & Legal
271
+ copy: "\u00A9",
272
+ reg: "\u00AE",
273
+ trade: "\u2122",
274
+ // Math & Science
275
+ deg: "\u00B0",
276
+ plusmn: "\u00B1",
277
+ times: "\u00D7",
278
+ divide: "\u00F7",
279
+ minus: "\u2212",
280
+ lowast: "\u2217",
281
+ radic: "\u221A",
282
+ infin: "\u221E",
283
+ sum: "\u2211",
284
+ prod: "\u220F",
285
+ int: "\u222B",
286
+ part: "\u2202",
287
+ nabla: "\u2207",
288
+ ne: "\u2260",
289
+ equiv: "\u2261",
290
+ asymp: "\u2248",
291
+ le: "\u2264",
292
+ ge: "\u2265",
293
+ sub: "\u2282",
294
+ sup: "\u2283",
295
+ nsub: "\u2284",
296
+ sube: "\u2286",
297
+ supe: "\u2287",
298
+ oplus: "\u2295",
299
+ otimes: "\u2297",
300
+ perp: "\u22A5",
301
+ and: "\u2227",
302
+ or: "\u2228",
303
+ not: "\u00AC",
304
+ exist: "\u2203",
305
+ forall: "\u2200",
306
+ empty: "\u2205",
307
+ isin: "\u2208",
308
+ notin: "\u2209",
309
+ ni: "\u220B",
310
+ there4: "\u2234",
311
+ sim: "\u223C",
312
+ cong: "\u2245",
313
+ prop: "\u221D",
314
+ // Currency
315
+ euro: "\u20AC",
316
+ pound: "\u00A3",
317
+ yen: "\u00A5",
318
+ cent: "\u00A2",
319
+ curren: "\u00A4",
320
+ fnof: "\u0192",
321
+ // Greek letters (lowercase)
322
+ alpha: "\u03B1",
323
+ beta: "\u03B2",
324
+ gamma: "\u03B3",
325
+ delta: "\u03B4",
326
+ epsilon: "\u03B5",
327
+ zeta: "\u03B6",
328
+ eta: "\u03B7",
329
+ theta: "\u03B8",
330
+ iota: "\u03B9",
331
+ kappa: "\u03BA",
332
+ lambda: "\u03BB",
333
+ mu: "\u03BC",
334
+ nu: "\u03BD",
335
+ xi: "\u03BE",
336
+ omicron: "\u03BF",
337
+ pi: "\u03C0",
338
+ rho: "\u03C1",
339
+ sigma: "\u03C3",
340
+ tau: "\u03C4",
341
+ upsilon: "\u03C5",
342
+ phi: "\u03C6",
343
+ chi: "\u03C7",
344
+ psi: "\u03C8",
345
+ omega: "\u03C9",
346
+ // Greek letters (uppercase)
347
+ Alpha: "\u0391",
348
+ Beta: "\u0392",
349
+ Gamma: "\u0393",
350
+ Delta: "\u0394",
351
+ Epsilon: "\u0395",
352
+ Zeta: "\u0396",
353
+ Eta: "\u0397",
354
+ Theta: "\u0398",
355
+ Iota: "\u0399",
356
+ Kappa: "\u039A",
357
+ Lambda: "\u039B",
358
+ Mu: "\u039C",
359
+ Nu: "\u039D",
360
+ Xi: "\u039E",
361
+ Omicron: "\u039F",
362
+ Pi: "\u03A0",
363
+ Rho: "\u03A1",
364
+ Sigma: "\u03A3",
365
+ Tau: "\u03A4",
366
+ Upsilon: "\u03A5",
367
+ Phi: "\u03A6",
368
+ Chi: "\u03A7",
369
+ Psi: "\u03A8",
370
+ Omega: "\u03A9",
371
+ // Arrows
372
+ larr: "\u2190",
373
+ uarr: "\u2191",
374
+ rarr: "\u2192",
375
+ darr: "\u2193",
376
+ harr: "\u2194",
377
+ lArr: "\u21D0",
378
+ uArr: "\u21D1",
379
+ rArr: "\u21D2",
380
+ dArr: "\u21D3",
381
+ hArr: "\u21D4",
382
+ crarr: "\u21B5",
383
+ // Fractions
384
+ frac12: "\u00BD",
385
+ frac14: "\u00BC",
386
+ frac34: "\u00BE",
387
+ frac13: "\u2153",
388
+ frac23: "\u2154",
389
+ frac15: "\u2155",
390
+ frac18: "\u215B",
391
+ frac38: "\u215C",
392
+ frac58: "\u215D",
393
+ frac78: "\u215E",
394
+ // Spaces
395
+ ensp: "\u2002",
396
+ emsp: "\u2003",
397
+ thinsp: "\u2009",
398
+ zwnj: "\u200C",
399
+ zwj: "\u200D",
400
+ lrm: "\u200E",
401
+ rlm: "\u200F",
402
+ // Misc Symbols
403
+ spades: "\u2660",
404
+ clubs: "\u2663",
405
+ hearts: "\u2665",
406
+ diams: "\u2666",
407
+ loz: "\u25CA",
408
+ circ: "\u02C6",
409
+ tilde: "\u02DC",
410
+ shy: "\u00AD",
411
+ macr: "\u00AF",
412
+ acute: "\u00B4",
413
+ cedil: "\u00B8",
414
+ micro: "\u00B5",
415
+ sup1: "\u00B9",
416
+ sup2: "\u00B2",
417
+ sup3: "\u00B3",
418
+ ordf: "\u00AA",
419
+ ordm: "\u00BA"
420
+ };
421
+ /** Parse a CSS inline style string into structured values. */
422
+ function parseCssStyle(styleStr) {
423
+ const result = {};
424
+ if (!styleStr) {
425
+ return result;
426
+ }
427
+ const declarations = styleStr.split(";");
428
+ for (const decl of declarations) {
429
+ const colonIdx = decl.indexOf(":");
430
+ if (colonIdx < 0) {
431
+ continue;
432
+ }
433
+ const prop = decl.slice(0, colonIdx).trim().toLowerCase();
434
+ const value = decl
435
+ .slice(colonIdx + 1)
436
+ .trim()
437
+ .toLowerCase();
438
+ switch (prop) {
439
+ case "font-family":
440
+ result.fontFamily = parseFontFamily(value);
441
+ break;
442
+ case "font-size":
443
+ result.fontSize = parseFontSize(value);
444
+ break;
445
+ case "color":
446
+ result.color = parseCssColor(value);
447
+ break;
448
+ case "background-color":
449
+ result.backgroundColor = parseCssColor(value);
450
+ break;
451
+ case "font-weight":
452
+ if (value === "bold" || value === "bolder" || parseInt(value, 10) >= 700) {
453
+ result.bold = true;
454
+ }
455
+ break;
456
+ case "font-style":
457
+ if (value === "italic" || value === "oblique") {
458
+ result.italic = true;
459
+ }
460
+ break;
461
+ case "text-decoration":
462
+ case "text-decoration-line":
463
+ if (value.includes("underline")) {
464
+ result.underline = true;
465
+ }
466
+ if (value.includes("line-through")) {
467
+ result.lineThrough = true;
468
+ }
469
+ break;
470
+ case "text-align":
471
+ if (value === "left" || value === "start") {
472
+ result.textAlign = "left";
473
+ }
474
+ else if (value === "center") {
475
+ result.textAlign = "center";
476
+ }
477
+ else if (value === "right" || value === "end") {
478
+ result.textAlign = "right";
479
+ }
480
+ else if (value === "justify") {
481
+ result.textAlign = "both";
482
+ }
483
+ break;
484
+ case "page-break-before":
485
+ if (value === "always") {
486
+ result.pageBreakBefore = true;
487
+ }
488
+ break;
489
+ case "margin-left": {
490
+ const twips = parseLengthToTwips(value);
491
+ if (twips !== undefined) {
492
+ result.marginLeft = twips;
493
+ }
494
+ break;
495
+ }
496
+ case "line-height": {
497
+ const spacing = parseLineHeight(value);
498
+ if (spacing !== undefined) {
499
+ result.lineHeight = spacing;
500
+ }
501
+ break;
502
+ }
503
+ case "border": {
504
+ // Shorthand: border: 1px solid black
505
+ const parts = value.split(/\s+/);
506
+ for (const part of parts) {
507
+ if (/^\d/.test(part)) {
508
+ result.borderWidth = parseBorderWidth(part);
509
+ }
510
+ else if (isBorderStyleKeyword(part)) {
511
+ result.borderStyle = part;
512
+ }
513
+ else {
514
+ const c = parseCssColor(part);
515
+ if (c) {
516
+ result.borderColor = c;
517
+ }
518
+ }
519
+ }
520
+ break;
521
+ }
522
+ case "border-style":
523
+ result.borderStyle = value.split(/\s+/)[0];
524
+ break;
525
+ case "border-width":
526
+ result.borderWidth = parseBorderWidth(value.split(/\s+/)[0]);
527
+ break;
528
+ case "border-color": {
529
+ const c = parseCssColor(value.split(/\s+/)[0]);
530
+ if (c) {
531
+ result.borderColor = c;
532
+ }
533
+ break;
534
+ }
535
+ case "width": {
536
+ const twips = parseLengthToTwips(value);
537
+ if (twips !== undefined) {
538
+ result.width = twips;
539
+ }
540
+ break;
541
+ }
542
+ }
543
+ }
544
+ return result;
545
+ }
546
+ /** Extract the first font-family name from a CSS font-family value. */
547
+ function parseFontFamily(value) {
548
+ // Take the original (non-lowercased) value for font names — but our parser
549
+ // already lowered it. We'll capitalize for common fonts. Instead, let's
550
+ // just strip quotes and return as-is (already lowered).
551
+ // Actually we need the original casing. Let's re-parse from the raw value.
552
+ // Since we already lowercased, we'll just clean it up:
553
+ const first = value.split(",")[0].trim();
554
+ // Remove quotes
555
+ const cleaned = first.replace(/["']/g, "").trim();
556
+ // Capitalize each word for display
557
+ return cleaned
558
+ .split(/\s+/)
559
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
560
+ .join(" ");
561
+ }
562
+ /** Parse CSS font-size into half-points. */
563
+ function parseFontSize(value) {
564
+ // Support px, pt, em, rem
565
+ const match = /^([\d.]+)\s*(px|pt|em|rem)?$/.exec(value);
566
+ if (!match) {
567
+ return undefined;
568
+ }
569
+ const num = parseFloat(match[1]);
570
+ const unit = match[2] || "px";
571
+ switch (unit) {
572
+ case "pt":
573
+ return Math.round(num * 2); // half-points
574
+ case "px":
575
+ // 1px ≈ 0.75pt
576
+ return Math.round(num * 0.75 * 2);
577
+ case "em":
578
+ case "rem":
579
+ // Assume 1em = 12pt = 24 half-points
580
+ return Math.round(num * 24);
581
+ default:
582
+ return undefined;
583
+ }
584
+ }
585
+ /** Parse a CSS color value into a 6-digit hex string (without #). */
586
+ function parseCssColor(value) {
587
+ // #RGB or #RRGGBB
588
+ if (value.startsWith("#")) {
589
+ const hex = value.slice(1);
590
+ if (hex.length === 3) {
591
+ return hex
592
+ .split("")
593
+ .map(c => c + c)
594
+ .join("")
595
+ .toUpperCase();
596
+ }
597
+ if (hex.length === 6) {
598
+ return hex.toUpperCase();
599
+ }
600
+ return undefined;
601
+ }
602
+ // rgb(r, g, b) or rgba(r, g, b, a)
603
+ const rgbMatch = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(value);
604
+ if (rgbMatch) {
605
+ const r = Math.min(255, parseInt(rgbMatch[1], 10));
606
+ const g = Math.min(255, parseInt(rgbMatch[2], 10));
607
+ const b = Math.min(255, parseInt(rgbMatch[3], 10));
608
+ return (r.toString(16).padStart(2, "0") +
609
+ g.toString(16).padStart(2, "0") +
610
+ b.toString(16).padStart(2, "0")).toUpperCase();
611
+ }
612
+ // Named colors (common subset)
613
+ const named = CSS_NAMED_COLORS[value];
614
+ if (named) {
615
+ return named;
616
+ }
617
+ return undefined;
618
+ }
619
+ /** Common CSS named colors mapped to hex. */
620
+ const CSS_NAMED_COLORS = {
621
+ black: "000000",
622
+ white: "FFFFFF",
623
+ red: "FF0000",
624
+ green: "008000",
625
+ blue: "0000FF",
626
+ yellow: "FFFF00",
627
+ cyan: "00FFFF",
628
+ magenta: "FF00FF",
629
+ gray: "808080",
630
+ grey: "808080",
631
+ silver: "C0C0C0",
632
+ maroon: "800000",
633
+ olive: "808000",
634
+ lime: "00FF00",
635
+ aqua: "00FFFF",
636
+ teal: "008080",
637
+ navy: "000080",
638
+ fuchsia: "FF00FF",
639
+ purple: "800080",
640
+ orange: "FFA500",
641
+ pink: "FFC0CB",
642
+ brown: "A52A2A",
643
+ coral: "FF7F50",
644
+ crimson: "DC143C",
645
+ darkblue: "00008B",
646
+ darkgreen: "006400",
647
+ darkred: "8B0000",
648
+ gold: "FFD700",
649
+ indigo: "4B0082",
650
+ ivory: "FFFFF0",
651
+ khaki: "F0E68C",
652
+ lavender: "E6E6FA",
653
+ lightblue: "ADD8E6",
654
+ lightgray: "D3D3D3",
655
+ lightgrey: "D3D3D3",
656
+ lightgreen: "90EE90",
657
+ lightyellow: "FFFFE0",
658
+ darkgray: "A9A9A9",
659
+ darkgrey: "A9A9A9",
660
+ dimgray: "696969",
661
+ dimgrey: "696969",
662
+ tomato: "FF6347",
663
+ violet: "EE82EE",
664
+ wheat: "F5DEB3"
665
+ };
666
+ /** Parse a CSS length value (px, pt, in, cm, mm) into twips. 1 inch = 1440 twips. */
667
+ function parseLengthToTwips(value) {
668
+ const match = /^([\d.]+)\s*(px|pt|in|cm|mm|em|rem)?$/.exec(value);
669
+ if (!match) {
670
+ return undefined;
671
+ }
672
+ const num = parseFloat(match[1]);
673
+ const unit = match[2] || "px";
674
+ switch (unit) {
675
+ case "pt":
676
+ return Math.round(num * 20); // 1pt = 20 twips
677
+ case "px":
678
+ return Math.round(num * 15); // 1px ≈ 0.75pt ≈ 15 twips
679
+ case "in":
680
+ return Math.round(num * 1440); // 1in = 1440 twips
681
+ case "cm":
682
+ return Math.round(num * 567); // 1cm ≈ 567 twips
683
+ case "mm":
684
+ return Math.round(num * 56.7); // 1mm ≈ 56.7 twips
685
+ case "em":
686
+ case "rem":
687
+ // Assume 1em = 12pt = 240 twips
688
+ return Math.round(num * 240);
689
+ default:
690
+ return undefined;
691
+ }
692
+ }
693
+ /** Parse CSS line-height into 240ths of a line for WordprocessingML spacing. */
694
+ function parseLineHeight(value) {
695
+ // Unitless number: e.g., "1.5" means 1.5 lines → 360 (240 * 1.5)
696
+ const unitlessMatch = /^([\d.]+)$/.exec(value);
697
+ if (unitlessMatch) {
698
+ const num = parseFloat(unitlessMatch[1]);
699
+ return Math.round(num * 240);
700
+ }
701
+ // Percentage: e.g., "150%" means 1.5 lines → 360
702
+ const percentMatch = /^([\d.]+)%$/.exec(value);
703
+ if (percentMatch) {
704
+ const num = parseFloat(percentMatch[1]);
705
+ return Math.round((num / 100) * 240);
706
+ }
707
+ // With units (px, pt): convert to twips and use "exact" style — but the "auto" rule
708
+ // uses 240ths of a line, so we approximate with the unitless conversion
709
+ const unitMatch = /^([\d.]+)\s*(px|pt|em|rem)$/.exec(value);
710
+ if (unitMatch) {
711
+ const num = parseFloat(unitMatch[1]);
712
+ const unit = unitMatch[2];
713
+ switch (unit) {
714
+ case "pt":
715
+ // Convert pt to 240ths of a line: 12pt = 240 (single line)
716
+ return Math.round((num / 12) * 240);
717
+ case "px":
718
+ // 1px ≈ 0.75pt; 16px ≈ 12pt = single
719
+ return Math.round(((num * 0.75) / 12) * 240);
720
+ case "em":
721
+ case "rem":
722
+ return Math.round(num * 240);
723
+ }
724
+ }
725
+ return undefined;
726
+ }
727
+ const _BLOCK_TAGS = new Set([
728
+ "p",
729
+ "div",
730
+ "h1",
731
+ "h2",
732
+ "h3",
733
+ "h4",
734
+ "h5",
735
+ "h6",
736
+ "blockquote",
737
+ "pre",
738
+ "li",
739
+ "dt",
740
+ "dd",
741
+ "dl",
742
+ "section",
743
+ "article",
744
+ "main",
745
+ "aside",
746
+ "header",
747
+ "footer",
748
+ "figure",
749
+ "figcaption",
750
+ "details",
751
+ "summary",
752
+ "address"
753
+ ]);
754
+ function parseBlocks(tokens, start, blocks, parentCtx, classStyles) {
755
+ let i = start;
756
+ let pendingInline;
757
+ const flushPending = () => {
758
+ if (pendingInline && pendingInline.runs.length > 0) {
759
+ blocks.push({
760
+ type: "paragraph",
761
+ children: pendingInline.runs
762
+ });
763
+ }
764
+ pendingInline = undefined;
765
+ };
766
+ while (i < tokens.length) {
767
+ const tok = tokens[i];
768
+ if (tok.type === "close") {
769
+ flushPending();
770
+ return i + 1; // consumed the close tag
771
+ }
772
+ if (tok.type === "text") {
773
+ if (!pendingInline) {
774
+ pendingInline = { runs: [], ctx: parentCtx };
775
+ }
776
+ const run = makeRun(tok.value, parentCtx);
777
+ pendingInline.runs.push(run);
778
+ i++;
779
+ continue;
780
+ }
781
+ // Open or self-close tag
782
+ const tag = tok.type === "open" || tok.type === "selfclose" ? tok.tag : "";
783
+ // Document scaffolding (<html>, <body>) is transparent — descend into
784
+ // its children. <head> and its leaf children carry no body-text and
785
+ // are skipped entirely so their whitespace/newlines don't leak as
786
+ // empty paragraphs into the document.
787
+ if (tag === "html" || tag === "body") {
788
+ if (tok.type === "open") {
789
+ flushPending();
790
+ i = parseBlocks(tokens, i + 1, blocks, parentCtx, classStyles);
791
+ continue;
792
+ }
793
+ i++;
794
+ continue;
795
+ }
796
+ if (tag === "head") {
797
+ // Fast-forward to </head>; ignore everything in between (titles,
798
+ // meta, link, etc.). <style> bodies were already extracted by
799
+ // tokenize+extractStyleRules and stripped from the token stream
800
+ // through RAW_TEXT_ELEMENTS handling.
801
+ if (tok.type === "open") {
802
+ let depth = 1;
803
+ i++;
804
+ while (i < tokens.length && depth > 0) {
805
+ const t = tokens[i];
806
+ if (t.type === "open" && t.tag === "head") {
807
+ depth++;
808
+ }
809
+ else if (t.type === "close" && t.tag === "head") {
810
+ depth--;
811
+ }
812
+ i++;
813
+ }
814
+ continue;
815
+ }
816
+ i++;
817
+ continue;
818
+ }
819
+ if (tag === "title" || tag === "meta" || tag === "link" || tag === "base") {
820
+ // Should never reach here because <head> handler swallows them, but
821
+ // guard against malformed HTML where they appear at body level.
822
+ if (tok.type === "open") {
823
+ let depth = 1;
824
+ i++;
825
+ while (i < tokens.length && depth > 0) {
826
+ const t = tokens[i];
827
+ if (t.type === "open" && t.tag === tag) {
828
+ depth++;
829
+ }
830
+ else if (t.type === "close" && t.tag === tag) {
831
+ depth--;
832
+ }
833
+ i++;
834
+ }
835
+ continue;
836
+ }
837
+ i++;
838
+ continue;
839
+ }
840
+ if (tag === "br") {
841
+ if (!pendingInline) {
842
+ pendingInline = { runs: [], ctx: parentCtx };
843
+ }
844
+ pendingInline.runs.push({ content: [{ type: "break" }] });
845
+ i++;
846
+ continue;
847
+ }
848
+ if (tag === "hr") {
849
+ flushPending();
850
+ blocks.push({
851
+ type: "paragraph",
852
+ properties: {
853
+ borders: {
854
+ bottom: { style: "single", size: 6, space: 1, color: "auto" }
855
+ }
856
+ },
857
+ children: []
858
+ });
859
+ i++;
860
+ continue;
861
+ }
862
+ // Headings
863
+ if (/^h[1-6]$/.test(tag)) {
864
+ flushPending();
865
+ const level = parseInt(tag[1], 10);
866
+ const style = parseCssStyle(resolveEffectiveStyle(tok.attrs, classStyles));
867
+ const children = [];
868
+ const headingCtx = { ...parentCtx, bold: true };
869
+ applyCssToInlineContext(headingCtx, style);
870
+ i = parseInlines(tokens, i + 1, children, headingCtx, tag, classStyles);
871
+ const props = {
872
+ style: `Heading${level}`,
873
+ ...(style.textAlign ? { alignment: style.textAlign } : {})
874
+ };
875
+ if (style.marginLeft !== undefined) {
876
+ props.indent = { left: style.marginLeft };
877
+ }
878
+ if (style.lineHeight !== undefined) {
879
+ props.spacing = { line: style.lineHeight, lineRule: "auto" };
880
+ }
881
+ blocks.push({
882
+ type: "paragraph",
883
+ properties: props,
884
+ children
885
+ });
886
+ continue;
887
+ }
888
+ // Page-break detection: <div style="page-break-before: always"> or <div class="page-break">
889
+ if (tag === "div" && tok.type === "open") {
890
+ const attrs = tok.attrs;
891
+ const style = parseCssStyle(resolveEffectiveStyle(attrs, classStyles));
892
+ const hasPageBreakClass = (attrs["class"] || "").split(/\s+/).includes("page-break");
893
+ if (style.pageBreakBefore || hasPageBreakClass) {
894
+ flushPending();
895
+ // Emit a page break paragraph
896
+ blocks.push({
897
+ type: "paragraph",
898
+ children: [{ content: [{ type: "break", breakType: "page" }] }]
899
+ });
900
+ // Continue parsing the div's children as normal content
901
+ i = parseBlocks(tokens, i + 1, blocks, parentCtx, classStyles);
902
+ continue;
903
+ }
904
+ }
905
+ // Paragraph-like blocks
906
+ if (tag === "p" || tag === "div" || tag === "blockquote" || tag === "pre" || tag === "aside") {
907
+ flushPending();
908
+ const attrs = tok.attrs;
909
+ const style = parseCssStyle(resolveEffectiveStyle(attrs, classStyles));
910
+ const children = [];
911
+ const ctx = tag === "pre" ? { ...parentCtx, code: true } : { ...parentCtx };
912
+ applyCssToInlineContext(ctx, style);
913
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
914
+ const props = {};
915
+ if (tag === "blockquote" || tag === "aside") {
916
+ props.indent = { left: 720 }; // 0.5 inch indent
917
+ }
918
+ if (style.marginLeft !== undefined) {
919
+ // margin-left → paragraph indentation (merges with blockquote indent)
920
+ const existing = props.indent || {};
921
+ props.indent = { ...existing, left: style.marginLeft };
922
+ }
923
+ if (style.textAlign) {
924
+ props.alignment = style.textAlign;
925
+ }
926
+ if (style.lineHeight !== undefined) {
927
+ props.spacing = { line: style.lineHeight, lineRule: "auto" };
928
+ }
929
+ blocks.push({
930
+ type: "paragraph",
931
+ ...(Object.keys(props).length > 0 ? { properties: props } : {}),
932
+ children
933
+ });
934
+ continue;
935
+ }
936
+ // Container elements: figure, details — recurse into children
937
+ if (tag === "figure" || tag === "details") {
938
+ flushPending();
939
+ i = parseBlocks(tokens, i + 1, blocks, parentCtx, classStyles);
940
+ continue;
941
+ }
942
+ // figcaption — paragraph with Caption style
943
+ if (tag === "figcaption") {
944
+ flushPending();
945
+ const attrs = tok.attrs;
946
+ const style = parseCssStyle(resolveEffectiveStyle(attrs, classStyles));
947
+ const children = [];
948
+ const ctx = { ...parentCtx };
949
+ applyCssToInlineContext(ctx, style);
950
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
951
+ blocks.push({
952
+ type: "paragraph",
953
+ properties: { style: "Caption" },
954
+ children
955
+ });
956
+ continue;
957
+ }
958
+ // summary — bold paragraph
959
+ if (tag === "summary") {
960
+ flushPending();
961
+ const children = [];
962
+ const ctx = { ...parentCtx, bold: true };
963
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
964
+ blocks.push({
965
+ type: "paragraph",
966
+ children
967
+ });
968
+ continue;
969
+ }
970
+ // Definition list: dl is a container, dt is bold, dd is indented
971
+ if (tag === "dl") {
972
+ flushPending();
973
+ i = parseBlocks(tokens, i + 1, blocks, parentCtx, classStyles);
974
+ continue;
975
+ }
976
+ if (tag === "dt") {
977
+ flushPending();
978
+ const children = [];
979
+ const ctx = { ...parentCtx, bold: true };
980
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
981
+ blocks.push({
982
+ type: "paragraph",
983
+ children
984
+ });
985
+ continue;
986
+ }
987
+ if (tag === "dd") {
988
+ flushPending();
989
+ const children = [];
990
+ const ctx = { ...parentCtx };
991
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
992
+ blocks.push({
993
+ type: "paragraph",
994
+ properties: { indent: { left: 720 } },
995
+ children
996
+ });
997
+ continue;
998
+ }
999
+ // address — italic paragraph
1000
+ if (tag === "address") {
1001
+ flushPending();
1002
+ const children = [];
1003
+ const ctx = { ...parentCtx, italic: true };
1004
+ i = parseInlines(tokens, i + 1, children, ctx, tag, classStyles);
1005
+ blocks.push({
1006
+ type: "paragraph",
1007
+ children
1008
+ });
1009
+ continue;
1010
+ }
1011
+ // Lists
1012
+ if (tag === "ul" || tag === "ol") {
1013
+ flushPending();
1014
+ i = parseList(tokens, i + 1, blocks, parentCtx, tag === "ol", 0, tag, classStyles);
1015
+ continue;
1016
+ }
1017
+ // Tables
1018
+ if (tag === "table") {
1019
+ flushPending();
1020
+ const table = parseTable(tokens, i + 1, tok.attrs, classStyles);
1021
+ blocks.push(table.table);
1022
+ i = table.endIdx;
1023
+ continue;
1024
+ }
1025
+ // Inline elements treated at block level (wrap in paragraph)
1026
+ if (INLINE_TAGS.has(tag) || tok.type === "selfclose") {
1027
+ if (!pendingInline) {
1028
+ pendingInline = { runs: [], ctx: parentCtx };
1029
+ }
1030
+ i = parseInlineTag(tokens, i, pendingInline.runs, parentCtx, classStyles);
1031
+ continue;
1032
+ }
1033
+ // Unknown block: recurse
1034
+ if (tok.type === "open") {
1035
+ flushPending();
1036
+ i = parseBlocks(tokens, i + 1, blocks, parentCtx, classStyles);
1037
+ continue;
1038
+ }
1039
+ i++;
1040
+ }
1041
+ flushPending();
1042
+ return i;
1043
+ }
1044
+ const INLINE_TAGS = new Set([
1045
+ "strong",
1046
+ "b",
1047
+ "em",
1048
+ "i",
1049
+ "u",
1050
+ "s",
1051
+ "strike",
1052
+ "del",
1053
+ "a",
1054
+ "span",
1055
+ "code",
1056
+ "sub",
1057
+ "sup",
1058
+ "mark",
1059
+ "small",
1060
+ "abbr",
1061
+ "q",
1062
+ "cite",
1063
+ "time",
1064
+ "kbd",
1065
+ "var",
1066
+ "samp",
1067
+ "img"
1068
+ ]);
1069
+ // =============================================================================
1070
+ // Inline parser
1071
+ // =============================================================================
1072
+ function parseInlines(tokens, start, runs, ctx, untilClose, classStyles) {
1073
+ let i = start;
1074
+ while (i < tokens.length) {
1075
+ const tok = tokens[i];
1076
+ if (tok.type === "close" && tok.tag === untilClose) {
1077
+ return i + 1;
1078
+ }
1079
+ if (tok.type === "text") {
1080
+ runs.push(makeRun(tok.value, ctx));
1081
+ i++;
1082
+ }
1083
+ else if (tok.type === "close") {
1084
+ // Mismatched close tag, just skip
1085
+ return i + 1;
1086
+ }
1087
+ else {
1088
+ i = parseInlineTag(tokens, i, runs, ctx, classStyles);
1089
+ }
1090
+ }
1091
+ return i;
1092
+ }
1093
+ function parseInlineTag(tokens, idx, runs, ctx, classStyles) {
1094
+ const tok = tokens[idx];
1095
+ const tag = tok.tag;
1096
+ if (tok.type === "selfclose" || tag === "br") {
1097
+ if (tag === "br") {
1098
+ runs.push({ content: [{ type: "break" }] });
1099
+ }
1100
+ else if (tag === "img") {
1101
+ const imgContent = buildImageContent(tok.attrs);
1102
+ if (imgContent) {
1103
+ runs.push({ content: [imgContent] });
1104
+ }
1105
+ else {
1106
+ // Fallback placeholder text
1107
+ const alt = tok.attrs["alt"] || "image";
1108
+ runs.push(makeRun(`[Image: ${alt}]`, ctx));
1109
+ }
1110
+ }
1111
+ return idx + 1;
1112
+ }
1113
+ // Open tags
1114
+ const newCtx = { ...ctx };
1115
+ const style = parseCssStyle(resolveEffectiveStyle(tok.attrs, classStyles));
1116
+ applyCssToInlineContext(newCtx, style);
1117
+ if (tag === "strong" || tag === "b") {
1118
+ newCtx.bold = true;
1119
+ }
1120
+ else if (tag === "em" || tag === "i") {
1121
+ newCtx.italic = true;
1122
+ }
1123
+ else if (tag === "u") {
1124
+ newCtx.underline = true;
1125
+ }
1126
+ else if (tag === "s" || tag === "strike" || tag === "del") {
1127
+ newCtx.strikethrough = true;
1128
+ }
1129
+ else if (tag === "sub") {
1130
+ newCtx.subscript = true;
1131
+ }
1132
+ else if (tag === "sup") {
1133
+ newCtx.superscript = true;
1134
+ }
1135
+ else if (tag === "mark") {
1136
+ if (!newCtx.backgroundColor) {
1137
+ newCtx.backgroundColor = "FFFF00"; // default highlight
1138
+ }
1139
+ }
1140
+ else if (tag === "cite") {
1141
+ newCtx.italic = true;
1142
+ }
1143
+ else if (tag === "small") {
1144
+ // 80% of default font size (default 24 half-points = 12pt)
1145
+ const baseSize = newCtx.fontSize || 24;
1146
+ newCtx.fontSize = Math.round(baseSize * 0.8);
1147
+ }
1148
+ else if (tag === "code" || tag === "kbd" || tag === "samp") {
1149
+ newCtx.code = true;
1150
+ }
1151
+ else if (tag === "a") {
1152
+ // Collect inner runs and wrap them in a Hyperlink
1153
+ const innerRuns = [];
1154
+ // Drop unsafe schemes (javascript:/vbscript:/...) silently — the link
1155
+ // text is still preserved as plain runs.
1156
+ const safeHref = sanitizeUrl(tok.attrs["href"]);
1157
+ let i = idx + 1;
1158
+ while (i < tokens.length) {
1159
+ const t = tokens[i];
1160
+ if (t.type === "close" && t.tag === tag) {
1161
+ const hyperlink = {
1162
+ type: "hyperlink",
1163
+ url: safeHref ?? "",
1164
+ children: innerRuns
1165
+ };
1166
+ runs.push(hyperlink);
1167
+ return i + 1;
1168
+ }
1169
+ if (t.type === "text") {
1170
+ innerRuns.push(makeRun(t.value, { ...ctx }));
1171
+ i++;
1172
+ }
1173
+ else if (t.type === "close") {
1174
+ const hyperlink = {
1175
+ type: "hyperlink",
1176
+ url: safeHref ?? "",
1177
+ children: innerRuns
1178
+ };
1179
+ runs.push(hyperlink);
1180
+ return i + 1;
1181
+ }
1182
+ else {
1183
+ const childRuns = [];
1184
+ i = parseInlineTag(tokens, i, childRuns, { ...ctx }, classStyles);
1185
+ for (const r of childRuns) {
1186
+ if ("content" in r && !("type" in r)) {
1187
+ innerRuns.push(r);
1188
+ }
1189
+ else if ("type" in r && r.type === "hyperlink") {
1190
+ // Flatten nested hyperlink children
1191
+ for (const c of r.children) {
1192
+ innerRuns.push(c);
1193
+ }
1194
+ }
1195
+ }
1196
+ }
1197
+ }
1198
+ // EOF fallback: tokens ran out without a matching `</a>`. Use the
1199
+ // already-sanitized href so an unclosed `<a href="javascript:...">`
1200
+ // can't smuggle a dangerous URL into the model.
1201
+ const hyperlink = {
1202
+ type: "hyperlink",
1203
+ url: safeHref ?? "",
1204
+ children: innerRuns
1205
+ };
1206
+ runs.push(hyperlink);
1207
+ return i;
1208
+ }
1209
+ // Parse inner content
1210
+ let i = idx + 1;
1211
+ while (i < tokens.length) {
1212
+ const t = tokens[i];
1213
+ if (t.type === "close" && t.tag === tag) {
1214
+ return i + 1;
1215
+ }
1216
+ if (t.type === "text") {
1217
+ runs.push(makeRun(t.value, newCtx));
1218
+ i++;
1219
+ }
1220
+ else if (t.type === "close") {
1221
+ return i + 1;
1222
+ }
1223
+ else {
1224
+ i = parseInlineTag(tokens, i, runs, newCtx, classStyles);
1225
+ }
1226
+ }
1227
+ return i;
1228
+ }
1229
+ // =============================================================================
1230
+ // List parser
1231
+ // =============================================================================
1232
+ function parseList(tokens, start, blocks, ctx, ordered, level, untilClose, classStyles) {
1233
+ let i = start;
1234
+ while (i < tokens.length) {
1235
+ const tok = tokens[i];
1236
+ if (tok.type === "close" && tok.tag === untilClose) {
1237
+ return i + 1;
1238
+ }
1239
+ if (tok.type === "open" && tok.tag === "li") {
1240
+ i = parseListItem(tokens, i + 1, blocks, ctx, ordered, level, classStyles);
1241
+ }
1242
+ else if (tok.type === "open" && (tok.tag === "ul" || tok.tag === "ol")) {
1243
+ // Nested list directly under ul/ol (without li wrapper) — increase level
1244
+ i = parseList(tokens, i + 1, blocks, ctx, tok.tag === "ol", level + 1, tok.tag, classStyles);
1245
+ }
1246
+ else {
1247
+ i++;
1248
+ }
1249
+ }
1250
+ return i;
1251
+ }
1252
+ /** Parse contents of a single `<li>`, handling nested `<ul>/<ol>` inside it. */
1253
+ function parseListItem(tokens, start, blocks, ctx, ordered, level, classStyles) {
1254
+ const children = [];
1255
+ let i = start;
1256
+ let hasEmittedContent = false;
1257
+ while (i < tokens.length) {
1258
+ const tok = tokens[i];
1259
+ // End of this <li>
1260
+ if (tok.type === "close" && tok.tag === "li") {
1261
+ // Only emit a paragraph if there's content, or if we haven't emitted any paragraph for this item yet
1262
+ if (children.length > 0 || !hasEmittedContent) {
1263
+ blocks.push({
1264
+ type: "paragraph",
1265
+ properties: {
1266
+ numbering: {
1267
+ numId: ordered ? 2 : 1,
1268
+ level: level
1269
+ }
1270
+ },
1271
+ children
1272
+ });
1273
+ }
1274
+ return i + 1;
1275
+ }
1276
+ // Nested list inside <li>: emit current inline content as paragraph, then recurse
1277
+ if (tok.type === "open" && (tok.tag === "ul" || tok.tag === "ol")) {
1278
+ // Emit any collected inline content as the list item paragraph first
1279
+ if (children.length > 0 || !hasEmittedContent) {
1280
+ blocks.push({
1281
+ type: "paragraph",
1282
+ properties: {
1283
+ numbering: {
1284
+ numId: ordered ? 2 : 1,
1285
+ level: level
1286
+ }
1287
+ },
1288
+ children: [...children]
1289
+ });
1290
+ children.length = 0;
1291
+ hasEmittedContent = true;
1292
+ }
1293
+ // Parse the nested list at the next level
1294
+ const nestedOrdered = tok.tag === "ol";
1295
+ i = parseList(tokens, i + 1, blocks, ctx, nestedOrdered, level + 1, tok.tag, classStyles);
1296
+ continue;
1297
+ }
1298
+ // Text content
1299
+ if (tok.type === "text") {
1300
+ children.push(makeRun(tok.value, ctx));
1301
+ i++;
1302
+ continue;
1303
+ }
1304
+ // Inline tags
1305
+ if (tok.type === "open" || tok.type === "selfclose") {
1306
+ if (INLINE_TAGS.has(tok.tag) || tok.type === "selfclose") {
1307
+ i = parseInlineTag(tokens, i, children, ctx, classStyles);
1308
+ }
1309
+ else if (tok.tag === "br") {
1310
+ children.push({ content: [{ type: "break" }] });
1311
+ i++;
1312
+ }
1313
+ else {
1314
+ // Some other block-level tag inside <li> (e.g., <p>, <div>) — treat as inline
1315
+ i = parseInlineTag(tokens, i, children, ctx, classStyles);
1316
+ }
1317
+ continue;
1318
+ }
1319
+ // Mismatched close tag
1320
+ if (tok.type === "close") {
1321
+ // Emit what we have and stop
1322
+ blocks.push({
1323
+ type: "paragraph",
1324
+ properties: {
1325
+ numbering: {
1326
+ numId: ordered ? 2 : 1,
1327
+ level: level
1328
+ }
1329
+ },
1330
+ children
1331
+ });
1332
+ return i + 1;
1333
+ }
1334
+ i++;
1335
+ }
1336
+ // Ran out of tokens without seeing </li> — emit what we have
1337
+ if (children.length > 0) {
1338
+ blocks.push({
1339
+ type: "paragraph",
1340
+ properties: {
1341
+ numbering: {
1342
+ numId: ordered ? 2 : 1,
1343
+ level: level
1344
+ }
1345
+ },
1346
+ children
1347
+ });
1348
+ }
1349
+ return i;
1350
+ }
1351
+ // =============================================================================
1352
+ // Table parser
1353
+ // =============================================================================
1354
+ function parseTable(tokens, start, tableAttrs, classStyles) {
1355
+ const rows = [];
1356
+ let i = start;
1357
+ while (i < tokens.length) {
1358
+ const tok = tokens[i];
1359
+ if (tok.type === "close" && tok.tag === "table") {
1360
+ i++;
1361
+ break;
1362
+ }
1363
+ if (tok.type === "open" &&
1364
+ (tok.tag === "thead" || tok.tag === "tbody" || tok.tag === "tfoot")) {
1365
+ i++;
1366
+ continue;
1367
+ }
1368
+ if (tok.type === "close" &&
1369
+ (tok.tag === "thead" || tok.tag === "tbody" || tok.tag === "tfoot")) {
1370
+ i++;
1371
+ continue;
1372
+ }
1373
+ if (tok.type === "open" && tok.tag === "tr") {
1374
+ const row = parseTableRow(tokens, i + 1, classStyles);
1375
+ rows.push(row.row);
1376
+ i = row.endIdx;
1377
+ continue;
1378
+ }
1379
+ i++;
1380
+ }
1381
+ // Apply rowspan: insert vMerge "continue" cells in subsequent rows
1382
+ applyRowSpan(rows);
1383
+ // Parse table border style from attributes
1384
+ const tableBorders = parseTableBorders(tableAttrs);
1385
+ // Parse table width from style
1386
+ const tableStyle = parseCssStyle(tableAttrs["style"]);
1387
+ const tableProps = {};
1388
+ if (tableBorders) {
1389
+ tableProps.borders = tableBorders;
1390
+ }
1391
+ if (tableStyle.width) {
1392
+ tableProps.width = { value: tableStyle.width, type: "dxa" };
1393
+ }
1394
+ return {
1395
+ table: {
1396
+ type: "table",
1397
+ ...(Object.keys(tableProps).length > 0 ? { properties: tableProps } : {}),
1398
+ rows
1399
+ },
1400
+ endIdx: i
1401
+ };
1402
+ }
1403
+ function parseTableRow(tokens, start, classStyles) {
1404
+ const cells = [];
1405
+ let i = start;
1406
+ while (i < tokens.length) {
1407
+ const tok = tokens[i];
1408
+ if (tok.type === "close" && tok.tag === "tr") {
1409
+ return { row: { cells }, endIdx: i + 1 };
1410
+ }
1411
+ if (tok.type === "open" && (tok.tag === "td" || tok.tag === "th")) {
1412
+ const isHeader = tok.tag === "th";
1413
+ const attrs = tok.attrs;
1414
+ const children = [];
1415
+ const cellCtx = isHeader ? { bold: true } : {};
1416
+ const style = parseCssStyle(resolveEffectiveStyle(attrs, classStyles));
1417
+ applyCssToInlineContext(cellCtx, style);
1418
+ i = parseInlines(tokens, i + 1, children, cellCtx, tok.tag, classStyles);
1419
+ // Build cell properties
1420
+ const cellProps = buildCellProperties(attrs, style);
1421
+ // Build paragraph properties for text-align
1422
+ const paraProps = {};
1423
+ if (style.textAlign) {
1424
+ paraProps.alignment = style.textAlign;
1425
+ }
1426
+ cells.push({
1427
+ ...(cellProps ? { properties: cellProps } : {}),
1428
+ content: [
1429
+ {
1430
+ type: "paragraph",
1431
+ ...(Object.keys(paraProps).length > 0
1432
+ ? { properties: paraProps }
1433
+ : {}),
1434
+ children
1435
+ }
1436
+ ]
1437
+ });
1438
+ continue;
1439
+ }
1440
+ i++;
1441
+ }
1442
+ return { row: { cells }, endIdx: i };
1443
+ }
1444
+ /** Build TableCellProperties from HTML attributes (colspan, rowspan, borders). */
1445
+ function buildCellProperties(attrs, style) {
1446
+ const props = {};
1447
+ // colspan → gridSpan
1448
+ const colspan = parseInt(attrs["colspan"], 10);
1449
+ if (colspan > 1) {
1450
+ props.gridSpan = colspan;
1451
+ }
1452
+ // rowspan → verticalMerge restart (the continuation cells need "continue")
1453
+ const rowspan = parseInt(attrs["rowspan"], 10);
1454
+ if (rowspan > 1) {
1455
+ props.verticalMerge = "restart";
1456
+ props.rowSpan = rowspan;
1457
+ }
1458
+ // Cell width from style or width attribute
1459
+ if (style.width) {
1460
+ props.width = { value: style.width, type: "dxa" };
1461
+ }
1462
+ else if (attrs["width"]) {
1463
+ const w = parseCellWidthAttr(attrs["width"]);
1464
+ if (w) {
1465
+ props.width = w;
1466
+ }
1467
+ }
1468
+ // Background color from style
1469
+ if (style.backgroundColor) {
1470
+ props.shading = { pattern: "clear", fill: style.backgroundColor };
1471
+ }
1472
+ // Cell borders from inline style
1473
+ const cellBorders = parseCellBordersFromStyle(attrs["style"]);
1474
+ if (cellBorders) {
1475
+ props.borders = cellBorders;
1476
+ }
1477
+ return Object.keys(props).length > 0 ? props : undefined;
1478
+ }
1479
+ /** Parse a cell width attribute value (number in px, percentage, or plain number). */
1480
+ function parseCellWidthAttr(value) {
1481
+ if (!value) {
1482
+ return undefined;
1483
+ }
1484
+ // Percentage: "50%" → pct (fiftieths of a percent: 50% = 2500)
1485
+ const pctMatch = /^([\d.]+)%$/.exec(value.trim());
1486
+ if (pctMatch) {
1487
+ return { value: Math.round(parseFloat(pctMatch[1]) * 50), type: "pct" };
1488
+ }
1489
+ // Numeric (pixels): "200" or "200px" → convert to twips
1490
+ const pxMatch = /^(\d+)(?:px)?$/.exec(value.trim());
1491
+ if (pxMatch) {
1492
+ return { value: parseInt(pxMatch[1], 10) * 15, type: "dxa" };
1493
+ }
1494
+ return undefined;
1495
+ }
1496
+ /**
1497
+ * Post-process rows to insert vMerge "continue" cells for rowspan.
1498
+ * Scans rows for cells with rowSpan > 1, then inserts placeholder cells
1499
+ * with verticalMerge: "continue" in the appropriate positions in subsequent rows.
1500
+ */
1501
+ function applyRowSpan(rows) {
1502
+ const activeSpans = new Map();
1503
+ for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
1504
+ const row = rows[rowIdx];
1505
+ const newCells = [];
1506
+ let cellIdx = 0; // index into original cells
1507
+ let colIdx = 0; // logical column position
1508
+ // Insert vMerge "continue" cells for active rowspans
1509
+ while (colIdx < 1000) {
1510
+ // safety limit
1511
+ const span = activeSpans.get(colIdx);
1512
+ if (span && span.remaining > 0) {
1513
+ // Insert a continuation cell
1514
+ const contCell = {
1515
+ properties: {
1516
+ verticalMerge: "continue",
1517
+ ...(span.gridSpan > 1 ? { gridSpan: span.gridSpan } : {})
1518
+ },
1519
+ content: [{ type: "paragraph", children: [] }]
1520
+ };
1521
+ newCells.push(contCell);
1522
+ span.remaining--;
1523
+ if (span.remaining === 0) {
1524
+ activeSpans.delete(colIdx);
1525
+ }
1526
+ colIdx += span.gridSpan;
1527
+ continue;
1528
+ }
1529
+ // No active span at this column: use the next original cell
1530
+ if (cellIdx >= row.cells.length) {
1531
+ break;
1532
+ }
1533
+ const cell = row.cells[cellIdx];
1534
+ const cellGridSpan = cell.properties?.gridSpan || 1;
1535
+ const cellRowSpan = cell.properties?.rowSpan;
1536
+ // Register new rowspan
1537
+ if (cellRowSpan && cellRowSpan > 1) {
1538
+ activeSpans.set(colIdx, { remaining: cellRowSpan - 1, gridSpan: cellGridSpan });
1539
+ }
1540
+ newCells.push(cell);
1541
+ colIdx += cellGridSpan;
1542
+ cellIdx++;
1543
+ }
1544
+ // Replace the row's cells with the new array (including continuation cells)
1545
+ // We need to cast away readonly for mutation during this post-processing step
1546
+ rows[rowIdx].cells = newCells;
1547
+ }
1548
+ }
1549
+ /** Parse table-level borders from table attributes. */
1550
+ function parseTableBorders(attrs) {
1551
+ const style = parseCssStyle(attrs["style"]);
1552
+ const borderAttr = attrs["border"];
1553
+ // Check for border="1" attribute (common HTML table pattern)
1554
+ if (borderAttr && parseInt(borderAttr, 10) > 0) {
1555
+ const size = Math.max(4, parseInt(borderAttr, 10) * 4); // eighths of a point
1556
+ const border = { style: "single", size, color: "000000" };
1557
+ return {
1558
+ top: border,
1559
+ left: border,
1560
+ bottom: border,
1561
+ right: border,
1562
+ insideH: border,
1563
+ insideV: border
1564
+ };
1565
+ }
1566
+ // Check style attribute for border
1567
+ const borderStyle = parseBorderStyleFromCss(attrs["style"]);
1568
+ if (borderStyle) {
1569
+ return {
1570
+ top: borderStyle,
1571
+ left: borderStyle,
1572
+ bottom: borderStyle,
1573
+ right: borderStyle,
1574
+ insideH: borderStyle,
1575
+ insideV: borderStyle
1576
+ };
1577
+ }
1578
+ // background-color at table level can influence shading (handled separately)
1579
+ void style;
1580
+ return undefined;
1581
+ }
1582
+ /** Parse border CSS shorthand to a Border object. */
1583
+ function parseBorderStyleFromCss(styleStr) {
1584
+ if (!styleStr) {
1585
+ return undefined;
1586
+ }
1587
+ // Match border: <width> <style> <color> or border-style, border-width, border-color
1588
+ const declarations = styleStr.split(";");
1589
+ let borderWidth;
1590
+ let borderStyleVal;
1591
+ let borderColor;
1592
+ for (const decl of declarations) {
1593
+ const colonIdx = decl.indexOf(":");
1594
+ if (colonIdx < 0) {
1595
+ continue;
1596
+ }
1597
+ const prop = decl.slice(0, colonIdx).trim().toLowerCase();
1598
+ const value = decl
1599
+ .slice(colonIdx + 1)
1600
+ .trim()
1601
+ .toLowerCase();
1602
+ if (prop === "border") {
1603
+ // Shorthand: border: 1px solid black
1604
+ const parts = value.split(/\s+/);
1605
+ for (const part of parts) {
1606
+ if (/^\d/.test(part)) {
1607
+ borderWidth = parseBorderWidth(part);
1608
+ }
1609
+ else if (isBorderStyleKeyword(part)) {
1610
+ borderStyleVal = part;
1611
+ }
1612
+ else {
1613
+ borderColor = parseCssColor(part) || borderColor;
1614
+ }
1615
+ }
1616
+ }
1617
+ else if (prop === "border-style") {
1618
+ borderStyleVal = value.split(/\s+/)[0];
1619
+ }
1620
+ else if (prop === "border-width") {
1621
+ borderWidth = parseBorderWidth(value.split(/\s+/)[0]);
1622
+ }
1623
+ else if (prop === "border-color") {
1624
+ borderColor = parseCssColor(value.split(/\s+/)[0]) || borderColor;
1625
+ }
1626
+ }
1627
+ if (borderStyleVal && borderStyleVal !== "none" && borderStyleVal !== "hidden") {
1628
+ return {
1629
+ style: mapCssBorderStyle(borderStyleVal),
1630
+ size: borderWidth || 4,
1631
+ color: borderColor || "000000"
1632
+ };
1633
+ }
1634
+ return undefined;
1635
+ }
1636
+ /** Parse cell-level borders from inline style string. */
1637
+ function parseCellBordersFromStyle(styleStr) {
1638
+ if (!styleStr) {
1639
+ return undefined;
1640
+ }
1641
+ const borderDef = parseBorderStyleFromCss(styleStr);
1642
+ if (!borderDef) {
1643
+ return undefined;
1644
+ }
1645
+ return {
1646
+ top: borderDef,
1647
+ left: borderDef,
1648
+ bottom: borderDef,
1649
+ right: borderDef
1650
+ };
1651
+ }
1652
+ function parseBorderWidth(value) {
1653
+ const match = /^([\d.]+)\s*(px|pt)?$/.exec(value);
1654
+ if (!match) {
1655
+ return 4;
1656
+ }
1657
+ const num = parseFloat(match[1]);
1658
+ const unit = match[2] || "px";
1659
+ if (unit === "pt") {
1660
+ return Math.round(num * 8); // eighths of a point
1661
+ }
1662
+ // px: approximate 1px ≈ 0.75pt → 6 eighths
1663
+ return Math.round(num * 6);
1664
+ }
1665
+ function isBorderStyleKeyword(value) {
1666
+ return [
1667
+ "none",
1668
+ "hidden",
1669
+ "dotted",
1670
+ "dashed",
1671
+ "solid",
1672
+ "double",
1673
+ "groove",
1674
+ "ridge",
1675
+ "inset",
1676
+ "outset"
1677
+ ].includes(value);
1678
+ }
1679
+ function mapCssBorderStyle(cssStyle) {
1680
+ switch (cssStyle) {
1681
+ case "solid":
1682
+ case "groove":
1683
+ case "ridge":
1684
+ case "inset":
1685
+ case "outset":
1686
+ return "single";
1687
+ case "double":
1688
+ return "double";
1689
+ case "dotted":
1690
+ return "dotted";
1691
+ case "dashed":
1692
+ return "dashed";
1693
+ case "none":
1694
+ case "hidden":
1695
+ return "none";
1696
+ default:
1697
+ return "single";
1698
+ }
1699
+ }
1700
+ // =============================================================================
1701
+ // Image content builder
1702
+ // =============================================================================
1703
+ /** Build InlineImageContent from img attributes or return undefined if not applicable. */
1704
+ function buildImageContent(attrs) {
1705
+ const src = attrs["src"] || "";
1706
+ const alt = attrs["alt"] || "";
1707
+ // Parse width/height from attributes first, then fall back to style
1708
+ let width = parseImageDimension(attrs["width"]);
1709
+ let height = parseImageDimension(attrs["height"]);
1710
+ // Also check inline style for width/height
1711
+ if (!width || !height) {
1712
+ const styleDims = parseImageDimensionsFromStyle(attrs["style"]);
1713
+ if (!width && styleDims.width) {
1714
+ width = styleDims.width;
1715
+ }
1716
+ if (!height && styleDims.height) {
1717
+ height = styleDims.height;
1718
+ }
1719
+ }
1720
+ // Convert pixels to EMU
1721
+ const widthEmu = (width || 100) * EMU_PER_PX;
1722
+ const heightEmu = (height || 100) * EMU_PER_PX;
1723
+ // Both data: and http(s) URLs become placeholders. The DOCX writer needs
1724
+ // a real ImageDef registered in `doc.images` plus a corresponding
1725
+ // relationship; htmlToDocxBody returns BodyContent[] only and cannot do
1726
+ // that registration. We surface the original src in the alt text so the
1727
+ // user can post-process if they need real embedded images.
1728
+ if (src.startsWith("data:") || src.startsWith("http://") || src.startsWith("https://")) {
1729
+ return {
1730
+ type: "image",
1731
+ rId: "", // empty rId → renderer treats this as a placeholder
1732
+ width: widthEmu,
1733
+ height: heightEmu,
1734
+ altText: alt || `[Image placeholder: ${src.slice(0, 64)}${src.length > 64 ? "…" : ""}]`,
1735
+ name: alt || "image"
1736
+ };
1737
+ }
1738
+ return undefined;
1739
+ }
1740
+ /** Parse an image dimension from HTML attribute value (number or "Npx"). */
1741
+ function parseImageDimension(value) {
1742
+ if (!value) {
1743
+ return undefined;
1744
+ }
1745
+ const match = /^(\d+)(?:px)?$/.exec(value.trim());
1746
+ return match ? parseInt(match[1], 10) : undefined;
1747
+ }
1748
+ /** Parse width and height from an inline style string (for <img> elements). */
1749
+ function parseImageDimensionsFromStyle(styleStr) {
1750
+ const result = {};
1751
+ if (!styleStr) {
1752
+ return result;
1753
+ }
1754
+ const declarations = styleStr.split(";");
1755
+ for (const decl of declarations) {
1756
+ const colonIdx = decl.indexOf(":");
1757
+ if (colonIdx < 0) {
1758
+ continue;
1759
+ }
1760
+ const prop = decl.slice(0, colonIdx).trim().toLowerCase();
1761
+ const value = decl
1762
+ .slice(colonIdx + 1)
1763
+ .trim()
1764
+ .toLowerCase();
1765
+ if (prop === "width") {
1766
+ const px = parseImageCssDimension(value);
1767
+ if (px !== undefined) {
1768
+ result.width = px;
1769
+ }
1770
+ }
1771
+ else if (prop === "height") {
1772
+ const px = parseImageCssDimension(value);
1773
+ if (px !== undefined) {
1774
+ result.height = px;
1775
+ }
1776
+ }
1777
+ }
1778
+ return result;
1779
+ }
1780
+ /** Parse a CSS dimension value for images into pixels. */
1781
+ function parseImageCssDimension(value) {
1782
+ const match = /^([\d.]+)\s*(px|pt|in|cm|mm)?$/.exec(value);
1783
+ if (!match) {
1784
+ return undefined;
1785
+ }
1786
+ const num = parseFloat(match[1]);
1787
+ const unit = match[2] || "px";
1788
+ switch (unit) {
1789
+ case "px":
1790
+ return Math.round(num);
1791
+ case "pt":
1792
+ // 1pt = 1.333px
1793
+ return Math.round(num * 1.333);
1794
+ case "in":
1795
+ // 1in = 96px
1796
+ return Math.round(num * 96);
1797
+ case "cm":
1798
+ // 1cm ≈ 37.8px
1799
+ return Math.round(num * 37.8);
1800
+ case "mm":
1801
+ // 1mm ≈ 3.78px
1802
+ return Math.round(num * 3.78);
1803
+ default:
1804
+ return undefined;
1805
+ }
1806
+ }
1807
+ // =============================================================================
1808
+ // CSS → InlineContext helper
1809
+ // =============================================================================
1810
+ /** Apply parsed CSS styles to an InlineContext. */
1811
+ function applyCssToInlineContext(ctx, style) {
1812
+ if (style.bold) {
1813
+ ctx.bold = true;
1814
+ }
1815
+ if (style.italic) {
1816
+ ctx.italic = true;
1817
+ }
1818
+ if (style.underline) {
1819
+ ctx.underline = true;
1820
+ }
1821
+ if (style.lineThrough) {
1822
+ ctx.strikethrough = true;
1823
+ }
1824
+ if (style.color) {
1825
+ ctx.color = style.color;
1826
+ }
1827
+ if (style.backgroundColor) {
1828
+ ctx.backgroundColor = style.backgroundColor;
1829
+ }
1830
+ if (style.fontFamily) {
1831
+ ctx.fontFamily = style.fontFamily;
1832
+ }
1833
+ if (style.fontSize) {
1834
+ ctx.fontSize = style.fontSize;
1835
+ }
1836
+ }
1837
+ /**
1838
+ * Resolve the effective inline style string for an element by merging class-based styles
1839
+ * with inline styles. Inline styles take priority over class-based styles.
1840
+ */
1841
+ function resolveEffectiveStyle(attrs, classStyles) {
1842
+ const classAttr = attrs["class"];
1843
+ let merged;
1844
+ if (classAttr) {
1845
+ const classNames = classAttr.split(/\s+/).filter(Boolean);
1846
+ const parts = [];
1847
+ for (const name of classNames) {
1848
+ const s = classStyles[name];
1849
+ if (s) {
1850
+ parts.push(s);
1851
+ }
1852
+ }
1853
+ if (parts.length > 0) {
1854
+ merged = parts.join("; ");
1855
+ }
1856
+ }
1857
+ const inlineStyle = attrs["style"];
1858
+ if (merged && inlineStyle) {
1859
+ // Inline style overrides: append after class-based style so later declarations win
1860
+ return merged + "; " + inlineStyle;
1861
+ }
1862
+ return inlineStyle || merged;
1863
+ }
1864
+ // =============================================================================
1865
+ // Run builder
1866
+ // =============================================================================
1867
+ function makeRun(text, ctx) {
1868
+ const props = {};
1869
+ if (ctx.bold) {
1870
+ props.bold = true;
1871
+ }
1872
+ if (ctx.italic) {
1873
+ props.italic = true;
1874
+ }
1875
+ if (ctx.underline) {
1876
+ props.underline = "single";
1877
+ }
1878
+ if (ctx.strikethrough) {
1879
+ props.strike = true;
1880
+ }
1881
+ if (ctx.superscript) {
1882
+ props.vertAlign = "superscript";
1883
+ }
1884
+ if (ctx.subscript) {
1885
+ props.vertAlign = "subscript";
1886
+ }
1887
+ if (ctx.code) {
1888
+ props.font = { ascii: "Courier New", hAnsi: "Courier New" };
1889
+ }
1890
+ else if (ctx.fontFamily) {
1891
+ props.font = { ascii: ctx.fontFamily, hAnsi: ctx.fontFamily };
1892
+ }
1893
+ if (ctx.fontSize) {
1894
+ props.size = ctx.fontSize;
1895
+ }
1896
+ if (ctx.color) {
1897
+ props.color = ctx.color;
1898
+ }
1899
+ if (ctx.backgroundColor) {
1900
+ props.shading = { pattern: "clear", fill: ctx.backgroundColor };
1901
+ }
1902
+ const run = {
1903
+ ...(Object.keys(props).length > 0 ? { properties: props } : {}),
1904
+ content: [{ type: "text", text }]
1905
+ };
1906
+ return run;
1907
+ }