docxmlater 11.0.10 → 12.1.0

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 (361) hide show
  1. package/README.md +53 -13
  2. package/dist/core/Document.d.ts +29 -3
  3. package/dist/core/Document.d.ts.map +1 -1
  4. package/dist/core/Document.js +733 -170
  5. package/dist/core/Document.js.map +1 -1
  6. package/dist/core/DocumentGenerator.d.ts +1 -0
  7. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  8. package/dist/core/DocumentGenerator.js +77 -25
  9. package/dist/core/DocumentGenerator.js.map +1 -1
  10. package/dist/core/DocumentParser.d.ts +7 -3
  11. package/dist/core/DocumentParser.d.ts.map +1 -1
  12. package/dist/core/DocumentParser.js +427 -81
  13. package/dist/core/DocumentParser.js.map +1 -1
  14. package/dist/core/RelationshipManager.d.ts.map +1 -1
  15. package/dist/core/RelationshipManager.js +2 -2
  16. package/dist/core/RelationshipManager.js.map +1 -1
  17. package/dist/elements/Comment.d.ts +15 -1
  18. package/dist/elements/Comment.d.ts.map +1 -1
  19. package/dist/elements/Comment.js +67 -12
  20. package/dist/elements/Comment.js.map +1 -1
  21. package/dist/elements/CommentManager.d.ts +4 -0
  22. package/dist/elements/CommentManager.d.ts.map +1 -1
  23. package/dist/elements/CommentManager.js +74 -16
  24. package/dist/elements/CommentManager.js.map +1 -1
  25. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  26. package/dist/elements/EndnoteManager.js.map +1 -1
  27. package/dist/elements/Field.d.ts +10 -1
  28. package/dist/elements/Field.d.ts.map +1 -1
  29. package/dist/elements/Field.js +76 -34
  30. package/dist/elements/Field.js.map +1 -1
  31. package/dist/elements/FieldHelpers.d.ts +1 -0
  32. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  33. package/dist/elements/FieldHelpers.js +8 -4
  34. package/dist/elements/FieldHelpers.js.map +1 -1
  35. package/dist/elements/Footer.d.ts +3 -1
  36. package/dist/elements/Footer.d.ts.map +1 -1
  37. package/dist/elements/Footer.js +39 -53
  38. package/dist/elements/Footer.js.map +1 -1
  39. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  40. package/dist/elements/FootnoteManager.js.map +1 -1
  41. package/dist/elements/Header.d.ts +3 -1
  42. package/dist/elements/Header.d.ts.map +1 -1
  43. package/dist/elements/Header.js +39 -53
  44. package/dist/elements/Header.js.map +1 -1
  45. package/dist/elements/HeaderFooterManager.d.ts +4 -2
  46. package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
  47. package/dist/elements/HeaderFooterManager.js +36 -6
  48. package/dist/elements/HeaderFooterManager.js.map +1 -1
  49. package/dist/elements/Hyperlink.d.ts +6 -1
  50. package/dist/elements/Hyperlink.d.ts.map +1 -1
  51. package/dist/elements/Hyperlink.js +69 -44
  52. package/dist/elements/Hyperlink.js.map +1 -1
  53. package/dist/elements/Image.d.ts.map +1 -1
  54. package/dist/elements/Image.js +33 -6
  55. package/dist/elements/Image.js.map +1 -1
  56. package/dist/elements/ImageManager.d.ts +1 -0
  57. package/dist/elements/ImageManager.d.ts.map +1 -1
  58. package/dist/elements/ImageManager.js +11 -0
  59. package/dist/elements/ImageManager.js.map +1 -1
  60. package/dist/elements/Paragraph.d.ts +3 -0
  61. package/dist/elements/Paragraph.d.ts.map +1 -1
  62. package/dist/elements/Paragraph.js +91 -26
  63. package/dist/elements/Paragraph.js.map +1 -1
  64. package/dist/elements/Revision.d.ts +4 -0
  65. package/dist/elements/Revision.d.ts.map +1 -1
  66. package/dist/elements/Revision.js +369 -29
  67. package/dist/elements/Revision.js.map +1 -1
  68. package/dist/elements/Run.d.ts +1 -0
  69. package/dist/elements/Run.d.ts.map +1 -1
  70. package/dist/elements/Run.js +24 -4
  71. package/dist/elements/Run.js.map +1 -1
  72. package/dist/elements/Section.d.ts.map +1 -1
  73. package/dist/elements/Section.js +17 -7
  74. package/dist/elements/Section.js.map +1 -1
  75. package/dist/elements/Shape.d.ts.map +1 -1
  76. package/dist/elements/Shape.js +50 -42
  77. package/dist/elements/Shape.js.map +1 -1
  78. package/dist/elements/StructuredDocumentTag.d.ts +9 -1
  79. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  80. package/dist/elements/StructuredDocumentTag.js +46 -6
  81. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  82. package/dist/elements/Table.d.ts +2 -0
  83. package/dist/elements/Table.d.ts.map +1 -1
  84. package/dist/elements/Table.js +90 -42
  85. package/dist/elements/Table.js.map +1 -1
  86. package/dist/elements/TableCell.d.ts +1 -0
  87. package/dist/elements/TableCell.d.ts.map +1 -1
  88. package/dist/elements/TableCell.js +32 -13
  89. package/dist/elements/TableCell.js.map +1 -1
  90. package/dist/elements/TableOfContents.d.ts.map +1 -1
  91. package/dist/elements/TableOfContents.js +5 -7
  92. package/dist/elements/TableOfContents.js.map +1 -1
  93. package/dist/elements/TableRow.d.ts +1 -0
  94. package/dist/elements/TableRow.d.ts.map +1 -1
  95. package/dist/elements/TableRow.js +16 -1
  96. package/dist/elements/TableRow.js.map +1 -1
  97. package/dist/elements/TextBox.d.ts.map +1 -1
  98. package/dist/elements/TextBox.js +55 -42
  99. package/dist/elements/TextBox.js.map +1 -1
  100. package/dist/esm/core/Document.js +735 -172
  101. package/dist/esm/core/Document.js.map +1 -1
  102. package/dist/esm/core/DocumentGenerator.js +77 -25
  103. package/dist/esm/core/DocumentGenerator.js.map +1 -1
  104. package/dist/esm/core/DocumentParser.js +427 -81
  105. package/dist/esm/core/DocumentParser.js.map +1 -1
  106. package/dist/esm/core/RelationshipManager.js +2 -2
  107. package/dist/esm/core/RelationshipManager.js.map +1 -1
  108. package/dist/esm/elements/Comment.js +67 -12
  109. package/dist/esm/elements/Comment.js.map +1 -1
  110. package/dist/esm/elements/CommentManager.js +74 -16
  111. package/dist/esm/elements/CommentManager.js.map +1 -1
  112. package/dist/esm/elements/EndnoteManager.js.map +1 -1
  113. package/dist/esm/elements/Field.js +77 -35
  114. package/dist/esm/elements/Field.js.map +1 -1
  115. package/dist/esm/elements/FieldHelpers.js +7 -4
  116. package/dist/esm/elements/FieldHelpers.js.map +1 -1
  117. package/dist/esm/elements/Footer.js +39 -53
  118. package/dist/esm/elements/Footer.js.map +1 -1
  119. package/dist/esm/elements/FootnoteManager.js.map +1 -1
  120. package/dist/esm/elements/Header.js +39 -53
  121. package/dist/esm/elements/Header.js.map +1 -1
  122. package/dist/esm/elements/HeaderFooterManager.js +36 -6
  123. package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
  124. package/dist/esm/elements/Hyperlink.js +69 -44
  125. package/dist/esm/elements/Hyperlink.js.map +1 -1
  126. package/dist/esm/elements/Image.js +33 -6
  127. package/dist/esm/elements/Image.js.map +1 -1
  128. package/dist/esm/elements/ImageManager.js +11 -0
  129. package/dist/esm/elements/ImageManager.js.map +1 -1
  130. package/dist/esm/elements/Paragraph.js +91 -26
  131. package/dist/esm/elements/Paragraph.js.map +1 -1
  132. package/dist/esm/elements/Revision.js +369 -29
  133. package/dist/esm/elements/Revision.js.map +1 -1
  134. package/dist/esm/elements/Run.js +24 -4
  135. package/dist/esm/elements/Run.js.map +1 -1
  136. package/dist/esm/elements/Section.js +17 -7
  137. package/dist/esm/elements/Section.js.map +1 -1
  138. package/dist/esm/elements/Shape.js +50 -42
  139. package/dist/esm/elements/Shape.js.map +1 -1
  140. package/dist/esm/elements/StructuredDocumentTag.js +46 -6
  141. package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
  142. package/dist/esm/elements/Table.js +90 -42
  143. package/dist/esm/elements/Table.js.map +1 -1
  144. package/dist/esm/elements/TableCell.js +32 -13
  145. package/dist/esm/elements/TableCell.js.map +1 -1
  146. package/dist/esm/elements/TableOfContents.js +5 -7
  147. package/dist/esm/elements/TableOfContents.js.map +1 -1
  148. package/dist/esm/elements/TableRow.js +16 -1
  149. package/dist/esm/elements/TableRow.js.map +1 -1
  150. package/dist/esm/elements/TextBox.js +55 -42
  151. package/dist/esm/elements/TextBox.js.map +1 -1
  152. package/dist/esm/formatting/AbstractNumbering.js +1 -1
  153. package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
  154. package/dist/esm/formatting/NumberingLevel.js +8 -6
  155. package/dist/esm/formatting/NumberingLevel.js.map +1 -1
  156. package/dist/esm/formatting/NumberingManager.js +16 -1
  157. package/dist/esm/formatting/NumberingManager.js.map +1 -1
  158. package/dist/esm/formatting/Style.js +14 -0
  159. package/dist/esm/formatting/Style.js.map +1 -1
  160. package/dist/esm/formatting/StylesManager.js +14 -2
  161. package/dist/esm/formatting/StylesManager.js.map +1 -1
  162. package/dist/esm/helpers/CleanupHelper.js +103 -26
  163. package/dist/esm/helpers/CleanupHelper.js.map +1 -1
  164. package/dist/esm/images/ImageOptimizer.js +52 -4
  165. package/dist/esm/images/ImageOptimizer.js.map +1 -1
  166. package/dist/esm/index.js +1 -0
  167. package/dist/esm/index.js.map +1 -1
  168. package/dist/esm/internal.js +1 -1
  169. package/dist/esm/internal.js.map +1 -1
  170. package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
  171. package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
  172. package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
  173. package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
  174. package/dist/esm/processors/RevisionWalker.js +223 -39
  175. package/dist/esm/processors/RevisionWalker.js.map +1 -1
  176. package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
  177. package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
  178. package/dist/esm/processors/acceptRevisions.js +20 -11
  179. package/dist/esm/processors/acceptRevisions.js.map +1 -1
  180. package/dist/esm/processors/cnfStyleDecoder.js +7 -7
  181. package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
  182. package/dist/esm/processors/stripTrackedChanges.js +16 -5
  183. package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
  184. package/dist/esm/utils/deepClone.js +24 -11
  185. package/dist/esm/utils/deepClone.js.map +1 -1
  186. package/dist/esm/utils/units.js +1 -1
  187. package/dist/esm/utils/units.js.map +1 -1
  188. package/dist/esm/utils/validation.js +11 -23
  189. package/dist/esm/utils/validation.js.map +1 -1
  190. package/dist/esm/utils/xmlSanitization.js +131 -7
  191. package/dist/esm/utils/xmlSanitization.js.map +1 -1
  192. package/dist/esm/validation/RevisionAutoFixer.js +69 -55
  193. package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
  194. package/dist/esm/validation/RevisionValidator.js +24 -20
  195. package/dist/esm/validation/RevisionValidator.js.map +1 -1
  196. package/dist/esm/xml/XMLBuilder.js +52 -20
  197. package/dist/esm/xml/XMLBuilder.js.map +1 -1
  198. package/dist/esm/xml/XMLParser.js +55 -13
  199. package/dist/esm/xml/XMLParser.js.map +1 -1
  200. package/dist/esm/zip/ZipHandler.js +37 -13
  201. package/dist/esm/zip/ZipHandler.js.map +1 -1
  202. package/dist/esm/zip/ZipReader.js +53 -6
  203. package/dist/esm/zip/ZipReader.js.map +1 -1
  204. package/dist/esm/zip/errors.js +7 -0
  205. package/dist/esm/zip/errors.js.map +1 -1
  206. package/dist/esm/zip/types.js +4 -0
  207. package/dist/esm/zip/types.js.map +1 -1
  208. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  209. package/dist/formatting/AbstractNumbering.js +1 -1
  210. package/dist/formatting/AbstractNumbering.js.map +1 -1
  211. package/dist/formatting/NumberingLevel.d.ts +1 -1
  212. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  213. package/dist/formatting/NumberingLevel.js +8 -6
  214. package/dist/formatting/NumberingLevel.js.map +1 -1
  215. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  216. package/dist/formatting/NumberingManager.js +16 -1
  217. package/dist/formatting/NumberingManager.js.map +1 -1
  218. package/dist/formatting/Style.d.ts.map +1 -1
  219. package/dist/formatting/Style.js +14 -0
  220. package/dist/formatting/Style.js.map +1 -1
  221. package/dist/formatting/StylesManager.d.ts +2 -0
  222. package/dist/formatting/StylesManager.d.ts.map +1 -1
  223. package/dist/formatting/StylesManager.js +14 -2
  224. package/dist/formatting/StylesManager.js.map +1 -1
  225. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  226. package/dist/helpers/CleanupHelper.js +103 -26
  227. package/dist/helpers/CleanupHelper.js.map +1 -1
  228. package/dist/images/ImageOptimizer.d.ts.map +1 -1
  229. package/dist/images/ImageOptimizer.js +52 -4
  230. package/dist/images/ImageOptimizer.js.map +1 -1
  231. package/dist/index.d.ts +3 -1
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/index.js +4 -2
  234. package/dist/index.js.map +1 -1
  235. package/dist/internal.d.ts +1 -1
  236. package/dist/internal.d.ts.map +1 -1
  237. package/dist/internal.js +2 -1
  238. package/dist/internal.js.map +1 -1
  239. package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
  240. package/dist/processors/CompatibilityUpgrader.js +7 -1
  241. package/dist/processors/CompatibilityUpgrader.js.map +1 -1
  242. package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
  243. package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
  244. package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
  245. package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
  246. package/dist/processors/RevisionWalker.d.ts +9 -3
  247. package/dist/processors/RevisionWalker.d.ts.map +1 -1
  248. package/dist/processors/RevisionWalker.js +223 -39
  249. package/dist/processors/RevisionWalker.js.map +1 -1
  250. package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
  251. package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
  252. package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
  253. package/dist/processors/acceptRevisions.d.ts +1 -0
  254. package/dist/processors/acceptRevisions.d.ts.map +1 -1
  255. package/dist/processors/acceptRevisions.js +21 -11
  256. package/dist/processors/acceptRevisions.js.map +1 -1
  257. package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
  258. package/dist/processors/cnfStyleDecoder.js +7 -7
  259. package/dist/processors/cnfStyleDecoder.js.map +1 -1
  260. package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
  261. package/dist/processors/stripTrackedChanges.js +16 -5
  262. package/dist/processors/stripTrackedChanges.js.map +1 -1
  263. package/dist/utils/deepClone.d.ts.map +1 -1
  264. package/dist/utils/deepClone.js +24 -11
  265. package/dist/utils/deepClone.js.map +1 -1
  266. package/dist/utils/units.d.ts.map +1 -1
  267. package/dist/utils/units.js +1 -1
  268. package/dist/utils/units.js.map +1 -1
  269. package/dist/utils/validation.d.ts.map +1 -1
  270. package/dist/utils/validation.js +11 -23
  271. package/dist/utils/validation.js.map +1 -1
  272. package/dist/utils/xmlSanitization.d.ts +2 -0
  273. package/dist/utils/xmlSanitization.d.ts.map +1 -1
  274. package/dist/utils/xmlSanitization.js +133 -7
  275. package/dist/utils/xmlSanitization.js.map +1 -1
  276. package/dist/validation/RevisionAutoFixer.d.ts +6 -2
  277. package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
  278. package/dist/validation/RevisionAutoFixer.js +68 -54
  279. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  280. package/dist/validation/RevisionValidator.d.ts +2 -0
  281. package/dist/validation/RevisionValidator.d.ts.map +1 -1
  282. package/dist/validation/RevisionValidator.js +26 -21
  283. package/dist/validation/RevisionValidator.js.map +1 -1
  284. package/dist/xml/XMLBuilder.d.ts +1 -0
  285. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  286. package/dist/xml/XMLBuilder.js +52 -20
  287. package/dist/xml/XMLBuilder.js.map +1 -1
  288. package/dist/xml/XMLParser.d.ts +1 -0
  289. package/dist/xml/XMLParser.d.ts.map +1 -1
  290. package/dist/xml/XMLParser.js +55 -13
  291. package/dist/xml/XMLParser.js.map +1 -1
  292. package/dist/zip/ZipHandler.d.ts.map +1 -1
  293. package/dist/zip/ZipHandler.js +37 -13
  294. package/dist/zip/ZipHandler.js.map +1 -1
  295. package/dist/zip/ZipReader.d.ts.map +1 -1
  296. package/dist/zip/ZipReader.js +52 -5
  297. package/dist/zip/ZipReader.js.map +1 -1
  298. package/dist/zip/errors.d.ts +3 -0
  299. package/dist/zip/errors.d.ts.map +1 -1
  300. package/dist/zip/errors.js +9 -1
  301. package/dist/zip/errors.js.map +1 -1
  302. package/dist/zip/types.d.ts +4 -0
  303. package/dist/zip/types.d.ts.map +1 -1
  304. package/dist/zip/types.js +4 -0
  305. package/dist/zip/types.js.map +1 -1
  306. package/package.json +2 -2
  307. package/src/core/Document.ts +1184 -242
  308. package/src/core/DocumentGenerator.ts +106 -26
  309. package/src/core/DocumentParser.ts +681 -114
  310. package/src/core/RelationshipManager.ts +446 -442
  311. package/src/elements/Comment.ts +123 -18
  312. package/src/elements/CommentManager.ts +121 -22
  313. package/src/elements/EndnoteManager.ts +4 -1
  314. package/src/elements/Field.ts +134 -43
  315. package/src/elements/FieldHelpers.ts +20 -4
  316. package/src/elements/Footer.ts +62 -67
  317. package/src/elements/FootnoteManager.ts +4 -1
  318. package/src/elements/Header.ts +62 -67
  319. package/src/elements/HeaderFooterManager.ts +56 -8
  320. package/src/elements/Hyperlink.ts +150 -55
  321. package/src/elements/Image.ts +51 -7
  322. package/src/elements/ImageManager.ts +24 -0
  323. package/src/elements/Paragraph.ts +161 -40
  324. package/src/elements/Revision.ts +446 -47
  325. package/src/elements/Run.ts +44 -6
  326. package/src/elements/Section.ts +25 -9
  327. package/src/elements/Shape.ts +52 -44
  328. package/src/elements/StructuredDocumentTag.ts +83 -8
  329. package/src/elements/Table.ts +151 -50
  330. package/src/elements/TableCell.ts +57 -17
  331. package/src/elements/TableOfContents.ts +10 -9
  332. package/src/elements/TableRow.ts +35 -3
  333. package/src/elements/TextBox.ts +58 -43
  334. package/src/formatting/AbstractNumbering.ts +4 -2
  335. package/src/formatting/NumberingLevel.ts +50 -12
  336. package/src/formatting/NumberingManager.ts +32 -3
  337. package/src/formatting/Style.ts +14 -0
  338. package/src/formatting/StylesManager.ts +29 -2
  339. package/src/helpers/CleanupHelper.ts +122 -30
  340. package/src/images/ImageOptimizer.ts +64 -5
  341. package/src/index.ts +7 -0
  342. package/src/internal.ts +1 -0
  343. package/src/processors/CompatibilityUpgrader.ts +15 -2
  344. package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
  345. package/src/processors/RevisionWalker.ts +390 -46
  346. package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
  347. package/src/processors/acceptRevisions.ts +67 -17
  348. package/src/processors/cnfStyleDecoder.ts +18 -12
  349. package/src/processors/stripTrackedChanges.ts +47 -10
  350. package/src/utils/deepClone.ts +48 -14
  351. package/src/utils/units.ts +3 -1
  352. package/src/utils/validation.ts +30 -32
  353. package/src/utils/xmlSanitization.ts +218 -22
  354. package/src/validation/RevisionAutoFixer.ts +109 -65
  355. package/src/validation/RevisionValidator.ts +48 -23
  356. package/src/xml/XMLBuilder.ts +82 -22
  357. package/src/xml/XMLParser.ts +87 -20
  358. package/src/zip/ZipHandler.ts +61 -21
  359. package/src/zip/ZipReader.ts +135 -13
  360. package/src/zip/errors.ts +15 -0
  361. package/src/zip/types.ts +44 -2
