docxmlater 10.0.2 → 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 (393) hide show
  1. package/README.md +2 -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 +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.js.map +1 -1
  139. package/dist/images/ImageOptimizer.js.map +1 -1
  140. package/dist/index.js.map +1 -1
  141. package/dist/managers/DrawingManager.d.ts.map +1 -1
  142. package/dist/managers/DrawingManager.js.map +1 -1
  143. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  144. package/dist/tracking/TrackingContext.js.map +1 -1
  145. package/dist/types/compatibility-types.js.map +1 -1
  146. package/dist/types/formatting.js.map +1 -1
  147. package/dist/types/list-types.d.ts +4 -4
  148. package/dist/types/list-types.d.ts.map +1 -1
  149. package/dist/types/list-types.js.map +1 -1
  150. package/dist/types/settings-types.js.map +1 -1
  151. package/dist/types/styleConfig.js.map +1 -1
  152. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  153. package/dist/utils/ChangelogGenerator.js.map +1 -1
  154. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  155. package/dist/utils/CompatibilityUpgrader.js +7 -7
  156. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  157. package/dist/utils/InMemoryRevisionAcceptor.js +1 -1
  158. package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
  159. package/dist/utils/MoveOperationHelper.js.map +1 -1
  160. package/dist/utils/RevisionAwareProcessor.js.map +1 -1
  161. package/dist/utils/RevisionWalker.js.map +1 -1
  162. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  163. package/dist/utils/ShadingResolver.js +1 -1
  164. package/dist/utils/ShadingResolver.js.map +1 -1
  165. package/dist/utils/acceptRevisions.d.ts +0 -28
  166. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  167. package/dist/utils/acceptRevisions.js +5 -7
  168. package/dist/utils/acceptRevisions.js.map +1 -1
  169. package/dist/utils/cnfStyleDecoder.js +1 -1
  170. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  171. package/dist/utils/corruptionDetection.js.map +1 -1
  172. package/dist/utils/dateFormatting.js.map +1 -1
  173. package/dist/utils/deepClone.d.ts +0 -1
  174. package/dist/utils/deepClone.d.ts.map +1 -1
  175. package/dist/utils/deepClone.js +0 -7
  176. package/dist/utils/deepClone.js.map +1 -1
  177. package/dist/utils/diagnostics.d.ts +2 -2
  178. package/dist/utils/diagnostics.d.ts.map +1 -1
  179. package/dist/utils/diagnostics.js.map +1 -1
  180. package/dist/utils/errorHandling.js.map +1 -1
  181. package/dist/utils/formatting.js.map +1 -1
  182. package/dist/utils/list-detection.d.ts +2 -2
  183. package/dist/utils/list-detection.d.ts.map +1 -1
  184. package/dist/utils/list-detection.js +3 -3
  185. package/dist/utils/list-detection.js.map +1 -1
  186. package/dist/utils/logger.d.ts +2 -4
  187. package/dist/utils/logger.d.ts.map +1 -1
  188. package/dist/utils/logger.js +0 -2
  189. package/dist/utils/logger.js.map +1 -1
  190. package/dist/utils/parsingHelpers.js.map +1 -1
  191. package/dist/utils/stripTrackedChanges.d.ts +0 -19
  192. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  193. package/dist/utils/stripTrackedChanges.js +0 -2
  194. package/dist/utils/stripTrackedChanges.js.map +1 -1
  195. package/dist/utils/textDiff.js.map +1 -1
  196. package/dist/utils/units.js.map +1 -1
  197. package/dist/utils/validation.d.ts.map +1 -1
  198. package/dist/utils/validation.js.map +1 -1
  199. package/dist/utils/xmlSanitization.js.map +1 -1
  200. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  201. package/dist/validation/RevisionValidator.js.map +1 -1
  202. package/dist/validation/ValidationRules.js.map +1 -1
  203. package/dist/validation/index.js.map +1 -1
  204. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  205. package/dist/xml/XMLBuilder.js +10 -0
  206. package/dist/xml/XMLBuilder.js.map +1 -1
  207. package/dist/xml/XMLParser.d.ts.map +1 -1
  208. package/dist/xml/XMLParser.js +4 -5
  209. package/dist/xml/XMLParser.js.map +1 -1
  210. package/dist/zip/ZipHandler.js.map +1 -1
  211. package/dist/zip/ZipReader.js.map +1 -1
  212. package/dist/zip/ZipWriter.js.map +1 -1
  213. package/dist/zip/errors.js.map +1 -1
  214. package/dist/zip/types.js.map +1 -1
  215. package/package.json +34 -4
  216. package/src/__tests__/helper-methods.test.ts +512 -0
  217. package/src/constants/legacyCompatFlags.ts +138 -0
  218. package/src/constants/limits.ts +50 -0
  219. package/src/core/CLAUDE.md +109 -0
  220. package/src/core/Document.ts +15569 -0
  221. package/src/core/DocumentContent.ts +467 -0
  222. package/src/core/DocumentGenerator.ts +1104 -0
  223. package/src/core/DocumentIdManager.ts +158 -0
  224. package/src/core/DocumentParser.ts +10107 -0
  225. package/src/core/DocumentValidator.ts +372 -0
  226. package/src/core/Relationship.ts +367 -0
  227. package/src/core/RelationshipManager.ts +428 -0
  228. package/src/elements/AlternateContent.ts +42 -0
  229. package/src/elements/Bookmark.ts +210 -0
  230. package/src/elements/BookmarkManager.ts +250 -0
  231. package/src/elements/CLAUDE.md +126 -0
  232. package/src/elements/Comment.ts +359 -0
  233. package/src/elements/CommentManager.ts +502 -0
  234. package/src/elements/CommonTypes.ts +549 -0
  235. package/src/elements/CustomXml.ts +36 -0
  236. package/src/elements/Endnote.ts +217 -0
  237. package/src/elements/EndnoteManager.ts +249 -0
  238. package/src/elements/Field.ts +1233 -0
  239. package/src/elements/FieldHelpers.ts +333 -0
  240. package/src/elements/FontManager.ts +339 -0
  241. package/src/elements/Footer.ts +269 -0
  242. package/src/elements/Footnote.ts +217 -0
  243. package/src/elements/FootnoteManager.ts +249 -0
  244. package/src/elements/Header.ts +269 -0
  245. package/src/elements/HeaderFooterManager.ts +219 -0
  246. package/src/elements/Hyperlink.ts +1146 -0
  247. package/src/elements/Image.ts +1756 -0
  248. package/src/elements/ImageManager.ts +432 -0
  249. package/src/elements/ImageRun.ts +59 -0
  250. package/src/elements/MathElement.ts +65 -0
  251. package/src/elements/Paragraph.ts +4227 -0
  252. package/src/elements/PreservedElement.ts +53 -0
  253. package/src/elements/PropertyChangeTypes.ts +442 -0
  254. package/src/elements/RangeMarker.ts +400 -0
  255. package/src/elements/Revision.ts +1217 -0
  256. package/src/elements/RevisionContent.ts +73 -0
  257. package/src/elements/RevisionManager.ts +1070 -0
  258. package/src/elements/Run.ts +3068 -0
  259. package/src/elements/Section.ts +1421 -0
  260. package/src/elements/Shape.ts +873 -0
  261. package/src/elements/StructuredDocumentTag.ts +978 -0
  262. package/src/elements/Table.ts +2524 -0
  263. package/src/elements/TableCell.ts +1586 -0
  264. package/src/elements/TableGridChange.ts +151 -0
  265. package/src/elements/TableOfContents.ts +691 -0
  266. package/src/elements/TableOfContentsElement.ts +89 -0
  267. package/src/elements/TableRow.ts +906 -0
  268. package/src/elements/TextBox.ts +768 -0
  269. package/src/formatting/AbstractNumbering.ts +548 -0
  270. package/src/formatting/CLAUDE.md +74 -0
  271. package/src/formatting/NumberingInstance.ts +212 -0
  272. package/src/formatting/NumberingLevel.ts +1006 -0
  273. package/src/formatting/NumberingManager.ts +827 -0
  274. package/src/formatting/Style.ts +1833 -0
  275. package/src/formatting/StylesManager.ts +1005 -0
  276. package/src/helpers/CleanupHelper.ts +524 -0
  277. package/src/images/ImageOptimizer.ts +274 -0
  278. package/src/index.ts +554 -0
  279. package/src/managers/CLAUDE.md +47 -0
  280. package/src/managers/DrawingManager.ts +319 -0
  281. package/src/tracking/DocumentTrackingContext.ts +643 -0
  282. package/src/tracking/TrackingContext.ts +173 -0
  283. package/src/types/compatibility-types.ts +49 -0
  284. package/src/types/formatting.ts +210 -0
  285. package/src/types/list-types.ts +152 -0
  286. package/src/types/settings-types.ts +59 -0
  287. package/src/types/styleConfig.ts +189 -0
  288. package/src/utils/CLAUDE.md +153 -0
  289. package/src/utils/ChangelogGenerator.ts +1581 -0
  290. package/src/utils/CompatibilityUpgrader.ts +237 -0
  291. package/src/utils/InMemoryRevisionAcceptor.ts +668 -0
  292. package/src/utils/MoveOperationHelper.ts +238 -0
  293. package/src/utils/RevisionAwareProcessor.ts +526 -0
  294. package/src/utils/RevisionWalker.ts +457 -0
  295. package/src/utils/SelectiveRevisionAcceptor.ts +613 -0
  296. package/src/utils/ShadingResolver.ts +107 -0
  297. package/src/utils/acceptRevisions.ts +714 -0
  298. package/src/utils/cnfStyleDecoder.ts +217 -0
  299. package/src/utils/corruptionDetection.ts +345 -0
  300. package/src/utils/dateFormatting.ts +20 -0
  301. package/src/utils/deepClone.ts +78 -0
  302. package/src/utils/diagnostics.ts +129 -0
  303. package/src/utils/errorHandling.ts +80 -0
  304. package/src/utils/formatting.ts +213 -0
  305. package/src/utils/list-detection.ts +274 -0
  306. package/src/utils/logger.ts +404 -0
  307. package/src/utils/parsingHelpers.ts +190 -0
  308. package/src/utils/stripTrackedChanges.ts +353 -0
  309. package/src/utils/textDiff.ts +100 -0
  310. package/src/utils/units.ts +421 -0
  311. package/src/utils/validation.ts +542 -0
  312. package/src/utils/xmlSanitization.ts +182 -0
  313. package/src/validation/RevisionAutoFixer.ts +542 -0
  314. package/src/validation/RevisionValidator.ts +460 -0
  315. package/src/validation/ValidationRules.ts +338 -0
  316. package/src/validation/index.ts +30 -0
  317. package/src/xml/CLAUDE.md +65 -0
  318. package/src/xml/XMLBuilder.ts +871 -0
  319. package/src/xml/XMLParser.ts +919 -0
  320. package/src/zip/CLAUDE.md +55 -0
  321. package/src/zip/ZipHandler.ts +637 -0
  322. package/src/zip/ZipReader.ts +299 -0
  323. package/src/zip/ZipWriter.ts +390 -0
  324. package/src/zip/errors.ts +69 -0
  325. package/src/zip/types.ts +116 -0
  326. package/dist/core/ListNormalizer.d.ts +0 -23
  327. package/dist/core/ListNormalizer.d.ts.map +0 -1
  328. package/dist/core/ListNormalizer.js +0 -624
  329. package/dist/core/ListNormalizer.js.map +0 -1
  330. package/dist/images/index.d.ts +0 -2
  331. package/dist/images/index.d.ts.map +0 -1
  332. package/dist/images/index.js +0 -8
  333. package/dist/images/index.js.map +0 -1
  334. package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
  335. package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
  336. package/dist/ms-doc/cfb/CFBReader.js +0 -360
  337. package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
  338. package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
  339. package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
  340. package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
  341. package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
  342. package/dist/ms-doc/fib/FIB.d.ts +0 -18
  343. package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
  344. package/dist/ms-doc/fib/FIB.js +0 -342
  345. package/dist/ms-doc/fib/FIB.js.map +0 -1
  346. package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
  347. package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
  348. package/dist/ms-doc/fields/FieldParser.js +0 -266
  349. package/dist/ms-doc/fields/FieldParser.js.map +0 -1
  350. package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
  351. package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
  352. package/dist/ms-doc/images/PictureExtractor.js +0 -233
  353. package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
  354. package/dist/ms-doc/index.d.ts +0 -20
  355. package/dist/ms-doc/index.d.ts.map +0 -1
  356. package/dist/ms-doc/index.js +0 -59
  357. package/dist/ms-doc/index.js.map +0 -1
  358. package/dist/ms-doc/properties/SPRM.d.ts +0 -210
  359. package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
  360. package/dist/ms-doc/properties/SPRM.js +0 -633
  361. package/dist/ms-doc/properties/SPRM.js.map +0 -1
  362. package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
  363. package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
  364. package/dist/ms-doc/sections/SectionParser.js +0 -214
  365. package/dist/ms-doc/sections/SectionParser.js.map +0 -1
  366. package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
  367. package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
  368. package/dist/ms-doc/styles/StyleSheet.js +0 -268
  369. package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
  370. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
  371. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
  372. package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
  373. package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
  374. package/dist/ms-doc/tables/TableParser.d.ts +0 -29
  375. package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
  376. package/dist/ms-doc/tables/TableParser.js +0 -176
  377. package/dist/ms-doc/tables/TableParser.js.map +0 -1
  378. package/dist/ms-doc/text/PieceTable.d.ts +0 -21
  379. package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
  380. package/dist/ms-doc/text/PieceTable.js +0 -171
  381. package/dist/ms-doc/text/PieceTable.js.map +0 -1
  382. package/dist/ms-doc/types/Constants.d.ts +0 -99
  383. package/dist/ms-doc/types/Constants.d.ts.map +0 -1
  384. package/dist/ms-doc/types/Constants.js +0 -102
  385. package/dist/ms-doc/types/Constants.js.map +0 -1
  386. package/dist/ms-doc/types/DocTypes.d.ts +0 -368
  387. package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
  388. package/dist/ms-doc/types/DocTypes.js +0 -3
  389. package/dist/ms-doc/types/DocTypes.js.map +0 -1
  390. package/dist/tracking/index.d.ts +0 -3
  391. package/dist/tracking/index.d.ts.map +0 -1
  392. package/dist/tracking/index.js +0 -6
  393. package/dist/tracking/index.js.map +0 -1
