docxmlater 11.0.10 → 12.1.0

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 (361) hide show
  1. package/README.md +53 -13
  2. package/dist/core/Document.d.ts +29 -3
  3. package/dist/core/Document.d.ts.map +1 -1
  4. package/dist/core/Document.js +733 -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 +427 -81
  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 +735 -172
  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 +427 -81
  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 +223 -39
  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/acceptRevisions.js +20 -11
  179. package/dist/esm/processors/acceptRevisions.js.map +1 -1
  180. package/dist/esm/processors/cnfStyleDecoder.js +7 -7
  181. package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
  182. package/dist/esm/processors/stripTrackedChanges.js +16 -5
  183. package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
  184. package/dist/esm/utils/deepClone.js +24 -11
  185. package/dist/esm/utils/deepClone.js.map +1 -1
  186. package/dist/esm/utils/units.js +1 -1
  187. package/dist/esm/utils/units.js.map +1 -1
  188. package/dist/esm/utils/validation.js +11 -23
  189. package/dist/esm/utils/validation.js.map +1 -1
  190. package/dist/esm/utils/xmlSanitization.js +131 -7
  191. package/dist/esm/utils/xmlSanitization.js.map +1 -1
  192. package/dist/esm/validation/RevisionAutoFixer.js +69 -55
  193. package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
  194. package/dist/esm/validation/RevisionValidator.js +24 -20
  195. package/dist/esm/validation/RevisionValidator.js.map +1 -1
  196. package/dist/esm/xml/XMLBuilder.js +52 -20
  197. package/dist/esm/xml/XMLBuilder.js.map +1 -1
  198. package/dist/esm/xml/XMLParser.js +55 -13
  199. package/dist/esm/xml/XMLParser.js.map +1 -1
  200. package/dist/esm/zip/ZipHandler.js +37 -13
  201. package/dist/esm/zip/ZipHandler.js.map +1 -1
  202. package/dist/esm/zip/ZipReader.js +53 -6
  203. package/dist/esm/zip/ZipReader.js.map +1 -1
  204. package/dist/esm/zip/errors.js +7 -0
  205. package/dist/esm/zip/errors.js.map +1 -1
  206. package/dist/esm/zip/types.js +4 -0
  207. package/dist/esm/zip/types.js.map +1 -1
  208. package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
  209. package/dist/formatting/AbstractNumbering.js +1 -1
  210. package/dist/formatting/AbstractNumbering.js.map +1 -1
  211. package/dist/formatting/NumberingLevel.d.ts +1 -1
  212. package/dist/formatting/NumberingLevel.d.ts.map +1 -1
  213. package/dist/formatting/NumberingLevel.js +8 -6
  214. package/dist/formatting/NumberingLevel.js.map +1 -1
  215. package/dist/formatting/NumberingManager.d.ts.map +1 -1
  216. package/dist/formatting/NumberingManager.js +16 -1
  217. package/dist/formatting/NumberingManager.js.map +1 -1
  218. package/dist/formatting/Style.d.ts.map +1 -1
  219. package/dist/formatting/Style.js +14 -0
  220. package/dist/formatting/Style.js.map +1 -1
  221. package/dist/formatting/StylesManager.d.ts +2 -0
  222. package/dist/formatting/StylesManager.d.ts.map +1 -1
  223. package/dist/formatting/StylesManager.js +14 -2
  224. package/dist/formatting/StylesManager.js.map +1 -1
  225. package/dist/helpers/CleanupHelper.d.ts.map +1 -1
  226. package/dist/helpers/CleanupHelper.js +103 -26
  227. package/dist/helpers/CleanupHelper.js.map +1 -1
  228. package/dist/images/ImageOptimizer.d.ts.map +1 -1
  229. package/dist/images/ImageOptimizer.js +52 -4
  230. package/dist/images/ImageOptimizer.js.map +1 -1
  231. package/dist/index.d.ts +3 -1
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/index.js +4 -2
  234. package/dist/index.js.map +1 -1
  235. package/dist/internal.d.ts +1 -1
  236. package/dist/internal.d.ts.map +1 -1
  237. package/dist/internal.js +2 -1
  238. package/dist/internal.js.map +1 -1
  239. package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
  240. package/dist/processors/CompatibilityUpgrader.js +7 -1
  241. package/dist/processors/CompatibilityUpgrader.js.map +1 -1
  242. package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
  243. package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
  244. package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
  245. package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
  246. package/dist/processors/RevisionWalker.d.ts +9 -3
  247. package/dist/processors/RevisionWalker.d.ts.map +1 -1
  248. package/dist/processors/RevisionWalker.js +223 -39
  249. package/dist/processors/RevisionWalker.js.map +1 -1
  250. package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
  251. package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
  252. package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
  253. package/dist/processors/acceptRevisions.d.ts +1 -0
  254. package/dist/processors/acceptRevisions.d.ts.map +1 -1
  255. package/dist/processors/acceptRevisions.js +21 -11
  256. package/dist/processors/acceptRevisions.js.map +1 -1
  257. package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
  258. package/dist/processors/cnfStyleDecoder.js +7 -7
  259. package/dist/processors/cnfStyleDecoder.js.map +1 -1
  260. package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
  261. package/dist/processors/stripTrackedChanges.js +16 -5
  262. package/dist/processors/stripTrackedChanges.js.map +1 -1
  263. package/dist/utils/deepClone.d.ts.map +1 -1
  264. package/dist/utils/deepClone.js +24 -11
  265. package/dist/utils/deepClone.js.map +1 -1
  266. package/dist/utils/units.d.ts.map +1 -1
  267. package/dist/utils/units.js +1 -1
  268. package/dist/utils/units.js.map +1 -1
  269. package/dist/utils/validation.d.ts.map +1 -1
  270. package/dist/utils/validation.js +11 -23
  271. package/dist/utils/validation.js.map +1 -1
  272. package/dist/utils/xmlSanitization.d.ts +2 -0
  273. package/dist/utils/xmlSanitization.d.ts.map +1 -1
  274. package/dist/utils/xmlSanitization.js +133 -7
  275. package/dist/utils/xmlSanitization.js.map +1 -1
  276. package/dist/validation/RevisionAutoFixer.d.ts +6 -2
  277. package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
  278. package/dist/validation/RevisionAutoFixer.js +68 -54
  279. package/dist/validation/RevisionAutoFixer.js.map +1 -1
  280. package/dist/validation/RevisionValidator.d.ts +2 -0
  281. package/dist/validation/RevisionValidator.d.ts.map +1 -1
  282. package/dist/validation/RevisionValidator.js +26 -21
  283. package/dist/validation/RevisionValidator.js.map +1 -1
  284. package/dist/xml/XMLBuilder.d.ts +1 -0
  285. package/dist/xml/XMLBuilder.d.ts.map +1 -1
  286. package/dist/xml/XMLBuilder.js +52 -20
  287. package/dist/xml/XMLBuilder.js.map +1 -1
  288. package/dist/xml/XMLParser.d.ts +1 -0
  289. package/dist/xml/XMLParser.d.ts.map +1 -1
  290. package/dist/xml/XMLParser.js +55 -13
  291. package/dist/xml/XMLParser.js.map +1 -1
  292. package/dist/zip/ZipHandler.d.ts.map +1 -1
  293. package/dist/zip/ZipHandler.js +37 -13
  294. package/dist/zip/ZipHandler.js.map +1 -1
  295. package/dist/zip/ZipReader.d.ts.map +1 -1
  296. package/dist/zip/ZipReader.js +52 -5
  297. package/dist/zip/ZipReader.js.map +1 -1
  298. package/dist/zip/errors.d.ts +3 -0
  299. package/dist/zip/errors.d.ts.map +1 -1
  300. package/dist/zip/errors.js +9 -1
  301. package/dist/zip/errors.js.map +1 -1
  302. package/dist/zip/types.d.ts +4 -0
  303. package/dist/zip/types.d.ts.map +1 -1
  304. package/dist/zip/types.js +4 -0
  305. package/dist/zip/types.js.map +1 -1
  306. package/package.json +2 -2
  307. package/src/core/Document.ts +1184 -242
  308. package/src/core/DocumentGenerator.ts +106 -26
  309. package/src/core/DocumentParser.ts +681 -114
  310. package/src/core/RelationshipManager.ts +446 -442
  311. package/src/elements/Comment.ts +123 -18
  312. package/src/elements/CommentManager.ts +121 -22
  313. package/src/elements/EndnoteManager.ts +4 -1
  314. package/src/elements/Field.ts +134 -43
  315. package/src/elements/FieldHelpers.ts +20 -4
  316. package/src/elements/Footer.ts +62 -67
  317. package/src/elements/FootnoteManager.ts +4 -1
  318. package/src/elements/Header.ts +62 -67
  319. package/src/elements/HeaderFooterManager.ts +56 -8
  320. package/src/elements/Hyperlink.ts +150 -55
  321. package/src/elements/Image.ts +51 -7
  322. package/src/elements/ImageManager.ts +24 -0
  323. package/src/elements/Paragraph.ts +161 -40
  324. package/src/elements/Revision.ts +446 -47
  325. package/src/elements/Run.ts +44 -6
  326. package/src/elements/Section.ts +25 -9
  327. package/src/elements/Shape.ts +52 -44
  328. package/src/elements/StructuredDocumentTag.ts +83 -8
  329. package/src/elements/Table.ts +151 -50
  330. package/src/elements/TableCell.ts +57 -17
  331. package/src/elements/TableOfContents.ts +10 -9
  332. package/src/elements/TableRow.ts +35 -3
  333. package/src/elements/TextBox.ts +58 -43
  334. package/src/formatting/AbstractNumbering.ts +4 -2
  335. package/src/formatting/NumberingLevel.ts +50 -12
  336. package/src/formatting/NumberingManager.ts +32 -3
  337. package/src/formatting/Style.ts +14 -0
  338. package/src/formatting/StylesManager.ts +29 -2
  339. package/src/helpers/CleanupHelper.ts +122 -30
  340. package/src/images/ImageOptimizer.ts +64 -5
  341. package/src/index.ts +7 -0
  342. package/src/internal.ts +1 -0
  343. package/src/processors/CompatibilityUpgrader.ts +15 -2
  344. package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
  345. package/src/processors/RevisionWalker.ts +390 -46
  346. package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
  347. package/src/processors/acceptRevisions.ts +67 -17
  348. package/src/processors/cnfStyleDecoder.ts +18 -12
  349. package/src/processors/stripTrackedChanges.ts +47 -10
  350. package/src/utils/deepClone.ts +48 -14
  351. package/src/utils/units.ts +3 -1
  352. package/src/utils/validation.ts +30 -32
  353. package/src/utils/xmlSanitization.ts +218 -22
  354. package/src/validation/RevisionAutoFixer.ts +109 -65
  355. package/src/validation/RevisionValidator.ts +48 -23
  356. package/src/xml/XMLBuilder.ts +82 -22
  357. package/src/xml/XMLParser.ts +87 -20
  358. package/src/zip/ZipHandler.ts +61 -21
  359. package/src/zip/ZipReader.ts +135 -13
  360. package/src/zip/errors.ts +15 -0
  361. package/src/zip/types.ts +44 -2
