docxmlater 10.1.3 → 10.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/README.md +759 -754
  2. package/dist/constants/legacyCompatFlags.js +1 -1
  3. package/dist/constants/legacyCompatFlags.js.map +1 -1
  4. package/dist/constants/limits.js.map +1 -1
  5. package/dist/core/Document.d.ts +50 -50
  6. package/dist/core/Document.d.ts.map +1 -1
  7. package/dist/core/Document.js +483 -471
  8. package/dist/core/Document.js.map +1 -1
  9. package/dist/core/DocumentContent.d.ts +9 -9
  10. package/dist/core/DocumentContent.d.ts.map +1 -1
  11. package/dist/core/DocumentContent.js +1 -1
  12. package/dist/core/DocumentContent.js.map +1 -1
  13. package/dist/core/DocumentGenerator.d.ts +11 -11
  14. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  15. package/dist/core/DocumentGenerator.js +251 -251
  16. package/dist/core/DocumentGenerator.js.map +1 -1
  17. package/dist/core/DocumentIdManager.js.map +1 -1
  18. package/dist/core/DocumentParser.d.ts +15 -15
  19. package/dist/core/DocumentParser.d.ts.map +1 -1
  20. package/dist/core/DocumentParser.js +2123 -2155
  21. package/dist/core/DocumentParser.js.map +1 -1
  22. package/dist/core/DocumentValidator.d.ts.map +1 -1
  23. package/dist/core/DocumentValidator.js +2 -5
  24. package/dist/core/DocumentValidator.js.map +1 -1
  25. package/dist/core/Relationship.js.map +1 -1
  26. package/dist/core/RelationshipManager.d.ts.map +1 -1
  27. package/dist/core/RelationshipManager.js +3 -3
  28. package/dist/core/RelationshipManager.js.map +1 -1
  29. package/dist/elements/AlternateContent.js.map +1 -1
  30. package/dist/elements/Bookmark.d.ts.map +1 -1
  31. package/dist/elements/Bookmark.js +3 -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.d.ts.map +1 -1
  36. package/dist/elements/Comment.js +9 -6
  37. package/dist/elements/Comment.js.map +1 -1
  38. package/dist/elements/CommentManager.d.ts.map +1 -1
  39. package/dist/elements/CommentManager.js +18 -17
  40. package/dist/elements/CommentManager.js.map +1 -1
  41. package/dist/elements/CommonTypes.d.ts +21 -21
  42. package/dist/elements/CommonTypes.d.ts.map +1 -1
  43. package/dist/elements/CommonTypes.js +56 -56
  44. package/dist/elements/CommonTypes.js.map +1 -1
  45. package/dist/elements/CustomXml.js.map +1 -1
  46. package/dist/elements/Endnote.d.ts.map +1 -1
  47. package/dist/elements/Endnote.js +6 -6
  48. package/dist/elements/Endnote.js.map +1 -1
  49. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  50. package/dist/elements/EndnoteManager.js +6 -7
  51. package/dist/elements/EndnoteManager.js.map +1 -1
  52. package/dist/elements/Field.d.ts.map +1 -1
  53. package/dist/elements/Field.js +82 -25
  54. package/dist/elements/Field.js.map +1 -1
  55. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  56. package/dist/elements/FieldHelpers.js.map +1 -1
  57. package/dist/elements/FontManager.d.ts.map +1 -1
  58. package/dist/elements/FontManager.js +1 -1
  59. package/dist/elements/FontManager.js.map +1 -1
  60. package/dist/elements/Footer.js +2 -2
  61. package/dist/elements/Footer.js.map +1 -1
  62. package/dist/elements/Footnote.d.ts.map +1 -1
  63. package/dist/elements/Footnote.js +6 -6
  64. package/dist/elements/Footnote.js.map +1 -1
  65. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  66. package/dist/elements/FootnoteManager.js +6 -7
  67. package/dist/elements/FootnoteManager.js.map +1 -1
  68. package/dist/elements/Header.js +2 -2
  69. package/dist/elements/Header.js.map +1 -1
  70. package/dist/elements/HeaderFooterManager.js.map +1 -1
  71. package/dist/elements/Hyperlink.d.ts +5 -3
  72. package/dist/elements/Hyperlink.d.ts.map +1 -1
  73. package/dist/elements/Hyperlink.js +134 -76
  74. package/dist/elements/Hyperlink.js.map +1 -1
  75. package/dist/elements/Image.d.ts.map +1 -1
  76. package/dist/elements/Image.js +238 -106
  77. package/dist/elements/Image.js.map +1 -1
  78. package/dist/elements/ImageManager.d.ts.map +1 -1
  79. package/dist/elements/ImageManager.js +1 -1
  80. package/dist/elements/ImageManager.js.map +1 -1
  81. package/dist/elements/ImageRun.js +1 -1
  82. package/dist/elements/ImageRun.js.map +1 -1
  83. package/dist/elements/MathElement.js.map +1 -1
  84. package/dist/elements/Paragraph.d.ts +24 -24
  85. package/dist/elements/Paragraph.d.ts.map +1 -1
  86. package/dist/elements/Paragraph.js +181 -188
  87. package/dist/elements/Paragraph.js.map +1 -1
  88. package/dist/elements/PreservedElement.js.map +1 -1
  89. package/dist/elements/PropertyChangeTypes.d.ts.map +1 -1
  90. package/dist/elements/PropertyChangeTypes.js +6 -6
  91. package/dist/elements/PropertyChangeTypes.js.map +1 -1
  92. package/dist/elements/RangeMarker.d.ts.map +1 -1
  93. package/dist/elements/RangeMarker.js.map +1 -1
  94. package/dist/elements/Revision.d.ts.map +1 -1
  95. package/dist/elements/Revision.js +4 -5
  96. package/dist/elements/Revision.js.map +1 -1
  97. package/dist/elements/RevisionContent.js.map +1 -1
  98. package/dist/elements/RevisionManager.d.ts.map +1 -1
  99. package/dist/elements/RevisionManager.js +40 -48
  100. package/dist/elements/RevisionManager.js.map +1 -1
  101. package/dist/elements/Run.d.ts +16 -16
  102. package/dist/elements/Run.d.ts.map +1 -1
  103. package/dist/elements/Run.js +256 -238
  104. package/dist/elements/Run.js.map +1 -1
  105. package/dist/elements/Section.d.ts.map +1 -1
  106. package/dist/elements/Section.js +36 -11
  107. package/dist/elements/Section.js.map +1 -1
  108. package/dist/elements/Shape.d.ts.map +1 -1
  109. package/dist/elements/Shape.js.map +1 -1
  110. package/dist/elements/StructuredDocumentTag.d.ts +6 -6
  111. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  112. package/dist/elements/StructuredDocumentTag.js +99 -104
  113. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  114. package/dist/elements/Table.d.ts +11 -11
  115. package/dist/elements/Table.d.ts.map +1 -1
  116. package/dist/elements/Table.js +102 -107
  117. package/dist/elements/Table.js.map +1 -1
  118. package/dist/elements/TableCell.d.ts +10 -10
  119. package/dist/elements/TableCell.d.ts.map +1 -1
  120. package/dist/elements/TableCell.js +105 -106
  121. package/dist/elements/TableCell.js.map +1 -1
  122. package/dist/elements/TableGridChange.d.ts.map +1 -1
  123. package/dist/elements/TableGridChange.js.map +1 -1
  124. package/dist/elements/TableOfContents.d.ts.map +1 -1
  125. package/dist/elements/TableOfContents.js +4 -4
  126. package/dist/elements/TableOfContents.js.map +1 -1
  127. package/dist/elements/TableOfContentsElement.js.map +1 -1
  128. package/dist/elements/TableRow.d.ts.map +1 -1
  129. package/dist/elements/TableRow.js +13 -6
  130. package/dist/elements/TableRow.js.map +1 -1
  131. package/dist/elements/TextBox.d.ts.map +1 -1
  132. package/dist/elements/TextBox.js +3 -5
  133. package/dist/elements/TextBox.js.map +1 -1
  134. package/dist/formatting/AbstractNumbering.d.ts +4 -4
  135. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  136. package/dist/formatting/AbstractNumbering.js +54 -49
  137. package/dist/formatting/AbstractNumbering.js.map +1 -1
  138. package/dist/formatting/NumberingInstance.d.ts.map +1 -1
  139. package/dist/formatting/NumberingInstance.js +1 -3
  140. package/dist/formatting/NumberingInstance.js.map +1 -1
  141. package/dist/formatting/NumberingLevel.d.ts +5 -5
  142. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  143. package/dist/formatting/NumberingLevel.js +119 -125
  144. package/dist/formatting/NumberingLevel.js.map +1 -1
  145. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  146. package/dist/formatting/NumberingManager.js +9 -9
  147. package/dist/formatting/NumberingManager.js.map +1 -1
  148. package/dist/formatting/Style.d.ts +11 -11
  149. package/dist/formatting/Style.d.ts.map +1 -1
  150. package/dist/formatting/Style.js +219 -247
  151. package/dist/formatting/Style.js.map +1 -1
  152. package/dist/formatting/StylesManager.d.ts +2 -2
  153. package/dist/formatting/StylesManager.d.ts.map +1 -1
  154. package/dist/formatting/StylesManager.js +96 -102
  155. package/dist/formatting/StylesManager.js.map +1 -1
  156. package/dist/helpers/CleanupHelper.d.ts +1 -1
  157. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  158. package/dist/helpers/CleanupHelper.js +6 -6
  159. package/dist/helpers/CleanupHelper.js.map +1 -1
  160. package/dist/images/ImageOptimizer.js +7 -7
  161. package/dist/images/ImageOptimizer.js.map +1 -1
  162. package/dist/index.d.ts +9 -9
  163. package/dist/index.d.ts.map +1 -1
  164. package/dist/index.js.map +1 -1
  165. package/dist/managers/DrawingManager.js.map +1 -1
  166. package/dist/tracking/DocumentTrackingContext.d.ts.map +1 -1
  167. package/dist/tracking/DocumentTrackingContext.js +23 -7
  168. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  169. package/dist/tracking/TrackingContext.d.ts.map +1 -1
  170. package/dist/tracking/TrackingContext.js.map +1 -1
  171. package/dist/types/compatibility-types.js.map +1 -1
  172. package/dist/types/formatting.js.map +1 -1
  173. package/dist/types/list-types.d.ts +6 -6
  174. package/dist/types/list-types.js.map +1 -1
  175. package/dist/types/settings-types.js.map +1 -1
  176. package/dist/types/styleConfig.d.ts +2 -2
  177. package/dist/types/styleConfig.js.map +1 -1
  178. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  179. package/dist/utils/ChangelogGenerator.js +97 -101
  180. package/dist/utils/ChangelogGenerator.js.map +1 -1
  181. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  182. package/dist/utils/CompatibilityUpgrader.js +1 -1
  183. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  184. package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
  185. package/dist/utils/InMemoryRevisionAcceptor.js +1 -6
  186. package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
  187. package/dist/utils/MoveOperationHelper.d.ts.map +1 -1
  188. package/dist/utils/MoveOperationHelper.js +1 -1
  189. package/dist/utils/MoveOperationHelper.js.map +1 -1
  190. package/dist/utils/RevisionAwareProcessor.d.ts.map +1 -1
  191. package/dist/utils/RevisionAwareProcessor.js +2 -4
  192. package/dist/utils/RevisionAwareProcessor.js.map +1 -1
  193. package/dist/utils/RevisionWalker.d.ts.map +1 -1
  194. package/dist/utils/RevisionWalker.js +4 -12
  195. package/dist/utils/RevisionWalker.js.map +1 -1
  196. package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
  197. package/dist/utils/SelectiveRevisionAcceptor.js +2 -6
  198. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  199. package/dist/utils/ShadingResolver.d.ts.map +1 -1
  200. package/dist/utils/ShadingResolver.js +1 -1
  201. package/dist/utils/ShadingResolver.js.map +1 -1
  202. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  203. package/dist/utils/acceptRevisions.js +23 -12
  204. package/dist/utils/acceptRevisions.js.map +1 -1
  205. package/dist/utils/cnfStyleDecoder.d.ts +1 -1
  206. package/dist/utils/cnfStyleDecoder.d.ts.map +1 -1
  207. package/dist/utils/cnfStyleDecoder.js +40 -40
  208. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  209. package/dist/utils/corruptionDetection.d.ts.map +1 -1
  210. package/dist/utils/corruptionDetection.js.map +1 -1
  211. package/dist/utils/dateFormatting.js.map +1 -1
  212. package/dist/utils/deepClone.js +1 -1
  213. package/dist/utils/deepClone.js.map +1 -1
  214. package/dist/utils/diagnostics.d.ts.map +1 -1
  215. package/dist/utils/diagnostics.js +1 -1
  216. package/dist/utils/diagnostics.js.map +1 -1
  217. package/dist/utils/errorHandling.js.map +1 -1
  218. package/dist/utils/formatting.d.ts.map +1 -1
  219. package/dist/utils/formatting.js +10 -2
  220. package/dist/utils/formatting.js.map +1 -1
  221. package/dist/utils/list-detection.d.ts +2 -2
  222. package/dist/utils/list-detection.d.ts.map +1 -1
  223. package/dist/utils/list-detection.js +21 -23
  224. package/dist/utils/list-detection.js.map +1 -1
  225. package/dist/utils/logger.d.ts.map +1 -1
  226. package/dist/utils/logger.js +12 -7
  227. package/dist/utils/logger.js.map +1 -1
  228. package/dist/utils/parsingHelpers.js.map +1 -1
  229. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  230. package/dist/utils/stripTrackedChanges.js +3 -3
  231. package/dist/utils/stripTrackedChanges.js.map +1 -1
  232. package/dist/utils/textDiff.d.ts +1 -1
  233. package/dist/utils/textDiff.js +8 -8
  234. package/dist/utils/textDiff.js.map +1 -1
  235. package/dist/utils/units.js.map +1 -1
  236. package/dist/utils/validation.d.ts.map +1 -1
  237. package/dist/utils/validation.js +24 -7
  238. package/dist/utils/validation.js.map +1 -1
  239. package/dist/utils/xmlSanitization.d.ts.map +1 -1
  240. package/dist/utils/xmlSanitization.js +3 -3
  241. package/dist/utils/xmlSanitization.js.map +1 -1
  242. package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
  243. package/dist/validation/RevisionAutoFixer.js +5 -5
  244. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  245. package/dist/validation/RevisionValidator.d.ts.map +1 -1
  246. package/dist/validation/RevisionValidator.js +7 -9
  247. package/dist/validation/RevisionValidator.js.map +1 -1
  248. package/dist/validation/ValidationRules.js +3 -3
  249. package/dist/validation/ValidationRules.js.map +1 -1
  250. package/dist/validation/index.js.map +1 -1
  251. package/dist/xml/XMLBuilder.d.ts +1 -1
  252. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  253. package/dist/xml/XMLBuilder.js +98 -100
  254. package/dist/xml/XMLBuilder.js.map +1 -1
  255. package/dist/xml/XMLParser.d.ts.map +1 -1
  256. package/dist/xml/XMLParser.js +61 -66
  257. package/dist/xml/XMLParser.js.map +1 -1
  258. package/dist/zip/ZipHandler.d.ts.map +1 -1
  259. package/dist/zip/ZipHandler.js.map +1 -1
  260. package/dist/zip/ZipReader.d.ts.map +1 -1
  261. package/dist/zip/ZipReader.js +1 -3
  262. package/dist/zip/ZipReader.js.map +1 -1
  263. package/dist/zip/ZipWriter.d.ts +1 -1
  264. package/dist/zip/ZipWriter.d.ts.map +1 -1
  265. package/dist/zip/ZipWriter.js +28 -36
  266. package/dist/zip/ZipWriter.js.map +1 -1
  267. package/dist/zip/types.js +1 -1
  268. package/dist/zip/types.js.map +1 -1
  269. package/package.json +92 -92
  270. package/src/__tests__/helper-methods.test.ts +512 -512
  271. package/src/constants/legacyCompatFlags.ts +138 -138
  272. package/src/constants/limits.ts +50 -50
  273. package/src/core/Document.ts +985 -1145
  274. package/src/core/DocumentContent.ts +461 -467
  275. package/src/core/DocumentGenerator.ts +1133 -1104
  276. package/src/core/DocumentIdManager.ts +158 -158
  277. package/src/core/DocumentParser.ts +2347 -2716
  278. package/src/core/DocumentValidator.ts +363 -372
  279. package/src/core/Relationship.ts +367 -367
  280. package/src/core/RelationshipManager.ts +429 -428
  281. package/src/elements/AlternateContent.ts +42 -42
  282. package/src/elements/Bookmark.ts +212 -210
  283. package/src/elements/BookmarkManager.ts +247 -250
  284. package/src/elements/Comment.ts +356 -359
  285. package/src/elements/CommentManager.ts +499 -502
  286. package/src/elements/CommonTypes.ts +524 -549
  287. package/src/elements/CustomXml.ts +36 -36
  288. package/src/elements/Endnote.ts +221 -217
  289. package/src/elements/EndnoteManager.ts +246 -249
  290. package/src/elements/Field.ts +1292 -1233
  291. package/src/elements/FieldHelpers.ts +329 -333
  292. package/src/elements/FontManager.ts +336 -339
  293. package/src/elements/Footer.ts +269 -269
  294. package/src/elements/Footnote.ts +221 -217
  295. package/src/elements/FootnoteManager.ts +246 -249
  296. package/src/elements/Header.ts +269 -269
  297. package/src/elements/HeaderFooterManager.ts +219 -219
  298. package/src/elements/Hyperlink.ts +1288 -1193
  299. package/src/elements/Image.ts +1982 -1756
  300. package/src/elements/ImageManager.ts +437 -432
  301. package/src/elements/ImageRun.ts +59 -59
  302. package/src/elements/MathElement.ts +65 -65
  303. package/src/elements/Paragraph.ts +4347 -4287
  304. package/src/elements/PreservedElement.ts +53 -53
  305. package/src/elements/PropertyChangeTypes.ts +458 -442
  306. package/src/elements/RangeMarker.ts +382 -400
  307. package/src/elements/Revision.ts +1198 -1217
  308. package/src/elements/RevisionContent.ts +73 -73
  309. package/src/elements/RevisionManager.ts +1070 -1070
  310. package/src/elements/Run.ts +3103 -3073
  311. package/src/elements/Section.ts +1521 -1421
  312. package/src/elements/Shape.ts +884 -873
  313. package/src/elements/StructuredDocumentTag.ts +1176 -1207
  314. package/src/elements/Table.ts +2468 -2524
  315. package/src/elements/TableCell.ts +1617 -1621
  316. package/src/elements/TableGridChange.ts +149 -151
  317. package/src/elements/TableOfContents.ts +701 -691
  318. package/src/elements/TableOfContentsElement.ts +89 -89
  319. package/src/elements/TableRow.ts +960 -929
  320. package/src/elements/TextBox.ts +766 -768
  321. package/src/formatting/AbstractNumbering.ts +580 -579
  322. package/src/formatting/NumberingInstance.ts +295 -299
  323. package/src/formatting/NumberingLevel.ts +981 -1040
  324. package/src/formatting/NumberingManager.ts +833 -827
  325. package/src/formatting/Style.ts +1785 -1879
  326. package/src/formatting/StylesManager.ts +1090 -1130
  327. package/src/helpers/CleanupHelper.ts +524 -524
  328. package/src/images/ImageOptimizer.ts +274 -274
  329. package/src/index.ts +559 -554
  330. package/src/managers/DrawingManager.ts +319 -319
  331. package/src/tracking/DocumentTrackingContext.ts +687 -674
  332. package/src/tracking/TrackingContext.ts +175 -173
  333. package/src/types/compatibility-types.ts +49 -49
  334. package/src/types/formatting.ts +210 -210
  335. package/src/types/list-types.ts +14 -14
  336. package/src/types/settings-types.ts +59 -59
  337. package/src/types/styleConfig.ts +189 -189
  338. package/src/utils/ChangelogGenerator.ts +1583 -1581
  339. package/src/utils/CompatibilityUpgrader.ts +235 -237
  340. package/src/utils/InMemoryRevisionAcceptor.ts +691 -696
  341. package/src/utils/MoveOperationHelper.ts +233 -238
  342. package/src/utils/RevisionAwareProcessor.ts +518 -526
  343. package/src/utils/RevisionWalker.ts +427 -457
  344. package/src/utils/SelectiveRevisionAcceptor.ts +662 -683
  345. package/src/utils/ShadingResolver.ts +105 -107
  346. package/src/utils/acceptRevisions.ts +723 -714
  347. package/src/utils/cnfStyleDecoder.ts +212 -217
  348. package/src/utils/corruptionDetection.ts +346 -345
  349. package/src/utils/dateFormatting.ts +20 -20
  350. package/src/utils/deepClone.ts +77 -78
  351. package/src/utils/diagnostics.ts +125 -129
  352. package/src/utils/errorHandling.ts +80 -80
  353. package/src/utils/formatting.ts +220 -213
  354. package/src/utils/list-detection.ts +32 -42
  355. package/src/utils/logger.ts +412 -404
  356. package/src/utils/parsingHelpers.ts +190 -190
  357. package/src/utils/stripTrackedChanges.ts +356 -353
  358. package/src/utils/textDiff.ts +100 -100
  359. package/src/utils/units.ts +421 -421
  360. package/src/utils/validation.ts +553 -542
  361. package/src/utils/xmlSanitization.ts +179 -182
  362. package/src/validation/RevisionAutoFixer.ts +541 -542
  363. package/src/validation/RevisionValidator.ts +470 -460
  364. package/src/validation/ValidationRules.ts +338 -338
  365. package/src/validation/index.ts +30 -30
  366. package/src/xml/XMLBuilder.ts +857 -871
  367. package/src/xml/XMLParser.ts +877 -919
  368. package/src/zip/ZipHandler.ts +629 -637
  369. package/src/zip/ZipReader.ts +295 -299
  370. package/src/zip/ZipWriter.ts +374 -390
  371. package/src/zip/types.ts +116 -116
