docxmlater 11.0.9 → 12.0.1

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 (354) hide show
  1. package/README.md +51 -13
  2. package/dist/core/Document.d.ts +28 -2
  3. package/dist/core/Document.d.ts.map +1 -1
  4. package/dist/core/Document.js +725 -170
  5. package/dist/core/Document.js.map +1 -1
  6. package/dist/core/DocumentGenerator.d.ts +1 -0
  7. package/dist/core/DocumentGenerator.d.ts.map +1 -1
  8. package/dist/core/DocumentGenerator.js +77 -25
  9. package/dist/core/DocumentGenerator.js.map +1 -1
  10. package/dist/core/DocumentParser.d.ts +7 -3
  11. package/dist/core/DocumentParser.d.ts.map +1 -1
  12. package/dist/core/DocumentParser.js +431 -85
  13. package/dist/core/DocumentParser.js.map +1 -1
  14. package/dist/core/RelationshipManager.d.ts.map +1 -1
  15. package/dist/core/RelationshipManager.js +2 -2
  16. package/dist/core/RelationshipManager.js.map +1 -1
  17. package/dist/elements/Comment.d.ts +15 -1
  18. package/dist/elements/Comment.d.ts.map +1 -1
  19. package/dist/elements/Comment.js +67 -12
  20. package/dist/elements/Comment.js.map +1 -1
  21. package/dist/elements/CommentManager.d.ts +4 -0
  22. package/dist/elements/CommentManager.d.ts.map +1 -1
  23. package/dist/elements/CommentManager.js +74 -16
  24. package/dist/elements/CommentManager.js.map +1 -1
  25. package/dist/elements/EndnoteManager.d.ts.map +1 -1
  26. package/dist/elements/EndnoteManager.js.map +1 -1
  27. package/dist/elements/Field.d.ts +10 -1
  28. package/dist/elements/Field.d.ts.map +1 -1
  29. package/dist/elements/Field.js +76 -34
  30. package/dist/elements/Field.js.map +1 -1
  31. package/dist/elements/FieldHelpers.d.ts +1 -0
  32. package/dist/elements/FieldHelpers.d.ts.map +1 -1
  33. package/dist/elements/FieldHelpers.js +8 -4
  34. package/dist/elements/FieldHelpers.js.map +1 -1
  35. package/dist/elements/Footer.d.ts +3 -1
  36. package/dist/elements/Footer.d.ts.map +1 -1
  37. package/dist/elements/Footer.js +39 -53
  38. package/dist/elements/Footer.js.map +1 -1
  39. package/dist/elements/FootnoteManager.d.ts.map +1 -1
  40. package/dist/elements/FootnoteManager.js.map +1 -1
  41. package/dist/elements/Header.d.ts +3 -1
  42. package/dist/elements/Header.d.ts.map +1 -1
  43. package/dist/elements/Header.js +39 -53
  44. package/dist/elements/Header.js.map +1 -1
  45. package/dist/elements/HeaderFooterManager.d.ts +4 -2
  46. package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
  47. package/dist/elements/HeaderFooterManager.js +36 -6
  48. package/dist/elements/HeaderFooterManager.js.map +1 -1
  49. package/dist/elements/Hyperlink.d.ts +6 -1
  50. package/dist/elements/Hyperlink.d.ts.map +1 -1
  51. package/dist/elements/Hyperlink.js +69 -44
  52. package/dist/elements/Hyperlink.js.map +1 -1
  53. package/dist/elements/Image.d.ts.map +1 -1
  54. package/dist/elements/Image.js +33 -6
  55. package/dist/elements/Image.js.map +1 -1
  56. package/dist/elements/ImageManager.d.ts +1 -0
  57. package/dist/elements/ImageManager.d.ts.map +1 -1
  58. package/dist/elements/ImageManager.js +11 -0
  59. package/dist/elements/ImageManager.js.map +1 -1
  60. package/dist/elements/Paragraph.d.ts +3 -0
  61. package/dist/elements/Paragraph.d.ts.map +1 -1
  62. package/dist/elements/Paragraph.js +91 -26
  63. package/dist/elements/Paragraph.js.map +1 -1
  64. package/dist/elements/Revision.d.ts +4 -0
  65. package/dist/elements/Revision.d.ts.map +1 -1
  66. package/dist/elements/Revision.js +369 -29
  67. package/dist/elements/Revision.js.map +1 -1
  68. package/dist/elements/Run.d.ts +1 -0
  69. package/dist/elements/Run.d.ts.map +1 -1
  70. package/dist/elements/Run.js +24 -4
  71. package/dist/elements/Run.js.map +1 -1
  72. package/dist/elements/Section.d.ts.map +1 -1
  73. package/dist/elements/Section.js +17 -7
  74. package/dist/elements/Section.js.map +1 -1
  75. package/dist/elements/Shape.d.ts.map +1 -1
  76. package/dist/elements/Shape.js +50 -42
  77. package/dist/elements/Shape.js.map +1 -1
  78. package/dist/elements/StructuredDocumentTag.d.ts +9 -1
  79. package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
  80. package/dist/elements/StructuredDocumentTag.js +46 -6
  81. package/dist/elements/StructuredDocumentTag.js.map +1 -1
  82. package/dist/elements/Table.d.ts +2 -0
  83. package/dist/elements/Table.d.ts.map +1 -1
  84. package/dist/elements/Table.js +90 -42
  85. package/dist/elements/Table.js.map +1 -1
  86. package/dist/elements/TableCell.d.ts +1 -0
  87. package/dist/elements/TableCell.d.ts.map +1 -1
  88. package/dist/elements/TableCell.js +32 -13
  89. package/dist/elements/TableCell.js.map +1 -1
  90. package/dist/elements/TableOfContents.d.ts.map +1 -1
  91. package/dist/elements/TableOfContents.js +5 -7
  92. package/dist/elements/TableOfContents.js.map +1 -1
  93. package/dist/elements/TableRow.d.ts +1 -0
  94. package/dist/elements/TableRow.d.ts.map +1 -1
  95. package/dist/elements/TableRow.js +16 -1
  96. package/dist/elements/TableRow.js.map +1 -1
  97. package/dist/elements/TextBox.d.ts.map +1 -1
  98. package/dist/elements/TextBox.js +55 -42
  99. package/dist/elements/TextBox.js.map +1 -1
  100. package/dist/esm/core/Document.js +726 -171
  101. package/dist/esm/core/Document.js.map +1 -1
  102. package/dist/esm/core/DocumentGenerator.js +77 -25
  103. package/dist/esm/core/DocumentGenerator.js.map +1 -1
  104. package/dist/esm/core/DocumentParser.js +431 -85
  105. package/dist/esm/core/DocumentParser.js.map +1 -1
  106. package/dist/esm/core/RelationshipManager.js +2 -2
  107. package/dist/esm/core/RelationshipManager.js.map +1 -1
  108. package/dist/esm/elements/Comment.js +67 -12
  109. package/dist/esm/elements/Comment.js.map +1 -1
  110. package/dist/esm/elements/CommentManager.js +74 -16
  111. package/dist/esm/elements/CommentManager.js.map +1 -1
  112. package/dist/esm/elements/EndnoteManager.js.map +1 -1
  113. package/dist/esm/elements/Field.js +77 -35
  114. package/dist/esm/elements/Field.js.map +1 -1
  115. package/dist/esm/elements/FieldHelpers.js +7 -4
  116. package/dist/esm/elements/FieldHelpers.js.map +1 -1
  117. package/dist/esm/elements/Footer.js +39 -53
  118. package/dist/esm/elements/Footer.js.map +1 -1
  119. package/dist/esm/elements/FootnoteManager.js.map +1 -1
  120. package/dist/esm/elements/Header.js +39 -53
  121. package/dist/esm/elements/Header.js.map +1 -1
  122. package/dist/esm/elements/HeaderFooterManager.js +36 -6
  123. package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
  124. package/dist/esm/elements/Hyperlink.js +69 -44
  125. package/dist/esm/elements/Hyperlink.js.map +1 -1
  126. package/dist/esm/elements/Image.js +33 -6
  127. package/dist/esm/elements/Image.js.map +1 -1
  128. package/dist/esm/elements/ImageManager.js +11 -0
  129. package/dist/esm/elements/ImageManager.js.map +1 -1
  130. package/dist/esm/elements/Paragraph.js +91 -26
  131. package/dist/esm/elements/Paragraph.js.map +1 -1
  132. package/dist/esm/elements/Revision.js +369 -29
  133. package/dist/esm/elements/Revision.js.map +1 -1
  134. package/dist/esm/elements/Run.js +24 -4
  135. package/dist/esm/elements/Run.js.map +1 -1
  136. package/dist/esm/elements/Section.js +17 -7
  137. package/dist/esm/elements/Section.js.map +1 -1
  138. package/dist/esm/elements/Shape.js +50 -42
  139. package/dist/esm/elements/Shape.js.map +1 -1
  140. package/dist/esm/elements/StructuredDocumentTag.js +46 -6
  141. package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
  142. package/dist/esm/elements/Table.js +90 -42
  143. package/dist/esm/elements/Table.js.map +1 -1
  144. package/dist/esm/elements/TableCell.js +32 -13
  145. package/dist/esm/elements/TableCell.js.map +1 -1
  146. package/dist/esm/elements/TableOfContents.js +5 -7
  147. package/dist/esm/elements/TableOfContents.js.map +1 -1
  148. package/dist/esm/elements/TableRow.js +16 -1
  149. package/dist/esm/elements/TableRow.js.map +1 -1
  150. package/dist/esm/elements/TextBox.js +55 -42
  151. package/dist/esm/elements/TextBox.js.map +1 -1
  152. package/dist/esm/formatting/AbstractNumbering.js +1 -1
  153. package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
  154. package/dist/esm/formatting/NumberingLevel.js +8 -6
  155. package/dist/esm/formatting/NumberingLevel.js.map +1 -1
  156. package/dist/esm/formatting/NumberingManager.js +16 -1
  157. package/dist/esm/formatting/NumberingManager.js.map +1 -1
  158. package/dist/esm/formatting/Style.js +14 -0
  159. package/dist/esm/formatting/Style.js.map +1 -1
  160. package/dist/esm/formatting/StylesManager.js +14 -2
  161. package/dist/esm/formatting/StylesManager.js.map +1 -1
  162. package/dist/esm/helpers/CleanupHelper.js +103 -26
  163. package/dist/esm/helpers/CleanupHelper.js.map +1 -1
  164. package/dist/esm/images/ImageOptimizer.js +52 -4
  165. package/dist/esm/images/ImageOptimizer.js.map +1 -1
  166. package/dist/esm/index.js +1 -0
  167. package/dist/esm/index.js.map +1 -1
  168. package/dist/esm/internal.js +1 -1
  169. package/dist/esm/internal.js.map +1 -1
  170. package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
  171. package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
  172. package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
  173. package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
  174. package/dist/esm/processors/RevisionWalker.js +58 -8
  175. package/dist/esm/processors/RevisionWalker.js.map +1 -1
  176. package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
  177. package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
  178. package/dist/esm/processors/cnfStyleDecoder.js +7 -7
  179. package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
  180. package/dist/esm/processors/stripTrackedChanges.js +16 -5
  181. package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
  182. package/dist/esm/utils/deepClone.js +24 -11
  183. package/dist/esm/utils/deepClone.js.map +1 -1
  184. package/dist/esm/utils/units.js +1 -1
  185. package/dist/esm/utils/units.js.map +1 -1
  186. package/dist/esm/utils/validation.js +11 -23
  187. package/dist/esm/utils/validation.js.map +1 -1
  188. package/dist/esm/utils/xmlSanitization.js +131 -7
  189. package/dist/esm/utils/xmlSanitization.js.map +1 -1
  190. package/dist/esm/validation/RevisionAutoFixer.js +69 -55
  191. package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
  192. package/dist/esm/validation/RevisionValidator.js +24 -20
  193. package/dist/esm/validation/RevisionValidator.js.map +1 -1
  194. package/dist/esm/xml/XMLBuilder.js +52 -20
  195. package/dist/esm/xml/XMLBuilder.js.map +1 -1
  196. package/dist/esm/xml/XMLParser.js +55 -13
  197. package/dist/esm/xml/XMLParser.js.map +1 -1
  198. package/dist/esm/zip/ZipHandler.js +37 -13
  199. package/dist/esm/zip/ZipHandler.js.map +1 -1
  200. package/dist/esm/zip/ZipReader.js +53 -6
  201. package/dist/esm/zip/ZipReader.js.map +1 -1
  202. package/dist/esm/zip/errors.js +7 -0
  203. package/dist/esm/zip/errors.js.map +1 -1
  204. package/dist/esm/zip/types.js +4 -0
  205. package/dist/esm/zip/types.js.map +1 -1
  206. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  207. package/dist/formatting/AbstractNumbering.js +1 -1
  208. package/dist/formatting/AbstractNumbering.js.map +1 -1
  209. package/dist/formatting/NumberingLevel.d.ts +1 -1
  210. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  211. package/dist/formatting/NumberingLevel.js +8 -6
  212. package/dist/formatting/NumberingLevel.js.map +1 -1
  213. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  214. package/dist/formatting/NumberingManager.js +16 -1
  215. package/dist/formatting/NumberingManager.js.map +1 -1
  216. package/dist/formatting/Style.d.ts.map +1 -1
  217. package/dist/formatting/Style.js +14 -0
  218. package/dist/formatting/Style.js.map +1 -1
  219. package/dist/formatting/StylesManager.d.ts +2 -0
  220. package/dist/formatting/StylesManager.d.ts.map +1 -1
  221. package/dist/formatting/StylesManager.js +14 -2
  222. package/dist/formatting/StylesManager.js.map +1 -1
  223. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  224. package/dist/helpers/CleanupHelper.js +103 -26
  225. package/dist/helpers/CleanupHelper.js.map +1 -1
  226. package/dist/images/ImageOptimizer.d.ts.map +1 -1
  227. package/dist/images/ImageOptimizer.js +52 -4
  228. package/dist/images/ImageOptimizer.js.map +1 -1
  229. package/dist/index.d.ts +3 -1
  230. package/dist/index.d.ts.map +1 -1
  231. package/dist/index.js +4 -2
  232. package/dist/index.js.map +1 -1
  233. package/dist/internal.d.ts +1 -1
  234. package/dist/internal.d.ts.map +1 -1
  235. package/dist/internal.js +2 -1
  236. package/dist/internal.js.map +1 -1
  237. package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
  238. package/dist/processors/CompatibilityUpgrader.js +7 -1
  239. package/dist/processors/CompatibilityUpgrader.js.map +1 -1
  240. package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
  241. package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
  242. package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
  243. package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
  244. package/dist/processors/RevisionWalker.d.ts +2 -0
  245. package/dist/processors/RevisionWalker.d.ts.map +1 -1
  246. package/dist/processors/RevisionWalker.js +58 -8
  247. package/dist/processors/RevisionWalker.js.map +1 -1
  248. package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
  249. package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
  250. package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
  251. package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
  252. package/dist/processors/cnfStyleDecoder.js +7 -7
  253. package/dist/processors/cnfStyleDecoder.js.map +1 -1
  254. package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
  255. package/dist/processors/stripTrackedChanges.js +16 -5
  256. package/dist/processors/stripTrackedChanges.js.map +1 -1
  257. package/dist/utils/deepClone.d.ts.map +1 -1
  258. package/dist/utils/deepClone.js +24 -11
  259. package/dist/utils/deepClone.js.map +1 -1
  260. package/dist/utils/units.d.ts.map +1 -1
  261. package/dist/utils/units.js +1 -1
  262. package/dist/utils/units.js.map +1 -1
  263. package/dist/utils/validation.d.ts.map +1 -1
  264. package/dist/utils/validation.js +11 -23
  265. package/dist/utils/validation.js.map +1 -1
  266. package/dist/utils/xmlSanitization.d.ts +2 -0
  267. package/dist/utils/xmlSanitization.d.ts.map +1 -1
  268. package/dist/utils/xmlSanitization.js +133 -7
  269. package/dist/utils/xmlSanitization.js.map +1 -1
  270. package/dist/validation/RevisionAutoFixer.d.ts +6 -2
  271. package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
  272. package/dist/validation/RevisionAutoFixer.js +68 -54
  273. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  274. package/dist/validation/RevisionValidator.d.ts +2 -0
  275. package/dist/validation/RevisionValidator.d.ts.map +1 -1
  276. package/dist/validation/RevisionValidator.js +26 -21
  277. package/dist/validation/RevisionValidator.js.map +1 -1
  278. package/dist/xml/XMLBuilder.d.ts +1 -0
  279. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  280. package/dist/xml/XMLBuilder.js +52 -20
  281. package/dist/xml/XMLBuilder.js.map +1 -1
  282. package/dist/xml/XMLParser.d.ts +1 -0
  283. package/dist/xml/XMLParser.d.ts.map +1 -1
  284. package/dist/xml/XMLParser.js +55 -13
  285. package/dist/xml/XMLParser.js.map +1 -1
  286. package/dist/zip/ZipHandler.d.ts.map +1 -1
  287. package/dist/zip/ZipHandler.js +37 -13
  288. package/dist/zip/ZipHandler.js.map +1 -1
  289. package/dist/zip/ZipReader.d.ts.map +1 -1
  290. package/dist/zip/ZipReader.js +52 -5
  291. package/dist/zip/ZipReader.js.map +1 -1
  292. package/dist/zip/errors.d.ts +3 -0
  293. package/dist/zip/errors.d.ts.map +1 -1
  294. package/dist/zip/errors.js +9 -1
  295. package/dist/zip/errors.js.map +1 -1
  296. package/dist/zip/types.d.ts +4 -0
  297. package/dist/zip/types.d.ts.map +1 -1
  298. package/dist/zip/types.js +4 -0
  299. package/dist/zip/types.js.map +1 -1
  300. package/package.json +2 -2
  301. package/src/core/Document.ts +1159 -240
  302. package/src/core/DocumentGenerator.ts +106 -26
  303. package/src/core/DocumentParser.ts +692 -120
  304. package/src/core/RelationshipManager.ts +446 -442
  305. package/src/elements/Comment.ts +123 -18
  306. package/src/elements/CommentManager.ts +121 -22
  307. package/src/elements/EndnoteManager.ts +4 -1
  308. package/src/elements/Field.ts +134 -43
  309. package/src/elements/FieldHelpers.ts +20 -4
  310. package/src/elements/Footer.ts +62 -67
  311. package/src/elements/FootnoteManager.ts +4 -1
  312. package/src/elements/Header.ts +62 -67
  313. package/src/elements/HeaderFooterManager.ts +56 -8
  314. package/src/elements/Hyperlink.ts +150 -55
  315. package/src/elements/Image.ts +51 -7
  316. package/src/elements/ImageManager.ts +24 -0
  317. package/src/elements/Paragraph.ts +161 -40
  318. package/src/elements/Revision.ts +446 -47
  319. package/src/elements/Run.ts +44 -6
  320. package/src/elements/Section.ts +25 -9
  321. package/src/elements/Shape.ts +52 -44
  322. package/src/elements/StructuredDocumentTag.ts +83 -8
  323. package/src/elements/Table.ts +151 -50
  324. package/src/elements/TableCell.ts +57 -17
  325. package/src/elements/TableOfContents.ts +10 -9
  326. package/src/elements/TableRow.ts +35 -3
  327. package/src/elements/TextBox.ts +58 -43
  328. package/src/formatting/AbstractNumbering.ts +4 -2
  329. package/src/formatting/NumberingLevel.ts +50 -12
  330. package/src/formatting/NumberingManager.ts +32 -3
  331. package/src/formatting/Style.ts +14 -0
  332. package/src/formatting/StylesManager.ts +29 -2
  333. package/src/helpers/CleanupHelper.ts +122 -30
  334. package/src/images/ImageOptimizer.ts +64 -5
  335. package/src/index.ts +7 -0
  336. package/src/internal.ts +1 -0
  337. package/src/processors/CompatibilityUpgrader.ts +15 -2
  338. package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
  339. package/src/processors/RevisionWalker.ts +83 -7
  340. package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
  341. package/src/processors/cnfStyleDecoder.ts +18 -12
  342. package/src/processors/stripTrackedChanges.ts +47 -10
  343. package/src/utils/deepClone.ts +48 -14
  344. package/src/utils/units.ts +3 -1
  345. package/src/utils/validation.ts +30 -32
  346. package/src/utils/xmlSanitization.ts +218 -22
  347. package/src/validation/RevisionAutoFixer.ts +109 -65
  348. package/src/validation/RevisionValidator.ts +48 -23
  349. package/src/xml/XMLBuilder.ts +82 -22
  350. package/src/xml/XMLParser.ts +87 -20
  351. package/src/zip/ZipHandler.ts +61 -21
  352. package/src/zip/ZipReader.ts +135 -13
  353. package/src/zip/errors.ts +15 -0
  354. package/src/zip/types.ts +44 -2