@@ -77,8 +77,8 @@ class XMLBuilder {
77
77
  let xml = `<${element.name}`;
78
78
  if (element.attributes) {
79
79
  for (const [key, value] of Object.entries(element.attributes)) {
80
- if (value !== undefined && value !== null && value !== false) {
81
- const attrValue = value === true ? key : String(value);
80
+ if (value !== undefined && value !== null) {
81
+ const attrValue = value === true ? '1' : value === false ? '0' : String(value);
82
82
  xml += ` ${key}="${XMLBuilder.escapeXmlAttribute(attrValue)}"`;
83
83
  }
84
84
  }
@@ -118,13 +118,27 @@ class XMLBuilder {
118
118
  .replace(/"/g, '&quot;')
119
119
  .replace(/'/g, '&apos;');
120
120
  }
121
+ static NAMED_ENTITIES = {
122
+ lt: '<',
123
+ gt: '>',
124
+ quot: '"',
125
+ apos: "'",
126
+ amp: '&',
127
+ };
121
128
  static unescapeXml(text) {
122
- return text
123
- .replace(/&lt;/g, '<')
124
- .replace(/&gt;/g, '>')
125
- .replace(/&quot;/g, '"')
126
- .replace(/&apos;/g, "'")
127
- .replace(/&amp;/g, '&');
129
+ return text.replace(/&(?:(lt|gt|quot|apos|amp)|#x([0-9A-Fa-f]+)|#(\d+));/g, (match, named, hex, dec) => {
130
+ if (named !== undefined) {
131
+ return XMLBuilder.NAMED_ENTITIES[named] ?? match;
132
+ }
133
+ const code = hex !== undefined ? parseInt(hex, 16) : Number(dec);
134
+ const isXmlChar = code === 0x9 ||
135
+ code === 0xa ||
136
+ code === 0xd ||
137
+ (code >= 0x20 && code <= 0xd7ff) ||
138
+ (code >= 0xe000 && code <= 0xfffd) ||
139
+ (code >= 0x10000 && code <= 0x10ffff);
140
+ return isXmlChar ? String.fromCodePoint(code) : match;
141
+ });
128
142
  }
129
143
  static sanitizeXmlContent(text) {
130
144
  return ((0, xmlSanitization_js_1.removeInvalidXmlChars)(text)
@@ -314,12 +328,7 @@ class XMLBuilder {
314
328
  const builder = new XMLBuilder();
315
329
  const element = XMLBuilder.objectToElement(obj, rootName);
316
330
  if (element) {
317
- if (typeof element === 'string') {
318
- builder.text(element);
319
- }
320
- else {
321
- builder.elements.push(element);
322
- }
331
+ builder.elements.push(element);
323
332
  }
324
333
  return builder.build();
325
334
  }
@@ -327,14 +336,11 @@ class XMLBuilder {
327
336
  if (obj === null || obj === undefined) {
328
337
  return null;
329
338
  }
330
- if (typeof obj !== 'object' || obj === null) {
331
- return String(obj);
339
+ if (typeof obj !== 'object') {
340
+ return { name, children: [String(obj)] };
332
341
  }
333
342
  const attributes = {};
334
343
  const children = [];
335
- if (obj['#text'] && Object.keys(obj).length === 1) {
336
- return String(obj['#text']);
337
- }
338
344
  for (const key in obj) {
339
345
  if (key.startsWith('@_')) {
340
346
  const attrName = key.substring(2);
@@ -345,7 +351,33 @@ class XMLBuilder {
345
351
  else if (key === '#text') {
346
352
  children.push(String(obj[key]));
347
353
  }
348
- else {
354
+ }
355
+ const orderedChildren = obj['_orderedChildren'];
356
+ if (orderedChildren && orderedChildren.length > 0) {
357
+ for (const childInfo of orderedChildren) {
358
+ const childValue = obj[childInfo.type];
359
+ if (childValue === undefined) {
360
+ continue;
361
+ }
362
+ const item = Array.isArray(childValue)
363
+ ? childValue[childInfo.index]
364
+ : childInfo.index === 0
365
+ ? childValue
366
+ : undefined;
367
+ if (item === undefined) {
368
+ continue;
369
+ }
370
+ const childElement = XMLBuilder.objectToElement(item, childInfo.type);
371
+ if (childElement) {
372
+ children.push(childElement);
373
+ }
374
+ }
375
+ }
376
+ else {
377
+ for (const key in obj) {
378
+ if (key.startsWith('@_') || key === '#text' || key === '_orderedChildren') {
379
+ continue;
380
+ }
349
381
  const childObj = obj[key];
350
382
  if (Array.isArray(childObj)) {
351
383
  childObj.forEach((item) => {
@@ -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"]}
@@ -22,6 +22,7 @@ export declare class XMLParser {
22
22
  static extractText(xml: string): string;
23
23
  static validateSize(xml: string, maxSize?: number): void;
24
24
  static extractBetweenTags(xml: string, startTag: string, endTag: string): string | undefined;
25
+ private static findTagEnd;
25
26
  static extractSelfClosingTag(xml: string, tagName: string): string | undefined;
26
27
  static parseToObject(xml: string, options?: ParseToObjectOptions): ParsedXMLObject;
27
28
  private static parseElementToObject;
@@ -1 +1 @@
1
- {"version":3,"file":"XMLParser.d.ts","sourceRoot":"","sources":["../../src/xml/XMLParser.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAK7C,MAAM,WAAW,oBAAoB;IAEnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAG7B,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAG1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAG9B,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB,WAAW,CAAC,EAAE,OAAO,CAAC;IAGtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,MAAM,GACN,OAAO,GACP,eAAe,GACf,eAAe,EAAE,GACjB,IAAI,GACJ,SAAS,CAAC;AAKd,MAAM,WAAW,eAAe;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC;CAC/B;AAcD,qBAAa,SAAS;IAMpB,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAyB1C,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAyG9D,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAsB/E,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAoB/D,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAqBhE,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAkCvC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAyB,GAAG,IAAI;IAiB1E,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA4B5F,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAsD9E,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,eAAe;IAoClF,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAqLnC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA0FvC,OAAO,CAAC,MAAM,CAAC,cAAc;IAuE7B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAgD/B,OAAO,CAAC,MAAM,CAAC,UAAU;CAqC1B"}
1
+ {"version":3,"file":"XMLParser.d.ts","sourceRoot":"","sources":["../../src/xml/XMLParser.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAK7C,MAAM,WAAW,oBAAoB;IAEnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAG7B,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAG1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAG9B,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB,WAAW,CAAC,EAAE,OAAO,CAAC;IAGtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,MAAM,GACN,OAAO,GACP,eAAe,GACf,eAAe,EAAE,GACjB,IAAI,GACJ,SAAS,CAAC;AAKd,MAAM,WAAW,eAAe;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAAC;CAC/B;AAcD,qBAAa,SAAS;IAMpB,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAyB1C,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IA0G9D,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAsB/E,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAoB/D,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAqBhE,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAkCvC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAyB,GAAG,IAAI;IAiB1E,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAuB5F,OAAO,CAAC,MAAM,CAAC,UAAU;IA4BzB,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAoD9E,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,eAAe;IAoClF,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA6NnC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA+FvC,OAAO,CAAC,MAAM,CAAC,cAAc;IAuE7B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAgD/B,OAAO,CAAC,MAAM,CAAC,UAAU;CAqC1B"}
@@ -44,7 +44,7 @@ class XMLParser {
44
44
  pos = startIdx + openTag.length;
45
45
  continue;
46
46
  }
47
- const openEnd = xml.indexOf('>', startIdx);
47
+ const openEnd = XMLParser.findTagEnd(xml, startIdx);
48
48
  if (openEnd === -1)
49
49
  break;
50
50
  if (xml.substring(openEnd - 1, openEnd + 1) === selfClosingEnd) {
@@ -155,7 +155,7 @@ class XMLParser {
155
155
  const startIdx = xml.indexOf(startTag);
156
156
  if (startIdx === -1)
157
157
  return undefined;
158
- const openEnd = xml.indexOf('>', startIdx);
158
+ const openEnd = XMLParser.findTagEnd(xml, startIdx);
159
159
  if (openEnd === -1)
160
160
  return undefined;
161
161
  const endIdx = xml.indexOf(endTag, openEnd);
@@ -163,6 +163,23 @@ class XMLParser {
163
163
  return undefined;
164
164
  return xml.substring(openEnd + 1, endIdx);
165
165
  }
166
+ static findTagEnd(xml, startPos) {
167
+ let quote;
168
+ for (let pos = startPos; pos < xml.length; pos++) {
169
+ const ch = xml[pos];
170
+ if (quote) {
171
+ if (ch === quote)
172
+ quote = undefined;
173
+ }
174
+ else if (ch === '"' || ch === "'") {
175
+ quote = ch;
176
+ }
177
+ else if (ch === '>') {
178
+ return pos;
179
+ }
180
+ }
181
+ return -1;
182
+ }
166
183
  static extractSelfClosingTag(xml, tagName) {
167
184
  const startPattern = `<${tagName}`;
168
185
  let searchPos = 0;
@@ -172,14 +189,11 @@ class XMLParser {
172
189
  return undefined;
173
190
  const charAfterTag = xml[startIdx + startPattern.length];
174
191
  if (charAfterTag === ' ' || charAfterTag === '/' || charAfterTag === '>') {
175
- const endIdx = xml.indexOf('/>', startIdx);
176
- if (endIdx === -1) {
177
- const closeTagStart = xml.indexOf('>', startIdx);
178
- if (closeTagStart === -1)
179
- return undefined;
180
- return xml.substring(startIdx + startPattern.length, closeTagStart);
181
- }
182
- return xml.substring(startIdx + startPattern.length, endIdx);
192
+ const tagEnd = XMLParser.findTagEnd(xml, startIdx + startPattern.length);
193
+ if (tagEnd === -1)
194
+ return undefined;
195
+ const attrEnd = xml[tagEnd - 1] === '/' ? tagEnd - 1 : tagEnd;
196
+ return xml.substring(startIdx + startPattern.length, attrEnd);
183
197
  }
184
198
  searchPos = startIdx + 1;
185
199
  }
@@ -223,13 +237,27 @@ class XMLParser {
223
237
  }
224
238
  return { value: {}, endPos: xml.length };
225
239
  }
240
+ if (xml.substring(openTagStart, openTagStart + 2) === '<?') {
241
+ const piEnd = xml.indexOf('?>', openTagStart + 2);
242
+ if (piEnd !== -1) {
243
+ return XMLParser.parseElementToObject(xml, piEnd + 2, options, depth);
244
+ }
245
+ return { value: {}, endPos: xml.length };
246
+ }
247
+ if (xml.substring(openTagStart, openTagStart + 9) === '<![CDATA[') {
248
+ const cdataEnd = xml.indexOf(']]>', openTagStart + 9);
249
+ if (cdataEnd !== -1) {
250
+ return XMLParser.parseElementToObject(xml, cdataEnd + 3, options, depth);
251
+ }
252
+ return { value: {}, endPos: xml.length };
253
+ }
226
254
  const nameMatch = /^([a-zA-Z0-9:_-]+)/.exec(xml.substring(openTagStart + 1));
227
255
  if (!nameMatch) {
228
256
  return { value: {}, endPos: openTagStart + 1 };
229
257
  }
230
258
  const originalElementName = nameMatch[1] || '';
231
259
  let elementName = originalElementName;
232
- const tagHeaderEnd = xml.indexOf('>', openTagStart);
260
+ const tagHeaderEnd = XMLParser.findTagEnd(xml, openTagStart);
233
261
  if (tagHeaderEnd === -1) {
234
262
  return { value: {}, endPos: xml.length };
235
263
  }
@@ -274,6 +302,16 @@ class XMLParser {
274
302
  textContent += XMLBuilder_js_1.XMLBuilder.unescapeXml(text);
275
303
  }
276
304
  }
305
+ if (content.startsWith('<![CDATA[', nextTag)) {
306
+ const cdataEnd = content.indexOf(']]>', nextTag + 9);
307
+ if (cdataEnd === -1) {
308
+ textContent += content.substring(nextTag + 9);
309
+ break;
310
+ }
311
+ textContent += content.substring(nextTag + 9, cdataEnd);
312
+ pos = cdataEnd + 3;
313
+ continue;
314
+ }
277
315
  const childResult = XMLParser.parseElementToObject(content, nextTag, options, depth + 1);
278
316
  const childObj = childResult.value;
279
317
  const childKeys = Object.keys(childObj);
@@ -303,6 +341,9 @@ class XMLParser {
303
341
  }
304
342
  if (children.length > 0) {
305
343
  const coalescedChildren = XMLParser.coalesceChildren(children, options);
344
+ if (typeof elementValue === 'string') {
345
+ elementValue = { [options.textNodeName]: elementValue };
346
+ }
306
347
  if (typeof elementValue === 'object' && !Array.isArray(elementValue)) {
307
348
  elementValue = { ...elementValue, ...coalescedChildren };
308
349
  }
@@ -377,9 +418,10 @@ class XMLParser {
377
418
  attrName = attrName.split(':')[1] || attrName;
378
419
  }
379
420
  const prefixedName = options.attributeNamePrefix + attrName;
421
+ const decodedValue = XMLBuilder_js_1.XMLBuilder.unescapeXml(attrValue);
380
422
  attributes[prefixedName] = options.parseAttributeValue
381
- ? XMLParser.parseValue(attrValue)
382
- : attrValue;
423
+ ? XMLParser.parseValue(decodedValue)
424
+ : decodedValue;
383
425
  }
384
426
  return attributes;
385
427
  }