@@ -1,691 +1,701 @@
1
- /**
2
- * TableOfContents - Represents a Table of Contents in a Word document
3
- *
4
- * A TOC is a special field that automatically generates a list of headings
5
- * based on heading styles (Heading1, Heading2, etc.) in the document.
6
- */
7
-
8
- import { XMLBuilder, XMLElement } from '../xml/XMLBuilder';
9
-
10
- /**
11
- * TOC properties
12
- */
13
- export interface TOCProperties {
14
- /** Title for the TOC (default: "Table of Contents") */
15
- title?: string;
16
- /** Heading levels to include (1-9, default: 1-3) */
17
- levels?: number;
18
- /** Specific styles to include (overrides levels if provided) */
19
- includeStyles?: { styleName: string; level: number }[];
20
- /** Whether to show page numbers (default: true) */
21
- showPageNumbers?: boolean;
22
- /** Whether to right-align page numbers (default: true) */
23
- rightAlignPageNumbers?: boolean;
24
- /** Whether to use hyperlinks instead of page numbers (default: false) */
25
- useHyperlinks?: boolean;
26
- /** Custom TOC style (default: built-in TOC style) */
27
- style?: string;
28
- /** Tab leader character (default: dot) */
29
- tabLeader?: 'dot' | 'hyphen' | 'underscore' | 'none';
30
- /** Custom field switches */
31
- fieldSwitches?: string;
32
- /** Hide page numbers in web layout with \z switch (default: false) */
33
- hideInWebLayout?: boolean;
34
- /** Whether TOC entries should be numbered (default: false) */
35
- numbered?: boolean;
36
- /** Numbering format for TOC entries */
37
- numberingFormat?: 'decimal' | 'roman' | 'alpha';
38
- /** Remove all indentation from TOC entries (default: false) */
39
- noIndent?: boolean;
40
- /** Custom indents for each TOC level in twips */
41
- customIndents?: number[];
42
- /** Space between TOC entries in twips (default: 0) */
43
- spaceBetweenEntries?: number;
44
- /** Hyperlink color in hex format without # (default: 0000FF) */
45
- hyperlinkColor?: string;
46
- /** Original field instruction from loaded document (internal use) */
47
- originalFieldInstruction?: string;
48
- /** Enable automatic normalization of incomplete \t switches (default: false) */
49
- normalizeFieldInstruction?: boolean;
50
- }
51
-
52
- /**
53
- * Represents a Table of Contents
54
- */
55
- export class TableOfContents {
56
- private title: string;
57
- private levels: number;
58
- private includeStyles?: { styleName: string; level: number }[];
59
- private showPageNumbers: boolean;
60
- private useHyperlinks: boolean;
61
- private tabLeader: 'dot' | 'hyphen' | 'underscore' | 'none';
62
- private fieldSwitches?: string;
63
- private hideInWebLayout: boolean;
64
- private numbered: boolean;
65
- private numberingFormat: 'decimal' | 'roman' | 'alpha';
66
- private noIndent: boolean;
67
- private customIndents?: number[];
68
- private spaceBetweenEntries: number;
69
- private hyperlinkColor: string;
70
- private originalFieldInstruction?: string; // Preserve original instruction from loaded documents
71
-
72
- /**
73
- * Creates a new Table of Contents
74
- * @param properties TOC properties
75
- */
76
- constructor(properties: TOCProperties = {}) {
77
- this.title = properties.title || 'Table of Contents';
78
- this.levels = properties.levels || 3;
79
- this.includeStyles = properties.includeStyles;
80
- this.showPageNumbers = properties.showPageNumbers !== false;
81
- this.useHyperlinks = properties.useHyperlinks || false;
82
- this.tabLeader = properties.tabLeader || 'dot';
83
- this.fieldSwitches = properties.fieldSwitches;
84
- this.hideInWebLayout = properties.hideInWebLayout || false;
85
- this.numbered = properties.numbered || false;
86
- this.numberingFormat = properties.numberingFormat || 'decimal';
87
- this.noIndent = properties.noIndent || false;
88
- this.customIndents = properties.customIndents;
89
- this.spaceBetweenEntries = properties.spaceBetweenEntries || 0;
90
- this.hyperlinkColor = properties.hyperlinkColor || '0000FF';
91
- this.originalFieldInstruction = properties.originalFieldInstruction;
92
- }
93
-
94
- /**
95
- * Gets the TOC title
96
- */
97
- getTitle(): string {
98
- return this.title;
99
- }
100
-
101
- /**
102
- * Sets the TOC title
103
- */
104
- setTitle(title: string): this {
105
- this.title = title;
106
- return this;
107
- }
108
-
109
- /**
110
- * Gets the number of heading levels to include
111
- */
112
- getLevels(): number {
113
- return this.levels;
114
- }
115
-
116
- /**
117
- * Sets the number of heading levels to include (1-9)
118
- */
119
- setLevels(levels: number): this {
120
- if (levels < 1 || levels > 9) {
121
- throw new Error('TOC levels must be between 1 and 9');
122
- }
123
- this.levels = levels;
124
- return this;
125
- }
126
-
127
- /**
128
- * Sets (or clears) the original field instruction preserved from a loaded document.
129
- * When set, this instruction is used verbatim in XML generation instead of
130
- * buildFieldInstruction(). Pass undefined to clear it and use computed instruction.
131
- */
132
- setOriginalFieldInstruction(instruction: string | undefined): this {
133
- this.originalFieldInstruction = instruction;
134
- return this;
135
- }
136
-
137
- /**
138
- * Gets the original field instruction preserved from a loaded document, if any.
139
- */
140
- getOriginalFieldInstruction(): string | undefined {
141
- return this.originalFieldInstruction;
142
- }
143
-
144
- /**
145
- * Gets whether page numbers are shown
146
- */
147
- getShowPageNumbers(): boolean {
148
- return this.showPageNumbers;
149
- }
150
-
151
- /**
152
- * Sets whether to show page numbers
153
- */
154
- setShowPageNumbers(show: boolean): this {
155
- this.showPageNumbers = show;
156
- return this;
157
- }
158
-
159
- /**
160
- * Gets whether to use hyperlinks
161
- */
162
- getUseHyperlinks(): boolean {
163
- return this.useHyperlinks;
164
- }
165
-
166
- /**
167
- * Sets whether to use hyperlinks instead of page numbers
168
- */
169
- setUseHyperlinks(use: boolean): this {
170
- this.useHyperlinks = use;
171
- return this;
172
- }
173
-
174
- /**
175
- * Gets whether TOC entries are numbered
176
- */
177
- getNumbered(): boolean {
178
- return this.numbered;
179
- }
180
-
181
- /**
182
- * Gets the numbering format
183
- */
184
- getNumberingFormat(): 'decimal' | 'roman' | 'alpha' {
185
- return this.numberingFormat;
186
- }
187
-
188
- /**
189
- * Gets whether indentation is removed
190
- */
191
- getNoIndent(): boolean {
192
- return this.noIndent;
193
- }
194
-
195
- /**
196
- * Gets custom indents
197
- */
198
- getCustomIndents(): number[] | undefined {
199
- return this.customIndents;
200
- }
201
-
202
- /**
203
- * Gets spacing between entries
204
- */
205
- getSpaceBetweenEntries(): number {
206
- return this.spaceBetweenEntries;
207
- }
208
-
209
- /**
210
- * Gets hyperlink color
211
- */
212
- getHyperlinkColor(): string {
213
- return this.hyperlinkColor;
214
- }
215
-
216
- /**
217
- * Gets specific included styles
218
- */
219
- getIncludeStyles(): { styleName: string; level: number }[] | undefined {
220
- return this.includeStyles;
221
- }
222
-
223
- /**
224
- * Gets whether page numbers are hidden in web layout
225
- * @returns True if \z switch will be generated
226
- */
227
- getHideInWebLayout(): boolean {
228
- return this.hideInWebLayout;
229
- }
230
-
231
- /**
232
- * Sets whether to hide page numbers in web layout
233
- * Generates the \z field switch
234
- * @param hide - True to hide page numbers in web layout
235
- * @returns This instance for chaining
236
- */
237
- setHideInWebLayout(hide: boolean): this {
238
- this.hideInWebLayout = hide;
239
- return this;
240
- }
241
-
242
- /**
243
- * Builds the TOC field instruction string
244
- */
245
- private buildFieldInstruction(): string {
246
- let instruction = 'TOC';
247
-
248
- // Add specific styles switch OR heading levels switch
249
- if (this.includeStyles && this.includeStyles.length > 0) {
250
- // Use \t switch to specify exact styles
251
- // Format: \t "StyleName,Level," for each style
252
- for (const style of this.includeStyles) {
253
- instruction += ` \\t "${style.styleName},${style.level},"`;
254
- }
255
- } else {
256
- // Use \o switch for heading levels
257
- instruction += ` \\o "1-${this.levels}"`;
258
- }
259
-
260
- // Add hyperlinks switch if enabled
261
- if (this.useHyperlinks) {
262
- instruction += ' \\h';
263
- }
264
-
265
- // Add page number switches
266
- if (!this.showPageNumbers) {
267
- instruction += ' \\n';
268
- }
269
-
270
- // Add web layout hide switch
271
- if (this.hideInWebLayout) {
272
- instruction += ' \\z';
273
- }
274
-
275
- // Add tab leader switch
276
- if (this.tabLeader !== 'dot') {
277
- const leaderMap = {
278
- hyphen: 'h',
279
- underscore: 'u',
280
- none: 'n',
281
- };
282
- instruction += ` \\p "${leaderMap[this.tabLeader]}"`;
283
- }
284
-
285
- // Add custom field switches
286
- if (this.fieldSwitches) {
287
- instruction += ` ${this.fieldSwitches}`;
288
- }
289
-
290
- // Add MERGEFORMAT to preserve formatting
291
- instruction += ' \\* MERGEFORMAT';
292
-
293
- return instruction;
294
- }
295
-
296
- /**
297
- * Gets the TOC field instruction string
298
- * Public accessor for the field instruction
299
- *
300
- * @returns The complete TOC field instruction (e.g., "TOC \o "1-3" \h \z")
301
- */
302
- public getFieldInstruction(): string {
303
- return this.buildFieldInstruction();
304
- }
305
-
306
- /**
307
- * Generates XML for the TOC field wrapped in an SDT (Structured Document Tag)
308
- *
309
- * A TOC in Word is represented as:
310
- * 1. SDT wrapper with docPartGallery="Table of Contents"
311
- * 2. SDT content containing:
312
- * a. A paragraph with the title (styled as TOC Heading)
313
- * b. A complex field (fldChar) with the TOC instruction (begin → separate → end)
314
- * c. Placeholder entries (updated by Word when opening)
315
- *
316
- * Per ECMA-376 Part 1 §17.16.5: All complex fields MUST have
317
- * begin → instrText → separate → content → end structure.
318
- * Missing any of these causes Word to reject the document as corrupted.
319
- *
320
- * @throws Error if field structure cannot be generated completely
321
- */
322
- toXML(): XMLElement[] {
323
- const sdtContent: XMLElement[] = [];
324
-
325
- // 1. Title paragraph
326
- if (this.title) {
327
- sdtContent.push({
328
- name: 'w:p',
329
- children: [
330
- {
331
- name: 'w:pPr',
332
- children: [
333
- {
334
- name: 'w:pStyle',
335
- attributes: { 'w:val': 'TOCHeading' },
336
- selfClosing: true,
337
- },
338
- ],
339
- },
340
- {
341
- name: 'w:r',
342
- children: [
343
- {
344
- name: 'w:t',
345
- children: [this.title],
346
- },
347
- ],
348
- },
349
- ],
350
- });
351
- }
352
-
353
- // 2. TOC field paragraph - CRITICAL: Must have complete begin → separate → end structure
354
- const tocParagraph: XMLElement = {
355
- name: 'w:p',
356
- children: [],
357
- };
358
-
359
- // FIELD BEGIN (required)
360
- tocParagraph.children!.push({
361
- name: 'w:r',
362
- children: [
363
- {
364
- name: 'w:fldChar',
365
- attributes: { 'w:fldCharType': 'begin' },
366
- selfClosing: true,
367
- },
368
- ],
369
- });
370
-
371
- // FIELD INSTRUCTION (required)
372
- // Use original field instruction if available (from loaded documents)
373
- // Otherwise, build instruction from properties
374
- const fieldInstruction = this.originalFieldInstruction || this.buildFieldInstruction();
375
- tocParagraph.children!.push({
376
- name: 'w:r',
377
- children: [
378
- {
379
- name: 'w:instrText',
380
- attributes: { 'xml:space': 'preserve' },
381
- children: [fieldInstruction],
382
- },
383
- ],
384
- });
385
-
386
- // FIELD SEPARATE (required - marks boundary between instruction and result)
387
- tocParagraph.children!.push({
388
- name: 'w:r',
389
- children: [
390
- {
391
- name: 'w:fldChar',
392
- attributes: { 'w:fldCharType': 'separate' },
393
- selfClosing: true,
394
- },
395
- ],
396
- });
397
-
398
- // FIELD CONTENT (placeholder - Word updates on open)
399
- tocParagraph.children!.push({
400
- name: 'w:r',
401
- children: [
402
- {
403
- name: 'w:rPr',
404
- children: [
405
- {
406
- name: 'w:noProof',
407
- selfClosing: true,
408
- },
409
- ],
410
- },
411
- {
412
- name: 'w:t',
413
- children: ['Right-click to update field.'],
414
- },
415
- ],
416
- });
417
-
418
- // FIELD END (CRITICAL - REQUIRED by ECMA-376 §17.16.5)
419
- // Missing this causes Word to treat document as corrupted
420
- tocParagraph.children!.push({
421
- name: 'w:r',
422
- children: [
423
- {
424
- name: 'w:fldChar',
425
- attributes: { 'w:fldCharType': 'end' },
426
- selfClosing: true,
427
- },
428
- ],
429
- });
430
-
431
- // Validate complete structure before adding to SDT content
432
- if (tocParagraph.children!.length !== 5) {
433
- throw new Error(
434
- `CRITICAL: TOC field structure incomplete. Expected 5 elements ` +
435
- `(begin, instruction, separate, content, end), got ${tocParagraph.children!.length}. ` +
436
- `This would create an invalid OpenXML document per ECMA-376 §17.16.5.`
437
- );
438
- }
439
-
440
- sdtContent.push(tocParagraph);
441
-
442
- // Wrap TOC content in SDT (Structured Document Tag) for Word native integration
443
- const sdtWrapper = XMLBuilder.createSDT(sdtContent, {
444
- docPartGallery: 'Table of Contents',
445
- docPartUnique: true
446
- });
447
-
448
- return [sdtWrapper];
449
- }
450
-
451
- /**
452
- * Creates a standard TOC with 3 levels
453
- */
454
- static createStandard(title?: string): TableOfContents {
455
- return new TableOfContents({
456
- title: title || 'Table of Contents',
457
- levels: 3,
458
- showPageNumbers: true,
459
- rightAlignPageNumbers: true,
460
- });
461
- }
462
-
463
- /**
464
- * Creates a simple TOC with 2 levels
465
- */
466
- static createSimple(title?: string): TableOfContents {
467
- return new TableOfContents({
468
- title: title || 'Contents',
469
- levels: 2,
470
- showPageNumbers: true,
471
- rightAlignPageNumbers: true,
472
- });
473
- }
474
-
475
- /**
476
- * Creates a detailed TOC with 4 levels
477
- */
478
- static createDetailed(title?: string): TableOfContents {
479
- return new TableOfContents({
480
- title: title || 'Table of Contents',
481
- levels: 4,
482
- showPageNumbers: true,
483
- rightAlignPageNumbers: true,
484
- });
485
- }
486
-
487
- /**
488
- * Creates a hyperlinked TOC (for web documents)
489
- */
490
- static createHyperlinked(title?: string): TableOfContents {
491
- return new TableOfContents({
492
- title: title || 'Contents',
493
- levels: 3,
494
- showPageNumbers: false,
495
- useHyperlinks: true,
496
- });
497
- }
498
-
499
- /**
500
- * Creates a hyperlinked TOC without page numbers
501
- * Combines \h, \n, and \z switches for complete page number hiding
502
- * @param options - TOC configuration options
503
- * @returns New TableOfContents instance
504
- */
505
- static createNoPageNumbers(options: Partial<TOCProperties> = {}): TableOfContents {
506
- return new TableOfContents({
507
- ...options,
508
- useHyperlinks: true,
509
- showPageNumbers: false,
510
- hideInWebLayout: true,
511
- });
512
- }
513
-
514
- /**
515
- * Creates a TOC with custom properties
516
- */
517
- static create(properties?: TOCProperties): TableOfContents {
518
- return new TableOfContents(properties);
519
- }
520
-
521
- /**
522
- * Sets specific styles to include in TOC (overrides levels)
523
- * @param styles - Array of style names (e.g., ['Heading1', 'Heading3']) or objects with styleName and level
524
- * @returns This TOC for chaining
525
- */
526
- setIncludeStyles(styles: string[] | { styleName: string; level: number }[]): this {
527
- // Convert string[] to object format for backward compatibility
528
- if (styles.length > 0 && typeof styles[0] === 'string') {
529
- this.includeStyles = (styles as string[]).map((styleName, index) => ({
530
- styleName,
531
- level: index + 1 // Default: assign sequential levels
532
- }));
533
- } else {
534
- this.includeStyles = styles as { styleName: string; level: number }[];
535
- }
536
- return this;
537
- }
538
-
539
- /**
540
- * Sets whether TOC entries should be numbered
541
- * @param numbered - Whether to number entries
542
- * @param format - Numbering format (decimal, roman, alpha)
543
- * @returns This TOC for chaining
544
- */
545
- setNumbered(numbered: boolean, format: 'decimal' | 'roman' | 'alpha' = 'decimal'): this {
546
- this.numbered = numbered;
547
- this.numberingFormat = format;
548
- return this;
549
- }
550
-
551
- /**
552
- * Sets whether to remove indentation from TOC entries
553
- * @param noIndent - Whether to remove indentation
554
- * @returns This TOC for chaining
555
- */
556
- setNoIndent(noIndent: boolean): this {
557
- this.noIndent = noIndent;
558
- return this;
559
- }
560
-
561
- /**
562
- * Sets custom indents for each TOC level
563
- * @param indents - Array of indent values in twips
564
- * @returns This TOC for chaining
565
- */
566
- setCustomIndents(indents: number[]): this {
567
- this.customIndents = indents;
568
- return this;
569
- }
570
-
571
- /**
572
- * Sets spacing between TOC entries
573
- * @param spacing - Spacing in twips
574
- * @returns This TOC for chaining
575
- */
576
- setSpaceBetweenEntries(spacing: number): this {
577
- this.spaceBetweenEntries = spacing;
578
- return this;
579
- }
580
-
581
- /**
582
- * Sets hyperlink color for TOC entries
583
- * @param color - Hex color without # (e.g., '0000FF' for blue)
584
- * @returns This TOC for chaining
585
- */
586
- setHyperlinkColor(color: string): this {
587
- this.hyperlinkColor = color;
588
- return this;
589
- }
590
-
591
- /**
592
- * Configures multiple properties at once
593
- * @param options - Partial TOC properties to apply
594
- * @returns This TOC for chaining
595
- */
596
- configure(options: Partial<TOCProperties>): this {
597
- if (options.title !== undefined) this.title = options.title;
598
- if (options.levels !== undefined) this.levels = options.levels;
599
- if (options.includeStyles !== undefined) this.includeStyles = options.includeStyles;
600
- if (options.showPageNumbers !== undefined) this.showPageNumbers = options.showPageNumbers;
601
- if (options.useHyperlinks !== undefined) this.useHyperlinks = options.useHyperlinks;
602
- if (options.tabLeader !== undefined) this.tabLeader = options.tabLeader;
603
- if (options.fieldSwitches !== undefined) this.fieldSwitches = options.fieldSwitches;
604
- if (options.hideInWebLayout !== undefined) this.hideInWebLayout = options.hideInWebLayout;
605
- if (options.numbered !== undefined) this.numbered = options.numbered;
606
- if (options.numberingFormat !== undefined) this.numberingFormat = options.numberingFormat;
607
- if (options.noIndent !== undefined) this.noIndent = options.noIndent;
608
- if (options.customIndents !== undefined) this.customIndents = options.customIndents;
609
- if (options.spaceBetweenEntries !== undefined) this.spaceBetweenEntries = options.spaceBetweenEntries;
610
- if (options.hyperlinkColor !== undefined) this.hyperlinkColor = options.hyperlinkColor;
611
- return this;
612
- }
613
-
614
- /**
615
- * Creates a TOC with specific styles
616
- * @param styles - Array of style names to include
617
- * @param options - Additional TOC options
618
- * @returns New TableOfContents instance
619
- */
620
- static createWithStyles(styles: string[], options?: Partial<TOCProperties>): TableOfContents {
621
- // Convert string[] to object format
622
- const stylesWithLevels = styles.map((styleName, index) => ({
623
- styleName,
624
- level: index + 1 // Default: assign sequential levels
625
- }));
626
- return new TableOfContents({
627
- ...options,
628
- includeStyles: stylesWithLevels,
629
- });
630
- }
631
-
632
- /**
633
- * Creates a flat (no indent) TOC
634
- * @param title - Optional TOC title
635
- * @param styles - Optional specific styles (default: all heading levels)
636
- * @returns New TableOfContents instance
637
- */
638
- static createFlat(title?: string, styles?: string[]): TableOfContents {
639
- // Convert string[] to object format if provided
640
- const stylesWithLevels = styles?.map((styleName, index) => ({
641
- styleName,
642
- level: index + 1 // Default: assign sequential levels
643
- }));
644
- return new TableOfContents({
645
- title: title || 'Contents',
646
- includeStyles: stylesWithLevels,
647
- noIndent: true,
648
- spaceBetweenEntries: 100, // Small spacing for flat TOC
649
- });
650
- }
651
-
652
- /**
653
- * Creates a numbered TOC
654
- * @param title - Optional TOC title
655
- * @param format - Numbering format (decimal, roman, alpha)
656
- * @returns New TableOfContents instance
657
- */
658
- static createNumbered(title?: string, format: 'decimal' | 'roman' | 'alpha' = 'decimal'): TableOfContents {
659
- return new TableOfContents({
660
- title: title || 'Table of Contents',
661
- numbered: true,
662
- numberingFormat: format,
663
- });
664
- }
665
-
666
- /**
667
- * Creates a TOC with custom spacing
668
- * @param spaceBetweenEntries - Spacing in twips
669
- * @param options - Additional TOC options
670
- * @returns New TableOfContents instance
671
- */
672
- static createWithSpacing(spaceBetweenEntries: number, options?: Partial<TOCProperties>): TableOfContents {
673
- return new TableOfContents({
674
- ...options,
675
- spaceBetweenEntries,
676
- });
677
- }
678
-
679
- /**
680
- * Creates a TOC with custom hyperlink color
681
- * @param color - Hex color without # (e.g., '0000FF' for blue)
682
- * @param options - Additional TOC options
683
- * @returns New TableOfContents instance
684
- */
685
- static createWithHyperlinkColor(color: string, options?: Partial<TOCProperties>): TableOfContents {
686
- return new TableOfContents({
687
- ...options,
688
- hyperlinkColor: color,
689
- });
690
- }
691
- }
1
+ /**
2
+ * TableOfContents - Represents a Table of Contents in a Word document
3
+ *
4
+ * A TOC is a special field that automatically generates a list of headings
5
+ * based on heading styles (Heading1, Heading2, etc.) in the document.
6
+ */
7
+
8
+ import { XMLBuilder, XMLElement } from '../xml/XMLBuilder';
9
+
10
+ /**
11
+ * TOC properties
12
+ */
13
+ export interface TOCProperties {
14
+ /** Title for the TOC (default: "Table of Contents") */
15
+ title?: string;
16
+ /** Heading levels to include (1-9, default: 1-3) */
17
+ levels?: number;
18
+ /** Specific styles to include (overrides levels if provided) */
19
+ includeStyles?: { styleName: string; level: number }[];
20
+ /** Whether to show page numbers (default: true) */
21
+ showPageNumbers?: boolean;
22
+ /** Whether to right-align page numbers (default: true) */
23
+ rightAlignPageNumbers?: boolean;
24
+ /** Whether to use hyperlinks instead of page numbers (default: false) */
25
+ useHyperlinks?: boolean;
26
+ /** Custom TOC style (default: built-in TOC style) */
27
+ style?: string;
28
+ /** Tab leader character (default: dot) */
29
+ tabLeader?: 'dot' | 'hyphen' | 'underscore' | 'none';
30
+ /** Custom field switches */
31
+ fieldSwitches?: string;
32
+ /** Hide page numbers in web layout with \z switch (default: false) */
33
+ hideInWebLayout?: boolean;
34
+ /** Whether TOC entries should be numbered (default: false) */
35
+ numbered?: boolean;
36
+ /** Numbering format for TOC entries */
37
+ numberingFormat?: 'decimal' | 'roman' | 'alpha';
38
+ /** Remove all indentation from TOC entries (default: false) */
39
+ noIndent?: boolean;
40
+ /** Custom indents for each TOC level in twips */
41
+ customIndents?: number[];
42
+ /** Space between TOC entries in twips (default: 0) */
43
+ spaceBetweenEntries?: number;
44
+ /** Hyperlink color in hex format without # (default: 0000FF) */
45
+ hyperlinkColor?: string;
46
+ /** Original field instruction from loaded document (internal use) */
47
+ originalFieldInstruction?: string;
48
+ /** Enable automatic normalization of incomplete \t switches (default: false) */
49
+ normalizeFieldInstruction?: boolean;
50
+ }
51
+
52
+ /**
53
+ * Represents a Table of Contents
54
+ */
55
+ export class TableOfContents {
56
+ private title: string;
57
+ private levels: number;
58
+ private includeStyles?: { styleName: string; level: number }[];
59
+ private showPageNumbers: boolean;
60
+ private useHyperlinks: boolean;
61
+ private tabLeader: 'dot' | 'hyphen' | 'underscore' | 'none';
62
+ private fieldSwitches?: string;
63
+ private hideInWebLayout: boolean;
64
+ private numbered: boolean;
65
+ private numberingFormat: 'decimal' | 'roman' | 'alpha';
66
+ private noIndent: boolean;
67
+ private customIndents?: number[];
68
+ private spaceBetweenEntries: number;
69
+ private hyperlinkColor: string;
70
+ private originalFieldInstruction?: string; // Preserve original instruction from loaded documents
71
+
72
+ /**
73
+ * Creates a new Table of Contents
74
+ * @param properties TOC properties
75
+ */
76
+ constructor(properties: TOCProperties = {}) {
77
+ this.title = properties.title || 'Table of Contents';
78
+ this.levels = properties.levels || 3;
79
+ this.includeStyles = properties.includeStyles;
80
+ this.showPageNumbers = properties.showPageNumbers !== false;
81
+ this.useHyperlinks = properties.useHyperlinks || false;
82
+ this.tabLeader = properties.tabLeader || 'dot';
83
+ this.fieldSwitches = properties.fieldSwitches;
84
+ this.hideInWebLayout = properties.hideInWebLayout || false;
85
+ this.numbered = properties.numbered || false;
86
+ this.numberingFormat = properties.numberingFormat || 'decimal';
87
+ this.noIndent = properties.noIndent || false;
88
+ this.customIndents = properties.customIndents;
89
+ this.spaceBetweenEntries = properties.spaceBetweenEntries || 0;
90
+ this.hyperlinkColor = properties.hyperlinkColor || '0000FF';
91
+ this.originalFieldInstruction = properties.originalFieldInstruction;
92
+ }
93
+
94
+ /**
95
+ * Gets the TOC title
96
+ */
97
+ getTitle(): string {
98
+ return this.title;
99
+ }
100
+
101
+ /**
102
+ * Sets the TOC title
103
+ */
104
+ setTitle(title: string): this {
105
+ this.title = title;
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Gets the number of heading levels to include
111
+ */
112
+ getLevels(): number {
113
+ return this.levels;
114
+ }
115
+
116
+ /**
117
+ * Sets the number of heading levels to include (1-9)
118
+ */
119
+ setLevels(levels: number): this {
120
+ if (levels < 1 || levels > 9) {
121
+ throw new Error('TOC levels must be between 1 and 9');
122
+ }
123
+ this.levels = levels;
124
+ return this;
125
+ }
126
+
127
+ /**
128
+ * Sets (or clears) the original field instruction preserved from a loaded document.
129
+ * When set, this instruction is used verbatim in XML generation instead of
130
+ * buildFieldInstruction(). Pass undefined to clear it and use computed instruction.
131
+ */
132
+ setOriginalFieldInstruction(instruction: string | undefined): this {
133
+ this.originalFieldInstruction = instruction;
134
+ return this;
135
+ }
136
+
137
+ /**
138
+ * Gets the original field instruction preserved from a loaded document, if any.
139
+ */
140
+ getOriginalFieldInstruction(): string | undefined {
141
+ return this.originalFieldInstruction;
142
+ }
143
+
144
+ /**
145
+ * Gets whether page numbers are shown
146
+ */
147
+ getShowPageNumbers(): boolean {
148
+ return this.showPageNumbers;
149
+ }
150
+
151
+ /**
152
+ * Sets whether to show page numbers
153
+ */
154
+ setShowPageNumbers(show: boolean): this {
155
+ this.showPageNumbers = show;
156
+ return this;
157
+ }
158
+
159
+ /**
160
+ * Gets whether to use hyperlinks
161
+ */
162
+ getUseHyperlinks(): boolean {
163
+ return this.useHyperlinks;
164
+ }
165
+
166
+ /**
167
+ * Sets whether to use hyperlinks instead of page numbers
168
+ */
169
+ setUseHyperlinks(use: boolean): this {
170
+ this.useHyperlinks = use;
171
+ return this;
172
+ }
173
+
174
+ /**
175
+ * Gets whether TOC entries are numbered
176
+ */
177
+ getNumbered(): boolean {
178
+ return this.numbered;
179
+ }
180
+
181
+ /**
182
+ * Gets the numbering format
183
+ */
184
+ getNumberingFormat(): 'decimal' | 'roman' | 'alpha' {
185
+ return this.numberingFormat;
186
+ }
187
+
188
+ /**
189
+ * Gets whether indentation is removed
190
+ */
191
+ getNoIndent(): boolean {
192
+ return this.noIndent;
193
+ }
194
+
195
+ /**
196
+ * Gets custom indents
197
+ */
198
+ getCustomIndents(): number[] | undefined {
199
+ return this.customIndents;
200
+ }
201
+
202
+ /**
203
+ * Gets spacing between entries
204
+ */
205
+ getSpaceBetweenEntries(): number {
206
+ return this.spaceBetweenEntries;
207
+ }
208
+
209
+ /**
210
+ * Gets hyperlink color
211
+ */
212
+ getHyperlinkColor(): string {
213
+ return this.hyperlinkColor;
214
+ }
215
+
216
+ /**
217
+ * Gets specific included styles
218
+ */
219
+ getIncludeStyles(): { styleName: string; level: number }[] | undefined {
220
+ return this.includeStyles;
221
+ }
222
+
223
+ /**
224
+ * Gets whether page numbers are hidden in web layout
225
+ * @returns True if \z switch will be generated
226
+ */
227
+ getHideInWebLayout(): boolean {
228
+ return this.hideInWebLayout;
229
+ }
230
+
231
+ /**
232
+ * Sets whether to hide page numbers in web layout
233
+ * Generates the \z field switch
234
+ * @param hide - True to hide page numbers in web layout
235
+ * @returns This instance for chaining
236
+ */
237
+ setHideInWebLayout(hide: boolean): this {
238
+ this.hideInWebLayout = hide;
239
+ return this;
240
+ }
241
+
242
+ /**
243
+ * Builds the TOC field instruction string
244
+ */
245
+ private buildFieldInstruction(): string {
246
+ let instruction = 'TOC';
247
+
248
+ // Add specific styles switch OR heading levels switch
249
+ if (this.includeStyles && this.includeStyles.length > 0) {
250
+ // Use \t switch to specify exact styles
251
+ // Format: \t "StyleName,Level," for each style
252
+ for (const style of this.includeStyles) {
253
+ instruction += ` \\t "${style.styleName},${style.level},"`;
254
+ }
255
+ } else {
256
+ // Use \o switch for heading levels
257
+ instruction += ` \\o "1-${this.levels}"`;
258
+ }
259
+
260
+ // Add hyperlinks switch if enabled
261
+ if (this.useHyperlinks) {
262
+ instruction += ' \\h';
263
+ }
264
+
265
+ // Add page number switches
266
+ if (!this.showPageNumbers) {
267
+ instruction += ' \\n';
268
+ }
269
+
270
+ // Add web layout hide switch
271
+ if (this.hideInWebLayout) {
272
+ instruction += ' \\z';
273
+ }
274
+
275
+ // Add tab leader switch
276
+ if (this.tabLeader !== 'dot') {
277
+ const leaderMap = {
278
+ hyphen: 'h',
279
+ underscore: 'u',
280
+ none: 'n',
281
+ };
282
+ instruction += ` \\p "${leaderMap[this.tabLeader]}"`;
283
+ }
284
+
285
+ // Add custom field switches
286
+ if (this.fieldSwitches) {
287
+ instruction += ` ${this.fieldSwitches}`;
288
+ }
289
+
290
+ // Add MERGEFORMAT to preserve formatting
291
+ instruction += ' \\* MERGEFORMAT';
292
+
293
+ return instruction;
294
+ }
295
+
296
+ /**
297
+ * Gets the TOC field instruction string
298
+ * Public accessor for the field instruction
299
+ *
300
+ * @returns The complete TOC field instruction (e.g., "TOC \o "1-3" \h \z")
301
+ */
302
+ public getFieldInstruction(): string {
303
+ return this.buildFieldInstruction();
304
+ }
305
+
306
+ /**
307
+ * Generates XML for the TOC field wrapped in an SDT (Structured Document Tag)
308
+ *
309
+ * A TOC in Word is represented as:
310
+ * 1. SDT wrapper with docPartGallery="Table of Contents"
311
+ * 2. SDT content containing:
312
+ * a. A paragraph with the title (styled as TOC Heading)
313
+ * b. A complex field (fldChar) with the TOC instruction (begin → separate → end)
314
+ * c. Placeholder entries (updated by Word when opening)
315
+ *
316
+ * Per ECMA-376 Part 1 §17.16.5: All complex fields MUST have
317
+ * begin → instrText → separate → content → end structure.
318
+ * Missing any of these causes Word to reject the document as corrupted.
319
+ *
320
+ * @throws Error if field structure cannot be generated completely
321
+ */
322
+ toXML(): XMLElement[] {
323
+ const sdtContent: XMLElement[] = [];
324
+
325
+ // 1. Title paragraph
326
+ if (this.title) {
327
+ sdtContent.push({
328
+ name: 'w:p',
329
+ children: [
330
+ {
331
+ name: 'w:pPr',
332
+ children: [
333
+ {
334
+ name: 'w:pStyle',
335
+ attributes: { 'w:val': 'TOCHeading' },
336
+ selfClosing: true,
337
+ },
338
+ ],
339
+ },
340
+ {
341
+ name: 'w:r',
342
+ children: [
343
+ {
344
+ name: 'w:t',
345
+ children: [this.title],
346
+ },
347
+ ],
348
+ },
349
+ ],
350
+ });
351
+ }
352
+
353
+ // 2. TOC field paragraph - CRITICAL: Must have complete begin → separate → end structure
354
+ const tocParagraph: XMLElement = {
355
+ name: 'w:p',
356
+ children: [],
357
+ };
358
+
359
+ // FIELD BEGIN (required)
360
+ tocParagraph.children!.push({
361
+ name: 'w:r',
362
+ children: [
363
+ {
364
+ name: 'w:fldChar',
365
+ attributes: { 'w:fldCharType': 'begin' },
366
+ selfClosing: true,
367
+ },
368
+ ],
369
+ });
370
+
371
+ // FIELD INSTRUCTION (required)
372
+ // Use original field instruction if available (from loaded documents)
373
+ // Otherwise, build instruction from properties
374
+ const fieldInstruction = this.originalFieldInstruction || this.buildFieldInstruction();
375
+ tocParagraph.children!.push({
376
+ name: 'w:r',
377
+ children: [
378
+ {
379
+ name: 'w:instrText',
380
+ attributes: { 'xml:space': 'preserve' },
381
+ children: [fieldInstruction],
382
+ },
383
+ ],
384
+ });
385
+
386
+ // FIELD SEPARATE (required - marks boundary between instruction and result)
387
+ tocParagraph.children!.push({
388
+ name: 'w:r',
389
+ children: [
390
+ {
391
+ name: 'w:fldChar',
392
+ attributes: { 'w:fldCharType': 'separate' },
393
+ selfClosing: true,
394
+ },
395
+ ],
396
+ });
397
+
398
+ // FIELD CONTENT (placeholder - Word updates on open)
399
+ tocParagraph.children!.push({
400
+ name: 'w:r',
401
+ children: [
402
+ {
403
+ name: 'w:rPr',
404
+ children: [
405
+ {
406
+ name: 'w:noProof',
407
+ selfClosing: true,
408
+ },
409
+ ],
410
+ },
411
+ {
412
+ name: 'w:t',
413
+ children: ['Right-click to update field.'],
414
+ },
415
+ ],
416
+ });
417
+
418
+ // FIELD END (CRITICAL - REQUIRED by ECMA-376 §17.16.5)
419
+ // Missing this causes Word to treat document as corrupted
420
+ tocParagraph.children!.push({
421
+ name: 'w:r',
422
+ children: [
423
+ {
424
+ name: 'w:fldChar',
425
+ attributes: { 'w:fldCharType': 'end' },
426
+ selfClosing: true,
427
+ },
428
+ ],
429
+ });
430
+
431
+ // Validate complete structure before adding to SDT content
432
+ if (tocParagraph.children!.length !== 5) {
433
+ throw new Error(
434
+ `CRITICAL: TOC field structure incomplete. Expected 5 elements ` +
435
+ `(begin, instruction, separate, content, end), got ${tocParagraph.children!.length}. ` +
436
+ `This would create an invalid OpenXML document per ECMA-376 §17.16.5.`
437
+ );
438
+ }
439
+
440
+ sdtContent.push(tocParagraph);
441
+
442
+ // Wrap TOC content in SDT (Structured Document Tag) for Word native integration
443
+ const sdtWrapper = XMLBuilder.createSDT(sdtContent, {
444
+ docPartGallery: 'Table of Contents',
445
+ docPartUnique: true,
446
+ });
447
+
448
+ return [sdtWrapper];
449
+ }
450
+
451
+ /**
452
+ * Creates a standard TOC with 3 levels
453
+ */
454
+ static createStandard(title?: string): TableOfContents {
455
+ return new TableOfContents({
456
+ title: title || 'Table of Contents',
457
+ levels: 3,
458
+ showPageNumbers: true,
459
+ rightAlignPageNumbers: true,
460
+ });
461
+ }
462
+
463
+ /**
464
+ * Creates a simple TOC with 2 levels
465
+ */
466
+ static createSimple(title?: string): TableOfContents {
467
+ return new TableOfContents({
468
+ title: title || 'Contents',
469
+ levels: 2,
470
+ showPageNumbers: true,
471
+ rightAlignPageNumbers: true,
472
+ });
473
+ }
474
+
475
+ /**
476
+ * Creates a detailed TOC with 4 levels
477
+ */
478
+ static createDetailed(title?: string): TableOfContents {
479
+ return new TableOfContents({
480
+ title: title || 'Table of Contents',
481
+ levels: 4,
482
+ showPageNumbers: true,
483
+ rightAlignPageNumbers: true,
484
+ });
485
+ }
486
+
487
+ /**
488
+ * Creates a hyperlinked TOC (for web documents)
489
+ */
490
+ static createHyperlinked(title?: string): TableOfContents {
491
+ return new TableOfContents({
492
+ title: title || 'Contents',
493
+ levels: 3,
494
+ showPageNumbers: false,
495
+ useHyperlinks: true,
496
+ });
497
+ }
498
+
499
+ /**
500
+ * Creates a hyperlinked TOC without page numbers
501
+ * Combines \h, \n, and \z switches for complete page number hiding
502
+ * @param options - TOC configuration options
503
+ * @returns New TableOfContents instance
504
+ */
505
+ static createNoPageNumbers(options: Partial<TOCProperties> = {}): TableOfContents {
506
+ return new TableOfContents({
507
+ ...options,
508
+ useHyperlinks: true,
509
+ showPageNumbers: false,
510
+ hideInWebLayout: true,
511
+ });
512
+ }
513
+
514
+ /**
515
+ * Creates a TOC with custom properties
516
+ */
517
+ static create(properties?: TOCProperties): TableOfContents {
518
+ return new TableOfContents(properties);
519
+ }
520
+
521
+ /**
522
+ * Sets specific styles to include in TOC (overrides levels)
523
+ * @param styles - Array of style names (e.g., ['Heading1', 'Heading3']) or objects with styleName and level
524
+ * @returns This TOC for chaining
525
+ */
526
+ setIncludeStyles(styles: string[] | { styleName: string; level: number }[]): this {
527
+ // Convert string[] to object format for backward compatibility
528
+ if (styles.length > 0 && typeof styles[0] === 'string') {
529
+ this.includeStyles = (styles as string[]).map((styleName, index) => ({
530
+ styleName,
531
+ level: index + 1, // Default: assign sequential levels
532
+ }));
533
+ } else {
534
+ this.includeStyles = styles as { styleName: string; level: number }[];
535
+ }
536
+ return this;
537
+ }
538
+
539
+ /**
540
+ * Sets whether TOC entries should be numbered
541
+ * @param numbered - Whether to number entries
542
+ * @param format - Numbering format (decimal, roman, alpha)
543
+ * @returns This TOC for chaining
544
+ */
545
+ setNumbered(numbered: boolean, format: 'decimal' | 'roman' | 'alpha' = 'decimal'): this {
546
+ this.numbered = numbered;
547
+ this.numberingFormat = format;
548
+ return this;
549
+ }
550
+
551
+ /**
552
+ * Sets whether to remove indentation from TOC entries
553
+ * @param noIndent - Whether to remove indentation
554
+ * @returns This TOC for chaining
555
+ */
556
+ setNoIndent(noIndent: boolean): this {
557
+ this.noIndent = noIndent;
558
+ return this;
559
+ }
560
+
561
+ /**
562
+ * Sets custom indents for each TOC level
563
+ * @param indents - Array of indent values in twips
564
+ * @returns This TOC for chaining
565
+ */
566
+ setCustomIndents(indents: number[]): this {
567
+ this.customIndents = indents;
568
+ return this;
569
+ }
570
+
571
+ /**
572
+ * Sets spacing between TOC entries
573
+ * @param spacing - Spacing in twips
574
+ * @returns This TOC for chaining
575
+ */
576
+ setSpaceBetweenEntries(spacing: number): this {
577
+ this.spaceBetweenEntries = spacing;
578
+ return this;
579
+ }
580
+
581
+ /**
582
+ * Sets hyperlink color for TOC entries
583
+ * @param color - Hex color without # (e.g., '0000FF' for blue)
584
+ * @returns This TOC for chaining
585
+ */
586
+ setHyperlinkColor(color: string): this {
587
+ this.hyperlinkColor = color;
588
+ return this;
589
+ }
590
+
591
+ /**
592
+ * Configures multiple properties at once
593
+ * @param options - Partial TOC properties to apply
594
+ * @returns This TOC for chaining
595
+ */
596
+ configure(options: Partial<TOCProperties>): this {
597
+ if (options.title !== undefined) this.title = options.title;
598
+ if (options.levels !== undefined) this.levels = options.levels;
599
+ if (options.includeStyles !== undefined) this.includeStyles = options.includeStyles;
600
+ if (options.showPageNumbers !== undefined) this.showPageNumbers = options.showPageNumbers;
601
+ if (options.useHyperlinks !== undefined) this.useHyperlinks = options.useHyperlinks;
602
+ if (options.tabLeader !== undefined) this.tabLeader = options.tabLeader;
603
+ if (options.fieldSwitches !== undefined) this.fieldSwitches = options.fieldSwitches;
604
+ if (options.hideInWebLayout !== undefined) this.hideInWebLayout = options.hideInWebLayout;
605
+ if (options.numbered !== undefined) this.numbered = options.numbered;
606
+ if (options.numberingFormat !== undefined) this.numberingFormat = options.numberingFormat;
607
+ if (options.noIndent !== undefined) this.noIndent = options.noIndent;
608
+ if (options.customIndents !== undefined) this.customIndents = options.customIndents;
609
+ if (options.spaceBetweenEntries !== undefined)
610
+ this.spaceBetweenEntries = options.spaceBetweenEntries;
611
+ if (options.hyperlinkColor !== undefined) this.hyperlinkColor = options.hyperlinkColor;
612
+ return this;
613
+ }
614
+
615
+ /**
616
+ * Creates a TOC with specific styles
617
+ * @param styles - Array of style names to include
618
+ * @param options - Additional TOC options
619
+ * @returns New TableOfContents instance
620
+ */
621
+ static createWithStyles(styles: string[], options?: Partial<TOCProperties>): TableOfContents {
622
+ // Convert string[] to object format
623
+ const stylesWithLevels = styles.map((styleName, index) => ({
624
+ styleName,
625
+ level: index + 1, // Default: assign sequential levels
626
+ }));
627
+ return new TableOfContents({
628
+ ...options,
629
+ includeStyles: stylesWithLevels,
630
+ });
631
+ }
632
+
633
+ /**
634
+ * Creates a flat (no indent) TOC
635
+ * @param title - Optional TOC title
636
+ * @param styles - Optional specific styles (default: all heading levels)
637
+ * @returns New TableOfContents instance
638
+ */
639
+ static createFlat(title?: string, styles?: string[]): TableOfContents {
640
+ // Convert string[] to object format if provided
641
+ const stylesWithLevels = styles?.map((styleName, index) => ({
642
+ styleName,
643
+ level: index + 1, // Default: assign sequential levels
644
+ }));
645
+ return new TableOfContents({
646
+ title: title || 'Contents',
647
+ includeStyles: stylesWithLevels,
648
+ noIndent: true,
649
+ spaceBetweenEntries: 100, // Small spacing for flat TOC
650
+ });
651
+ }
652
+
653
+ /**
654
+ * Creates a numbered TOC
655
+ * @param title - Optional TOC title
656
+ * @param format - Numbering format (decimal, roman, alpha)
657
+ * @returns New TableOfContents instance
658
+ */
659
+ static createNumbered(
660
+ title?: string,
661
+ format: 'decimal' | 'roman' | 'alpha' = 'decimal'
662
+ ): TableOfContents {
663
+ return new TableOfContents({
664
+ title: title || 'Table of Contents',
665
+ numbered: true,
666
+ numberingFormat: format,
667
+ });
668
+ }
669
+
670
+ /**
671
+ * Creates a TOC with custom spacing
672
+ * @param spaceBetweenEntries - Spacing in twips
673
+ * @param options - Additional TOC options
674
+ * @returns New TableOfContents instance
675
+ */
676
+ static createWithSpacing(
677
+ spaceBetweenEntries: number,
678
+ options?: Partial<TOCProperties>
679
+ ): TableOfContents {
680
+ return new TableOfContents({
681
+ ...options,
682
+ spaceBetweenEntries,
683
+ });
684
+ }
685
+
686
+ /**
687
+ * Creates a TOC with custom hyperlink color
688
+ * @param color - Hex color without # (e.g., '0000FF' for blue)
689
+ * @param options - Additional TOC options
690
+ * @returns New TableOfContents instance
691
+ */
692
+ static createWithHyperlinkColor(
693
+ color: string,
694
+ options?: Partial<TOCProperties>
695
+ ): TableOfContents {
696
+ return new TableOfContents({
697
+ ...options,
698
+ hyperlinkColor: color,
699
+ });
700
+ }
701
+ }