@@ -24,6 +24,8 @@ import {
24
24
  isImageRunContent,
25
25
  } from '../elements/RevisionContent.js';
26
26
  import { ComplexField } from '../elements/Field.js';
27
+ import { RangeMarker, RangeMarkerType } from '../elements/RangeMarker.js';
28
+ import { PreservedElement } from '../elements/PreservedElement.js';
27
29
  import { Table } from '../elements/Table.js';
28
30
  import { getGlobalLogger, createScopedLogger, ILogger } from '../utils/logger.js';
29
31
 
@@ -82,6 +84,34 @@ const PROPERTY_REVISION_TYPES: RevisionType[] = [
82
84
  'numberingChange',
83
85
  ];
84
86
 
87
+ /**
88
+ * Range-marker boundary types dropped when the matching accept option is set.
89
+ * These are paired boundaries for the move / ins / del revisions handled
90
+ * elsewhere in the loop; once the revision they delimit is accepted, the
91
+ * markers reference a change that no longer exists (ECMA-376 §17.13.5.21-28)
92
+ * and Word still reports the document as containing tracked changes. The
93
+ * raw-XML acceptor (acceptRevisions.ts) and stripRevisionsFromXml remove the
94
+ * same set; this keeps the in-memory paragraph path in parity.
95
+ */
96
+ const MOVE_RANGE_MARKER_TYPES = new Set<RangeMarkerType>([
97
+ 'moveFromRangeStart',
98
+ 'moveFromRangeEnd',
99
+ 'moveToRangeStart',
100
+ 'moveToRangeEnd',
101
+ 'customXmlMoveFromRangeStart',
102
+ 'customXmlMoveFromRangeEnd',
103
+ 'customXmlMoveToRangeStart',
104
+ 'customXmlMoveToRangeEnd',
105
+ ]);
106
+ const INS_RANGE_MARKER_TYPES = new Set<RangeMarkerType>([
107
+ 'customXmlInsRangeStart',
108
+ 'customXmlInsRangeEnd',
109
+ ]);
110
+ const DEL_RANGE_MARKER_TYPES = new Set<RangeMarkerType>([
111
+ 'customXmlDelRangeStart',
112
+ 'customXmlDelRangeEnd',
113
+ ]);
114
+
85
115
  /**
86
116
  * Strip revision markup from raw XML string.
87
117
  * Used for nested tables stored as raw XML that cannot be processed via the in-memory model.
@@ -132,21 +162,27 @@ export function stripRevisionsFromXml(xml: string): string {
132
162
  }
133
163
 
134
164
  // Step 3: Remove deletions entirely (including content)
165
+ // Self-closing markers (paragraph-mark deletions in w:pPr/w:rPr per
166
+ // ECMA-376 §17.13.5.15) must be stripped BEFORE the block pattern runs:
167
+ // its [^>]* also matches the trailing '/' of `<w:del .../>`, which would
168
+ // turn the marker into an opening tag and swallow everything up to the
169
+ // next </w:del>, leaving unbalanced XML.
170
+ result = result.replace(/<w:del\b[^>]*\/>/g, '');
135
171
  // Iterate until no more deletions (handles nested cases)
136
172
  let prevLen = 0;
137
173
  while (result.length !== prevLen) {
138
174
  prevLen = result.length;
139
175
  result = result.replace(/<w:del\b[^>]*>[\s\S]*?<\/w:del>/g, '');
140
176
  }
141
- result = result.replace(/<w:del\b[^>]*\/>/g, '');
142
177
 
143
178
  // Step 4: Remove moveFrom entirely (source of moved content)
179
+ // Same self-closing-first ordering as Step 3.
180
+ result = result.replace(/<w:moveFrom\b[^>]*\/>/g, '');
144
181
  prevLen = 0;
145
182
  while (result.length !== prevLen) {
146
183
  prevLen = result.length;
147
184
  result = result.replace(/<w:moveFrom\b[^>]*>[\s\S]*?<\/w:moveFrom>/g, '');
148
185
  }
149
- result = result.replace(/<w:moveFrom\b[^>]*\/>/g, '');
150
186
 
151
187
  // Step 5: Unwrap moveTo (keep content, remove wrapper)
152
188
  result = result.replace(/<\/w:moveTo>/g, '');
@@ -200,6 +236,11 @@ export function acceptRevisionsInMemory(
200
236
 
201
237
  logger.info('Accepting revisions in-memory', { options: opts });
202
238
 
239
+ // Paragraphs whose tracked paragraph-mark deletion (w:del in w:pPr/w:rPr)
240
+ // is accepted — they must be merged into their following sibling after the
241
+ // walk completes (ECMA-376 §17.13.5.15).
242
+ const acceptedMarkDeletions: Paragraph[] = [];
243
+
203
244
  // Validate move pairs before accepting if moves are being accepted
204
245
  // Orphaned moves could result in content loss (moveFrom without moveTo = content deleted)
205
246
  if (opts.acceptMoves) {
@@ -228,7 +269,7 @@ export function acceptRevisionsInMemory(
228
269
  // Process all paragraphs in the document body
229
270
  const paragraphs = doc.getAllParagraphs();
230
271
  for (const paragraph of paragraphs) {
231
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
272
+ const paragraphResult = acceptRevisionsInParagraph(paragraph, opts, acceptedMarkDeletions);
232
273
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
233
274
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
234
275
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -309,7 +350,11 @@ export function acceptRevisionsInMemory(
309
350
 
310
351
  // Process paragraphs in the cell
311
352
  for (const paragraph of cell.getParagraphs()) {
312
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
353
+ const paragraphResult = acceptRevisionsInParagraph(
354
+ paragraph,
355
+ opts,
356
+ acceptedMarkDeletions
357
+ );
313
358
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
314
359
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
315
360
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -352,7 +397,7 @@ export function acceptRevisionsInMemory(
352
397
  for (const element of elements) {
353
398
  // Element can be Paragraph or Table - use instanceof for type safety
354
399
  if (element instanceof Paragraph) {
355
- const paragraphResult = acceptRevisionsInParagraph(element, opts);
400
+ const paragraphResult = acceptRevisionsInParagraph(element, opts, acceptedMarkDeletions);
356
401
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
357
402
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
358
403
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -362,7 +407,11 @@ export function acceptRevisionsInMemory(
362
407
  for (const row of element.getRows()) {
363
408
  for (const cell of row.getCells()) {
364
409
  for (const paragraph of cell.getParagraphs()) {
365
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
410
+ const paragraphResult = acceptRevisionsInParagraph(
411
+ paragraph,
412
+ opts,
413
+ acceptedMarkDeletions
414
+ );
366
415
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
367
416
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
368
417
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -395,7 +444,7 @@ export function acceptRevisionsInMemory(
395
444
  for (const element of elements) {
396
445
  // Element can be Paragraph or Table - use instanceof for type safety
397
446
  if (element instanceof Paragraph) {
398
- const paragraphResult = acceptRevisionsInParagraph(element, opts);
447
+ const paragraphResult = acceptRevisionsInParagraph(element, opts, acceptedMarkDeletions);
399
448
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
400
449
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
401
450
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -405,7 +454,11 @@ export function acceptRevisionsInMemory(
405
454
  for (const row of element.getRows()) {
406
455
  for (const cell of row.getCells()) {
407
456
  for (const paragraph of cell.getParagraphs()) {
408
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
457
+ const paragraphResult = acceptRevisionsInParagraph(
458
+ paragraph,
459
+ opts,
460
+ acceptedMarkDeletions
461
+ );
409
462
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
410
463
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
411
464
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -445,7 +498,7 @@ export function acceptRevisionsInMemory(
445
498
  if (footnoteManager) {
446
499
  for (const fn of footnoteManager.getAllFootnotes()) {
447
500
  for (const paragraph of fn.getParagraphs()) {
448
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
501
+ const paragraphResult = acceptRevisionsInParagraph(paragraph, opts, acceptedMarkDeletions);
449
502
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
450
503
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
451
504
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -457,7 +510,7 @@ export function acceptRevisionsInMemory(
457
510
  if (endnoteManager) {
458
511
  for (const en of endnoteManager.getAllEndnotes()) {
459
512
  for (const paragraph of en.getParagraphs()) {
460
- const paragraphResult = acceptRevisionsInParagraph(paragraph, opts);
513
+ const paragraphResult = acceptRevisionsInParagraph(paragraph, opts, acceptedMarkDeletions);
461
514
  result.insertionsAccepted += paragraphResult.insertionsAccepted;
462
515
  result.deletionsAccepted += paragraphResult.deletionsAccepted;
463
516
  result.movesAccepted += paragraphResult.movesAccepted;
@@ -484,6 +537,13 @@ export function acceptRevisionsInMemory(
484
537
  // Disable track changes setting
485
538
  doc.disableTrackChanges();
486
539
 
540
+ // Combine paragraphs whose paragraph-mark deletion was accepted with their
541
+ // following sibling (ECMA-376 §17.13.5.15). Runs after tracking is disabled
542
+ // so the removals are plain splices rather than new tracked deletions.
543
+ if (acceptedMarkDeletions.length > 0) {
544
+ mergeParagraphsWithDeletedMarks(doc, new Set(acceptedMarkDeletions));
545
+ }
546
+
487
547
  // Cleanup empty tables if enabled
488
548
  // This removes tables that have no visible content after revision acceptance
489
549
  // (e.g., tables where all content was deleted via tracked changes)
@@ -525,7 +585,8 @@ export function acceptRevisionsInMemory(
525
585
  */