@@ -1 +1 @@
1
- {"version":3,"file":"XMLBuilder.js","sourceRoot":"","sources":["../../../src/xml/XMLBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * XMLBuilder - Utility for building XML content\n * Provides a simple fluent API for generating WordprocessingML XML\n */\n\nimport { removeInvalidXmlChars } from '../utils/xmlSanitization.js';\nimport type { ShadingConfig } from '../elements/CommonTypes.js';\nimport { buildShadingAttributes } from '../elements/CommonTypes.js';\n\n/** Represents a parsed XML object from XMLParser.parseToObject() */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- parsed XML has dynamic keys and recursive structure\ntype ParsedXmlObject = Record<string, any>;\n\n/**\n * Represents an XML element with attributes and children\n */\nexport interface XMLElement {\n name: string;\n attributes?: Record<string, string | number | boolean | undefined>;\n children?: (XMLElement | string)[];\n selfClosing?: boolean;\n /** Raw XML content to include without escaping (used for VML passthrough) */\n rawXml?: string;\n}\n\n/**\n * XML Builder for creating WordprocessingML XML\n */\nexport class XMLBuilder {\n private elements: (XMLElement | string)[] = [];\n\n /**\n * Elements that must NEVER be self-closing in Word XML per ECMA-376.\n * Self-closing these elements causes Word to not parse correctly or lose content.\n */\n private static readonly CANNOT_SELF_CLOSE = [\n 'w:t',\n 'w:r',\n 'w:p',\n 'w:tbl',\n 'w:tr',\n 'w:tc',\n 'w:body',\n 'w:document',\n 'w:hyperlink',\n 'w:sdt',\n 'w:sdtContent',\n 'w:sdtPr',\n 'w:pPr',\n 'w:rPr',\n 'w:sectPr',\n 'w:del', // Deletion revisions - container element, must have closing tag\n 'w:ins', // Insertion revisions - container element, must have closing tag\n 'w:moveFrom', // Move source markers - container element\n 'w:moveTo', // Move destination markers - container element\n // Note: w:bookmarkStart and w:bookmarkEnd MUST be self-closing per ECMA-376\n ];\n\n /**\n * Adds an element to the builder\n * @param name - Element name (with namespace prefix if needed)\n * @param attributes - Element attributes\n * @param children - Child elements or text\n * @returns This builder for chaining\n */\n element(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLBuilder {\n this.elements.push({\n name,\n attributes,\n children,\n });\n return this;\n }\n\n /**\n * Adds a self-closing element\n * @param name - Element name\n * @param attributes - Element attributes\n * @returns This builder for chaining\n * @throws {Error} If attempting to create self-closing w:t element (not allowed per ECMA-376)\n */\n selfClosingElement(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLBuilder {\n // Validation: Text elements (<w:t>) cannot be self-closing per ECMA-376\n // Self-closing <w:t/> elements cause Word to fail opening the document\n if (name === 'w:t' || name === 't') {\n throw new Error(\n 'Text elements (<w:t>) cannot be self-closing per ECMA-376. ' +\n 'Use element() with empty text content instead: XMLBuilder.w(\"t\", attrs, [\"\"])'\n );\n }\n\n this.elements.push({\n name,\n attributes,\n selfClosing: true,\n });\n return this;\n }\n\n /**\n * Adds text content\n * @param text - Text to add\n * @returns This builder for chaining\n */\n text(text: string): XMLBuilder {\n this.elements.push(text);\n return this;\n }\n\n /**\n * Builds the XML string\n * @param includeDeclaration - Whether to include XML declaration\n * @returns Generated XML string\n */\n build(includeDeclaration = false): string {\n let xml = '';\n\n if (includeDeclaration) {\n xml += '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n';\n }\n\n xml += this.elementsToString(this.elements);\n return xml;\n }\n\n /**\n * Converts elements to XML string\n */\n private elementsToString(elements: (XMLElement | string)[]): string {\n let xml = '';\n\n for (const element of elements) {\n if (typeof element === 'string') {\n xml += this.escapeXml(element);\n } else {\n xml += this.elementToString(element);\n }\n }\n\n return xml;\n }\n\n /**\n * Converts a single element to XML string\n */\n private elementToString(element: XMLElement): string {\n // Special case: raw XML passthrough (no wrapper element)\n // Used for VML and other legacy content that must be preserved exactly\n if (element.name === '__rawXml' && element.rawXml) {\n return element.rawXml;\n }\n\n let xml = `<${element.name}`;\n\n // Add attributes\n if (element.attributes) {\n for (const [key, value] of Object.entries(element.attributes)) {\n if (value !== undefined && value !== null && value !== false) {\n // Handle boolean attributes\n const attrValue = value === true ? key : String(value);\n // Use escapeXmlAttribute for attribute values (Issue #8)\n xml += ` ${key}=\"${XMLBuilder.escapeXmlAttribute(attrValue)}\"`;\n }\n }\n }\n\n // Self-closing element validation\n if (element.selfClosing) {\n if (XMLBuilder.CANNOT_SELF_CLOSE.includes(element.name)) {\n // Instead of throwing, force open/close tags for safety\n xml += '></' + element.name + '>';\n return xml;\n }\n xml += '/>';\n return xml;\n }\n\n xml += '>';\n\n // Add raw XML content if present (for VML passthrough)\n if (element.rawXml) {\n xml += element.rawXml;\n }\n\n // Add children\n if (element.children && element.children.length > 0) {\n xml += this.elementsToString(element.children);\n }\n\n xml += `</${element.name}>`;\n return xml;\n }\n\n /**\n * Escapes special XML characters for text content\n * (Issue #8 fix: Use escapeXmlText for element text, escapeXmlAttribute called directly for attrs)\n */\n private escapeXml(text: string): string {\n // This method is now only used for text content in elementsToString()\n // Attributes call escapeXmlAttribute() directly in elementToString()\n // Text content should NOT escape quotes (only & < >)\n return XMLBuilder.escapeXmlText(text);\n }\n\n /**\n * Escapes XML text content (element text nodes)\n * Removes invalid XML 1.0 control characters and escapes: & < >\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param text Text to escape\n * @returns Escaped text safe for XML content\n */\n static escapeXmlText(text: string): string {\n return removeInvalidXmlChars(text)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n }\n\n /**\n * Escapes XML attribute values\n * Removes invalid XML 1.0 control characters and escapes: & < > \" '\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param value Attribute value to escape\n * @returns Escaped value safe for XML attributes\n */\n static escapeXmlAttribute(value: string): string {\n return removeInvalidXmlChars(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n }\n\n /**\n * Unescapes XML entities back to original characters\n * @param text Text with XML entities\n * @returns Unescaped text\n */\n static unescapeXml(text: string): string {\n return text\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&apos;/g, \"'\")\n .replace(/&amp;/g, '&'); // Must be last to avoid double-unescaping\n }\n\n /**\n * Sanitizes and escapes XML content for safe inclusion in XML documents\n * Removes control characters, null bytes, and escapes special XML characters\n * Use this for user-provided content that may contain unsafe characters\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param text Text to sanitize and escape\n * @returns Sanitized text safe for XML content\n *\n * **Issue #11 fix:** Prevents malformed XML from CDATA markers, control chars, etc.\n */\n static sanitizeXmlContent(text: string): string {\n return (\n removeInvalidXmlChars(text)\n // Escape CDATA end marker to prevent CDATA injection\n .replace(/\\]\\]>/g, ']]&gt;')\n // Standard XML escaping (& must be first to avoid double-escaping)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n );\n }\n\n /**\n * Creates a WordprocessingML namespace attribute object\n */\n static createNamespaces(): Record<string, string> {\n return {\n 'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',\n 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',\n 'xmlns:wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',\n 'xmlns:a': 'http://schemas.openxmlformats.org/drawingml/2006/main',\n 'xmlns:pic': 'http://schemas.openxmlformats.org/drawingml/2006/picture',\n 'xmlns:w14': 'http://schemas.microsoft.com/office/word/2010/wordml',\n 'xmlns:wpc': 'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas',\n 'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',\n 'xmlns:o': 'urn:schemas-microsoft-com:office:office',\n 'xmlns:v': 'urn:schemas-microsoft-com:vml',\n 'xmlns:wp14': 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing',\n 'xmlns:w10': 'urn:schemas-microsoft-com:office:word',\n 'xmlns:w15': 'http://schemas.microsoft.com/office/word/2012/wordml',\n 'xmlns:wpg': 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup',\n 'xmlns:wpi': 'http://schemas.microsoft.com/office/word/2010/wordprocessingInk',\n 'xmlns:wne': 'http://schemas.microsoft.com/office/word/2006/wordml',\n 'xmlns:wps': 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape',\n 'xmlns:asvg': 'http://schemas.microsoft.com/office/drawing/2016/SVG/main',\n };\n }\n\n /**\n * Converts a single XMLElement to its XML string representation\n * Useful for merging elements into existing XML\n *\n * @param element - The XMLElement to convert\n * @returns XML string representation of the element\n */\n static elementToString(element: XMLElement): string {\n const builder = new XMLBuilder();\n // Use the private elementToString via the elements array + build\n (builder as any).elements.push(element);\n return builder.build();\n }\n\n /**\n * Helper method to create a WordprocessingML element\n * @param name - Element name (without 'w:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static w(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `w:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing WordprocessingML element\n * @param name - Element name (without 'w:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static wSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `w:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a w14 element (Word 2010+ features)\n * @param name - Element name (without 'w14:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static w14(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `w14:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing w14 element\n * @param name - Element name (without 'w14:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static w14Self(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `w14:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a DrawingML element (a: namespace)\n * @param name - Element name (without 'a:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static a(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `a:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing DrawingML element\n * @param name - Element name (without 'a:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static aSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `a:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a Picture element (pic: namespace)\n * @param name - Element name (without 'pic:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static pic(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `pic:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing Picture element\n * @param name - Element name (without 'pic:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static picSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `pic:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a Wordprocessing Drawing element (wp: namespace)\n * @param name - Element name (without 'wp:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static wp(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `wp:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing Wordprocessing Drawing element\n * @param name - Element name (without 'wp:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static wpSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `wp:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper to create cx/cy extent attributes (for a:ext, wp:extent, etc.)\n * @param name - Element name (e.g., 'ext')\n * @param cx - Width in EMUs\n * @param cy - Height in EMUs\n * @returns Self-closing XMLElement\n */\n static cxCy(name: string, cx: number, cy: number): XMLElement {\n return {\n name,\n attributes: { cx, cy },\n selfClosing: true,\n };\n }\n\n /**\n * Creates an SDT (Structured Document Tag) wrapper for content\n * @param content - Content to wrap (paragraphs, tables, etc.)\n * @param options - SDT options\n * @returns XMLElement representing the SDT wrapper\n */\n static createSDT(\n content: XMLElement[],\n options?: {\n id?: number;\n docPartGallery?: string;\n docPartUnique?: boolean;\n }\n ): XMLElement {\n const sdtId = options?.id ?? Math.floor(Math.random() * 2000000000) - 1000000000;\n\n // Build SDT properties\n const sdtPrChildren: XMLElement[] = [XMLBuilder.wSelf('id', { 'w:val': sdtId })];\n\n // Add docPartObj if docPartGallery is specified\n if (options?.docPartGallery) {\n sdtPrChildren.push(\n XMLBuilder.w('docPartObj', undefined, [\n XMLBuilder.wSelf('docPartGallery', { 'w:val': options.docPartGallery }),\n XMLBuilder.wSelf('docPartUnique', {\n 'w:val': options?.docPartUnique !== false ? '1' : '0',\n }),\n ])\n );\n }\n\n // Create complete SDT structure\n return XMLBuilder.w('sdt', undefined, [\n XMLBuilder.w('sdtPr', undefined, sdtPrChildren),\n XMLBuilder.w('sdtContent', undefined, content),\n ]);\n }\n\n /**\n * Creates a complete WordprocessingML document structure\n * @param bodyContent - Content for the document body\n * @returns XML string for word/document.xml\n */\n static createDocument(\n bodyContent: XMLElement[],\n namespaces: Record<string, string> = {},\n preBodyContent?: XMLElement[]\n ): string {\n const builder = new XMLBuilder();\n\n // Preserve document's original namespace order, then fill in framework defaults\n const allNamespaces: Record<string, string> = {};\n for (const [key, value] of Object.entries(namespaces)) {\n allNamespaces[key] = value;\n }\n for (const [key, value] of Object.entries(XMLBuilder.createNamespaces())) {\n if (!(key in allNamespaces)) {\n allNamespaces[key] = value;\n }\n }\n\n // Ensure mc:Ignorable is present when extended namespaces are declared.\n // Per ECMA-376, mc:Ignorable tells Word which namespace prefixes can be\n // safely ignored if the processor doesn't support them. Without it,\n // attributes like w14:paraId in raw XML passthrough zones cause corruption.\n if (!allNamespaces['mc:Ignorable']) {\n const ignorable: string[] = [];\n if (allNamespaces['xmlns:w14']) ignorable.push('w14');\n if (allNamespaces['xmlns:w15']) ignorable.push('w15');\n if (allNamespaces['xmlns:wp14']) ignorable.push('wp14');\n if (allNamespaces['xmlns:w16se']) ignorable.push('w16se');\n if (allNamespaces['xmlns:w16cid']) ignorable.push('w16cid');\n if (allNamespaces['xmlns:w16']) ignorable.push('w16');\n if (allNamespaces['xmlns:w16cex']) ignorable.push('w16cex');\n if (allNamespaces['xmlns:w16sdtdh']) ignorable.push('w16sdtdh');\n if (allNamespaces['xmlns:w16sdtfl']) ignorable.push('w16sdtfl');\n if (allNamespaces['xmlns:w16du']) ignorable.push('w16du');\n if (allNamespaces['xmlns:asvg']) ignorable.push('asvg');\n if (ignorable.length > 0) {\n allNamespaces['mc:Ignorable'] = ignorable.join(' ');\n }\n } else {\n // mc:Ignorable was loaded from the original document — ensure every\n // prefix referenced in mc:Ignorable has a matching xmlns declaration.\n // Without this, the validator rejects prefixes that appear in\n // mc:Ignorable but lack namespace declarations in the root element.\n const defaults = XMLBuilder.createNamespaces();\n const prefixes = allNamespaces['mc:Ignorable'].split(/\\s+/);\n for (const prefix of prefixes) {\n const nsKey = `xmlns:${prefix}`;\n if (!allNamespaces[nsKey] && defaults[nsKey]) {\n allNamespaces[nsKey] = defaults[nsKey];\n }\n }\n }\n\n const documentChildren: XMLElement[] = [];\n if (preBodyContent) {\n documentChildren.push(...preBodyContent);\n }\n documentChildren.push(XMLBuilder.w('body', undefined, bodyContent));\n builder.element('w:document', allNamespaces, documentChildren);\n\n return builder.build(true);\n }\n\n /**\n * Builds an XML string from a JavaScript object.\n * This is the reverse of XMLParser.parseToObject\n */\n static buildObject(obj: ParsedXmlObject, rootName: string): string {\n const builder = new XMLBuilder();\n const element = XMLBuilder.objectToElement(obj, rootName);\n if (element) {\n if (typeof element === 'string') {\n builder.text(element);\n } else {\n builder.elements.push(element);\n }\n }\n return builder.build();\n }\n\n /**\n * Converts a JavaScript object to an XMLElement.\n * @private\n */\n private static objectToElement(\n obj: ParsedXmlObject | string | number | boolean | null | undefined,\n name: string\n ): XMLElement | string | null {\n if (obj === null || obj === undefined) {\n return null;\n }\n\n if (typeof obj !== 'object' || obj === null) {\n return String(obj);\n }\n\n const attributes: Record<string, string | number | boolean> = {};\n const children: (XMLElement | string)[] = [];\n\n if (obj['#text'] && Object.keys(obj).length === 1) {\n return String(obj['#text']);\n }\n\n for (const key in obj) {\n if (key.startsWith('@_')) {\n const attrName = key.substring(2);\n // Validate attribute name is not empty after prefix removal\n if (attrName.length > 0) {\n attributes[attrName] = obj[key];\n }\n } else if (key === '#text') {\n children.push(String(obj[key]));\n } else {\n const childObj = obj[key];\n if (Array.isArray(childObj)) {\n childObj.forEach((item) => {\n const childElement = XMLBuilder.objectToElement(item, key);\n if (childElement) {\n children.push(childElement);\n }\n });\n } else {\n const childElement = XMLBuilder.objectToElement(childObj, key);\n if (childElement) {\n children.push(childElement);\n }\n }\n }\n }\n\n const element: XMLElement = {\n name,\n attributes,\n children: children.length > 0 ? children : undefined,\n };\n\n if (!element.children || element.children.length === 0) {\n if (!XMLBuilder.CANNOT_SELF_CLOSE.includes(name)) {\n element.selfClosing = true;\n }\n }\n\n return element;\n }\n\n /**\n * Helper method to build attributes object, filtering out undefined/null values\n * This simplifies the common pattern of conditionally adding attributes\n *\n * @param mapping - Map of attribute names to values\n * @returns Filtered attributes object with only defined values\n *\n * @example\n * ```typescript\n * const attrs = XMLBuilder.buildAttributes({\n * 'w:before': spacing?.before,\n * 'w:after': spacing?.after,\n * 'w:line': spacing?.line\n * });\n * // Returns only attributes with defined values\n * ```\n */\n static buildAttributes(mapping: Record<string, any>): Record<string, string | number> {\n const attrs: Record<string, string | number> = {};\n for (const [key, value] of Object.entries(mapping)) {\n if (value !== undefined && value !== null) {\n attrs[key] = value;\n }\n }\n return attrs;\n }\n\n /**\n * Creates a border element for WordprocessingML\n * Used for table borders, cell borders, and paragraph borders\n *\n * @param side - Border side (e.g., 'top', 'left', 'bottom', 'right', 'insideH', 'insideV')\n * @param border - Border definition\n * @returns XML element for border\n *\n * @example\n * ```typescript\n * const border = XMLBuilder.createBorder('top', {\n * style: 'single',\n * size: 4,\n * color: 'FF0000',\n * space: 0\n * });\n * ```\n */\n static createBorder(\n side: string,\n border: {\n style?: string;\n size?: number;\n color?: string;\n space?: number;\n themeColor?: string;\n themeTint?: string;\n themeShade?: string;\n shadow?: boolean;\n frame?: boolean;\n }\n ): XMLElement {\n const attrs = XMLBuilder.buildAttributes({\n 'w:val': border.style || 'single',\n 'w:sz': border.size,\n 'w:color': border.color,\n 'w:space': border.space,\n 'w:themeColor': border.themeColor,\n 'w:themeTint': border.themeTint,\n 'w:themeShade': border.themeShade,\n 'w:shadow': border.shadow === undefined ? undefined : border.shadow ? '1' : '0',\n 'w:frame': border.frame === undefined ? undefined : border.frame ? '1' : '0',\n });\n\n return XMLBuilder.wSelf(side, attrs);\n }\n\n /**\n * Creates a shading element for WordprocessingML\n * Used for paragraph shading, table shading, and cell shading\n *\n * @param shading - Shading definition (ShadingConfig with theme support)\n * @returns XML element for shading, or null if no shading properties\n *\n * @example\n * ```typescript\n * const shading = XMLBuilder.createShading({\n * fill: 'FFFF00',\n * pattern: 'clear',\n * color: '000000'\n * });\n * ```\n */\n static createShading(shading: ShadingConfig): XMLElement | null {\n const attrs = buildShadingAttributes(shading);\n // Default w:val to \"clear\" if not specified but other attrs exist\n if (!attrs['w:val'] && Object.keys(attrs).length > 0) {\n attrs['w:val'] = 'clear';\n }\n if (Object.keys(attrs).length > 0) {\n return XMLBuilder.wSelf('shd', attrs);\n }\n return null;\n }\n\n /**\n * Creates a margins element (tcMar, pgMar, etc.)\n * Used for cell margins, page margins, etc.\n *\n * @param type - Margin type element name (e.g., 'tcMar', 'pgMar')\n * @param margins - Margin values in twips\n * @returns XML element for margins, or null if no margins defined\n *\n * @example\n * ```typescript\n * const margins = XMLBuilder.createMargins('tcMar', {\n * top: 100,\n * bottom: 100,\n * left: 100,\n * right: 100\n * });\n * ```\n */\n static createMargins(\n type: string,\n margins: {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n start?: number;\n end?: number;\n }\n ): XMLElement | null {\n const children: XMLElement[] = [];\n\n if (margins.top !== undefined) {\n children.push(XMLBuilder.wSelf('top', { 'w:w': margins.top, 'w:type': 'dxa' }));\n }\n if (margins.bottom !== undefined) {\n children.push(XMLBuilder.wSelf('bottom', { 'w:w': margins.bottom, 'w:type': 'dxa' }));\n }\n if (margins.left !== undefined) {\n children.push(XMLBuilder.wSelf('left', { 'w:w': margins.left, 'w:type': 'dxa' }));\n }\n if (margins.right !== undefined) {\n children.push(XMLBuilder.wSelf('right', { 'w:w': margins.right, 'w:type': 'dxa' }));\n }\n if (margins.start !== undefined) {\n children.push(XMLBuilder.wSelf('start', { 'w:w': margins.start, 'w:type': 'dxa' }));\n }\n if (margins.end !== undefined) {\n children.push(XMLBuilder.wSelf('end', { 'w:w': margins.end, 'w:type': 'dxa' }));\n }\n\n if (children.length > 0) {\n return XMLBuilder.w(type, undefined, children);\n }\n return null;\n }\n}\n"]}
1
+ {"version":3,"file":"XMLBuilder.js","sourceRoot":"","sources":["../../../src/xml/XMLBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * XMLBuilder - Utility for building XML content\n * Provides a simple fluent API for generating WordprocessingML XML\n */\n\nimport { removeInvalidXmlChars } from '../utils/xmlSanitization.js';\nimport type { ShadingConfig } from '../elements/CommonTypes.js';\nimport { buildShadingAttributes } from '../elements/CommonTypes.js';\n\n/** Represents a parsed XML object from XMLParser.parseToObject() */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- parsed XML has dynamic keys and recursive structure\ntype ParsedXmlObject = Record<string, any>;\n\n/**\n * Represents an XML element with attributes and children\n */\nexport interface XMLElement {\n name: string;\n attributes?: Record<string, string | number | boolean | undefined>;\n children?: (XMLElement | string)[];\n selfClosing?: boolean;\n /** Raw XML content to include without escaping (used for VML passthrough) */\n rawXml?: string;\n}\n\n/**\n * XML Builder for creating WordprocessingML XML\n */\nexport class XMLBuilder {\n private elements: (XMLElement | string)[] = [];\n\n /**\n * Elements that must NEVER be self-closing in Word XML per ECMA-376.\n * Self-closing these elements causes Word to not parse correctly or lose content.\n */\n private static readonly CANNOT_SELF_CLOSE = [\n 'w:t',\n 'w:r',\n 'w:p',\n 'w:tbl',\n 'w:tr',\n 'w:tc',\n 'w:body',\n 'w:document',\n 'w:hyperlink',\n 'w:sdt',\n 'w:sdtContent',\n 'w:sdtPr',\n 'w:pPr',\n 'w:rPr',\n 'w:sectPr',\n 'w:del', // Deletion revisions - container element, must have closing tag\n 'w:ins', // Insertion revisions - container element, must have closing tag\n 'w:moveFrom', // Move source markers - container element\n 'w:moveTo', // Move destination markers - container element\n // Note: w:bookmarkStart and w:bookmarkEnd MUST be self-closing per ECMA-376\n ];\n\n /**\n * Adds an element to the builder\n * @param name - Element name (with namespace prefix if needed)\n * @param attributes - Element attributes\n * @param children - Child elements or text\n * @returns This builder for chaining\n */\n element(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLBuilder {\n this.elements.push({\n name,\n attributes,\n children,\n });\n return this;\n }\n\n /**\n * Adds a self-closing element\n * @param name - Element name\n * @param attributes - Element attributes\n * @returns This builder for chaining\n * @throws {Error} If attempting to create self-closing w:t element (not allowed per ECMA-376)\n */\n selfClosingElement(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLBuilder {\n // Validation: Text elements (<w:t>) cannot be self-closing per ECMA-376\n // Self-closing <w:t/> elements cause Word to fail opening the document\n if (name === 'w:t' || name === 't') {\n throw new Error(\n 'Text elements (<w:t>) cannot be self-closing per ECMA-376. ' +\n 'Use element() with empty text content instead: XMLBuilder.w(\"t\", attrs, [\"\"])'\n );\n }\n\n this.elements.push({\n name,\n attributes,\n selfClosing: true,\n });\n return this;\n }\n\n /**\n * Adds text content\n * @param text - Text to add\n * @returns This builder for chaining\n */\n text(text: string): XMLBuilder {\n this.elements.push(text);\n return this;\n }\n\n /**\n * Builds the XML string\n * @param includeDeclaration - Whether to include XML declaration\n * @returns Generated XML string\n */\n build(includeDeclaration = false): string {\n let xml = '';\n\n if (includeDeclaration) {\n xml += '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n';\n }\n\n xml += this.elementsToString(this.elements);\n return xml;\n }\n\n /**\n * Converts elements to XML string\n */\n private elementsToString(elements: (XMLElement | string)[]): string {\n let xml = '';\n\n for (const element of elements) {\n if (typeof element === 'string') {\n xml += this.escapeXml(element);\n } else {\n xml += this.elementToString(element);\n }\n }\n\n return xml;\n }\n\n /**\n * Converts a single element to XML string\n */\n private elementToString(element: XMLElement): string {\n // Special case: raw XML passthrough (no wrapper element)\n // Used for VML and other legacy content that must be preserved exactly\n if (element.name === '__rawXml' && element.rawXml) {\n return element.rawXml;\n }\n\n let xml = `<${element.name}`;\n\n // Add attributes\n if (element.attributes) {\n for (const [key, value] of Object.entries(element.attributes)) {\n if (value !== undefined && value !== null) {\n // Booleans serialize as ST_OnOff literals (ECMA-376 §22.9.2.13).\n // Explicit false must emit \"0\" — dropping it would flip an explicit\n // override to inherited/on under CT_OnOff presence semantics.\n // Callers signal absence with undefined, never false.\n const attrValue = value === true ? '1' : value === false ? '0' : String(value);\n // Use escapeXmlAttribute for attribute values (Issue #8)\n xml += ` ${key}=\"${XMLBuilder.escapeXmlAttribute(attrValue)}\"`;\n }\n }\n }\n\n // Self-closing element validation\n if (element.selfClosing) {\n if (XMLBuilder.CANNOT_SELF_CLOSE.includes(element.name)) {\n // Instead of throwing, force open/close tags for safety\n xml += '></' + element.name + '>';\n return xml;\n }\n xml += '/>';\n return xml;\n }\n\n xml += '>';\n\n // Add raw XML content if present (for VML passthrough)\n if (element.rawXml) {\n xml += element.rawXml;\n }\n\n // Add children\n if (element.children && element.children.length > 0) {\n xml += this.elementsToString(element.children);\n }\n\n xml += `</${element.name}>`;\n return xml;\n }\n\n /**\n * Escapes special XML characters for text content\n * (Issue #8 fix: Use escapeXmlText for element text, escapeXmlAttribute called directly for attrs)\n */\n private escapeXml(text: string): string {\n // This method is now only used for text content in elementsToString()\n // Attributes call escapeXmlAttribute() directly in elementToString()\n // Text content should NOT escape quotes (only & < >)\n return XMLBuilder.escapeXmlText(text);\n }\n\n /**\n * Escapes XML text content (element text nodes)\n * Removes invalid XML 1.0 control characters and escapes: & < >\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param text Text to escape\n * @returns Escaped text safe for XML content\n */\n static escapeXmlText(text: string): string {\n return removeInvalidXmlChars(text)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n }\n\n /**\n * Escapes XML attribute values\n * Removes invalid XML 1.0 control characters and escapes: & < > \" '\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param value Attribute value to escape\n * @returns Escaped value safe for XML attributes\n */\n static escapeXmlAttribute(value: string): string {\n return removeInvalidXmlChars(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n }\n\n /** The five predefined XML 1.0 named entities */\n private static readonly NAMED_ENTITIES: Record<string, string> = {\n lt: '<',\n gt: '>',\n quot: '\"',\n apos: \"'\",\n amp: '&',\n };\n\n /**\n * Unescapes XML entities back to original characters\n * Decodes the five predefined named entities plus numeric character\n * references (&#8217; / &#xA0;), which XML 1.0 §4.1 requires every\n * conforming processor to expand — third-party producers emit them, and\n * leaving them raw double-escapes the ampersand on save.\n * @param text Text with XML entities\n * @returns Unescaped text\n */\n static unescapeXml(text: string): string {\n // Single pass so text produced by one decode is never re-decoded by a\n // later one (e.g. '&#38;amp;' must yield '&amp;', not '&').\n return text.replace(\n /&(?:(lt|gt|quot|apos|amp)|#x([0-9A-Fa-f]+)|#(\\d+));/g,\n (match, named?: string, hex?: string, dec?: string) => {\n if (named !== undefined) {\n return XMLBuilder.NAMED_ENTITIES[named] ?? match;\n }\n const code = hex !== undefined ? parseInt(hex, 16) : Number(dec);\n // Code points outside the XML 1.0 Char production (NUL, surrogates,\n // beyond U+10FFFF) would make the decoded string unserializable —\n // keep the raw reference instead of injecting an invalid character.\n const isXmlChar =\n code === 0x9 ||\n code === 0xa ||\n code === 0xd ||\n (code >= 0x20 && code <= 0xd7ff) ||\n (code >= 0xe000 && code <= 0xfffd) ||\n (code >= 0x10000 && code <= 0x10ffff);\n return isXmlChar ? String.fromCodePoint(code) : match;\n }\n );\n }\n\n /**\n * Sanitizes and escapes XML content for safe inclusion in XML documents\n * Removes control characters, null bytes, and escapes special XML characters\n * Use this for user-provided content that may contain unsafe characters\n *\n * Per XML 1.0 spec, control chars 0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F are invalid.\n * Tab (0x09), newline (0x0A), and CR (0x0D) are preserved.\n *\n * @param text Text to sanitize and escape\n * @returns Sanitized text safe for XML content\n *\n * **Issue #11 fix:** Prevents malformed XML from CDATA markers, control chars, etc.\n */\n static sanitizeXmlContent(text: string): string {\n return (\n removeInvalidXmlChars(text)\n // Escape CDATA end marker to prevent CDATA injection\n .replace(/\\]\\]>/g, ']]&gt;')\n // Standard XML escaping (& must be first to avoid double-escaping)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n );\n }\n\n /**\n * Creates a WordprocessingML namespace attribute object\n */\n static createNamespaces(): Record<string, string> {\n return {\n 'xmlns:w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',\n 'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',\n 'xmlns:wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',\n 'xmlns:a': 'http://schemas.openxmlformats.org/drawingml/2006/main',\n 'xmlns:pic': 'http://schemas.openxmlformats.org/drawingml/2006/picture',\n 'xmlns:w14': 'http://schemas.microsoft.com/office/word/2010/wordml',\n 'xmlns:wpc': 'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas',\n 'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',\n 'xmlns:o': 'urn:schemas-microsoft-com:office:office',\n 'xmlns:v': 'urn:schemas-microsoft-com:vml',\n 'xmlns:wp14': 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing',\n 'xmlns:w10': 'urn:schemas-microsoft-com:office:word',\n 'xmlns:w15': 'http://schemas.microsoft.com/office/word/2012/wordml',\n 'xmlns:wpg': 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup',\n 'xmlns:wpi': 'http://schemas.microsoft.com/office/word/2010/wordprocessingInk',\n 'xmlns:wne': 'http://schemas.microsoft.com/office/word/2006/wordml',\n 'xmlns:wps': 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape',\n 'xmlns:asvg': 'http://schemas.microsoft.com/office/drawing/2016/SVG/main',\n };\n }\n\n /**\n * Converts a single XMLElement to its XML string representation\n * Useful for merging elements into existing XML\n *\n * @param element - The XMLElement to convert\n * @returns XML string representation of the element\n */\n static elementToString(element: XMLElement): string {\n const builder = new XMLBuilder();\n // Use the private elementToString via the elements array + build\n (builder as any).elements.push(element);\n return builder.build();\n }\n\n /**\n * Helper method to create a WordprocessingML element\n * @param name - Element name (without 'w:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static w(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `w:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing WordprocessingML element\n * @param name - Element name (without 'w:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static wSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `w:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a w14 element (Word 2010+ features)\n * @param name - Element name (without 'w14:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static w14(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `w14:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing w14 element\n * @param name - Element name (without 'w14:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static w14Self(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `w14:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a DrawingML element (a: namespace)\n * @param name - Element name (without 'a:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static a(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `a:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing DrawingML element\n * @param name - Element name (without 'a:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static aSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `a:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a Picture element (pic: namespace)\n * @param name - Element name (without 'pic:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static pic(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `pic:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing Picture element\n * @param name - Element name (without 'pic:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static picSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `pic:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper method to create a Wordprocessing Drawing element (wp: namespace)\n * @param name - Element name (without 'wp:' prefix)\n * @param attributes - Element attributes\n * @param children - Child elements\n * @returns XMLElement\n */\n static wp(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>,\n children?: (XMLElement | string)[]\n ): XMLElement {\n return {\n name: `wp:${name}`,\n attributes,\n children,\n };\n }\n\n /**\n * Helper method to create a self-closing Wordprocessing Drawing element\n * @param name - Element name (without 'wp:' prefix)\n * @param attributes - Element attributes\n * @returns XMLElement\n */\n static wpSelf(\n name: string,\n attributes?: Record<string, string | number | boolean | undefined>\n ): XMLElement {\n return {\n name: `wp:${name}`,\n attributes,\n selfClosing: true,\n };\n }\n\n /**\n * Helper to create cx/cy extent attributes (for a:ext, wp:extent, etc.)\n * @param name - Element name (e.g., 'ext')\n * @param cx - Width in EMUs\n * @param cy - Height in EMUs\n * @returns Self-closing XMLElement\n */\n static cxCy(name: string, cx: number, cy: number): XMLElement {\n return {\n name,\n attributes: { cx, cy },\n selfClosing: true,\n };\n }\n\n /**\n * Creates an SDT (Structured Document Tag) wrapper for content\n * @param content - Content to wrap (paragraphs, tables, etc.)\n * @param options - SDT options\n * @returns XMLElement representing the SDT wrapper\n */\n static createSDT(\n content: XMLElement[],\n options?: {\n id?: number;\n docPartGallery?: string;\n docPartUnique?: boolean;\n }\n ): XMLElement {\n const sdtId = options?.id ?? Math.floor(Math.random() * 2000000000) - 1000000000;\n\n // Build SDT properties\n const sdtPrChildren: XMLElement[] = [XMLBuilder.wSelf('id', { 'w:val': sdtId })];\n\n // Add docPartObj if docPartGallery is specified\n if (options?.docPartGallery) {\n sdtPrChildren.push(\n XMLBuilder.w('docPartObj', undefined, [\n XMLBuilder.wSelf('docPartGallery', { 'w:val': options.docPartGallery }),\n XMLBuilder.wSelf('docPartUnique', {\n 'w:val': options?.docPartUnique !== false ? '1' : '0',\n }),\n ])\n );\n }\n\n // Create complete SDT structure\n return XMLBuilder.w('sdt', undefined, [\n XMLBuilder.w('sdtPr', undefined, sdtPrChildren),\n XMLBuilder.w('sdtContent', undefined, content),\n ]);\n }\n\n /**\n * Creates a complete WordprocessingML document structure\n * @param bodyContent - Content for the document body\n * @returns XML string for word/document.xml\n */\n static createDocument(\n bodyContent: XMLElement[],\n namespaces: Record<string, string> = {},\n preBodyContent?: XMLElement[]\n ): string {\n const builder = new XMLBuilder();\n\n // Preserve document's original namespace order, then fill in framework defaults\n const allNamespaces: Record<string, string> = {};\n for (const [key, value] of Object.entries(namespaces)) {\n allNamespaces[key] = value;\n }\n for (const [key, value] of Object.entries(XMLBuilder.createNamespaces())) {\n if (!(key in allNamespaces)) {\n allNamespaces[key] = value;\n }\n }\n\n // Ensure mc:Ignorable is present when extended namespaces are declared.\n // Per ECMA-376, mc:Ignorable tells Word which namespace prefixes can be\n // safely ignored if the processor doesn't support them. Without it,\n // attributes like w14:paraId in raw XML passthrough zones cause corruption.\n if (!allNamespaces['mc:Ignorable']) {\n const ignorable: string[] = [];\n if (allNamespaces['xmlns:w14']) ignorable.push('w14');\n if (allNamespaces['xmlns:w15']) ignorable.push('w15');\n if (allNamespaces['xmlns:wp14']) ignorable.push('wp14');\n if (allNamespaces['xmlns:w16se']) ignorable.push('w16se');\n if (allNamespaces['xmlns:w16cid']) ignorable.push('w16cid');\n if (allNamespaces['xmlns:w16']) ignorable.push('w16');\n if (allNamespaces['xmlns:w16cex']) ignorable.push('w16cex');\n if (allNamespaces['xmlns:w16sdtdh']) ignorable.push('w16sdtdh');\n if (allNamespaces['xmlns:w16sdtfl']) ignorable.push('w16sdtfl');\n if (allNamespaces['xmlns:w16du']) ignorable.push('w16du');\n if (allNamespaces['xmlns:asvg']) ignorable.push('asvg');\n if (ignorable.length > 0) {\n allNamespaces['mc:Ignorable'] = ignorable.join(' ');\n }\n } else {\n // mc:Ignorable was loaded from the original document — ensure every\n // prefix referenced in mc:Ignorable has a matching xmlns declaration.\n // Without this, the validator rejects prefixes that appear in\n // mc:Ignorable but lack namespace declarations in the root element.\n const defaults = XMLBuilder.createNamespaces();\n const prefixes = allNamespaces['mc:Ignorable'].split(/\\s+/);\n for (const prefix of prefixes) {\n const nsKey = `xmlns:${prefix}`;\n if (!allNamespaces[nsKey] && defaults[nsKey]) {\n allNamespaces[nsKey] = defaults[nsKey];\n }\n }\n }\n\n const documentChildren: XMLElement[] = [];\n if (preBodyContent) {\n documentChildren.push(...preBodyContent);\n }\n documentChildren.push(XMLBuilder.w('body', undefined, bodyContent));\n builder.element('w:document', allNamespaces, documentChildren);\n\n return builder.build(true);\n }\n\n /**\n * Builds an XML string from a JavaScript object.\n * This is the reverse of XMLParser.parseToObject\n */\n static buildObject(obj: ParsedXmlObject, rootName: string): string {\n const builder = new XMLBuilder();\n const element = XMLBuilder.objectToElement(obj, rootName);\n if (element) {\n builder.elements.push(element);\n }\n return builder.build();\n }\n\n /**\n * Converts a JavaScript object to an XMLElement.\n * @private\n */\n private static objectToElement(\n obj: ParsedXmlObject | string | number | boolean | null | undefined,\n name: string\n ): XMLElement | null {\n if (obj === null || obj === undefined) {\n return null;\n }\n\n if (typeof obj !== 'object') {\n // The parser collapses text-only elements to their primitive value, so\n // the wrapping tag must be re-emitted here — bare text inside container\n // elements (e.g. w:r) is invalid WordprocessingML.\n return { name, children: [String(obj)] };\n }\n\n const attributes: Record<string, string | number | boolean> = {};\n const children: (XMLElement | string)[] = [];\n\n for (const key in obj) {\n if (key.startsWith('@_')) {\n const attrName = key.substring(2);\n // Validate attribute name is not empty after prefix removal\n if (attrName.length > 0) {\n attributes[attrName] = obj[key];\n }\n } else if (key === '#text') {\n children.push(String(obj[key]));\n }\n }\n\n // _orderedChildren is parser metadata, never document content. When\n // present, it restores the original interleaving of same-named siblings\n // (e.g. w:t / w:tab / w:t in a run) that the keyed object form loses.\n const orderedChildren = obj['_orderedChildren'] as\n | { type: string; index: number }[]\n | undefined;\n\n if (orderedChildren && orderedChildren.length > 0) {\n for (const childInfo of orderedChildren) {\n const childValue = obj[childInfo.type];\n if (childValue === undefined) {\n continue;\n }\n const item = Array.isArray(childValue)\n ? childValue[childInfo.index]\n : childInfo.index === 0\n ? childValue\n : undefined;\n if (item === undefined) {\n continue;\n }\n const childElement = XMLBuilder.objectToElement(item, childInfo.type);\n if (childElement) {\n children.push(childElement);\n }\n }\n } else {\n for (const key in obj) {\n if (key.startsWith('@_') || key === '#text' || key === '_orderedChildren') {\n continue;\n }\n const childObj = obj[key];\n if (Array.isArray(childObj)) {\n childObj.forEach((item) => {\n const childElement = XMLBuilder.objectToElement(item, key);\n if (childElement) {\n children.push(childElement);\n }\n });\n } else {\n const childElement = XMLBuilder.objectToElement(childObj, key);\n if (childElement) {\n children.push(childElement);\n }\n }\n }\n }\n\n const element: XMLElement = {\n name,\n attributes,\n children: children.length > 0 ? children : undefined,\n };\n\n if (!element.children || element.children.length === 0) {\n if (!XMLBuilder.CANNOT_SELF_CLOSE.includes(name)) {\n element.selfClosing = true;\n }\n }\n\n return element;\n }\n\n /**\n * Helper method to build attributes object, filtering out undefined/null values\n * This simplifies the common pattern of conditionally adding attributes\n *\n * @param mapping - Map of attribute names to values\n * @returns Filtered attributes object with only defined values\n *\n * @example\n * ```typescript\n * const attrs = XMLBuilder.buildAttributes({\n * 'w:before': spacing?.before,\n * 'w:after': spacing?.after,\n * 'w:line': spacing?.line\n * });\n * // Returns only attributes with defined values\n * ```\n */\n static buildAttributes(mapping: Record<string, any>): Record<string, string | number> {\n const attrs: Record<string, string | number> = {};\n for (const [key, value] of Object.entries(mapping)) {\n if (value !== undefined && value !== null) {\n attrs[key] = value;\n }\n }\n return attrs;\n }\n\n /**\n * Creates a border element for WordprocessingML\n * Used for table borders, cell borders, and paragraph borders\n *\n * @param side - Border side (e.g., 'top', 'left', 'bottom', 'right', 'insideH', 'insideV')\n * @param border - Border definition\n * @returns XML element for border\n *\n * @example\n * ```typescript\n * const border = XMLBuilder.createBorder('top', {\n * style: 'single',\n * size: 4,\n * color: 'FF0000',\n * space: 0\n * });\n * ```\n */\n static createBorder(\n side: string,\n border: {\n style?: string;\n size?: number;\n color?: string;\n space?: number;\n themeColor?: string;\n themeTint?: string;\n themeShade?: string;\n shadow?: boolean;\n frame?: boolean;\n }\n ): XMLElement {\n const attrs = XMLBuilder.buildAttributes({\n 'w:val': border.style || 'single',\n 'w:sz': border.size,\n 'w:color': border.color,\n 'w:space': border.space,\n 'w:themeColor': border.themeColor,\n 'w:themeTint': border.themeTint,\n 'w:themeShade': border.themeShade,\n 'w:shadow': border.shadow === undefined ? undefined : border.shadow ? '1' : '0',\n 'w:frame': border.frame === undefined ? undefined : border.frame ? '1' : '0',\n });\n\n return XMLBuilder.wSelf(side, attrs);\n }\n\n /**\n * Creates a shading element for WordprocessingML\n * Used for paragraph shading, table shading, and cell shading\n *\n * @param shading - Shading definition (ShadingConfig with theme support)\n * @returns XML element for shading, or null if no shading properties\n *\n * @example\n * ```typescript\n * const shading = XMLBuilder.createShading({\n * fill: 'FFFF00',\n * pattern: 'clear',\n * color: '000000'\n * });\n * ```\n */\n static createShading(shading: ShadingConfig): XMLElement | null {\n const attrs = buildShadingAttributes(shading);\n // Default w:val to \"clear\" if not specified but other attrs exist\n if (!attrs['w:val'] && Object.keys(attrs).length > 0) {\n attrs['w:val'] = 'clear';\n }\n if (Object.keys(attrs).length > 0) {\n return XMLBuilder.wSelf('shd', attrs);\n }\n return null;\n }\n\n /**\n * Creates a margins element (tcMar, pgMar, etc.)\n * Used for cell margins, page margins, etc.\n *\n * @param type - Margin type element name (e.g., 'tcMar', 'pgMar')\n * @param margins - Margin values in twips\n * @returns XML element for margins, or null if no margins defined\n *\n * @example\n * ```typescript\n * const margins = XMLBuilder.createMargins('tcMar', {\n * top: 100,\n * bottom: 100,\n * left: 100,\n * right: 100\n * });\n * ```\n */\n static createMargins(\n type: string,\n margins: {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n start?: number;\n end?: number;\n }\n ): XMLElement | null {\n const children: XMLElement[] = [];\n\n if (margins.top !== undefined) {\n children.push(XMLBuilder.wSelf('top', { 'w:w': margins.top, 'w:type': 'dxa' }));\n }\n if (margins.bottom !== undefined) {\n children.push(XMLBuilder.wSelf('bottom', { 'w:w': margins.bottom, 'w:type': 'dxa' }));\n }\n if (margins.left !== undefined) {\n children.push(XMLBuilder.wSelf('left', { 'w:w': margins.left, 'w:type': 'dxa' }));\n }\n if (margins.right !== undefined) {\n children.push(XMLBuilder.wSelf('right', { 'w:w': margins.right, 'w:type': 'dxa' }));\n }\n if (margins.start !== undefined) {\n children.push(XMLBuilder.wSelf('start', { 'w:w': margins.start, 'w:type': 'dxa' }));\n }\n if (margins.end !== undefined) {\n children.push(XMLBuilder.wSelf('end', { 'w:w': margins.end, 'w:type': 'dxa' }));\n }\n\n if (children.length > 0) {\n return XMLBuilder.w(type, undefined, children);\n }\n return null;\n }\n}\n"]}
@@ -41,7 +41,7 @@ export class XMLParser {
41
41
  pos = startIdx + openTag.length;
42
42
  continue;
43
43
  }
