docxmlater 10.0.2 → 10.0.4

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 (398) 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 +23 -19
  9. package/dist/core/Document.d.ts.map +1 -1
  10. package/dist/core/Document.js +197 -63
  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 +86 -55
  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 +8 -0
  76. package/dist/elements/Paragraph.d.ts.map +1 -1
  77. package/dist/elements/Paragraph.js +153 -118
  78. package/dist/elements/Paragraph.js.map +1 -1
  79. package/dist/elements/PreservedElement.js.map +1 -1
  80. package/dist/elements/PropertyChangeTypes.js.map +1 -1
  81. package/dist/elements/RangeMarker.js.map +1 -1
  82. package/dist/elements/Revision.d.ts +1 -0
  83. package/dist/elements/Revision.d.ts.map +1 -1
  84. package/dist/elements/Revision.js +44 -5
  85. package/dist/elements/Revision.js.map +1 -1
  86. package/dist/elements/RevisionContent.js.map +1 -1
  87. package/dist/elements/RevisionManager.d.ts.map +1 -1
  88. package/dist/elements/RevisionManager.js.map +1 -1
  89. package/dist/elements/Run.d.ts.map +1 -1
  90. package/dist/elements/Run.js +1 -3
  91. package/dist/elements/Run.js.map +1 -1
  92. package/dist/elements/Section.d.ts.map +1 -1
  93. package/dist/elements/Section.js +127 -118
  94. package/dist/elements/Section.js.map +1 -1
  95. package/dist/elements/Shape.d.ts.map +1 -1
  96. package/dist/elements/Shape.js +21 -0
  97. package/dist/elements/Shape.js.map +1 -1
  98. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  99. package/dist/elements/StructuredDocumentTag.js +20 -8
  100. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  101. package/dist/elements/Table.d.ts +2 -2
  102. package/dist/elements/Table.d.ts.map +1 -1
  103. package/dist/elements/Table.js +29 -35
  104. package/dist/elements/Table.js.map +1 -1
  105. package/dist/elements/TableCell.d.ts +2 -2
  106. package/dist/elements/TableCell.d.ts.map +1 -1
  107. package/dist/elements/TableCell.js +63 -67
  108. package/dist/elements/TableCell.js.map +1 -1
  109. package/dist/elements/TableGridChange.js.map +1 -1
  110. package/dist/elements/TableOfContents.d.ts +6 -6
  111. package/dist/elements/TableOfContents.d.ts.map +1 -1
  112. package/dist/elements/TableOfContents.js.map +1 -1
  113. package/dist/elements/TableOfContentsElement.js.map +1 -1
  114. package/dist/elements/TableRow.d.ts.map +1 -1
  115. package/dist/elements/TableRow.js +65 -47
  116. package/dist/elements/TableRow.js.map +1 -1
  117. package/dist/elements/TextBox.d.ts.map +1 -1
  118. package/dist/elements/TextBox.js +1 -1
  119. package/dist/elements/TextBox.js.map +1 -1
  120. package/dist/formatting/AbstractNumbering.d.ts +1 -1
  121. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  122. package/dist/formatting/AbstractNumbering.js +11 -11
  123. package/dist/formatting/AbstractNumbering.js.map +1 -1
  124. package/dist/formatting/NumberingInstance.d.ts.map +1 -1
  125. package/dist/formatting/NumberingInstance.js +4 -4
  126. package/dist/formatting/NumberingInstance.js.map +1 -1
  127. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  128. package/dist/formatting/NumberingLevel.js +26 -26
  129. package/dist/formatting/NumberingLevel.js.map +1 -1
  130. package/dist/formatting/NumberingManager.d.ts +1 -1
  131. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  132. package/dist/formatting/NumberingManager.js.map +1 -1
  133. package/dist/formatting/Style.d.ts.map +1 -1
  134. package/dist/formatting/Style.js +87 -95
  135. package/dist/formatting/Style.js.map +1 -1
  136. package/dist/formatting/StylesManager.d.ts +3 -3
  137. package/dist/formatting/StylesManager.d.ts.map +1 -1
  138. package/dist/formatting/StylesManager.js.map +1 -1
  139. package/dist/helpers/CleanupHelper.js.map +1 -1
  140. package/dist/images/ImageOptimizer.js.map +1 -1
  141. package/dist/index.js.map +1 -1
  142. package/dist/managers/DrawingManager.d.ts.map +1 -1
  143. package/dist/managers/DrawingManager.js.map +1 -1
  144. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  145. package/dist/tracking/TrackingContext.js.map +1 -1
  146. package/dist/types/compatibility-types.js.map +1 -1
  147. package/dist/types/formatting.js.map +1 -1
  148. package/dist/types/list-types.d.ts +4 -4
  149. package/dist/types/list-types.d.ts.map +1 -1
  150. package/dist/types/list-types.js.map +1 -1
  151. package/dist/types/settings-types.js.map +1 -1
  152. package/dist/types/styleConfig.js.map +1 -1
  153. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  154. package/dist/utils/ChangelogGenerator.js.map +1 -1
  155. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  156. package/dist/utils/CompatibilityUpgrader.js +7 -7
  157. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  158. package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
  159. package/dist/utils/InMemoryRevisionAcceptor.js +23 -2
  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.d.ts +1 -0
  165. package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
  166. package/dist/utils/SelectiveRevisionAcceptor.js +46 -0
  167. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  168. package/dist/utils/ShadingResolver.js +1 -1
  169. package/dist/utils/ShadingResolver.js.map +1 -1
  170. package/dist/utils/acceptRevisions.d.ts +0 -28
  171. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  172. package/dist/utils/acceptRevisions.js +5 -7
  173. package/dist/utils/acceptRevisions.js.map +1 -1
  174. package/dist/utils/cnfStyleDecoder.js +1 -1
  175. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  176. package/dist/utils/corruptionDetection.js.map +1 -1
  177. package/dist/utils/dateFormatting.js.map +1 -1
  178. package/dist/utils/deepClone.d.ts +0 -1
  179. package/dist/utils/deepClone.d.ts.map +1 -1
  180. package/dist/utils/deepClone.js +0 -7
  181. package/dist/utils/deepClone.js.map +1 -1
  182. package/dist/utils/diagnostics.d.ts +2 -2
  183. package/dist/utils/diagnostics.d.ts.map +1 -1
  184. package/dist/utils/diagnostics.js.map +1 -1
  185. package/dist/utils/errorHandling.js.map +1 -1
  186. package/dist/utils/formatting.js.map +1 -1
  187. package/dist/utils/list-detection.d.ts +2 -2
  188. package/dist/utils/list-detection.d.ts.map +1 -1
  189. package/dist/utils/list-detection.js +3 -3
  190. package/dist/utils/list-detection.js.map +1 -1
  191. package/dist/utils/logger.d.ts +2 -4
  192. package/dist/utils/logger.d.ts.map +1 -1
  193. package/dist/utils/logger.js +0 -2
  194. package/dist/utils/logger.js.map +1 -1
  195. package/dist/utils/parsingHelpers.js.map +1 -1
  196. package/dist/utils/stripTrackedChanges.d.ts +0 -19
  197. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  198. package/dist/utils/stripTrackedChanges.js +0 -2
  199. package/dist/utils/stripTrackedChanges.js.map +1 -1
  200. package/dist/utils/textDiff.js.map +1 -1
  201. package/dist/utils/units.js.map +1 -1
  202. package/dist/utils/validation.d.ts.map +1 -1
  203. package/dist/utils/validation.js.map +1 -1
  204. package/dist/utils/xmlSanitization.js.map +1 -1
  205. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  206. package/dist/validation/RevisionValidator.js.map +1 -1
  207. package/dist/validation/ValidationRules.js.map +1 -1
  208. package/dist/validation/index.js.map +1 -1
  209. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  210. package/dist/xml/XMLBuilder.js +10 -0
  211. package/dist/xml/XMLBuilder.js.map +1 -1
  212. package/dist/xml/XMLParser.d.ts.map +1 -1
  213. package/dist/xml/XMLParser.js +4 -5
  214. package/dist/xml/XMLParser.js.map +1 -1
  215. package/dist/zip/ZipHandler.js.map +1 -1
  216. package/dist/zip/ZipReader.js.map +1 -1
  217. package/dist/zip/ZipWriter.js.map +1 -1
  218. package/dist/zip/errors.js.map +1 -1
  219. package/dist/zip/types.js.map +1 -1
  220. package/package.json +34 -4
  221. package/src/__tests__/helper-methods.test.ts +512 -0
  222. package/src/constants/legacyCompatFlags.ts +138 -0
  223. package/src/constants/limits.ts +50 -0
  224. package/src/core/CLAUDE.md +109 -0
  225. package/src/core/Document.ts +15569 -0
  226. package/src/core/DocumentContent.ts +467 -0
  227. package/src/core/DocumentGenerator.ts +1104 -0
  228. package/src/core/DocumentIdManager.ts +158 -0
  229. package/src/core/DocumentParser.ts +10140 -0
  230. package/src/core/DocumentValidator.ts +372 -0
  231. package/src/core/Relationship.ts +367 -0
  232. package/src/core/RelationshipManager.ts +428 -0
  233. package/src/elements/AlternateContent.ts +42 -0
  234. package/src/elements/Bookmark.ts +210 -0
  235. package/src/elements/BookmarkManager.ts +250 -0
  236. package/src/elements/CLAUDE.md +126 -0
  237. package/src/elements/Comment.ts +359 -0
  238. package/src/elements/CommentManager.ts +502 -0
  239. package/src/elements/CommonTypes.ts +549 -0
  240. package/src/elements/CustomXml.ts +36 -0
  241. package/src/elements/Endnote.ts +217 -0
  242. package/src/elements/EndnoteManager.ts +249 -0
  243. package/src/elements/Field.ts +1233 -0
  244. package/src/elements/FieldHelpers.ts +333 -0
  245. package/src/elements/FontManager.ts +339 -0
  246. package/src/elements/Footer.ts +269 -0
  247. package/src/elements/Footnote.ts +217 -0
  248. package/src/elements/FootnoteManager.ts +249 -0
  249. package/src/elements/Header.ts +269 -0
  250. package/src/elements/HeaderFooterManager.ts +219 -0
  251. package/src/elements/Hyperlink.ts +1146 -0
  252. package/src/elements/Image.ts +1756 -0
  253. package/src/elements/ImageManager.ts +432 -0
  254. package/src/elements/ImageRun.ts +59 -0
  255. package/src/elements/MathElement.ts +65 -0
  256. package/src/elements/Paragraph.ts +4287 -0
  257. package/src/elements/PreservedElement.ts +53 -0
  258. package/src/elements/PropertyChangeTypes.ts +442 -0
  259. package/src/elements/RangeMarker.ts +400 -0
  260. package/src/elements/Revision.ts +1217 -0
  261. package/src/elements/RevisionContent.ts +73 -0
  262. package/src/elements/RevisionManager.ts +1070 -0
  263. package/src/elements/Run.ts +3068 -0
  264. package/src/elements/Section.ts +1421 -0
  265. package/src/elements/Shape.ts +873 -0
  266. package/src/elements/StructuredDocumentTag.ts +978 -0
  267. package/src/elements/Table.ts +2524 -0
  268. package/src/elements/TableCell.ts +1586 -0
  269. package/src/elements/TableGridChange.ts +151 -0
  270. package/src/elements/TableOfContents.ts +691 -0
  271. package/src/elements/TableOfContentsElement.ts +89 -0
  272. package/src/elements/TableRow.ts +906 -0
  273. package/src/elements/TextBox.ts +768 -0
  274. package/src/formatting/AbstractNumbering.ts +548 -0
  275. package/src/formatting/CLAUDE.md +74 -0
  276. package/src/formatting/NumberingInstance.ts +212 -0
  277. package/src/formatting/NumberingLevel.ts +1006 -0
  278. package/src/formatting/NumberingManager.ts +827 -0
  279. package/src/formatting/Style.ts +1833 -0
  280. package/src/formatting/StylesManager.ts +1005 -0
  281. package/src/helpers/CleanupHelper.ts +524 -0
  282. package/src/images/ImageOptimizer.ts +274 -0
  283. package/src/index.ts +554 -0
  284. package/src/managers/CLAUDE.md +47 -0
  285. package/src/managers/DrawingManager.ts +319 -0
  286. package/src/tracking/DocumentTrackingContext.ts +643 -0
  287. package/src/tracking/TrackingContext.ts +173 -0
  288. package/src/types/compatibility-types.ts +49 -0
  289. package/src/types/formatting.ts +210 -0
  290. package/src/types/list-types.ts +152 -0
  291. package/src/types/settings-types.ts +59 -0
  292. package/src/types/styleConfig.ts +189 -0
  293. package/src/utils/CLAUDE.md +153 -0
  294. package/src/utils/ChangelogGenerator.ts +1581 -0
  295. package/src/utils/CompatibilityUpgrader.ts +237 -0
  296. package/src/utils/InMemoryRevisionAcceptor.ts +696 -0
  297. package/src/utils/MoveOperationHelper.ts +238 -0
  298. package/src/utils/RevisionAwareProcessor.ts +526 -0
  299. package/src/utils/RevisionWalker.ts +457 -0
  300. package/src/utils/SelectiveRevisionAcceptor.ts +683 -0
  301. package/src/utils/ShadingResolver.ts +107 -0
  302. package/src/utils/acceptRevisions.ts +714 -0
  303. package/src/utils/cnfStyleDecoder.ts +217 -0
  304. package/src/utils/corruptionDetection.ts +345 -0
  305. package/src/utils/dateFormatting.ts +20 -0
  306. package/src/utils/deepClone.ts +78 -0
  307. package/src/utils/diagnostics.ts +129 -0
  308. package/src/utils/errorHandling.ts +80 -0
  309. package/src/utils/formatting.ts +213 -0
  310. package/src/utils/list-detection.ts +274 -0
  311. package/src/utils/logger.ts +404 -0
  312. package/src/utils/parsingHelpers.ts +190 -0
  313. package/src/utils/stripTrackedChanges.ts +353 -0
  314. package/src/utils/textDiff.ts +100 -0
  315. package/src/utils/units.ts +421 -0
  316. package/src/utils/validation.ts +542 -0
  317. package/src/utils/xmlSanitization.ts +182 -0
  318. package/src/validation/RevisionAutoFixer.ts +542 -0
  319. package/src/validation/RevisionValidator.ts +460 -0
  320. package/src/validation/ValidationRules.ts +338 -0
  321. package/src/validation/index.ts +30 -0
  322. package/src/xml/CLAUDE.md +65 -0
  323. package/src/xml/XMLBuilder.ts +871 -0
  324. package/src/xml/XMLParser.ts +919 -0
  325. package/src/zip/CLAUDE.md +55 -0
  326. package/src/zip/ZipHandler.ts +637 -0
  327. package/src/zip/ZipReader.ts +299 -0
  328. package/src/zip/ZipWriter.ts +390 -0
  329. package/src/zip/errors.ts +69 -0
  330. package/src/zip/types.ts +116 -0
  331. package/dist/core/ListNormalizer.d.ts +0 -23
  332. package/dist/core/ListNormalizer.d.ts.map +0 -1
  333. package/dist/core/ListNormalizer.js +0 -624
  334. package/dist/core/ListNormalizer.js.map +0 -1
  335. package/dist/images/index.d.ts +0 -2
  336. package/dist/images/index.d.ts.map +0 -1
  337. package/dist/images/index.js +0 -8
  338. package/dist/images/index.js.map +0 -1
  339. package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
  340. package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
  341. package/dist/ms-doc/cfb/CFBReader.js +0 -360
  342. package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
  343. package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
  344. package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
  345. package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
  346. package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
  347. package/dist/ms-doc/fib/FIB.d.ts +0 -18
  348. package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
  349. package/dist/ms-doc/fib/FIB.js +0 -342
  350. package/dist/ms-doc/fib/FIB.js.map +0 -1
  351. package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
  352. package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
  353. package/dist/ms-doc/fields/FieldParser.js +0 -266
  354. package/dist/ms-doc/fields/FieldParser.js.map +0 -1
  355. package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
  356. package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
  357. package/dist/ms-doc/images/PictureExtractor.js +0 -233
  358. package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
  359. package/dist/ms-doc/index.d.ts +0 -20
  360. package/dist/ms-doc/index.d.ts.map +0 -1
  361. package/dist/ms-doc/index.js +0 -59
  362. package/dist/ms-doc/index.js.map +0 -1
  363. package/dist/ms-doc/properties/SPRM.d.ts +0 -210
  364. package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
  365. package/dist/ms-doc/properties/SPRM.js +0 -633
  366. package/dist/ms-doc/properties/SPRM.js.map +0 -1
  367. package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
  368. package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
  369. package/dist/ms-doc/sections/SectionParser.js +0 -214
  370. package/dist/ms-doc/sections/SectionParser.js.map +0 -1
  371. package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
  372. package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
  373. package/dist/ms-doc/styles/StyleSheet.js +0 -268
  374. package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
  375. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
  376. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
  377. package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
  378. package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
  379. package/dist/ms-doc/tables/TableParser.d.ts +0 -29
  380. package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
  381. package/dist/ms-doc/tables/TableParser.js +0 -176
  382. package/dist/ms-doc/tables/TableParser.js.map +0 -1
  383. package/dist/ms-doc/text/PieceTable.d.ts +0 -21
  384. package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
  385. package/dist/ms-doc/text/PieceTable.js +0 -171
  386. package/dist/ms-doc/text/PieceTable.js.map +0 -1
  387. package/dist/ms-doc/types/Constants.d.ts +0 -99
  388. package/dist/ms-doc/types/Constants.d.ts.map +0 -1
  389. package/dist/ms-doc/types/Constants.js +0 -102
  390. package/dist/ms-doc/types/Constants.js.map +0 -1
  391. package/dist/ms-doc/types/DocTypes.d.ts +0 -368
  392. package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
  393. package/dist/ms-doc/types/DocTypes.js +0 -3
  394. package/dist/ms-doc/types/DocTypes.js.map +0 -1
  395. package/dist/tracking/index.d.ts +0 -3
  396. package/dist/tracking/index.d.ts.map +0 -1
  397. package/dist/tracking/index.js +0 -6
  398. package/dist/tracking/index.js.map +0 -1
