docxmlater 10.0.1 → 10.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/README.md +3 -2
  2. package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
  3. package/dist/constants/legacyCompatFlags.js.map +1 -1
  4. package/dist/constants/limits.d.ts +0 -27
  5. package/dist/constants/limits.d.ts.map +1 -1
  6. package/dist/constants/limits.js +13 -13
  7. package/dist/constants/limits.js.map +1 -1
  8. package/dist/core/Document.d.ts +24 -19
  9. package/dist/core/Document.d.ts.map +1 -1
  10. package/dist/core/Document.js +272 -71
  11. package/dist/core/Document.js.map +1 -1
  12. package/dist/core/DocumentContent.d.ts.map +1 -1
  13. package/dist/core/DocumentContent.js.map +1 -1
  14. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  15. package/dist/core/DocumentGenerator.js +59 -24
  16. package/dist/core/DocumentGenerator.js.map +1 -1
  17. package/dist/core/DocumentIdManager.d.ts.map +1 -1
  18. package/dist/core/DocumentIdManager.js.map +1 -1
  19. package/dist/core/DocumentParser.d.ts +6 -6
  20. package/dist/core/DocumentParser.d.ts.map +1 -1
  21. package/dist/core/DocumentParser.js +60 -54
  22. package/dist/core/DocumentParser.js.map +1 -1
  23. package/dist/core/DocumentValidator.d.ts.map +1 -1
  24. package/dist/core/DocumentValidator.js.map +1 -1
  25. package/dist/core/Relationship.d.ts.map +1 -1
  26. package/dist/core/Relationship.js +1 -1
  27. package/dist/core/Relationship.js.map +1 -1
  28. package/dist/core/RelationshipManager.js +3 -3
  29. package/dist/core/RelationshipManager.js.map +1 -1
  30. package/dist/elements/AlternateContent.js.map +1 -1
  31. package/dist/elements/Bookmark.d.ts.map +1 -1
  32. package/dist/elements/Bookmark.js.map +1 -1
  33. package/dist/elements/BookmarkManager.d.ts.map +1 -1
  34. package/dist/elements/BookmarkManager.js.map +1 -1
  35. package/dist/elements/Comment.js +1 -1
  36. package/dist/elements/Comment.js.map +1 -1
  37. package/dist/elements/CommentManager.d.ts.map +1 -1
  38. package/dist/elements/CommentManager.js +8 -2
  39. package/dist/elements/CommentManager.js.map +1 -1
  40. package/dist/elements/CommonTypes.d.ts.map +1 -1
  41. package/dist/elements/CommonTypes.js +1 -2
  42. package/dist/elements/CommonTypes.js.map +1 -1
  43. package/dist/elements/CustomXml.js.map +1 -1
  44. package/dist/elements/Endnote.d.ts.map +1 -1
  45. package/dist/elements/Endnote.js.map +1 -1
  46. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  47. package/dist/elements/EndnoteManager.js.map +1 -1
  48. package/dist/elements/Field.d.ts.map +1 -1
  49. package/dist/elements/Field.js +31 -28
  50. package/dist/elements/Field.js.map +1 -1
  51. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  52. package/dist/elements/FieldHelpers.js +6 -6
  53. package/dist/elements/FieldHelpers.js.map +1 -1
  54. package/dist/elements/FontManager.d.ts.map +1 -1
  55. package/dist/elements/FontManager.js.map +1 -1
  56. package/dist/elements/Footer.js.map +1 -1
  57. package/dist/elements/Footnote.d.ts.map +1 -1
  58. package/dist/elements/Footnote.js.map +1 -1
  59. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  60. package/dist/elements/FootnoteManager.js.map +1 -1
  61. package/dist/elements/Header.js.map +1 -1
  62. package/dist/elements/HeaderFooterManager.js.map +1 -1
  63. package/dist/elements/Hyperlink.d.ts.map +1 -1
  64. package/dist/elements/Hyperlink.js +5 -5
  65. package/dist/elements/Hyperlink.js.map +1 -1
  66. package/dist/elements/Image.d.ts +2 -2
  67. package/dist/elements/Image.d.ts.map +1 -1
  68. package/dist/elements/Image.js +21 -5
  69. package/dist/elements/Image.js.map +1 -1
  70. package/dist/elements/ImageManager.d.ts.map +1 -1
  71. package/dist/elements/ImageManager.js +2 -2
  72. package/dist/elements/ImageManager.js.map +1 -1
  73. package/dist/elements/ImageRun.js.map +1 -1
  74. package/dist/elements/MathElement.js.map +1 -1
  75. package/dist/elements/Paragraph.d.ts.map +1 -1
  76. package/dist/elements/Paragraph.js +128 -117
  77. package/dist/elements/Paragraph.js.map +1 -1
  78. package/dist/elements/PreservedElement.js.map +1 -1
  79. package/dist/elements/PropertyChangeTypes.js.map +1 -1
  80. package/dist/elements/RangeMarker.js.map +1 -1
  81. package/dist/elements/Revision.d.ts +1 -0
  82. package/dist/elements/Revision.d.ts.map +1 -1
  83. package/dist/elements/Revision.js +44 -5
  84. package/dist/elements/Revision.js.map +1 -1
  85. package/dist/elements/RevisionContent.js.map +1 -1
  86. package/dist/elements/RevisionManager.d.ts.map +1 -1
  87. package/dist/elements/RevisionManager.js.map +1 -1
  88. package/dist/elements/Run.d.ts.map +1 -1
  89. package/dist/elements/Run.js +1 -3
  90. package/dist/elements/Run.js.map +1 -1
  91. package/dist/elements/Section.d.ts.map +1 -1
  92. package/dist/elements/Section.js +127 -118
  93. package/dist/elements/Section.js.map +1 -1
  94. package/dist/elements/Shape.d.ts.map +1 -1
  95. package/dist/elements/Shape.js +21 -0
  96. package/dist/elements/Shape.js.map +1 -1
  97. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  98. package/dist/elements/StructuredDocumentTag.js +20 -8
  99. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  100. package/dist/elements/Table.d.ts +2 -2
  101. package/dist/elements/Table.d.ts.map +1 -1
  102. package/dist/elements/Table.js +29 -35
  103. package/dist/elements/Table.js.map +1 -1
  104. package/dist/elements/TableCell.d.ts +2 -2
  105. package/dist/elements/TableCell.d.ts.map +1 -1
  106. package/dist/elements/TableCell.js +63 -67
  107. package/dist/elements/TableCell.js.map +1 -1
  108. package/dist/elements/TableGridChange.js.map +1 -1
  109. package/dist/elements/TableOfContents.d.ts +6 -6
  110. package/dist/elements/TableOfContents.d.ts.map +1 -1
  111. package/dist/elements/TableOfContents.js.map +1 -1
  112. package/dist/elements/TableOfContentsElement.js.map +1 -1
  113. package/dist/elements/TableRow.d.ts.map +1 -1
  114. package/dist/elements/TableRow.js +65 -47
  115. package/dist/elements/TableRow.js.map +1 -1
  116. package/dist/elements/TextBox.d.ts.map +1 -1
  117. package/dist/elements/TextBox.js +1 -1
  118. package/dist/elements/TextBox.js.map +1 -1
  119. package/dist/formatting/AbstractNumbering.d.ts +1 -1
  120. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  121. package/dist/formatting/AbstractNumbering.js +11 -11
  122. package/dist/formatting/AbstractNumbering.js.map +1 -1
  123. package/dist/formatting/NumberingInstance.d.ts.map +1 -1
  124. package/dist/formatting/NumberingInstance.js +4 -4
  125. package/dist/formatting/NumberingInstance.js.map +1 -1
  126. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  127. package/dist/formatting/NumberingLevel.js +26 -26
  128. package/dist/formatting/NumberingLevel.js.map +1 -1
  129. package/dist/formatting/NumberingManager.d.ts +1 -1
  130. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  131. package/dist/formatting/NumberingManager.js.map +1 -1
  132. package/dist/formatting/Style.d.ts.map +1 -1
  133. package/dist/formatting/Style.js +87 -95
  134. package/dist/formatting/Style.js.map +1 -1
  135. package/dist/formatting/StylesManager.d.ts +3 -3
  136. package/dist/formatting/StylesManager.d.ts.map +1 -1
  137. package/dist/formatting/StylesManager.js.map +1 -1
  138. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  139. package/dist/helpers/CleanupHelper.js +1 -7
  140. package/dist/helpers/CleanupHelper.js.map +1 -1
  141. package/dist/images/ImageOptimizer.js.map +1 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/managers/DrawingManager.d.ts.map +1 -1
  144. package/dist/managers/DrawingManager.js.map +1 -1
  145. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  146. package/dist/tracking/TrackingContext.js.map +1 -1
  147. package/dist/types/compatibility-types.js.map +1 -1
  148. package/dist/types/formatting.js.map +1 -1
  149. package/dist/types/list-types.d.ts +4 -4
  150. package/dist/types/list-types.d.ts.map +1 -1
  151. package/dist/types/list-types.js.map +1 -1
  152. package/dist/types/settings-types.js.map +1 -1
  153. package/dist/types/styleConfig.js.map +1 -1
  154. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  155. package/dist/utils/ChangelogGenerator.js.map +1 -1
  156. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  157. package/dist/utils/CompatibilityUpgrader.js +7 -7
  158. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  159. package/dist/utils/InMemoryRevisionAcceptor.js +1 -1
  160. package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
  161. package/dist/utils/MoveOperationHelper.js.map +1 -1
  162. package/dist/utils/RevisionAwareProcessor.js.map +1 -1
  163. package/dist/utils/RevisionWalker.js.map +1 -1
  164. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  165. package/dist/utils/ShadingResolver.js +1 -1
  166. package/dist/utils/ShadingResolver.js.map +1 -1
  167. package/dist/utils/acceptRevisions.d.ts +0 -28
  168. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  169. package/dist/utils/acceptRevisions.js +5 -7
  170. package/dist/utils/acceptRevisions.js.map +1 -1
  171. package/dist/utils/cnfStyleDecoder.js +1 -1
  172. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  173. package/dist/utils/corruptionDetection.js.map +1 -1
  174. package/dist/utils/dateFormatting.js.map +1 -1
  175. package/dist/utils/deepClone.d.ts +0 -1
  176. package/dist/utils/deepClone.d.ts.map +1 -1
  177. package/dist/utils/deepClone.js +0 -7
  178. package/dist/utils/deepClone.js.map +1 -1
  179. package/dist/utils/diagnostics.d.ts +2 -2
  180. package/dist/utils/diagnostics.d.ts.map +1 -1
  181. package/dist/utils/diagnostics.js.map +1 -1
  182. package/dist/utils/errorHandling.js.map +1 -1
  183. package/dist/utils/formatting.js.map +1 -1
  184. package/dist/utils/list-detection.d.ts +2 -2
  185. package/dist/utils/list-detection.d.ts.map +1 -1
  186. package/dist/utils/list-detection.js +3 -3
  187. package/dist/utils/list-detection.js.map +1 -1
  188. package/dist/utils/logger.d.ts +2 -4
  189. package/dist/utils/logger.d.ts.map +1 -1
  190. package/dist/utils/logger.js +0 -2
  191. package/dist/utils/logger.js.map +1 -1
  192. package/dist/utils/parsingHelpers.js.map +1 -1
  193. package/dist/utils/stripTrackedChanges.d.ts +0 -19
  194. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  195. package/dist/utils/stripTrackedChanges.js +0 -2
  196. package/dist/utils/stripTrackedChanges.js.map +1 -1
  197. package/dist/utils/textDiff.js.map +1 -1
  198. package/dist/utils/units.js.map +1 -1
  199. package/dist/utils/validation.d.ts.map +1 -1
  200. package/dist/utils/validation.js.map +1 -1
  201. package/dist/utils/xmlSanitization.js.map +1 -1
  202. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  203. package/dist/validation/RevisionValidator.js.map +1 -1
  204. package/dist/validation/ValidationRules.js.map +1 -1
  205. package/dist/validation/index.js.map +1 -1
  206. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  207. package/dist/xml/XMLBuilder.js +10 -0
  208. package/dist/xml/XMLBuilder.js.map +1 -1
  209. package/dist/xml/XMLParser.d.ts.map +1 -1
  210. package/dist/xml/XMLParser.js +4 -5
  211. package/dist/xml/XMLParser.js.map +1 -1
  212. package/dist/zip/ZipHandler.js.map +1 -1
  213. package/dist/zip/ZipReader.js.map +1 -1
  214. package/dist/zip/ZipWriter.js.map +1 -1
  215. package/dist/zip/errors.js.map +1 -1
  216. package/dist/zip/types.js.map +1 -1
  217. package/package.json +34 -4
  218. package/src/__tests__/helper-methods.test.ts +512 -0
  219. package/src/constants/legacyCompatFlags.ts +138 -0
  220. package/src/constants/limits.ts +50 -0
  221. package/src/core/CLAUDE.md +109 -0
  222. package/src/core/Document.ts +15569 -0
  223. package/src/core/DocumentContent.ts +467 -0
  224. package/src/core/DocumentGenerator.ts +1104 -0
  225. package/src/core/DocumentIdManager.ts +158 -0
  226. package/src/core/DocumentParser.ts +10107 -0
  227. package/src/core/DocumentValidator.ts +372 -0
  228. package/src/core/Relationship.ts +367 -0
  229. package/src/core/RelationshipManager.ts +428 -0
  230. package/src/elements/AlternateContent.ts +42 -0
  231. package/src/elements/Bookmark.ts +210 -0
  232. package/src/elements/BookmarkManager.ts +250 -0
  233. package/src/elements/CLAUDE.md +126 -0
  234. package/src/elements/Comment.ts +359 -0
  235. package/src/elements/CommentManager.ts +502 -0
  236. package/src/elements/CommonTypes.ts +549 -0
  237. package/src/elements/CustomXml.ts +36 -0
  238. package/src/elements/Endnote.ts +217 -0
  239. package/src/elements/EndnoteManager.ts +249 -0
  240. package/src/elements/Field.ts +1233 -0
  241. package/src/elements/FieldHelpers.ts +333 -0
  242. package/src/elements/FontManager.ts +339 -0
  243. package/src/elements/Footer.ts +269 -0
  244. package/src/elements/Footnote.ts +217 -0
  245. package/src/elements/FootnoteManager.ts +249 -0
  246. package/src/elements/Header.ts +269 -0
  247. package/src/elements/HeaderFooterManager.ts +219 -0
  248. package/src/elements/Hyperlink.ts +1146 -0
  249. package/src/elements/Image.ts +1756 -0
  250. package/src/elements/ImageManager.ts +432 -0
  251. package/src/elements/ImageRun.ts +59 -0
  252. package/src/elements/MathElement.ts +65 -0
  253. package/src/elements/Paragraph.ts +4227 -0
  254. package/src/elements/PreservedElement.ts +53 -0
  255. package/src/elements/PropertyChangeTypes.ts +442 -0
  256. package/src/elements/RangeMarker.ts +400 -0
  257. package/src/elements/Revision.ts +1217 -0
  258. package/src/elements/RevisionContent.ts +73 -0
  259. package/src/elements/RevisionManager.ts +1070 -0
  260. package/src/elements/Run.ts +3068 -0
  261. package/src/elements/Section.ts +1421 -0
  262. package/src/elements/Shape.ts +873 -0
  263. package/src/elements/StructuredDocumentTag.ts +978 -0
  264. package/src/elements/Table.ts +2524 -0
  265. package/src/elements/TableCell.ts +1586 -0
  266. package/src/elements/TableGridChange.ts +151 -0
  267. package/src/elements/TableOfContents.ts +691 -0
  268. package/src/elements/TableOfContentsElement.ts +89 -0
  269. package/src/elements/TableRow.ts +906 -0
  270. package/src/elements/TextBox.ts +768 -0
  271. package/src/formatting/AbstractNumbering.ts +548 -0
  272. package/src/formatting/CLAUDE.md +74 -0
  273. package/src/formatting/NumberingInstance.ts +212 -0
  274. package/src/formatting/NumberingLevel.ts +1006 -0
  275. package/src/formatting/NumberingManager.ts +827 -0
  276. package/src/formatting/Style.ts +1833 -0
  277. package/src/formatting/StylesManager.ts +1005 -0
  278. package/src/helpers/CleanupHelper.ts +524 -0
  279. package/src/images/ImageOptimizer.ts +274 -0
  280. package/src/index.ts +554 -0
  281. package/src/managers/CLAUDE.md +47 -0
  282. package/src/managers/DrawingManager.ts +319 -0
  283. package/src/tracking/DocumentTrackingContext.ts +643 -0
  284. package/src/tracking/TrackingContext.ts +173 -0
  285. package/src/types/compatibility-types.ts +49 -0
  286. package/src/types/formatting.ts +210 -0
  287. package/src/types/list-types.ts +152 -0
  288. package/src/types/settings-types.ts +59 -0
  289. package/src/types/styleConfig.ts +189 -0
  290. package/src/utils/CLAUDE.md +153 -0
  291. package/src/utils/ChangelogGenerator.ts +1581 -0
  292. package/src/utils/CompatibilityUpgrader.ts +237 -0
  293. package/src/utils/InMemoryRevisionAcceptor.ts +668 -0
  294. package/src/utils/MoveOperationHelper.ts +238 -0
  295. package/src/utils/RevisionAwareProcessor.ts +526 -0
  296. package/src/utils/RevisionWalker.ts +457 -0
  297. package/src/utils/SelectiveRevisionAcceptor.ts +613 -0
  298. package/src/utils/ShadingResolver.ts +107 -0
  299. package/src/utils/acceptRevisions.ts +714 -0
  300. package/src/utils/cnfStyleDecoder.ts +217 -0
  301. package/src/utils/corruptionDetection.ts +345 -0
  302. package/src/utils/dateFormatting.ts +20 -0
  303. package/src/utils/deepClone.ts +78 -0
  304. package/src/utils/diagnostics.ts +129 -0
  305. package/src/utils/errorHandling.ts +80 -0
  306. package/src/utils/formatting.ts +213 -0
  307. package/src/utils/list-detection.ts +274 -0
  308. package/src/utils/logger.ts +404 -0
  309. package/src/utils/parsingHelpers.ts +190 -0
  310. package/src/utils/stripTrackedChanges.ts +353 -0
  311. package/src/utils/textDiff.ts +100 -0
  312. package/src/utils/units.ts +421 -0
  313. package/src/utils/validation.ts +542 -0
  314. package/src/utils/xmlSanitization.ts +182 -0
  315. package/src/validation/RevisionAutoFixer.ts +542 -0
  316. package/src/validation/RevisionValidator.ts +460 -0
  317. package/src/validation/ValidationRules.ts +338 -0
  318. package/src/validation/index.ts +30 -0
  319. package/src/xml/CLAUDE.md +65 -0
  320. package/src/xml/XMLBuilder.ts +871 -0
  321. package/src/xml/XMLParser.ts +919 -0
  322. package/src/zip/CLAUDE.md +55 -0
  323. package/src/zip/ZipHandler.ts +637 -0
  324. package/src/zip/ZipReader.ts +299 -0
  325. package/src/zip/ZipWriter.ts +390 -0
  326. package/src/zip/errors.ts +69 -0
  327. package/src/zip/types.ts +116 -0
  328. package/dist/core/ListNormalizer.d.ts +0 -23
  329. package/dist/core/ListNormalizer.d.ts.map +0 -1
  330. package/dist/core/ListNormalizer.js +0 -624
  331. package/dist/core/ListNormalizer.js.map +0 -1
  332. package/dist/images/index.d.ts +0 -2
  333. package/dist/images/index.d.ts.map +0 -1
  334. package/dist/images/index.js +0 -8
  335. package/dist/images/index.js.map +0 -1
  336. package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
  337. package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
  338. package/dist/ms-doc/cfb/CFBReader.js +0 -360
  339. package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
  340. package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
  341. package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
  342. package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
  343. package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
  344. package/dist/ms-doc/fib/FIB.d.ts +0 -18
  345. package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
  346. package/dist/ms-doc/fib/FIB.js +0 -342
  347. package/dist/ms-doc/fib/FIB.js.map +0 -1
  348. package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
  349. package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
  350. package/dist/ms-doc/fields/FieldParser.js +0 -266
  351. package/dist/ms-doc/fields/FieldParser.js.map +0 -1
  352. package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
  353. package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
  354. package/dist/ms-doc/images/PictureExtractor.js +0 -233
  355. package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
  356. package/dist/ms-doc/index.d.ts +0 -20
  357. package/dist/ms-doc/index.d.ts.map +0 -1
  358. package/dist/ms-doc/index.js +0 -59
  359. package/dist/ms-doc/index.js.map +0 -1
  360. package/dist/ms-doc/properties/SPRM.d.ts +0 -210
  361. package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
  362. package/dist/ms-doc/properties/SPRM.js +0 -633
  363. package/dist/ms-doc/properties/SPRM.js.map +0 -1
  364. package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
  365. package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
  366. package/dist/ms-doc/sections/SectionParser.js +0 -214
  367. package/dist/ms-doc/sections/SectionParser.js.map +0 -1
  368. package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
  369. package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
  370. package/dist/ms-doc/styles/StyleSheet.js +0 -268
  371. package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
  372. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
  373. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
  374. package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
  375. package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
  376. package/dist/ms-doc/tables/TableParser.d.ts +0 -29
  377. package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
  378. package/dist/ms-doc/tables/TableParser.js +0 -176
  379. package/dist/ms-doc/tables/TableParser.js.map +0 -1
  380. package/dist/ms-doc/text/PieceTable.d.ts +0 -21
  381. package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
  382. package/dist/ms-doc/text/PieceTable.js +0 -171
  383. package/dist/ms-doc/text/PieceTable.js.map +0 -1
  384. package/dist/ms-doc/types/Constants.d.ts +0 -99
  385. package/dist/ms-doc/types/Constants.d.ts.map +0 -1
  386. package/dist/ms-doc/types/Constants.js +0 -102
  387. package/dist/ms-doc/types/Constants.js.map +0 -1
  388. package/dist/ms-doc/types/DocTypes.d.ts +0 -368
  389. package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
  390. package/dist/ms-doc/types/DocTypes.js +0 -3
  391. package/dist/ms-doc/types/DocTypes.js.map +0 -1
  392. package/dist/tracking/index.d.ts +0 -3
  393. package/dist/tracking/index.d.ts.map +0 -1
  394. package/dist/tracking/index.js +0 -6
  395. package/dist/tracking/index.js.map +0 -1
