docxmlater 10.0.2 → 10.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/README.md +2 -2
  2. package/dist/constants/legacyCompatFlags.d.ts.map +1 -1
  3. package/dist/constants/legacyCompatFlags.js.map +1 -1
  4. package/dist/constants/limits.d.ts +0 -27
  5. package/dist/constants/limits.d.ts.map +1 -1
  6. package/dist/constants/limits.js +13 -13
  7. package/dist/constants/limits.js.map +1 -1
  8. package/dist/core/Document.d.ts +23 -19
  9. package/dist/core/Document.d.ts.map +1 -1
  10. package/dist/core/Document.js +197 -63
  11. package/dist/core/Document.js.map +1 -1
  12. package/dist/core/DocumentContent.d.ts.map +1 -1
  13. package/dist/core/DocumentContent.js.map +1 -1
  14. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  15. package/dist/core/DocumentGenerator.js +59 -24
  16. package/dist/core/DocumentGenerator.js.map +1 -1
  17. package/dist/core/DocumentIdManager.d.ts.map +1 -1
  18. package/dist/core/DocumentIdManager.js.map +1 -1
  19. package/dist/core/DocumentParser.d.ts +6 -6
  20. package/dist/core/DocumentParser.d.ts.map +1 -1
  21. package/dist/core/DocumentParser.js +60 -54
  22. package/dist/core/DocumentParser.js.map +1 -1
  23. package/dist/core/DocumentValidator.d.ts.map +1 -1
  24. package/dist/core/DocumentValidator.js.map +1 -1
  25. package/dist/core/Relationship.d.ts.map +1 -1
  26. package/dist/core/Relationship.js +1 -1
  27. package/dist/core/Relationship.js.map +1 -1
  28. package/dist/core/RelationshipManager.js +3 -3
  29. package/dist/core/RelationshipManager.js.map +1 -1
  30. package/dist/elements/AlternateContent.js.map +1 -1
  31. package/dist/elements/Bookmark.d.ts.map +1 -1
  32. package/dist/elements/Bookmark.js.map +1 -1
  33. package/dist/elements/BookmarkManager.d.ts.map +1 -1
  34. package/dist/elements/BookmarkManager.js.map +1 -1
  35. package/dist/elements/Comment.js +1 -1
  36. package/dist/elements/Comment.js.map +1 -1
  37. package/dist/elements/CommentManager.d.ts.map +1 -1
  38. package/dist/elements/CommentManager.js +8 -2
  39. package/dist/elements/CommentManager.js.map +1 -1
  40. package/dist/elements/CommonTypes.d.ts.map +1 -1
  41. package/dist/elements/CommonTypes.js +1 -2
  42. package/dist/elements/CommonTypes.js.map +1 -1
  43. package/dist/elements/CustomXml.js.map +1 -1
  44. package/dist/elements/Endnote.d.ts.map +1 -1
  45. package/dist/elements/Endnote.js.map +1 -1
  46. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  47. package/dist/elements/EndnoteManager.js.map +1 -1
  48. package/dist/elements/Field.d.ts.map +1 -1
  49. package/dist/elements/Field.js +31 -28
  50. package/dist/elements/Field.js.map +1 -1
  51. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  52. package/dist/elements/FieldHelpers.js +6 -6
  53. package/dist/elements/FieldHelpers.js.map +1 -1
  54. package/dist/elements/FontManager.d.ts.map +1 -1
  55. package/dist/elements/FontManager.js.map +1 -1
  56. package/dist/elements/Footer.js.map +1 -1
  57. package/dist/elements/Footnote.d.ts.map +1 -1
  58. package/dist/elements/Footnote.js.map +1 -1
  59. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  60. package/dist/elements/FootnoteManager.js.map +1 -1
  61. package/dist/elements/Header.js.map +1 -1
  62. package/dist/elements/HeaderFooterManager.js.map +1 -1
  63. package/dist/elements/Hyperlink.d.ts.map +1 -1
  64. package/dist/elements/Hyperlink.js +5 -5
  65. package/dist/elements/Hyperlink.js.map +1 -1
  66. package/dist/elements/Image.d.ts +2 -2
  67. package/dist/elements/Image.d.ts.map +1 -1
  68. package/dist/elements/Image.js +21 -5
  69. package/dist/elements/Image.js.map +1 -1
  70. package/dist/elements/ImageManager.d.ts.map +1 -1
  71. package/dist/elements/ImageManager.js +2 -2
  72. package/dist/elements/ImageManager.js.map +1 -1
  73. package/dist/elements/ImageRun.js.map +1 -1
  74. package/dist/elements/MathElement.js.map +1 -1
  75. package/dist/elements/Paragraph.d.ts.map +1 -1
  76. package/dist/elements/Paragraph.js +128 -117
  77. package/dist/elements/Paragraph.js.map +1 -1
  78. package/dist/elements/PreservedElement.js.map +1 -1
  79. package/dist/elements/PropertyChangeTypes.js.map +1 -1
  80. package/dist/elements/RangeMarker.js.map +1 -1
  81. package/dist/elements/Revision.d.ts +1 -0
  82. package/dist/elements/Revision.d.ts.map +1 -1
  83. package/dist/elements/Revision.js +44 -5
  84. package/dist/elements/Revision.js.map +1 -1
  85. package/dist/elements/RevisionContent.js.map +1 -1
  86. package/dist/elements/RevisionManager.d.ts.map +1 -1
  87. package/dist/elements/RevisionManager.js.map +1 -1
  88. package/dist/elements/Run.d.ts.map +1 -1
  89. package/dist/elements/Run.js +1 -3
  90. package/dist/elements/Run.js.map +1 -1
  91. package/dist/elements/Section.d.ts.map +1 -1
  92. package/dist/elements/Section.js +127 -118
  93. package/dist/elements/Section.js.map +1 -1
  94. package/dist/elements/Shape.d.ts.map +1 -1
  95. package/dist/elements/Shape.js +21 -0
  96. package/dist/elements/Shape.js.map +1 -1
  97. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  98. package/dist/elements/StructuredDocumentTag.js +20 -8
  99. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  100. package/dist/elements/Table.d.ts +2 -2
  101. package/dist/elements/Table.d.ts.map +1 -1
  102. package/dist/elements/Table.js +29 -35
  103. package/dist/elements/Table.js.map +1 -1
  104. package/dist/elements/TableCell.d.ts +2 -2
  105. package/dist/elements/TableCell.d.ts.map +1 -1
  106. package/dist/elements/TableCell.js +63 -67
  107. package/dist/elements/TableCell.js.map +1 -1
  108. package/dist/elements/TableGridChange.js.map +1 -1
  109. package/dist/elements/TableOfContents.d.ts +6 -6
  110. package/dist/elements/TableOfContents.d.ts.map +1 -1
  111. package/dist/elements/TableOfContents.js.map +1 -1
  112. package/dist/elements/TableOfContentsElement.js.map +1 -1
  113. package/dist/elements/TableRow.d.ts.map +1 -1
  114. package/dist/elements/TableRow.js +65 -47
  115. package/dist/elements/TableRow.js.map +1 -1
  116. package/dist/elements/TextBox.d.ts.map +1 -1
  117. package/dist/elements/TextBox.js +1 -1
  118. package/dist/elements/TextBox.js.map +1 -1
  119. package/dist/formatting/AbstractNumbering.d.ts +1 -1
  120. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  121. package/dist/formatting/AbstractNumbering.js +11 -11
  122. package/dist/formatting/AbstractNumbering.js.map +1 -1
  123. package/dist/formatting/NumberingInstance.d.ts.map +1 -1
  124. package/dist/formatting/NumberingInstance.js +4 -4
  125. package/dist/formatting/NumberingInstance.js.map +1 -1
  126. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  127. package/dist/formatting/NumberingLevel.js +26 -26
  128. package/dist/formatting/NumberingLevel.js.map +1 -1
  129. package/dist/formatting/NumberingManager.d.ts +1 -1
  130. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  131. package/dist/formatting/NumberingManager.js.map +1 -1
  132. package/dist/formatting/Style.d.ts.map +1 -1
  133. package/dist/formatting/Style.js +87 -95
  134. package/dist/formatting/Style.js.map +1 -1
  135. package/dist/formatting/StylesManager.d.ts +3 -3
  136. package/dist/formatting/StylesManager.d.ts.map +1 -1
  137. package/dist/formatting/StylesManager.js.map +1 -1
  138. package/dist/helpers/CleanupHelper.js.map +1 -1
  139. package/dist/images/ImageOptimizer.js.map +1 -1
  140. package/dist/index.js.map +1 -1
  141. package/dist/managers/DrawingManager.d.ts.map +1 -1
  142. package/dist/managers/DrawingManager.js.map +1 -1
  143. package/dist/tracking/DocumentTrackingContext.js.map +1 -1
  144. package/dist/tracking/TrackingContext.js.map +1 -1
  145. package/dist/types/compatibility-types.js.map +1 -1
  146. package/dist/types/formatting.js.map +1 -1
  147. package/dist/types/list-types.d.ts +4 -4
  148. package/dist/types/list-types.d.ts.map +1 -1
  149. package/dist/types/list-types.js.map +1 -1
  150. package/dist/types/settings-types.js.map +1 -1
  151. package/dist/types/styleConfig.js.map +1 -1
  152. package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
  153. package/dist/utils/ChangelogGenerator.js.map +1 -1
  154. package/dist/utils/CompatibilityUpgrader.d.ts.map +1 -1
  155. package/dist/utils/CompatibilityUpgrader.js +7 -7
  156. package/dist/utils/CompatibilityUpgrader.js.map +1 -1
  157. package/dist/utils/InMemoryRevisionAcceptor.js +1 -1
  158. package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
  159. package/dist/utils/MoveOperationHelper.js.map +1 -1
  160. package/dist/utils/RevisionAwareProcessor.js.map +1 -1
  161. package/dist/utils/RevisionWalker.js.map +1 -1
  162. package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
  163. package/dist/utils/ShadingResolver.js +1 -1
  164. package/dist/utils/ShadingResolver.js.map +1 -1
  165. package/dist/utils/acceptRevisions.d.ts +0 -28
  166. package/dist/utils/acceptRevisions.d.ts.map +1 -1
  167. package/dist/utils/acceptRevisions.js +5 -7
  168. package/dist/utils/acceptRevisions.js.map +1 -1
  169. package/dist/utils/cnfStyleDecoder.js +1 -1
  170. package/dist/utils/cnfStyleDecoder.js.map +1 -1
  171. package/dist/utils/corruptionDetection.js.map +1 -1
  172. package/dist/utils/dateFormatting.js.map +1 -1
  173. package/dist/utils/deepClone.d.ts +0 -1
  174. package/dist/utils/deepClone.d.ts.map +1 -1
  175. package/dist/utils/deepClone.js +0 -7
  176. package/dist/utils/deepClone.js.map +1 -1
  177. package/dist/utils/diagnostics.d.ts +2 -2
  178. package/dist/utils/diagnostics.d.ts.map +1 -1
  179. package/dist/utils/diagnostics.js.map +1 -1
  180. package/dist/utils/errorHandling.js.map +1 -1
  181. package/dist/utils/formatting.js.map +1 -1
  182. package/dist/utils/list-detection.d.ts +2 -2
  183. package/dist/utils/list-detection.d.ts.map +1 -1
  184. package/dist/utils/list-detection.js +3 -3
  185. package/dist/utils/list-detection.js.map +1 -1
  186. package/dist/utils/logger.d.ts +2 -4
  187. package/dist/utils/logger.d.ts.map +1 -1
  188. package/dist/utils/logger.js +0 -2
  189. package/dist/utils/logger.js.map +1 -1
  190. package/dist/utils/parsingHelpers.js.map +1 -1
  191. package/dist/utils/stripTrackedChanges.d.ts +0 -19
  192. package/dist/utils/stripTrackedChanges.d.ts.map +1 -1
  193. package/dist/utils/stripTrackedChanges.js +0 -2
  194. package/dist/utils/stripTrackedChanges.js.map +1 -1
  195. package/dist/utils/textDiff.js.map +1 -1
  196. package/dist/utils/units.js.map +1 -1
  197. package/dist/utils/validation.d.ts.map +1 -1
  198. package/dist/utils/validation.js.map +1 -1
  199. package/dist/utils/xmlSanitization.js.map +1 -1
  200. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  201. package/dist/validation/RevisionValidator.js.map +1 -1
  202. package/dist/validation/ValidationRules.js.map +1 -1
  203. package/dist/validation/index.js.map +1 -1
  204. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  205. package/dist/xml/XMLBuilder.js +10 -0
  206. package/dist/xml/XMLBuilder.js.map +1 -1
  207. package/dist/xml/XMLParser.d.ts.map +1 -1
  208. package/dist/xml/XMLParser.js +4 -5
  209. package/dist/xml/XMLParser.js.map +1 -1
  210. package/dist/zip/ZipHandler.js.map +1 -1
  211. package/dist/zip/ZipReader.js.map +1 -1
  212. package/dist/zip/ZipWriter.js.map +1 -1
  213. package/dist/zip/errors.js.map +1 -1
  214. package/dist/zip/types.js.map +1 -1
  215. package/package.json +34 -4
  216. package/src/__tests__/helper-methods.test.ts +512 -0
  217. package/src/constants/legacyCompatFlags.ts +138 -0
  218. package/src/constants/limits.ts +50 -0
  219. package/src/core/CLAUDE.md +109 -0
  220. package/src/core/Document.ts +15569 -0
  221. package/src/core/DocumentContent.ts +467 -0
  222. package/src/core/DocumentGenerator.ts +1104 -0
  223. package/src/core/DocumentIdManager.ts +158 -0
  224. package/src/core/DocumentParser.ts +10107 -0
  225. package/src/core/DocumentValidator.ts +372 -0
  226. package/src/core/Relationship.ts +367 -0
  227. package/src/core/RelationshipManager.ts +428 -0
  228. package/src/elements/AlternateContent.ts +42 -0
  229. package/src/elements/Bookmark.ts +210 -0
  230. package/src/elements/BookmarkManager.ts +250 -0
  231. package/src/elements/CLAUDE.md +126 -0
  232. package/src/elements/Comment.ts +359 -0
  233. package/src/elements/CommentManager.ts +502 -0
  234. package/src/elements/CommonTypes.ts +549 -0
  235. package/src/elements/CustomXml.ts +36 -0
  236. package/src/elements/Endnote.ts +217 -0
  237. package/src/elements/EndnoteManager.ts +249 -0
  238. package/src/elements/Field.ts +1233 -0
  239. package/src/elements/FieldHelpers.ts +333 -0
  240. package/src/elements/FontManager.ts +339 -0
  241. package/src/elements/Footer.ts +269 -0
  242. package/src/elements/Footnote.ts +217 -0
  243. package/src/elements/FootnoteManager.ts +249 -0
  244. package/src/elements/Header.ts +269 -0
  245. package/src/elements/HeaderFooterManager.ts +219 -0
  246. package/src/elements/Hyperlink.ts +1146 -0
  247. package/src/elements/Image.ts +1756 -0
  248. package/src/elements/ImageManager.ts +432 -0
  249. package/src/elements/ImageRun.ts +59 -0
  250. package/src/elements/MathElement.ts +65 -0
  251. package/src/elements/Paragraph.ts +4227 -0
  252. package/src/elements/PreservedElement.ts +53 -0
  253. package/src/elements/PropertyChangeTypes.ts +442 -0
  254. package/src/elements/RangeMarker.ts +400 -0
  255. package/src/elements/Revision.ts +1217 -0
  256. package/src/elements/RevisionContent.ts +73 -0
  257. package/src/elements/RevisionManager.ts +1070 -0
  258. package/src/elements/Run.ts +3068 -0
  259. package/src/elements/Section.ts +1421 -0
  260. package/src/elements/Shape.ts +873 -0
  261. package/src/elements/StructuredDocumentTag.ts +978 -0
  262. package/src/elements/Table.ts +2524 -0
  263. package/src/elements/TableCell.ts +1586 -0
  264. package/src/elements/TableGridChange.ts +151 -0
  265. package/src/elements/TableOfContents.ts +691 -0
  266. package/src/elements/TableOfContentsElement.ts +89 -0
  267. package/src/elements/TableRow.ts +906 -0
  268. package/src/elements/TextBox.ts +768 -0
  269. package/src/formatting/AbstractNumbering.ts +548 -0
  270. package/src/formatting/CLAUDE.md +74 -0
  271. package/src/formatting/NumberingInstance.ts +212 -0
  272. package/src/formatting/NumberingLevel.ts +1006 -0
  273. package/src/formatting/NumberingManager.ts +827 -0
  274. package/src/formatting/Style.ts +1833 -0
  275. package/src/formatting/StylesManager.ts +1005 -0
  276. package/src/helpers/CleanupHelper.ts +524 -0
  277. package/src/images/ImageOptimizer.ts +274 -0
  278. package/src/index.ts +554 -0
  279. package/src/managers/CLAUDE.md +47 -0
  280. package/src/managers/DrawingManager.ts +319 -0
  281. package/src/tracking/DocumentTrackingContext.ts +643 -0
  282. package/src/tracking/TrackingContext.ts +173 -0
  283. package/src/types/compatibility-types.ts +49 -0
  284. package/src/types/formatting.ts +210 -0
  285. package/src/types/list-types.ts +152 -0
  286. package/src/types/settings-types.ts +59 -0
  287. package/src/types/styleConfig.ts +189 -0
  288. package/src/utils/CLAUDE.md +153 -0
  289. package/src/utils/ChangelogGenerator.ts +1581 -0
  290. package/src/utils/CompatibilityUpgrader.ts +237 -0
  291. package/src/utils/InMemoryRevisionAcceptor.ts +668 -0
  292. package/src/utils/MoveOperationHelper.ts +238 -0
  293. package/src/utils/RevisionAwareProcessor.ts +526 -0
  294. package/src/utils/RevisionWalker.ts +457 -0
  295. package/src/utils/SelectiveRevisionAcceptor.ts +613 -0
  296. package/src/utils/ShadingResolver.ts +107 -0
  297. package/src/utils/acceptRevisions.ts +714 -0
  298. package/src/utils/cnfStyleDecoder.ts +217 -0
  299. package/src/utils/corruptionDetection.ts +345 -0
  300. package/src/utils/dateFormatting.ts +20 -0
  301. package/src/utils/deepClone.ts +78 -0
  302. package/src/utils/diagnostics.ts +129 -0
  303. package/src/utils/errorHandling.ts +80 -0
  304. package/src/utils/formatting.ts +213 -0
  305. package/src/utils/list-detection.ts +274 -0
  306. package/src/utils/logger.ts +404 -0
  307. package/src/utils/parsingHelpers.ts +190 -0
  308. package/src/utils/stripTrackedChanges.ts +353 -0
  309. package/src/utils/textDiff.ts +100 -0
  310. package/src/utils/units.ts +421 -0
  311. package/src/utils/validation.ts +542 -0
  312. package/src/utils/xmlSanitization.ts +182 -0
  313. package/src/validation/RevisionAutoFixer.ts +542 -0
  314. package/src/validation/RevisionValidator.ts +460 -0
  315. package/src/validation/ValidationRules.ts +338 -0
  316. package/src/validation/index.ts +30 -0
  317. package/src/xml/CLAUDE.md +65 -0
  318. package/src/xml/XMLBuilder.ts +871 -0
  319. package/src/xml/XMLParser.ts +919 -0
  320. package/src/zip/CLAUDE.md +55 -0
  321. package/src/zip/ZipHandler.ts +637 -0
  322. package/src/zip/ZipReader.ts +299 -0
  323. package/src/zip/ZipWriter.ts +390 -0
  324. package/src/zip/errors.ts +69 -0
  325. package/src/zip/types.ts +116 -0
  326. package/dist/core/ListNormalizer.d.ts +0 -23
  327. package/dist/core/ListNormalizer.d.ts.map +0 -1
  328. package/dist/core/ListNormalizer.js +0 -624
  329. package/dist/core/ListNormalizer.js.map +0 -1
  330. package/dist/images/index.d.ts +0 -2
  331. package/dist/images/index.d.ts.map +0 -1
  332. package/dist/images/index.js +0 -8
  333. package/dist/images/index.js.map +0 -1
  334. package/dist/ms-doc/cfb/CFBReader.d.ts +0 -35
  335. package/dist/ms-doc/cfb/CFBReader.d.ts.map +0 -1
  336. package/dist/ms-doc/cfb/CFBReader.js +0 -360
  337. package/dist/ms-doc/cfb/CFBReader.js.map +0 -1
  338. package/dist/ms-doc/converter/DocToDocxConverter.d.ts +0 -55
  339. package/dist/ms-doc/converter/DocToDocxConverter.d.ts.map +0 -1
  340. package/dist/ms-doc/converter/DocToDocxConverter.js +0 -324
  341. package/dist/ms-doc/converter/DocToDocxConverter.js.map +0 -1
  342. package/dist/ms-doc/fib/FIB.d.ts +0 -18
  343. package/dist/ms-doc/fib/FIB.d.ts.map +0 -1
  344. package/dist/ms-doc/fib/FIB.js +0 -342
  345. package/dist/ms-doc/fib/FIB.js.map +0 -1
  346. package/dist/ms-doc/fields/FieldParser.d.ts +0 -31
  347. package/dist/ms-doc/fields/FieldParser.d.ts.map +0 -1
  348. package/dist/ms-doc/fields/FieldParser.js +0 -266
  349. package/dist/ms-doc/fields/FieldParser.js.map +0 -1
  350. package/dist/ms-doc/images/PictureExtractor.d.ts +0 -22
  351. package/dist/ms-doc/images/PictureExtractor.d.ts.map +0 -1
  352. package/dist/ms-doc/images/PictureExtractor.js +0 -233
  353. package/dist/ms-doc/images/PictureExtractor.js.map +0 -1
  354. package/dist/ms-doc/index.d.ts +0 -20
  355. package/dist/ms-doc/index.d.ts.map +0 -1
  356. package/dist/ms-doc/index.js +0 -59
  357. package/dist/ms-doc/index.js.map +0 -1
  358. package/dist/ms-doc/properties/SPRM.d.ts +0 -210
  359. package/dist/ms-doc/properties/SPRM.d.ts.map +0 -1
  360. package/dist/ms-doc/properties/SPRM.js +0 -633
  361. package/dist/ms-doc/properties/SPRM.js.map +0 -1
  362. package/dist/ms-doc/sections/SectionParser.d.ts +0 -25
  363. package/dist/ms-doc/sections/SectionParser.d.ts.map +0 -1
  364. package/dist/ms-doc/sections/SectionParser.js +0 -214
  365. package/dist/ms-doc/sections/SectionParser.js.map +0 -1
  366. package/dist/ms-doc/styles/StyleSheet.d.ts +0 -23
  367. package/dist/ms-doc/styles/StyleSheet.d.ts.map +0 -1
  368. package/dist/ms-doc/styles/StyleSheet.js +0 -268
  369. package/dist/ms-doc/styles/StyleSheet.js.map +0 -1
  370. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts +0 -61
  371. package/dist/ms-doc/subdocuments/SubdocumentParser.d.ts.map +0 -1
  372. package/dist/ms-doc/subdocuments/SubdocumentParser.js +0 -208
  373. package/dist/ms-doc/subdocuments/SubdocumentParser.js.map +0 -1
  374. package/dist/ms-doc/tables/TableParser.d.ts +0 -29
  375. package/dist/ms-doc/tables/TableParser.d.ts.map +0 -1
  376. package/dist/ms-doc/tables/TableParser.js +0 -176
  377. package/dist/ms-doc/tables/TableParser.js.map +0 -1
  378. package/dist/ms-doc/text/PieceTable.d.ts +0 -21
  379. package/dist/ms-doc/text/PieceTable.d.ts.map +0 -1
  380. package/dist/ms-doc/text/PieceTable.js +0 -171
  381. package/dist/ms-doc/text/PieceTable.js.map +0 -1
  382. package/dist/ms-doc/types/Constants.d.ts +0 -99
  383. package/dist/ms-doc/types/Constants.d.ts.map +0 -1
  384. package/dist/ms-doc/types/Constants.js +0 -102
  385. package/dist/ms-doc/types/Constants.js.map +0 -1
  386. package/dist/ms-doc/types/DocTypes.d.ts +0 -368
  387. package/dist/ms-doc/types/DocTypes.d.ts.map +0 -1
  388. package/dist/ms-doc/types/DocTypes.js +0 -3
  389. package/dist/ms-doc/types/DocTypes.js.map +0 -1
  390. package/dist/tracking/index.d.ts +0 -3
  391. package/dist/tracking/index.d.ts.map +0 -1
  392. package/dist/tracking/index.js +0 -6
  393. package/dist/tracking/index.js.map +0 -1