@@ -0,0 +1,827 @@
1
+ /**
2
+ * NumberingManager - Manages numbering definitions and generates numbering.xml
3
+ *
4
+ * The NumberingManager is responsible for managing all abstract numbering definitions
5
+ * and numbering instances in a document, and generating the numbering.xml file.
6
+ */
7
+
8
+ import { XMLBuilder, XMLElement } from '../xml/XMLBuilder';
9
+ import { AbstractNumbering } from './AbstractNumbering';
10
+ import { NumberingInstance } from './NumberingInstance';
11
+ import { NumberingLevel } from './NumberingLevel';
12
+ import { defaultLogger } from '../utils/logger';
13
+
14
+ /**
15
+ * Options for numbering consolidation
16
+ */
17
+ export interface NumberingConsolidationOptions {
18
+ /** AbstractNumIds to exclude from consolidation (e.g., HLP/row-number lists) */
19
+ protectedAbstractNumIds?: Set<number>;
20
+ }
21
+
22
+ /**
23
+ * Result of numbering consolidation
24
+ */
25
+ export interface NumberingConsolidationResult {
26
+ abstractNumsRemoved: number;
27
+ instancesRemapped: number;
28
+ groupsConsolidated: number;
29
+ }
30
+
31
+ /**
32
+ * Manages numbering definitions and instances for a document
33
+ */
34
+ export class NumberingManager {
35
+ private abstractNumberings: Map<number, AbstractNumbering>;
36
+ private instances: Map<number, NumberingInstance>;
37
+ private nextAbstractNumId: number;
38
+ private nextNumId: number;
39
+
40
+ // Track if numbering has been modified (for XML preservation)
41
+ private _modified = false;
42
+
43
+ // Track which specific definitions have been modified (for selective merging)
44
+ private _modifiedAbstractNumIds = new Set<number>();
45
+ private _modifiedNumIds = new Set<number>();
46
+
47
+ // Track which definitions have been removed (for removal from original XML during merge)
48
+ private _removedAbstractNumIds = new Set<number>();
49
+ private _removedNumIds = new Set<number>();
50
+
51
+ /**
52
+ * Creates a new numbering manager
53
+ * @param initializeDefaults Whether to initialize with default numbering definitions
54
+ */
55
+ constructor(initializeDefaults = false) {
56
+ this.abstractNumberings = new Map();
57
+ this.instances = new Map();
58
+ this.nextAbstractNumId = 0;
59
+ this.nextNumId = 1;
60
+
61
+ if (initializeDefaults) {
62
+ this.initializeDefaultNumberings();
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Initializes default numbering definitions (bullet and numbered lists)
68
+ */
69
+ private initializeDefaultNumberings(): void {
70
+ // Create default bullet list
71
+ const bulletAbstract = AbstractNumbering.createBulletList(this.nextAbstractNumId++);
72
+ this.addAbstractNumbering(bulletAbstract);
73
+
74
+ // Create default numbered list
75
+ const numberedAbstract = AbstractNumbering.createNumberedList(this.nextAbstractNumId++);
76
+ this.addAbstractNumbering(numberedAbstract);
77
+ }
78
+
79
+ /**
80
+ * Adds an abstract numbering definition
81
+ * @param abstractNumbering The abstract numbering to add
82
+ */
83
+ addAbstractNumbering(abstractNumbering: AbstractNumbering): this {
84
+ const id = abstractNumbering.getAbstractNumId();
85
+ this.abstractNumberings.set(id, abstractNumbering);
86
+
87
+ // Update next ID if necessary
88
+ if (id >= this.nextAbstractNumId) {
89
+ this.nextAbstractNumId = id + 1;
90
+ }
91
+
92
+ this._modified = true;
93
+ this._modifiedAbstractNumIds.add(id);
94
+ return this;
95
+ }
96
+
97
+ /**
98
+ * Gets an abstract numbering by ID
99
+ * @param abstractNumId The abstract numbering ID
100
+ */
101
+ getAbstractNumbering(abstractNumId: number): AbstractNumbering | undefined {
102
+ return this.abstractNumberings.get(abstractNumId);
103
+ }
104
+
105
+ /**
106
+ * Gets all abstract numberings
107
+ */
108
+ getAllAbstractNumberings(): AbstractNumbering[] {
109
+ return Array.from(this.abstractNumberings.values()).sort(
110
+ (a, b) => a.getAbstractNumId() - b.getAbstractNumId()
111
+ );
112
+ }
113
+
114
+ /**
115
+ * Checks if an abstract numbering exists
116
+ * @param abstractNumId The abstract numbering ID
117
+ */
118
+ hasAbstractNumbering(abstractNumId: number): boolean {
119
+ return this.abstractNumberings.has(abstractNumId);
120
+ }
121
+
122
+ /**
123
+ * Removes an abstract numbering
124
+ * @param abstractNumId The abstract numbering ID
125
+ */
126
+ removeAbstractNumbering(abstractNumId: number): boolean {
127
+ // Also remove all instances referencing this abstract numbering
128
+ const instancesToRemove: number[] = [];
129
+ this.instances.forEach((instance, numId) => {
130
+ if (instance.getAbstractNumId() === abstractNumId) {
131
+ instancesToRemove.push(numId);
132
+ }
133
+ });
134
+
135
+ instancesToRemove.forEach(numId => {
136
+ this.instances.delete(numId);
137
+ this._removedNumIds.add(numId);
138
+ });
139
+
140
+ const deleted = this.abstractNumberings.delete(abstractNumId);
141
+ if (deleted) {
142
+ this._modified = true;
143
+ this._removedAbstractNumIds.add(abstractNumId);
144
+ }
145
+ return deleted;
146
+ }
147
+
148
+ /**
149
+ * Adds a numbering instance
150
+ * @param instance The numbering instance to add
151
+ */
152
+ addInstance(instance: NumberingInstance): this {
153
+ const numId = instance.getNumId();
154
+ const abstractNumId = instance.getAbstractNumId();
155
+
156
+ // Verify that the abstract numbering exists
157
+ if (!this.hasAbstractNumbering(abstractNumId)) {
158
+ throw new Error(`Abstract numbering ${abstractNumId} does not exist`);
159
+ }
160
+
161
+ this.instances.set(numId, instance);
162
+ this._modified = true;
163
+ this._modifiedNumIds.add(numId);
164
+
165
+ // Update next ID if necessary
166
+ if (numId >= this.nextNumId) {
167
+ this.nextNumId = numId + 1;
168
+ }
169
+
170
+ return this;
171
+ }
172
+
173
+ /**
174
+ * Alias for addInstance for backward compatibility
175
+ * @param instance The numbering instance to add
176
+ */
177
+ addNumberingInstance(instance: NumberingInstance): this {
178
+ return this.addInstance(instance);
179
+ }
180
+
181
+ /**
182
+ * Gets a numbering instance by ID
183
+ * @param numId The numbering instance ID
184
+ */
185
+ getInstance(numId: number): NumberingInstance | undefined {
186
+ return this.instances.get(numId);
187
+ }
188
+
189
+ /**
190
+ * Alias for getInstance for backward compatibility
191
+ * @param numId The numbering instance ID
192
+ */
193
+ getNumberingInstance(numId: number): NumberingInstance | undefined {
194
+ return this.getInstance(numId);
195
+ }
196
+
197
+ /**
198
+ * Gets all numbering instances
199
+ */
200
+ getAllInstances(): NumberingInstance[] {
201
+ return Array.from(this.instances.values()).sort(
202
+ (a, b) => a.getNumId() - b.getNumId()
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Checks if numbering has been modified since loading
208
+ * Used for XML preservation optimization
209
+ * @returns True if numbering was added or modified
210
+ */
211
+ isModified(): boolean {
212
+ return this._modified;
213
+ }
214
+
215
+ /**
216
+ * Marks an abstract numbering as modified for XML regeneration.
217
+ * Use when modifying NumberingLevel properties directly (setLeftIndent, etc.)
218
+ * which don't automatically trigger the modified flag.
219
+ * @param abstractNumId The abstract numbering ID to mark as modified
220
+ */
221
+ markAbstractNumberingModified(abstractNumId: number): void {
222
+ if (this.abstractNumberings.has(abstractNumId)) {
223
+ this._modified = true;
224
+ this._modifiedAbstractNumIds.add(abstractNumId);
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Resets the modified flag
230
+ * Called after parsing to indicate that loaded numbering doesn't count as modifications
231
+ */
232
+ resetModified(): void {
233
+ this._modified = false;
234
+ this._modifiedAbstractNumIds.clear();
235
+ this._modifiedNumIds.clear();
236
+ this._removedAbstractNumIds.clear();
237
+ this._removedNumIds.clear();
238
+ }
239
+
240
+ /**
241
+ * Gets the IDs of abstract numberings that have been modified since loading
242
+ * Used for selective merging with original numbering.xml
243
+ */
244
+ getModifiedAbstractNumIds(): Set<number> {
245
+ return new Set(this._modifiedAbstractNumIds);
246
+ }
247
+
248
+ /**
249
+ * Gets the IDs of numbering instances that have been modified since loading
250
+ * Used for selective merging with original numbering.xml
251
+ */
252
+ getModifiedNumIds(): Set<number> {
253
+ return new Set(this._modifiedNumIds);
254
+ }
255
+
256
+ /**
257
+ * Gets the IDs of abstract numberings that have been removed since loading
258
+ * Used for removal from original numbering.xml during merge
259
+ */
260
+ getRemovedAbstractNumIds(): Set<number> {
261
+ return new Set(this._removedAbstractNumIds);
262
+ }
263
+
264
+ /**
265
+ * Gets the IDs of numbering instances that have been removed since loading
266
+ * Used for removal from original numbering.xml during merge
267
+ */
268
+ getRemovedNumIds(): Set<number> {
269
+ return new Set(this._removedNumIds);
270
+ }
271
+
272
+ /**
273
+ * Alias for getAllInstances for backward compatibility
274
+ */
275
+ getAllNumberingInstances(): NumberingInstance[] {
276
+ return this.getAllInstances();
277
+ }
278
+
279
+ /**
280
+ * Checks if a numbering instance exists
281
+ * @param numId The numbering instance ID
282
+ */
283
+ hasInstance(numId: number): boolean {
284
+ return this.instances.has(numId);
285
+ }
286
+
287
+ /**
288
+ * Removes a numbering instance
289
+ * @param numId The numbering instance ID
290
+ */
291
+ removeInstance(numId: number): boolean {
292
+ const deleted = this.instances.delete(numId);
293
+ if (deleted) {
294
+ this._modified = true;
295
+ this._removedNumIds.add(numId);
296
+ }
297
+ return deleted;
298
+ }
299
+
300
+ /**
301
+ * Creates a new bullet list and returns its numId
302
+ * @param levels Number of levels (default: 9)
303
+ * @param bullets Array of bullet characters
304
+ */
305
+ createBulletList(levels = 9, bullets?: string[]): number {
306
+ // Create abstract numbering
307
+ const abstractNumId = this.nextAbstractNumId++;
308
+ // Only pass bullets if it's defined, so defaults are used otherwise
309
+ const abstractNumbering = bullets
310
+ ? AbstractNumbering.createBulletList(abstractNumId, levels, bullets)
311
+ : AbstractNumbering.createBulletList(abstractNumId, levels);
312
+ this.addAbstractNumbering(abstractNumbering);
313
+
314
+ // Create instance
315
+ const numId = this.nextNumId++;
316
+ const instance = NumberingInstance.create({ numId, abstractNumId });
317
+ this.addInstance(instance);
318
+
319
+ return numId;
320
+ }
321
+
322
+ /**
323
+ * Creates a new numbered list and returns its numId
324
+ * @param levels Number of levels (default: 9)
325
+ * @param formats Array of formats for each level
326
+ */
327
+ createNumberedList(
328
+ levels = 9,
329
+ formats?: ('decimal' | 'lowerLetter' | 'lowerRoman')[]
330
+ ): number {
331
+ // Create abstract numbering
332
+ const abstractNumId = this.nextAbstractNumId++;
333
+ // Only pass formats if it's defined, so defaults are used otherwise
334
+ const abstractNumbering = formats
335
+ ? AbstractNumbering.createNumberedList(abstractNumId, levels, formats)
336
+ : AbstractNumbering.createNumberedList(abstractNumId, levels);
337
+ this.addAbstractNumbering(abstractNumbering);
338
+
339
+ // Create instance
340
+ const numId = this.nextNumId++;
341
+ const instance = NumberingInstance.create({ numId, abstractNumId });
342
+ this.addInstance(instance);
343
+
344
+ return numId;
345
+ }
346
+
347
+ /**
348
+ * Creates a new multi-level list and returns its numId
349
+ */
350
+ createMultiLevelList(): number {
351
+ // Create abstract numbering
352
+ const abstractNumId = this.nextAbstractNumId++;
353
+ const abstractNumbering = AbstractNumbering.createMultiLevelList(abstractNumId);
354
+ this.addAbstractNumbering(abstractNumbering);
355
+
356
+ // Create instance
357
+ const numId = this.nextNumId++;
358
+ const instance = NumberingInstance.create({ numId, abstractNumId });
359
+ this.addInstance(instance);
360
+
361
+ return numId;
362
+ }
363
+
364
+ /**
365
+ * Creates a new outline list and returns its numId
366
+ */
367
+ createOutlineList(): number {
368
+ // Create abstract numbering
369
+ const abstractNumId = this.nextAbstractNumId++;
370
+ const abstractNumbering = AbstractNumbering.createOutlineList(abstractNumId);
371
+ this.addAbstractNumbering(abstractNumbering);
372
+
373
+ // Create instance
374
+ const numId = this.nextNumId++;
375
+ const instance = NumberingInstance.create({ numId, abstractNumId });
376
+ this.addInstance(instance);
377
+
378
+ return numId;
379
+ }
380
+
381
+ /**
382
+ * Creates a custom list with specified levels and returns its numId
383
+ * @param levels Array of numbering levels
384
+ * @param name Optional name for the list
385
+ */
386
+ createCustomList(levels: NumberingLevel[], name?: string): number {
387
+ // Create abstract numbering
388
+ const abstractNumId = this.nextAbstractNumId++;
389
+ const abstractNumbering = AbstractNumbering.create({
390
+ abstractNumId,
391
+ name,
392
+ levels,
393
+ });
394
+ this.addAbstractNumbering(abstractNumbering);
395
+
396
+ // Create instance
397
+ const numId = this.nextNumId++;
398
+ const instance = NumberingInstance.create({ numId, abstractNumId });
399
+ this.addInstance(instance);
400
+
401
+ return numId;
402
+ }
403
+
404
+ /**
405
+ * Creates a new instance of an existing abstract numbering
406
+ * @param abstractNumId The abstract numbering ID to create an instance of
407
+ */
408
+ createInstance(abstractNumId: number): number {
409
+ if (!this.hasAbstractNumbering(abstractNumId)) {
410
+ throw new Error(`Abstract numbering ${abstractNumId} does not exist`);
411
+ }
412
+
413
+ const numId = this.nextNumId++;
414
+ const instance = NumberingInstance.create({ numId, abstractNumId });
415
+ this.addInstance(instance);
416
+
417
+ return numId;
418
+ }
419
+
420
+ /**
421
+ * Gets the framework's standard indentation for a list level
422
+ *
423
+ * The framework uses a consistent indentation scheme:
424
+ * - leftIndent: 720 + (level * 360) twips
425
+ * - hangingIndent: 360 twips
426
+ *
427
+ * Examples:
428
+ * - Level 0: 720 twips (0.5 inch) left, 360 twips hanging
429
+ * - Level 1: 1080 twips (0.75 inch) left, 360 twips hanging
430
+ * - Level 2: 1440 twips (1.0 inch) left, 360 twips hanging
431
+ *
432
+ * @param level The level (0-8)
433
+ * @returns Object with leftIndent and hangingIndent in twips
434
+ * @example
435
+ * ```typescript
436
+ * const indent = manager.getStandardIndentation(0);
437
+ * // Returns: { leftIndent: 720, hangingIndent: 360 }
438
+ * ```
439
+ */
440
+ getStandardIndentation(level: number): { leftIndent: number; hangingIndent: number } {
441
+ if (level < 0 || level > 8) {
442
+ throw new Error(`Invalid level ${level}. Level must be between 0 and 8.`);
443
+ }
444
+
445
+ return {
446
+ leftIndent: 720 + (level * 360),
447
+ hangingIndent: 360,
448
+ };
449
+ }
450
+
451
+ /**
452
+ * Sets custom indentation for a specific level in a numbering definition
453
+ *
454
+ * This updates the indentation for a specific level across ALL paragraphs
455
+ * that use this numId and level combination.
456
+ *
457
+ * @param numId The numbering instance ID
458
+ * @param level The level to modify (0-8)
459
+ * @param leftIndent Left indentation in twips
460
+ * @param hangingIndent Hanging indentation in twips (optional, defaults to 360)
461
+ * @returns true if successful, false if numId doesn't exist
462
+ * @example
463
+ * ```typescript
464
+ * // Set level 0 to 0.5 inch left, 0.25 inch hanging
465
+ * manager.setListIndentation(1, 0, 720, 360);
466
+ * ```
467
+ */
468
+ setListIndentation(
469
+ numId: number,
470
+ level: number,
471
+ leftIndent: number,
472
+ hangingIndent = 360
473
+ ): boolean {
474
+ // Validate level
475
+ if (level < 0 || level > 8) {
476
+ throw new Error(`Invalid level ${level}. Level must be between 0 and 8.`);
477
+ }
478
+
479
+ // Validate indents (clamp negatives to 0)
480
+ leftIndent = Math.max(0, leftIndent);
481
+ hangingIndent = Math.max(0, hangingIndent);
482
+
483
+ // Get the numbering instance
484
+ const instance = this.getInstance(numId);
485
+ if (!instance) {
486
+ defaultLogger.warn(`Numbering instance ${numId} does not exist`);
487
+ return false;
488
+ }
489
+
490
+ // Get the abstract numbering
491
+ const abstractNum = this.getAbstractNumbering(instance.getAbstractNumId());
492
+ if (!abstractNum) {
493
+ defaultLogger.warn(`Abstract numbering for instance ${numId} does not exist`);
494
+ return false;
495
+ }
496
+
497
+ // Get the level from the abstract numbering
498
+ const numLevel = abstractNum.getLevel(level);
499
+ if (!numLevel) {
500
+ defaultLogger.warn(`Level ${level} does not exist in abstract numbering`);
501
+ return false;
502
+ }
503
+
504
+ // Update the level's indentation
505
+ numLevel.setLeftIndent(leftIndent);
506
+ numLevel.setHangingIndent(hangingIndent);
507
+
508
+ return true;
509
+ }
510
+
511
+ /**
512
+ * Resets all levels in a numbering definition to standard indentation
513
+ *
514
+ * This applies the framework's standard indentation formula to all levels:
515
+ * - leftIndent: 720 + (level * 360) twips
516
+ * - hangingIndent: 360 twips
517
+ *
518
+ * @param numId The numbering instance ID
519
+ * @returns true if successful, false if numId doesn't exist
520
+ * @example
521
+ * ```typescript
522
+ * // Reset list 1 to standard indentation
523
+ * manager.normalizeListIndentation(1);
524
+ * ```
525
+ */
526
+ normalizeListIndentation(numId: number): boolean {
527
+ // Get the numbering instance
528
+ const instance = this.getInstance(numId);
529
+ if (!instance) {
530
+ defaultLogger.warn(`Numbering instance ${numId} does not exist`);
531
+ return false;
532
+ }
533
+
534
+ // Get the abstract numbering
535
+ const abstractNum = this.getAbstractNumbering(instance.getAbstractNumId());
536
+ if (!abstractNum) {
537
+ defaultLogger.warn(`Abstract numbering for instance ${numId} does not exist`);
538
+ return false;
539
+ }
540
+
541
+ // Get all levels
542
+ const levels = abstractNum.getAllLevels();
543
+
544
+ // Apply standard indentation to each level
545
+ for (const level of levels) {
546
+ const standardIndent = this.getStandardIndentation(level.getLevel());
547
+ level.setLeftIndent(standardIndent.leftIndent);
548
+ level.setHangingIndent(standardIndent.hangingIndent);
549
+ }
550
+
551
+ return true;
552
+ }
553
+
554
+ /**
555
+ * Normalizes indentation for all lists in the document
556
+ *
557
+ * Applies standard indentation to every numbering instance:
558
+ * - leftIndent: 720 + (level * 360) twips
559
+ * - hangingIndent: 360 twips
560
+ *
561
+ * This ensures consistent spacing across all lists in the document.
562
+ *
563
+ * @returns Number of numbering instances updated
564
+ * @example
565
+ * ```typescript
566
+ * const count = manager.normalizeAllListIndentation();
567
+ * console.log(`Normalized ${count} lists`);
568
+ * ```
569
+ */
570
+ normalizeAllListIndentation(): number {
571
+ let count = 0;
572
+
573
+ // Iterate over all instances
574
+ for (const instance of this.getAllInstances()) {
575
+ const success = this.normalizeListIndentation(instance.getNumId());
576
+ if (success) {
577
+ count++;
578
+ }
579
+ }
580
+
581
+ return count;
582
+ }
583
+
584
+ /**
585
+ * Gets the total number of abstract numberings
586
+ */
587
+ getAbstractNumberingCount(): number {
588
+ return this.abstractNumberings.size;
589
+ }
590
+
591
+ /**
592
+ * Gets the total number of numbering instances
593
+ */
594
+ getInstanceCount(): number {
595
+ return this.instances.size;
596
+ }
597
+
598
+ /**
599
+ * Clears all numbering definitions and instances
600
+ */
601
+ clear(): this {
602
+ this.abstractNumberings.clear();
603
+ this.instances.clear();
604
+ this.nextAbstractNumId = 0;
605
+ this.nextNumId = 1;
606
+ return this;
607
+ }
608
+
609
+ /**
610
+ * Removes unused numbering instances and abstract numberings
611
+ *
612
+ * This method cleans up numbering definitions that are no longer referenced
613
+ * by any paragraphs in the document. It removes:
614
+ * 1. Instances not in the usedNumIds set
615
+ * 2. Abstract numberings not referenced by any remaining instance
616
+ *
617
+ * @param usedNumIds Set of numIds currently used by paragraphs
618
+ * @returns Object with counts of removed instances and abstract numberings
619
+ */
620
+ cleanupUnusedNumbering(usedNumIds: Set<number>): { instancesRemoved: number; abstractsRemoved: number } {
621
+ let instancesRemoved = 0;
622
+ let abstractsRemoved = 0;
623
+
624
+ // Step 1: Remove unused instances
625
+ const instancesToRemove: number[] = [];
626
+ this.instances.forEach((_instance, numId) => {
627
+ if (!usedNumIds.has(numId)) {
628
+ instancesToRemove.push(numId);
629
+ }
630
+ });
631
+
632
+ for (const numId of instancesToRemove) {
633
+ this.instances.delete(numId);
634
+ this._modified = true;
635
+ this._removedNumIds.add(numId);
636
+ instancesRemoved++;
637
+ }
638
+
639
+ // Step 2: Find abstract numberings still referenced by remaining instances
640
+ const referencedAbstractNumIds = new Set<number>();
641
+ this.instances.forEach(instance => {
642
+ referencedAbstractNumIds.add(instance.getAbstractNumId());
643
+ });
644
+
645
+ // Step 3: Remove unreferenced abstract numberings
646
+ const abstractsToRemove: number[] = [];
647
+ this.abstractNumberings.forEach((_abstractNum, abstractNumId) => {
648
+ if (!referencedAbstractNumIds.has(abstractNumId)) {
649
+ abstractsToRemove.push(abstractNumId);
650
+ }
651
+ });
652
+
653
+ for (const abstractNumId of abstractsToRemove) {
654
+ this.abstractNumberings.delete(abstractNumId);
655
+ this._modified = true;
656
+ this._removedAbstractNumIds.add(abstractNumId);
657
+ abstractsRemoved++;
658
+ }
659
+
660
+ return { instancesRemoved, abstractsRemoved };
661
+ }
662
+
663
+ /**
664
+ * Consolidates duplicate abstract numbering definitions
665
+ *
666
+ * Groups abstractNums by a deterministic fingerprint of their level properties
667
+ * (format, text, font, fontSize, color, indentation, alignment, etc.).
668
+ * For each group with >1 member, picks the lowest abstractNumId as canonical,
669
+ * remaps all instances pointing to non-canonical IDs, and removes duplicates.
670
+ *
671
+ * This is safe because multiple num instances can reference the same abstractNum —
672
+ * each instance maintains its own independent counter via level overrides.
673
+ *
674
+ * @param options Optional configuration (e.g., protected IDs to skip)
675
+ * @returns Summary of what was consolidated
676
+ */
677
+ consolidateNumbering(options?: NumberingConsolidationOptions): NumberingConsolidationResult {
678
+ const protectedIds = options?.protectedAbstractNumIds ?? new Set<number>();
679
+
680
+ // 1. Compute fingerprint for each non-protected abstractNum
681
+ const fingerprintGroups = new Map<string, number[]>();
682
+ for (const abstractNum of this.abstractNumberings.values()) {
683
+ const id = abstractNum.getAbstractNumId();
684
+ if (protectedIds.has(id)) continue;
685
+
686
+ const fingerprint = this._fingerprintAbstractNum(abstractNum);
687
+ const group = fingerprintGroups.get(fingerprint);
688
+ if (group) {
689
+ group.push(id);
690
+ } else {
691
+ fingerprintGroups.set(fingerprint, [id]);
692
+ }
693
+ }
694
+
695
+ // 2. For each group with >1 member, consolidate
696
+ let abstractNumsRemoved = 0;
697
+ let instancesRemapped = 0;
698
+ let groupsConsolidated = 0;
699
+
700
+ for (const [, ids] of fingerprintGroups) {
701
+ if (ids.length <= 1) continue;
702
+
703
+ // Sort to pick lowest ID as canonical
704
+ ids.sort((a, b) => a - b);
705
+ const canonicalId = ids[0]!;
706
+ const duplicateIds = new Set(ids.slice(1));
707
+
708
+ groupsConsolidated++;
709
+
710
+ // Remap instances pointing to duplicate abstractNums
711
+ for (const instance of this.instances.values()) {
712
+ if (duplicateIds.has(instance.getAbstractNumId())) {
713
+ instance.setAbstractNumId(canonicalId);
714
+ this._modifiedNumIds.add(instance.getNumId());
715
+ instancesRemapped++;
716
+ }
717
+ }
718
+
719
+ // Remove duplicate abstractNums
720
+ for (const dupId of duplicateIds) {
721
+ this.abstractNumberings.delete(dupId);
722
+ this._removedAbstractNumIds.add(dupId);
723
+ abstractNumsRemoved++;
724
+ }
725
+ }
726
+
727
+ if (abstractNumsRemoved > 0) {
728
+ this._modified = true;
729
+ }
730
+
731
+ return { abstractNumsRemoved, instancesRemapped, groupsConsolidated };
732
+ }
733
+
734
+ /**
735
+ * Computes a deterministic fingerprint for an abstract numbering definition
736
+ * based on its multiLevelType and all level properties. Name and abstractNumId
737
+ * are excluded since they don't affect rendering.
738
+ */
739
+ private _fingerprintAbstractNum(abstractNum: AbstractNumbering): string {
740
+ const parts: string[] = [
741
+ abstractNum.getNumStyleLink() ?? '',
742
+ abstractNum.getStyleLink() ?? '',
743
+ abstractNum.getMultiLevelType(),
744
+ ];
745
+
746
+ for (const level of abstractNum.getAllLevels()) {
747
+ const props = level.getProperties();
748
+ parts.push(
749
+ `${props.level}|${props.format}|${props.text}|${props.font}|${props.fontSize}|` +
750
+ `${props.color}|${props.leftIndent}|${props.hangingIndent}|${props.alignment}|` +
751
+ `${props.start}|${props.bold}|${props.italic}|${props.underline ?? ''}|` +
752
+ `${props.suffix}|${props.isLegalNumberingStyle}|${props.lvlRestart ?? ''}`
753
+ );
754
+ }
755
+
756
+ return parts.join('::');
757
+ }
758
+
759
+ /**
760
+ * Generates the complete numbering.xml content
761
+ */
762
+ generateNumberingXml(): string {
763
+ const builder = new XMLBuilder();
764
+
765
+ const children: XMLElement[] = [];
766
+
767
+ // Add all abstract numberings
768
+ const abstractNumberings = this.getAllAbstractNumberings();
769
+ abstractNumberings.forEach(abstractNum => {
770
+ children.push(abstractNum.toXML());
771
+ });
772
+
773
+ // Add all numbering instances
774
+ const instances = this.getAllInstances();
775
+ instances.forEach(instance => {
776
+ children.push(instance.toXML());
777
+ });
778
+
779
+ const numbering = XMLBuilder.w('numbering', {
780
+ 'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
781
+ 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
782
+ }, children);
783
+
784
+ builder.element(numbering.name, numbering.attributes, numbering.children);
785
+
786
+ // Generate XML with declaration
787
+ return builder.build(true);
788
+ }
789
+
790
+ /**
791
+ * Generates the numbering.xml as XMLElement (for API compatibility)
792
+ */
793
+ toXML(): XMLElement {
794
+ const children: XMLElement[] = [];
795
+
796
+ // Add all abstract numberings
797
+ const abstractNumberings = this.getAllAbstractNumberings();
798
+ abstractNumberings.forEach(abstractNum => {
799
+ children.push(abstractNum.toXML());
800
+ });
801
+
802
+ // Add all numbering instances
803
+ const instances = this.getAllInstances();
804
+ instances.forEach(instance => {
805
+ children.push(instance.toXML());
806
+ });
807
+
808
+ return XMLBuilder.w('numbering', {
809
+ 'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
810
+ 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
811
+ }, children);
812
+ }
813
+
814
+ /**
815
+ * Creates a numbering manager with default numbering definitions
816
+ */
817
+ static create(): NumberingManager {
818
+ return new NumberingManager(false);
819
+ }
820
+
821
+ /**
822
+ * Creates an empty numbering manager
823
+ */
824
+ static createEmpty(): NumberingManager {
825
+ return new NumberingManager(false);
826
+ }
827
+ }