docxmlater 10.0.1 → 10.0.3

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 (395) hide show
  1. package/README.md +3 -2
  2. package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
  3. package/dist/constants/legacyCompatFlags.js.map +1 -1
  4. package/dist/constants/limits.d.ts +0 -27
  5. package/dist/constants/limits.d.ts.map +1 -1
  6. package/dist/constants/limits.js +13 -13
  7. package/dist/constants/limits.js.map +1 -1
  8. package/dist/core/Document.d.ts +24 -19
  9. package/dist/core/Document.d.ts.map +1 -1
  10. package/dist/core/Document.js +272 -71
  11. package/dist/core/Document.js.map +1 -1
  12. package/dist/core/DocumentContent.d.ts.map +1 -1
  13. package/dist/core/DocumentContent.js.map +1 -1
  14. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  15. package/dist/core/DocumentGenerator.js +59 -24
  16. package/dist/core/DocumentGenerator.js.map +1 -1
  17. package/dist/core/DocumentIdManager.d.ts.map +1 -1
  18. package/dist/core/DocumentIdManager.js.map +1 -1
  19. package/dist/core/DocumentParser.d.ts +6 -6
  20. package/dist/core/DocumentParser.d.ts.map +1 -1
  21. package/dist/core/DocumentParser.js +60 -54
  22. package/dist/core/DocumentParser.js.map +1 -1
  23. package/dist/core/DocumentValidator.d.ts.map +1 -1
  24. package/dist/core/DocumentValidator.js.map +1 -1
  25. package/dist/core/Relationship.d.ts.map +1 -1
  26. package/dist/core/Relationship.js +1 -1
  27. package/dist/core/Relationship.js.map +1 -1
  28. package/dist/core/RelationshipManager.js +3 -3
  29. package/dist/core/RelationshipManager.js.map +1 -1
  30. package/dist/elements/AlternateContent.js.map +1 -1
  31. package/dist/elements/Bookmark.d.ts.map +1 -1
  32. package/dist/elements/Bookmark.js.map +1 -1
  33. package/dist/elements/BookmarkManager.d.ts.map +1 -1
  34. package/dist/elements/BookmarkManager.js.map +1 -1
  35. package/dist/elements/Comment.js +1 -1
  36. package/dist/elements/Comment.js.map +1 -1
  37. package/dist/elements/CommentManager.d.ts.map +1 -1
  38. package/dist/elements/CommentManager.js +8 -2
  39. package/dist/elements/CommentManager.js.map +1 -1
  40. package/dist/elements/CommonTypes.d.ts.map +1 -1
  41. package/dist/elements/CommonTypes.js +1 -2
  42. package/dist/elements/CommonTypes.js.map +1 -1
  43. package/dist/elements/CustomXml.js.map +1 -1
  44. package/dist/elements/Endnote.d.ts.map +1 -1
  45. package/dist/elements/Endnote.js.map +1 -1
  46. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  47. package/dist/elements/EndnoteManager.js.map +1 -1
  48. package/dist/elements/Field.d.ts.map +1 -1
  49. package/dist/elements/Field.js +31 -28
  50. package/dist/elements/Field.js.map +1 -1
  51. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  52. package/dist/elements/FieldHelpers.js +6 -6
  53. package/dist/elements/FieldHelpers.js.map +1 -1
  54. package/dist/elements/FontManager.d.ts.map +1 -1
  55. package/dist/elements/FontManager.js.map +1 -1
  56. package/dist/elements/Footer.js.map +1 -1
  57. package/dist/elements/Footnote.d.ts.map +1 -1
  58. package/dist/elements/Footnote.js.map +1 -1
  59. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  60. package/dist/elements/FootnoteManager.js.map +1 -1
  61. package/dist/elements/Header.js.map +1 -1
  62. package/dist/elements/HeaderFooterManager.js.map +1 -1
  63. package/dist/elements/Hyperlink.d.ts.map +1 -1
  64. package/dist/elements/Hyperlink.js +5 -5
  65. package/dist/elements/Hyperlink.js.map +1 -1
  66. package/dist/elements/Image.d.ts +2 -2
  67. package/dist/elements/Image.d.ts.map +1 -1
  68. package/dist/elements/Image.js +21 -5
  69. package/dist/elements/Image.js.map +1 -1
  70. package/dist/elements/ImageManager.d.ts.map +1 -1
  71. package/dist/elements/ImageManager.js +2 -2
  72. package/dist/elements/ImageManager.js.map +1 -1
  73. package/dist/elements/ImageRun.js.map +1 -1
  74. package/dist/elements/MathElement.js.map +1 -1
  75. package/dist/elements/Paragraph.d.ts.map +1 -1
  76. package/dist/elements/Paragraph.js +128 -117
  77. package/dist/elements/Paragraph.js.map +1 -1
  78. package/dist/elements/PreservedElement.js.map +1 -1
  79. package/dist/elements/PropertyChangeTypes.js.map +1 -1
  80. package/dist/elements/RangeMarker.js.map +1 -1
  81. package/dist/elements/Revision.d.ts +1 -0
  82. package/dist/elements/Revision.d.ts.map +1 -1
  83. package/dist/elements/Revision.js +44 -5
  84. package/dist/elements/Revision.js.map +1 -1
  85. package/dist/elements/RevisionContent.js.map +1 -1
  86. package/dist/elements/RevisionManager.d.ts.map +1 -1
  87. package/dist/elements/RevisionManager.js.map +1 -1
  88. package/dist/elements/Run.d.ts.map +1 -1
  89. package/dist/elements/Run.js +1 -3
  90. package/dist/elements/Run.js.map +1 -1
  91. package/dist/elements/Section.d.ts.map +1 -1
  92. package/dist/elements/Section.js +127 -118
  93. package/dist/elements/Section.js.map +1 -1
  94. package/dist/elements/Shape.d.ts.map +1 -1
  95. package/dist/elements/Shape.js +21 -0
  96. package/dist/elements/Shape.js.map +1 -1
  97. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  98. package/dist/elements/StructuredDocumentTag.js +20 -8
  99. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  100. package/dist/elements/Table.d.ts +2 -2
  101. package/dist/elements/Table.d.ts.map +1 -1
  102. package/dist/elements/Table.js +29 -35
  103. package/dist/elements/Table.js.map +1 -1
  104. package/dist/elements/TableCell.d.ts +2 -2
  105. package/dist/elements/TableCell.d.ts.map +1 -1
  106. package/dist/elements/TableCell.js +63 -67
  107. package/dist/elements/TableCell.js.map +1 -1
  108. package/dist/elements/TableGridChange.js.map +1 -1
  109. package/dist/elements/TableOfContents.d.ts +6 -6
  110. package/dist/elements/TableOfContents.d.ts.map +1 -1
  111. package/dist/elements/TableOfContents.js.map +1 -1
  112. package/dist/elements/TableOfContentsElement.js.map +1 -1
  113. package/dist/elements/TableRow.d.ts.map +1 -1
  114. package/dist/elements/TableRow.js +65 -47
  115. package/dist/elements/TableRow.js.map +1 -1
  116. package/dist/elements/TextBox.d.ts.map +1 -1
  117. package/dist/elements/TextBox.js +1 -1
  118. package/dist/elements/TextBox.js.map +1 -1
  119. package/dist/formatting/AbstractNumbering.d.ts +1 -1
  120. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  121. package/dist/formatting/AbstractNumbering.js +11 -11
  122. package/dist/formatting/AbstractNumbering.js.map +1 -1
  123. package/dist/formatting/NumberingInstance.d.ts.map +1 -1
  124. package/dist/formatting/NumberingInstance.js +4 -4
  125. package/dist/formatting/NumberingInstance.js.map +1 -1
  126. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  127. package/dist/formatting/NumberingLevel.js +26 -26
  128. package/dist/formatting/NumberingLevel.js.map +1 -1
  129. package/dist/formatting/NumberingManager.d.ts +1 -1
  130. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  131. package/dist/formatting/NumberingManager.js.map +1 -1
  132. package/dist/formatting/Style.d.ts.map +1 -1
  133. package/dist/formatting/Style.js +87 -95
  134. package/dist/formatting/Style.js.map +1 -1
  135. package/dist/formatting/StylesManager.d.ts +3 -3
  136. package/dist/formatting/StylesManager.d.ts.map +1 -1
  137. package/dist/formatting/StylesManager.js.map +1 -1
  138. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  139. package/dist/helpers/CleanupHelper.js +1 -7
  140. package/dist/helpers/CleanupHelper.js.map +1 -1
  141. package/dist/images/ImageOptimizer.js.map +1 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/managers/DrawingManager.d.ts.map +1 -1
  144. package/dist/managers/DrawingManager.js.map +1 -1
  145. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  146. package/dist/tracking/TrackingContext.js.map +1 -1
  147. package/dist/types/compatibility-types.js.map +1 -1
  148. package/dist/types/formatting.js.map +1 -1
  149. package/dist/types/list-types.d.ts +4 -4
  150. package/dist/types/list-types.d.ts.map +1 -1
  151. package/dist/types/list-types.js.map +1 -1
  152. package/dist/types/settings-types.js.map +1 -1
  153. package/dist/types/styleConfig.js.map +1 -1
  154. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  155. package/dist/utils/ChangelogGenerator.js.map +1 -1
  156. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  157. package/dist/utils/CompatibilityUpgrader.js +7 -7
  158. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  159. package/dist/utils/InMemoryRevisionAcceptor.js +1 -1
  160. package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
  161. package/dist/utils/MoveOperationHelper.js.map +1 -1
  162. package/dist/utils/RevisionAwareProcessor.js.map +1 -1
  163. package/dist/utils/RevisionWalker.js.map +1 -1
  164. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  165. package/dist/utils/ShadingResolver.js +1 -1
  166. package/dist/utils/ShadingResolver.js.map +1 -1
  167. package/dist/utils/acceptRevisions.d.ts +0 -28
  168. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  169. package/dist/utils/acceptRevisions.js +5 -7
  170. package/dist/utils/acceptRevisions.js.map +1 -1
  171. package/dist/utils/cnfStyleDecoder.js +1 -1
  172. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  173. package/dist/utils/corruptionDetection.js.map +1 -1
  174. package/dist/utils/dateFormatting.js.map +1 -1
  175. package/dist/utils/deepClone.d.ts +0 -1
  176. package/dist/utils/deepClone.d.ts.map +1 -1
  177. package/dist/utils/deepClone.js +0 -7
  178. package/dist/utils/deepClone.js.map +1 -1
  179. package/dist/utils/diagnostics.d.ts +2 -2
  180. package/dist/utils/diagnostics.d.ts.map +1 -1
  181. package/dist/utils/diagnostics.js.map +1 -1
  182. package/dist/utils/errorHandling.js.map +1 -1
  183. package/dist/utils/formatting.js.map +1 -1
  184. package/dist/utils/list-detection.d.ts +2 -2
  185. package/dist/utils/list-detection.d.ts.map +1 -1
  186. package/dist/utils/list-detection.js +3 -3
  187. package/dist/utils/list-detection.js.map +1 -1
  188. package/dist/utils/logger.d.ts +2 -4
  189. package/dist/utils/logger.d.ts.map +1 -1
  190. package/dist/utils/logger.js +0 -2
  191. package/dist/utils/logger.js.map +1 -1
  192. package/dist/utils/parsingHelpers.js.map +1 -1
  193. package/dist/utils/stripTrackedChanges.d.ts +0 -19
  194. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  195. package/dist/utils/stripTrackedChanges.js +0 -2
  196. package/dist/utils/stripTrackedChanges.js.map +1 -1
  197. package/dist/utils/textDiff.js.map +1 -1
  198. package/dist/utils/units.js.map +1 -1
  199. package/dist/utils/validation.d.ts.map +1 -1
  200. package/dist/utils/validation.js.map +1 -1
  201. package/dist/utils/xmlSanitization.js.map +1 -1
  202. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  203. package/dist/validation/RevisionValidator.js.map +1 -1
  204. package/dist/validation/ValidationRules.js.map +1 -1
  205. package/dist/validation/index.js.map +1 -1
  206. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  207. package/dist/xml/XMLBuilder.js +10 -0
  208. package/dist/xml/XMLBuilder.js.map +1 -1
  209. package/dist/xml/XMLParser.d.ts.map +1 -1
  210. package/dist/xml/XMLParser.js +4 -5
  211. package/dist/xml/XMLParser.js.map +1 -1
  212. package/dist/zip/ZipHandler.js.map +1 -1
  213. package/dist/zip/ZipReader.js.map +1 -1
  214. package/dist/zip/ZipWriter.js.map +1 -1
  215. package/dist/zip/errors.js.map +1 -1
  216. package/dist/zip/types.js.map +1 -1
  217. package/package.json +34 -4
  218. package/src/__tests__/helper-methods.test.ts +512 -0
  219. package/src/constants/legacyCompatFlags.ts +138 -0
  220. package/src/constants/limits.ts +50 -0
  221. package/src/core/CLAUDE.md +109 -0
  222. package/src/core/Document.ts +15569 -0
  223. package/src/core/DocumentContent.ts +467 -0
  224. package/src/core/DocumentGenerator.ts +1104 -0
  225. package/src/core/DocumentIdManager.ts +158 -0
  226. package/src/core/DocumentParser.ts +10107 -0
  227. package/src/core/DocumentValidator.ts +372 -0
  228. package/src/core/Relationship.ts +367 -0
  229. package/src/core/RelationshipManager.ts +428 -0
  230. package/src/elements/AlternateContent.ts +42 -0
  231. package/src/elements/Bookmark.ts +210 -0
  232. package/src/elements/BookmarkManager.ts +250 -0
  233. package/src/elements/CLAUDE.md +126 -0
  234. package/src/elements/Comment.ts +359 -0
  235. package/src/elements/CommentManager.ts +502 -0
  236. package/src/elements/CommonTypes.ts +549 -0
  237. package/src/elements/CustomXml.ts +36 -0
  238. package/src/elements/Endnote.ts +217 -0
  239. package/src/elements/EndnoteManager.ts +249 -0
  240. package/src/elements/Field.ts +1233 -0
  241. package/src/elements/FieldHelpers.ts +333 -0
  242. package/src/elements/FontManager.ts +339 -0
  243. package/src/elements/Footer.ts +269 -0
  244. package/src/elements/Footnote.ts +217 -0
  245. package/src/elements/FootnoteManager.ts +249 -0
  246. package/src/elements/Header.ts +269 -0
  247. package/src/elements/HeaderFooterManager.ts +219 -0
  248. package/src/elements/Hyperlink.ts +1146 -0
  249. package/src/elements/Image.ts +1756 -0
  250. package/src/elements/ImageManager.ts +432 -0
  251. package/src/elements/ImageRun.ts +59 -0
  252. package/src/elements/MathElement.ts +65 -0
  253. package/src/elements/Paragraph.ts +4227 -0
  254. package/src/elements/PreservedElement.ts +53 -0
  255. package/src/elements/PropertyChangeTypes.ts +442 -0
  256. package/src/elements/RangeMarker.ts +400 -0
  257. package/src/elements/Revision.ts +1217 -0
  258. package/src/elements/RevisionContent.ts +73 -0
  259. package/src/elements/RevisionManager.ts +1070 -0
  260. package/src/elements/Run.ts +3068 -0
  261. package/src/elements/Section.ts +1421 -0
  262. package/src/elements/Shape.ts +873 -0
  263. package/src/elements/StructuredDocumentTag.ts +978 -0
  264. package/src/elements/Table.ts +2524 -0
  265. package/src/elements/TableCell.ts +1586 -0
  266. package/src/elements/TableGridChange.ts +151 -0
  267. package/src/elements/TableOfContents.ts +691 -0
  268. package/src/elements/TableOfContentsElement.ts +89 -0
  269. package/src/elements/TableRow.ts +906 -0
  270. package/src/elements/TextBox.ts +768 -0
  271. package/src/formatting/AbstractNumbering.ts +548 -0
  272. package/src/formatting/CLAUDE.md +74 -0
  273. package/src/formatting/NumberingInstance.ts +212 -0
  274. package/src/formatting/NumberingLevel.ts +1006 -0
  275. package/src/formatting/NumberingManager.ts +827 -0
  276. package/src/formatting/Style.ts +1833 -0
  277. package/src/formatting/StylesManager.ts +1005 -0
  278. package/src/helpers/CleanupHelper.ts +524 -0
  279. package/src/images/ImageOptimizer.ts +274 -0
  280. package/src/index.ts +554 -0
  281. package/src/managers/CLAUDE.md +47 -0
  282. package/src/managers/DrawingManager.ts +319 -0
  283. package/src/tracking/DocumentTrackingContext.ts +643 -0
  284. package/src/tracking/TrackingContext.ts +173 -0
  285. package/src/types/compatibility-types.ts +49 -0
  286. package/src/types/formatting.ts +210 -0
  287. package/src/types/list-types.ts +152 -0
  288. package/src/types/settings-types.ts +59 -0
  289. package/src/types/styleConfig.ts +189 -0
  290. package/src/utils/CLAUDE.md +153 -0
  291. package/src/utils/ChangelogGenerator.ts +1581 -0
  292. package/src/utils/CompatibilityUpgrader.ts +237 -0
  293. package/src/utils/InMemoryRevisionAcceptor.ts +668 -0
  294. package/src/utils/MoveOperationHelper.ts +238 -0
  295. package/src/utils/RevisionAwareProcessor.ts +526 -0
  296. package/src/utils/RevisionWalker.ts +457 -0
  297. package/src/utils/SelectiveRevisionAcceptor.ts +613 -0
  298. package/src/utils/ShadingResolver.ts +107 -0
  299. package/src/utils/acceptRevisions.ts +714 -0
  300. package/src/utils/cnfStyleDecoder.ts +217 -0
  301. package/src/utils/corruptionDetection.ts +345 -0
  302. package/src/utils/dateFormatting.ts +20 -0
  303. package/src/utils/deepClone.ts +78 -0
  304. package/src/utils/diagnostics.ts +129 -0
  305. package/src/utils/errorHandling.ts +80 -0
  306. package/src/utils/formatting.ts +213 -0
  307. package/src/utils/list-detection.ts +274 -0
  308. package/src/utils/logger.ts +404 -0
  309. package/src/utils/parsingHelpers.ts +190 -0
  310. package/src/utils/stripTrackedChanges.ts +353 -0
  311. package/src/utils/textDiff.ts +100 -0
  312. package/src/utils/units.ts +421 -0
  313. package/src/utils/validation.ts +542 -0
  314. package/src/utils/xmlSanitization.ts +182 -0
  315. package/src/validation/RevisionAutoFixer.ts +542 -0
  316. package/src/validation/RevisionValidator.ts +460 -0
  317. package/src/validation/ValidationRules.ts +338 -0
  318. package/src/validation/index.ts +30 -0
  319. package/src/xml/CLAUDE.md +65 -0
  320. package/src/xml/XMLBuilder.ts +871 -0
  321. package/src/xml/XMLParser.ts +919 -0
  322. package/src/zip/CLAUDE.md +55 -0
  323. package/src/zip/ZipHandler.ts +637 -0
  324. package/src/zip/ZipReader.ts +299 -0
  325. package/src/zip/ZipWriter.ts +390 -0
  326. package/src/zip/errors.ts +69 -0
  327. package/src/zip/types.ts +116 -0
  328. package/dist/core/ListNormalizer.d.ts +0 -23
  329. package/dist/core/ListNormalizer.d.ts.map +0 -1
  330. package/dist/core/ListNormalizer.js +0 -624
  331. package/dist/core/ListNormalizer.js.map +0 -1
  332. package/dist/images/index.d.ts +0 -2
  333. package/dist/images/index.d.ts.map +0 -1
  334. package/dist/images/index.js +0 -8
  335. package/dist/images/index.js.map +0 -1
  336. package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
  337. package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
  338. package/dist/ms-doc/cfb/CFBReader.js +0 -360
  339. package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
  340. package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
  341. package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
  342. package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
  343. package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
  344. package/dist/ms-doc/fib/FIB.d.ts +0 -18
  345. package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
  346. package/dist/ms-doc/fib/FIB.js +0 -342
  347. package/dist/ms-doc/fib/FIB.js.map +0 -1
  348. package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
  349. package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
  350. package/dist/ms-doc/fields/FieldParser.js +0 -266
  351. package/dist/ms-doc/fields/FieldParser.js.map +0 -1
  352. package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
  353. package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
  354. package/dist/ms-doc/images/PictureExtractor.js +0 -233
  355. package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
  356. package/dist/ms-doc/index.d.ts +0 -20
  357. package/dist/ms-doc/index.d.ts.map +0 -1
  358. package/dist/ms-doc/index.js +0 -59
  359. package/dist/ms-doc/index.js.map +0 -1
  360. package/dist/ms-doc/properties/SPRM.d.ts +0 -210
  361. package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
  362. package/dist/ms-doc/properties/SPRM.js +0 -633
  363. package/dist/ms-doc/properties/SPRM.js.map +0 -1
  364. package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
  365. package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
  366. package/dist/ms-doc/sections/SectionParser.js +0 -214
  367. package/dist/ms-doc/sections/SectionParser.js.map +0 -1
  368. package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
  369. package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
  370. package/dist/ms-doc/styles/StyleSheet.js +0 -268
  371. package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
  372. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
  373. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
  374. package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
  375. package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
  376. package/dist/ms-doc/tables/TableParser.d.ts +0 -29
  377. package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
  378. package/dist/ms-doc/tables/TableParser.js +0 -176
  379. package/dist/ms-doc/tables/TableParser.js.map +0 -1
  380. package/dist/ms-doc/text/PieceTable.d.ts +0 -21
  381. package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
  382. package/dist/ms-doc/text/PieceTable.js +0 -171
  383. package/dist/ms-doc/text/PieceTable.js.map +0 -1
  384. package/dist/ms-doc/types/Constants.d.ts +0 -99
  385. package/dist/ms-doc/types/Constants.d.ts.map +0 -1
  386. package/dist/ms-doc/types/Constants.js +0 -102
  387. package/dist/ms-doc/types/Constants.js.map +0 -1
  388. package/dist/ms-doc/types/DocTypes.d.ts +0 -368
  389. package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
  390. package/dist/ms-doc/types/DocTypes.js +0 -3
  391. package/dist/ms-doc/types/DocTypes.js.map +0 -1
  392. package/dist/tracking/index.d.ts +0 -3
  393. package/dist/tracking/index.d.ts.map +0 -1
  394. package/dist/tracking/index.js +0 -6
  395. package/dist/tracking/index.js.map +0 -1