@@ -0,0 +1,1833 @@
1
+ /**
2
+ * Style - Represents a style definition in a Word document
3
+ * Supports paragraph, character, table, and numbering styles
4
+ */
5
+
6
+ import { XMLBuilder, XMLElement } from "../xml/XMLBuilder";
7
+ import { ParagraphFormatting } from "../elements/Paragraph";
8
+ import { RunFormatting } from "../elements/Run";
9
+ import { ShadingConfig, ShadingPattern, buildShadingAttributes } from "../elements/CommonTypes";
10
+ import { Heading2TableOptions } from "../types/styleConfig";
11
+ import { deepClone } from "../utils/deepClone";
12
+ import { pointsToHalfPoints } from "../utils/units";
13
+
14
+ /**
15
+ * Style type
16
+ */
17
+ export type StyleType = "paragraph" | "character" | "table" | "numbering";
18
+
19
+ /**
20
+ * Table alignment
21
+ */
22
+ export type TableAlignment = "left" | "center" | "right";
23
+
24
+ /**
25
+ * Border properties
26
+ */
27
+ export interface BorderProperties {
28
+ /** Border style */
29
+ style?: "none" | "single" | "double" | "dashed" | "dotted" | "thick";
30
+ /** Border size in eighths of a point */
31
+ size?: number;
32
+ /** Border spacing/padding in points */
33
+ space?: number;
34
+ /** Border color (hex without #) */
35
+ color?: string;
36
+ }
37
+
38
+ /**
39
+ * Table borders (6 possible borders)
40
+ */
41
+ export interface TableBorders {
42
+ top?: BorderProperties;
43
+ bottom?: BorderProperties;
44
+ left?: BorderProperties;
45
+ right?: BorderProperties;
46
+ /** Inside horizontal borders */
47
+ insideH?: BorderProperties;
48
+ /** Inside vertical borders */
49
+ insideV?: BorderProperties;
50
+ }
51
+
52
+ /**
53
+ * Cell borders (8 possible borders, includes diagonals)
54
+ */
55
+ export interface CellBorders extends TableBorders {
56
+ /** Top-left to bottom-right diagonal */
57
+ tl2br?: BorderProperties;
58
+ /** Top-right to bottom-left diagonal */
59
+ tr2bl?: BorderProperties;
60
+ }
61
+
62
+ /**
63
+ * Shading properties
64
+ * @see ShadingConfig in CommonTypes.ts for the canonical definition
65
+ */
66
+ export type ShadingProperties = ShadingConfig;
67
+
68
+ /**
69
+ * Cell margins
70
+ */
71
+ export interface CellMargins {
72
+ /** Top margin in twips */
73
+ top?: number;
74
+ /** Bottom margin in twips */
75
+ bottom?: number;
76
+ /** Left margin in twips */
77
+ left?: number;
78
+ /** Right margin in twips */
79
+ right?: number;
80
+ }
81
+
82
+ /**
83
+ * Table-level formatting properties (tblPr)
84
+ */
85
+ export interface TableStyleFormatting {
86
+ /** Table indentation from left margin in twips */
87
+ indent?: number;
88
+ /** Default cell spacing in twips */
89
+ cellSpacing?: number;
90
+ /** Table borders */
91
+ borders?: TableBorders;
92
+ /** Default cell margins */
93
+ cellMargins?: CellMargins;
94
+ /** Table background shading */
95
+ shading?: ShadingProperties;
96
+ /** Table alignment */
97
+ alignment?: TableAlignment;
98
+ }
99
+
100
+ /**
101
+ * Table cell formatting properties (tcPr)
102
+ */
103
+ export interface TableCellStyleFormatting {
104
+ /** Cell borders (8 possible borders) */
105
+ borders?: CellBorders;
106
+ /** Cell background shading */
107
+ shading?: ShadingProperties;
108
+ /** Cell-specific margins */
109
+ margins?: CellMargins;
110
+ /** Vertical alignment in cell */
111
+ verticalAlignment?: "top" | "center" | "bottom";
112
+ }
113
+
114
+ /**
115
+ * Table row formatting properties (trPr)
116
+ */
117
+ export interface TableRowStyleFormatting {
118
+ /** Prevent row from splitting across pages */
119
+ cantSplit?: boolean;
120
+ /** Mark row as header row */
121
+ isHeader?: boolean;
122
+ /** Row height in twips */
123
+ height?: number;
124
+ /** Row height rule */
125
+ heightRule?: "auto" | "exact" | "atLeast";
126
+ }
127
+
128
+ /**
129
+ * Conditional formatting type for table regions
130
+ */
131
+ export type ConditionalFormattingType =
132
+ | "wholeTable" // Entire table
133
+ | "firstRow" // First row
134
+ | "lastRow" // Last row
135
+ | "firstCol" // First column
136
+ | "lastCol" // Last column
137
+ | "band1Vert" // Odd column banding
138
+ | "band2Vert" // Even column banding
139
+ | "band1Horz" // Odd row banding
140
+ | "band2Horz" // Even row banding
141
+ | "nwCell" // Northwest (top-left) corner cell
142
+ | "neCell" // Northeast (top-right) corner cell
143
+ | "swCell" // Southwest (bottom-left) corner cell
144
+ | "seCell"; // Southeast (bottom-right) corner cell
145
+
146
+ /**
147
+ * Conditional table formatting for a specific region
148
+ */
149
+ export interface ConditionalTableFormatting {
150
+ /** Region type */
151
+ type: ConditionalFormattingType;
152
+ /** Paragraph formatting for this region */
153
+ paragraphFormatting?: ParagraphFormatting;
154
+ /** Run formatting for this region */
155
+ runFormatting?: RunFormatting;
156
+ /** Table formatting for this region */
157
+ tableFormatting?: TableStyleFormatting;
158
+ /** Cell formatting for this region */
159
+ cellFormatting?: TableCellStyleFormatting;
160
+ /** Row formatting for this region */
161
+ rowFormatting?: TableRowStyleFormatting;
162
+ }
163
+
164
+ /**
165
+ * Table style properties (Phase 5.1)
166
+ */
167
+ export interface TableStyleProperties {
168
+ /** Table-level formatting */
169
+ table?: TableStyleFormatting;
170
+ /** Default cell formatting */
171
+ cell?: TableCellStyleFormatting;
172
+ /** Default row formatting */
173
+ row?: TableRowStyleFormatting;
174
+ /** Rows per band for row banding (default 1) */
175
+ rowBandSize?: number;
176
+ /** Columns per band for column banding (default 1) */
177
+ colBandSize?: number;
178
+ /** Conditional formatting for specific table regions */
179
+ conditionalFormatting?: ConditionalTableFormatting[];
180
+ }
181
+
182
+ /**
183
+ * Style properties
184
+ */
185
+ export interface StyleProperties {
186
+ /** Unique style identifier */
187
+ styleId: string;
188
+ /** Display name */
189
+ name: string;
190
+ /** Style type */
191
+ type: StyleType;
192
+ /** Parent style ID for inheritance */
193
+ basedOn?: string;
194
+ /** Next style ID (auto-next paragraph style) */
195
+ next?: string;
196
+ /** Whether this is a default style */
197
+ isDefault?: boolean;
198
+ /** Whether this is a custom style */
199
+ customStyle?: boolean;
200
+ /** Paragraph formatting (for paragraph and table styles) */
201
+ paragraphFormatting?: ParagraphFormatting;
202
+ /** Numbering properties for styles that inherit list formatting */
203
+ numPr?: {
204
+ numId?: number;
205
+ ilvl?: number;
206
+ };
207
+ /** Run formatting (for character and paragraph styles) */
208
+ runFormatting?: RunFormatting;
209
+ /** Table style properties (for table styles only - Phase 5.1) */
210
+ tableStyle?: TableStyleProperties;
211
+
212
+ // Style Gallery Metadata (Phase 5.3)
213
+ /** Quick style - show in style gallery */
214
+ qFormat?: boolean;
215
+ /** UI priority - sort order in style picker (0-99, lower = higher priority) */
216
+ uiPriority?: number;
217
+ /** Semi-hidden - hide from gallery unless in use */
218
+ semiHidden?: boolean;
219
+ /** Unhide when used - auto-show when applied */
220
+ unhideWhenUsed?: boolean;
221
+ /** Locked - prevent modification */
222
+ locked?: boolean;
223
+ /** Personal - user-specific style */
224
+ personal?: boolean;
225
+ /** Link - linked character/paragraph style ID */
226
+ link?: string;
227
+ /** Auto-redefine - update style from manual formatting */
228
+ autoRedefine?: boolean;
229
+ /** Aliases - alternative names (comma-separated) */
230
+ aliases?: string;
231
+
232
+ // Document Helper Metadata
233
+ /**
234
+ * Table options for Heading2 wrapping
235
+ * Used by Document.applyCustomFormattingToExistingStyles() to configure
236
+ * how Heading2 paragraphs are wrapped in tables
237
+ */
238
+ heading2TableOptions?: Heading2TableOptions;
239
+ }
240
+
241
+ /**
242
+ * Represents a style definition
243
+ */
244
+ export class Style {
245
+ private properties: StyleProperties;
246
+
247
+ /**
248
+ * Creates a new Style
249
+ * @param properties - Style properties
250
+ */
251
+ constructor(properties: StyleProperties) {
252
+ this.properties = { ...properties };
253
+ }
254
+
255
+ /**
256
+ * Gets the style ID
257
+ * @returns Style ID
258
+ */
259
+ getStyleId(): string {
260
+ return this.properties.styleId;
261
+ }
262
+
263
+ /**
264
+ * Gets the style name
265
+ * @returns Style name
266
+ */
267
+ getName(): string {
268
+ return this.properties.name;
269
+ }
270
+
271
+ /**
272
+ * Gets the style type
273
+ * @returns Style type
274
+ */
275
+ getType(): StyleType {
276
+ return this.properties.type;
277
+ }
278
+
279
+ /**
280
+ * Gets all style properties
281
+ * @returns Style properties
282
+ */
283
+ getProperties(): StyleProperties {
284
+ return { ...this.properties };
285
+ }
286
+
287
+ /**
288
+ * Gets whether this is a default style
289
+ * @returns True if this is a default style for its type
290
+ */
291
+ getIsDefault(): boolean {
292
+ return this.properties.isDefault ?? false;
293
+ }
294
+
295
+ /**
296
+ * Sets whether this is a default style
297
+ * @param value - True to mark as default style
298
+ * @returns This style for chaining
299
+ */
300
+ setIsDefault(value: boolean): this {
301
+ this.properties.isDefault = value;
302
+ return this;
303
+ }
304
+
305
+ /**
306
+ * Sets the base style
307
+ * @param styleId - Parent style ID
308
+ * @returns This style for chaining
309
+ */
310
+ setBasedOn(styleId: string): this {
311
+ this.properties.basedOn = styleId;
312
+ return this;
313
+ }
314
+
315
+ /**
316
+ * Sets the next style
317
+ * @param styleId - Next style ID
318
+ * @returns This style for chaining
319
+ */
320
+ setNext(styleId: string): this {
321
+ this.properties.next = styleId;
322
+ return this;
323
+ }
324
+
325
+ /**
326
+ * Sets paragraph formatting
327
+ * @param formatting - Paragraph formatting options
328
+ * @returns This style for chaining
329
+ */
330
+ setParagraphFormatting(formatting: ParagraphFormatting): this {
331
+ this.properties.paragraphFormatting = { ...formatting };
332
+ return this;
333
+ }
334
+
335
+ /**
336
+ * Sets run formatting
337
+ * @param formatting - Run formatting options
338
+ * @returns This style for chaining
339
+ */
340
+ setRunFormatting(formatting: RunFormatting): this {
341
+ this.properties.runFormatting = { ...formatting };
342
+ return this;
343
+ }
344
+
345
+ /**
346
+ * Gets the current run formatting
347
+ * @returns Run formatting or undefined if not set
348
+ */
349
+ getRunFormatting(): RunFormatting | undefined {
350
+ return this.properties.runFormatting;
351
+ }
352
+
353
+ /**
354
+ * Gets the current paragraph formatting
355
+ * @returns Paragraph formatting or undefined if not set
356
+ */
357
+ getParagraphFormatting(): ParagraphFormatting | undefined {
358
+ return this.properties.paragraphFormatting;
359
+ }
360
+
361
+ /**
362
+ * Sets Heading2 table wrapping options
363
+ * Used by Document.applyCustomFormattingToExistingStyles() when styleId is 'Heading2'
364
+ * @param options - Table options for wrapping Heading2 paragraphs
365
+ * @returns This style for chaining
366
+ */
367
+ setHeading2TableOptions(options: Heading2TableOptions): this {
368
+ this.properties.heading2TableOptions = options;
369
+ return this;
370
+ }
371
+
372
+ /**
373
+ * Gets the current Heading2 table options
374
+ * @returns Heading2 table options or undefined if not set
375
+ */
376
+ getHeading2TableOptions(): Heading2TableOptions | undefined {
377
+ return this.properties.heading2TableOptions;
378
+ }
379
+
380
+ /**
381
+ * Sets whether this is a quick style (appears in style gallery)
382
+ * @param enabled - True to show in quick style gallery
383
+ * @returns This style for chaining
384
+ */
385
+ setQFormat(enabled: boolean): this {
386
+ this.properties.qFormat = enabled;
387
+ return this;
388
+ }
389
+
390
+ /**
391
+ * Sets the UI priority (sort order in style picker)
392
+ * @param priority - Priority value (0-99, lower = higher priority)
393
+ * @returns This style for chaining
394
+ */
395
+ setUiPriority(priority: number): this {
396
+ if (priority < 0 || priority > 99) {
397
+ throw new Error("UI priority must be between 0 and 99");
398
+ }
399
+ this.properties.uiPriority = priority;
400
+ return this;
401
+ }
402
+
403
+ /**
404
+ * Sets whether this style is semi-hidden (hidden from recommended list)
405
+ * @param hidden - True to hide from recommended list
406
+ * @returns This style for chaining
407
+ */
408
+ setSemiHidden(hidden: boolean): this {
409
+ this.properties.semiHidden = hidden;
410
+ return this;
411
+ }
412
+
413
+ /**
414
+ * Sets whether to unhide this style when first used
415
+ * @param enabled - True to auto-show when applied
416
+ * @returns This style for chaining
417
+ */
418
+ setUnhideWhenUsed(enabled: boolean): this {
419
+ this.properties.unhideWhenUsed = enabled;
420
+ return this;
421
+ }
422
+
423
+ /**
424
+ * Sets whether this style is locked (prevents modification)
425
+ * @param locked - True to lock the style
426
+ * @returns This style for chaining
427
+ */
428
+ setLocked(locked: boolean): this {
429
+ this.properties.locked = locked;
430
+ return this;
431
+ }
432
+
433
+ /**
434
+ * Sets whether this is a personal style (user-specific)
435
+ * @param personal - True to mark as personal
436
+ * @returns This style for chaining
437
+ */
438
+ setPersonal(personal: boolean): this {
439
+ this.properties.personal = personal;
440
+ return this;
441
+ }
442
+
443
+ /**
444
+ * Sets the linked style ID (for character/paragraph style linking)
445
+ * @param styleId - ID of the linked style
446
+ * @returns This style for chaining
447
+ */
448
+ setLink(styleId: string): this {
449
+ this.properties.link = styleId;
450
+ return this;
451
+ }
452
+
453
+ /**
454
+ * Sets whether to auto-redefine this style from manual formatting
455
+ * @param enabled - True to enable auto-redefine
456
+ * @returns This style for chaining
457
+ */
458
+ setAutoRedefine(enabled: boolean): this {
459
+ this.properties.autoRedefine = enabled;
460
+ return this;
461
+ }
462
+
463
+ /**
464
+ * Sets alternative names for this style (comma-separated)
465
+ * @param aliases - Comma-separated list of alternative names
466
+ * @returns This style for chaining
467
+ */
468
+ setAliases(aliases: string): this {
469
+ this.properties.aliases = aliases;
470
+ return this;
471
+ }
472
+
473
+ /**
474
+ * Sets table-level formatting properties (Phase 5.1)
475
+ * @param formatting - Table formatting options
476
+ * @returns This style for chaining
477
+ */
478
+ setTableFormatting(formatting: TableStyleFormatting): this {
479
+ if (!this.properties.tableStyle) {
480
+ this.properties.tableStyle = {};
481
+ }
482
+ this.properties.tableStyle.table = { ...formatting };
483
+ return this;
484
+ }
485
+
486
+ /**
487
+ * Sets table cell formatting properties (Phase 5.1)
488
+ * @param formatting - Cell formatting options
489
+ * @returns This style for chaining
490
+ */
491
+ setTableCellFormatting(formatting: TableCellStyleFormatting): this {
492
+ if (!this.properties.tableStyle) {
493
+ this.properties.tableStyle = {};
494
+ }
495
+ this.properties.tableStyle.cell = { ...formatting };
496
+ return this;
497
+ }
498
+
499
+ /**
500
+ * Sets table row formatting properties (Phase 5.1)
501
+ * @param formatting - Row formatting options
502
+ * @returns This style for chaining
503
+ */
504
+ setTableRowFormatting(formatting: TableRowStyleFormatting): this {
505
+ if (!this.properties.tableStyle) {
506
+ this.properties.tableStyle = {};
507
+ }
508
+ this.properties.tableStyle.row = { ...formatting };
509
+ return this;
510
+ }
511
+
512
+ /**
513
+ * Sets row band size for row banding (Phase 5.1)
514
+ * @param size - Number of rows per band (default 1)
515
+ * @returns This style for chaining
516
+ */
517
+ setRowBandSize(size: number): this {
518
+ if (!this.properties.tableStyle) {
519
+ this.properties.tableStyle = {};
520
+ }
521
+ if (size < 0) {
522
+ throw new Error("Row band size must be non-negative");
523
+ }
524
+ this.properties.tableStyle.rowBandSize = size;
525
+ return this;
526
+ }
527
+
528
+ /**
529
+ * Sets column band size for column banding (Phase 5.1)
530
+ * @param size - Number of columns per band (default 1)
531
+ * @returns This style for chaining
532
+ */
533
+ setColBandSize(size: number): this {
534
+ if (!this.properties.tableStyle) {
535
+ this.properties.tableStyle = {};
536
+ }
537
+ if (size < 0) {
538
+ throw new Error("Column band size must be non-negative");
539
+ }
540
+ this.properties.tableStyle.colBandSize = size;
541
+ return this;
542
+ }
543
+
544
+ /**
545
+ * Adds conditional formatting for a specific table region (Phase 5.1)
546
+ * @param conditional - Conditional formatting definition
547
+ * @returns This style for chaining
548
+ */
549
+ addConditionalFormatting(conditional: ConditionalTableFormatting): this {
550
+ if (!this.properties.tableStyle) {
551
+ this.properties.tableStyle = {};
552
+ }
553
+ if (!this.properties.tableStyle.conditionalFormatting) {
554
+ this.properties.tableStyle.conditionalFormatting = [];
555
+ }
556
+ this.properties.tableStyle.conditionalFormatting.push({ ...conditional });
557
+ return this;
558
+ }
559
+
560
+ /**
561
+ * Validates that this style definition is valid
562
+ *
563
+ * Checks:
564
+ * - Required fields (styleId, name, type)
565
+ * - Valid type value
566
+ * - No circular references (basedOn != styleId)
567
+ * - Valid formatting values
568
+ *
569
+ * @returns True if the style is valid, false otherwise
570
+ */
571
+ isValid(): boolean {
572
+ try {
573
+ // Required fields
574
+ if (
575
+ !this.properties.styleId ||
576
+ !this.properties.name ||
577
+ !this.properties.type
578
+ ) {
579
+ return false;
580
+ }
581
+
582
+ // Valid type
583
+ const validTypes: StyleType[] = [
584
+ "paragraph",
585
+ "character",
586
+ "table",
587
+ "numbering",
588
+ ];
589
+ if (!validTypes.includes(this.properties.type)) {
590
+ return false;
591
+ }
592
+
593
+ // No circular reference
594
+ if (this.properties.basedOn === this.properties.styleId) {
595
+ return false;
596
+ }
597
+
598
+ // Check paragraph formatting if present
599
+ if (this.properties.paragraphFormatting) {
600
+ const pf = this.properties.paragraphFormatting;
601
+
602
+ // Check alignment
603
+ if (pf.alignment) {
604
+ const validAlignments = [
605
+ "left",
606
+ "center",
607
+ "right",
608
+ "justify",
609
+ "both",
610
+ "distribute",
611
+ ];
612
+ if (!validAlignments.includes(pf.alignment)) {
613
+ return false;
614
+ }
615
+ }
616
+
617
+ // Check spacing values
618
+ if (pf.spacing) {
619
+ const spacing = pf.spacing;
620
+ if (spacing.before !== undefined && spacing.before < 0) return false;
621
+ if (spacing.after !== undefined && spacing.after < 0) return false;
622
+ if (spacing.line !== undefined && spacing.line < 0) return false;
623
+ if (
624
+ spacing.lineRule &&
625
+ !["auto", "exact", "atLeast"].includes(spacing.lineRule)
626
+ ) {
627
+ return false;
628
+ }
629
+ }
630
+
631
+ // Check indentation values
632
+ if (pf.indentation) {
633
+ const ind = pf.indentation;
634
+ // Indentation values can be negative for hanging indent
635
+ if (ind.left !== undefined && ind.left < -100000) return false;
636
+ if (ind.right !== undefined && ind.right < -100000) return false;
637
+ }
638
+ }
639
+
640
+ // Check run formatting if present
641
+ if (this.properties.runFormatting) {
642
+ const rf = this.properties.runFormatting;
643
+
644
+ // Check font size
645
+ if (rf.size !== undefined && (rf.size <= 0 || rf.size > 1638)) {
646
+ return false; // Max font size in Word is 1638
647
+ }
648
+
649
+ // Check color format (should be 6 hex characters)
650
+ if (rf.color && !/^[0-9A-Fa-f]{6}$/.test(rf.color)) {
651
+ return false;
652
+ }
653
+
654
+ // Check highlight color
655
+ if (rf.highlight) {
656
+ const validHighlights = [
657
+ "black",
658
+ "blue",
659
+ "cyan",
660
+ "darkBlue",
661
+ "darkCyan",
662
+ "darkGray",
663
+ "darkGreen",
664
+ "darkMagenta",
665
+ "darkRed",
666
+ "darkYellow",
667
+ "green",
668
+ "lightGray",
669
+ "magenta",
670
+ "none",
671
+ "red",
672
+ "white",
673
+ "yellow",
674
+ ];
675
+ if (!validHighlights.includes(rf.highlight)) {
676
+ return false;
677
+ }
678
+ }
679
+ }
680
+
681
+ // Check metadata properties (Phase 5.3)
682
+ if (this.properties.uiPriority !== undefined) {
683
+ if (this.properties.uiPriority < 0 || this.properties.uiPriority > 99) {
684
+ return false;
685
+ }
686
+ }
687
+
688
+ // Check linked style doesn't reference self
689
+ if (this.properties.link === this.properties.styleId) {
690
+ return false;
691
+ }
692
+
693
+ return true;
694
+ } catch {
695
+ return false;
696
+ }
697
+ }
698
+
699
+ /**
700
+ * Converts the style to WordprocessingML XML element
701
+ * @returns XMLElement representing the style
702
+ */
703
+ toXML(): XMLElement {
704
+ const styleAttrs: Record<string, string> = {
705
+ "w:type": this.properties.type,
706
+ "w:styleId": this.properties.styleId,
707
+ };
708
+
709
+ if (this.properties.isDefault) {
710
+ styleAttrs["w:default"] = "1";
711
+ }
712
+
713
+ if (this.properties.customStyle) {
714
+ styleAttrs["w:customStyle"] = "1";
715
+ }
716
+
717
+ const styleChildren: XMLElement[] = [];
718
+
719
+ // Add style name
720
+ styleChildren.push(
721
+ XMLBuilder.wSelf("name", { "w:val": this.properties.name })
722
+ );
723
+
724
+ // aliases - Alternative names (must follow name per CT_Style)
725
+ if (this.properties.aliases) {
726
+ styleChildren.push(
727
+ XMLBuilder.wSelf("aliases", { "w:val": this.properties.aliases })
728
+ );
729
+ }
730
+
731
+ // Add basedOn
732
+ if (this.properties.basedOn) {
733
+ styleChildren.push(
734
+ XMLBuilder.wSelf("basedOn", { "w:val": this.properties.basedOn })
735
+ );
736
+ }
737
+
738
+ // Add next
739
+ if (this.properties.next) {
740
+ styleChildren.push(
741
+ XMLBuilder.wSelf("next", { "w:val": this.properties.next })
742
+ );
743
+ }
744
+
745
+ // Add link (linked character/paragraph style)
746
+ if (this.properties.link) {
747
+ styleChildren.push(
748
+ XMLBuilder.wSelf("link", { "w:val": this.properties.link })
749
+ );
750
+ }
751
+
752
+ // Add autoRedefine
753
+ if (this.properties.autoRedefine) {
754
+ styleChildren.push(XMLBuilder.wSelf("autoRedefine"));
755
+ }
756
+
757
+ // Add metadata properties — ordered per ECMA-376 CT_Style
758
+ // uiPriority - Sort order in style picker
759
+ if (this.properties.uiPriority !== undefined) {
760
+ styleChildren.push(
761
+ XMLBuilder.wSelf("uiPriority", {
762
+ "w:val": String(this.properties.uiPriority),
763
+ })
764
+ );
765
+ }
766
+
767
+ // semiHidden - Hide from recommended list
768
+ if (this.properties.semiHidden) {
769
+ styleChildren.push(XMLBuilder.wSelf("semiHidden"));
770
+ }
771
+
772
+ // unhideWhenUsed - Auto-show when applied
773
+ if (this.properties.unhideWhenUsed) {
774
+ styleChildren.push(XMLBuilder.wSelf("unhideWhenUsed"));
775
+ }
776
+
777
+ // qFormat - Quick style gallery appearance
778
+ if (this.properties.qFormat !== undefined) {
779
+ if (this.properties.qFormat) {
780
+ styleChildren.push(XMLBuilder.wSelf("qFormat"));
781
+ }
782
+ } else if (!this.properties.customStyle) {
783
+ // Default: built-in styles have qFormat
784
+ styleChildren.push(XMLBuilder.wSelf("qFormat"));
785
+ }
786
+
787
+ // locked - Prevent modification
788
+ if (this.properties.locked) {
789
+ styleChildren.push(XMLBuilder.wSelf("locked"));
790
+ }
791
+
792
+ // personal - User-specific style
793
+ if (this.properties.personal) {
794
+ styleChildren.push(XMLBuilder.wSelf("personal"));
795
+ }
796
+
797
+ // Add paragraph properties
798
+ if (this.properties.paragraphFormatting || this.properties.numPr) {
799
+ const pPr = this.generateParagraphProperties(
800
+ this.properties.paragraphFormatting || {}
801
+ );
802
+ // Add numPr (numbering properties) if present - styles can inherit list formatting
803
+ if (this.properties.numPr) {
804
+ const numPrChildren: XMLElement[] = [];
805
+ if (this.properties.numPr.ilvl !== undefined) {
806
+ numPrChildren.push(
807
+ XMLBuilder.wSelf("ilvl", { "w:val": String(this.properties.numPr.ilvl) })
808
+ );
809
+ }
810
+ if (this.properties.numPr.numId !== undefined) {
811
+ numPrChildren.push(
812
+ XMLBuilder.wSelf("numId", { "w:val": String(this.properties.numPr.numId) })
813
+ );
814
+ }
815
+ if (numPrChildren.length > 0) {
816
+ // Insert numPr at the beginning of pPr children (per ECMA-376 element order)
817
+ if (pPr.children) {
818
+ pPr.children.unshift(XMLBuilder.w("numPr", undefined, numPrChildren));
819
+ } else {
820
+ pPr.children = [XMLBuilder.w("numPr", undefined, numPrChildren)];
821
+ }
822
+ }
823
+ }
824
+ if (pPr.children && pPr.children.length > 0) {
825
+ styleChildren.push(pPr);
826
+ }
827
+ }
828
+
829
+ // Add run properties
830
+ if (this.properties.runFormatting) {
831
+ const rPr = this.generateRunProperties(this.properties.runFormatting);
832
+ if (rPr.children && rPr.children.length > 0) {
833
+ styleChildren.push(rPr);
834
+ }
835
+ }
836
+
837
+ // Add table style properties (Phase 5.1)
838
+ if (this.properties.tableStyle) {
839
+ // Add tblPr (table properties)
840
+ if (this.properties.tableStyle.table) {
841
+ const tblPr = this.generateTableProperties(
842
+ this.properties.tableStyle.table,
843
+ this.properties.tableStyle
844
+ );
845
+ if (tblPr.children && tblPr.children.length > 0) {
846
+ styleChildren.push(tblPr);
847
+ }
848
+ }
849
+
850
+ // Add trPr (table row properties) — per CT_Style: tblPr → trPr → tcPr
851
+ if (this.properties.tableStyle.row) {
852
+ const trPr = this.generateTableRowProperties(
853
+ this.properties.tableStyle.row
854
+ );
855
+ if (trPr.children && trPr.children.length > 0) {
856
+ styleChildren.push(trPr);
857
+ }
858
+ }
859
+
860
+ // Add tcPr (table cell properties)
861
+ if (this.properties.tableStyle.cell) {
862
+ const tcPr = this.generateTableCellProperties(
863
+ this.properties.tableStyle.cell
864
+ );
865
+ if (tcPr.children && tcPr.children.length > 0) {
866
+ styleChildren.push(tcPr);
867
+ }
868
+ }
869
+
870
+ // Add conditional formatting (tblStylePr)
871
+ if (this.properties.tableStyle.conditionalFormatting) {
872
+ for (const conditional of this.properties.tableStyle
873
+ .conditionalFormatting) {
874
+ const tblStylePr = this.generateConditionalFormatting(conditional);
875
+ if (tblStylePr.children && tblStylePr.children.length > 0) {
876
+ styleChildren.push(tblStylePr);
877
+ }
878
+ }
879
+ }
880
+ }
881
+
882
+ return XMLBuilder.w("style", styleAttrs, styleChildren);
883
+ }
884
+
885
+ /**
886
+ * Generates paragraph properties XML
887
+ */
888
+ private generateParagraphProperties(
889
+ formatting: ParagraphFormatting
890
+ ): XMLElement {
891
+ const pPrChildren: XMLElement[] = [];
892
+
893
+ // Ordered per ECMA-376 CT_PPrBase
894
+ if (formatting.keepNext) {
895
+ pPrChildren.push(XMLBuilder.wSelf("keepNext"));
896
+ }
897
+ if (formatting.keepLines) {
898
+ pPrChildren.push(XMLBuilder.wSelf("keepLines"));
899
+ }
900
+ if (formatting.pageBreakBefore) {
901
+ pPrChildren.push(XMLBuilder.wSelf("pageBreakBefore"));
902
+ }
903
+
904
+ // Add spacing
905
+ if (formatting.spacing) {
906
+ const spc = formatting.spacing;
907
+ const attributes: Record<string, number | string> = {};
908
+ if (spc.before !== undefined) attributes["w:before"] = spc.before;
909
+ if (spc.after !== undefined) attributes["w:after"] = spc.after;
910
+ if (spc.line !== undefined) attributes["w:line"] = spc.line;
911
+ if (spc.lineRule) attributes["w:lineRule"] = spc.lineRule;
912
+ if (Object.keys(attributes).length > 0) {
913
+ pPrChildren.push(XMLBuilder.wSelf("spacing", attributes));
914
+ }
915
+ }
916
+
917
+ // Add indentation
918
+ if (formatting.indentation) {
919
+ const ind = formatting.indentation;
920
+ const attributes: Record<string, number> = {};
921
+ if (ind.left !== undefined) attributes["w:left"] = ind.left;
922
+ if (ind.right !== undefined) attributes["w:right"] = ind.right;
923
+ if (ind.firstLine !== undefined)
924
+ attributes["w:firstLine"] = ind.firstLine;
925
+ if (ind.hanging !== undefined) attributes["w:hanging"] = ind.hanging;
926
+ if (Object.keys(attributes).length > 0) {
927
+ pPrChildren.push(XMLBuilder.wSelf("ind", attributes));
928
+ }
929
+ }
930
+
931
+ // Contextual spacing per ECMA-376 Part 1 §17.3.1.8
932
+ // Removes spacing between paragraphs of the same style
933
+ if (formatting.contextualSpacing) {
934
+ pPrChildren.push(XMLBuilder.wSelf("contextualSpacing", { "w:val": "1" }));
935
+ }
936
+
937
+ // Add alignment
938
+ if (formatting.alignment) {
939
+ // Map 'justify' to 'both' per ECMA-376 (Word uses 'both' for justified text)
940
+ const alignmentValue =
941
+ formatting.alignment === "justify" ? "both" : formatting.alignment;
942
+ pPrChildren.push(XMLBuilder.wSelf("jc", { "w:val": alignmentValue }));
943
+ }
944
+
945
+ // Add outline level for TOC support (Heading 1 = 0, Heading 2 = 1, etc.)
946
+ if (formatting.outlineLevel !== undefined) {
947
+ pPrChildren.push(
948
+ XMLBuilder.wSelf("outlineLvl", { "w:val": formatting.outlineLevel.toString() })
949
+ );
950
+ }
951
+
952
+ return XMLBuilder.w("pPr", undefined, pPrChildren);
953
+ }
954
+
955
+ /**
956
+ * Generates run properties XML
957
+ */
958
+ private generateRunProperties(formatting: RunFormatting): XMLElement {
959
+ const rPrChildren: XMLElement[] = [];
960
+
961
+ // Add formatting elements — ordered per ECMA-376 CT_RPr
962
+ if (formatting.font) {
963
+ rPrChildren.push(
964
+ XMLBuilder.wSelf("rFonts", {
965
+ "w:ascii": formatting.font,
966
+ "w:hAnsi": formatting.font,
967
+ "w:cs": formatting.font,
968
+ })
969
+ );
970
+ }
971
+ if (formatting.bold) {
972
+ rPrChildren.push(XMLBuilder.wSelf("b"));
973
+ }
974
+ if (formatting.italic) {
975
+ rPrChildren.push(XMLBuilder.wSelf("i"));
976
+ }
977
+ if (formatting.allCaps) {
978
+ rPrChildren.push(XMLBuilder.wSelf("caps"));
979
+ }
980
+ if (formatting.smallCaps) {
981
+ rPrChildren.push(XMLBuilder.wSelf("smallCaps"));
982
+ }
983
+ if (formatting.strike) {
984
+ rPrChildren.push(XMLBuilder.wSelf("strike"));
985
+ }
986
+ if (formatting.dstrike) {
987
+ rPrChildren.push(XMLBuilder.wSelf("dstrike"));
988
+ }
989
+ if (formatting.color) {
990
+ rPrChildren.push(
991
+ XMLBuilder.wSelf("color", { "w:val": formatting.color })
992
+ );
993
+ }
994
+ if (formatting.size !== undefined) {
995
+ const halfPoints = pointsToHalfPoints(formatting.size);
996
+ rPrChildren.push(XMLBuilder.wSelf("sz", { "w:val": halfPoints }));
997
+ rPrChildren.push(XMLBuilder.wSelf("szCs", { "w:val": halfPoints }));
998
+ }
999
+ if (formatting.highlight) {
1000
+ rPrChildren.push(
1001
+ XMLBuilder.wSelf("highlight", { "w:val": formatting.highlight })
1002
+ );
1003
+ }
1004
+ if (formatting.underline) {
1005
+ const underlineValue =
1006
+ typeof formatting.underline === "string"
1007
+ ? formatting.underline
1008
+ : "single";
1009
+ rPrChildren.push(XMLBuilder.wSelf("u", { "w:val": underlineValue }));
1010
+ }
1011
+ if (formatting.subscript) {
1012
+ rPrChildren.push(XMLBuilder.wSelf("vertAlign", { "w:val": "subscript" }));
1013
+ }
1014
+ if (formatting.superscript) {
1015
+ rPrChildren.push(
1016
+ XMLBuilder.wSelf("vertAlign", { "w:val": "superscript" })
1017
+ );
1018
+ }
1019
+
1020
+ return XMLBuilder.w("rPr", undefined, rPrChildren);
1021
+ }
1022
+
1023
+ /**
1024
+ * Generates table properties XML (tblPr) - Phase 5.1
1025
+ */
1026
+ private generateTableProperties(
1027
+ formatting: TableStyleFormatting,
1028
+ tableStyle: TableStyleProperties,
1029
+ isConditional = false
1030
+ ): XMLElement {
1031
+ const tblPrChildren: XMLElement[] = [];
1032
+
1033
+ // Ordered per CT_TblPrBase (ECMA-376 §17.4.60):
1034
+ // tblStyleRowBandSize → tblStyleColBandSize → tblW → jc →
1035
+ // tblCellSpacing → tblInd → tblBorders → shd → tblCellMar
1036
+
1037
+ // Row band size (must come first)
1038
+ if (tableStyle.rowBandSize !== undefined) {
1039
+ tblPrChildren.push(
1040
+ XMLBuilder.wSelf("tblStyleRowBandSize", {
1041
+ "w:val": tableStyle.rowBandSize,
1042
+ })
1043
+ );
1044
+ }
1045
+
1046
+ // Column band size
1047
+ if (tableStyle.colBandSize !== undefined) {
1048
+ tblPrChildren.push(
1049
+ XMLBuilder.wSelf("tblStyleColBandSize", {
1050
+ "w:val": tableStyle.colBandSize,
1051
+ })
1052
+ );
1053
+ }
1054
+
1055
+ // Note: tblW is omitted for table styles. It's only valid in inline tblPr
1056
+ // (CT_TblPr in table elements), not in CT_Style's tblPr.
1057
+
1058
+ // Table alignment
1059
+ if (formatting.alignment) {
1060
+ tblPrChildren.push(
1061
+ XMLBuilder.wSelf("jc", { "w:val": formatting.alignment })
1062
+ );
1063
+ }
1064
+
1065
+ // Cell spacing
1066
+ if (formatting.cellSpacing !== undefined) {
1067
+ tblPrChildren.push(
1068
+ XMLBuilder.wSelf("tblCellSpacing", {
1069
+ "w:w": formatting.cellSpacing,
1070
+ "w:type": "dxa",
1071
+ })
1072
+ );
1073
+ }
1074
+
1075
+ // Table indentation
1076
+ if (formatting.indent !== undefined) {
1077
+ tblPrChildren.push(
1078
+ XMLBuilder.wSelf("tblInd", {
1079
+ "w:w": formatting.indent,
1080
+ "w:type": "dxa",
1081
+ })
1082
+ );
1083
+ }
1084
+
1085
+ // Table borders
1086
+ if (formatting.borders) {
1087
+ const borderElements = this.generateBorderElements(
1088
+ formatting.borders,
1089
+ false
1090
+ );
1091
+ if (borderElements.length > 0) {
1092
+ tblPrChildren.push(
1093
+ XMLBuilder.w("tblBorders", undefined, borderElements)
1094
+ );
1095
+ }
1096
+ }
1097
+
1098
+ // Table shading (not valid in tblStylePr conditional context)
1099
+ if (formatting.shading && !isConditional) {
1100
+ tblPrChildren.push(this.generateShadingElement(formatting.shading));
1101
+ }
1102
+
1103
+ // Cell margins
1104
+ if (formatting.cellMargins) {
1105
+ const marginElements: XMLElement[] = [];
1106
+ if (formatting.cellMargins.top !== undefined) {
1107
+ marginElements.push(
1108
+ XMLBuilder.wSelf("top", {
1109
+ "w:w": formatting.cellMargins.top,
1110
+ "w:type": "dxa",
1111
+ })
1112
+ );
1113
+ }
1114
+ if (formatting.cellMargins.left !== undefined) {
1115
+ marginElements.push(
1116
+ XMLBuilder.wSelf("left", {
1117
+ "w:w": formatting.cellMargins.left,
1118
+ "w:type": "dxa",
1119
+ })
1120
+ );
1121
+ }
1122
+ if (formatting.cellMargins.bottom !== undefined) {
1123
+ marginElements.push(
1124
+ XMLBuilder.wSelf("bottom", {
1125
+ "w:w": formatting.cellMargins.bottom,
1126
+ "w:type": "dxa",
1127
+ })
1128
+ );
1129
+ }
1130
+ if (formatting.cellMargins.right !== undefined) {
1131
+ marginElements.push(
1132
+ XMLBuilder.wSelf("right", {
1133
+ "w:w": formatting.cellMargins.right,
1134
+ "w:type": "dxa",
1135
+ })
1136
+ );
1137
+ }
1138
+ if (marginElements.length > 0) {
1139
+ tblPrChildren.push(
1140
+ XMLBuilder.w("tblCellMar", undefined, marginElements)
1141
+ );
1142
+ }
1143
+ }
1144
+
1145
+ return XMLBuilder.w("tblPr", undefined, tblPrChildren);
1146
+ }
1147
+
1148
+ /**
1149
+ * Generates table cell properties XML (tcPr) - Phase 5.1
1150
+ */
1151
+ private generateTableCellProperties(
1152
+ formatting: TableCellStyleFormatting
1153
+ ): XMLElement {
1154
+ const tcPrChildren: XMLElement[] = [];
1155
+
1156
+ // Cell borders
1157
+ if (formatting.borders) {
1158
+ const borderElements = this.generateBorderElements(
1159
+ formatting.borders,
1160
+ true
1161
+ );
1162
+ if (borderElements.length > 0) {
1163
+ tcPrChildren.push(XMLBuilder.w("tcBorders", undefined, borderElements));
1164
+ }
1165
+ }
1166
+
1167
+ // Cell shading
1168
+ if (formatting.shading) {
1169
+ tcPrChildren.push(this.generateShadingElement(formatting.shading));
1170
+ }
1171
+
1172
+ // Cell margins
1173
+ if (formatting.margins) {
1174
+ const marginElements: XMLElement[] = [];
1175
+ if (formatting.margins.top !== undefined) {
1176
+ marginElements.push(
1177
+ XMLBuilder.wSelf("top", {
1178
+ "w:w": formatting.margins.top,
1179
+ "w:type": "dxa",
1180
+ })
1181
+ );
1182
+ }
1183
+ if (formatting.margins.left !== undefined) {
1184
+ marginElements.push(
1185
+ XMLBuilder.wSelf("left", {
1186
+ "w:w": formatting.margins.left,
1187
+ "w:type": "dxa",
1188
+ })
1189
+ );
1190
+ }
1191
+ if (formatting.margins.bottom !== undefined) {
1192
+ marginElements.push(
1193
+ XMLBuilder.wSelf("bottom", {
1194
+ "w:w": formatting.margins.bottom,
1195
+ "w:type": "dxa",
1196
+ })
1197
+ );
1198
+ }
1199
+ if (formatting.margins.right !== undefined) {
1200
+ marginElements.push(
1201
+ XMLBuilder.wSelf("right", {
1202
+ "w:w": formatting.margins.right,
1203
+ "w:type": "dxa",
1204
+ })
1205
+ );
1206
+ }
1207
+ if (marginElements.length > 0) {
1208
+ tcPrChildren.push(XMLBuilder.w("tcMar", undefined, marginElements));
1209
+ }
1210
+ }
1211
+
1212
+ // Vertical alignment
1213
+ if (formatting.verticalAlignment) {
1214
+ tcPrChildren.push(
1215
+ XMLBuilder.wSelf("vAlign", { "w:val": formatting.verticalAlignment })
1216
+ );
1217
+ }
1218
+
1219
+ return XMLBuilder.w("tcPr", undefined, tcPrChildren);
1220
+ }
1221
+
1222
+ /**
1223
+ * Generates table row properties XML (trPr) - Phase 5.1
1224
+ */
1225
+ private generateTableRowProperties(
1226
+ formatting: TableRowStyleFormatting
1227
+ ): XMLElement {
1228
+ const trPrChildren: XMLElement[] = [];
1229
+
1230
+ // Style-level trPr has a restricted content model compared to inline trPr.
1231
+ // Valid children: cantSplit, tblHeader, tblCellSpacing, jc, hidden
1232
+ // NOTE: trHeight is NOT valid in style-level trPr per OOXML strict schema.
1233
+
1234
+ // Can't split row across pages
1235
+ if (formatting.cantSplit) {
1236
+ trPrChildren.push(XMLBuilder.wSelf("cantSplit"));
1237
+ }
1238
+
1239
+ // Header row
1240
+ if (formatting.isHeader) {
1241
+ trPrChildren.push(XMLBuilder.wSelf("tblHeader"));
1242
+ }
1243
+
1244
+ return XMLBuilder.w("trPr", undefined, trPrChildren);
1245
+ }
1246
+
1247
+ /**
1248
+ * Generates conditional formatting XML (tblStylePr) - Phase 5.1
1249
+ */
1250
+ private generateConditionalFormatting(
1251
+ conditional: ConditionalTableFormatting
1252
+ ): XMLElement {
1253
+ const tblStylePrChildren: XMLElement[] = [];
1254
+
1255
+ // Add paragraph properties if specified
1256
+ if (conditional.paragraphFormatting) {
1257
+ const pPr = this.generateParagraphProperties(
1258
+ conditional.paragraphFormatting
1259
+ );
1260
+ if (pPr.children && pPr.children.length > 0) {
1261
+ tblStylePrChildren.push(pPr);
1262
+ }
1263
+ }
1264
+
1265
+ // Add run properties if specified
1266
+ if (conditional.runFormatting) {
1267
+ const rPr = this.generateRunProperties(conditional.runFormatting);
1268
+ if (rPr.children && rPr.children.length > 0) {
1269
+ tblStylePrChildren.push(rPr);
1270
+ }
1271
+ }
1272
+
1273
+ // Add table properties if specified
1274
+ if (conditional.tableFormatting) {
1275
+ const tblPr = this.generateTableProperties(
1276
+ conditional.tableFormatting,
1277
+ {},
1278
+ true
1279
+ );
1280
+ if (tblPr.children && tblPr.children.length > 0) {
1281
+ tblStylePrChildren.push(tblPr);
1282
+ }
1283
+ }
1284
+
1285
+ // Add cell properties if specified
1286
+ if (conditional.cellFormatting) {
1287
+ const tcPr = this.generateTableCellProperties(conditional.cellFormatting);
1288
+ if (tcPr.children && tcPr.children.length > 0) {
1289
+ tblStylePrChildren.push(tcPr);
1290
+ }
1291
+ }
1292
+
1293
+ // Add row properties if specified
1294
+ if (conditional.rowFormatting) {
1295
+ const trPr = this.generateTableRowProperties(conditional.rowFormatting);
1296
+ if (trPr.children && trPr.children.length > 0) {
1297
+ tblStylePrChildren.push(trPr);
1298
+ }
1299
+ }
1300
+
1301
+ return XMLBuilder.w(
1302
+ "tblStylePr",
1303
+ { "w:type": conditional.type },
1304
+ tblStylePrChildren
1305
+ );
1306
+ }
1307
+
1308
+ /**
1309
+ * Generates border elements for tables or cells - Phase 5.1
1310
+ * @param borders - Border properties
1311
+ * @param includeDiagonals - Whether to include diagonal borders (for cells)
1312
+ */
1313
+ private generateBorderElements(
1314
+ borders: TableBorders | CellBorders,
1315
+ includeDiagonals: boolean
1316
+ ): XMLElement[] {
1317
+ const borderElements: XMLElement[] = [];
1318
+
1319
+ // Ordered per ECMA-376 CT_TblBorders / CT_TcBorders: top, left, bottom, right
1320
+ const borderProps = [
1321
+ "top",
1322
+ "left",
1323
+ "bottom",
1324
+ "right",
1325
+ "insideH",
1326
+ "insideV",
1327
+ ] as const;
1328
+ for (const prop of borderProps) {
1329
+ const border = borders[prop];
1330
+ if (border) {
1331
+ const attrs: Record<string, string | number> = {};
1332
+ if (border.style) attrs["w:val"] = border.style;
1333
+ if (border.size !== undefined) attrs["w:sz"] = border.size;
1334
+ if (border.space !== undefined) attrs["w:space"] = border.space;
1335
+ if (border.color) attrs["w:color"] = border.color;
1336
+
1337
+ if (Object.keys(attrs).length > 0) {
1338
+ borderElements.push(XMLBuilder.wSelf(prop, attrs));
1339
+ }
1340
+ }
1341
+ }
1342
+
1343
+ // Add diagonal borders for cells
1344
+ if (includeDiagonals) {
1345
+ const cellBorders = borders as CellBorders;
1346
+ if (cellBorders.tl2br) {
1347
+ const attrs: Record<string, string | number> = {};
1348
+ if (cellBorders.tl2br.style) attrs["w:val"] = cellBorders.tl2br.style;
1349
+ if (cellBorders.tl2br.size !== undefined)
1350
+ attrs["w:sz"] = cellBorders.tl2br.size;
1351
+ if (cellBorders.tl2br.space !== undefined)
1352
+ attrs["w:space"] = cellBorders.tl2br.space;
1353
+ if (cellBorders.tl2br.color) attrs["w:color"] = cellBorders.tl2br.color;
1354
+
1355
+ if (Object.keys(attrs).length > 0) {
1356
+ borderElements.push(XMLBuilder.wSelf("tl2br", attrs));
1357
+ }
1358
+ }
1359
+ if (cellBorders.tr2bl) {
1360
+ const attrs: Record<string, string | number> = {};
1361
+ if (cellBorders.tr2bl.style) attrs["w:val"] = cellBorders.tr2bl.style;
1362
+ if (cellBorders.tr2bl.size !== undefined)
1363
+ attrs["w:sz"] = cellBorders.tr2bl.size;
1364
+ if (cellBorders.tr2bl.space !== undefined)
1365
+ attrs["w:space"] = cellBorders.tr2bl.space;
1366
+ if (cellBorders.tr2bl.color) attrs["w:color"] = cellBorders.tr2bl.color;
1367
+
1368
+ if (Object.keys(attrs).length > 0) {
1369
+ borderElements.push(XMLBuilder.wSelf("tr2bl", attrs));
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ return borderElements;
1375
+ }
1376
+
1377
+ /**
1378
+ * Generates shading element - Phase 5.1
1379
+ */
1380
+ private generateShadingElement(shading: ShadingProperties): XMLElement {
1381
+ const attrs = buildShadingAttributes(shading);
1382
+ return XMLBuilder.wSelf("shd", attrs);
1383
+ }
1384
+
1385
+ /**
1386
+ * Creates a new Style
1387
+ * @param properties - Style properties
1388
+ * @returns New Style instance
1389
+ */
1390
+ static create(properties: StyleProperties): Style {
1391
+ return new Style(properties);
1392
+ }
1393
+
1394
+ /**
1395
+ * Creates the Normal style (default paragraph style)
1396
+ * @returns Normal style
1397
+ */
1398
+ static createNormalStyle(): Style {
1399
+ return new Style({
1400
+ styleId: "Normal",
1401
+ name: "Normal",
1402
+ type: "paragraph",
1403
+ isDefault: true,
1404
+ next: "Normal",
1405
+ qFormat: true,
1406
+ uiPriority: 0,
1407
+ paragraphFormatting: {
1408
+ alignment: "left",
1409
+ spacing: {
1410
+ before: 60, // 3pt
1411
+ after: 60, // 3pt
1412
+ line: 240, // Single line spacing
1413
+ lineRule: "auto",
1414
+ },
1415
+ },
1416
+ runFormatting: {
1417
+ font: "Verdana",
1418
+ size: 12,
1419
+ color: "000000",
1420
+ },
1421
+ });
1422
+ }
1423
+
1424
+ /**
1425
+ * Creates a Heading style
1426
+ * @param level - Heading level (1-9)
1427
+ * @returns Heading style
1428
+ */
1429
+ static createHeadingStyle(level: number): Style {
1430
+ if (level < 1 || level > 9) {
1431
+ throw new Error("Heading level must be between 1 and 9");
1432
+ }
1433
+
1434
+ // Font sizes: H1=18pt, H2=14pt, H3=12pt, H4-9=12pt
1435
+ const sizes = [18, 14, 12, 12, 12, 12, 12, 12, 12];
1436
+
1437
+ // Spacing before: H1=0pt, H2=6pt, H3=3pt, H4-9=6pt (in twips: 1pt = 20 twips)
1438
+ const spacingBefore =
1439
+ level === 1 ? 0 : level === 2 ? 120 : level === 3 ? 60 : 120;
1440
+
1441
+ // Spacing after: H1=12pt, H2=6pt, H3=3pt, H4-9=6pt (in twips)
1442
+ const spacingAfter =
1443
+ level === 1 ? 240 : level === 2 ? 120 : level === 3 ? 60 : 120;
1444
+
1445
+ return new Style({
1446
+ styleId: `Heading${level}`,
1447
+ name: `Heading ${level}`,
1448
+ type: "paragraph",
1449
+ basedOn: "Normal",
1450
+ next: "Normal",
1451
+ link: `Heading${level}Char`,
1452
+ qFormat: true,
1453
+ uiPriority: 9,
1454
+ paragraphFormatting: {
1455
+ alignment: "left",
1456
+ spacing: {
1457
+ before: spacingBefore,
1458
+ after: spacingAfter,
1459
+ line: 240, // Single line spacing
1460
+ lineRule: "auto",
1461
+ },
1462
+ keepNext: true,
1463
+ keepLines: true,
1464
+ outlineLevel: level - 1, // Heading 1 = 0, Heading 2 = 1, etc. Required for TOC
1465
+ },
1466
+ runFormatting: {
1467
+ font: "Verdana",
1468
+ size: sizes[level - 1],
1469
+ bold: true,
1470
+ color: "000000",
1471
+ },
1472
+ });
1473
+ }
1474
+
1475
+ /**
1476
+ * Creates a Heading character style (linked to paragraph style)
1477
+ * @param level - Heading level (1-9)
1478
+ * @returns Heading character style
1479
+ */
1480
+ static createHeadingCharStyle(level: number): Style {
1481
+ if (level < 1 || level > 9) {
1482
+ throw new Error("Heading level must be between 1 and 9");
1483
+ }
1484
+
1485
+ // Font sizes: H1=18pt, H2=14pt, H3=12pt, H4-9=12pt
1486
+ const sizes = [18, 14, 12, 12, 12, 12, 12, 12, 12];
1487
+
1488
+ return new Style({
1489
+ styleId: `Heading${level}Char`,
1490
+ name: `Heading ${level} Char`,
1491
+ type: "character",
1492
+ link: `Heading${level}`,
1493
+ qFormat: true,
1494
+ uiPriority: 9,
1495
+ runFormatting: {
1496
+ font: "Verdana",
1497
+ size: sizes[level - 1],
1498
+ bold: true,
1499
+ color: "000000",
1500
+ },
1501
+ });
1502
+ }
1503
+
1504
+ /**
1505
+ * Creates the Title style
1506
+ * @returns Title style
1507
+ */
1508
+ static createTitleStyle(): Style {
1509
+ return new Style({
1510
+ styleId: "Title",
1511
+ name: "Title",
1512
+ type: "paragraph",
1513
+ basedOn: "Normal",
1514
+ next: "Normal",
1515
+ paragraphFormatting: {
1516
+ spacing: {
1517
+ after: 120,
1518
+ },
1519
+ },
1520
+ runFormatting: {
1521
+ font: "Verdana",
1522
+ size: 28,
1523
+ color: "000000",
1524
+ },
1525
+ });
1526
+ }
1527
+
1528
+ /**
1529
+ * Creates the Subtitle style
1530
+ * @returns Subtitle style
1531
+ */
1532
+ static createSubtitleStyle(): Style {
1533
+ return new Style({
1534
+ styleId: "Subtitle",
1535
+ name: "Subtitle",
1536
+ type: "paragraph",
1537
+ basedOn: "Normal",
1538
+ next: "Normal",
1539
+ paragraphFormatting: {
1540
+ spacing: {
1541
+ after: 120,
1542
+ },
1543
+ },
1544
+ runFormatting: {
1545
+ font: "Verdana",
1546
+ size: 14,
1547
+ color: "000000",
1548
+ italic: true,
1549
+ },
1550
+ });
1551
+ }
1552
+
1553
+ /**
1554
+ * Creates a List Paragraph style (for lists)
1555
+ * @returns List Paragraph style
1556
+ */
1557
+ static createListParagraphStyle(): Style {
1558
+ return new Style({
1559
+ styleId: "ListParagraph",
1560
+ name: "List Paragraph",
1561
+ type: "paragraph",
1562
+ basedOn: "Normal",
1563
+ next: "ListParagraph",
1564
+ qFormat: true,
1565
+ uiPriority: 34,
1566
+ paragraphFormatting: {
1567
+ alignment: "left",
1568
+ indentation: {
1569
+ left: 720, // 0.5 inch (text indentation)
1570
+ hanging: 360, // 0.25 inch (bullet/number indentation)
1571
+ },
1572
+ spacing: {
1573
+ before: 0, // 0pt
1574
+ after: 60, // 3pt
1575
+ line: 240, // Single line spacing
1576
+ lineRule: "auto",
1577
+ },
1578
+ contextualSpacing: true, // No space between similar paragraphs
1579
+ },
1580
+ runFormatting: {
1581
+ font: "Verdana",
1582
+ size: 12,
1583
+ color: "000000",
1584
+ },
1585
+ });
1586
+ }
1587
+
1588
+ /**
1589
+ * Creates a TOC Heading style (for table of contents titles)
1590
+ * @returns TOC Heading style
1591
+ */
1592
+ static createTOCHeadingStyle(): Style {
1593
+ return new Style({
1594
+ styleId: "TOCHeading",
1595
+ name: "TOC Heading",
1596
+ type: "paragraph",
1597
+ basedOn: "Heading1",
1598
+ next: "Normal",
1599
+ runFormatting: {
1600
+ bold: true,
1601
+ font: "Verdana",
1602
+ size: 14,
1603
+ color: "000000", // Black
1604
+ },
1605
+ paragraphFormatting: {
1606
+ spacing: {
1607
+ before: 480, // Larger spacing before TOC
1608
+ after: 240,
1609
+ },
1610
+ },
1611
+ });
1612
+ }
1613
+
1614
+ /**
1615
+ * Creates a TOC entry style for a specific level (1-9).
1616
+ * TOC 1-9 are built-in Word styles for Table of Contents entries.
1617
+ * When Word updates a TOC field, it applies these styles to the generated entries.
1618
+ *
1619
+ * @param level - TOC level (1-9)
1620
+ * @param formatting - Optional run and paragraph formatting overrides
1621
+ * @returns TOC style for the specified level
1622
+ */
1623
+ static createTOCStyle(
1624
+ level: number,
1625
+ formatting?: {
1626
+ run?: RunFormatting;
1627
+ paragraph?: ParagraphFormatting;
1628
+ }
1629
+ ): Style {
1630
+ if (level < 1 || level > 9) {
1631
+ throw new Error("TOC level must be between 1 and 9");
1632
+ }
1633
+
1634
+ // Default indentation: 220 twips per level (11pt)
1635
+ const defaultLeftIndent = (level - 1) * 220;
1636
+
1637
+ return Style.create({
1638
+ styleId: `TOC${level}`,
1639
+ name: `toc ${level}`,
1640
+ type: "paragraph",
1641
+ basedOn: "Normal",
1642
+ uiPriority: 39,
1643
+ semiHidden: true,
1644
+ unhideWhenUsed: true,
1645
+ runFormatting: formatting?.run,
1646
+ paragraphFormatting: {
1647
+ indentation: { left: defaultLeftIndent },
1648
+ ...formatting?.paragraph,
1649
+ },
1650
+ });
1651
+ }
1652
+
1653
+ /**
1654
+ * Creates a Table Normal style (Phase 5.1)
1655
+ * @returns Table Normal style
1656
+ */
1657
+ static createTableNormalStyle(): Style {
1658
+ return new Style({
1659
+ styleId: "TableNormal",
1660
+ name: "Table Normal",
1661
+ type: "table",
1662
+ basedOn: "Normal",
1663
+ tableStyle: {
1664
+ table: {
1665
+ cellMargins: {
1666
+ top: 0,
1667
+ left: 108, // ~0.075 inch
1668
+ bottom: 0,
1669
+ right: 108,
1670
+ },
1671
+ },
1672
+ rowBandSize: 1,
1673
+ colBandSize: 1,
1674
+ },
1675
+ });
1676
+ }
1677
+
1678
+ /**
1679
+ * Creates a Table Grid style with borders (Phase 5.1)
1680
+ * @returns Table Grid style
1681
+ */
1682
+ static createTableGridStyle(): Style {
1683
+ return new Style({
1684
+ styleId: "TableGrid",
1685
+ name: "Table Grid",
1686
+ type: "table",
1687
+ basedOn: "TableNormal",
1688
+ tableStyle: {
1689
+ table: {
1690
+ borders: {
1691
+ top: { style: "single", size: 4, color: "000000" },
1692
+ bottom: { style: "single", size: 4, color: "000000" },
1693
+ left: { style: "single", size: 4, color: "000000" },
1694
+ right: { style: "single", size: 4, color: "000000" },
1695
+ insideH: { style: "single", size: 4, color: "000000" },
1696
+ insideV: { style: "single", size: 4, color: "000000" },
1697
+ },
1698
+ cellMargins: {
1699
+ top: 0,
1700
+ left: 108,
1701
+ bottom: 0,
1702
+ right: 108,
1703
+ },
1704
+ },
1705
+ rowBandSize: 1,
1706
+ colBandSize: 1,
1707
+ },
1708
+ });
1709
+ }
1710
+
1711
+ /**
1712
+ * Creates a deep clone of this style
1713
+ * @returns New Style instance with copied properties
1714
+ * @example
1715
+ * ```typescript
1716
+ * const original = Style.createHeadingStyle(1);
1717
+ * const copy = original.clone();
1718
+ * copy.setRunFormatting({ color: 'FF0000' }); // Doesn't affect original
1719
+ * ```
1720
+ */
1721
+ clone(): Style {
1722
+ // Deep copy all properties
1723
+ const clonedProps: StyleProperties = deepClone(this.properties);
1724
+ return new Style(clonedProps);
1725
+ }
1726
+
1727
+ /**
1728
+ * Resets the style to its minimal state
1729
+ * Clears all paragraph and run formatting while preserving the style identity
1730
+ * @returns This style for chaining
1731
+ * @example
1732
+ * ```typescript
1733
+ * const style = Style.createHeadingStyle(1);
1734
+ * style.reset(); // Clears all formatting, keeps styleId and name
1735
+ * ```
1736
+ */
1737
+ reset(): this {
1738
+ // Preserve identity properties
1739
+ const { styleId, name, type, basedOn } = this.properties;
1740
+
1741
+ // Reset to minimal properties
1742
+ this.properties = {
1743
+ styleId,
1744
+ name,
1745
+ type,
1746
+ basedOn,
1747
+ };
1748
+
1749
+ return this;
1750
+ }
1751
+
1752
+ /**
1753
+ * Merges properties from another style into this one
1754
+ * @param otherStyle - Style to merge from
1755
+ * @returns This style for chaining
1756
+ * @example
1757
+ * ```typescript
1758
+ * const base = Style.createNormalStyle();
1759
+ * const override = Style.create({
1760
+ * styleId: 'Override',
1761
+ * name: 'Override',
1762
+ * type: 'paragraph',
1763
+ * runFormatting: { bold: true, color: 'FF0000' }
1764
+ * });
1765
+ * base.mergeWith(override); // base now has bold red text
1766
+ * ```
1767
+ */
1768
+ mergeWith(otherStyle: Style): this {
1769
+ const otherProps = otherStyle.getProperties();
1770
+
1771
+ // Merge paragraph formatting
1772
+ if (otherProps.paragraphFormatting) {
1773
+ if (!this.properties.paragraphFormatting) {
1774
+ this.properties.paragraphFormatting = {};
1775
+ }
1776
+
1777
+ // Merge top-level paragraph properties
1778
+ if (otherProps.paragraphFormatting.alignment) {
1779
+ this.properties.paragraphFormatting.alignment =
1780
+ otherProps.paragraphFormatting.alignment;
1781
+ }
1782
+ if (otherProps.paragraphFormatting.keepNext !== undefined) {
1783
+ this.properties.paragraphFormatting.keepNext =
1784
+ otherProps.paragraphFormatting.keepNext;
1785
+ }
1786
+ if (otherProps.paragraphFormatting.keepLines !== undefined) {
1787
+ this.properties.paragraphFormatting.keepLines =
1788
+ otherProps.paragraphFormatting.keepLines;
1789
+ }
1790
+ if (otherProps.paragraphFormatting.pageBreakBefore !== undefined) {
1791
+ this.properties.paragraphFormatting.pageBreakBefore =
1792
+ otherProps.paragraphFormatting.pageBreakBefore;
1793
+ }
1794
+
1795
+ // Merge indentation
1796
+ if (otherProps.paragraphFormatting.indentation) {
1797
+ if (!this.properties.paragraphFormatting.indentation) {
1798
+ this.properties.paragraphFormatting.indentation = {};
1799
+ }
1800
+ Object.assign(
1801
+ this.properties.paragraphFormatting.indentation,
1802
+ otherProps.paragraphFormatting.indentation
1803
+ );
1804
+ }
1805
+
1806
+ // Merge spacing
1807
+ if (otherProps.paragraphFormatting.spacing) {
1808
+ if (!this.properties.paragraphFormatting.spacing) {
1809
+ this.properties.paragraphFormatting.spacing = {};
1810
+ }
1811
+ Object.assign(
1812
+ this.properties.paragraphFormatting.spacing,
1813
+ otherProps.paragraphFormatting.spacing
1814
+ );
1815
+ }
1816
+ }
1817
+
1818
+ // Merge run formatting
1819
+ if (otherProps.runFormatting) {
1820
+ if (!this.properties.runFormatting) {
1821
+ this.properties.runFormatting = {};
1822
+ }
1823
+ Object.assign(this.properties.runFormatting, otherProps.runFormatting);
1824
+ }
1825
+
1826
+ // Merge other properties (but don't override styleId)
1827
+ if (otherProps.name) this.properties.name = otherProps.name;
1828
+ if (otherProps.basedOn) this.properties.basedOn = otherProps.basedOn;
1829
+ if (otherProps.next) this.properties.next = otherProps.next;
1830
+
1831
+ return this;
1832
+ }
1833
+ }