@@ -0,0 +1,1233 @@
1
+ /**
2
+ * Field - Represents a dynamic field in a Word document
3
+ *
4
+ * Fields are used for dynamic content like page numbers, dates, document properties, etc.
5
+ * They are represented using the <w:fldSimple> element with field codes.
6
+ */
7
+
8
+ import { XMLElement } from '../xml/XMLBuilder';
9
+ import { RunFormatting, FormFieldData } from './Run';
10
+ import { ParsedHyperlinkInstruction, parseHyperlinkInstruction, isHyperlinkInstruction } from './FieldHelpers';
11
+ import type { Revision } from './Revision';
12
+ import { pointsToHalfPoints } from '../utils/units';
13
+
14
+ /**
15
+ * Common field types
16
+ */
17
+ export type FieldType =
18
+ | 'PAGE' // Current page number
19
+ | 'NUMPAGES' // Total number of pages
20
+ | 'DATE' // Current date
21
+ | 'TIME' // Current time
22
+ | 'AUTHOR' // Document author
23
+ | 'TITLE' // Document title
24
+ | 'FILENAME' // Document filename
25
+ | 'FILENAMEWITHPATH' // Document filename with path
26
+ | 'SUBJECT' // Document subject
27
+ | 'KEYWORDS' // Document keywords
28
+ | 'CREATEDATE' // Document creation date
29
+ | 'SAVEDATE' // Last save date
30
+ | 'PRINTDATE' // Last print date
31
+ | 'SECTIONPAGES' // Pages in current section
32
+ | 'SECTION' // Current section number
33
+ | 'REF' // Cross-reference to bookmark
34
+ | 'HYPERLINK' // Hyperlink field
35
+ | 'SEQ' // Sequence numbering
36
+ | 'TC' // Table of contents entry
37
+ | 'XE' // Index entry
38
+ | 'IF' // Conditional field
39
+ | 'MERGEFIELD' // Mail merge field
40
+ | 'INCLUDE' // Include text from external file
41
+ | 'INCLUDETEXT' // Include text from external file (alias)
42
+ | 'CUSTOM'; // Custom field type for unknown/specialized fields
43
+
44
+ /**
45
+ * Field properties
46
+ */
47
+ export interface FieldProperties {
48
+ /** Field type */
49
+ type: FieldType;
50
+ /** Field instruction (e.g., 'PAGE \* MERGEFORMAT') */
51
+ instruction?: string;
52
+ /** Format switches (e.g., '\\* MERGEFORMAT') */
53
+ format?: string;
54
+ /** Date/time format (e.g., 'MMMM d, yyyy') */
55
+ dateFormat?: string;
56
+ /** Preserve formatting during updates */
57
+ preserveFormatting?: boolean;
58
+ /** Run formatting for field result */
59
+ formatting?: RunFormatting;
60
+ }
61
+
62
+ /**
63
+ * Represents a dynamic field
64
+ */
65
+ export class Field {
66
+ private type: FieldType;
67
+ private instruction: string;
68
+ private formatting?: RunFormatting;
69
+
70
+ /**
71
+ * Creates a new field
72
+ * @param properties Field properties
73
+ */
74
+ constructor(properties: FieldProperties) {
75
+ this.type = properties.type;
76
+ this.formatting = properties.formatting;
77
+
78
+ // Build field instruction
79
+ if (properties.instruction) {
80
+ this.instruction = properties.instruction;
81
+ } else {
82
+ this.instruction = this.buildInstruction(properties);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Builds field instruction from properties
88
+ */
89
+ private buildInstruction(properties: FieldProperties): string {
90
+ let instruction = properties.type;
91
+
92
+ // Add date format for date/time fields
93
+ if (properties.dateFormat && this.isDateField(properties.type)) {
94
+ instruction += ` \\@ "${properties.dateFormat}"`;
95
+ }
96
+
97
+ // Add format switch
98
+ if (properties.format) {
99
+ instruction += ` ${properties.format}`;
100
+ } else if (properties.preserveFormatting !== false) {
101
+ // Add MERGEFORMAT by default to preserve formatting
102
+ instruction += ' \\* MERGEFORMAT';
103
+ }
104
+
105
+ return instruction;
106
+ }
107
+
108
+ /**
109
+ * Checks if field type is a date field
110
+ */
111
+ private isDateField(type: FieldType): boolean {
112
+ return ['DATE', 'TIME', 'CREATEDATE', 'SAVEDATE', 'PRINTDATE'].includes(type);
113
+ }
114
+
115
+ /**
116
+ * Gets the field type
117
+ */
118
+ getType(): FieldType {
119
+ return this.type;
120
+ }
121
+
122
+ /**
123
+ * Gets the field instruction
124
+ */
125
+ getInstruction(): string {
126
+ return this.instruction;
127
+ }
128
+
129
+ /**
130
+ * Sets run formatting for the field
131
+ */
132
+ setFormatting(formatting: RunFormatting): this {
133
+ this.formatting = formatting;
134
+ return this;
135
+ }
136
+
137
+ /**
138
+ * Gets run formatting
139
+ */
140
+ getFormatting(): RunFormatting | undefined {
141
+ return this.formatting;
142
+ }
143
+
144
+ /**
145
+ * Checks if this field is a HYPERLINK field
146
+ * @returns True if the field type is HYPERLINK or instruction starts with HYPERLINK
147
+ */
148
+ isHyperlinkField(): boolean {
149
+ return this.type === 'HYPERLINK' ||
150
+ this.instruction.trim().toUpperCase().startsWith('HYPERLINK');
151
+ }
152
+
153
+ /**
154
+ * Sets text color for the field
155
+ * @param color Color in hex format (e.g., '0000FF')
156
+ * @returns This field for chaining
157
+ */
158
+ setColor(color: string): this {
159
+ if (!this.formatting) {
160
+ this.formatting = {};
161
+ }
162
+ this.formatting.color = color.replace('#', '');
163
+ return this;
164
+ }
165
+
166
+ /**
167
+ * Generates XML for the field.
168
+ * Per ECMA-376, w:fldSimple is a paragraph-level element that CONTAINS w:r children.
169
+ * Structure: <w:fldSimple w:instr="..."><w:r><w:rPr/><w:t>...</w:t></w:r></w:fldSimple>
170
+ * The fldSimple element should be added directly to paragraph children (not wrapped in w:r).
171
+ */
172
+ toXML(): XMLElement {
173
+ // Build the inner run with optional formatting
174
+ const runChildren: XMLElement[] = [];
175
+ if (this.formatting) {
176
+ runChildren.push(this.createRunProperties());
177
+ }
178
+ runChildren.push({
179
+ name: 'w:t',
180
+ children: [this.getPlaceholderText()],
181
+ });
182
+
183
+ return {
184
+ name: 'w:fldSimple',
185
+ attributes: {
186
+ 'w:instr': this.instruction,
187
+ },
188
+ children: [{
189
+ name: 'w:r',
190
+ children: runChildren,
191
+ }],
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Gets placeholder text for the field
197
+ */
198
+ private getPlaceholderText(): string {
199
+ switch (this.type) {
200
+ case 'PAGE':
201
+ return '1';
202
+ case 'NUMPAGES':
203
+ return '1';
204
+ case 'SECTIONPAGES':
205
+ return '1';
206
+ case 'SECTION':
207
+ return '1';
208
+ case 'DATE':
209
+ return new Date().toLocaleDateString();
210
+ case 'TIME':
211
+ return new Date().toLocaleTimeString();
212
+ case 'CREATEDATE':
213
+ case 'SAVEDATE':
214
+ case 'PRINTDATE':
215
+ return new Date().toLocaleDateString();
216
+ case 'FILENAME':
217
+ return 'Document';
218
+ case 'FILENAMEWITHPATH':
219
+ return 'C:\\Document.docx';
220
+ case 'AUTHOR':
221
+ return 'Author';
222
+ case 'TITLE':
223
+ return 'Title';
224
+ case 'SUBJECT':
225
+ return 'Subject';
226
+ case 'KEYWORDS':
227
+ return 'Keywords';
228
+ case 'REF':
229
+ return '1'; // Reference typically shows page number or heading text
230
+ case 'HYPERLINK':
231
+ return 'Link'; // Hyperlink displays the link text
232
+ case 'SEQ':
233
+ return '1'; // Sequence shows the current number
234
+ case 'TC':
235
+ return ''; // TC fields are hidden
236
+ case 'XE':
237
+ return ''; // XE fields are hidden
238
+ default:
239
+ return '';
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Creates run properties XML
245
+ */
246
+ private createRunProperties(): XMLElement {
247
+ const children: XMLElement[] = [];
248
+
249
+ if (!this.formatting) {
250
+ return { name: 'w:rPr', children };
251
+ }
252
+
253
+ // Per ECMA-376 CT_RPr ordering:
254
+ // rFonts → b → i → strike → color → sz/szCs → highlight → u
255
+
256
+ if (this.formatting.font) {
257
+ children.push({
258
+ name: 'w:rFonts',
259
+ attributes: {
260
+ 'w:ascii': this.formatting.font,
261
+ 'w:hAnsi': this.formatting.font,
262
+ 'w:cs': this.formatting.font,
263
+ },
264
+ selfClosing: true,
265
+ });
266
+ }
267
+
268
+ if (this.formatting.bold) {
269
+ children.push({ name: 'w:b', selfClosing: true });
270
+ }
271
+
272
+ if (this.formatting.italic) {
273
+ children.push({ name: 'w:i', selfClosing: true });
274
+ }
275
+
276
+ if (this.formatting.strike) {
277
+ children.push({ name: 'w:strike', selfClosing: true });
278
+ }
279
+
280
+ if (this.formatting.color) {
281
+ const color = this.formatting.color.replace('#', '');
282
+ children.push({
283
+ name: 'w:color',
284
+ attributes: { 'w:val': color },
285
+ selfClosing: true,
286
+ });
287
+ }
288
+
289
+ if (this.formatting.size) {
290
+ const sizeValue = pointsToHalfPoints(this.formatting.size).toString();
291
+ children.push({
292
+ name: 'w:sz',
293
+ attributes: { 'w:val': sizeValue },
294
+ selfClosing: true,
295
+ });
296
+ children.push({
297
+ name: 'w:szCs',
298
+ attributes: { 'w:val': sizeValue },
299
+ selfClosing: true,
300
+ });
301
+ }
302
+
303
+ if (this.formatting.highlight) {
304
+ children.push({
305
+ name: 'w:highlight',
306
+ attributes: { 'w:val': this.formatting.highlight },
307
+ selfClosing: true,
308
+ });
309
+ }
310
+
311
+ if (this.formatting.underline) {
312
+ const val = typeof this.formatting.underline === 'string'
313
+ ? this.formatting.underline
314
+ : 'single';
315
+ children.push({
316
+ name: 'w:u',
317
+ attributes: { 'w:val': val },
318
+ selfClosing: true,
319
+ });
320
+ }
321
+
322
+ return { name: 'w:rPr', children };
323
+ }
324
+
325
+ /**
326
+ * Creates a page number field
327
+ * @param formatting Optional run formatting
328
+ */
329
+ static createPageNumber(formatting?: RunFormatting): Field {
330
+ return new Field({
331
+ type: 'PAGE',
332
+ formatting,
333
+ });
334
+ }
335
+
336
+ /**
337
+ * Creates a total pages field
338
+ * @param formatting Optional run formatting
339
+ */
340
+ static createTotalPages(formatting?: RunFormatting): Field {
341
+ return new Field({
342
+ type: 'NUMPAGES',
343
+ formatting,
344
+ });
345
+ }
346
+
347
+ /**
348
+ * Creates a date field
349
+ * @param format Date format (e.g., 'MMMM d, yyyy')
350
+ * @param formatting Optional run formatting
351
+ */
352
+ static createDate(format?: string, formatting?: RunFormatting): Field {
353
+ return new Field({
354
+ type: 'DATE',
355
+ dateFormat: format,
356
+ formatting,
357
+ });
358
+ }
359
+
360
+ /**
361
+ * Creates a time field
362
+ * @param format Time format
363
+ * @param formatting Optional run formatting
364
+ */
365
+ static createTime(format?: string, formatting?: RunFormatting): Field {
366
+ return new Field({
367
+ type: 'TIME',
368
+ dateFormat: format,
369
+ formatting,
370
+ });
371
+ }
372
+
373
+ /**
374
+ * Creates a filename field
375
+ * @param includePath Whether to include full path
376
+ * @param formatting Optional run formatting
377
+ */
378
+ static createFilename(includePath = false, formatting?: RunFormatting): Field {
379
+ return new Field({
380
+ type: includePath ? 'FILENAMEWITHPATH' : 'FILENAME',
381
+ formatting,
382
+ });
383
+ }
384
+
385
+ /**
386
+ * Creates an author field
387
+ * @param formatting Optional run formatting
388
+ */
389
+ static createAuthor(formatting?: RunFormatting): Field {
390
+ return new Field({
391
+ type: 'AUTHOR',
392
+ formatting,
393
+ });
394
+ }
395
+
396
+ /**
397
+ * Creates a title field
398
+ * @param formatting Optional run formatting
399
+ */
400
+ static createTitle(formatting?: RunFormatting): Field {
401
+ return new Field({
402
+ type: 'TITLE',
403
+ formatting,
404
+ });
405
+ }
406
+
407
+ /**
408
+ * Creates a section pages field (pages in current section)
409
+ * @param formatting Optional run formatting
410
+ */
411
+ static createSectionPages(formatting?: RunFormatting): Field {
412
+ return new Field({
413
+ type: 'SECTIONPAGES',
414
+ formatting,
415
+ });
416
+ }
417
+
418
+ /**
419
+ * Creates a cross-reference field
420
+ * @param bookmark Bookmark name to reference
421
+ * @param format Reference format (\h for hyperlink, \p for page number, etc.)
422
+ * @param formatting Optional run formatting
423
+ */
424
+ static createRef(bookmark: string, format?: string, formatting?: RunFormatting): Field {
425
+ const formatSwitch = format || '\\h'; // Default to hyperlink format
426
+ const instruction = `REF ${bookmark} ${formatSwitch} \\* MERGEFORMAT`;
427
+
428
+ return new Field({
429
+ type: 'REF',
430
+ instruction,
431
+ formatting,
432
+ });
433
+ }
434
+
435
+ /**
436
+ * Creates a hyperlink field
437
+ * @param url The URL to link to
438
+ * @param displayText The text to display
439
+ * @param tooltip Optional tooltip text
440
+ * @param formatting Optional run formatting
441
+ */
442
+ static createHyperlink(
443
+ url: string,
444
+ displayText: string = url,
445
+ tooltip?: string,
446
+ formatting?: RunFormatting
447
+ ): Field {
448
+ let instruction = `HYPERLINK "${url}"`;
449
+
450
+ if (tooltip) {
451
+ instruction += ` \\o "${tooltip}"`;
452
+ }
453
+
454
+ instruction += ' \\* MERGEFORMAT';
455
+
456
+ return new Field({
457
+ type: 'HYPERLINK',
458
+ instruction,
459
+ formatting,
460
+ });
461
+ }
462
+
463
+ /**
464
+ * Creates a sequence numbering field
465
+ * @param identifier Sequence identifier (e.g., 'Figure', 'Table')
466
+ * @param format Number format (\* ARABIC, \* ROMAN, etc.)
467
+ * @param formatting Optional run formatting
468
+ */
469
+ static createSeq(
470
+ identifier: string,
471
+ format?: string,
472
+ formatting?: RunFormatting
473
+ ): Field {
474
+ let instruction = `SEQ ${identifier}`;
475
+
476
+ if (format) {
477
+ instruction += ` ${format}`;
478
+ } else {
479
+ instruction += ' \\* ARABIC'; // Default to Arabic numerals
480
+ }
481
+
482
+ instruction += ' \\* MERGEFORMAT';
483
+
484
+ return new Field({
485
+ type: 'SEQ',
486
+ instruction,
487
+ formatting,
488
+ });
489
+ }
490
+
491
+ /**
492
+ * Creates a table of contents entry field (TC)
493
+ * @param text Entry text
494
+ * @param level TOC level (1-9)
495
+ * @param formatting Optional run formatting
496
+ */
497
+ static createTCEntry(
498
+ text: string,
499
+ level = 1,
500
+ formatting?: RunFormatting
501
+ ): Field {
502
+ if (level < 1 || level > 9) {
503
+ throw new Error('TC level must be between 1 and 9');
504
+ }
505
+
506
+ const instruction = `TC "${text}" \\f C \\l ${level}`;
507
+
508
+ return new Field({
509
+ type: 'TC',
510
+ instruction,
511
+ formatting,
512
+ });
513
+ }
514
+
515
+ /**
516
+ * Creates an index entry field (XE)
517
+ * @param text Entry text
518
+ * @param subEntry Optional sub-entry text
519
+ * @param formatting Optional run formatting
520
+ */
521
+ static createXEEntry(
522
+ text: string,
523
+ subEntry?: string,
524
+ formatting?: RunFormatting
525
+ ): Field {
526
+ let instruction = `XE "${text}"`;
527
+
528
+ if (subEntry) {
529
+ instruction += `:${subEntry}`;
530
+ }
531
+
532
+ return new Field({
533
+ type: 'XE',
534
+ instruction,
535
+ formatting,
536
+ });
537
+ }
538
+
539
+ /**
540
+ * Creates a custom field with instruction
541
+ * @param instruction Field instruction code
542
+ * @param formatting Optional run formatting
543
+ */
544
+ static createCustom(instruction: string, formatting?: RunFormatting): Field {
545
+ return new Field({
546
+ type: 'PAGE', // Placeholder type
547
+ instruction,
548
+ formatting,
549
+ });
550
+ }
551
+
552
+ /**
553
+ * Creates a field from properties
554
+ * @param properties Field properties
555
+ */
556
+ static create(properties: FieldProperties): Field {
557
+ return new Field(properties);
558
+ }
559
+ }
560
+
561
+ /**
562
+ * Field character type for complex fields
563
+ */
564
+ export type FieldCharType = 'begin' | 'separate' | 'end';
565
+
566
+ /**
567
+ * Complex field properties
568
+ * Complex fields use begin/separate/end structure instead of fldSimple
569
+ */
570
+ export interface ComplexFieldProperties {
571
+ /** Field instruction (e.g., " TOC \\o \"1-3\" \\h \\z \\u ") */
572
+ instruction: string;
573
+
574
+ /** Current field result text (optional) */
575
+ result?: string;
576
+
577
+ /** Run formatting for instruction */
578
+ instructionFormatting?: RunFormatting;
579
+
580
+ /** Run formatting for result */
581
+ resultFormatting?: RunFormatting;
582
+
583
+ /** Nested fields to include within this field */
584
+ nestedFields?: ComplexField[];
585
+
586
+ /** Custom XML content for result section */
587
+ resultContent?: XMLElement[];
588
+
589
+ /** Whether field spans multiple paragraphs */
590
+ multiParagraph?: boolean;
591
+
592
+ /** Parsed HYPERLINK instruction components (auto-populated if instruction is HYPERLINK) */
593
+ parsedHyperlink?: ParsedHyperlinkInstruction;
594
+
595
+ /**
596
+ * Whether the field has a result section (w:fldSep was present during parsing)
597
+ * Per ECMA-376, fields without results skip the separator element.
598
+ * This flag distinguishes between:
599
+ * - hasResult=true, result="" → Field had separator but result was empty
600
+ * - hasResult=false, result="" → Field never had a result section (empty field)
601
+ */
602
+ hasResult?: boolean;
603
+
604
+ /** Form field data (w:ffData) from begin field char per ECMA-376 §17.16.17 */
605
+ formFieldData?: FormFieldData;
606
+ }
607
+
608
+ /**
609
+ * Represents a complex field (begin/separate/end structure)
610
+ * Used for TOC, cross-references, and other advanced fields
611
+ *
612
+ * Structure:
613
+ * <w:r><w:fldChar w:fldCharType="begin"/></w:r>
614
+ * <w:r><w:instrText>INSTRUCTION</w:instrText></w:r>
615
+ * <w:r><w:fldChar w:fldCharType="separate"/></w:r>
616
+ * <w:r><w:t>RESULT</w:t></w:r>
617
+ * <w:r><w:fldChar w:fldCharType="end"/></w:r>
618
+ */
619
+ export class ComplexField {
620
+ private instruction: string;
621
+ private result?: string;
622
+ private instructionFormatting?: RunFormatting;
623
+ private resultFormatting?: RunFormatting;
624
+ private nestedFields: ComplexField[];
625
+ private resultContent: XMLElement[];
626
+ private multiParagraph: boolean;
627
+ private parsedHyperlink?: ParsedHyperlinkInstruction;
628
+ /** Revisions that wrap the result section (for tracked changes in field content) */
629
+ private resultRevisions: Revision[] = [];
630
+ /**
631
+ * Whether the field has a result section (w:fldSep was present during parsing)
632
+ * Per ECMA-376, fields without results skip the separator element.
633
+ */
634
+ private _hasResultSection = false;
635
+ private _formFieldData?: FormFieldData;
636
+
637
+ /**
638
+ * Creates a new complex field
639
+ * @param properties Complex field properties
640
+ */
641
+ constructor(properties: ComplexFieldProperties) {
642
+ this.instruction = properties.instruction;
643
+ this.result = properties.result;
644
+ this.instructionFormatting = properties.instructionFormatting;
645
+ this.resultFormatting = properties.resultFormatting;
646
+ this.nestedFields = properties.nestedFields || [];
647
+ this.resultContent = properties.resultContent || [];
648
+ this.multiParagraph = properties.multiParagraph || false;
649
+ this._hasResultSection = properties.hasResult ?? false;
650
+ this._formFieldData = properties.formFieldData;
651
+
652
+ // Auto-parse HYPERLINK instruction if provided or detected
653
+ if (properties.parsedHyperlink) {
654
+ this.parsedHyperlink = properties.parsedHyperlink;
655
+ } else if (isHyperlinkInstruction(this.instruction)) {
656
+ this.parsedHyperlink = parseHyperlinkInstruction(this.instruction) || undefined;
657
+ }
658
+ }
659
+
660
+ /**
661
+ * Gets the field instruction
662
+ */
663
+ getInstruction(): string {
664
+ return this.instruction;
665
+ }
666
+
667
+ /**
668
+ * Sets the field instruction
669
+ */
670
+ setInstruction(instruction: string): this {
671
+ this.instruction = instruction;
672
+ return this;
673
+ }
674
+
675
+ /**
676
+ * Gets form field data (w:ffData) if present
677
+ */
678
+ getFormFieldData(): FormFieldData | undefined {
679
+ return this._formFieldData;
680
+ }
681
+
682
+ /**
683
+ * Gets the field result text
684
+ */
685
+ getResult(): string | undefined {
686
+ return this.result;
687
+ }
688
+
689
+ /**
690
+ * Sets the field result text
691
+ */
692
+ setResult(result: string): this {
693
+ this.result = result;
694
+ return this;
695
+ }
696
+
697
+ /**
698
+ * Checks if the field has a result section
699
+ *
700
+ * Per ECMA-376, complex fields may or may not have a result section.
701
+ * Fields without results (like TOC markers or empty PAGE fields) skip
702
+ * the w:fldSep (separator) element entirely.
703
+ *
704
+ * This method distinguishes between:
705
+ * - `hasResultSection() === true && getResult() === ""` → Field had separator but result was empty
706
+ * - `hasResultSection() === false && getResult() === undefined` → Field never had a result section
707
+ *
708
+ * @returns True if the field has a result section (w:fldSep was present)
709
+ *
710
+ * @example
711
+ * ```typescript
712
+ * const field = paragraph.getFields()[0];
713
+ * if (field instanceof ComplexField) {
714
+ * if (field.hasResultSection()) {
715
+ * console.log('Field result:', field.getResult());
716
+ * } else {
717
+ * console.log('Field has no result section (empty field)');
718
+ * }
719
+ * }
720
+ * ```
721
+ */
722
+ hasResultSection(): boolean {
723
+ return this._hasResultSection;
724
+ }
725
+
726
+ /**
727
+ * Sets instruction formatting
728
+ */
729
+ setInstructionFormatting(formatting: RunFormatting): this {
730
+ this.instructionFormatting = formatting;
731
+ return this;
732
+ }
733
+
734
+ /**
735
+ * Sets result formatting
736
+ */
737
+ setResultFormatting(formatting: RunFormatting): this {
738
+ this.resultFormatting = formatting;
739
+ return this;
740
+ }
741
+
742
+ /**
743
+ * Gets the parsed HYPERLINK instruction components
744
+ * Returns undefined if this is not a HYPERLINK field
745
+ */
746
+ getParsedHyperlink(): ParsedHyperlinkInstruction | undefined {
747
+ return this.parsedHyperlink;
748
+ }
749
+
750
+ /**
751
+ * Checks if this field is a HYPERLINK field
752
+ */
753
+ isHyperlinkField(): boolean {
754
+ return this.parsedHyperlink !== undefined;
755
+ }
756
+
757
+ /**
758
+ * Gets the full URL for HYPERLINK fields (combining base URL and anchor)
759
+ * Returns undefined if not a HYPERLINK field
760
+ */
761
+ getHyperlinkUrl(): string | undefined {
762
+ return this.parsedHyperlink?.fullUrl;
763
+ }
764
+
765
+ /**
766
+ * Adds a nested field within this field
767
+ * Nested fields appear between instruction and separator
768
+ */
769
+ addNestedField(field: ComplexField): this {
770
+ this.nestedFields.push(field);
771
+ return this;
772
+ }
773
+
774
+ /**
775
+ * Gets all nested fields
776
+ */
777
+ getNestedFields(): ComplexField[] {
778
+ return [...this.nestedFields];
779
+ }
780
+
781
+ /**
782
+ * Removes a nested field at the specified index
783
+ * @param index - Index of the nested field to remove (0-based)
784
+ * @returns True if removed, false if index out of bounds
785
+ *
786
+ * @example
787
+ * ```typescript
788
+ * const field = new ComplexField({ instruction: 'TOC' });
789
+ * field.addNestedField(nested1);
790
+ * field.addNestedField(nested2);
791
+ * field.removeNestedField(0); // Removes nested1
792
+ * ```
793
+ */
794
+ removeNestedField(index: number): boolean {
795
+ if (index < 0 || index >= this.nestedFields.length) {
796
+ return false;
797
+ }
798
+ this.nestedFields.splice(index, 1);
799
+ return true;
800
+ }
801
+
802
+ /**
803
+ * Gets the count of nested fields
804
+ * @returns Number of nested fields
805
+ */
806
+ getNestedFieldCount(): number {
807
+ return this.nestedFields.length;
808
+ }
809
+
810
+ /**
811
+ * Clears all nested fields
812
+ * @returns This field for chaining
813
+ */
814
+ clearNestedFields(): this {
815
+ this.nestedFields = [];
816
+ return this;
817
+ }
818
+
819
+ /**
820
+ * Updates the field instruction
821
+ * @param instruction - New field instruction (e.g., 'TOC \\o "1-3"')
822
+ * @returns This field for chaining
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * const field = new ComplexField({ instruction: 'DATE' });
827
+ * field.updateInstruction('DATE \\@ "yyyy-MM-dd"');
828
+ * ```
829
+ */
830
+ updateInstruction(instruction: string): this {
831
+ this.instruction = instruction;
832
+ return this;
833
+ }
834
+
835
+ /**
836
+ * Adds custom XML content to the result section
837
+ */
838
+ addResultContent(content: XMLElement): this {
839
+ this.resultContent.push(content);
840
+ return this;
841
+ }
842
+
843
+ /**
844
+ * Gets result content XML elements
845
+ */
846
+ getResultContent(): XMLElement[] {
847
+ return [...this.resultContent];
848
+ }
849
+
850
+ /**
851
+ * Sets whether this field spans multiple paragraphs
852
+ */
853
+ setMultiParagraph(multiParagraph: boolean): this {
854
+ this.multiParagraph = multiParagraph;
855
+ return this;
856
+ }
857
+
858
+ /**
859
+ * Gets whether this field spans multiple paragraphs
860
+ */
861
+ isMultiParagraph(): boolean {
862
+ return this.multiParagraph;
863
+ }
864
+
865
+ /**
866
+ * Sets revisions that wrap the result section
867
+ * These are tracked changes (w:ins, w:del) that need to wrap the result AND end marker
868
+ * @param revisions Array of Revision objects
869
+ */
870
+ setResultRevisions(revisions: Revision[]): this {
871
+ this.resultRevisions = revisions;
872
+ return this;
873
+ }
874
+
875
+ /**
876
+ * Adds a revision to the result section
877
+ * @param revision Revision to add
878
+ */
879
+ addResultRevision(revision: Revision): this {
880
+ this.resultRevisions.push(revision);
881
+ return this;
882
+ }
883
+
884
+ /**
885
+ * Gets revisions that wrap the result section
886
+ */
887
+ getResultRevisions(): Revision[] {
888
+ return [...this.resultRevisions];
889
+ }
890
+
891
+ /**
892
+ * Checks if this field has revisions in the result section
893
+ */
894
+ hasResultRevisions(): boolean {
895
+ return this.resultRevisions.length > 0;
896
+ }
897
+
898
+ /**
899
+ * Generates XML for the complex field
900
+ * Returns array of run elements (begin, instr, sep, result, end)
901
+ */
902
+ toXML(): XMLElement[] {
903
+ const runs: XMLElement[] = [];
904
+
905
+ // 1. Begin marker run
906
+ const beginFldChar: XMLElement = this._formFieldData
907
+ ? this.buildFldCharWithFfData()
908
+ : {
909
+ name: 'w:fldChar',
910
+ attributes: { 'w:fldCharType': 'begin' },
911
+ selfClosing: true,
912
+ };
913
+ runs.push({
914
+ name: 'w:r',
915
+ children: [beginFldChar],
916
+ });
917
+
918
+ // 2. Instruction run
919
+ const instrChildren: XMLElement[] = [];
920
+ if (this.instructionFormatting) {
921
+ instrChildren.push(this.createRunProperties(this.instructionFormatting));
922
+ }
923
+ instrChildren.push({
924
+ name: 'w:instrText',
925
+ attributes: { 'xml:space': 'preserve' },
926
+ children: [this.instruction],
927
+ });
928
+ runs.push({
929
+ name: 'w:r',
930
+ children: instrChildren,
931
+ });
932
+
933
+ // 2a. Nested fields (if any)
934
+ for (const nestedField of this.nestedFields) {
935
+ runs.push(...nestedField.toXML());
936
+ }
937
+
938
+ // 3. Separator run
939
+ runs.push({
940
+ name: 'w:r',
941
+ children: [
942
+ {
943
+ name: 'w:fldChar',
944
+ attributes: { 'w:fldCharType': 'separate' },
945
+ selfClosing: true,
946
+ },
947
+ ],
948
+ });
949
+
950
+ // 4. Result content (prioritize custom XML content, then simple text)
951
+ // Design note: For INCLUDEPICTURE fields, the parser stores the w:drawing
952
+ // content in resultContent so it survives the parser→generator round-trip.
953
+ // When flattenFieldCodes() is active, the full field structure is emitted
954
+ // here, then _postProcessDocumentXml() strips the INCLUDEPICTURE scaffolding
955
+ // (fldChar/instrText runs) from the final XML while preserving the drawing.
956
+ // Non-INCLUDEPICTURE fields emit their complete structure unchanged.
957
+ if (this.resultContent.length > 0) {
958
+ // Use custom XML content
959
+ runs.push(...this.resultContent);
960
+ } else if (this.result) {
961
+ // Use simple text result
962
+ const resultChildren: XMLElement[] = [];
963
+ if (this.resultFormatting) {
964
+ resultChildren.push(this.createRunProperties(this.resultFormatting));
965
+ }
966
+ resultChildren.push({
967
+ name: 'w:t',
968
+ attributes: { 'xml:space': 'preserve' },
969
+ children: [this.result],
970
+ });
971
+ runs.push({
972
+ name: 'w:r',
973
+ children: resultChildren,
974
+ });
975
+ }
976
+
977
+ // 4a. Result revisions (tracked changes within the result section)
978
+ // These MUST appear between the separator and end marker per ECMA-376
979
+ // The revisions contain the actual field result content wrapped in w:ins or w:del
980
+ for (const revision of this.resultRevisions) {
981
+ const revisionXml = revision.toXML();
982
+ if (revisionXml) {
983
+ runs.push(revisionXml);
984
+ }
985
+ }
986
+
987
+ // 5. End marker run
988
+ runs.push({
989
+ name: 'w:r',
990
+ children: [
991
+ {
992
+ name: 'w:fldChar',
993
+ attributes: { 'w:fldCharType': 'end' },
994
+ selfClosing: true,
995
+ },
996
+ ],
997
+ });
998
+
999
+ return runs;
1000
+ }
1001
+
1002
+ /**
1003
+ * Creates run properties XML from formatting
1004
+ */
1005
+ private createRunProperties(formatting: RunFormatting): XMLElement {
1006
+ const children: XMLElement[] = [];
1007
+
1008
+ if (formatting.bold) {
1009
+ children.push({ name: 'w:b', selfClosing: true });
1010
+ }
1011
+
1012
+ if (formatting.italic) {
1013
+ children.push({ name: 'w:i', selfClosing: true });
1014
+ }
1015
+
1016
+ if (formatting.underline) {
1017
+ const val =
1018
+ typeof formatting.underline === 'string'
1019
+ ? formatting.underline
1020
+ : 'single';
1021
+ children.push({
1022
+ name: 'w:u',
1023
+ attributes: { 'w:val': val },
1024
+ selfClosing: true,
1025
+ });
1026
+ }
1027
+
1028
+ if (formatting.strike) {
1029
+ children.push({ name: 'w:strike', selfClosing: true });
1030
+ }
1031
+
1032
+ if (formatting.font) {
1033
+ children.push({
1034
+ name: 'w:rFonts',
1035
+ attributes: {
1036
+ 'w:ascii': formatting.font,
1037
+ 'w:hAnsi': formatting.font,
1038
+ 'w:cs': formatting.font,
1039
+ },
1040
+ selfClosing: true,
1041
+ });
1042
+ }
1043
+
1044
+ if (formatting.size) {
1045
+ const sizeValue = pointsToHalfPoints(formatting.size).toString();
1046
+ children.push({
1047
+ name: 'w:sz',
1048
+ attributes: { 'w:val': sizeValue },
1049
+ selfClosing: true,
1050
+ });
1051
+ children.push({
1052
+ name: 'w:szCs',
1053
+ attributes: { 'w:val': sizeValue },
1054
+ selfClosing: true,
1055
+ });
1056
+ }
1057
+
1058
+ if (formatting.color) {
1059
+ const color = formatting.color.replace('#', '');
1060
+ children.push({
1061
+ name: 'w:color',
1062
+ attributes: { 'w:val': color },
1063
+ selfClosing: true,
1064
+ });
1065
+ }
1066
+
1067
+ if (formatting.highlight) {
1068
+ children.push({
1069
+ name: 'w:highlight',
1070
+ attributes: { 'w:val': formatting.highlight },
1071
+ selfClosing: true,
1072
+ });
1073
+ }
1074
+
1075
+ return { name: 'w:rPr', children };
1076
+ }
1077
+
1078
+ /**
1079
+ * Builds a w:fldChar begin element with w:ffData child
1080
+ */
1081
+ private buildFldCharWithFfData(): XMLElement {
1082
+ const ffd = this._formFieldData!;
1083
+ const ffDataChildren: (string | XMLElement)[] = [];
1084
+
1085
+ if (ffd.name) {
1086
+ ffDataChildren.push({ name: 'w:name', attributes: { 'w:val': ffd.name }, selfClosing: true });
1087
+ }
1088
+ if (ffd.enabled !== undefined) {
1089
+ if (ffd.enabled) {
1090
+ ffDataChildren.push({ name: 'w:enabled', selfClosing: true });
1091
+ } else {
1092
+ ffDataChildren.push({ name: 'w:enabled', attributes: { 'w:val': '0' }, selfClosing: true });
1093
+ }
1094
+ }
1095
+ if (ffd.calcOnExit !== undefined) {
1096
+ ffDataChildren.push({ name: 'w:calcOnExit', attributes: { 'w:val': ffd.calcOnExit ? '1' : '0' }, selfClosing: true });
1097
+ }
1098
+ if (ffd.helpText) {
1099
+ ffDataChildren.push({ name: 'w:helpText', attributes: { 'w:type': 'text', 'w:val': ffd.helpText }, selfClosing: true });
1100
+ }
1101
+ if (ffd.statusText) {
1102
+ ffDataChildren.push({ name: 'w:statusText', attributes: { 'w:type': 'text', 'w:val': ffd.statusText }, selfClosing: true });
1103
+ }
1104
+ if (ffd.entryMacro) {
1105
+ ffDataChildren.push({ name: 'w:entryMacro', attributes: { 'w:val': ffd.entryMacro }, selfClosing: true });
1106
+ }
1107
+ if (ffd.exitMacro) {
1108
+ ffDataChildren.push({ name: 'w:exitMacro', attributes: { 'w:val': ffd.exitMacro }, selfClosing: true });
1109
+ }
1110
+
1111
+ if (ffd.fieldType) {
1112
+ switch (ffd.fieldType.type) {
1113
+ case 'textInput': {
1114
+ const tiChildren: (string | XMLElement)[] = [];
1115
+ if (ffd.fieldType.inputType) tiChildren.push({ name: 'w:type', attributes: { 'w:val': ffd.fieldType.inputType }, selfClosing: true });
1116
+ if (ffd.fieldType.defaultValue) tiChildren.push({ name: 'w:default', attributes: { 'w:val': ffd.fieldType.defaultValue }, selfClosing: true });
1117
+ if (ffd.fieldType.maxLength !== undefined) tiChildren.push({ name: 'w:maxLength', attributes: { 'w:val': String(ffd.fieldType.maxLength) }, selfClosing: true });
1118
+ if (ffd.fieldType.format) tiChildren.push({ name: 'w:format', attributes: { 'w:val': ffd.fieldType.format }, selfClosing: true });
1119
+ ffDataChildren.push({ name: 'w:textInput', children: tiChildren });
1120
+ break;
1121
+ }
1122
+ case 'checkBox': {
1123
+ const cbChildren: (string | XMLElement)[] = [];
1124
+ if (ffd.fieldType.size === 'auto') {
1125
+ cbChildren.push({ name: 'w:sizeAuto', selfClosing: true });
1126
+ } else if (ffd.fieldType.size !== undefined) {
1127
+ cbChildren.push({ name: 'w:size', attributes: { 'w:val': String(ffd.fieldType.size) }, selfClosing: true });
1128
+ }
1129
+ if (ffd.fieldType.defaultChecked !== undefined) cbChildren.push({ name: 'w:default', attributes: { 'w:val': ffd.fieldType.defaultChecked ? '1' : '0' }, selfClosing: true });
1130
+ if (ffd.fieldType.checked !== undefined) cbChildren.push({ name: 'w:checked', attributes: { 'w:val': ffd.fieldType.checked ? '1' : '0' }, selfClosing: true });
1131
+ ffDataChildren.push({ name: 'w:checkBox', children: cbChildren });
1132
+ break;
1133
+ }
1134
+ case 'dropDownList': {
1135
+ const ddChildren: (string | XMLElement)[] = [];
1136
+ if (ffd.fieldType.result !== undefined) ddChildren.push({ name: 'w:result', attributes: { 'w:val': String(ffd.fieldType.result) }, selfClosing: true });
1137
+ if (ffd.fieldType.defaultResult !== undefined) ddChildren.push({ name: 'w:default', attributes: { 'w:val': String(ffd.fieldType.defaultResult) }, selfClosing: true });
1138
+ if (ffd.fieldType.listEntries) {
1139
+ for (const entry of ffd.fieldType.listEntries) {
1140
+ ddChildren.push({ name: 'w:listEntry', attributes: { 'w:val': entry }, selfClosing: true });
1141
+ }
1142
+ }
1143
+ ffDataChildren.push({ name: 'w:ddList', children: ddChildren });
1144
+ break;
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ return {
1150
+ name: 'w:fldChar',
1151
+ attributes: { 'w:fldCharType': 'begin' },
1152
+ children: [{ name: 'w:ffData', children: ffDataChildren }],
1153
+ };
1154
+ }
1155
+ }
1156
+
1157
+ /**
1158
+ * TOC field options
1159
+ */
1160
+ export interface TOCFieldOptions {
1161
+ /** Heading levels to include (e.g., "1-3" for levels 1-3) */
1162
+ levels?: string;
1163
+
1164
+ /** Make entries hyperlinks (\h switch) */
1165
+ hyperlinks?: boolean;
1166
+
1167
+ /** Hide tab leaders and page numbers in Web Layout (\z switch) */
1168
+ hideInWebLayout?: boolean;
1169
+
1170
+ /** Use outline levels (\u switch) */
1171
+ useOutlineLevels?: boolean;
1172
+
1173
+ /** Omit page numbers (\n switch) */
1174
+ omitPageNumbers?: boolean;
1175
+
1176
+ /** Custom styles to use (\t switch) */
1177
+ customStyles?: string;
1178
+ }
1179
+
1180
+ /**
1181
+ * Creates a TOC (Table of Contents) complex field
1182
+ * Generates proper field instruction with switches
1183
+ *
1184
+ * @param options TOC field options
1185
+ * @returns ComplexField configured for TOC
1186
+ *
1187
+ * @example
1188
+ * const toc = createTOCField({ levels: '1-3', hyperlinks: true });
1189
+ * // Generates: TOC \o "1-3" \h \z \u
1190
+ */
1191
+ export function createTOCField(options: TOCFieldOptions = {}): ComplexField {
1192
+ // Build instruction string
1193
+ let instruction = ' TOC';
1194
+
1195
+ // Add outline levels switch
1196
+ if (options.levels !== undefined) {
1197
+ instruction += ` \\o "${options.levels}"`;
1198
+ } else {
1199
+ instruction += ' \\o "1-3"'; // Default: levels 1-3
1200
+ }
1201
+
1202
+ // Add hyperlinks switch
1203
+ if (options.hyperlinks !== false) {
1204
+ instruction += ' \\h';
1205
+ }
1206
+
1207
+ // Add hide in web layout switch
1208
+ if (options.hideInWebLayout !== false) {
1209
+ instruction += ' \\z';
1210
+ }
1211
+
1212
+ // Add use outline levels switch
1213
+ if (options.useOutlineLevels !== false) {
1214
+ instruction += ' \\u';
1215
+ }
1216
+
1217
+ // Add omit page numbers switch
1218
+ if (options.omitPageNumbers) {
1219
+ instruction += ' \\n';
1220
+ }
1221
+
1222
+ // Add custom styles switch
1223
+ if (options.customStyles) {
1224
+ instruction += ` \\t "${options.customStyles}"`;
1225
+ }
1226
+
1227
+ instruction += ' '; // Trailing space per Microsoft convention
1228
+
1229
+ return new ComplexField({
1230
+ instruction,
1231
+ result: 'Table of Contents', // Placeholder result
1232
+ });
1233
+ }