@@ -0,0 +1,182 @@
1
+ /**
2
+ * XML Sanitization Utilities
3
+ *
4
+ * Provides functions for validating and sanitizing text content per XML 1.0 specification.
5
+ * Per XML 1.0, certain control characters are invalid and must be removed before
6
+ * including text in XML documents.
7
+ *
8
+ * Valid characters in XML 1.0:
9
+ * - 0x09 (tab), 0x0A (newline), 0x0D (carriage return)
10
+ * - 0x20-0xD7FF, 0xE000-0xFFFD, 0x10000-0x10FFFF
11
+ *
12
+ * Invalid characters (control characters that must be removed):
13
+ * - 0x00-0x08 (NULL through BACKSPACE)
14
+ * - 0x0B-0x0C (VERTICAL TAB and FORM FEED)
15
+ * - 0x0E-0x1F (SHIFT OUT through UNIT SEPARATOR)
16
+ * - 0x7F (DELETE)
17
+ *
18
+ * @module xmlSanitization
19
+ */
20
+
21
+ import { getGlobalLogger } from "./logger";
22
+
23
+ /**
24
+ * Regular expression matching invalid XML 1.0 control characters.
25
+ * Matches: 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F
26
+ * Does NOT match valid chars: 0x09 (tab), 0x0A (newline), 0x0D (CR)
27
+ */
28
+ const INVALID_XML_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
29
+
30
+ /**
31
+ * Removes invalid XML 1.0 control characters from text.
32
+ *
33
+ * Per XML 1.0 spec, characters 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid
34
+ * and cannot appear in XML documents. This function removes them.
35
+ *
36
+ * Valid control characters are preserved:
37
+ * - Tab (0x09)
38
+ * - Line Feed / Newline (0x0A)
39
+ * - Carriage Return (0x0D)
40
+ *
41
+ * @param text - Input text to sanitize
42
+ * @param logWarning - If true, logs a warning when invalid chars are found (default: true)
43
+ * @returns Sanitized text with invalid control characters removed
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // Remove NULL byte from text
48
+ * const clean = removeInvalidXmlChars("Hello\x00World");
49
+ * // Returns: "HelloWorld"
50
+ *
51
+ * // Tab and newline are preserved
52
+ * const preserved = removeInvalidXmlChars("Hello\tWorld\n");
53
+ * // Returns: "Hello\tWorld\n"
54
+ * ```
55
+ */
56
+ export function removeInvalidXmlChars(
57
+ text: string,
58
+ logWarning = true
59
+ ): string {
60
+ // Reset regex lastIndex for global regex
61
+ INVALID_XML_CHAR_REGEX.lastIndex = 0;
62
+
63
+ if (logWarning && INVALID_XML_CHAR_REGEX.test(text)) {
64
+ // Reset regex lastIndex after test
65
+ INVALID_XML_CHAR_REGEX.lastIndex = 0;
66
+
67
+ const invalidChars = findInvalidXmlChars(text);
68
+ const hexCodes = invalidChars
69
+ .map((c) => `0x${c.toString(16).toUpperCase().padStart(2, "0")}`)
70
+ .join(", ");
71
+ getGlobalLogger().warn(
72
+ `[XMLSanitization] Removing invalid XML control characters: ${hexCodes}`
73
+ );
74
+ }
75
+
76
+ // Reset regex lastIndex before replace
77
+ INVALID_XML_CHAR_REGEX.lastIndex = 0;
78
+ return text.replace(INVALID_XML_CHAR_REGEX, "");
79
+ }
80
+
81
+ /**
82
+ * Finds all invalid XML 1.0 control characters in text.
83
+ *
84
+ * Returns an array of unique character codes that are invalid per XML 1.0 spec.
85
+ * This is useful for diagnostics and error reporting.
86
+ *
87
+ * @param text - Text to scan for invalid characters
88
+ * @returns Array of unique invalid character codes found, or empty array if text is valid
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const invalid = findInvalidXmlChars("Hello\x00\x08World");
93
+ * // Returns: [0, 8] - NULL and BACKSPACE codes
94
+ *
95
+ * const valid = findInvalidXmlChars("Hello\tWorld");
96
+ * // Returns: [] - tab is valid
97
+ * ```
98
+ */
99
+ export function findInvalidXmlChars(text: string): number[] {
100
+ const invalid: number[] = [];
101
+
102
+ for (let i = 0; i < text.length; i++) {
103
+ const code = text.charCodeAt(i);
104
+
105
+ // Check if character is in invalid ranges
106
+ if (
107
+ (code >= 0x00 && code <= 0x08) || // NULL through BACKSPACE
108
+ (code >= 0x0b && code <= 0x0c) || // VERTICAL TAB and FORM FEED
109
+ (code >= 0x0e && code <= 0x1f) || // SHIFT OUT through UNIT SEPARATOR
110
+ code === 0x7f // DELETE
111
+ ) {
112
+ // Only add unique codes
113
+ if (!invalid.includes(code)) {
114
+ invalid.push(code);
115
+ }
116
+ }
117
+ }
118
+
119
+ return invalid;
120
+ }
121
+
122
+ /**
123
+ * Checks if text contains any invalid XML 1.0 control characters.
124
+ *
125
+ * This is a fast check that returns true/false without identifying specific characters.
126
+ * Use `findInvalidXmlChars()` if you need to know which characters are invalid.
127
+ *
128
+ * @param text - Text to check
129
+ * @returns true if text contains invalid characters, false otherwise
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * hasInvalidXmlChars("Hello\x00World"); // true - NULL byte
134
+ * hasInvalidXmlChars("Hello\tWorld"); // false - tab is valid
135
+ * hasInvalidXmlChars("Normal text"); // false
136
+ * ```
137
+ */
138
+ export function hasInvalidXmlChars(text: string): boolean {
139
+ // Reset regex lastIndex for global regex
140
+ INVALID_XML_CHAR_REGEX.lastIndex = 0;
141
+ return INVALID_XML_CHAR_REGEX.test(text);
142
+ }
143
+
144
+ /**
145
+ * Character code constants for documentation and testing.
146
+ */
147
+ export const XML_CONTROL_CHARS = {
148
+ /** NULL (0x00) - Invalid */
149
+ NULL: 0x00,
150
+ /** Start of Heading (0x01) - Invalid */
151
+ SOH: 0x01,
152
+ /** Start of Text (0x02) - Invalid */
153
+ STX: 0x02,
154
+ /** End of Text (0x03) - Invalid */
155
+ ETX: 0x03,
156
+ /** End of Transmission (0x04) - Invalid */
157
+ EOT: 0x04,
158
+ /** Enquiry (0x05) - Invalid */
159
+ ENQ: 0x05,
160
+ /** Acknowledge (0x06) - Invalid */
161
+ ACK: 0x06,
162
+ /** Bell (0x07) - Invalid */
163
+ BEL: 0x07,
164
+ /** Backspace (0x08) - Invalid */
165
+ BS: 0x08,
166
+ /** Horizontal Tab (0x09) - VALID */
167
+ TAB: 0x09,
168
+ /** Line Feed / Newline (0x0A) - VALID */
169
+ LF: 0x0a,
170
+ /** Vertical Tab (0x0B) - Invalid */
171
+ VT: 0x0b,
172
+ /** Form Feed (0x0C) - Invalid */
173
+ FF: 0x0c,
174
+ /** Carriage Return (0x0D) - VALID */
175
+ CR: 0x0d,
176
+ /** Shift Out (0x0E) - Invalid */
177
+ SO: 0x0e,
178
+ /** Unit Separator (0x1F) - Invalid */
179
+ US: 0x1f,
180
+ /** Delete (0x7F) - Invalid */
181
+ DEL: 0x7f,
182
+ } as const;
@@ -0,0 +1,542 @@
1
+ /**
2
+ * RevisionAutoFixer - Automatically fixes revision validation issues
3
+ *
4
+ * Provides auto-fix capabilities for common revision compliance issues,
5
+ * helping to prevent document corruption while preserving user intent.
6
+ *
7
+ * @module RevisionAutoFixer
8
+ */
9
+
10
+ import type { Document } from '../core/Document';
11
+ import type { Revision } from '../elements/Revision';
12
+ import {
13
+ REVISION_RULES,
14
+ AutoFixOptions,
15
+ AutoFixResult,
16
+ FixAction,
17
+ ValidationIssue,
18
+ } from './ValidationRules';
19
+ import { RevisionValidator } from './RevisionValidator';
20
+
21
+ /**
22
+ * Automatically fixes revision validation issues.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Auto-fix all issues
27
+ * const result = RevisionAutoFixer.fix(doc);
28
+ * console.log(`Fixed ${result.issuesFixed} issues`);
29
+ *
30
+ * // Dry run (preview fixes without applying)
31
+ * const preview = RevisionAutoFixer.fix(doc, { dryRun: true });
32
+ * for (const action of preview.actions) {
33
+ * console.log(`Would fix: ${action.action}`);
34
+ * }
35
+ * ```
36
+ */
37
+ export class RevisionAutoFixer {
38
+ /**
39
+ * Auto-fix all fixable issues in a document.
40
+ *
41
+ * @param doc - Document to fix
42
+ * @param options - Fix options
43
+ * @returns Result with details of all fixes applied
44
+ */
45
+ static fix(doc: Document, options?: AutoFixOptions): AutoFixResult {
46
+ const actions: FixAction[] = [];
47
+ const errors: string[] = [];
48
+ const revisionManager = doc.getRevisionManager();
49
+
50
+ if (!revisionManager) {
51
+ return {
52
+ allFixed: true,
53
+ issuesFixed: 0,
54
+ issuesRemaining: 0,
55
+ actions: [],
56
+ errors: [],
57
+ };
58
+ }
59
+
60
+ const revisions = revisionManager.getAllRevisions();
61
+ const skipRules = new Set(options?.skipRules || []);
62
+ const onlyRules = options?.onlyRules ? new Set(options.onlyRules) : null;
63
+
64
+ // Helper to check if a rule should be processed
65
+ const shouldProcess = (ruleCode: string) => {
66
+ if (skipRules.has(ruleCode)) return false;
67
+ if (onlyRules && !onlyRules.has(ruleCode)) return false;
68
+ return true;
69
+ };
70
+
71
+ try {
72
+ // Fix duplicate IDs (REV001)
73
+ if (shouldProcess('REV001')) {
74
+ actions.push(...this.fixDuplicateIds(revisions, options?.dryRun));
75
+ }
76
+
77
+ // Fix missing authors (REV002)
78
+ if (shouldProcess('REV002')) {
79
+ const defaultAuthor = options?.defaultAuthor || 'Unknown Author';
80
+ actions.push(...this.fixMissingAuthors(revisions, defaultAuthor, options?.dryRun));
81
+ }
82
+
83
+ // Fix orphaned move markers (REV003, REV004)
84
+ if (shouldProcess('REV003') || shouldProcess('REV004')) {
85
+ actions.push(...this.fixOrphanedMoveMarkers(revisionManager, revisions, options?.dryRun));
86
+ }
87
+
88
+ // Fix missing dates (REV101)
89
+ if (shouldProcess('REV101')) {
90
+ actions.push(...this.fixMissingDates(revisions, options?.dryRun));
91
+ }
92
+
93
+ // Fix invalid dates (REV102)
94
+ if (shouldProcess('REV102')) {
95
+ actions.push(...this.fixInvalidDates(revisions, options?.dryRun));
96
+ }
97
+
98
+ // Fix empty revisions (REV103)
99
+ if (shouldProcess('REV103')) {
100
+ actions.push(...this.fixEmptyRevisions(revisionManager, revisions, options?.dryRun));
101
+ }
102
+
103
+ // Fix non-sequential IDs (REV104)
104
+ if (shouldProcess('REV104')) {
105
+ actions.push(...this.fixNonSequentialIds(revisions, options?.dryRun));
106
+ }
107
+
108
+ } catch (error: unknown) {
109
+ errors.push(`Fix error: ${error instanceof Error ? error.message : String(error)}`);
110
+ }
111
+
112
+ // Validate after fixes
113
+ const postValidation = RevisionValidator.validate(doc);
114
+
115
+ // Log actions if verbose
116
+ if (options?.verbose) {
117
+ for (const action of actions) {
118
+ console.log(`[AutoFix] ${action.action}: ${action.issue.code}`);
119
+ }
120
+ }
121
+
122
+ return {
123
+ allFixed: postValidation.valid,
124
+ issuesFixed: actions.filter(a => a.success).length,
125
+ issuesRemaining: postValidation.summary.errorCount + postValidation.summary.warningCount,
126
+ actions,
127
+ errors,
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Fix duplicate revision IDs by reassigning.
133
+ *
134
+ * Assigns new unique IDs to revisions with duplicate IDs.
135
+ *
136
+ * @param revisions - Array of revisions
137
+ * @param dryRun - If true, only report changes without applying
138
+ * @returns Array of fix actions
139
+ */
140
+ static fixDuplicateIds(revisions: Revision[], dryRun?: boolean): FixAction[] {
141
+ const actions: FixAction[] = [];
142
+ const usedIds = new Set<number>();
143
+ let nextId = Math.max(...revisions.map(r => r.getId()), 0) + 1;
144
+
145
+ for (const rev of revisions) {
146
+ const id = rev.getId();
147
+
148
+ if (usedIds.has(id)) {
149
+ const newId = nextId++;
150
+ const issue: ValidationIssue = {
151
+ code: REVISION_RULES.DUPLICATE_ID.code,
152
+ severity: 'error',
153
+ message: `Duplicate ID ${id}`,
154
+ location: { revisionId: id },
155
+ autoFixable: true,
156
+ };
157
+
158
+ actions.push({
159
+ issue,
160
+ action: `Reassigned duplicate ID ${id} to ${newId}`,
161
+ before: id,
162
+ after: newId,
163
+ success: true,
164
+ });
165
+
166
+ if (!dryRun) {
167
+ rev.setId(newId);
168
+ }
169
+ }
170
+ usedIds.add(rev.getId());
171
+ }
172
+
173
+ return actions;
174
+ }
175
+
176
+ /**
177
+ * Fix missing authors by setting a default value.
178
+ *
179
+ * @param revisions - Array of revisions
180
+ * @param defaultAuthor - Default author name to use
181
+ * @param dryRun - If true, only report changes without applying
182
+ * @returns Array of fix actions
183
+ */
184
+ static fixMissingAuthors(
185
+ revisions: Revision[],
186
+ defaultAuthor: string,
187
+ dryRun?: boolean
188
+ ): FixAction[] {
189
+ const actions: FixAction[] = [];
190
+
191
+ for (const rev of revisions) {
192
+ const author = rev.getAuthor();
193
+
194
+ if (!author || author.trim() === '') {
195
+ const issue: ValidationIssue = {
196
+ code: REVISION_RULES.MISSING_AUTHOR.code,
197
+ severity: 'error',
198
+ message: `Missing author for revision ${rev.getId()}`,
199
+ location: { revisionId: rev.getId() },
200
+ autoFixable: true,
201
+ };
202
+
203
+ actions.push({
204
+ issue,
205
+ action: `Set author to "${defaultAuthor}" for revision ${rev.getId()}`,
206
+ before: author,
207
+ after: defaultAuthor,
208
+ success: true,
209
+ });
210
+
211
+ if (!dryRun) {
212
+ rev.setAuthor(defaultAuthor);
213
+ }
214
+ }
215
+ }
216
+
217
+ return actions;
218
+ }
219
+
220
+ /**
221
+ * Fix missing dates by setting current date.
222
+ *
223
+ * @param revisions - Array of revisions
224
+ * @param dryRun - If true, only report changes without applying
225
+ * @returns Array of fix actions
226
+ */
227
+ static fixMissingDates(revisions: Revision[], dryRun?: boolean): FixAction[] {
228
+ const actions: FixAction[] = [];
229
+ const now = new Date();
230
+
231
+ for (const rev of revisions) {
232
+ const date = rev.getDate();
233
+
234
+ if (!date) {
235
+ const issue: ValidationIssue = {
236
+ code: REVISION_RULES.MISSING_DATE.code,
237
+ severity: 'warning',
238
+ message: `Missing date for revision ${rev.getId()}`,
239
+ location: { revisionId: rev.getId() },
240
+ autoFixable: true,
241
+ };
242
+
243
+ actions.push({
244
+ issue,
245
+ action: `Set date to ${now.toISOString()} for revision ${rev.getId()}`,
246
+ before: null,
247
+ after: now,
248
+ success: true,
249
+ });
250
+
251
+ if (!dryRun) {
252
+ rev.setDate(now);
253
+ }
254
+ }
255
+ }
256
+
257
+ return actions;
258
+ }
259
+
260
+ /**
261
+ * Fix invalid dates by replacing with current date.
262
+ *
263
+ * @param revisions - Array of revisions
264
+ * @param dryRun - If true, only report changes without applying
265
+ * @returns Array of fix actions
266
+ */
267
+ static fixInvalidDates(revisions: Revision[], dryRun?: boolean): FixAction[] {
268
+ const actions: FixAction[] = [];
269
+ const now = new Date();
270
+
271
+ for (const rev of revisions) {
272
+ const date = rev.getDate();
273
+
274
+ if (date && isNaN(date.getTime())) {
275
+ const issue: ValidationIssue = {
276
+ code: REVISION_RULES.INVALID_DATE_FORMAT.code,
277
+ severity: 'warning',
278
+ message: `Invalid date for revision ${rev.getId()}`,
279
+ location: { revisionId: rev.getId() },
280
+ autoFixable: true,
281
+ };
282
+
283
+ actions.push({
284
+ issue,
285
+ action: `Replaced invalid date with ${now.toISOString()} for revision ${rev.getId()}`,
286
+ before: date,
287
+ after: now,
288
+ success: true,
289
+ });
290
+
291
+ if (!dryRun) {
292
+ rev.setDate(now);
293
+ }
294
+ }
295
+ }
296
+
297
+ return actions;
298
+ }
299
+
300
+ /**
301
+ * Fix orphaned move markers by removing them.
302
+ *
303
+ * @param revisionManager - RevisionManager instance
304
+ * @param revisions - Array of revisions
305
+ * @param dryRun - If true, only report changes without applying
306
+ * @returns Array of fix actions
307
+ */
308
+ static fixOrphanedMoveMarkers(
309
+ revisionManager: { removeById(id: number): boolean },
310
+ revisions: Revision[],
311
+ dryRun?: boolean
312
+ ): FixAction[] {
313
+ const actions: FixAction[] = [];
314
+
315
+ const moveFromIds = new Map<string, Revision>();
316
+ const moveToIds = new Map<string, Revision>();
317
+
318
+ for (const rev of revisions) {
319
+ const moveId = rev.getMoveId();
320
+ if (!moveId) continue;
321
+
322
+ if (rev.getType() === 'moveFrom') {
323
+ moveFromIds.set(moveId, rev);
324
+ } else if (rev.getType() === 'moveTo') {
325
+ moveToIds.set(moveId, rev);
326
+ }
327
+ }
328
+
329
+ // Remove orphaned moveFrom
330
+ for (const [moveId, rev] of moveFromIds) {
331
+ if (!moveToIds.has(moveId)) {
332
+ const issue: ValidationIssue = {
333
+ code: REVISION_RULES.ORPHANED_MOVE_FROM.code,
334
+ severity: 'error',
335
+ message: `Orphaned moveFrom with moveId="${moveId}"`,
336
+ location: { revisionId: rev.getId() },
337
+ autoFixable: true,
338
+ };
339
+
340
+ actions.push({
341
+ issue,
342
+ action: `Removed orphaned moveFrom (ID: ${rev.getId()}, moveId: ${moveId})`,
343
+ before: { type: 'moveFrom', moveId },
344
+ after: null,
345
+ success: true,
346
+ });
347
+
348
+ if (!dryRun) {
349
+ revisionManager.removeById(rev.getId());
350
+ }
351
+ }
352
+ }
353
+
354
+ // Remove orphaned moveTo
355
+ for (const [moveId, rev] of moveToIds) {
356
+ if (!moveFromIds.has(moveId)) {
357
+ const issue: ValidationIssue = {
358
+ code: REVISION_RULES.ORPHANED_MOVE_TO.code,
359
+ severity: 'error',
360
+ message: `Orphaned moveTo with moveId="${moveId}"`,
361
+ location: { revisionId: rev.getId() },
362
+ autoFixable: true,
363
+ };
364
+
365
+ actions.push({
366
+ issue,
367
+ action: `Removed orphaned moveTo (ID: ${rev.getId()}, moveId: ${moveId})`,
368
+ before: { type: 'moveTo', moveId },
369
+ after: null,
370
+ success: true,
371
+ });
372
+
373
+ if (!dryRun) {
374
+ revisionManager.removeById(rev.getId());
375
+ }
376
+ }
377
+ }
378
+
379
+ return actions;
380
+ }
381
+
382
+ /**
383
+ * Fix empty revisions by removing them.
384
+ *
385
+ * @param revisionManager - RevisionManager instance
386
+ * @param revisions - Array of revisions
387
+ * @param dryRun - If true, only report changes without applying
388
+ * @returns Array of fix actions
389
+ */
390
+ static fixEmptyRevisions(
391
+ revisionManager: any,
392
+ revisions: Revision[],
393
+ dryRun?: boolean
394
+ ): FixAction[] {
395
+ const actions: FixAction[] = [];
396
+
397
+ const propertyChangeTypes = [
398
+ 'runPropertiesChange',
399
+ 'paragraphPropertiesChange',
400
+ 'tablePropertiesChange',
401
+ 'tableExceptionPropertiesChange',
402
+ 'tableRowPropertiesChange',
403
+ 'tableCellPropertiesChange',
404
+ 'sectionPropertiesChange',
405
+ 'numberingChange',
406
+ ];
407
+
408
+ for (const rev of revisions) {
409
+ const type = rev.getType();
410
+
411
+ // Skip property changes
412
+ if (propertyChangeTypes.includes(type)) {
413
+ continue;
414
+ }
415
+
416
+ const runs = rev.getRuns();
417
+ const hasContent = runs.length > 0 && runs.some(r => r.getText().length > 0);
418
+
419
+ if (!hasContent) {
420
+ const issue: ValidationIssue = {
421
+ code: REVISION_RULES.EMPTY_REVISION.code,
422
+ severity: 'warning',
423
+ message: `Empty revision ${rev.getId()} (type: ${type})`,
424
+ location: { revisionId: rev.getId() },
425
+ autoFixable: true,
426
+ };
427
+
428
+ actions.push({
429
+ issue,
430
+ action: `Removed empty revision (ID: ${rev.getId()}, type: ${type})`,
431
+ before: { id: rev.getId(), type },
432
+ after: null,
433
+ success: true,
434
+ });
435
+
436
+ if (!dryRun) {
437
+ revisionManager.removeById(rev.getId());
438
+ }
439
+ }
440
+ }
441
+
442
+ return actions;
443
+ }
444
+
445
+ /**
446
+ * Fix non-sequential IDs by reassigning.
447
+ *
448
+ * @param revisions - Array of revisions
449
+ * @param dryRun - If true, only report changes without applying
450
+ * @returns Array of fix actions
451
+ */
452
+ static fixNonSequentialIds(revisions: Revision[], dryRun?: boolean): FixAction[] {
453
+ const actions: FixAction[] = [];
454
+
455
+ if (revisions.length === 0) return actions;
456
+
457
+ // Check if IDs are already sequential
458
+ const ids = revisions.map(r => r.getId()).sort((a, b) => a - b);
459
+ let isSequential = true;
460
+
461
+ for (let i = 1; i < ids.length; i++) {
462
+ const currentId = ids[i]!;
463
+ const prevId = ids[i - 1]!;
464
+ if (currentId !== prevId + 1) {
465
+ isSequential = false;
466
+ break;
467
+ }
468
+ }
469
+
470
+ if (!isSequential) {
471
+ const issue: ValidationIssue = {
472
+ code: REVISION_RULES.NON_SEQUENTIAL_IDS.code,
473
+ severity: 'warning',
474
+ message: 'Revision IDs are not sequential',
475
+ autoFixable: true,
476
+ };
477
+
478
+ const oldIds = revisions.map(r => r.getId());
479
+ const newIds: number[] = [];
480
+
481
+ revisions.forEach((rev, index) => {
482
+ newIds.push(index);
483
+ if (!dryRun) {
484
+ rev.setId(index);
485
+ }
486
+ });
487
+
488
+ actions.push({
489
+ issue,
490
+ action: `Reassigned ${revisions.length} revision IDs to be sequential (0 to ${revisions.length - 1})`,
491
+ before: oldIds,
492
+ after: newIds,
493
+ success: true,
494
+ });
495
+ }
496
+
497
+ return actions;
498
+ }
499
+
500
+ /**
501
+ * Preview fixes without applying them.
502
+ *
503
+ * Convenience method that calls fix() with dryRun: true.
504
+ *
505
+ * @param doc - Document to preview fixes for
506
+ * @param options - Fix options (dryRun is forced to true)
507
+ * @returns Result showing what would be fixed
508
+ */
509
+ static preview(doc: Document, options?: Omit<AutoFixOptions, 'dryRun'>): AutoFixResult {
510
+ return this.fix(doc, { ...options, dryRun: true });
511
+ }
512
+
513
+ /**
514
+ * Format fix result as a human-readable string.
515
+ *
516
+ * @param result - AutoFixResult to format
517
+ * @returns Formatted string
518
+ */
519
+ static formatResult(result: AutoFixResult): string {
520
+ const lines: string[] = [];
521
+
522
+ lines.push(`Auto-Fix ${result.allFixed ? 'COMPLETE' : 'PARTIAL'}`);
523
+ lines.push(`Fixed: ${result.issuesFixed}, Remaining: ${result.issuesRemaining}`);
524
+
525
+ if (result.actions.length > 0) {
526
+ lines.push('\nActions taken:');
527
+ for (const action of result.actions) {
528
+ const status = action.success ? 'OK' : 'FAILED';
529
+ lines.push(` [${status}] ${action.action}`);
530
+ }
531
+ }
532
+
533
+ if (result.errors.length > 0) {
534
+ lines.push('\nErrors:');
535
+ for (const error of result.errors) {
536
+ lines.push(` - ${error}`);
537
+ }
538
+ }
539
+
540
+ return lines.join('\n');
541
+ }
542
+ }