44
- const openEnd = xml.indexOf('>', startIdx);
44
+ const openEnd = XMLParser.findTagEnd(xml, startIdx);
45
45
  if (openEnd === -1)
46
46
  break;
47
47
  if (xml.substring(openEnd - 1, openEnd + 1) === selfClosingEnd) {
@@ -152,7 +152,7 @@ export class XMLParser {
152
152
  const startIdx = xml.indexOf(startTag);
153
153
  if (startIdx === -1)
154
154
  return undefined;
155
- const openEnd = xml.indexOf('>', startIdx);
155
+ const openEnd = XMLParser.findTagEnd(xml, startIdx);
156
156
  if (openEnd === -1)
157
157
  return undefined;
158
158
  const endIdx = xml.indexOf(endTag, openEnd);
@@ -160,6 +160,23 @@ export class XMLParser {
160
160
  return undefined;
161
161
  return xml.substring(openEnd + 1, endIdx);
162
162
  }
163
+ static findTagEnd(xml, startPos) {
164
+ let quote;
165
+ for (let pos = startPos; pos < xml.length; pos++) {
166
+ const ch = xml[pos];
167
+ if (quote) {
168
+ if (ch === quote)
169
+ quote = undefined;
170
+ }
171
+ else if (ch === '"' || ch === "'") {
172
+ quote = ch;
173
+ }
174
+ else if (ch === '>') {
175
+ return pos;
176
+ }
177
+ }
178
+ return -1;
179
+ }
163
180
  static extractSelfClosingTag(xml, tagName) {
164
181
  const startPattern = `<${tagName}`;
165
182
  let searchPos = 0;
@@ -169,14 +186,11 @@ export class XMLParser {
169
186
  return undefined;
170
187
  const charAfterTag = xml[startIdx + startPattern.length];
171
188
  if (charAfterTag === ' ' || charAfterTag === '/' || charAfterTag === '>') {
172
- const endIdx = xml.indexOf('/>', startIdx);
173
- if (endIdx === -1) {
174
- const closeTagStart = xml.indexOf('>', startIdx);
175
- if (closeTagStart === -1)
176
- return undefined;
177
- return xml.substring(startIdx + startPattern.length, closeTagStart);
178
- }
179
- return xml.substring(startIdx + startPattern.length, endIdx);
189
+ const tagEnd = XMLParser.findTagEnd(xml, startIdx + startPattern.length);
190
+ if (tagEnd === -1)
191
+ return undefined;
192
+ const attrEnd = xml[tagEnd - 1] === '/' ? tagEnd - 1 : tagEnd;
193
+ return xml.substring(startIdx + startPattern.length, attrEnd);
180
194
  }
181
195
  searchPos = startIdx + 1;
182
196
  }
@@ -220,13 +234,27 @@ export class XMLParser {
220
234
  }
221
235
  return { value: {}, endPos: xml.length };
222
236
  }
237
+ if (xml.substring(openTagStart, openTagStart + 2) === '<?') {
238
+ const piEnd = xml.indexOf('?>', openTagStart + 2);
239
+ if (piEnd !== -1) {
240
+ return XMLParser.parseElementToObject(xml, piEnd + 2, options, depth);
241
+ }
242
+ return { value: {}, endPos: xml.length };
243
+ }
244
+ if (xml.substring(openTagStart, openTagStart + 9) === '<![CDATA[') {
245
+ const cdataEnd = xml.indexOf(']]>', openTagStart + 9);
246
+ if (cdataEnd !== -1) {
247
+ return XMLParser.parseElementToObject(xml, cdataEnd + 3, options, depth);
248
+ }
249
+ return { value: {}, endPos: xml.length };
250
+ }
223
251
  const nameMatch = /^([a-zA-Z0-9:_-]+)/.exec(xml.substring(openTagStart + 1));
224
252
  if (!nameMatch) {
225
253
  return { value: {}, endPos: openTagStart + 1 };
226
254
  }
227
255
  const originalElementName = nameMatch[1] || '';
228
256
  let elementName = originalElementName;
229
- const tagHeaderEnd = xml.indexOf('>', openTagStart);
257
+ const tagHeaderEnd = XMLParser.findTagEnd(xml, openTagStart);
230
258
  if (tagHeaderEnd === -1) {
231
259
  return { value: {}, endPos: xml.length };
232
260
  }
@@ -271,6 +299,16 @@ export class XMLParser {
271
299
  textContent += XMLBuilder.unescapeXml(text);
272
300
  }
273
301
  }
302
+ if (content.startsWith('<![CDATA[', nextTag)) {
303
+ const cdataEnd = content.indexOf(']]>', nextTag + 9);
304
+ if (cdataEnd === -1) {
305
+ textContent += content.substring(nextTag + 9);
306
+ break;
307
+ }
308
+ textContent += content.substring(nextTag + 9, cdataEnd);
309
+ pos = cdataEnd + 3;
310
+ continue;
311
+ }
274
312
  const childResult = XMLParser.parseElementToObject(content, nextTag, options, depth + 1);
275
313
  const childObj = childResult.value;
276
314
  const childKeys = Object.keys(childObj);
@@ -300,6 +338,9 @@ export class XMLParser {
300
338
  }
301
339
  if (children.length > 0) {
302
340
  const coalescedChildren = XMLParser.coalesceChildren(children, options);
341
+ if (typeof elementValue === 'string') {
342
+ elementValue = { [options.textNodeName]: elementValue };
343
+ }
303
344
  if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {
304
345
  elementValue = { ...elementValue, ...coalescedChildren };
305
346
  }
@@ -374,9 +415,10 @@ export class XMLParser {
374
415
  attrName = attrName.split(':')[1] || attrName;
375
416
  }
376
417
  const prefixedName = options.attributeNamePrefix + attrName;
418
+ const decodedValue = XMLBuilder.unescapeXml(attrValue);
377
419
  attributes[prefixedName] = options.parseAttributeValue
378
- ? XMLParser.parseValue(attrValue)
379
- : attrValue;
420
+ ? XMLParser.parseValue(decodedValue)
421
+ : decodedValue;
380
422
  }
381
423
  return attributes;
382
424
  }