@@ -0,0 +1,871 @@
1
+ /**
2
+ * XMLBuilder - Utility for building XML content
3
+ * Provides a simple fluent API for generating WordprocessingML XML
4
+ */
5
+
6
+ import { removeInvalidXmlChars } from "../utils/xmlSanitization";
7
+ import type { ShadingConfig } from "../elements/CommonTypes";
8
+ import { buildShadingAttributes } from "../elements/CommonTypes";
9
+
10
+ /** Represents a parsed XML object from XMLParser.parseToObject() */
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- parsed XML has dynamic keys and recursive structure
12
+ type ParsedXmlObject = Record<string, any>;
13
+
14
+ /**
15
+ * Represents an XML element with attributes and children
16
+ */
17
+ export interface XMLElement {
18
+ name: string;
19
+ attributes?: Record<string, string | number | boolean | undefined>;
20
+ children?: (XMLElement | string)[];
21
+ selfClosing?: boolean;
22
+ /** Raw XML content to include without escaping (used for VML passthrough) */
23
+ rawXml?: string;
24
+ }
25
+
26
+ /**
27
+ * XML Builder for creating WordprocessingML XML
28
+ */
29
+ export class XMLBuilder {
30
+ private elements: (XMLElement | string)[] = [];
31
+
32
+ /**
33
+ * Elements that must NEVER be self-closing in Word XML per ECMA-376.
34
+ * Self-closing these elements causes Word to not parse correctly or lose content.
35
+ */
36
+ private static readonly CANNOT_SELF_CLOSE = [
37
+ "w:t",
38
+ "w:r",
39
+ "w:p",
40
+ "w:tbl",
41
+ "w:tr",
42
+ "w:tc",
43
+ "w:body",
44
+ "w:document",
45
+ "w:hyperlink",
46
+ "w:sdt",
47
+ "w:sdtContent",
48
+ "w:sdtPr",
49
+ "w:pPr",
50
+ "w:rPr",
51
+ "w:sectPr",
52
+ "w:del", // Deletion revisions - container element, must have closing tag
53
+ "w:ins", // Insertion revisions - container element, must have closing tag
54
+ "w:moveFrom", // Move source markers - container element
55
+ "w:moveTo", // Move destination markers - container element
56
+ // Note: w:bookmarkStart and w:bookmarkEnd MUST be self-closing per ECMA-376
57
+ ];
58
+
59
+ /**
60
+ * Adds an element to the builder
61
+ * @param name - Element name (with namespace prefix if needed)
62
+ * @param attributes - Element attributes
63
+ * @param children - Child elements or text
64
+ * @returns This builder for chaining
65
+ */
66
+ element(
67
+ name: string,
68
+ attributes?: Record<string, string | number | boolean | undefined>,
69
+ children?: (XMLElement | string)[]
70
+ ): XMLBuilder {
71
+ this.elements.push({
72
+ name,
73
+ attributes,
74
+ children,
75
+ });
76
+ return this;
77
+ }
78
+
79
+ /**
80
+ * Adds a self-closing element
81
+ * @param name - Element name
82
+ * @param attributes - Element attributes
83
+ * @returns This builder for chaining
84
+ * @throws {Error} If attempting to create self-closing w:t element (not allowed per ECMA-376)
85
+ */
86
+ selfClosingElement(
87
+ name: string,
88
+ attributes?: Record<string, string | number | boolean | undefined>
89
+ ): XMLBuilder {
90
+ // Validation: Text elements (<w:t>) cannot be self-closing per ECMA-376
91
+ // Self-closing <w:t/> elements cause Word to fail opening the document
92
+ if (name === 'w:t' || name === 't') {
93
+ throw new Error(
94
+ 'Text elements (<w:t>) cannot be self-closing per ECMA-376. ' +
95
+ 'Use element() with empty text content instead: XMLBuilder.w("t", attrs, [""])'
96
+ );
97
+ }
98
+
99
+ this.elements.push({
100
+ name,
101
+ attributes,
102
+ selfClosing: true,
103
+ });
104
+ return this;
105
+ }
106
+
107
+ /**
108
+ * Adds text content
109
+ * @param text - Text to add
110
+ * @returns This builder for chaining
111
+ */
112
+ text(text: string): XMLBuilder {
113
+ this.elements.push(text);
114
+ return this;
115
+ }
116
+
117
+ /**
118
+ * Builds the XML string
119
+ * @param includeDeclaration - Whether to include XML declaration
120
+ * @returns Generated XML string
121
+ */
122
+ build(includeDeclaration = false): string {
123
+ let xml = "";
124
+
125
+ if (includeDeclaration) {
126
+ xml += '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
127
+ }
128
+
129
+ xml += this.elementsToString(this.elements);
130
+ return xml;
131
+ }
132
+
133
+ /**
134
+ * Converts elements to XML string
135
+ */
136
+ private elementsToString(elements: (XMLElement | string)[]): string {
137
+ let xml = "";
138
+
139
+ for (const element of elements) {
140
+ if (typeof element === "string") {
141
+ xml += this.escapeXml(element);
142
+ } else {
143
+ xml += this.elementToString(element);
144
+ }
145
+ }
146
+
147
+ return xml;
148
+ }
149
+
150
+ /**
151
+ * Converts a single element to XML string
152
+ */
153
+ private elementToString(element: XMLElement): string {
154
+ // Special case: raw XML passthrough (no wrapper element)
155
+ // Used for VML and other legacy content that must be preserved exactly
156
+ if (element.name === "__rawXml" && element.rawXml) {
157
+ return element.rawXml;
158
+ }
159
+
160
+ let xml = `<${element.name}`;
161
+
162
+ // Add attributes
163
+ if (element.attributes) {
164
+ for (const [key, value] of Object.entries(element.attributes)) {
165
+ if (value !== undefined && value !== null && value !== false) {
166
+ // Handle boolean attributes
167
+ const attrValue = value === true ? key : String(value);
168
+ // Use escapeXmlAttribute for attribute values (Issue #8)
169
+ xml += ` ${key}="${XMLBuilder.escapeXmlAttribute(attrValue)}"`;
170
+ }
171
+ }
172
+ }
173
+
174
+ // Self-closing element validation
175
+ if (element.selfClosing) {
176
+ if (XMLBuilder.CANNOT_SELF_CLOSE.includes(element.name)) {
177
+ // Instead of throwing, force open/close tags for safety
178
+ xml += "></" + element.name + ">";
179
+ return xml;
180
+ }
181
+ xml += "/>";
182
+ return xml;
183
+ }
184
+
185
+ xml += ">";
186
+
187
+ // Add raw XML content if present (for VML passthrough)
188
+ if (element.rawXml) {
189
+ xml += element.rawXml;
190
+ }
191
+
192
+ // Add children
193
+ if (element.children && element.children.length > 0) {
194
+ xml += this.elementsToString(element.children);
195
+ }
196
+
197
+ xml += `</${element.name}>`;
198
+ return xml;
199
+ }
200
+
201
+ /**
202
+ * Escapes special XML characters for text content
203
+ * (Issue #8 fix: Use escapeXmlText for element text, escapeXmlAttribute called directly for attrs)
204
+ */
205
+ private escapeXml(text: string): string {
206
+ // This method is now only used for text content in elementsToString()
207
+ // Attributes call escapeXmlAttribute() directly in elementToString()
208
+ // Text content should NOT escape quotes (only & < >)
209
+ return XMLBuilder.escapeXmlText(text);
210
+ }
211
+
212
+ /**
213
+ * Escapes XML text content (element text nodes)
214
+ * Removes invalid XML 1.0 control characters and escapes: & < >
215
+ *
216
+ * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.
217
+ * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.
218
+ *
219
+ * @param text Text to escape
220
+ * @returns Escaped text safe for XML content
221
+ */
222
+ static escapeXmlText(text: string): string {
223
+ return removeInvalidXmlChars(text)
224
+ .replace(/&/g, "&amp;")
225
+ .replace(/</g, "&lt;")
226
+ .replace(/>/g, "&gt;");
227
+ }
228
+
229
+ /**
230
+ * Escapes XML attribute values
231
+ * Removes invalid XML 1.0 control characters and escapes: & < > " '
232
+ *
233
+ * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.
234
+ * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.
235
+ *
236
+ * @param value Attribute value to escape
237
+ * @returns Escaped value safe for XML attributes
238
+ */
239
+ static escapeXmlAttribute(value: string): string {
240
+ return removeInvalidXmlChars(value)
241
+ .replace(/&/g, "&amp;")
242
+ .replace(/</g, "&lt;")
243
+ .replace(/>/g, "&gt;")
244
+ .replace(/"/g, "&quot;")
245
+ .replace(/'/g, "&apos;");
246
+ }
247
+
248
+ /**
249
+ * Unescapes XML entities back to original characters
250
+ * @param text Text with XML entities
251
+ * @returns Unescaped text
252
+ */
253
+ static unescapeXml(text: string): string {
254
+ return text
255
+ .replace(/&lt;/g, "<")
256
+ .replace(/&gt;/g, ">")
257
+ .replace(/&quot;/g, '"')
258
+ .replace(/&apos;/g, "'")
259
+ .replace(/&amp;/g, "&"); // Must be last to avoid double-unescaping
260
+ }
261
+
262
+ /**
263
+ * Sanitizes and escapes XML content for safe inclusion in XML documents
264
+ * Removes control characters, null bytes, and escapes special XML characters
265
+ * Use this for user-provided content that may contain unsafe characters
266
+ *
267
+ * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.
268
+ * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.
269
+ *
270
+ * @param text Text to sanitize and escape
271
+ * @returns Sanitized text safe for XML content
272
+ *
273
+ * **Issue #11 fix:** Prevents malformed XML from CDATA markers, control chars, etc.
274
+ */
275
+ static sanitizeXmlContent(text: string): string {
276
+ return (
277
+ removeInvalidXmlChars(text)
278
+ // Escape CDATA end marker to prevent CDATA injection
279
+ .replace(/\]\]>/g, "]]&gt;")
280
+ // Standard XML escaping (& must be first to avoid double-escaping)
281
+ .replace(/&/g, "&amp;")
282
+ .replace(/</g, "&lt;")
283
+ .replace(/>/g, "&gt;")
284
+ );
285
+ }
286
+
287
+ /**
288
+ * Creates a WordprocessingML namespace attribute object
289
+ */
290
+ static createNamespaces(): Record<string, string> {
291
+ return {
292
+ "xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
293
+ "xmlns:r":
294
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
295
+ "xmlns:wp":
296
+ "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
297
+ "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
298
+ "xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture",
299
+ "xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
300
+ "xmlns:wpc":
301
+ "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
302
+ "xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
303
+ "xmlns:o": "urn:schemas-microsoft-com:office:office",
304
+ "xmlns:v": "urn:schemas-microsoft-com:vml",
305
+ "xmlns:wp14":
306
+ "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
307
+ "xmlns:w10": "urn:schemas-microsoft-com:office:word",
308
+ "xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
309
+ "xmlns:wpg":
310
+ "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
311
+ "xmlns:wpi":
312
+ "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
313
+ "xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
314
+ "xmlns:wps":
315
+ "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
316
+ "xmlns:asvg":
317
+ "http://schemas.microsoft.com/office/drawing/2016/SVG/main",
318
+ };
319
+ }
320
+
321
+ /**
322
+ * Converts a single XMLElement to its XML string representation
323
+ * Useful for merging elements into existing XML
324
+ *
325
+ * @param element - The XMLElement to convert
326
+ * @returns XML string representation of the element
327
+ */
328
+ static elementToString(element: XMLElement): string {
329
+ const builder = new XMLBuilder();
330
+ // Use the private elementToString via the elements array + build
331
+ (builder as any).elements.push(element);
332
+ return builder.build();
333
+ }
334
+
335
+ /**
336
+ * Helper method to create a WordprocessingML element
337
+ * @param name - Element name (without 'w:' prefix)
338
+ * @param attributes - Element attributes
339
+ * @param children - Child elements
340
+ * @returns XMLElement
341
+ */
342
+ static w(
343
+ name: string,
344
+ attributes?: Record<string, string | number | boolean | undefined>,
345
+ children?: (XMLElement | string)[]
346
+ ): XMLElement {
347
+ return {
348
+ name: `w:${name}`,
349
+ attributes,
350
+ children,
351
+ };
352
+ }
353
+
354
+ /**
355
+ * Helper method to create a self-closing WordprocessingML element
356
+ * @param name - Element name (without 'w:' prefix)
357
+ * @param attributes - Element attributes
358
+ * @returns XMLElement
359
+ */
360
+ static wSelf(
361
+ name: string,
362
+ attributes?: Record<string, string | number | boolean | undefined>
363
+ ): XMLElement {
364
+ return {
365
+ name: `w:${name}`,
366
+ attributes,
367
+ selfClosing: true,
368
+ };
369
+ }
370
+
371
+ /**
372
+ * Helper method to create a w14 element (Word 2010+ features)
373
+ * @param name - Element name (without 'w14:' prefix)
374
+ * @param attributes - Element attributes
375
+ * @param children - Child elements
376
+ * @returns XMLElement
377
+ */
378
+ static w14(
379
+ name: string,
380
+ attributes?: Record<string, string | number | boolean | undefined>,
381
+ children?: (XMLElement | string)[]
382
+ ): XMLElement {
383
+ return {
384
+ name: `w14:${name}`,
385
+ attributes,
386
+ children,
387
+ };
388
+ }
389
+
390
+ /**
391
+ * Helper method to create a self-closing w14 element
392
+ * @param name - Element name (without 'w14:' prefix)
393
+ * @param attributes - Element attributes
394
+ * @returns XMLElement
395
+ */
396
+ static w14Self(
397
+ name: string,
398
+ attributes?: Record<string, string | number | boolean | undefined>
399
+ ): XMLElement {
400
+ return {
401
+ name: `w14:${name}`,
402
+ attributes,
403
+ selfClosing: true,
404
+ };
405
+ }
406
+
407
+ /**
408
+ * Helper method to create a DrawingML element (a: namespace)
409
+ * @param name - Element name (without 'a:' prefix)
410
+ * @param attributes - Element attributes
411
+ * @param children - Child elements
412
+ * @returns XMLElement
413
+ */
414
+ static a(
415
+ name: string,
416
+ attributes?: Record<string, string | number | boolean | undefined>,
417
+ children?: (XMLElement | string)[]
418
+ ): XMLElement {
419
+ return {
420
+ name: `a:${name}`,
421
+ attributes,
422
+ children,
423
+ };
424
+ }
425
+
426
+ /**
427
+ * Helper method to create a self-closing DrawingML element
428
+ * @param name - Element name (without 'a:' prefix)
429
+ * @param attributes - Element attributes
430
+ * @returns XMLElement
431
+ */
432
+ static aSelf(
433
+ name: string,
434
+ attributes?: Record<string, string | number | boolean | undefined>
435
+ ): XMLElement {
436
+ return {
437
+ name: `a:${name}`,
438
+ attributes,
439
+ selfClosing: true,
440
+ };
441
+ }
442
+
443
+ /**
444
+ * Helper method to create a Picture element (pic: namespace)
445
+ * @param name - Element name (without 'pic:' prefix)
446
+ * @param attributes - Element attributes
447
+ * @param children - Child elements
448
+ * @returns XMLElement
449
+ */
450
+ static pic(
451
+ name: string,
452
+ attributes?: Record<string, string | number | boolean | undefined>,
453
+ children?: (XMLElement | string)[]
454
+ ): XMLElement {
455
+ return {
456
+ name: `pic:${name}`,
457
+ attributes,
458
+ children,
459
+ };
460
+ }
461
+
462
+ /**
463
+ * Helper method to create a self-closing Picture element
464
+ * @param name - Element name (without 'pic:' prefix)
465
+ * @param attributes - Element attributes
466
+ * @returns XMLElement
467
+ */
468
+ static picSelf(
469
+ name: string,
470
+ attributes?: Record<string, string | number | boolean | undefined>
471
+ ): XMLElement {
472
+ return {
473
+ name: `pic:${name}`,
474
+ attributes,
475
+ selfClosing: true,
476
+ };
477
+ }
478
+
479
+ /**
480
+ * Helper method to create a Wordprocessing Drawing element (wp: namespace)
481
+ * @param name - Element name (without 'wp:' prefix)
482
+ * @param attributes - Element attributes
483
+ * @param children - Child elements
484
+ * @returns XMLElement
485
+ */
486
+ static wp(
487
+ name: string,
488
+ attributes?: Record<string, string | number | boolean | undefined>,
489
+ children?: (XMLElement | string)[]
490
+ ): XMLElement {
491
+ return {
492
+ name: `wp:${name}`,
493
+ attributes,
494
+ children,
495
+ };
496
+ }
497
+
498
+ /**
499
+ * Helper method to create a self-closing Wordprocessing Drawing element
500
+ * @param name - Element name (without 'wp:' prefix)
501
+ * @param attributes - Element attributes
502
+ * @returns XMLElement
503
+ */
504
+ static wpSelf(
505
+ name: string,
506
+ attributes?: Record<string, string | number | boolean | undefined>
507
+ ): XMLElement {
508
+ return {
509
+ name: `wp:${name}`,
510
+ attributes,
511
+ selfClosing: true,
512
+ };
513
+ }
514
+
515
+ /**
516
+ * Helper to create cx/cy extent attributes (for a:ext, wp:extent, etc.)
517
+ * @param name - Element name (e.g., 'ext')
518
+ * @param cx - Width in EMUs
519
+ * @param cy - Height in EMUs
520
+ * @returns Self-closing XMLElement
521
+ */
522
+ static cxCy(
523
+ name: string,
524
+ cx: number,
525
+ cy: number
526
+ ): XMLElement {
527
+ return {
528
+ name,
529
+ attributes: { cx, cy },
530
+ selfClosing: true
531
+ };
532
+ }
533
+
534
+ /**
535
+ * Creates an SDT (Structured Document Tag) wrapper for content
536
+ * @param content - Content to wrap (paragraphs, tables, etc.)
537
+ * @param options - SDT options
538
+ * @returns XMLElement representing the SDT wrapper
539
+ */
540
+ static createSDT(
541
+ content: XMLElement[],
542
+ options?: {
543
+ id?: number;
544
+ docPartGallery?: string;
545
+ docPartUnique?: boolean;
546
+ }
547
+ ): XMLElement {
548
+ const sdtId = options?.id ?? Math.floor(Math.random() * 2000000000) - 1000000000;
549
+
550
+ // Build SDT properties
551
+ const sdtPrChildren: XMLElement[] = [
552
+ XMLBuilder.wSelf('id', { 'w:val': sdtId })
553
+ ];
554
+
555
+ // Add docPartObj if docPartGallery is specified
556
+ if (options?.docPartGallery) {
557
+ sdtPrChildren.push(
558
+ XMLBuilder.w('docPartObj', undefined, [
559
+ XMLBuilder.wSelf('docPartGallery', { 'w:val': options.docPartGallery }),
560
+ XMLBuilder.wSelf('docPartUnique', {
561
+ 'w:val': options?.docPartUnique !== false ? '1' : '0'
562
+ })
563
+ ])
564
+ );
565
+ }
566
+
567
+ // Create complete SDT structure
568
+ return XMLBuilder.w('sdt', undefined, [
569
+ XMLBuilder.w('sdtPr', undefined, sdtPrChildren),
570
+ XMLBuilder.w('sdtContent', undefined, content)
571
+ ]);
572
+ }
573
+
574
+ /**
575
+ * Creates a complete WordprocessingML document structure
576
+ * @param bodyContent - Content for the document body
577
+ * @returns XML string for word/document.xml
578
+ */
579
+ static createDocument(
580
+ bodyContent: XMLElement[],
581
+ namespaces: Record<string, string> = {},
582
+ preBodyContent?: XMLElement[]
583
+ ): string {
584
+ const builder = new XMLBuilder();
585
+
586
+ // Preserve document's original namespace order, then fill in framework defaults
587
+ const allNamespaces: Record<string, string> = {};
588
+ for (const [key, value] of Object.entries(namespaces)) {
589
+ allNamespaces[key] = value;
590
+ }
591
+ for (const [key, value] of Object.entries(XMLBuilder.createNamespaces())) {
592
+ if (!(key in allNamespaces)) {
593
+ allNamespaces[key] = value;
594
+ }
595
+ }
596
+
597
+ // Ensure mc:Ignorable is present when extended namespaces are declared.
598
+ // Per ECMA-376, mc:Ignorable tells Word which namespace prefixes can be
599
+ // safely ignored if the processor doesn't support them. Without it,
600
+ // attributes like w14:paraId in raw XML passthrough zones cause corruption.
601
+ if (!allNamespaces["mc:Ignorable"]) {
602
+ const ignorable: string[] = [];
603
+ if (allNamespaces["xmlns:w14"]) ignorable.push("w14");
604
+ if (allNamespaces["xmlns:w15"]) ignorable.push("w15");
605
+ if (allNamespaces["xmlns:wp14"]) ignorable.push("wp14");
606
+ if (allNamespaces["xmlns:w16se"]) ignorable.push("w16se");
607
+ if (allNamespaces["xmlns:w16cid"]) ignorable.push("w16cid");
608
+ if (allNamespaces["xmlns:w16"]) ignorable.push("w16");
609
+ if (allNamespaces["xmlns:w16cex"]) ignorable.push("w16cex");
610
+ if (allNamespaces["xmlns:w16sdtdh"]) ignorable.push("w16sdtdh");
611
+ if (allNamespaces["xmlns:w16sdtfl"]) ignorable.push("w16sdtfl");
612
+ if (allNamespaces["xmlns:w16du"]) ignorable.push("w16du");
613
+ if (allNamespaces["xmlns:asvg"]) ignorable.push("asvg");
614
+ if (ignorable.length > 0) {
615
+ allNamespaces["mc:Ignorable"] = ignorable.join(" ");
616
+ }
617
+ } else {
618
+ // mc:Ignorable was loaded from the original document — ensure every
619
+ // prefix referenced in mc:Ignorable has a matching xmlns declaration.
620
+ // Without this, the validator rejects prefixes that appear in
621
+ // mc:Ignorable but lack namespace declarations in the root element.
622
+ const defaults = XMLBuilder.createNamespaces();
623
+ const prefixes = allNamespaces["mc:Ignorable"].split(/\s+/);
624
+ for (const prefix of prefixes) {
625
+ const nsKey = `xmlns:${prefix}`;
626
+ if (!allNamespaces[nsKey] && defaults[nsKey]) {
627
+ allNamespaces[nsKey] = defaults[nsKey];
628
+ }
629
+ }
630
+ }
631
+
632
+ const documentChildren: XMLElement[] = [];
633
+ if (preBodyContent) {
634
+ documentChildren.push(...preBodyContent);
635
+ }
636
+ documentChildren.push(XMLBuilder.w("body", undefined, bodyContent));
637
+ builder.element("w:document", allNamespaces, documentChildren);
638
+
639
+ return builder.build(true);
640
+ }
641
+
642
+ /**
643
+ * Builds an XML string from a JavaScript object.
644
+ * This is the reverse of XMLParser.parseToObject
645
+ */
646
+ static buildObject(obj: ParsedXmlObject, rootName: string): string {
647
+ const builder = new XMLBuilder();
648
+ const element = XMLBuilder.objectToElement(obj, rootName);
649
+ if (element) {
650
+ if (typeof element === "string") {
651
+ builder.text(element);
652
+ } else {
653
+ builder.elements.push(element);
654
+ }
655
+ }
656
+ return builder.build();
657
+ }
658
+
659
+ /**
660
+ * Converts a JavaScript object to an XMLElement.
661
+ * @private
662
+ */
663
+ private static objectToElement(
664
+ obj: ParsedXmlObject | string | number | boolean | null | undefined,
665
+ name: string
666
+ ): XMLElement | string | null {
667
+ if (obj === null || obj === undefined) {
668
+ return null;
669
+ }
670
+
671
+ if (typeof obj !== "object" || obj === null) {
672
+ return String(obj);
673
+ }
674
+
675
+ const attributes: Record<string, string | number | boolean> = {};
676
+ const children: (XMLElement | string)[] = [];
677
+
678
+ if (obj["#text"] && Object.keys(obj).length === 1) {
679
+ return String(obj["#text"]);
680
+ }
681
+
682
+ for (const key in obj) {
683
+ if (key.startsWith("@_")) {
684
+ const attrName = key.substring(2);
685
+ // Validate attribute name is not empty after prefix removal
686
+ if (attrName.length > 0) {
687
+ attributes[attrName] = obj[key];
688
+ }
689
+ } else if (key === "#text") {
690
+ children.push(String(obj[key]));
691
+ } else {
692
+ const childObj = obj[key];
693
+ if (Array.isArray(childObj)) {
694
+ childObj.forEach((item) => {
695
+ const childElement = XMLBuilder.objectToElement(item, key);
696
+ if (childElement) {
697
+ children.push(childElement);
698
+ }
699
+ });
700
+ } else {
701
+ const childElement = XMLBuilder.objectToElement(childObj, key);
702
+ if (childElement) {
703
+ children.push(childElement);
704
+ }
705
+ }
706
+ }
707
+ }
708
+
709
+ const element: XMLElement = {
710
+ name,
711
+ attributes,
712
+ children: children.length > 0 ? children : undefined,
713
+ };
714
+
715
+ if (!element.children || element.children.length === 0) {
716
+ if (!XMLBuilder.CANNOT_SELF_CLOSE.includes(name)) {
717
+ element.selfClosing = true;
718
+ }
719
+ }
720
+
721
+ return element;
722
+ }
723
+
724
+ /**
725
+ * Helper method to build attributes object, filtering out undefined/null values
726
+ * This simplifies the common pattern of conditionally adding attributes
727
+ *
728
+ * @param mapping - Map of attribute names to values
729
+ * @returns Filtered attributes object with only defined values
730
+ *
731
+ * @example
732
+ * ```typescript
733
+ * const attrs = XMLBuilder.buildAttributes({
734
+ * 'w:before': spacing?.before,
735
+ * 'w:after': spacing?.after,
736
+ * 'w:line': spacing?.line
737
+ * });
738
+ * // Returns only attributes with defined values
739
+ * ```
740
+ */
741
+ static buildAttributes(mapping: Record<string, any>): Record<string, string | number> {
742
+ const attrs: Record<string, string | number> = {};
743
+ for (const [key, value] of Object.entries(mapping)) {
744
+ if (value !== undefined && value !== null) {
745
+ attrs[key] = value;
746
+ }
747
+ }
748
+ return attrs;
749
+ }
750
+
751
+ /**
752
+ * Creates a border element for WordprocessingML
753
+ * Used for table borders, cell borders, and paragraph borders
754
+ *
755
+ * @param side - Border side (e.g., 'top', 'left', 'bottom', 'right', 'insideH', 'insideV')
756
+ * @param border - Border definition
757
+ * @returns XML element for border
758
+ *
759
+ * @example
760
+ * ```typescript
761
+ * const border = XMLBuilder.createBorder('top', {
762
+ * style: 'single',
763
+ * size: 4,
764
+ * color: 'FF0000',
765
+ * space: 0
766
+ * });
767
+ * ```
768
+ */
769
+ static createBorder(
770
+ side: string,
771
+ border: {
772
+ style?: string;
773
+ size?: number;
774
+ color?: string;
775
+ space?: number;
776
+ }
777
+ ): XMLElement {
778
+ const attrs = XMLBuilder.buildAttributes({
779
+ 'w:val': border.style || 'single',
780
+ 'w:sz': border.size,
781
+ 'w:color': border.color,
782
+ 'w:space': border.space
783
+ });
784
+
785
+ return XMLBuilder.wSelf(side, attrs);
786
+ }
787
+
788
+ /**
789
+ * Creates a shading element for WordprocessingML
790
+ * Used for paragraph shading, table shading, and cell shading
791
+ *
792
+ * @param shading - Shading definition (ShadingConfig with theme support)
793
+ * @returns XML element for shading, or null if no shading properties
794
+ *
795
+ * @example
796
+ * ```typescript
797
+ * const shading = XMLBuilder.createShading({
798
+ * fill: 'FFFF00',
799
+ * pattern: 'clear',
800
+ * color: '000000'
801
+ * });
802
+ * ```
803
+ */
804
+ static createShading(shading: ShadingConfig): XMLElement | null {
805
+ const attrs = buildShadingAttributes(shading);
806
+ // Default w:val to "clear" if not specified but other attrs exist
807
+ if (!attrs['w:val'] && Object.keys(attrs).length > 0) {
808
+ attrs['w:val'] = 'clear';
809
+ }
810
+ if (Object.keys(attrs).length > 0) {
811
+ return XMLBuilder.wSelf('shd', attrs);
812
+ }
813
+ return null;
814
+ }
815
+
816
+ /**
817
+ * Creates a margins element (tcMar, pgMar, etc.)
818
+ * Used for cell margins, page margins, etc.
819
+ *
820
+ * @param type - Margin type element name (e.g., 'tcMar', 'pgMar')
821
+ * @param margins - Margin values in twips
822
+ * @returns XML element for margins, or null if no margins defined
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * const margins = XMLBuilder.createMargins('tcMar', {
827
+ * top: 100,
828
+ * bottom: 100,
829
+ * left: 100,
830
+ * right: 100
831
+ * });
832
+ * ```
833
+ */
834
+ static createMargins(
835
+ type: string,
836
+ margins: {
837
+ top?: number;
838
+ bottom?: number;
839
+ left?: number;
840
+ right?: number;
841
+ start?: number;
842
+ end?: number;
843
+ }
844
+ ): XMLElement | null {
845
+ const children: XMLElement[] = [];
846
+
847
+ if (margins.top !== undefined) {
848
+ children.push(XMLBuilder.wSelf('top', { 'w:w': margins.top, 'w:type': 'dxa' }));
849
+ }
850
+ if (margins.bottom !== undefined) {
851
+ children.push(XMLBuilder.wSelf('bottom', { 'w:w': margins.bottom, 'w:type': 'dxa' }));
852
+ }
853
+ if (margins.left !== undefined) {
854
+ children.push(XMLBuilder.wSelf('left', { 'w:w': margins.left, 'w:type': 'dxa' }));
855
+ }
856
+ if (margins.right !== undefined) {
857
+ children.push(XMLBuilder.wSelf('right', { 'w:w': margins.right, 'w:type': 'dxa' }));
858
+ }
859
+ if (margins.start !== undefined) {
860
+ children.push(XMLBuilder.wSelf('start', { 'w:w': margins.start, 'w:type': 'dxa' }));
861
+ }
862
+ if (margins.end !== undefined) {
863
+ children.push(XMLBuilder.wSelf('end', { 'w:w': margins.end, 'w:type': 'dxa' }));
864
+ }
865
+
866
+ if (children.length > 0) {
867
+ return XMLBuilder.w(type, undefined, children);
868
+ }
869
+ return null;
870
+ }
871
+ }