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,1005 @@
1
+ /**
2
+ * StylesManager - Manages the collection of styles in a document
3
+ * Handles style registration, retrieval, and styles.xml generation
4
+ */
5
+
6
+ import { Paragraph } from "../elements/Paragraph";
7
+ import { XMLBuilder } from "../xml/XMLBuilder";
8
+ import { XMLParser } from "../xml/XMLParser";
9
+ import { Style, StyleType } from "./Style";
10
+
11
+ /**
12
+ * Result of XML validation
13
+ */
14
+ export interface ValidationResult {
15
+ /** Whether the XML is valid */
16
+ isValid: boolean;
17
+ /** Validation errors if any */
18
+ errors: string[];
19
+ /** Validation warnings if any */
20
+ warnings: string[];
21
+ /** Number of styles found */
22
+ styleCount: number;
23
+ /** List of style IDs found */
24
+ styleIds: string[];
25
+ }
26
+
27
+ /**
28
+ * Manages document styles
29
+ */
30
+ export class StylesManager {
31
+ private styles = new Map<string, Style>();
32
+ private includeBuiltInStyles: boolean;
33
+
34
+ // Track if styles have been modified (for XML preservation)
35
+ private _modified = false;
36
+
37
+ // Track which specific styles have been modified (for selective merging)
38
+ private _modifiedStyleIds = new Set<string>();
39
+
40
+ /**
41
+ * Registry of built-in style factory functions
42
+ * Maps style ID to factory function for lazy loading
43
+ */
44
+ private static readonly BUILT_IN_STYLE_FACTORIES = new Map<
45
+ string,
46
+ () => Style
47
+ >([
48
+ ["Normal", () => Style.createNormalStyle()],
49
+ ["Heading1", () => Style.createHeadingStyle(1)],
50
+ ["Heading2", () => Style.createHeadingStyle(2)],
51
+ ["Heading3", () => Style.createHeadingStyle(3)],
52
+ ["Heading4", () => Style.createHeadingStyle(4)],
53
+ ["Heading5", () => Style.createHeadingStyle(5)],
54
+ ["Heading6", () => Style.createHeadingStyle(6)],
55
+ ["Heading7", () => Style.createHeadingStyle(7)],
56
+ ["Heading8", () => Style.createHeadingStyle(8)],
57
+ ["Heading9", () => Style.createHeadingStyle(9)],
58
+ ["Heading1Char", () => Style.createHeadingCharStyle(1)],
59
+ ["Heading2Char", () => Style.createHeadingCharStyle(2)],
60
+ ["Heading3Char", () => Style.createHeadingCharStyle(3)],
61
+ ["Heading4Char", () => Style.createHeadingCharStyle(4)],
62
+ ["Heading5Char", () => Style.createHeadingCharStyle(5)],
63
+ ["Heading6Char", () => Style.createHeadingCharStyle(6)],
64
+ ["Heading7Char", () => Style.createHeadingCharStyle(7)],
65
+ ["Heading8Char", () => Style.createHeadingCharStyle(8)],
66
+ ["Heading9Char", () => Style.createHeadingCharStyle(9)],
67
+ ["Title", () => Style.createTitleStyle()],
68
+ ["Subtitle", () => Style.createSubtitleStyle()],
69
+ ["ListParagraph", () => Style.createListParagraphStyle()],
70
+ ["TOCHeading", () => Style.createTOCHeadingStyle()],
71
+ ["TableNormal", () => Style.createTableNormalStyle()],
72
+ ["TableGrid", () => Style.createTableGridStyle()],
73
+ ]);
74
+
75
+ /**
76
+ * Creates a new StylesManager
77
+ * @param includeBuiltInStyles - Whether to include built-in styles (default: true)
78
+ */
79
+ constructor(includeBuiltInStyles = true) {
80
+ this.includeBuiltInStyles = includeBuiltInStyles;
81
+
82
+ // Always load Normal style if built-in styles are enabled
83
+ // Normal is required and referenced by most other styles
84
+ if (includeBuiltInStyles) {
85
+ this.ensureStyleLoaded("Normal");
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Ensures a built-in style is loaded (lazy loading)
91
+ * @param styleId - Style ID to load
92
+ */
93
+ private ensureStyleLoaded(styleId: string): void {
94
+ // Already loaded?
95
+ if (this.styles.has(styleId)) {
96
+ return;
97
+ }
98
+
99
+ // Built-in styles disabled?
100
+ if (!this.includeBuiltInStyles) {
101
+ return;
102
+ }
103
+
104
+ // Is this a built-in style?
105
+ const factory = StylesManager.BUILT_IN_STYLE_FACTORIES.get(styleId);
106
+ if (factory) {
107
+ this.styles.set(styleId, factory());
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Adds a style to the collection
113
+ * @param style - Style to add
114
+ * @returns This manager for chaining
115
+ */
116
+ addStyle(style: Style): this {
117
+ const existing = this.styles.get(style.getStyleId());
118
+ if (existing) {
119
+ // Preserve isDefault flag if replacing an existing default style
120
+ if (existing.getIsDefault() && !style.getIsDefault()) {
121
+ style.setIsDefault(true);
122
+ }
123
+ // Preserve structural properties from existing style if not explicitly set on new
124
+ const newProps = style.getProperties();
125
+ const existingProps = existing.getProperties();
126
+ if (newProps.basedOn === undefined && existingProps.basedOn !== undefined) {
127
+ style.setBasedOn(existingProps.basedOn);
128
+ }
129
+ if (newProps.next === undefined && existingProps.next !== undefined) {
130
+ style.setNext(existingProps.next);
131
+ }
132
+ if (newProps.link === undefined && existingProps.link !== undefined) {
133
+ style.setLink(existingProps.link);
134
+ }
135
+ if (newProps.uiPriority === undefined && existingProps.uiPriority !== undefined) {
136
+ style.setUiPriority(existingProps.uiPriority);
137
+ }
138
+ }
139
+ this.styles.set(style.getStyleId(), style);
140
+ this._modifiedStyleIds.add(style.getStyleId());
141
+ this._modified = true;
142
+ return this;
143
+ }
144
+
145
+ /**
146
+ * Gets a style by ID
147
+ * Lazy-loads built-in styles on first access
148
+ * @param styleId - Style ID to retrieve
149
+ * @returns The style, or undefined if not found
150
+ */
151
+ getStyle(styleId: string): Style | undefined {
152
+ // Ensure built-in style is loaded if applicable
153
+ this.ensureStyleLoaded(styleId);
154
+ return this.styles.get(styleId);
155
+ }
156
+
157
+ /**
158
+ * Checks if a style exists or can be loaded
159
+ * @param styleId - Style ID to check
160
+ * @returns True if the style exists or is a built-in style
161
+ */
162
+ hasStyle(styleId: string): boolean {
163
+ // Check if already loaded
164
+ if (this.styles.has(styleId)) {
165
+ return true;
166
+ }
167
+
168
+ // Check if it's a built-in style that can be loaded
169
+ return (
170
+ this.includeBuiltInStyles &&
171
+ StylesManager.BUILT_IN_STYLE_FACTORIES.has(styleId)
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Removes a style from the collection
177
+ * @param styleId - Style ID to remove
178
+ * @returns True if the style was removed
179
+ */
180
+ removeStyle(styleId: string): boolean {
181
+ return this.styles.delete(styleId);
182
+ }
183
+
184
+ /**
185
+ * Gets all styles
186
+ * @returns Array of all styles
187
+ */
188
+ getAllStyles(): Style[] {
189
+ return Array.from(this.styles.values());
190
+ }
191
+
192
+ /**
193
+ * Checks if styles have been modified since loading
194
+ * Used for XML preservation optimization
195
+ * @returns True if styles were added or modified
196
+ */
197
+ isModified(): boolean {
198
+ return this._modified;
199
+ }
200
+
201
+ /**
202
+ * Resets the modified flag
203
+ * Called after parsing to indicate that loaded styles don't count as modifications
204
+ */
205
+ resetModified(): void {
206
+ this._modified = false;
207
+ this._modifiedStyleIds.clear();
208
+ }
209
+
210
+ /**
211
+ * Gets the IDs of styles that have been modified since loading
212
+ * Used for selective merging with original styles.xml
213
+ * @returns Set of modified style IDs
214
+ */
215
+ getModifiedStyleIds(): Set<string> {
216
+ return new Set(this._modifiedStyleIds);
217
+ }
218
+
219
+ /**
220
+ * Gets styles by type
221
+ * @param type - Style type to filter by
222
+ * @returns Array of styles matching the type
223
+ */
224
+ getStylesByType(type: StyleType): Style[] {
225
+ return this.getAllStyles().filter((style) => style.getType() === type);
226
+ }
227
+
228
+ /**
229
+ * Gets quick styles (styles that appear in the style gallery)
230
+ * A style appears in the gallery when qFormat=true AND semiHidden=false
231
+ * @returns Array of quick styles
232
+ */
233
+ getQuickStyles(): Style[] {
234
+ return this.getAllStyles().filter((style) => {
235
+ const props = style.getProperties();
236
+ const isQuick =
237
+ props.qFormat === true ||
238
+ (!props.customStyle && props.qFormat !== false);
239
+ const isVisible = !props.semiHidden;
240
+ return isQuick && isVisible;
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Gets visible styles (not semi-hidden)
246
+ * @returns Array of visible styles
247
+ */
248
+ getVisibleStyles(): Style[] {
249
+ return this.getAllStyles().filter((style) => {
250
+ const props = style.getProperties();
251
+ return !props.semiHidden;
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Gets styles sorted by UI priority
257
+ * Lower priority values appear first (higher importance)
258
+ * Styles without priority appear last
259
+ * @returns Array of styles sorted by priority
260
+ */
261
+ getStylesByPriority(): Style[] {
262
+ return this.getAllStyles().sort((a, b) => {
263
+ const propsA = a.getProperties();
264
+ const propsB = b.getProperties();
265
+
266
+ const priorityA = propsA.uiPriority ?? 999;
267
+ const priorityB = propsB.uiPriority ?? 999;
268
+
269
+ return priorityA - priorityB;
270
+ });
271
+ }
272
+
273
+ /**
274
+ * Gets the linked style for a given style
275
+ * @param styleId - Style ID to find the linked style for
276
+ * @returns The linked style, or undefined if not found
277
+ */
278
+ getLinkedStyle(styleId: string): Style | undefined {
279
+ const style = this.getStyle(styleId);
280
+ if (!style) {
281
+ return undefined;
282
+ }
283
+
284
+ const props = style.getProperties();
285
+ if (!props.link) {
286
+ return undefined;
287
+ }
288
+
289
+ return this.getStyle(props.link);
290
+ }
291
+
292
+ /**
293
+ * Gets all table styles (Phase 5.1)
294
+ * @returns Array of table styles
295
+ */
296
+ getTableStyles(): Style[] {
297
+ return this.getAllStyles().filter((style) => style.getType() === "table");
298
+ }
299
+
300
+ /**
301
+ * Creates and adds a table style (Phase 5.1)
302
+ * @param styleId - Style ID
303
+ * @param name - Style name
304
+ * @param basedOn - Base style ID (optional)
305
+ * @returns The created table style
306
+ */
307
+ createTableStyle(styleId: string, name: string, basedOn?: string): Style {
308
+ const style = Style.create({
309
+ styleId,
310
+ name,
311
+ type: "table",
312
+ basedOn,
313
+ customStyle: true,
314
+ });
315
+ this.addStyle(style);
316
+ return style;
317
+ }
318
+
319
+ /**
320
+ * Gets the number of styles
321
+ * @returns Number of styles
322
+ */
323
+ getStyleCount(): number {
324
+ return this.styles.size;
325
+ }
326
+
327
+ /**
328
+ * Clears all styles
329
+ * @returns This manager for chaining
330
+ */
331
+ clear(): this {
332
+ this.styles.clear();
333
+ return this;
334
+ }
335
+
336
+ /**
337
+ * Gets all available built-in style IDs
338
+ * @returns Array of built-in style IDs
339
+ */
340
+ static getBuiltInStyleIds(): string[] {
341
+ return Array.from(StylesManager.BUILT_IN_STYLE_FACTORIES.keys());
342
+ }
343
+
344
+ /**
345
+ * Checks if a style ID is a built-in style
346
+ * @param styleId - Style ID to check
347
+ * @returns True if the style is a built-in style
348
+ */
349
+ static isBuiltInStyle(styleId: string): boolean {
350
+ return StylesManager.BUILT_IN_STYLE_FACTORIES.has(styleId);
351
+ }
352
+
353
+ /**
354
+ * Gets statistics about loaded vs available styles
355
+ * @returns Object with style statistics
356
+ */
357
+ getStats(): {
358
+ loadedStyles: number;
359
+ availableBuiltInStyles: number;
360
+ customStyles: number;
361
+ } {
362
+ const loadedStyles = this.styles.size;
363
+ const customStyles = this.getAllStyles().filter(
364
+ (s) => s.getProperties().customStyle
365
+ ).length;
366
+
367
+ return {
368
+ loadedStyles,
369
+ availableBuiltInStyles: this.includeBuiltInStyles
370
+ ? StylesManager.BUILT_IN_STYLE_FACTORIES.size
371
+ : 0,
372
+ customStyles,
373
+ };
374
+ }
375
+
376
+ /**
377
+ * Creates a new paragraph style
378
+ * @param styleId - Unique style ID
379
+ * @param name - Display name
380
+ * @param basedOn - Parent style ID (optional)
381
+ * @returns The created style
382
+ */
383
+ createParagraphStyle(styleId: string, name: string, basedOn?: string): Style {
384
+ const style = Style.create({
385
+ styleId,
386
+ name,
387
+ type: "paragraph",
388
+ basedOn,
389
+ customStyle: true,
390
+ });
391
+ this.addStyle(style);
392
+ return style;
393
+ }
394
+
395
+ /**
396
+ * Creates a new character style
397
+ * @param styleId - Unique style ID
398
+ * @param name - Display name
399
+ * @param basedOn - Parent style ID (optional)
400
+ * @returns The created style
401
+ */
402
+ createCharacterStyle(styleId: string, name: string, basedOn?: string): Style {
403
+ const style = Style.create({
404
+ styleId,
405
+ name,
406
+ type: "character",
407
+ basedOn,
408
+ customStyle: true,
409
+ });
410
+ this.addStyle(style);
411
+ return style;
412
+ }
413
+
414
+ /**
415
+ * Generates the complete styles.xml file
416
+ * @returns XML string for word/styles.xml
417
+ */
418
+ generateStylesXml(): string {
419
+ const builder = new XMLBuilder();
420
+
421
+ // Create styles element with namespace
422
+ const stylesChildren = [];
423
+
424
+ // Add document defaults
425
+ stylesChildren.push(this.generateDocDefaults());
426
+
427
+ // Add all styles
428
+ for (const style of this.getAllStyles()) {
429
+ stylesChildren.push(style.toXML());
430
+ }
431
+
432
+ builder.element(
433
+ "w:styles",
434
+ {
435
+ "xmlns:w":
436
+ "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
437
+ "xmlns:r":
438
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
439
+ },
440
+ stylesChildren
441
+ );
442
+
443
+ return builder.build(true);
444
+ }
445
+
446
+ /**
447
+ * Generates document defaults
448
+ */
449
+ private generateDocDefaults() {
450
+ const rPrDefaultChildren = [
451
+ XMLBuilder.wSelf("rFonts", {
452
+ "w:ascii": "Calibri",
453
+ "w:hAnsi": "Calibri",
454
+ "w:eastAsia": "Calibri",
455
+ "w:cs": "Calibri",
456
+ }),
457
+ XMLBuilder.wSelf("sz", { "w:val": "22" }), // 11pt
458
+ XMLBuilder.wSelf("szCs", { "w:val": "22" }),
459
+ XMLBuilder.wSelf("lang", {
460
+ "w:val": "en-US",
461
+ "w:eastAsia": "en-US",
462
+ "w:bidi": "ar-SA",
463
+ }),
464
+ ];
465
+
466
+ const pPrDefaultChildren = [
467
+ XMLBuilder.wSelf("spacing", {
468
+ "w:after": "200",
469
+ "w:line": "276",
470
+ "w:lineRule": "auto",
471
+ }),
472
+ ];
473
+
474
+ return XMLBuilder.w("docDefaults", undefined, [
475
+ XMLBuilder.w("rPrDefault", undefined, [
476
+ XMLBuilder.w("rPr", undefined, rPrDefaultChildren),
477
+ ]),
478
+ XMLBuilder.w("pPrDefault", undefined, [
479
+ XMLBuilder.w("pPr", undefined, pPrDefaultChildren),
480
+ ]),
481
+ ]);
482
+ }
483
+
484
+ /**
485
+ * Creates a new StylesManager with built-in styles
486
+ * @returns New StylesManager instance
487
+ */
488
+ static create(): StylesManager {
489
+ return new StylesManager(true);
490
+ }
491
+
492
+ /**
493
+ * Creates an empty StylesManager (no built-in styles)
494
+ * @returns New empty StylesManager instance
495
+ */
496
+ static createEmpty(): StylesManager {
497
+ return new StylesManager(false);
498
+ }
499
+
500
+ /**
501
+ * Validates styles.xml content for structure and correctness
502
+ *
503
+ * This performs string-based validation to avoid XML parsing corruption.
504
+ * It checks for:
505
+ * - Well-formed XML structure
506
+ * - Required w:styles root element
507
+ * - Valid style definitions
508
+ * - No duplicate style IDs
509
+ * - Required attributes
510
+ *
511
+ * @param xml - The raw styles.xml content to validate
512
+ * @returns ValidationResult with details about validity
513
+ */
514
+ static validate(xml: string): ValidationResult {
515
+ const result: ValidationResult = {
516
+ isValid: true,
517
+ errors: [],
518
+ warnings: [],
519
+ styleCount: 0,
520
+ styleIds: [],
521
+ };
522
+
523
+ // Check for empty or null
524
+ if (!xml || xml.trim().length === 0) {
525
+ result.isValid = false;
526
+ result.errors.push("Styles XML is empty or null");
527
+ return result;
528
+ }
529
+
530
+ // Check for common corruption patterns FIRST (before parsing)
531
+ // This catches double-encoding issues that would break the parser
532
+ if (xml.includes("&lt;w:") || xml.includes("&gt;")) {
533
+ result.isValid = false;
534
+ result.errors.push(
535
+ "XML contains escaped tags - possible double-encoding corruption"
536
+ );
537
+ return result;
538
+ }
539
+
540
+ // Skip complex XML structure validation - focus on w:styles specific validation
541
+ // Checking balanced tags with regex is unreliable and can give false positives
542
+
543
+ // Use XMLParser to extract root element
544
+ const stylesContent = XMLParser.extractBetweenTags(
545
+ xml,
546
+ "<w:styles",
547
+ "</w:styles>"
548
+ );
549
+ if (!stylesContent) {
550
+ result.isValid = false;
551
+ result.errors.push("Missing required <w:styles> root element");
552
+ return result;
553
+ }
554
+
555
+ // Check for namespace declaration
556
+ if (!xml.includes("xmlns:w=")) {
557
+ result.warnings.push("Missing WordprocessingML namespace declaration");
558
+ }
559
+
560
+ // Use XMLParser to extract all style elements
561
+ const styleElements = XMLParser.extractElements(stylesContent, "w:style");
562
+ result.styleCount = styleElements.length;
563
+
564
+ // Check if any styles found
565
+ if (styleElements.length === 0) {
566
+ result.warnings.push("No styles found in document");
567
+ return result;
568
+ }
569
+
570
+ // Check for styles without attributes (invalid)
571
+ const styleWithoutAttrs = styleElements.filter((el) => {
572
+ // Check if element has any attributes
573
+ const openTagEnd = el.indexOf(">");
574
+ const openTag = el.substring(0, openTagEnd);
575
+ return !openTag.includes("w:type") || !openTag.includes("w:styleId");
576
+ });
577
+
578
+ if (styleWithoutAttrs.length > 0) {
579
+ result.isValid = false;
580
+ result.errors.push(
581
+ "Style found without any attributes - w:type and w:styleId are required"
582
+ );
583
+ }
584
+
585
+ // Process each style element
586
+ const foundStyleIds = new Set<string>();
587
+
588
+ for (const styleElement of styleElements) {
589
+ // Extract styleId using XMLParser
590
+ const styleId = XMLParser.extractAttribute(styleElement, "w:styleId");
591
+ if (styleId) {
592
+ // Check for duplicates
593
+ if (foundStyleIds.has(styleId)) {
594
+ result.isValid = false;
595
+ result.errors.push(`Duplicate style ID found: "${styleId}"`);
596
+ } else {
597
+ foundStyleIds.add(styleId);
598
+ result.styleIds.push(styleId);
599
+ }
600
+ } else {
601
+ result.isValid = false;
602
+ result.errors.push("Style found without required w:styleId attribute");
603
+ }
604
+
605
+ // Extract and validate type using XMLParser
606
+ const type = XMLParser.extractAttribute(styleElement, "w:type");
607
+ if (type) {
608
+ if (!["paragraph", "character", "table", "numbering"].includes(type)) {
609
+ result.warnings.push(`Invalid style type: "${type}"`);
610
+ }
611
+ } else {
612
+ result.isValid = false;
613
+ result.errors.push("Style found without required w:type attribute");
614
+ }
615
+
616
+ // Check for circular references - extract basedOn value
617
+ const basedOnElement = XMLParser.extractElements(
618
+ styleElement,
619
+ "w:basedOn"
620
+ )[0];
621
+ if (basedOnElement && styleId) {
622
+ const basedOn = XMLParser.extractAttribute(basedOnElement, "w:val");
623
+ if (basedOn && styleId === basedOn) {
624
+ result.isValid = false;
625
+ result.errors.push(
626
+ `Circular reference detected: style "${styleId}" based on itself`
627
+ );
628
+ }
629
+ }
630
+ }
631
+
632
+ // Check for required Normal style
633
+ if (!foundStyleIds.has("Normal")) {
634
+ result.warnings.push(
635
+ 'Missing "Normal" style - document may not render correctly'
636
+ );
637
+ }
638
+
639
+ // Check for BOM or invalid characters
640
+ if (xml.charCodeAt(0) === 0xfeff) {
641
+ result.warnings.push(
642
+ "XML contains BOM (Byte Order Mark) - may cause parsing issues"
643
+ );
644
+ }
645
+
646
+ // Summary
647
+ if (result.styleCount === 0) {
648
+ result.warnings.push("No styles found in document");
649
+ }
650
+
651
+ return result;
652
+ }
653
+
654
+ /**
655
+ * Searches styles by name (case-insensitive)
656
+ * @param searchTerm - Text to search for in style names
657
+ * @returns Array of styles whose names contain the search term
658
+ * @example
659
+ * ```typescript
660
+ * const headings = stylesManager.searchByName('heading');
661
+ * console.log(`Found ${headings.length} heading styles`);
662
+ * ```
663
+ */
664
+ searchByName(searchTerm: string): Style[] {
665
+ const term = searchTerm.toLowerCase();
666
+ return this.getAllStyles().filter((style) =>
667
+ style.getName().toLowerCase().includes(term)
668
+ );
669
+ }
670
+
671
+ /**
672
+ * Finds styles using a specific font
673
+ * @param fontName - Font family name to search for
674
+ * @returns Array of styles that use the specified font
675
+ * @example
676
+ * ```typescript
677
+ * const arialStyles = stylesManager.findByFont('Arial');
678
+ * console.log(`Found ${arialStyles.length} styles using Arial font`);
679
+ * ```
680
+ */
681
+ findByFont(fontName: string): Style[] {
682
+ return this.getAllStyles().filter((style) => {
683
+ const runFormatting = style.getRunFormatting();
684
+ return runFormatting?.font === fontName;
685
+ });
686
+ }
687
+
688
+ /**
689
+ * Finds styles with specific properties using a predicate function
690
+ * @param predicate - Filter function that returns true for styles to include
691
+ * @returns Array of styles matching the predicate
692
+ * @example
693
+ * ```typescript
694
+ * // Find all paragraph styles
695
+ * const paraStyles = stylesManager.findStyles(s => s.getType() === 'paragraph');
696
+ *
697
+ * // Find styles with custom formatting
698
+ * const customStyles = stylesManager.findStyles(s => s.getProperties().customStyle);
699
+ *
700
+ * // Find styles with specific formatting
701
+ * const boldStyles = stylesManager.findStyles(s => s.getRunFormatting()?.bold);
702
+ * ```
703
+ */
704
+ findStyles(predicate: (style: Style) => boolean): Style[] {
705
+ return this.getAllStyles().filter(predicate);
706
+ }
707
+
708
+ /**
709
+ * Finds unused styles (not referenced by any paragraphs)
710
+ * @param paragraphs - All paragraphs in the document to check against
711
+ * @returns Array of unused style IDs
712
+ * @example
713
+ * ```typescript
714
+ * const doc = Document.create();
715
+ * const unused = stylesManager.findUnusedStyles(doc.getAllParagraphs());
716
+ * console.log(`Found ${unused.length} unused styles: ${unused.join(', ')}`);
717
+ * ```
718
+ */
719
+ findUnusedStyles(paragraphs: Paragraph[]): string[] {
720
+ const usedStyles = new Set<string>();
721
+
722
+ // Collect all style IDs used by paragraphs
723
+ for (const para of paragraphs) {
724
+ const styleId = para.getStyle();
725
+ if (styleId) {
726
+ usedStyles.add(styleId);
727
+ }
728
+ }
729
+
730
+ // Get all style IDs and filter out used ones
731
+ const allStyleIds = this.getAllStyles().map((style) => style.getStyleId());
732
+ return allStyleIds.filter((styleId) => !usedStyles.has(styleId));
733
+ }
734
+
735
+ /**
736
+ * Removes all unused styles from the document
737
+ * @param paragraphs - All paragraphs in the document to check against
738
+ * @returns Number of styles removed
739
+ * @example
740
+ * ```typescript
741
+ * const doc = Document.create();
742
+ * const removedCount = stylesManager.cleanupUnusedStyles(doc.getAllParagraphs());
743
+ * console.log(`Cleaned up ${removedCount} unused styles`);
744
+ * ```
745
+ */
746
+ cleanupUnusedStyles(paragraphs: Paragraph[]): number {
747
+ const unused = this.findUnusedStyles(paragraphs);
748
+ let count = 0;
749
+
750
+ for (const styleId of unused) {
751
+ // Don't remove built-in styles
752
+ if (!StylesManager.isBuiltInStyle(styleId)) {
753
+ if (this.removeStyle(styleId)) {
754
+ count++;
755
+ }
756
+ }
757
+ }
758
+
759
+ return count;
760
+ }
761
+
762
+ /**
763
+ * Validates all style references for broken or circular dependencies
764
+ * @returns Validation result with broken references and circular dependencies
765
+ * @example
766
+ * ```typescript
767
+ * const validation = stylesManager.validateStyleReferences();
768
+ * if (!validation.valid) {
769
+ * console.log('Broken references:', validation.brokenReferences);
770
+ * console.log('Circular references:', validation.circularReferences);
771
+ * }
772
+ * ```
773
+ */
774
+ validateStyleReferences(): {
775
+ valid: boolean;
776
+ brokenReferences: { styleId: string; basedOn: string }[];
777
+ circularReferences: string[][];
778
+ } {
779
+ const broken: { styleId: string; basedOn: string }[] = [];
780
+ const circular: string[][] = [];
781
+ const checkedForCycles = new Set<string>();
782
+
783
+ for (const style of this.getAllStyles()) {
784
+ const props = style.getProperties();
785
+
786
+ // Check basedOn references exist
787
+ if (props.basedOn && !this.hasStyle(props.basedOn)) {
788
+ broken.push({ styleId: props.styleId, basedOn: props.basedOn });
789
+ }
790
+
791
+ // Check for circular references (only if not already checked as part of another cycle)
792
+ if (!checkedForCycles.has(props.styleId)) {
793
+ const result = this.hasCircularReference(props.styleId);
794
+ if (result.hasCircularRef && result.cyclePath) {
795
+ circular.push(result.cyclePath);
796
+ // Mark all styles in this cycle as checked
797
+ result.cyclePath.forEach((id) => checkedForCycles.add(id));
798
+ }
799
+ }
800
+ }
801
+
802
+ return {
803
+ valid: broken.length === 0 && circular.length === 0,
804
+ brokenReferences: broken,
805
+ circularReferences: circular,
806
+ };
807
+ }
808
+
809
+ /**
810
+ * Gets the complete inheritance chain for a style
811
+ * @param styleId - Style ID to analyze
812
+ * @returns Array of styles from base to derived (base style first)
813
+ * @throws Error if style doesn't exist or circular reference detected
814
+ * @example
815
+ * ```typescript
816
+ * const chain = stylesManager.getInheritanceChain('Heading1');
817
+ * console.log('Inheritance chain:', chain.map(s => s.getName()));
818
+ * // Output: ['Normal', 'Heading1'] (Normal is base, Heading1 inherits from it)
819
+ * ```
820
+ */
821
+ getInheritanceChain(styleId: string): Style[] {
822
+ const chain: Style[] = [];
823
+ const visited = new Set<string>(); // Track visited styles to detect cycles
824
+ let current = this.getStyle(styleId);
825
+
826
+ if (!current) {
827
+ throw new Error(`Style '${styleId}' not found`);
828
+ }
829
+
830
+ while (current) {
831
+ const currentId = current.getStyleId();
832
+
833
+ // Detect circular reference
834
+ if (visited.has(currentId)) {
835
+ const cycle = [...chain.map((s) => s.getStyleId()), currentId];
836
+ throw new Error(
837
+ `Circular style reference detected: ${cycle.join(" -> ")}. ` +
838
+ `Style '${currentId}' references itself through inheritance chain.`
839
+ );
840
+ }
841
+
842
+ visited.add(currentId);
843
+ chain.unshift(current); // Add to beginning to maintain base-to-derived order
844
+ const props = current.getProperties();
845
+ current = props.basedOn ? this.getStyle(props.basedOn) : undefined;
846
+ }
847
+
848
+ return chain;
849
+ }
850
+
851
+ /**
852
+ * Checks if a style has circular references in its inheritance chain
853
+ * @param styleId - Style ID to check
854
+ * @returns Object with hasCircularRef flag and the cycle path if found
855
+ * @example
856
+ * ```typescript
857
+ * const result = stylesManager.hasCircularReference('MyStyle');
858
+ * if (result.hasCircularRef) {
859
+ * console.log('Circular reference found:', result.cyclePath?.join(' -> '));
860
+ * }
861
+ * ```
862
+ */
863
+ hasCircularReference(styleId: string): {
864
+ hasCircularRef: boolean;
865
+ cyclePath?: string[];
866
+ } {
867
+ const visited = new Set<string>();
868
+ const path: string[] = [];
869
+ let current = this.getStyle(styleId);
870
+
871
+ while (current) {
872
+ const currentId = current.getStyleId();
873
+
874
+ if (visited.has(currentId)) {
875
+ path.push(currentId);
876
+ return { hasCircularRef: true, cyclePath: path };
877
+ }
878
+
879
+ visited.add(currentId);
880
+ path.push(currentId);
881
+ const props = current.getProperties();
882
+ current = props.basedOn ? this.getStyle(props.basedOn) : undefined;
883
+ }
884
+
885
+ return { hasCircularRef: false };
886
+ }
887
+
888
+ /**
889
+ * Gets all styles that inherit from a base style
890
+ * @param baseStyleId - Base style ID to find children for
891
+ * @returns Array of styles that inherit from the base style
892
+ * @example
893
+ * ```typescript
894
+ * const children = stylesManager.getDerivedStyles('Normal');
895
+ * console.log(`Styles based on Normal: ${children.map(s => s.getName()).join(', ')}`);
896
+ * ```
897
+ */
898
+ getDerivedStyles(baseStyleId: string): Style[] {
899
+ return this.getAllStyles().filter(
900
+ (style) => style.getProperties().basedOn === baseStyleId
901
+ );
902
+ }
903
+
904
+ /**
905
+ * Exports a single style as JSON string
906
+ * @param styleId - Style ID to export
907
+ * @returns JSON representation of the style
908
+ * @throws Error if style doesn't exist
909
+ * @example
910
+ * ```typescript
911
+ * const json = stylesManager.exportStyle('Heading1');
912
+ * console.log('Style JSON:', json);
913
+ *
914
+ * // Save to file
915
+ * await fs.writeFile('heading1-style.json', json);
916
+ * ```
917
+ */
918
+ exportStyle(styleId: string): string {
919
+ const style = this.getStyle(styleId);
920
+ if (!style) {
921
+ throw new Error(`Style '${styleId}' not found`);
922
+ }
923
+ return JSON.stringify(style.getProperties(), null, 2);
924
+ }
925
+
926
+ /**
927
+ * Imports a style from JSON string
928
+ * @param json - JSON string containing style properties
929
+ * @returns The imported style
930
+ * @throws Error if JSON is invalid or style creation fails
931
+ * @example
932
+ * ```typescript
933
+ * const json = await fs.readFile('custom-style.json', 'utf8');
934
+ * const style = stylesManager.importStyle(json);
935
+ * console.log(`Imported style: ${style.getName()}`);
936
+ * ```
937
+ */
938
+ importStyle(json: string): Style {
939
+ try {
940
+ const props = JSON.parse(json);
941
+ const style = Style.create(props);
942
+ this.addStyle(style);
943
+ return style;
944
+ } catch (error: unknown) {
945
+ throw new Error(
946
+ `Failed to import style: ${
947
+ error instanceof Error ? error.message : "Invalid JSON"
948
+ }`
949
+ );
950
+ }
951
+ }
952
+
953
+ /**
954
+ * Exports all styles as JSON string
955
+ * @returns JSON array of all style properties
956
+ * @example
957
+ * ```typescript
958
+ * const allStylesJson = stylesManager.exportAllStyles();
959
+ * console.log('All styles exported');
960
+ *
961
+ * // Save to file
962
+ * await fs.writeFile('all-styles.json', allStylesJson);
963
+ * ```
964
+ */
965
+ exportAllStyles(): string {
966
+ const styles = this.getAllStyles().map((style) => style.getProperties());
967
+ return JSON.stringify(styles, null, 2);
968
+ }
969
+
970
+ /**
971
+ * Imports multiple styles from JSON array string
972
+ * @param json - JSON string containing array of style properties
973
+ * @returns Array of imported styles
974
+ * @throws Error if JSON is invalid or style creation fails
975
+ * @example
976
+ * ```typescript
977
+ * const json = await fs.readFile('styles-collection.json', 'utf8');
978
+ * const styles = stylesManager.importStyles(json);
979
+ * console.log(`Imported ${styles.length} styles`);
980
+ * ```
981
+ */
982
+ importStyles(json: string): Style[] {
983
+ try {
984
+ const propsArray = JSON.parse(json);
985
+ if (!Array.isArray(propsArray)) {
986
+ throw new Error("JSON must contain an array of style properties");
987
+ }
988
+
989
+ const styles: Style[] = [];
990
+ for (const props of propsArray) {
991
+ const style = Style.create(props);
992
+ this.addStyle(style);
993
+ styles.push(style);
994
+ }
995
+
996
+ return styles;
997
+ } catch (error: unknown) {
998
+ throw new Error(
999
+ `Failed to import styles: ${
1000
+ error instanceof Error ? error.message : "Invalid JSON"
1001
+ }`
1002
+ );
1003
+ }
1004
+ }
1005
+ }