526
586
  function acceptRevisionsInParagraph(
527
587
  paragraph: Paragraph,
528
- options: Required<AcceptRevisionsOptions>
588
+ options: Required<AcceptRevisionsOptions>,
589
+ acceptedMarkDeletions?: Paragraph[]
529
590
  ): AcceptRevisionsResult {
530
591
  const result: AcceptRevisionsResult = {
531
592
  insertionsAccepted: 0,
@@ -645,6 +706,20 @@ function acceptRevisionsInParagraph(
645
706
  }
646
707
  }
647
708
  newContent.push(item);
709
+ } else if (item instanceof RangeMarker) {
710
+ // Boundary markers for a move / ins / del span. Drop them when the
711
+ // revision they delimit is being accepted so no orphaned range markers
712
+ // remain (the move/ins/del revisions themselves are counted above; the
713
+ // markers carry no content, so they are not counted again).
714
+ const markerType = item.getType();
715
+ if (
716
+ (options.acceptMoves && MOVE_RANGE_MARKER_TYPES.has(markerType)) ||
717
+ (options.acceptInsertions && INS_RANGE_MARKER_TYPES.has(markerType)) ||
718
+ (options.acceptDeletions && DEL_RANGE_MARKER_TYPES.has(markerType))
719
+ ) {
720
+ continue;
721
+ }
722
+ newContent.push(item);
648
723
  } else {
649
724
  // Non-revision content - keep as-is
650
725
  newContent.push(item);
@@ -672,12 +747,17 @@ function acceptRevisionsInParagraph(
672
747
  }
673
748
 
674
749
  // Clear paragraph mark deletion tracking if accepting deletions
675
- // This removes the w:del element from w:pPr/w:rPr
750
+ // This removes the w:del element from w:pPr/w:rPr. The paragraph is also
751
+ // recorded for the post-walk merge pass: per ECMA-376 §17.13.5.15 a deleted
752
+ // paragraph mark means this paragraph's contents combine with the FOLLOWING
753
+ // paragraph, so clearing the marker alone would leave a leftover paragraph
754
+ // Word's own Accept All removes.
676
755
  if (options.acceptDeletions) {
677
756
  const formatting = paragraph.getFormatting();
678
757
  if (formatting.paragraphMarkDeletion) {
679
758
  paragraph.clearParagraphMarkDeletion();
680
759
  result.deletionsAccepted++;
760
+ acceptedMarkDeletions?.push(paragraph);
681
761
  }
682
762
  }
683
763
 
@@ -694,6 +774,111 @@ function acceptRevisionsInParagraph(
694
774
  return result;
695
775
  }
696
776
 
777
+ /**
778
+ * Merge paragraphs whose tracked paragraph-mark deletion was accepted into
779
+ * their immediately following sibling paragraph.
780
+ *
781
+ * Per ECMA-376 §17.13.5.15, a w:del inside w:pPr/w:rPr marks the paragraph
782
+ * mark (¶) itself as deleted: accepting it means the paragraph's contents are
783
+ * no longer delimited by that mark and combine with the FOLLOWING paragraph.
784
+ * Clearing the marker alone leaves a leftover paragraph (blank line) that
785
+ * Word's own Accept All removes.
786
+ *
787
+ * Merging only happens between siblings of the same container (document body
788
+ * or table cell). A paragraph with no following sibling paragraph — last in
789
+ * its container, or followed by a table/SDT/raw nested content — keeps its
790
+ * content in place, matching Word, which cannot delete a container's final
791
+ * paragraph mark.
792
+ */
793
+ export function mergeParagraphsWithDeletedMarks(doc: Document, marked: Set<Paragraph>): void {
794
+ if (marked.size === 0) {
795
+ return;
796
+ }
797
+
798
+ // Body-level siblings
799
+ mergeMarkedSequence(doc.getBodyElements(), marked, (para) => {
800
+ doc.removeElement(para);
801
+ });
802
+
803
+ // Table-cell siblings (same tables the acceptance walk visits)
804
+ for (const table of doc.getTables()) {
805
+ for (const row of table.getRows()) {
806
+ for (const cell of row.getCells()) {
807
+ // Raw nested content (nested tables/SDTs) at position p renders
808
+ // between paragraph p-1 and paragraph p, so it interrupts sibling
809
+ // adjacency the same way a body-level table does. Capture the
810
+ // boundaries before any removal: removeParagraph keeps positions in
811
+ // sync with live indices, which match this snapshot only up front.
812
+ const blockedBoundaries = new Set(cell.getRawNestedContent().map((item) => item.position));
813
+ mergeMarkedSequence(
814
+ cell.getParagraphs(),
815
+ marked,
816
+ (para) => {
817
+ const index = cell.getParagraphs().indexOf(para);
818
+ if (index !== -1) {
819
+ cell.removeParagraph(index);
820
+ }
821
+ },
822
+ (index) => blockedBoundaries.has(index)
823
+ );
824
+ }
825
+ }
826
+ }
827
+ }
828
+
829
+ /**
830
+ * Walk one sibling sequence (body elements or cell paragraphs) and fold each
831
+ * run of marked paragraphs into the first unmarked paragraph that follows it.
832
+ * Consecutive marked paragraphs chain: their contents concatenate, in
833
+ * document order, ahead of the surviving paragraph's own content. The
834
+ * surviving paragraph keeps its own pPr — the deleted marks took their
835
+ * properties with them.
836
+ */
837
+ function mergeMarkedSequence(
838
+ sequence: readonly unknown[],
839
+ marked: Set<Paragraph>,
840
+ removeParagraph: (paragraph: Paragraph) => void,
841
+ blockedBefore?: (index: number) => boolean
842
+ ): void {
843
+ let chain: Paragraph[] = [];
844
+
845
+ for (let i = 0; i < sequence.length; i++) {
846
+ const element = sequence[i];
847
+
848
+ if (!(element instanceof Paragraph)) {
849
+ // A non-paragraph block (table, SDT, TOC) is not a valid merge target
850
+ chain = [];
851
+ continue;
852
+ }
853
+
854
+ if (blockedBefore?.(i)) {
855
+ chain = [];
856
+ }
857
+
858
+ if (marked.has(element)) {
859
+ chain.push(element);
860
+ continue;
861
+ }
862
+
863
+ if (chain.length > 0) {
864
+ const inherited: ParagraphContent[] = [];
865
+ for (const para of chain) {
866
+ inherited.push(...para.getContent());
867
+ }
868
+ element.setContent([...inherited, ...element.getContent()]);
869
+ for (const para of chain) {
870
+ // Empty before removal so a tracking-bound removal path can never
871
+ // duplicate content that now lives in the surviving paragraph
872
+ para.setContent([]);
873
+ removeParagraph(para);
874
+ }
875
+ chain = [];
876
+ }
877
+ }
878
+ // A trailing chain has no following sibling: the final paragraph mark of a
879
+ // container cannot be deleted, so those paragraphs stay as-is.
880
+ }
881
+
697
882
  /**
698
883
  * Check if a paragraph has any revisions
699
884
  */
@@ -736,12 +921,80 @@ export function countRevisionsByType(doc: Document): Map<RevisionType, number> {
736
921
  return counts;
737
922
  }
738
923
 
924
+ /**
925
+ * Inline preserved-element types that are pure range/proofing markers.
926
+ * They carry no displayable content, so a table whose cells hold only these
927
+ * (e.g. leftover proofErr markers after all text was deleted via tracked
928
+ * changes) must still be eligible for cleanup.
929
+ */
930
+ const MARKER_PRESERVED_ELEMENT_TYPES = new Set([
931
+ 'w:proofErr',
932
+ 'w:permStart',
933
+ 'w:permEnd',
934
+ 'w:commentRangeStart',
935
+ 'w:commentRangeEnd',
936
+ ]);
937
+
938
+ /**
939
+ * Check whether a paragraph carries visible content for empty-table cleanup.
940
+ *
941
+ * Paragraph.getText() only surfaces Run/Hyperlink text, so images, shapes,
942
+ * text boxes, fields, pending revisions, and preserved raw XML (loaded-doc
943
+ * hyperlinks, inline SDTs, math) would read as "empty" and the table holding
944
+ * them would be silently deleted. Mirrors TableCell.isParaBlank's duck-typed
945
+ * element detection.
946
+ */
947
+ function paragraphHasVisibleContent(para: Paragraph): boolean {
948
+ if (para.getText().trim().length > 0) {
949
+ return true;
950
+ }
951
+
952
+ for (const item of para.getContent()) {
953
+ if (!item) continue;
954
+
955
+ // Revisions left behind by selective acceptance still render their
956
+ // content (e.g. strikethrough deletions) — removing the table would
957
+ // discard tracked changes the caller chose to keep.
958
+ if (item instanceof Revision) {
959
+ return true;
960
+ }
961
+
962
+ // Marker-only preserved elements are not content; everything else
963
+ // preserved as raw XML (w:r, w:hyperlink, m:oMath, w:ruby, nested
964
+ // revision wrappers) is.
965
+ if (item instanceof PreservedElement) {
966
+ if (!MARKER_PRESERVED_ELEMENT_TYPES.has(item.getElementType())) {
967
+ return true;
968
+ }
969
+ continue;
970
+ }
971
+
972
+ // Duck-typed checks matching TableCell.isParaBlank: ImageRun
973
+ // (getImageElement), Shape (getShapeType), TextBox (getTextContent),
974
+ // Hyperlink (getUrl), Field/ComplexField (getInstruction).
975
+ const candidate = item as unknown as Record<string, unknown>;
976
+ if (
977
+ typeof candidate.getImageElement === 'function' ||
978
+ typeof candidate.getShapeType === 'function' ||
979
+ typeof candidate.getTextContent === 'function' ||
980
+ typeof candidate.getUrl === 'function' ||
981
+ typeof candidate.getInstruction === 'function'
982
+ ) {
983
+ return true;
984
+ }
985
+ }
986
+
987
+ return false;
988
+ }
989
+
739
990
  /**
740
991
  * Remove tables that have no visible content after revision acceptance.
741
992
  *
742
- * A table is considered empty if ALL cells in ALL rows have no text content.
743
- * This handles cases where all table content was deleted via tracked changes -
744
- * the deletion markers are stripped but the empty table structure remains.
993
+ * A table is considered empty only if ALL cells in ALL rows have no visible
994
+ * content: no text, images, shapes, text boxes, fields, hyperlinks, preserved
995
+ * raw XML, or raw nested content (nested tables/SDTs). This handles cases
996
+ * where all table content was deleted via tracked changes - the deletion
997
+ * markers are stripped but the empty table structure remains.
745
998
  *
746
999
  * @param doc - Document to clean up
747
1000
  * @param logger - Logger instance for debug output
@@ -762,10 +1015,16 @@ function cleanupEmptyTables(doc: Document, logger: ILogger): number {
762
1015
  for (const row of rows) {
763
1016
  const cells = row.getCells();
764
1017
  for (const cell of cells) {
1018
+ // Nested tables/SDTs live in raw XML passthrough, never in
1019
+ // paragraphs — a cell whose real content is a nested table would
1020
+ // otherwise read as empty and be deleted.
1021
+ if (cell.hasRawNestedContent()) {
1022
+ hasContent = true;
1023
+ break;
1024
+ }
765
1025
  const paragraphs = cell.getParagraphs();
766
1026
  for (const para of paragraphs) {
767
- const text = para.getText().trim();
768
- if (text.length > 0) {
1027
+ if (paragraphHasVisibleContent(para)) {
769
1028
  hasContent = true;
770
1029
  break;
771
1030
  }