@@ -1 +1 @@
1
- {"version":3,"file":"XMLParser.js","sourceRoot":"","sources":["../../../src/xml/XMLParser.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * XMLParser - Simple position-based XML parser\n * Avoids regex backtracking issues that can cause ReDoS attacks\n * Completes the DocXML framework (XMLBuilder + XMLParser)\n */\n\nimport { getGlobalLogger, createScopedLogger, ILogger } from '../utils/logger.js';\nimport { XMLBuilder } from './XMLBuilder.js';\n\n// Create scoped logger for XMLParser operations\nfunction getLogger(): ILogger {\n return createScopedLogger(getGlobalLogger(), 'XMLParser');\n}\n\n/**\n * Default maximum nesting depth for XML parsing.\n * Prevents stack overflow on deeply nested documents.\n */\nexport const DEFAULT_MAX_NESTING_DEPTH = 256;\n\n/**\n * Options for XML-to-object parsing\n */\nexport interface ParseToObjectOptions {\n /** Ignore attributes (default: false) */\n ignoreAttributes?: boolean;\n\n /** Attribute name prefix (default: '@_') */\n attributeNamePrefix?: string;\n\n /** Text node property name (default: '#text') */\n textNodeName?: string;\n\n /** Remove namespace prefixes from element names (default: false) */\n ignoreNamespace?: boolean;\n\n /** Parse numeric attribute values (default: true) */\n parseAttributeValue?: boolean;\n\n /** Trim whitespace from text values (default: true) */\n trimValues?: boolean;\n\n /** Always return arrays for elements (default: false) */\n alwaysArray?: boolean;\n\n /** Maximum nesting depth (default: 256). Prevents stack overflow on deeply nested documents. */\n maxNestingDepth?: number;\n}\n\n/**\n * Parsed XML object structure\n * Can be a string, object, array, or nested structure\n */\nexport type ParsedXMLValue =\n | string\n | number\n | boolean\n | ParsedXMLObject\n | ParsedXMLObject[]\n | null\n | undefined;\n\n/**\n * Parsed XML object with dynamic keys\n */\nexport interface ParsedXMLObject {\n [key: string]: ParsedXMLValue;\n}\n\n/**\n * Internal structure for tracking parsed elements during parsing\n */\ninterface ParsedElement {\n name: string;\n value: ParsedXMLValue;\n}\n\n/**\n * Simple XML parser using position-based parsing instead of regex\n * Prevents catastrophic backtracking (ReDoS attacks) by avoiding nested regex patterns\n */\nexport class XMLParser {\n /**\n * Extracts the body content from a Word document XML\n * @param docXml - The complete document.xml content\n * @returns The body content, or empty string if not found\n */\n static extractBody(docXml: string): string {\n const startTag = '<w:body';\n const endTag = '</w:body>';\n\n const startIdx = docXml.indexOf(startTag);\n if (startIdx === -1) return '';\n\n // Find the closing > of opening tag\n const openEnd = docXml.indexOf('>', startIdx);\n if (openEnd === -1) return '';\n\n // Find matching closing tag\n const endIdx = docXml.indexOf(endTag, openEnd);\n if (endIdx === -1) return '';\n\n return docXml.substring(openEnd + 1, endIdx);\n }\n\n /**\n * Extracts all elements of a given type using position-based parsing\n * Handles nested tags correctly by tracking depth\n * @param xml - XML content to parse\n * @param tagName - Tag name to extract (e.g., 'w:p', 'w:r')\n * @returns Array of XML strings for each element\n */\n static extractElements(xml: string, tagName: string): string[] {\n const elements: string[] = [];\n const openTag = `<${tagName}`;\n const closeTag = `</${tagName}>`;\n const selfClosingEnd = '/>';\n\n let pos = 0;\n while (pos < xml.length) {\n const startIdx = xml.indexOf(openTag, pos);\n if (startIdx === -1) break;\n\n // Verify this is the exact tag (not a prefix match like <w:p matching <w:pPr>)\n // The character after the tag name must be either '>', '/', whitespace, or '=' (for attributes)\n const charAfterTag = xml[startIdx + openTag.length];\n if (\n charAfterTag &&\n charAfterTag !== '>' &&\n charAfterTag !== '/' &&\n charAfterTag !== ' ' &&\n charAfterTag !== '\\t' &&\n charAfterTag !== '\\n' &&\n charAfterTag !== '\\r' &&\n charAfterTag !== '='\n ) {\n // This is a prefix match (e.g., <w:pPr> when looking for <w:p>), skip it (Issue #5)\n pos = startIdx + openTag.length;\n continue;\n }\n\n // Find the end of opening tag\n const openEnd = xml.indexOf('>', startIdx);\n if (openEnd === -1) break;\n\n // Check if self-closing\n if (xml.substring(openEnd - 1, openEnd + 1) === selfClosingEnd) {\n elements.push(xml.substring(startIdx, openEnd + 1));\n pos = openEnd + 1;\n continue;\n }\n\n // Find matching closing tag (handle nesting)\n let depth = 1;\n let searchPos = openEnd + 1;\n\n while (depth > 0 && searchPos < xml.length) {\n // Find next potential opening tag\n let nextOpen = -1;\n let openSearchPos = searchPos;\n while (true) {\n const candidateOpen = xml.indexOf(openTag, openSearchPos);\n if (candidateOpen === -1) {\n break;\n }\n // Verify it's an exact match (not a prefix)\n const charAfter = xml[candidateOpen + openTag.length];\n if (\n charAfter &&\n charAfter !== '>' &&\n charAfter !== '/' &&\n charAfter !== ' ' &&\n charAfter !== '\\t' &&\n charAfter !== '\\n' &&\n charAfter !== '\\r'\n ) {\n // Prefix match, keep searching\n openSearchPos = candidateOpen + openTag.length;\n continue;\n }\n nextOpen = candidateOpen;\n break;\n }\n\n const nextClose = xml.indexOf(closeTag, searchPos);\n\n if (nextClose === -1) break;\n\n if (nextOpen !== -1 && nextOpen < nextClose) {\n depth++;\n searchPos = nextOpen + openTag.length;\n } else {\n depth--;\n if (depth === 0) {\n elements.push(xml.substring(startIdx, nextClose + closeTag.length));\n pos = nextClose + closeTag.length;\n } else {\n searchPos = nextClose + closeTag.length;\n }\n }\n }\n\n if (depth > 0) {\n // Unclosed tag - skip it\n pos = startIdx + openTag.length;\n }\n }\n\n return elements;\n }\n\n /**\n * Extracts attribute value from an XML string\n * @param xml - XML content\n * @param attributeName - Attribute name (e.g., 'w:val')\n * @returns Attribute value or undefined\n */\n static extractAttribute(xml: string, attributeName: string): string | undefined {\n // Use simple indexOf for bounded string search (safe)\n const attrPattern = `${attributeName}=\"`;\n const startIdx = xml.indexOf(attrPattern);\n if (startIdx === -1) return undefined;\n\n const valueStart = startIdx + attrPattern.length;\n const valueEnd = xml.indexOf('\"', valueStart);\n if (valueEnd === -1) return undefined;\n\n const rawValue = xml.substring(valueStart, valueEnd);\n // Unescape XML entities to get the actual value\n // This prevents double-escaping when the value is later re-serialized\n return XMLBuilder.unescapeXml(rawValue);\n }\n\n /**\n * Checks if an XML string contains a self-closing tag\n * @param xml - XML content\n * @param tagName - Tag name to check\n * @returns True if the tag exists as self-closing\n */\n static hasSelfClosingTag(xml: string, tagName: string): boolean {\n return xml.includes(`<${tagName}/>`) || xml.includes(`<${tagName} `);\n }\n\n /**\n * Checks if a boolean property tag is enabled (w:val=\"1\" or w:val=\"true\")\n * Per ECMA-376, boolean properties can be:\n * - Present with w:val=\"1\" or w:val=\"true\" (enabled)\n * - Present with w:val=\"0\" or w:val=\"false\" (explicitly disabled)\n * - Absent (disabled by default)\n *\n * @param xml - XML content to search\n * @param tagName - Tag name (e.g., 'w:keepNext')\n * @returns True if tag exists with w:val=\"1\" or w:val=\"true\", false otherwise\n *\n * @example\n * hasBooleanProperty('<w:pPr><w:keepNext w:val=\"1\"/></w:pPr>', 'w:keepNext'); // true\n * hasBooleanProperty('<w:pPr><w:keepNext w:val=\"0\"/></w:pPr>', 'w:keepNext'); // false\n * hasBooleanProperty('<w:pPr><w:spacing/></w:pPr>', 'w:keepNext'); // false\n */\n static hasBooleanProperty(xml: string, tagName: string): boolean {\n // Check for tag with w:val=\"1\" or w:val=\"true\"\n if (xml.includes(`<${tagName} w:val=\"1\"`) || xml.includes(`<${tagName} w:val=\"true\"`)) {\n return true;\n }\n\n // Check for self-closing tag without w:val attribute (means true per ECMA-376)\n // Example: <w:b/> means bold=true\n if (xml.includes(`<${tagName}/>`)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Extracts text content from within tags\n * Finds all <w:t>...</w:t> tags and extracts their text\n * @param xml - XML content\n * @returns Combined text content\n */\n static extractText(xml: string): string {\n const texts: string[] = [];\n const openTag = '<w:t';\n const closeTag = '</w:t>';\n\n let pos = 0;\n while (pos < xml.length) {\n const startIdx = xml.indexOf(openTag, pos);\n if (startIdx === -1) break;\n\n // Find the end of opening tag\n const openEnd = xml.indexOf('>', startIdx);\n if (openEnd === -1) break;\n\n // Find closing tag\n const closeIdx = xml.indexOf(closeTag, openEnd);\n if (closeIdx === -1) break;\n\n // Extract text between tags\n const text = xml.substring(openEnd + 1, closeIdx);\n texts.push(text);\n\n pos = closeIdx + closeTag.length;\n }\n\n return texts.join('');\n }\n\n /**\n * Validates input size to prevent excessive memory usage\n * @param xml - XML content\n * @param maxSize - Maximum size in bytes (default: 10MB)\n * @throws Error if XML exceeds max size\n */\n static validateSize(xml: string, maxSize: number = 10 * 1024 * 1024): void {\n if (xml.length > maxSize) {\n throw new Error(\n `XML content too large for parsing (${(xml.length / 1024 / 1024).toFixed(1)}MB). ` +\n `Maximum allowed: ${(maxSize / 1024 / 1024).toFixed(0)}MB`\n );\n }\n }\n\n /**\n * Extracts content between two specific tags\n * More efficient than regex for large documents\n * @param xml - XML content\n * @param startTag - Opening tag (e.g., '<w:pPr')\n * @param endTag - Closing tag (e.g., '</w:pPr>')\n * @returns Content between tags, or undefined if not found\n */\n static extractBetweenTags(xml: string, startTag: string, endTag: string): string | undefined {\n const startIdx = xml.indexOf(startTag);\n if (startIdx === -1) return undefined;\n\n // Find the end of the opening tag\n const openEnd = xml.indexOf('>', startIdx);\n if (openEnd === -1) return undefined;\n\n // Find the closing tag\n const endIdx = xml.indexOf(endTag, openEnd);\n if (endIdx === -1) return undefined;\n\n return xml.substring(openEnd + 1, endIdx);\n }\n\n /**\n * Extracts a complete self-closing tag with its attributes\n * Handles cases where multiple similar tags exist (e.g., <w:sz.../> and <w:szCs.../>)\n *\n * @param xml - XML string to search\n * @param tagName - Tag name to find (e.g., \"w:color\", \"w:sz\")\n * @returns The complete tag content (attributes portion) or undefined if not found\n *\n * @example\n * const xml = '<w:sz w:val=\"36\"/><w:color w:val=\"FF0000\"/>';\n * const colorTag = XMLParser.extractSelfClosingTag(xml, 'w:color');\n * // Returns: ' w:val=\"FF0000\"'\n */\n static extractSelfClosingTag(xml: string, tagName: string): string | undefined {\n const startPattern = `<${tagName}`;\n let searchPos = 0;\n\n // Search for the exact tag (not tags that start with this pattern)\n while (true) {\n const startIdx = xml.indexOf(startPattern, searchPos);\n if (startIdx === -1) return undefined;\n\n // Check what character follows the tag name\n const charAfterTag = xml[startIdx + startPattern.length];\n\n // Valid separators after tag name: space, '/', or '>'\n if (charAfterTag === ' ' || charAfterTag === '/' || charAfterTag === '>') {\n // Found the exact tag, now find its end\n const endIdx = xml.indexOf('/>', startIdx);\n if (endIdx === -1) {\n // Try finding a closing tag instead (non-self-closing)\n const closeTagStart = xml.indexOf('>', startIdx);\n if (closeTagStart === -1) return undefined;\n\n // Return attributes portion\n return xml.substring(startIdx + startPattern.length, closeTagStart);\n }\n\n // Return attributes portion (between tag name and />)\n return xml.substring(startIdx + startPattern.length, endIdx);\n }\n\n // Not the exact tag (e.g., found \"w:sz\" when looking for \"w:s\")\n // Continue searching\n searchPos = startIdx + 1;\n }\n }\n\n /**\n * Parse XML string to JavaScript object\n * Compatible with fast-xml-parser output format\n *\n * @param xml - XML string to parse\n * @param options - Parsing options\n * @returns Parsed JavaScript object\n *\n * @example\n * const xml = '<Relationships><Relationship Id=\"rId1\" Target=\"https://example.com\"/></Relationships>';\n * const obj = XMLParser.parseToObject(xml);\n * // Returns: { Relationships: { Relationship: { '@_Id': 'rId1', '@_Target': 'https://example.com' } } }\n *\n * @example\n * // Multiple elements become arrays\n * const xml = '<Items><Item id=\"1\"/><Item id=\"2\"/></Items>';\n * const obj = XMLParser.parseToObject(xml);\n * // Returns: { Items: { Item: [{ '@_id': '1' }, { '@_id': '2' }] } }\n */\n static parseToObject(xml: string, options?: ParseToObjectOptions): ParsedXMLObject {\n const logger = getLogger();\n logger.debug('Parsing XML to object', { xmlSize: xml.length });\n\n // Default options\n const opts: Required<ParseToObjectOptions> = {\n ignoreAttributes: options?.ignoreAttributes ?? false,\n attributeNamePrefix: options?.attributeNamePrefix ?? '@_',\n textNodeName: options?.textNodeName ?? '#text',\n ignoreNamespace: options?.ignoreNamespace ?? false,\n parseAttributeValue: options?.parseAttributeValue ?? true,\n trimValues: options?.trimValues ?? true,\n alwaysArray: options?.alwaysArray ?? false,\n maxNestingDepth: options?.maxNestingDepth ?? DEFAULT_MAX_NESTING_DEPTH,\n };\n\n // Validate input size\n XMLParser.validateSize(xml);\n\n // Remove XML declaration and trim\n xml = xml.replace(/<\\?xml[^>]*\\?>\\s*/g, '').trim();\n\n if (!xml) {\n return {};\n }\n\n // Parse root element (start at depth 0)\n const result = XMLParser.parseElementToObject(xml, 0, opts, 0);\n logger.debug('XML parsed to object');\n return result.value as ParsedXMLObject;\n }\n\n /**\n * Parses a single XML element into an object\n * @private\n */\n private static parseElementToObject(\n xml: string,\n startPos: number,\n options: Required<ParseToObjectOptions>,\n depth: number\n ): { value: ParsedXMLValue; endPos: number } {\n // Check nesting depth to prevent stack overflow\n if (depth > options.maxNestingDepth) {\n throw new Error(\n `XML nesting depth exceeds maximum of ${options.maxNestingDepth}. ` +\n `This may indicate malformed XML or an attack attempt. ` +\n `Use the maxNestingDepth option to increase the limit if needed.`\n );\n }\n\n // Find opening tag\n const openTagStart = xml.indexOf('<', startPos);\n if (openTagStart === -1) {\n return { value: {}, endPos: xml.length };\n }\n\n // Skip comments\n if (xml.substring(openTagStart, openTagStart + 4) === '<!--') {\n const commentEnd = xml.indexOf('-->', openTagStart + 4);\n if (commentEnd !== -1) {\n return XMLParser.parseElementToObject(xml, commentEnd + 3, options, depth);\n }\n return { value: {}, endPos: xml.length };\n }\n\n // Extract element name\n const nameMatch = /^([a-zA-Z0-9:_-]+)/.exec(xml.substring(openTagStart + 1));\n if (!nameMatch) {\n return { value: {}, endPos: openTagStart + 1 };\n }\n\n const originalElementName: string = nameMatch[1] || '';\n let elementName: string = originalElementName;\n const tagHeaderEnd = xml.indexOf('>', openTagStart);\n if (tagHeaderEnd === -1) {\n return { value: {}, endPos: xml.length };\n }\n\n // Remove namespace if requested (but keep original for offset calculations)\n if (options.ignoreNamespace && elementName.includes(':')) {\n elementName = elementName.split(':')[1] || elementName;\n }\n\n // Extract attributes using ORIGINAL element name length for correct offset\n const tagHeader = xml.substring(openTagStart + 1 + originalElementName.length, tagHeaderEnd);\n const attributes = XMLParser.extractAttributesFromTag(tagHeader, options);\n\n // Check if self-closing\n const isSelfClosing = tagHeader.trim().endsWith('/') || xml[tagHeaderEnd - 1] === '/';\n\n if (isSelfClosing) {\n // Self-closing tag - return object with attributes only\n const elementValue: ParsedXMLObject = { ...attributes };\n return {\n value: { [elementName]: elementValue },\n endPos: tagHeaderEnd + 1,\n };\n }\n\n // Find closing tag (use original name with namespace for correct matching)\n const closingTag = `</${originalElementName}>`;\n const contentStart = tagHeaderEnd + 1;\n const closingTagPos = XMLParser.findClosingTag(xml, originalElementName, contentStart);\n\n if (closingTagPos === -1) {\n // No closing tag found - treat as self-closing\n return {\n value: { [elementName]: { ...attributes } },\n endPos: tagHeaderEnd + 1,\n };\n }\n\n // Extract content between tags\n const content = xml.substring(contentStart, closingTagPos);\n\n // Parse content (children or text)\n const children: ParsedElement[] = [];\n let textContent = '';\n let pos = 0;\n\n while (pos < content.length) {\n const nextTag = content.indexOf('<', pos);\n\n if (nextTag === -1) {\n // No more tags - rest is text\n const text = content.substring(pos);\n // When trimValues is false, preserve whitespace-only text\n // When trimValues is true, only include text that has non-whitespace content\n if (text.length > 0 && (!options.trimValues || text.trim())) {\n // Unescape XML entities in text content (e.g., &lt; -> <)\n textContent += XMLBuilder.unescapeXml(text);\n }\n break;\n }\n\n // Collect text before next tag\n if (nextTag > pos) {\n const text = content.substring(pos, nextTag);\n // When trimValues is false, preserve whitespace-only text\n // When trimValues is true, only include text that has non-whitespace content\n if (text.length > 0 && (!options.trimValues || text.trim())) {\n // Unescape XML entities in text content (e.g., &lt; -> <)\n textContent += XMLBuilder.unescapeXml(text);\n }\n }\n\n // Parse child element (increment depth for children)\n const childResult = XMLParser.parseElementToObject(content, nextTag, options, depth + 1);\n const childObj = childResult.value as ParsedXMLObject;\n\n // Extract child name and value\n const childKeys = Object.keys(childObj);\n if (childKeys.length > 0) {\n const childName = childKeys[0];\n if (childName) {\n const childValue = childObj[childName];\n children.push({ name: childName, value: childValue });\n }\n }\n\n pos = childResult.endPos;\n }\n\n // Build element value\n let elementValue: ParsedXMLValue = {};\n\n // Add attributes\n if (!options.ignoreAttributes && Object.keys(attributes).length > 0) {\n elementValue = { ...attributes };\n }\n\n // Add text content\n // When trimValues is false, include whitespace-only text\n // When trimValues is true, only include text with non-whitespace content\n if (textContent.length > 0 && (!options.trimValues || textContent.trim())) {\n const text = options.trimValues ? textContent.trim() : textContent;\n if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {\n if (Object.keys(elementValue).length === 0) {\n // Only text, no attributes - return as direct value if simple\n elementValue = text;\n } else {\n // Text with attributes\n elementValue[options.textNodeName] = text;\n }\n }\n }\n\n // Add children\n if (children.length > 0) {\n const coalescedChildren = XMLParser.coalesceChildren(children, options);\n if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {\n elementValue = { ...elementValue, ...coalescedChildren };\n } else {\n elementValue = coalescedChildren;\n }\n }\n\n // If element has no content, attributes, or children - return empty object\n if (\n typeof elementValue === 'object' &&\n !Array.isArray(elementValue) &&\n Object.keys(elementValue).length === 0\n ) {\n elementValue = {};\n }\n\n return {\n value: { [elementName]: elementValue },\n endPos: closingTagPos + closingTag.length,\n };\n }\n\n /**\n * Extracts attributes from a tag header\n * @private\n */\n private static extractAttributesFromTag(\n tagHeader: string,\n options: Required<ParseToObjectOptions>\n ): Record<string, string | number | boolean> {\n const attributes: Record<string, string | number | boolean> = {};\n\n if (options.ignoreAttributes) {\n return attributes;\n }\n\n // Simple attribute extraction using position-based parsing\n let pos = 0;\n while (pos < tagHeader.length) {\n // Skip whitespace\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /\\s/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n if (pos >= tagHeader.length || tagHeader[pos] === '/') {\n break;\n }\n\n // Extract attribute name\n const nameStart = pos;\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /[a-zA-Z0-9:_-]/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n if (pos === nameStart) {\n break;\n }\n\n let attrName = tagHeader.substring(nameStart, pos);\n\n // Skip whitespace and '='\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /[\\s=]/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n // Extract attribute value\n let attrValue = '';\n if (pos < tagHeader.length && (tagHeader[pos] === '\"' || tagHeader[pos] === \"'\")) {\n const quote = tagHeader[pos];\n pos++; // Skip opening quote\n const valueStart = pos;\n\n while (pos < tagHeader.length && tagHeader[pos] !== quote) {\n pos++;\n }\n\n attrValue = tagHeader.substring(valueStart, pos);\n pos++; // Skip closing quote\n }\n\n // Remove namespace from attribute name if requested\n if (options.ignoreNamespace && attrName.includes(':')) {\n attrName = attrName.split(':')[1] || attrName;\n }\n\n // Add prefix to attribute name\n const prefixedName = options.attributeNamePrefix + attrName;\n\n // Parse attribute value\n attributes[prefixedName] = options.parseAttributeValue\n ? XMLParser.parseValue(attrValue)\n : attrValue;\n }\n\n return attributes;\n }\n\n /**\n * Finds the closing tag for an element, handling nesting\n * @private\n */\n private static findClosingTag(xml: string, elementName: string, startPos: number): number {\n const openTag = `<${elementName}`;\n const closeTag = `</${elementName}>`;\n let depth = 1;\n let pos = startPos;\n\n while (depth > 0 && pos < xml.length) {\n const nextClose = xml.indexOf(closeTag, pos);\n\n if (nextClose === -1) {\n return -1; // No closing tag found\n }\n\n // Find the next REAL opening tag (not a prefix match like <w:pPrChange for <w:pPr)\n // Must search for all potential matches and verify each one\n let realOpenPos = -1;\n let searchPos = pos;\n while (searchPos < nextClose) {\n const candidateOpen = xml.indexOf(openTag, searchPos);\n if (candidateOpen === -1 || candidateOpen >= nextClose) {\n break; // No more candidates before the closing tag\n }\n\n const charAfter = xml[candidateOpen + openTag.length];\n if (\n charAfter === '>' ||\n charAfter === ' ' ||\n charAfter === '/' ||\n charAfter === '\\t' ||\n charAfter === '\\n' ||\n charAfter === '\\r'\n ) {\n // This looks like a real opening tag - but check if it's self-closing\n // Self-closing tags like <w:rPr/> should NOT increase depth\n const tagEnd = xml.indexOf('>', candidateOpen);\n if (tagEnd !== -1 && xml[tagEnd - 1] === '/') {\n // Self-closing tag - skip it (don't affect depth)\n searchPos = tagEnd + 1;\n continue;\n }\n // This is a real opening tag (not self-closing)\n realOpenPos = candidateOpen;\n break;\n }\n\n // False positive (e.g., <w:pPrChange when looking for <w:pPr)\n // Keep searching from after this position\n searchPos = candidateOpen + openTag.length;\n }\n\n if (realOpenPos !== -1) {\n // Found a real opening tag before the closing tag - increase depth\n depth++;\n pos = realOpenPos + openTag.length;\n } else {\n // No real opening tag before this closing tag - decrease depth\n depth--;\n if (depth === 0) {\n return nextClose;\n }\n pos = nextClose + closeTag.length;\n }\n }\n\n return -1;\n }\n\n /**\n * Coalesces children with duplicate names into arrays\n * @private\n */\n private static coalesceChildren(\n children: ParsedElement[],\n options: Required<ParseToObjectOptions>\n ): ParsedXMLObject {\n const result: ParsedXMLObject = {};\n const nameCounts: Record<string, number> = {};\n const nameIndices: Record<string, number> = {};\n\n // Track element order for correct run content parsing (tabs, breaks, text)\n // This is critical for preserving the order of mixed content like: text -> tab -> text\n const orderedChildren: { type: string; index: number }[] = [];\n\n // Count occurrences of each child name\n for (const child of children) {\n nameCounts[child.name] = (nameCounts[child.name] || 0) + 1;\n }\n\n // Build result object while tracking order\n for (const child of children) {\n const shouldBeArray = options.alwaysArray || (nameCounts[child.name] || 0) > 1;\n\n // Track element order with its index in the array\n const currentIndex = nameIndices[child.name] || 0;\n orderedChildren.push({ type: child.name, index: currentIndex });\n nameIndices[child.name] = currentIndex + 1;\n\n if (shouldBeArray) {\n if (!result[child.name]) {\n result[child.name] = [];\n }\n (result[child.name] as ParsedXMLValue[]).push(child.value);\n } else {\n result[child.name] = child.value;\n }\n }\n\n // Add _orderedChildren to track element order (used by DocumentParser for runs)\n if (orderedChildren.length > 0) {\n result._orderedChildren = orderedChildren;\n }\n\n return result;\n }\n\n /**\n * Parses a string value to number or boolean if applicable\n * @private\n */\n private static parseValue(value: string): string | number | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // Preserve 6-character hex color codes (OpenXML standard for colors)\n // This includes \"000000\" (black) which should stay as a string\n if (/^[0-9A-Fa-f]{6}$/.test(value)) {\n return value.toUpperCase(); // Normalize to uppercase per Microsoft convention\n }\n\n // Preserve long digit-only strings (e.g., cnfStyle binary strings like \"100000000000\")\n // These should not be converted to numbers to avoid losing leading zeros\n if (/^\\d{7,}$/.test(value)) {\n return value; // Keep as string for values with 7+ digits\n }\n\n // Try parsing as number\n // 3-character values like \"240\" will be parsed as numbers\n // 6-character hex values are already handled above\n if (/^-?\\d+$/.test(value)) {\n const num = parseInt(value, 10);\n if (!isNaN(num)) return num;\n }\n\n if (/^-?\\d+\\.\\d+$/.test(value)) {\n const num = parseFloat(value);\n if (!isNaN(num)) return num;\n }\n\n // Preserve 3-character hex codes (like \"F0A\") that have letters\n // Pure numeric 3-char values (like \"240\") are already parsed as numbers above\n if (/^[0-9A-Fa-f]{3}$/.test(value) && /[A-Fa-f]/.test(value)) {\n return value.toUpperCase();\n }\n\n return value;\n }\n}\n"]}
1
+ {"version":3,"file":"XMLParser.js","sourceRoot":"","sources":["../../../src/xml/XMLParser.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * XMLParser - Simple position-based XML parser\n * Avoids regex backtracking issues that can cause ReDoS attacks\n * Completes the DocXML framework (XMLBuilder + XMLParser)\n */\n\nimport { getGlobalLogger, createScopedLogger, ILogger } from '../utils/logger.js';\nimport { XMLBuilder } from './XMLBuilder.js';\n\n// Create scoped logger for XMLParser operations\nfunction getLogger(): ILogger {\n return createScopedLogger(getGlobalLogger(), 'XMLParser');\n}\n\n/**\n * Default maximum nesting depth for XML parsing.\n * Prevents stack overflow on deeply nested documents.\n */\nexport const DEFAULT_MAX_NESTING_DEPTH = 256;\n\n/**\n * Options for XML-to-object parsing\n */\nexport interface ParseToObjectOptions {\n /** Ignore attributes (default: false) */\n ignoreAttributes?: boolean;\n\n /** Attribute name prefix (default: '@_') */\n attributeNamePrefix?: string;\n\n /** Text node property name (default: '#text') */\n textNodeName?: string;\n\n /** Remove namespace prefixes from element names (default: false) */\n ignoreNamespace?: boolean;\n\n /** Parse numeric attribute values (default: true) */\n parseAttributeValue?: boolean;\n\n /** Trim whitespace from text values (default: true) */\n trimValues?: boolean;\n\n /** Always return arrays for elements (default: false) */\n alwaysArray?: boolean;\n\n /** Maximum nesting depth (default: 256). Prevents stack overflow on deeply nested documents. */\n maxNestingDepth?: number;\n}\n\n/**\n * Parsed XML object structure\n * Can be a string, object, array, or nested structure\n */\nexport type ParsedXMLValue =\n | string\n | number\n | boolean\n | ParsedXMLObject\n | ParsedXMLObject[]\n | null\n | undefined;\n\n/**\n * Parsed XML object with dynamic keys\n */\nexport interface ParsedXMLObject {\n [key: string]: ParsedXMLValue;\n}\n\n/**\n * Internal structure for tracking parsed elements during parsing\n */\ninterface ParsedElement {\n name: string;\n value: ParsedXMLValue;\n}\n\n/**\n * Simple XML parser using position-based parsing instead of regex\n * Prevents catastrophic backtracking (ReDoS attacks) by avoiding nested regex patterns\n */\nexport class XMLParser {\n /**\n * Extracts the body content from a Word document XML\n * @param docXml - The complete document.xml content\n * @returns The body content, or empty string if not found\n */\n static extractBody(docXml: string): string {\n const startTag = '<w:body';\n const endTag = '</w:body>';\n\n const startIdx = docXml.indexOf(startTag);\n if (startIdx === -1) return '';\n\n // Find the closing > of opening tag\n const openEnd = docXml.indexOf('>', startIdx);\n if (openEnd === -1) return '';\n\n // Find matching closing tag\n const endIdx = docXml.indexOf(endTag, openEnd);\n if (endIdx === -1) return '';\n\n return docXml.substring(openEnd + 1, endIdx);\n }\n\n /**\n * Extracts all elements of a given type using position-based parsing\n * Handles nested tags correctly by tracking depth\n * @param xml - XML content to parse\n * @param tagName - Tag name to extract (e.g., 'w:p', 'w:r')\n * @returns Array of XML strings for each element\n */\n static extractElements(xml: string, tagName: string): string[] {\n const elements: string[] = [];\n const openTag = `<${tagName}`;\n const closeTag = `</${tagName}>`;\n const selfClosingEnd = '/>';\n\n let pos = 0;\n while (pos < xml.length) {\n const startIdx = xml.indexOf(openTag, pos);\n if (startIdx === -1) break;\n\n // Verify this is the exact tag (not a prefix match like <w:p matching <w:pPr>)\n // The character after the tag name must be either '>', '/', whitespace, or '=' (for attributes)\n const charAfterTag = xml[startIdx + openTag.length];\n if (\n charAfterTag &&\n charAfterTag !== '>' &&\n charAfterTag !== '/' &&\n charAfterTag !== ' ' &&\n charAfterTag !== '\\t' &&\n charAfterTag !== '\\n' &&\n charAfterTag !== '\\r' &&\n charAfterTag !== '='\n ) {\n // This is a prefix match (e.g., <w:pPr> when looking for <w:p>), skip it (Issue #5)\n pos = startIdx + openTag.length;\n continue;\n }\n\n // Find the end of opening tag (quote-aware: attribute values may\n // legally contain a raw '>')\n const openEnd = XMLParser.findTagEnd(xml, startIdx);\n if (openEnd === -1) break;\n\n // Check if self-closing\n if (xml.substring(openEnd - 1, openEnd + 1) === selfClosingEnd) {\n elements.push(xml.substring(startIdx, openEnd + 1));\n pos = openEnd + 1;\n continue;\n }\n\n // Find matching closing tag (handle nesting)\n let depth = 1;\n let searchPos = openEnd + 1;\n\n while (depth > 0 && searchPos < xml.length) {\n // Find next potential opening tag\n let nextOpen = -1;\n let openSearchPos = searchPos;\n while (true) {\n const candidateOpen = xml.indexOf(openTag, openSearchPos);\n if (candidateOpen === -1) {\n break;\n }\n // Verify it's an exact match (not a prefix)\n const charAfter = xml[candidateOpen + openTag.length];\n if (\n charAfter &&\n charAfter !== '>' &&\n charAfter !== '/' &&\n charAfter !== ' ' &&\n charAfter !== '\\t' &&\n charAfter !== '\\n' &&\n charAfter !== '\\r'\n ) {\n // Prefix match, keep searching\n openSearchPos = candidateOpen + openTag.length;\n continue;\n }\n nextOpen = candidateOpen;\n break;\n }\n\n const nextClose = xml.indexOf(closeTag, searchPos);\n\n if (nextClose === -1) break;\n\n if (nextOpen !== -1 && nextOpen < nextClose) {\n depth++;\n searchPos = nextOpen + openTag.length;\n } else {\n depth--;\n if (depth === 0) {\n elements.push(xml.substring(startIdx, nextClose + closeTag.length));\n pos = nextClose + closeTag.length;\n } else {\n searchPos = nextClose + closeTag.length;\n }\n }\n }\n\n if (depth > 0) {\n // Unclosed tag - skip it\n pos = startIdx + openTag.length;\n }\n }\n\n return elements;\n }\n\n /**\n * Extracts attribute value from an XML string\n * @param xml - XML content\n * @param attributeName - Attribute name (e.g., 'w:val')\n * @returns Attribute value or undefined\n */\n static extractAttribute(xml: string, attributeName: string): string | undefined {\n // Use simple indexOf for bounded string search (safe)\n const attrPattern = `${attributeName}=\"`;\n const startIdx = xml.indexOf(attrPattern);\n if (startIdx === -1) return undefined;\n\n const valueStart = startIdx + attrPattern.length;\n const valueEnd = xml.indexOf('\"', valueStart);\n if (valueEnd === -1) return undefined;\n\n const rawValue = xml.substring(valueStart, valueEnd);\n // Unescape XML entities to get the actual value\n // This prevents double-escaping when the value is later re-serialized\n return XMLBuilder.unescapeXml(rawValue);\n }\n\n /**\n * Checks if an XML string contains a self-closing tag\n * @param xml - XML content\n * @param tagName - Tag name to check\n * @returns True if the tag exists as self-closing\n */\n static hasSelfClosingTag(xml: string, tagName: string): boolean {\n return xml.includes(`<${tagName}/>`) || xml.includes(`<${tagName} `);\n }\n\n /**\n * Checks if a boolean property tag is enabled (w:val=\"1\" or w:val=\"true\")\n * Per ECMA-376, boolean properties can be:\n * - Present with w:val=\"1\" or w:val=\"true\" (enabled)\n * - Present with w:val=\"0\" or w:val=\"false\" (explicitly disabled)\n * - Absent (disabled by default)\n *\n * @param xml - XML content to search\n * @param tagName - Tag name (e.g., 'w:keepNext')\n * @returns True if tag exists with w:val=\"1\" or w:val=\"true\", false otherwise\n *\n * @example\n * hasBooleanProperty('<w:pPr><w:keepNext w:val=\"1\"/></w:pPr>', 'w:keepNext'); // true\n * hasBooleanProperty('<w:pPr><w:keepNext w:val=\"0\"/></w:pPr>', 'w:keepNext'); // false\n * hasBooleanProperty('<w:pPr><w:spacing/></w:pPr>', 'w:keepNext'); // false\n */\n static hasBooleanProperty(xml: string, tagName: string): boolean {\n // Check for tag with w:val=\"1\" or w:val=\"true\"\n if (xml.includes(`<${tagName} w:val=\"1\"`) || xml.includes(`<${tagName} w:val=\"true\"`)) {\n return true;\n }\n\n // Check for self-closing tag without w:val attribute (means true per ECMA-376)\n // Example: <w:b/> means bold=true\n if (xml.includes(`<${tagName}/>`)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Extracts text content from within tags\n * Finds all <w:t>...</w:t> tags and extracts their text\n * @param xml - XML content\n * @returns Combined text content\n */\n static extractText(xml: string): string {\n const texts: string[] = [];\n const openTag = '<w:t';\n const closeTag = '</w:t>';\n\n let pos = 0;\n while (pos < xml.length) {\n const startIdx = xml.indexOf(openTag, pos);\n if (startIdx === -1) break;\n\n // Find the end of opening tag\n const openEnd = xml.indexOf('>', startIdx);\n if (openEnd === -1) break;\n\n // Find closing tag\n const closeIdx = xml.indexOf(closeTag, openEnd);\n if (closeIdx === -1) break;\n\n // Extract text between tags\n const text = xml.substring(openEnd + 1, closeIdx);\n texts.push(text);\n\n pos = closeIdx + closeTag.length;\n }\n\n return texts.join('');\n }\n\n /**\n * Validates input size to prevent excessive memory usage\n * @param xml - XML content\n * @param maxSize - Maximum size in bytes (default: 10MB)\n * @throws Error if XML exceeds max size\n */\n static validateSize(xml: string, maxSize: number = 10 * 1024 * 1024): void {\n if (xml.length > maxSize) {\n throw new Error(\n `XML content too large for parsing (${(xml.length / 1024 / 1024).toFixed(1)}MB). ` +\n `Maximum allowed: ${(maxSize / 1024 / 1024).toFixed(0)}MB`\n );\n }\n }\n\n /**\n * Extracts content between two specific tags\n * More efficient than regex for large documents\n * @param xml - XML content\n * @param startTag - Opening tag (e.g., '<w:pPr')\n * @param endTag - Closing tag (e.g., '</w:pPr>')\n * @returns Content between tags, or undefined if not found\n */\n static extractBetweenTags(xml: string, startTag: string, endTag: string): string | undefined {\n const startIdx = xml.indexOf(startTag);\n if (startIdx === -1) return undefined;\n\n // Find the end of the opening tag (quote-aware: attribute values may\n // legally contain a raw '>')\n const openEnd = XMLParser.findTagEnd(xml, startIdx);\n if (openEnd === -1) return undefined;\n\n // Find the closing tag\n const endIdx = xml.indexOf(endTag, openEnd);\n if (endIdx === -1) return undefined;\n\n return xml.substring(openEnd + 1, endIdx);\n }\n\n /**\n * Finds the first '>' at or after startPos that is not inside a quoted\n * attribute value. XML 1.0 §2.3 permits a raw '>' inside attribute values\n * (only '<', '&', and the delimiting quote must be escaped), so a bare\n * indexOf('>') can end a tag header mid-attribute.\n * @private\n */\n private static findTagEnd(xml: string, startPos: number): number {\n let quote: string | undefined;\n for (let pos = startPos; pos < xml.length; pos++) {\n const ch = xml[pos];\n if (quote) {\n if (ch === quote) quote = undefined;\n } else if (ch === '\"' || ch === \"'\") {\n quote = ch;\n } else if (ch === '>') {\n return pos;\n }\n }\n return -1;\n }\n\n /**\n * Extracts a complete self-closing tag with its attributes\n * Handles cases where multiple similar tags exist (e.g., <w:sz.../> and <w:szCs.../>)\n *\n * @param xml - XML string to search\n * @param tagName - Tag name to find (e.g., \"w:color\", \"w:sz\")\n * @returns The complete tag content (attributes portion) or undefined if not found\n *\n * @example\n * const xml = '<w:sz w:val=\"36\"/><w:color w:val=\"FF0000\"/>';\n * const colorTag = XMLParser.extractSelfClosingTag(xml, 'w:color');\n * // Returns: ' w:val=\"FF0000\"'\n */\n static extractSelfClosingTag(xml: string, tagName: string): string | undefined {\n const startPattern = `<${tagName}`;\n let searchPos = 0;\n\n // Search for the exact tag (not tags that start with this pattern)\n while (true) {\n const startIdx = xml.indexOf(startPattern, searchPos);\n if (startIdx === -1) return undefined;\n\n // Check what character follows the tag name\n const charAfterTag = xml[startIdx + startPattern.length];\n\n // Valid separators after tag name: space, '/', or '>'\n if (charAfterTag === ' ' || charAfterTag === '/' || charAfterTag === '>') {\n // Found the exact tag. Bound the search to this element's own tag\n // header: a global indexOf('/>') can land inside a later sibling\n // when the target is written in expanded form (<tag ...></tag>),\n // attributing the sibling's attributes to this tag.\n const tagEnd = XMLParser.findTagEnd(xml, startIdx + startPattern.length);\n if (tagEnd === -1) return undefined;\n\n // Self-closing: exclude the trailing '/'; expanded form: attributes\n // run up to the '>' of the open tag.\n const attrEnd = xml[tagEnd - 1] === '/' ? tagEnd - 1 : tagEnd;\n return xml.substring(startIdx + startPattern.length, attrEnd);\n }\n\n // Not the exact tag (e.g., found \"w:sz\" when looking for \"w:s\")\n // Continue searching\n searchPos = startIdx + 1;\n }\n }\n\n /**\n * Parse XML string to JavaScript object\n * Compatible with fast-xml-parser output format\n *\n * @param xml - XML string to parse\n * @param options - Parsing options\n * @returns Parsed JavaScript object\n *\n * @example\n * const xml = '<Relationships><Relationship Id=\"rId1\" Target=\"https://example.com\"/></Relationships>';\n * const obj = XMLParser.parseToObject(xml);\n * // Returns: { Relationships: { Relationship: { '@_Id': 'rId1', '@_Target': 'https://example.com' } } }\n *\n * @example\n * // Multiple elements become arrays\n * const xml = '<Items><Item id=\"1\"/><Item id=\"2\"/></Items>';\n * const obj = XMLParser.parseToObject(xml);\n * // Returns: { Items: { Item: [{ '@_id': '1' }, { '@_id': '2' }] } }\n */\n static parseToObject(xml: string, options?: ParseToObjectOptions): ParsedXMLObject {\n const logger = getLogger();\n logger.debug('Parsing XML to object', { xmlSize: xml.length });\n\n // Default options\n const opts: Required<ParseToObjectOptions> = {\n ignoreAttributes: options?.ignoreAttributes ?? false,\n attributeNamePrefix: options?.attributeNamePrefix ?? '@_',\n textNodeName: options?.textNodeName ?? '#text',\n ignoreNamespace: options?.ignoreNamespace ?? false,\n parseAttributeValue: options?.parseAttributeValue ?? true,\n trimValues: options?.trimValues ?? true,\n alwaysArray: options?.alwaysArray ?? false,\n maxNestingDepth: options?.maxNestingDepth ?? DEFAULT_MAX_NESTING_DEPTH,\n };\n\n // Validate input size\n XMLParser.validateSize(xml);\n\n // Remove XML declaration and trim\n xml = xml.replace(/<\\?xml[^>]*\\?>\\s*/g, '').trim();\n\n if (!xml) {\n return {};\n }\n\n // Parse root element (start at depth 0)\n const result = XMLParser.parseElementToObject(xml, 0, opts, 0);\n logger.debug('XML parsed to object');\n return result.value as ParsedXMLObject;\n }\n\n /**\n * Parses a single XML element into an object\n * @private\n */\n private static parseElementToObject(\n xml: string,\n startPos: number,\n options: Required<ParseToObjectOptions>,\n depth: number\n ): { value: ParsedXMLValue; endPos: number } {\n // Check nesting depth to prevent stack overflow\n if (depth > options.maxNestingDepth) {\n throw new Error(\n `XML nesting depth exceeds maximum of ${options.maxNestingDepth}. ` +\n `This may indicate malformed XML or an attack attempt. ` +\n `Use the maxNestingDepth option to increase the limit if needed.`\n );\n }\n\n // Find opening tag\n const openTagStart = xml.indexOf('<', startPos);\n if (openTagStart === -1) {\n return { value: {}, endPos: xml.length };\n }\n\n // Skip comments\n if (xml.substring(openTagStart, openTagStart + 4) === '<!--') {\n const commentEnd = xml.indexOf('-->', openTagStart + 4);\n if (commentEnd !== -1) {\n return XMLParser.parseElementToObject(xml, commentEnd + 3, options, depth);\n }\n return { value: {}, endPos: xml.length };\n }\n\n // Skip processing instructions (e.g. <?mso-application ...?>); without\n // this, '?' fails the element-name match and the PI body is mangled\n // into text one character at a time\n if (xml.substring(openTagStart, openTagStart + 2) === '<?') {\n const piEnd = xml.indexOf('?>', openTagStart + 2);\n if (piEnd !== -1) {\n return XMLParser.parseElementToObject(xml, piEnd + 2, options, depth);\n }\n return { value: {}, endPos: xml.length };\n }\n\n // Skip CDATA found where an element is expected (e.g. at the root);\n // CDATA inside element content is preserved by the content loop below\n if (xml.substring(openTagStart, openTagStart + 9) === '<![CDATA[') {\n const cdataEnd = xml.indexOf(']]>', openTagStart + 9);\n if (cdataEnd !== -1) {\n return XMLParser.parseElementToObject(xml, cdataEnd + 3, options, depth);\n }\n return { value: {}, endPos: xml.length };\n }\n\n // Extract element name\n const nameMatch = /^([a-zA-Z0-9:_-]+)/.exec(xml.substring(openTagStart + 1));\n if (!nameMatch) {\n return { value: {}, endPos: openTagStart + 1 };\n }\n\n const originalElementName: string = nameMatch[1] || '';\n let elementName: string = originalElementName;\n // Quote-aware scan: attribute values may legally contain a raw '>'\n const tagHeaderEnd = XMLParser.findTagEnd(xml, openTagStart);\n if (tagHeaderEnd === -1) {\n return { value: {}, endPos: xml.length };\n }\n\n // Remove namespace if requested (but keep original for offset calculations)\n if (options.ignoreNamespace && elementName.includes(':')) {\n elementName = elementName.split(':')[1] || elementName;\n }\n\n // Extract attributes using ORIGINAL element name length for correct offset\n const tagHeader = xml.substring(openTagStart + 1 + originalElementName.length, tagHeaderEnd);\n const attributes = XMLParser.extractAttributesFromTag(tagHeader, options);\n\n // Check if self-closing\n const isSelfClosing = tagHeader.trim().endsWith('/') || xml[tagHeaderEnd - 1] === '/';\n\n if (isSelfClosing) {\n // Self-closing tag - return object with attributes only\n const elementValue: ParsedXMLObject = { ...attributes };\n return {\n value: { [elementName]: elementValue },\n endPos: tagHeaderEnd + 1,\n };\n }\n\n // Find closing tag (use original name with namespace for correct matching)\n const closingTag = `</${originalElementName}>`;\n const contentStart = tagHeaderEnd + 1;\n const closingTagPos = XMLParser.findClosingTag(xml, originalElementName, contentStart);\n\n if (closingTagPos === -1) {\n // No closing tag found - treat as self-closing\n return {\n value: { [elementName]: { ...attributes } },\n endPos: tagHeaderEnd + 1,\n };\n }\n\n // Extract content between tags\n const content = xml.substring(contentStart, closingTagPos);\n\n // Parse content (children or text)\n const children: ParsedElement[] = [];\n let textContent = '';\n let pos = 0;\n\n while (pos < content.length) {\n const nextTag = content.indexOf('<', pos);\n\n if (nextTag === -1) {\n // No more tags - rest is text\n const text = content.substring(pos);\n // When trimValues is false, preserve whitespace-only text\n // When trimValues is true, only include text that has non-whitespace content\n if (text.length > 0 && (!options.trimValues || text.trim())) {\n // Unescape XML entities in text content (e.g., &lt; -> <)\n textContent += XMLBuilder.unescapeXml(text);\n }\n break;\n }\n\n // Collect text before next tag\n if (nextTag > pos) {\n const text = content.substring(pos, nextTag);\n // When trimValues is false, preserve whitespace-only text\n // When trimValues is true, only include text that has non-whitespace content\n if (text.length > 0 && (!options.trimValues || text.trim())) {\n // Unescape XML entities in text content (e.g., &lt; -> <)\n textContent += XMLBuilder.unescapeXml(text);\n }\n }\n\n // CDATA: append the payload verbatim — its content is by definition\n // already unescaped, so entity decoding must not be applied\n if (content.startsWith('<![CDATA[', nextTag)) {\n const cdataEnd = content.indexOf(']]>', nextTag + 9);\n if (cdataEnd === -1) {\n textContent += content.substring(nextTag + 9);\n break;\n }\n textContent += content.substring(nextTag + 9, cdataEnd);\n pos = cdataEnd + 3;\n continue;\n }\n\n // Parse child element (increment depth for children)\n const childResult = XMLParser.parseElementToObject(content, nextTag, options, depth + 1);\n const childObj = childResult.value as ParsedXMLObject;\n\n // Extract child name and value\n const childKeys = Object.keys(childObj);\n if (childKeys.length > 0) {\n const childName = childKeys[0];\n if (childName) {\n const childValue = childObj[childName];\n children.push({ name: childName, value: childValue });\n }\n }\n\n pos = childResult.endPos;\n }\n\n // Build element value\n let elementValue: ParsedXMLValue = {};\n\n // Add attributes\n if (!options.ignoreAttributes && Object.keys(attributes).length > 0) {\n elementValue = { ...attributes };\n }\n\n // Add text content\n // When trimValues is false, include whitespace-only text\n // When trimValues is true, only include text with non-whitespace content\n if (textContent.length > 0 && (!options.trimValues || textContent.trim())) {\n const text = options.trimValues ? textContent.trim() : textContent;\n if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {\n if (Object.keys(elementValue).length === 0) {\n // Only text, no attributes - return as direct value if simple\n elementValue = text;\n } else {\n // Text with attributes\n elementValue[options.textNodeName] = text;\n }\n }\n }\n\n // Add children\n if (children.length > 0) {\n const coalescedChildren = XMLParser.coalesceChildren(children, options);\n // Mixed content with no attributes leaves elementValue as a bare\n // string; fold it into object form so merging children keeps the text\n if (typeof elementValue === 'string') {\n elementValue = { [options.textNodeName]: elementValue };\n }\n if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {\n elementValue = { ...elementValue, ...coalescedChildren };\n } else {\n elementValue = coalescedChildren;\n }\n }\n\n // If element has no content, attributes, or children - return empty object\n if (\n typeof elementValue === 'object' &&\n !Array.isArray(elementValue) &&\n Object.keys(elementValue).length === 0\n ) {\n elementValue = {};\n }\n\n return {\n value: { [elementName]: elementValue },\n endPos: closingTagPos + closingTag.length,\n };\n }\n\n /**\n * Extracts attributes from a tag header\n * @private\n */\n private static extractAttributesFromTag(\n tagHeader: string,\n options: Required<ParseToObjectOptions>\n ): Record<string, string | number | boolean> {\n const attributes: Record<string, string | number | boolean> = {};\n\n if (options.ignoreAttributes) {\n return attributes;\n }\n\n // Simple attribute extraction using position-based parsing\n let pos = 0;\n while (pos < tagHeader.length) {\n // Skip whitespace\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /\\s/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n if (pos >= tagHeader.length || tagHeader[pos] === '/') {\n break;\n }\n\n // Extract attribute name\n const nameStart = pos;\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /[a-zA-Z0-9:_-]/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n if (pos === nameStart) {\n break;\n }\n\n let attrName = tagHeader.substring(nameStart, pos);\n\n // Skip whitespace and '='\n while (pos < tagHeader.length) {\n const char = tagHeader[pos];\n if (char && /[\\s=]/.test(char)) {\n pos++;\n } else {\n break;\n }\n }\n\n // Extract attribute value\n let attrValue = '';\n if (pos < tagHeader.length && (tagHeader[pos] === '\"' || tagHeader[pos] === \"'\")) {\n const quote = tagHeader[pos];\n pos++; // Skip opening quote\n const valueStart = pos;\n\n while (pos < tagHeader.length && tagHeader[pos] !== quote) {\n pos++;\n }\n\n attrValue = tagHeader.substring(valueStart, pos);\n pos++; // Skip closing quote\n }\n\n // Remove namespace from attribute name if requested\n if (options.ignoreNamespace && attrName.includes(':')) {\n attrName = attrName.split(':')[1] || attrName;\n }\n\n // Add prefix to attribute name\n const prefixedName = options.attributeNamePrefix + attrName;\n\n // Unescape XML entities so stored attribute values are the actual\n // decoded strings, matching text-node handling and extractAttribute.\n // This prevents double-escaping when the value is later re-serialized.\n const decodedValue = XMLBuilder.unescapeXml(attrValue);\n\n // Parse attribute value\n attributes[prefixedName] = options.parseAttributeValue\n ? XMLParser.parseValue(decodedValue)\n : decodedValue;\n }\n\n return attributes;\n }\n\n /**\n * Finds the closing tag for an element, handling nesting\n * @private\n */\n private static findClosingTag(xml: string, elementName: string, startPos: number): number {\n const openTag = `<${elementName}`;\n const closeTag = `</${elementName}>`;\n let depth = 1;\n let pos = startPos;\n\n while (depth > 0 && pos < xml.length) {\n const nextClose = xml.indexOf(closeTag, pos);\n\n if (nextClose === -1) {\n return -1; // No closing tag found\n }\n\n // Find the next REAL opening tag (not a prefix match like <w:pPrChange for <w:pPr)\n // Must search for all potential matches and verify each one\n let realOpenPos = -1;\n let searchPos = pos;\n while (searchPos < nextClose) {\n const candidateOpen = xml.indexOf(openTag, searchPos);\n if (candidateOpen === -1 || candidateOpen >= nextClose) {\n break; // No more candidates before the closing tag\n }\n\n const charAfter = xml[candidateOpen + openTag.length];\n if (\n charAfter === '>' ||\n charAfter === ' ' ||\n charAfter === '/' ||\n charAfter === '\\t' ||\n charAfter === '\\n' ||\n charAfter === '\\r'\n ) {\n // This looks like a real opening tag - but check if it's self-closing\n // Self-closing tags like <w:rPr/> should NOT increase depth\n const tagEnd = xml.indexOf('>', candidateOpen);\n if (tagEnd !== -1 && xml[tagEnd - 1] === '/') {\n // Self-closing tag - skip it (don't affect depth)\n searchPos = tagEnd + 1;\n continue;\n }\n // This is a real opening tag (not self-closing)\n realOpenPos = candidateOpen;\n break;\n }\n\n // False positive (e.g., <w:pPrChange when looking for <w:pPr)\n // Keep searching from after this position\n searchPos = candidateOpen + openTag.length;\n }\n\n if (realOpenPos !== -1) {\n // Found a real opening tag before the closing tag - increase depth\n depth++;\n pos = realOpenPos + openTag.length;\n } else {\n // No real opening tag before this closing tag - decrease depth\n depth--;\n if (depth === 0) {\n return nextClose;\n }\n pos = nextClose + closeTag.length;\n }\n }\n\n return -1;\n }\n\n /**\n * Coalesces children with duplicate names into arrays\n * @private\n */\n private static coalesceChildren(\n children: ParsedElement[],\n options: Required<ParseToObjectOptions>\n ): ParsedXMLObject {\n const result: ParsedXMLObject = {};\n const nameCounts: Record<string, number> = {};\n const nameIndices: Record<string, number> = {};\n\n // Track element order for correct run content parsing (tabs, breaks, text)\n // This is critical for preserving the order of mixed content like: text -> tab -> text\n const orderedChildren: { type: string; index: number }[] = [];\n\n // Count occurrences of each child name\n for (const child of children) {\n nameCounts[child.name] = (nameCounts[child.name] || 0) + 1;\n }\n\n // Build result object while tracking order\n for (const child of children) {\n const shouldBeArray = options.alwaysArray || (nameCounts[child.name] || 0) > 1;\n\n // Track element order with its index in the array\n const currentIndex = nameIndices[child.name] || 0;\n orderedChildren.push({ type: child.name, index: currentIndex });\n nameIndices[child.name] = currentIndex + 1;\n\n if (shouldBeArray) {\n if (!result[child.name]) {\n result[child.name] = [];\n }\n (result[child.name] as ParsedXMLValue[]).push(child.value);\n } else {\n result[child.name] = child.value;\n }\n }\n\n // Add _orderedChildren to track element order (used by DocumentParser for runs)\n if (orderedChildren.length > 0) {\n result._orderedChildren = orderedChildren;\n }\n\n return result;\n }\n\n /**\n * Parses a string value to number or boolean if applicable\n * @private\n */\n private static parseValue(value: string): string | number | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n\n // Preserve 6-character hex color codes (OpenXML standard for colors)\n // This includes \"000000\" (black) which should stay as a string\n if (/^[0-9A-Fa-f]{6}$/.test(value)) {\n return value.toUpperCase(); // Normalize to uppercase per Microsoft convention\n }\n\n // Preserve long digit-only strings (e.g., cnfStyle binary strings like \"100000000000\")\n // These should not be converted to numbers to avoid losing leading zeros\n if (/^\\d{7,}$/.test(value)) {\n return value; // Keep as string for values with 7+ digits\n }\n\n // Try parsing as number\n // 3-character values like \"240\" will be parsed as numbers\n // 6-character hex values are already handled above\n if (/^-?\\d+$/.test(value)) {\n const num = parseInt(value, 10);\n if (!isNaN(num)) return num;\n }\n\n if (/^-?\\d+\\.\\d+$/.test(value)) {\n const num = parseFloat(value);\n if (!isNaN(num)) return num;\n }\n\n // Preserve 3-character hex codes (like \"F0A\") that have letters\n // Pure numeric 3-char values (like \"240\") are already parsed as numbers above\n if (/^[0-9A-Fa-f]{3}$/.test(value) && /[A-Fa-f]/.test(value)) {\n return value.toUpperCase();\n }\n\n return value;\n }\n}\n"]}