@cj-tech-master/excelts 9.4.2 → 9.5.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 (618) hide show
  1. package/dist/browser/index.browser.d.ts +8 -5
  2. package/dist/browser/index.browser.js +19 -1
  3. package/dist/browser/index.d.ts +4 -2
  4. package/dist/browser/index.js +9 -1
  5. package/dist/browser/modules/excel/chart/cache-populator.d.ts +49 -0
  6. package/dist/browser/modules/excel/chart/cache-populator.js +1171 -0
  7. package/dist/browser/modules/excel/chart/chart-api.d.ts +92 -0
  8. package/dist/browser/modules/excel/chart/chart-api.js +364 -0
  9. package/dist/browser/modules/excel/chart/chart-builder.d.ts +48 -0
  10. package/dist/browser/modules/excel/chart/chart-builder.js +2432 -0
  11. package/dist/browser/modules/excel/chart/chart-ex-builder.d.ts +36 -0
  12. package/dist/browser/modules/excel/chart/chart-ex-builder.js +903 -0
  13. package/dist/browser/modules/excel/chart/chart-ex-parser.d.ts +8 -0
  14. package/dist/browser/modules/excel/chart/chart-ex-parser.js +1205 -0
  15. package/dist/browser/modules/excel/chart/chart-ex-renderer.d.ts +187 -0
  16. package/dist/browser/modules/excel/chart/chart-ex-renderer.js +5352 -0
  17. package/dist/browser/modules/excel/chart/chart-ex-types.d.ts +531 -0
  18. package/dist/browser/modules/excel/chart/chart-ex-types.js +11 -0
  19. package/dist/browser/modules/excel/chart/chart-images.d.ts +78 -0
  20. package/dist/browser/modules/excel/chart/chart-images.js +363 -0
  21. package/dist/browser/modules/excel/chart/chart-presets.d.ts +392 -0
  22. package/dist/browser/modules/excel/chart/chart-presets.js +179 -0
  23. package/dist/browser/modules/excel/chart/chart-renderer.d.ts +550 -0
  24. package/dist/browser/modules/excel/chart/chart-renderer.js +6440 -0
  25. package/dist/browser/modules/excel/chart/chart-sidecar.d.ts +21 -0
  26. package/dist/browser/modules/excel/chart/chart-sidecar.js +427 -0
  27. package/dist/browser/modules/excel/chart/chart-utils.d.ts +306 -0
  28. package/dist/browser/modules/excel/chart/chart-utils.js +821 -0
  29. package/dist/browser/modules/excel/chart/chart.d.ts +504 -0
  30. package/dist/browser/modules/excel/chart/chart.js +1320 -0
  31. package/dist/browser/modules/excel/chart/glyph-rasterizer.d.ts +62 -0
  32. package/dist/browser/modules/excel/chart/glyph-rasterizer.js +658 -0
  33. package/dist/browser/modules/excel/chart/index.d.ts +54 -0
  34. package/dist/browser/modules/excel/chart/index.js +46 -0
  35. package/dist/browser/modules/excel/chart/install.d.ts +44 -0
  36. package/dist/browser/modules/excel/chart/install.js +91 -0
  37. package/dist/browser/modules/excel/chart/shape-properties.d.ts +156 -0
  38. package/dist/browser/modules/excel/chart/shape-properties.js +1557 -0
  39. package/dist/browser/modules/excel/chart/stroke-font.d.ts +36 -0
  40. package/dist/browser/modules/excel/chart/stroke-font.js +1556 -0
  41. package/dist/browser/modules/excel/chart/topojson.d.ts +98 -0
  42. package/dist/browser/modules/excel/chart/topojson.js +236 -0
  43. package/dist/browser/modules/excel/chart/types.d.ts +2559 -0
  44. package/dist/browser/modules/excel/chart/types.js +8 -0
  45. package/dist/browser/modules/excel/chart-host-registry.d.ts +157 -0
  46. package/dist/browser/modules/excel/chart-host-registry.js +90 -0
  47. package/dist/browser/modules/excel/chartsheet.d.ts +102 -0
  48. package/dist/browser/modules/excel/chartsheet.js +196 -0
  49. package/dist/browser/modules/excel/defined-names.d.ts +35 -0
  50. package/dist/browser/modules/excel/defined-names.js +44 -4
  51. package/dist/browser/modules/excel/errors.d.ts +6 -0
  52. package/dist/browser/modules/excel/errors.js +9 -0
  53. package/dist/browser/modules/excel/form-control.d.ts +6 -0
  54. package/dist/browser/modules/excel/form-control.js +17 -0
  55. package/dist/browser/modules/excel/image.js +12 -2
  56. package/dist/browser/modules/excel/pivot-chart.d.ts +7 -0
  57. package/dist/browser/modules/excel/pivot-chart.js +53 -0
  58. package/dist/browser/modules/excel/pivot-table.d.ts +55 -0
  59. package/dist/browser/modules/excel/pivot-table.js +35 -0
  60. package/dist/browser/modules/excel/range.js +5 -1
  61. package/dist/browser/modules/excel/sparkline/index.d.ts +7 -0
  62. package/dist/browser/modules/excel/sparkline/index.js +7 -0
  63. package/dist/browser/modules/excel/sparkline/sparkline.d.ts +206 -0
  64. package/dist/browser/modules/excel/sparkline/sparkline.js +750 -0
  65. package/dist/browser/modules/excel/stream/worksheet-writer.js +3 -2
  66. package/dist/browser/modules/excel/table.js +42 -6
  67. package/dist/browser/modules/excel/types.d.ts +72 -0
  68. package/dist/browser/modules/excel/utils/address.d.ts +18 -0
  69. package/dist/browser/modules/excel/utils/address.js +28 -0
  70. package/dist/browser/modules/excel/utils/drawing-utils.js +11 -6
  71. package/dist/browser/modules/excel/utils/guid.d.ts +15 -0
  72. package/dist/browser/modules/excel/utils/guid.js +35 -0
  73. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +74 -0
  74. package/dist/browser/modules/excel/utils/ooxml-paths.js +206 -9
  75. package/dist/browser/modules/excel/utils/ooxml-validator/check-chart-sidecar.d.ts +35 -0
  76. package/dist/browser/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +101 -0
  77. package/dist/browser/modules/excel/utils/ooxml-validator/check-chart.d.ts +32 -0
  78. package/dist/browser/modules/excel/utils/ooxml-validator/check-chart.js +2125 -0
  79. package/dist/browser/modules/excel/utils/ooxml-validator/check-chartsheet.d.ts +9 -0
  80. package/dist/browser/modules/excel/utils/ooxml-validator/check-chartsheet.js +26 -0
  81. package/dist/browser/modules/excel/utils/ooxml-validator/check-content-types.d.ts +16 -0
  82. package/dist/browser/modules/excel/utils/ooxml-validator/check-content-types.js +181 -0
  83. package/dist/browser/modules/excel/utils/ooxml-validator/check-drawing.d.ts +34 -0
  84. package/dist/browser/modules/excel/utils/ooxml-validator/check-drawing.js +267 -0
  85. package/dist/browser/modules/excel/utils/ooxml-validator/check-pivot.d.ts +14 -0
  86. package/dist/browser/modules/excel/utils/ooxml-validator/check-pivot.js +104 -0
  87. package/dist/browser/modules/excel/utils/ooxml-validator/check-relationships.d.ts +18 -0
  88. package/dist/browser/modules/excel/utils/ooxml-validator/check-relationships.js +184 -0
  89. package/dist/browser/modules/excel/utils/ooxml-validator/check-structure.d.ts +21 -0
  90. package/dist/browser/modules/excel/utils/ooxml-validator/check-structure.js +56 -0
  91. package/dist/browser/modules/excel/utils/ooxml-validator/check-styles.d.ts +15 -0
  92. package/dist/browser/modules/excel/utils/ooxml-validator/check-styles.js +89 -0
  93. package/dist/browser/modules/excel/utils/ooxml-validator/check-table.d.ts +31 -0
  94. package/dist/browser/modules/excel/utils/ooxml-validator/check-table.js +177 -0
  95. package/dist/browser/modules/excel/utils/ooxml-validator/check-workbook.d.ts +19 -0
  96. package/dist/browser/modules/excel/utils/ooxml-validator/check-workbook.js +163 -0
  97. package/dist/browser/modules/excel/utils/ooxml-validator/check-worksheet.d.ts +25 -0
  98. package/dist/browser/modules/excel/utils/ooxml-validator/check-worksheet.js +569 -0
  99. package/dist/browser/modules/excel/utils/ooxml-validator/context.d.ts +85 -0
  100. package/dist/browser/modules/excel/utils/ooxml-validator/context.js +191 -0
  101. package/dist/browser/modules/excel/utils/ooxml-validator/index.d.ts +31 -0
  102. package/dist/browser/modules/excel/utils/ooxml-validator/index.js +102 -0
  103. package/dist/browser/modules/excel/utils/ooxml-validator/path-utils.d.ts +67 -0
  104. package/dist/browser/modules/excel/utils/ooxml-validator/path-utils.js +156 -0
  105. package/dist/browser/modules/excel/utils/ooxml-validator/reporter.d.ts +41 -0
  106. package/dist/browser/modules/excel/utils/ooxml-validator/reporter.js +61 -0
  107. package/dist/browser/modules/excel/utils/ooxml-validator/types.d.ts +109 -0
  108. package/dist/browser/modules/excel/utils/ooxml-validator/types.js +12 -0
  109. package/dist/browser/modules/excel/utils/ooxml-validator/xml-utils.d.ts +38 -0
  110. package/dist/browser/modules/excel/utils/ooxml-validator/xml-utils.js +100 -0
  111. package/dist/browser/modules/excel/workbook.browser.d.ts +248 -30
  112. package/dist/browser/modules/excel/workbook.browser.js +966 -31
  113. package/dist/browser/modules/excel/workbook.d.ts +43 -0
  114. package/dist/browser/modules/excel/workbook.js +48 -0
  115. package/dist/browser/modules/excel/worksheet.d.ts +157 -3
  116. package/dist/browser/modules/excel/worksheet.js +394 -35
  117. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +40 -0
  118. package/dist/browser/modules/excel/xlsx/rel-type.js +41 -1
  119. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +1 -0
  120. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
  121. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
  122. package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
  123. package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.d.ts +353 -0
  124. package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.js +6000 -0
  125. package/dist/browser/modules/excel/xlsx/xform/comment/threaded-comments-xform.d.ts +60 -0
  126. package/dist/browser/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +213 -0
  127. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +150 -11
  128. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
  129. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
  130. package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.d.ts +30 -0
  131. package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
  132. package/dist/browser/modules/excel/xlsx/xform/drawing/graphic-frame-xform.d.ts +54 -0
  133. package/dist/browser/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +225 -0
  134. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +3 -1
  135. package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
  136. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +46 -0
  137. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
  138. package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +13 -2
  139. package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
  140. package/dist/browser/modules/excel/xlsx/xform/sheet/chartsheet-xform.d.ts +185 -0
  141. package/dist/browser/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +441 -0
  142. package/dist/browser/modules/excel/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -0
  143. package/dist/browser/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
  144. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +196 -20
  145. package/dist/browser/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
  146. package/dist/browser/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
  147. package/dist/browser/modules/excel/xlsx/xform/xsd-values.d.ts +63 -0
  148. package/dist/browser/modules/excel/xlsx/xform/xsd-values.js +101 -0
  149. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +115 -21
  150. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +4422 -78
  151. package/dist/browser/modules/pdf/builder/document-builder.d.ts +74 -0
  152. package/dist/browser/modules/pdf/builder/document-builder.js +507 -2
  153. package/dist/browser/modules/pdf/builder/pdf-editor.js +48 -3
  154. package/dist/browser/modules/pdf/excel-bridge.d.ts +69 -0
  155. package/dist/browser/modules/pdf/excel-bridge.js +683 -12
  156. package/dist/browser/modules/pdf/font/font-manager.d.ts +25 -0
  157. package/dist/browser/modules/pdf/font/font-manager.js +39 -0
  158. package/dist/browser/modules/pdf/index.d.ts +5 -2
  159. package/dist/browser/modules/pdf/index.js +3 -1
  160. package/dist/browser/modules/pdf/render/chart-surface.d.ts +33 -0
  161. package/dist/browser/modules/pdf/render/chart-surface.js +200 -0
  162. package/dist/browser/modules/pdf/render/layout-engine.d.ts +22 -1
  163. package/dist/browser/modules/pdf/render/layout-engine.js +436 -56
  164. package/dist/browser/modules/pdf/render/page-renderer.js +169 -28
  165. package/dist/browser/modules/pdf/render/pdf-exporter.js +117 -7
  166. package/dist/browser/modules/pdf/types.d.ts +227 -23
  167. package/dist/browser/modules/pdf/types.js +4 -0
  168. package/dist/browser/modules/pdf/word-bridge.d.ts +47 -0
  169. package/dist/browser/modules/pdf/word-bridge.js +304 -0
  170. package/dist/browser/modules/word/constants.d.ts +179 -0
  171. package/dist/browser/modules/word/constants.js +231 -0
  172. package/dist/browser/modules/word/content-types.d.ts +27 -0
  173. package/dist/browser/modules/word/content-types.js +53 -0
  174. package/dist/browser/modules/word/digital-signatures.d.ts +87 -0
  175. package/dist/browser/modules/word/digital-signatures.js +134 -0
  176. package/dist/browser/modules/word/document.d.ts +728 -0
  177. package/dist/browser/modules/word/document.js +1795 -0
  178. package/dist/browser/modules/word/docx-packager.d.ts +14 -0
  179. package/dist/browser/modules/word/docx-packager.js +822 -0
  180. package/dist/browser/modules/word/docx-reader.d.ts +11 -0
  181. package/dist/browser/modules/word/docx-reader.js +4929 -0
  182. package/dist/browser/modules/word/encryption.d.ts +102 -0
  183. package/dist/browser/modules/word/encryption.js +274 -0
  184. package/dist/browser/modules/word/errors.d.ts +49 -0
  185. package/dist/browser/modules/word/errors.js +68 -0
  186. package/dist/browser/modules/word/font-obfuscation.d.ts +31 -0
  187. package/dist/browser/modules/word/font-obfuscation.js +83 -0
  188. package/dist/browser/modules/word/html-renderer.d.ts +38 -0
  189. package/dist/browser/modules/word/html-renderer.js +782 -0
  190. package/dist/browser/modules/word/index.base.d.ts +19 -0
  191. package/dist/browser/modules/word/index.base.js +51 -0
  192. package/dist/browser/modules/word/index.browser.d.ts +4 -0
  193. package/dist/browser/modules/word/index.browser.js +4 -0
  194. package/dist/browser/modules/word/index.d.ts +4 -0
  195. package/dist/browser/modules/word/index.js +4 -0
  196. package/dist/browser/modules/word/internal-utils.d.ts +23 -0
  197. package/dist/browser/modules/word/internal-utils.js +54 -0
  198. package/dist/browser/modules/word/relationships.d.ts +31 -0
  199. package/dist/browser/modules/word/relationships.js +56 -0
  200. package/dist/browser/modules/word/types.d.ts +2325 -0
  201. package/dist/browser/modules/word/types.js +10 -0
  202. package/dist/browser/modules/word/units.d.ts +49 -0
  203. package/dist/browser/modules/word/units.js +111 -0
  204. package/dist/browser/modules/word/writers/chart-writer.d.ts +10 -0
  205. package/dist/browser/modules/word/writers/chart-writer.js +385 -0
  206. package/dist/browser/modules/word/writers/checkbox-writer.d.ts +9 -0
  207. package/dist/browser/modules/word/writers/checkbox-writer.js +42 -0
  208. package/dist/browser/modules/word/writers/comment-writer.d.ts +15 -0
  209. package/dist/browser/modules/word/writers/comment-writer.js +70 -0
  210. package/dist/browser/modules/word/writers/document-writer.d.ts +16 -0
  211. package/dist/browser/modules/word/writers/document-writer.js +461 -0
  212. package/dist/browser/modules/word/writers/footnote-writer.d.ts +11 -0
  213. package/dist/browser/modules/word/writers/footnote-writer.js +72 -0
  214. package/dist/browser/modules/word/writers/header-footer-writer.d.ts +13 -0
  215. package/dist/browser/modules/word/writers/header-footer-writer.js +129 -0
  216. package/dist/browser/modules/word/writers/image-writer.d.ts +10 -0
  217. package/dist/browser/modules/word/writers/image-writer.js +185 -0
  218. package/dist/browser/modules/word/writers/math-writer.d.ts +9 -0
  219. package/dist/browser/modules/word/writers/math-writer.js +428 -0
  220. package/dist/browser/modules/word/writers/numbering-writer.d.ts +10 -0
  221. package/dist/browser/modules/word/writers/numbering-writer.js +125 -0
  222. package/dist/browser/modules/word/writers/paragraph-writer.d.ts +13 -0
  223. package/dist/browser/modules/word/writers/paragraph-writer.js +516 -0
  224. package/dist/browser/modules/word/writers/parts-writer.d.ts +26 -0
  225. package/dist/browser/modules/word/writers/parts-writer.js +660 -0
  226. package/dist/browser/modules/word/writers/run-writer.d.ts +15 -0
  227. package/dist/browser/modules/word/writers/run-writer.js +649 -0
  228. package/dist/browser/modules/word/writers/section-writer.d.ts +10 -0
  229. package/dist/browser/modules/word/writers/section-writer.js +238 -0
  230. package/dist/browser/modules/word/writers/styles-writer.d.ts +10 -0
  231. package/dist/browser/modules/word/writers/styles-writer.js +242 -0
  232. package/dist/browser/modules/word/writers/table-writer.d.ts +10 -0
  233. package/dist/browser/modules/word/writers/table-writer.js +503 -0
  234. package/dist/browser/modules/word/writers/textbox-writer.d.ts +9 -0
  235. package/dist/browser/modules/word/writers/textbox-writer.js +53 -0
  236. package/dist/browser/modules/word/writers/toc-writer.d.ts +9 -0
  237. package/dist/browser/modules/word/writers/toc-writer.js +79 -0
  238. package/dist/browser/modules/xml/encode.d.ts +56 -7
  239. package/dist/browser/modules/xml/encode.js +157 -11
  240. package/dist/cjs/index.js +13 -2
  241. package/dist/cjs/modules/excel/chart/cache-populator.js +1178 -0
  242. package/dist/cjs/modules/excel/chart/chart-api.js +371 -0
  243. package/dist/cjs/modules/excel/chart/chart-builder.js +2440 -0
  244. package/dist/cjs/modules/excel/chart/chart-ex-builder.js +907 -0
  245. package/dist/cjs/modules/excel/chart/chart-ex-parser.js +1208 -0
  246. package/dist/cjs/modules/excel/chart/chart-ex-renderer.js +5364 -0
  247. package/dist/cjs/modules/excel/chart/chart-ex-types.js +12 -0
  248. package/dist/cjs/modules/excel/chart/chart-images.js +366 -0
  249. package/dist/cjs/modules/excel/chart/chart-presets.js +184 -0
  250. package/dist/cjs/modules/excel/chart/chart-renderer.js +6450 -0
  251. package/dist/cjs/modules/excel/chart/chart-sidecar.js +433 -0
  252. package/dist/cjs/modules/excel/chart/chart-utils.js +845 -0
  253. package/dist/cjs/modules/excel/chart/chart.js +1324 -0
  254. package/dist/cjs/modules/excel/chart/glyph-rasterizer.js +664 -0
  255. package/dist/cjs/modules/excel/chart/index.js +101 -0
  256. package/dist/cjs/modules/excel/chart/install.js +95 -0
  257. package/dist/cjs/modules/excel/chart/shape-properties.js +1577 -0
  258. package/dist/cjs/modules/excel/chart/stroke-font.js +1559 -0
  259. package/dist/cjs/modules/excel/chart/topojson.js +239 -0
  260. package/dist/cjs/modules/excel/chart/types.js +9 -0
  261. package/dist/cjs/modules/excel/chart-host-registry.js +96 -0
  262. package/dist/cjs/modules/excel/chartsheet.js +199 -0
  263. package/dist/cjs/modules/excel/defined-names.js +44 -4
  264. package/dist/cjs/modules/excel/errors.js +11 -1
  265. package/dist/cjs/modules/excel/form-control.js +17 -0
  266. package/dist/cjs/modules/excel/image.js +12 -2
  267. package/dist/cjs/modules/excel/pivot-chart.js +56 -0
  268. package/dist/cjs/modules/excel/pivot-table.js +35 -0
  269. package/dist/cjs/modules/excel/range.js +5 -1
  270. package/dist/cjs/modules/excel/sparkline/index.js +23 -0
  271. package/dist/cjs/modules/excel/sparkline/sparkline.js +756 -0
  272. package/dist/cjs/modules/excel/stream/worksheet-writer.js +3 -2
  273. package/dist/cjs/modules/excel/table.js +42 -6
  274. package/dist/cjs/modules/excel/utils/address.js +29 -0
  275. package/dist/cjs/modules/excel/utils/drawing-utils.js +11 -6
  276. package/dist/cjs/modules/excel/utils/guid.js +38 -0
  277. package/dist/cjs/modules/excel/utils/ooxml-paths.js +246 -9
  278. package/dist/cjs/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +103 -0
  279. package/dist/cjs/modules/excel/utils/ooxml-validator/check-chart.js +2128 -0
  280. package/dist/cjs/modules/excel/utils/ooxml-validator/check-chartsheet.js +29 -0
  281. package/dist/cjs/modules/excel/utils/ooxml-validator/check-content-types.js +184 -0
  282. package/dist/cjs/modules/excel/utils/ooxml-validator/check-drawing.js +270 -0
  283. package/dist/cjs/modules/excel/utils/ooxml-validator/check-pivot.js +107 -0
  284. package/dist/cjs/modules/excel/utils/ooxml-validator/check-relationships.js +188 -0
  285. package/dist/cjs/modules/excel/utils/ooxml-validator/check-structure.js +60 -0
  286. package/dist/cjs/modules/excel/utils/ooxml-validator/check-styles.js +92 -0
  287. package/dist/cjs/modules/excel/utils/ooxml-validator/check-table.js +180 -0
  288. package/dist/cjs/modules/excel/utils/ooxml-validator/check-workbook.js +166 -0
  289. package/dist/cjs/modules/excel/utils/ooxml-validator/check-worksheet.js +572 -0
  290. package/dist/cjs/modules/excel/utils/ooxml-validator/context.js +196 -0
  291. package/dist/cjs/modules/excel/utils/ooxml-validator/index.js +105 -0
  292. package/dist/cjs/modules/excel/utils/ooxml-validator/path-utils.js +168 -0
  293. package/dist/cjs/modules/excel/utils/ooxml-validator/reporter.js +66 -0
  294. package/dist/cjs/modules/excel/utils/ooxml-validator/types.js +13 -0
  295. package/dist/cjs/modules/excel/utils/ooxml-validator/xml-utils.js +110 -0
  296. package/dist/cjs/modules/excel/workbook.browser.js +973 -38
  297. package/dist/cjs/modules/excel/workbook.js +48 -0
  298. package/dist/cjs/modules/excel/worksheet.js +393 -34
  299. package/dist/cjs/modules/excel/xlsx/rel-type.js +41 -1
  300. package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
  301. package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
  302. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
  303. package/dist/cjs/modules/excel/xlsx/xform/chart/chart-space-xform.js +6003 -0
  304. package/dist/cjs/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +219 -0
  305. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +149 -10
  306. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
  307. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
  308. package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
  309. package/dist/cjs/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +228 -0
  310. package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
  311. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
  312. package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
  313. package/dist/cjs/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +444 -0
  314. package/dist/cjs/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
  315. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +195 -19
  316. package/dist/cjs/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
  317. package/dist/cjs/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
  318. package/dist/cjs/modules/excel/xlsx/xform/xsd-values.js +106 -0
  319. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +4420 -76
  320. package/dist/cjs/modules/pdf/builder/document-builder.js +506 -1
  321. package/dist/cjs/modules/pdf/builder/pdf-editor.js +48 -3
  322. package/dist/cjs/modules/pdf/excel-bridge.js +684 -12
  323. package/dist/cjs/modules/pdf/font/font-manager.js +39 -0
  324. package/dist/cjs/modules/pdf/index.js +5 -1
  325. package/dist/cjs/modules/pdf/render/chart-surface.js +203 -0
  326. package/dist/cjs/modules/pdf/render/layout-engine.js +437 -56
  327. package/dist/cjs/modules/pdf/render/page-renderer.js +169 -28
  328. package/dist/cjs/modules/pdf/render/pdf-exporter.js +115 -5
  329. package/dist/cjs/modules/pdf/types.js +5 -0
  330. package/dist/cjs/modules/pdf/word-bridge.js +307 -0
  331. package/dist/cjs/modules/word/constants.js +234 -0
  332. package/dist/cjs/modules/word/content-types.js +57 -0
  333. package/dist/cjs/modules/word/digital-signatures.js +140 -0
  334. package/dist/cjs/modules/word/document.js +1909 -0
  335. package/dist/cjs/modules/word/docx-packager.js +825 -0
  336. package/dist/cjs/modules/word/docx-reader.js +4932 -0
  337. package/dist/cjs/modules/word/encryption.js +282 -0
  338. package/dist/cjs/modules/word/errors.js +88 -0
  339. package/dist/cjs/modules/word/font-obfuscation.js +88 -0
  340. package/dist/cjs/modules/word/html-renderer.js +785 -0
  341. package/dist/cjs/modules/word/index.base.js +199 -0
  342. package/dist/cjs/modules/word/index.browser.js +20 -0
  343. package/dist/cjs/modules/word/index.js +20 -0
  344. package/dist/cjs/modules/word/internal-utils.js +59 -0
  345. package/dist/cjs/modules/word/relationships.js +60 -0
  346. package/dist/cjs/modules/word/types.js +11 -0
  347. package/dist/cjs/modules/word/units.js +135 -0
  348. package/dist/cjs/modules/word/writers/chart-writer.js +388 -0
  349. package/dist/cjs/modules/word/writers/checkbox-writer.js +45 -0
  350. package/dist/cjs/modules/word/writers/comment-writer.js +74 -0
  351. package/dist/cjs/modules/word/writers/document-writer.js +465 -0
  352. package/dist/cjs/modules/word/writers/footnote-writer.js +76 -0
  353. package/dist/cjs/modules/word/writers/header-footer-writer.js +134 -0
  354. package/dist/cjs/modules/word/writers/image-writer.js +188 -0
  355. package/dist/cjs/modules/word/writers/math-writer.js +431 -0
  356. package/dist/cjs/modules/word/writers/numbering-writer.js +128 -0
  357. package/dist/cjs/modules/word/writers/paragraph-writer.js +521 -0
  358. package/dist/cjs/modules/word/writers/parts-writer.js +671 -0
  359. package/dist/cjs/modules/word/writers/run-writer.js +655 -0
  360. package/dist/cjs/modules/word/writers/section-writer.js +241 -0
  361. package/dist/cjs/modules/word/writers/styles-writer.js +245 -0
  362. package/dist/cjs/modules/word/writers/table-writer.js +506 -0
  363. package/dist/cjs/modules/word/writers/textbox-writer.js +56 -0
  364. package/dist/cjs/modules/word/writers/toc-writer.js +82 -0
  365. package/dist/cjs/modules/xml/encode.js +158 -11
  366. package/dist/esm/index.browser.js +20 -2
  367. package/dist/esm/index.js +9 -1
  368. package/dist/esm/modules/excel/chart/cache-populator.js +1171 -0
  369. package/dist/esm/modules/excel/chart/chart-api.js +364 -0
  370. package/dist/esm/modules/excel/chart/chart-builder.js +2432 -0
  371. package/dist/esm/modules/excel/chart/chart-ex-builder.js +903 -0
  372. package/dist/esm/modules/excel/chart/chart-ex-parser.js +1205 -0
  373. package/dist/esm/modules/excel/chart/chart-ex-renderer.js +5352 -0
  374. package/dist/esm/modules/excel/chart/chart-ex-types.js +11 -0
  375. package/dist/esm/modules/excel/chart/chart-images.js +363 -0
  376. package/dist/esm/modules/excel/chart/chart-presets.js +179 -0
  377. package/dist/esm/modules/excel/chart/chart-renderer.js +6440 -0
  378. package/dist/esm/modules/excel/chart/chart-sidecar.js +427 -0
  379. package/dist/esm/modules/excel/chart/chart-utils.js +821 -0
  380. package/dist/esm/modules/excel/chart/chart.js +1320 -0
  381. package/dist/esm/modules/excel/chart/glyph-rasterizer.js +658 -0
  382. package/dist/esm/modules/excel/chart/index.js +46 -0
  383. package/dist/esm/modules/excel/chart/install.js +91 -0
  384. package/dist/esm/modules/excel/chart/shape-properties.js +1557 -0
  385. package/dist/esm/modules/excel/chart/stroke-font.js +1556 -0
  386. package/dist/esm/modules/excel/chart/topojson.js +236 -0
  387. package/dist/esm/modules/excel/chart/types.js +8 -0
  388. package/dist/esm/modules/excel/chart-host-registry.js +90 -0
  389. package/dist/esm/modules/excel/chartsheet.js +196 -0
  390. package/dist/esm/modules/excel/defined-names.js +44 -4
  391. package/dist/esm/modules/excel/errors.js +9 -0
  392. package/dist/esm/modules/excel/form-control.js +17 -0
  393. package/dist/esm/modules/excel/image.js +12 -2
  394. package/dist/esm/modules/excel/pivot-chart.js +53 -0
  395. package/dist/esm/modules/excel/pivot-table.js +35 -0
  396. package/dist/esm/modules/excel/range.js +5 -1
  397. package/dist/esm/modules/excel/sparkline/index.js +7 -0
  398. package/dist/esm/modules/excel/sparkline/sparkline.js +750 -0
  399. package/dist/esm/modules/excel/stream/worksheet-writer.js +3 -2
  400. package/dist/esm/modules/excel/table.js +42 -6
  401. package/dist/esm/modules/excel/utils/address.js +28 -0
  402. package/dist/esm/modules/excel/utils/drawing-utils.js +11 -6
  403. package/dist/esm/modules/excel/utils/guid.js +35 -0
  404. package/dist/esm/modules/excel/utils/ooxml-paths.js +206 -9
  405. package/dist/esm/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +101 -0
  406. package/dist/esm/modules/excel/utils/ooxml-validator/check-chart.js +2125 -0
  407. package/dist/esm/modules/excel/utils/ooxml-validator/check-chartsheet.js +26 -0
  408. package/dist/esm/modules/excel/utils/ooxml-validator/check-content-types.js +181 -0
  409. package/dist/esm/modules/excel/utils/ooxml-validator/check-drawing.js +267 -0
  410. package/dist/esm/modules/excel/utils/ooxml-validator/check-pivot.js +104 -0
  411. package/dist/esm/modules/excel/utils/ooxml-validator/check-relationships.js +184 -0
  412. package/dist/esm/modules/excel/utils/ooxml-validator/check-structure.js +56 -0
  413. package/dist/esm/modules/excel/utils/ooxml-validator/check-styles.js +89 -0
  414. package/dist/esm/modules/excel/utils/ooxml-validator/check-table.js +177 -0
  415. package/dist/esm/modules/excel/utils/ooxml-validator/check-workbook.js +163 -0
  416. package/dist/esm/modules/excel/utils/ooxml-validator/check-worksheet.js +569 -0
  417. package/dist/esm/modules/excel/utils/ooxml-validator/context.js +191 -0
  418. package/dist/esm/modules/excel/utils/ooxml-validator/index.js +102 -0
  419. package/dist/esm/modules/excel/utils/ooxml-validator/path-utils.js +156 -0
  420. package/dist/esm/modules/excel/utils/ooxml-validator/reporter.js +61 -0
  421. package/dist/esm/modules/excel/utils/ooxml-validator/types.js +12 -0
  422. package/dist/esm/modules/excel/utils/ooxml-validator/xml-utils.js +100 -0
  423. package/dist/esm/modules/excel/workbook.browser.js +969 -34
  424. package/dist/esm/modules/excel/workbook.js +48 -0
  425. package/dist/esm/modules/excel/worksheet.js +394 -35
  426. package/dist/esm/modules/excel/xlsx/rel-type.js +41 -1
  427. package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
  428. package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
  429. package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
  430. package/dist/esm/modules/excel/xlsx/xform/chart/chart-space-xform.js +6000 -0
  431. package/dist/esm/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +213 -0
  432. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +150 -11
  433. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
  434. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
  435. package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
  436. package/dist/esm/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +225 -0
  437. package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
  438. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
  439. package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
  440. package/dist/esm/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +441 -0
  441. package/dist/esm/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
  442. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +196 -20
  443. package/dist/esm/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
  444. package/dist/esm/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
  445. package/dist/esm/modules/excel/xlsx/xform/xsd-values.js +101 -0
  446. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +4422 -78
  447. package/dist/esm/modules/pdf/builder/document-builder.js +507 -2
  448. package/dist/esm/modules/pdf/builder/pdf-editor.js +48 -3
  449. package/dist/esm/modules/pdf/excel-bridge.js +683 -12
  450. package/dist/esm/modules/pdf/font/font-manager.js +39 -0
  451. package/dist/esm/modules/pdf/index.js +3 -1
  452. package/dist/esm/modules/pdf/render/chart-surface.js +200 -0
  453. package/dist/esm/modules/pdf/render/layout-engine.js +436 -56
  454. package/dist/esm/modules/pdf/render/page-renderer.js +169 -28
  455. package/dist/esm/modules/pdf/render/pdf-exporter.js +117 -7
  456. package/dist/esm/modules/pdf/types.js +4 -0
  457. package/dist/esm/modules/pdf/word-bridge.js +304 -0
  458. package/dist/esm/modules/word/constants.js +231 -0
  459. package/dist/esm/modules/word/content-types.js +53 -0
  460. package/dist/esm/modules/word/digital-signatures.js +134 -0
  461. package/dist/esm/modules/word/document.js +1795 -0
  462. package/dist/esm/modules/word/docx-packager.js +822 -0
  463. package/dist/esm/modules/word/docx-reader.js +4929 -0
  464. package/dist/esm/modules/word/encryption.js +274 -0
  465. package/dist/esm/modules/word/errors.js +68 -0
  466. package/dist/esm/modules/word/font-obfuscation.js +83 -0
  467. package/dist/esm/modules/word/html-renderer.js +782 -0
  468. package/dist/esm/modules/word/index.base.js +51 -0
  469. package/dist/esm/modules/word/index.browser.js +4 -0
  470. package/dist/esm/modules/word/index.js +4 -0
  471. package/dist/esm/modules/word/internal-utils.js +54 -0
  472. package/dist/esm/modules/word/relationships.js +56 -0
  473. package/dist/esm/modules/word/types.js +10 -0
  474. package/dist/esm/modules/word/units.js +111 -0
  475. package/dist/esm/modules/word/writers/chart-writer.js +385 -0
  476. package/dist/esm/modules/word/writers/checkbox-writer.js +42 -0
  477. package/dist/esm/modules/word/writers/comment-writer.js +70 -0
  478. package/dist/esm/modules/word/writers/document-writer.js +461 -0
  479. package/dist/esm/modules/word/writers/footnote-writer.js +72 -0
  480. package/dist/esm/modules/word/writers/header-footer-writer.js +129 -0
  481. package/dist/esm/modules/word/writers/image-writer.js +185 -0
  482. package/dist/esm/modules/word/writers/math-writer.js +428 -0
  483. package/dist/esm/modules/word/writers/numbering-writer.js +125 -0
  484. package/dist/esm/modules/word/writers/paragraph-writer.js +516 -0
  485. package/dist/esm/modules/word/writers/parts-writer.js +660 -0
  486. package/dist/esm/modules/word/writers/run-writer.js +649 -0
  487. package/dist/esm/modules/word/writers/section-writer.js +238 -0
  488. package/dist/esm/modules/word/writers/styles-writer.js +242 -0
  489. package/dist/esm/modules/word/writers/table-writer.js +503 -0
  490. package/dist/esm/modules/word/writers/textbox-writer.js +53 -0
  491. package/dist/esm/modules/word/writers/toc-writer.js +79 -0
  492. package/dist/esm/modules/xml/encode.js +157 -11
  493. package/dist/iife/excelts.iife.js +11789 -687
  494. package/dist/iife/excelts.iife.js.map +1 -1
  495. package/dist/iife/excelts.iife.min.js +52 -44
  496. package/dist/types/index.browser.d.ts +8 -5
  497. package/dist/types/index.d.ts +4 -2
  498. package/dist/types/modules/excel/chart/cache-populator.d.ts +49 -0
  499. package/dist/types/modules/excel/chart/chart-api.d.ts +92 -0
  500. package/dist/types/modules/excel/chart/chart-builder.d.ts +48 -0
  501. package/dist/types/modules/excel/chart/chart-ex-builder.d.ts +36 -0
  502. package/dist/types/modules/excel/chart/chart-ex-parser.d.ts +8 -0
  503. package/dist/types/modules/excel/chart/chart-ex-renderer.d.ts +187 -0
  504. package/dist/types/modules/excel/chart/chart-ex-types.d.ts +531 -0
  505. package/dist/types/modules/excel/chart/chart-images.d.ts +78 -0
  506. package/dist/types/modules/excel/chart/chart-presets.d.ts +392 -0
  507. package/dist/types/modules/excel/chart/chart-renderer.d.ts +550 -0
  508. package/dist/types/modules/excel/chart/chart-sidecar.d.ts +21 -0
  509. package/dist/types/modules/excel/chart/chart-utils.d.ts +306 -0
  510. package/dist/types/modules/excel/chart/chart.d.ts +504 -0
  511. package/dist/types/modules/excel/chart/glyph-rasterizer.d.ts +62 -0
  512. package/dist/types/modules/excel/chart/index.d.ts +54 -0
  513. package/dist/types/modules/excel/chart/install.d.ts +44 -0
  514. package/dist/types/modules/excel/chart/shape-properties.d.ts +156 -0
  515. package/dist/types/modules/excel/chart/stroke-font.d.ts +36 -0
  516. package/dist/types/modules/excel/chart/topojson.d.ts +98 -0
  517. package/dist/types/modules/excel/chart/types.d.ts +2559 -0
  518. package/dist/types/modules/excel/chart-host-registry.d.ts +157 -0
  519. package/dist/types/modules/excel/chartsheet.d.ts +102 -0
  520. package/dist/types/modules/excel/defined-names.d.ts +35 -0
  521. package/dist/types/modules/excel/errors.d.ts +6 -0
  522. package/dist/types/modules/excel/form-control.d.ts +6 -0
  523. package/dist/types/modules/excel/pivot-chart.d.ts +7 -0
  524. package/dist/types/modules/excel/pivot-table.d.ts +55 -0
  525. package/dist/types/modules/excel/sparkline/index.d.ts +7 -0
  526. package/dist/types/modules/excel/sparkline/sparkline.d.ts +206 -0
  527. package/dist/types/modules/excel/types.d.ts +72 -0
  528. package/dist/types/modules/excel/utils/address.d.ts +18 -0
  529. package/dist/types/modules/excel/utils/guid.d.ts +15 -0
  530. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +74 -0
  531. package/dist/types/modules/excel/utils/ooxml-validator/check-chart-sidecar.d.ts +35 -0
  532. package/dist/types/modules/excel/utils/ooxml-validator/check-chart.d.ts +32 -0
  533. package/dist/types/modules/excel/utils/ooxml-validator/check-chartsheet.d.ts +9 -0
  534. package/dist/types/modules/excel/utils/ooxml-validator/check-content-types.d.ts +16 -0
  535. package/dist/types/modules/excel/utils/ooxml-validator/check-drawing.d.ts +34 -0
  536. package/dist/types/modules/excel/utils/ooxml-validator/check-pivot.d.ts +14 -0
  537. package/dist/types/modules/excel/utils/ooxml-validator/check-relationships.d.ts +18 -0
  538. package/dist/types/modules/excel/utils/ooxml-validator/check-structure.d.ts +21 -0
  539. package/dist/types/modules/excel/utils/ooxml-validator/check-styles.d.ts +15 -0
  540. package/dist/types/modules/excel/utils/ooxml-validator/check-table.d.ts +31 -0
  541. package/dist/types/modules/excel/utils/ooxml-validator/check-workbook.d.ts +19 -0
  542. package/dist/types/modules/excel/utils/ooxml-validator/check-worksheet.d.ts +25 -0
  543. package/dist/types/modules/excel/utils/ooxml-validator/context.d.ts +85 -0
  544. package/dist/types/modules/excel/utils/ooxml-validator/index.d.ts +31 -0
  545. package/dist/types/modules/excel/utils/ooxml-validator/path-utils.d.ts +67 -0
  546. package/dist/types/modules/excel/utils/ooxml-validator/reporter.d.ts +41 -0
  547. package/dist/types/modules/excel/utils/ooxml-validator/types.d.ts +109 -0
  548. package/dist/types/modules/excel/utils/ooxml-validator/xml-utils.d.ts +38 -0
  549. package/dist/types/modules/excel/workbook.browser.d.ts +248 -30
  550. package/dist/types/modules/excel/workbook.d.ts +43 -0
  551. package/dist/types/modules/excel/worksheet.d.ts +157 -3
  552. package/dist/types/modules/excel/xlsx/rel-type.d.ts +40 -0
  553. package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +1 -0
  554. package/dist/types/modules/excel/xlsx/xform/chart/chart-space-xform.d.ts +353 -0
  555. package/dist/types/modules/excel/xlsx/xform/comment/threaded-comments-xform.d.ts +60 -0
  556. package/dist/types/modules/excel/xlsx/xform/drawing/drawing-xform.d.ts +30 -0
  557. package/dist/types/modules/excel/xlsx/xform/drawing/graphic-frame-xform.d.ts +54 -0
  558. package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +3 -1
  559. package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +46 -0
  560. package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +13 -2
  561. package/dist/types/modules/excel/xlsx/xform/sheet/chartsheet-xform.d.ts +185 -0
  562. package/dist/types/modules/excel/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -0
  563. package/dist/types/modules/excel/xlsx/xform/xsd-values.d.ts +63 -0
  564. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +115 -21
  565. package/dist/types/modules/pdf/builder/document-builder.d.ts +74 -0
  566. package/dist/types/modules/pdf/excel-bridge.d.ts +69 -0
  567. package/dist/types/modules/pdf/font/font-manager.d.ts +25 -0
  568. package/dist/types/modules/pdf/index.d.ts +5 -2
  569. package/dist/types/modules/pdf/render/chart-surface.d.ts +33 -0
  570. package/dist/types/modules/pdf/render/layout-engine.d.ts +22 -1
  571. package/dist/types/modules/pdf/types.d.ts +227 -23
  572. package/dist/types/modules/pdf/word-bridge.d.ts +47 -0
  573. package/dist/types/modules/word/constants.d.ts +179 -0
  574. package/dist/types/modules/word/content-types.d.ts +27 -0
  575. package/dist/types/modules/word/digital-signatures.d.ts +87 -0
  576. package/dist/types/modules/word/document.d.ts +728 -0
  577. package/dist/types/modules/word/docx-packager.d.ts +14 -0
  578. package/dist/types/modules/word/docx-reader.d.ts +11 -0
  579. package/dist/types/modules/word/encryption.d.ts +102 -0
  580. package/dist/types/modules/word/errors.d.ts +49 -0
  581. package/dist/types/modules/word/font-obfuscation.d.ts +31 -0
  582. package/dist/types/modules/word/html-renderer.d.ts +38 -0
  583. package/dist/types/modules/word/index.base.d.ts +19 -0
  584. package/dist/types/modules/word/index.browser.d.ts +4 -0
  585. package/dist/types/modules/word/index.d.ts +4 -0
  586. package/dist/types/modules/word/internal-utils.d.ts +23 -0
  587. package/dist/types/modules/word/relationships.d.ts +31 -0
  588. package/dist/types/modules/word/types.d.ts +2325 -0
  589. package/dist/types/modules/word/units.d.ts +49 -0
  590. package/dist/types/modules/word/writers/chart-writer.d.ts +10 -0
  591. package/dist/types/modules/word/writers/checkbox-writer.d.ts +9 -0
  592. package/dist/types/modules/word/writers/comment-writer.d.ts +15 -0
  593. package/dist/types/modules/word/writers/document-writer.d.ts +16 -0
  594. package/dist/types/modules/word/writers/footnote-writer.d.ts +11 -0
  595. package/dist/types/modules/word/writers/header-footer-writer.d.ts +13 -0
  596. package/dist/types/modules/word/writers/image-writer.d.ts +10 -0
  597. package/dist/types/modules/word/writers/math-writer.d.ts +9 -0
  598. package/dist/types/modules/word/writers/numbering-writer.d.ts +10 -0
  599. package/dist/types/modules/word/writers/paragraph-writer.d.ts +13 -0
  600. package/dist/types/modules/word/writers/parts-writer.d.ts +26 -0
  601. package/dist/types/modules/word/writers/run-writer.d.ts +15 -0
  602. package/dist/types/modules/word/writers/section-writer.d.ts +10 -0
  603. package/dist/types/modules/word/writers/styles-writer.d.ts +10 -0
  604. package/dist/types/modules/word/writers/table-writer.d.ts +10 -0
  605. package/dist/types/modules/word/writers/textbox-writer.d.ts +9 -0
  606. package/dist/types/modules/word/writers/toc-writer.d.ts +9 -0
  607. package/dist/types/modules/xml/encode.d.ts +56 -7
  608. package/package.json +29 -11
  609. package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +0 -48
  610. package/dist/browser/modules/excel/utils/ooxml-validator.js +0 -493
  611. package/dist/browser/modules/excel/utils/passthrough-manager.d.ts +0 -77
  612. package/dist/browser/modules/excel/utils/passthrough-manager.js +0 -129
  613. package/dist/cjs/modules/excel/utils/ooxml-validator.js +0 -499
  614. package/dist/cjs/modules/excel/utils/passthrough-manager.js +0 -133
  615. package/dist/esm/modules/excel/utils/ooxml-validator.js +0 -493
  616. package/dist/esm/modules/excel/utils/passthrough-manager.js +0 -129
  617. package/dist/types/modules/excel/utils/ooxml-validator.d.ts +0 -48
  618. package/dist/types/modules/excel/utils/passthrough-manager.d.ts +0 -77
@@ -0,0 +1,2432 @@
1
+ /**
2
+ * Chart Builder - Constructs a ChartModel from simplified AddChartOptions.
3
+ *
4
+ * This bridges the high-level API (worksheet.addChart) to the full
5
+ * OOXML chart model that the XForm layer serialises.
6
+ */
7
+ import { ChartOptionsError } from "../errors.js";
8
+ import { escapeXml } from "./chart-utils.js";
9
+ const EMU_PER_POINT = 12700;
10
+ const DEFAULT_AXIS_START_ID = 100000000;
11
+ const AXIS_CHART_TYPES = new Set([
12
+ "bar",
13
+ "bar3D",
14
+ "line",
15
+ "line3D",
16
+ "area",
17
+ "area3D",
18
+ "scatter",
19
+ "bubble",
20
+ "radar",
21
+ "stock",
22
+ "surface",
23
+ "surface3D"
24
+ ]);
25
+ const NO_TRENDLINE_CHART_TYPES = new Set([
26
+ "pie",
27
+ "pie3D",
28
+ "doughnut",
29
+ "ofPie",
30
+ "surface",
31
+ "surface3D"
32
+ ]);
33
+ const PIE_FAMILY_CHART_TYPES = new Set([
34
+ "pie",
35
+ "pie3D",
36
+ "doughnut",
37
+ "ofPie"
38
+ ]);
39
+ /**
40
+ * Valid `c:dLblPos` values Excel accepts per chart type.
41
+ *
42
+ * Although ECMA-376 `ST_DLblPos` technically allows any of the nine
43
+ * values (`b | bestFit | ctr | inBase | inEnd | l | outEnd | r | t`)
44
+ * on any `c:dLbl` / `c:dLbls` element, Excel's reader is stricter:
45
+ * emitting a value outside the per-chart-type allow-list below
46
+ * triggers "Repaired Records: Drawing" warnings on open, and for
47
+ * doughnut charts the offending `drawing*.xml` part is stripped
48
+ * entirely ("Removed Part"). The allow-lists match the options
49
+ * surfaced by Excel 365's "Format Data Labels → Label Position"
50
+ * panel, which is the canonical UI reference.
51
+ *
52
+ * - `doughnut`: Excel's UI exposes no position choices at all, and
53
+ * any `c:dLblPos` in a doughnut chart's `c:dLbls` causes the
54
+ * entire drawing part to be removed on open. Use an empty list so
55
+ * the validator rejects every value.
56
+ * - `bar` / `bar3D`: `inBase` is unique to bar — it anchors the
57
+ * label to the axis end of a column, useful for negative values.
58
+ * - `pie`, `pie3D`, `ofPie`: share the pie label set. `bestFit` is
59
+ * Excel's default and the only value that lets Excel place labels
60
+ * automatically with leader lines.
61
+ * - `line` / `line3D` / `scatter` / `bubble` / `radar` / `stock`:
62
+ * share the cartesian label set (above / below / left / right /
63
+ * center).
64
+ * - `area` / `area3D`: Excel only accepts `ctr` for area fills.
65
+ * - `surface` / `surface3D`: data labels are already rejected
66
+ * wholesale by `validateChartLevelOptions`.
67
+ */
68
+ const VALID_DLBL_POSITIONS_BY_TYPE = {
69
+ bar: new Set(["ctr", "inBase", "inEnd", "outEnd"]),
70
+ bar3D: new Set(["ctr", "inBase", "inEnd", "outEnd"]),
71
+ line: new Set(["ctr", "l", "r", "t", "b"]),
72
+ line3D: new Set(["ctr", "l", "r", "t", "b"]),
73
+ scatter: new Set(["ctr", "l", "r", "t", "b"]),
74
+ bubble: new Set(["ctr", "l", "r", "t", "b"]),
75
+ radar: new Set(["ctr", "l", "r", "t", "b"]),
76
+ stock: new Set(["ctr", "l", "r", "t", "b"]),
77
+ pie: new Set(["bestFit", "ctr", "inEnd", "outEnd"]),
78
+ pie3D: new Set(["bestFit", "ctr", "inEnd", "outEnd"]),
79
+ ofPie: new Set(["bestFit", "ctr", "inEnd", "outEnd"]),
80
+ doughnut: new Set(),
81
+ area: new Set(["ctr"]),
82
+ area3D: new Set(["ctr"])
83
+ };
84
+ /**
85
+ * Simple axis ID allocator — scoped per buildChartModel call.
86
+ * Axis IDs only need to be unique within a single chart.
87
+ */
88
+ class AxIdAllocator {
89
+ constructor(start = DEFAULT_AXIS_START_ID) {
90
+ this.next = start;
91
+ }
92
+ alloc() {
93
+ return this.next++;
94
+ }
95
+ }
96
+ function makeNumRef(formula) {
97
+ return { formula, cache: { points: [] } };
98
+ }
99
+ function makeStrRef(formula) {
100
+ return { formula, cache: { points: [] } };
101
+ }
102
+ function makeNumData(formula) {
103
+ return { numRef: makeNumRef(formula) };
104
+ }
105
+ function makeCatData(formula) {
106
+ return { strRef: makeStrRef(formula) };
107
+ }
108
+ function makeAxisData(input) {
109
+ return typeof input === "string" ? makeCatData(input) : input;
110
+ }
111
+ function makeNumericAxisData(input) {
112
+ return typeof input === "string" ? { numRef: makeNumRef(input) } : input;
113
+ }
114
+ /**
115
+ * Wrap a scatter/bubble `xValues` input as the appropriate
116
+ * {@link AxisDataSource}. `xValueType` disambiguates the two OOXML
117
+ * spellings:
118
+ *
119
+ * - `"number"` (default) → `numRef` — standard scatter usage
120
+ * - `"text"` → `strRef` — labelled scatter / bubble with
121
+ * categorical x axis (Excel renders it as evenly-spaced labels)
122
+ *
123
+ * When the caller passes a pre-built `AxisDataSource`, the hint is
124
+ * ignored — the structure already carries the intent.
125
+ */
126
+ function makeXAxisData(input, xValueType) {
127
+ if (typeof input !== "string") {
128
+ return input;
129
+ }
130
+ return xValueType === "text" ? makeCatData(input) : makeNumericAxisData(input);
131
+ }
132
+ function assertChartOptions(condition, message) {
133
+ if (!condition) {
134
+ throw new ChartOptionsError(message);
135
+ }
136
+ }
137
+ function assertFiniteNumber(value, path) {
138
+ assertChartOptions(typeof value === "number" && Number.isFinite(value), `${path} must be a finite number.`);
139
+ }
140
+ function assertIntegerInRange(value, path, min, max) {
141
+ assertFiniteNumber(value, path);
142
+ assertChartOptions(Number.isInteger(value) && value >= min && value <= max, `${path} must be an integer between ${min} and ${max}.`);
143
+ }
144
+ function assertNumberInRange(value, path, min, max) {
145
+ assertFiniteNumber(value, path);
146
+ assertChartOptions(value >= min && value <= max, `${path} must be between ${min} and ${max}.`);
147
+ }
148
+ function validateChartOptions(opts, path = "chart") {
149
+ assertChartOptions(!!opts && typeof opts === "object", `${path} options are required.`);
150
+ assertChartOptions(!!opts.type, `${path}.type is required.`);
151
+ validateChartLevelOptions(opts, path);
152
+ const series = opts.series ?? [];
153
+ // A chart with zero series is invalid — Excel will either refuse to
154
+ // open the file or render a broken chart area. Catch it at build
155
+ // time with a precise error instead of deferring to Excel.
156
+ assertChartOptions(series.length > 0, `${path}.series must contain at least one series.`);
157
+ for (let i = 0; i < series.length; i++) {
158
+ validateSeriesOptions(opts.type, series[i], `${path}.series[${i}]`);
159
+ }
160
+ }
161
+ function validateComboChartOptions(opts) {
162
+ assertChartOptions(!!opts && typeof opts === "object", "combo chart options are required.");
163
+ assertChartOptions(Array.isArray(opts.groups) && opts.groups.length > 0, "combo chart groups must contain at least one group.");
164
+ for (let i = 0; i < opts.groups.length; i++) {
165
+ validateChartOptions(opts.groups[i], `groups[${i}]`);
166
+ }
167
+ validateSharedChartOptions(opts, "combo chart");
168
+ }
169
+ function validateChartLevelOptions(opts, path) {
170
+ validateSharedChartOptions(opts, path);
171
+ if (opts.grouping !== undefined) {
172
+ assertChartOptions(opts.type === "bar" ||
173
+ opts.type === "bar3D" ||
174
+ opts.type === "line" ||
175
+ opts.type === "line3D" ||
176
+ opts.type === "area" ||
177
+ opts.type === "area3D", `${path}.grouping is only valid for bar, line, and area charts.`);
178
+ // `BarGrouping` and `LineGrouping` overlap on stacked/percentStacked but
179
+ // diverge on `clustered` (bar only) and `standard` (line/area only).
180
+ // Reject the wrong-family value up front instead of silently emitting
181
+ // invalid OOXML.
182
+ const g = opts.grouping;
183
+ if (opts.type === "bar" || opts.type === "bar3D") {
184
+ assertChartOptions(g === "clustered" || g === "stacked" || g === "percentStacked", `${path}.grouping=${JSON.stringify(g)} is not valid for bar charts (use "clustered" | "stacked" | "percentStacked").`);
185
+ }
186
+ else {
187
+ assertChartOptions(g === "standard" || g === "stacked" || g === "percentStacked", `${path}.grouping=${JSON.stringify(g)} is not valid for ${opts.type} charts (use "standard" | "stacked" | "percentStacked").`);
188
+ }
189
+ }
190
+ if (opts.barDir !== undefined) {
191
+ assertChartOptions(opts.type === "bar" || opts.type === "bar3D", `${path}.barDir is only valid for bar and bar3D charts.`);
192
+ }
193
+ if (opts.scatterStyle !== undefined) {
194
+ assertChartOptions(opts.type === "scatter", `${path}.scatterStyle is only valid for scatter charts.`);
195
+ }
196
+ if (opts.radarStyle !== undefined) {
197
+ assertChartOptions(opts.type === "radar", `${path}.radarStyle is only valid for radar charts.`);
198
+ }
199
+ if (opts.ofPieType !== undefined) {
200
+ assertChartOptions(opts.type === "ofPie", `${path}.ofPieType is only valid for ofPie charts.`);
201
+ }
202
+ if (opts.wireframe !== undefined) {
203
+ assertChartOptions(opts.type === "surface" || opts.type === "surface3D", `${path}.wireframe is only valid for surface and surface3D charts.`);
204
+ }
205
+ if (opts.bandFormats !== undefined) {
206
+ assertChartOptions(opts.type === "surface" || opts.type === "surface3D", `${path}.bandFormats is only valid for surface and surface3D charts.`);
207
+ for (let i = 0; i < opts.bandFormats.length; i++) {
208
+ assertIntegerInRange(opts.bandFormats[i].index, `${path}.bandFormats[${i}].index`, 0, Number.MAX_SAFE_INTEGER);
209
+ }
210
+ }
211
+ if (!AXIS_CHART_TYPES.has(opts.type)) {
212
+ assertChartOptions(opts.categoryAxis === undefined, `${path}.categoryAxis is not valid for ${opts.type} charts because they do not have axes.`);
213
+ assertChartOptions(opts.valueAxis === undefined, `${path}.valueAxis is not valid for ${opts.type} charts because they do not have axes.`);
214
+ }
215
+ if ((opts.type === "surface" || opts.type === "surface3D") && opts.dataLabels !== undefined) {
216
+ assertChartOptions(false, `${path}.dataLabels is not supported for surface charts.`);
217
+ }
218
+ if (opts.dataLabels) {
219
+ // Chart-level data labels mirror the series-level ones at the
220
+ // `CT_*Chart/c:dLbls` slot (e.g. `CT_BarChart/c:dLbls`). Excel
221
+ // applies the same per-chart-type restrictions on `c:dLblPos`
222
+ // at this level, so run the same validator here.
223
+ validateDataLabelsOptions(opts.type, opts.dataLabels, `${path}.dataLabels`);
224
+ }
225
+ if (opts.holeSize !== undefined) {
226
+ assertChartOptions(opts.type === "doughnut", `${path}.holeSize is only valid for doughnut charts.`);
227
+ assertIntegerInRange(opts.holeSize, `${path}.holeSize`, 0, 90);
228
+ }
229
+ if (opts.firstSliceAng !== undefined) {
230
+ assertChartOptions(PIE_FAMILY_CHART_TYPES.has(opts.type), `${path}.firstSliceAng is only valid for pie, doughnut, and ofPie charts.`);
231
+ assertIntegerInRange(opts.firstSliceAng, `${path}.firstSliceAng`, 0, 360);
232
+ }
233
+ if (opts.gapWidth !== undefined) {
234
+ assertChartOptions(opts.type === "bar" || opts.type === "bar3D" || opts.type === "ofPie", `${path}.gapWidth is only valid for bar, bar3D, and ofPie charts.`);
235
+ assertIntegerInRange(opts.gapWidth, `${path}.gapWidth`, 0, 500);
236
+ }
237
+ if (opts.gapDepth !== undefined) {
238
+ // `c:gapDepth` is only declared on the 3-D chart types'
239
+ // `CT_*3DChart` definitions (bar3D, line3D, area3D). `pie3D`
240
+ // does NOT have it despite the type being 3-D.
241
+ assertChartOptions(opts.type === "bar3D" || opts.type === "line3D" || opts.type === "area3D", `${path}.gapDepth is only valid for bar3D, line3D, and area3D charts.`);
242
+ assertIntegerInRange(opts.gapDepth, `${path}.gapDepth`, 0, 500);
243
+ }
244
+ if (opts.overlap !== undefined) {
245
+ // `c:overlap` belongs to `CT_BarChart` only — `CT_Bar3DChart`
246
+ // omits it. The writer rejects it on bar3D (see
247
+ // `buildChartTypeGroup:case "bar3D"`); keep the two in sync so
248
+ // the rejection surfaces here at authoring time with a
249
+ // consistent error.
250
+ assertChartOptions(opts.type === "bar", `${path}.overlap is only valid for 2-D bar charts (bar3D rejects overlap per CT_Bar3DChart).`);
251
+ assertIntegerInRange(opts.overlap, `${path}.overlap`, -100, 100);
252
+ }
253
+ if (opts.bubbleScale !== undefined) {
254
+ assertChartOptions(opts.type === "bubble", `${path}.bubbleScale is only valid for bubble charts.`);
255
+ assertIntegerInRange(opts.bubbleScale, `${path}.bubbleScale`, 0, 300);
256
+ }
257
+ if (opts.showNegBubbles !== undefined) {
258
+ assertChartOptions(opts.type === "bubble", `${path}.showNegBubbles is only valid for bubble charts.`);
259
+ }
260
+ if (opts.sizeRepresents !== undefined) {
261
+ assertChartOptions(opts.type === "bubble", `${path}.sizeRepresents is only valid for bubble charts.`);
262
+ }
263
+ if (opts.splitPos !== undefined) {
264
+ assertChartOptions(opts.type === "ofPie", `${path}.splitPos is only valid for ofPie charts.`);
265
+ assertFiniteNumber(opts.splitPos, `${path}.splitPos`);
266
+ }
267
+ if (opts.secondPieSize !== undefined) {
268
+ assertChartOptions(opts.type === "ofPie", `${path}.secondPieSize is only valid for ofPie charts.`);
269
+ assertIntegerInRange(opts.secondPieSize, `${path}.secondPieSize`, 5, 200);
270
+ }
271
+ if (opts.shape !== undefined) {
272
+ assertChartOptions(opts.type === "bar3D", `${path}.shape is only valid for bar3D charts.`);
273
+ }
274
+ if (opts.showMarker !== undefined) {
275
+ assertChartOptions(opts.type === "line" || opts.type === "radar", `${path}.showMarker is only valid for line and radar charts (line3D does not support markers).`);
276
+ }
277
+ if (opts.smooth !== undefined) {
278
+ assertChartOptions(opts.type === "line" || opts.type === "scatter", `${path}.smooth is only valid for line and scatter charts (line3D does not support smooth).`);
279
+ }
280
+ if (opts.hiLowLines !== undefined) {
281
+ assertChartOptions(opts.type === "line" || opts.type === "stock", `${path}.hiLowLines is only valid for line and stock charts (line3D does not support hiLowLines).`);
282
+ }
283
+ if (opts.upDownBars !== undefined) {
284
+ assertChartOptions(opts.type === "line" || opts.type === "stock", `${path}.upDownBars is only valid for line and stock charts (line3D does not support upDownBars).`);
285
+ }
286
+ if (opts.dropLines !== undefined) {
287
+ assertChartOptions(opts.type === "line" ||
288
+ opts.type === "line3D" ||
289
+ opts.type === "area" ||
290
+ opts.type === "area3D" ||
291
+ opts.type === "stock", `${path}.dropLines is only valid for line, area, and stock charts.`);
292
+ }
293
+ if (opts.serLines !== undefined) {
294
+ assertChartOptions(opts.type === "bar" || opts.type === "ofPie", `${path}.serLines is only valid for bar and ofPie charts.`);
295
+ }
296
+ validateAxisOptions(opts.categoryAxis, `${path}.categoryAxis`);
297
+ validateAxisOptions(opts.valueAxis, `${path}.valueAxis`);
298
+ }
299
+ function validateSharedChartOptions(opts, path) {
300
+ if (opts.style !== undefined) {
301
+ assertIntegerInRange(opts.style, `${path}.style`, 1, 48);
302
+ }
303
+ }
304
+ function validateSeriesOptions(chartType, opts, path, flags = {}) {
305
+ const allowMissingRefs = flags.allowMissingRefs === true;
306
+ assertChartOptions(!!opts && typeof opts === "object", `${path} must be an object.`);
307
+ if (allowMissingRefs) {
308
+ if (opts.values !== undefined) {
309
+ assertChartOptions(typeof opts.values === "string" && opts.values.length > 0, `${path}.values must be a non-empty formula string.`);
310
+ }
311
+ }
312
+ else {
313
+ assertChartOptions(typeof opts.values === "string" && opts.values.length > 0, `${path}.values is required and must be a non-empty formula string.`);
314
+ }
315
+ if (opts.trendline !== undefined) {
316
+ assertChartOptions(!NO_TRENDLINE_CHART_TYPES.has(chartType), `${path}.trendline is not valid for ${chartType} charts.`);
317
+ const trendlines = Array.isArray(opts.trendline) ? opts.trendline : [opts.trendline];
318
+ for (let i = 0; i < trendlines.length; i++) {
319
+ validateTrendlineOptions(trendlines[i], `${path}.trendline${trendlines.length > 1 ? `[${i}]` : ""}`);
320
+ }
321
+ }
322
+ if (opts.marker?.size !== undefined) {
323
+ assertIntegerInRange(opts.marker.size, `${path}.marker.size`, 2, 72);
324
+ }
325
+ if (opts.explosion !== undefined) {
326
+ assertChartOptions(PIE_FAMILY_CHART_TYPES.has(chartType), `${path}.explosion is only valid for pie, doughnut, and ofPie charts.`);
327
+ assertIntegerInRange(opts.explosion, `${path}.explosion`, 0, 400);
328
+ }
329
+ if (opts.bubble3D !== undefined) {
330
+ assertChartOptions(chartType === "bubble", `${path}.bubble3D is only valid for bubble charts.`);
331
+ }
332
+ if (opts.bubbleSize !== undefined) {
333
+ assertChartOptions(chartType === "bubble", `${path}.bubbleSize is only valid for bubble charts.`);
334
+ }
335
+ if (chartType === "bubble" && !allowMissingRefs) {
336
+ assertChartOptions(opts.xValues !== undefined, `${path}.xValues is required for bubble charts. Use a numeric range for x-values.`);
337
+ assertChartOptions(opts.bubbleSize !== undefined, `${path}.bubbleSize is required for bubble charts. Use a numeric range for bubble sizes.`);
338
+ }
339
+ if (chartType === "scatter" && !allowMissingRefs) {
340
+ assertChartOptions(opts.xValues !== undefined, `${path}.xValues is required for scatter charts. Use a numeric range for x-values.`);
341
+ }
342
+ if (opts.xValues !== undefined) {
343
+ assertChartOptions(chartType === "scatter" || chartType === "bubble", `${path}.xValues is only valid for scatter and bubble charts.`);
344
+ }
345
+ // Note on `categories` for scatter / bubble: the field has no direct
346
+ // home on `ScatterSeries` / `BubbleSeries`, which use `xVal` for the
347
+ // numeric X axis. `buildScatterSeries` / `buildBubbleSeries` silently
348
+ // ignore `opts.categories` at create time (the `xVal` slot is already
349
+ // populated from `opts.xValues`). On the patch path
350
+ // (`applyChartSeriesOptionsPatch`), `options.categories` is routed to
351
+ // `xVal` so callers can switch a scatter's X source to a text axis
352
+ // via `{ categories, xValueType: "text" }`. Accepting the field on
353
+ // creation preserves API symmetry (users can pass the same option
354
+ // bundle across chart types in test fixtures) at the cost of a silent
355
+ // drop for this specific combination.
356
+ if (opts.dataPoints) {
357
+ for (let i = 0; i < opts.dataPoints.length; i++) {
358
+ validateDataPointOptions(chartType, opts.dataPoints[i], `${path}.dataPoints[${i}]`);
359
+ }
360
+ }
361
+ if (opts.dataLabels) {
362
+ validateDataLabelsOptions(chartType, opts.dataLabels, `${path}.dataLabels`);
363
+ }
364
+ if (opts.errorBars) {
365
+ assertChartOptions(!PIE_FAMILY_CHART_TYPES.has(chartType), `${path}.errorBars is not valid for ${chartType} charts.`);
366
+ const errorBars = Array.isArray(opts.errorBars) ? opts.errorBars : [opts.errorBars];
367
+ // Non-scatter/bubble series only support a single error-bar configuration
368
+ // (`ErrorBars`, not an array). Fail fast rather than silently keep only
369
+ // `errorBars[0]` and discard the rest.
370
+ if (Array.isArray(opts.errorBars) &&
371
+ opts.errorBars.length > 1 &&
372
+ chartType !== "scatter" &&
373
+ chartType !== "bubble") {
374
+ assertChartOptions(false, `${path}.errorBars must be a single configuration for ${chartType} charts; arrays are only valid for scatter and bubble.`);
375
+ }
376
+ // Scatter / bubble: CT_ScatterSer / CT_BubbleSer declare
377
+ // `errBars` as `maxOccurs="2"` — one X, one Y. Allowing more
378
+ // than two (or two with the same `c:errDir`) is an OOXML schema
379
+ // violation and causes Excel to repair the chart on open,
380
+ // silently dropping the extras. Fail the author up-front so
381
+ // mistakes like passing an array of "every error-bar type" on a
382
+ // single series are caught rather than producing a file that
383
+ // prompts a repair dialog.
384
+ if ((chartType === "scatter" || chartType === "bubble") &&
385
+ Array.isArray(opts.errorBars) &&
386
+ opts.errorBars.length > 2) {
387
+ assertChartOptions(false, `${path}.errorBars allows at most 2 entries on ${chartType} charts (one for direction "x", one for "y"). Split additional configurations across separate series.`);
388
+ }
389
+ if ((chartType === "scatter" || chartType === "bubble") &&
390
+ Array.isArray(opts.errorBars) &&
391
+ opts.errorBars.length === 2) {
392
+ const d0 = opts.errorBars[0]?.direction;
393
+ const d1 = opts.errorBars[1]?.direction;
394
+ assertChartOptions(d0 !== undefined && d1 !== undefined && d0 !== d1, `${path}.errorBars must use distinct directions ("x" and "y") when providing two entries on ${chartType} charts.`);
395
+ }
396
+ for (let i = 0; i < errorBars.length; i++) {
397
+ validateErrorBarsOptions(errorBars[i], `${path}.errorBars${errorBars.length > 1 ? `[${i}]` : ""}`);
398
+ }
399
+ }
400
+ }
401
+ function validateSeriesPatchOptions(chartType, opts, path) {
402
+ // Patch path: unlike series-creation validation we accept a partial
403
+ // options bag with no `values` / `xValues` / `bubbleSize`. The
404
+ // `allowMissingRefs` flag short-circuits the "required" assertions so we
405
+ // don't need to inject placeholder strings (previous implementation used
406
+ // an `__excelts_placeholder__` sentinel that would have triggered false
407
+ // positives if `values` ever gained a content-level check).
408
+ validateSeriesOptions(chartType, opts, path, { allowMissingRefs: true });
409
+ }
410
+ function validateDataPointOptions(chartType, opts, path) {
411
+ assertIntegerInRange(opts.index, `${path}.index`, 0, Number.MAX_SAFE_INTEGER);
412
+ if (opts.explosion !== undefined) {
413
+ assertChartOptions(PIE_FAMILY_CHART_TYPES.has(chartType), `${path}.explosion is only valid for pie, doughnut, and ofPie charts.`);
414
+ assertIntegerInRange(opts.explosion, `${path}.explosion`, 0, 400);
415
+ }
416
+ if (opts.marker?.size !== undefined) {
417
+ assertIntegerInRange(opts.marker.size, `${path}.marker.size`, 2, 72);
418
+ }
419
+ }
420
+ function validateTrendlineOptions(opts, path) {
421
+ assertChartOptions(!!opts && typeof opts === "object", `${path} must be an object.`);
422
+ assertChartOptions(!!opts.type, `${path}.type is required.`);
423
+ if (opts.type === "poly") {
424
+ assertIntegerInRange(opts.order, `${path}.order`, 2, 6);
425
+ }
426
+ else {
427
+ assertChartOptions(opts.order === undefined, `${path}.order is only valid for polynomial trendlines.`);
428
+ }
429
+ if (opts.type === "movingAvg") {
430
+ assertIntegerInRange(opts.period, `${path}.period`, 2, Number.MAX_SAFE_INTEGER);
431
+ }
432
+ else {
433
+ // `period` is only meaningful for moving-average trendlines (Excel
434
+ // silently ignores it on other types, which quickly devolves into
435
+ // phantom config bugs). Match the stricter `order` handling above.
436
+ assertChartOptions(opts.period === undefined, `${path}.period is only valid for movingAvg trendlines.`);
437
+ }
438
+ if (opts.forward !== undefined) {
439
+ assertNumberInRange(opts.forward, `${path}.forward`, 0, Number.MAX_SAFE_INTEGER);
440
+ }
441
+ if (opts.backward !== undefined) {
442
+ assertNumberInRange(opts.backward, `${path}.backward`, 0, Number.MAX_SAFE_INTEGER);
443
+ }
444
+ }
445
+ function validateErrorBarsOptions(opts, path) {
446
+ assertChartOptions(!!opts && typeof opts === "object", `${path} must be an object.`);
447
+ assertChartOptions(!!opts.type, `${path}.type is required.`);
448
+ if (opts.type === "cust") {
449
+ assertChartOptions(!!opts.plus && !!opts.minus, `${path}.plus and ${path}.minus are required when type is "cust".`);
450
+ }
451
+ else {
452
+ assertChartOptions(opts.plus === undefined && opts.minus === undefined, `${path}.plus and ${path}.minus are only valid when type is "cust".`);
453
+ }
454
+ if (opts.value !== undefined) {
455
+ assertNumberInRange(opts.value, `${path}.value`, 0, Number.MAX_SAFE_INTEGER);
456
+ }
457
+ }
458
+ /**
459
+ * Ensure every `dLblPos` value (group-level and per-entry overrides)
460
+ * is one that Excel will accept for the chart type — see the
461
+ * rationale on {@link VALID_DLBL_POSITIONS_BY_TYPE}. Writing an
462
+ * invalid position causes Excel to flag the drawing as corrupted
463
+ * ("Repaired Records" / "Removed Part") even though the OOXML
464
+ * schema would technically accept it.
465
+ *
466
+ * Rejects at author time so the caller gets a pointer to the exact
467
+ * offending field rather than debugging a Removed Part dialog.
468
+ */
469
+ function validateDataLabelsOptions(chartType, opts, path) {
470
+ const allowed = VALID_DLBL_POSITIONS_BY_TYPE[chartType];
471
+ const describeAllowed = () => {
472
+ if (!allowed) {
473
+ return "(unknown chart type)";
474
+ }
475
+ if (allowed.size === 0) {
476
+ return `(${chartType} does not support c:dLblPos — Excel rejects any value)`;
477
+ }
478
+ return [...allowed].sort().join(", ");
479
+ };
480
+ if (opts.position !== undefined) {
481
+ assertChartOptions(!!allowed && allowed.has(opts.position), `${path}.position="${opts.position}" is not valid for ${chartType} charts. Allowed: ${describeAllowed()}.`);
482
+ }
483
+ if (opts.entries) {
484
+ for (let i = 0; i < opts.entries.length; i++) {
485
+ const entry = opts.entries[i];
486
+ if (entry?.position !== undefined) {
487
+ assertChartOptions(!!allowed && allowed.has(entry.position), `${path}.entries[${i}].position="${entry.position}" is not valid for ${chartType} charts. Allowed: ${describeAllowed()}.`);
488
+ }
489
+ }
490
+ }
491
+ }
492
+ function validateAxisOptions(opts, path) {
493
+ if (!opts) {
494
+ return;
495
+ }
496
+ if (opts.min !== undefined) {
497
+ assertFiniteNumber(opts.min, `${path}.min`);
498
+ }
499
+ if (opts.max !== undefined) {
500
+ assertFiniteNumber(opts.max, `${path}.max`);
501
+ }
502
+ if (opts.min !== undefined && opts.max !== undefined) {
503
+ assertChartOptions(opts.min < opts.max, `${path}.min must be less than ${path}.max.`);
504
+ }
505
+ if (opts.majorUnit !== undefined) {
506
+ assertNumberInRange(opts.majorUnit, `${path}.majorUnit`, 0, Number.MAX_SAFE_INTEGER);
507
+ assertChartOptions(opts.majorUnit > 0, `${path}.majorUnit must be greater than 0.`);
508
+ }
509
+ if (opts.minorUnit !== undefined) {
510
+ assertNumberInRange(opts.minorUnit, `${path}.minorUnit`, 0, Number.MAX_SAFE_INTEGER);
511
+ assertChartOptions(opts.minorUnit > 0, `${path}.minorUnit must be greater than 0.`);
512
+ }
513
+ if (opts.majorUnit !== undefined && opts.minorUnit !== undefined) {
514
+ assertChartOptions(opts.minorUnit <= opts.majorUnit, `${path}.minorUnit must be less than or equal to ${path}.majorUnit.`);
515
+ }
516
+ if (opts.logBase !== undefined) {
517
+ assertNumberInRange(opts.logBase, `${path}.logBase`, 2, 1000);
518
+ }
519
+ if (opts.textRotation !== undefined) {
520
+ assertIntegerInRange(opts.textRotation, `${path}.textRotation`, -90, 90);
521
+ }
522
+ if (opts.lblOffset !== undefined) {
523
+ assertIntegerInRange(opts.lblOffset, `${path}.lblOffset`, 0, 1000);
524
+ }
525
+ if (opts.tickLblSkip !== undefined) {
526
+ assertIntegerInRange(opts.tickLblSkip, `${path}.tickLblSkip`, 1, Number.MAX_SAFE_INTEGER);
527
+ }
528
+ if (opts.tickMarkSkip !== undefined) {
529
+ assertIntegerInRange(opts.tickMarkSkip, `${path}.tickMarkSkip`, 1, Number.MAX_SAFE_INTEGER);
530
+ }
531
+ if (opts.crossesAt !== undefined) {
532
+ assertFiniteNumber(opts.crossesAt, `${path}.crossesAt`);
533
+ }
534
+ if (opts.customUnit !== undefined) {
535
+ assertNumberInRange(opts.customUnit, `${path}.customUnit`, 0, Number.MAX_SAFE_INTEGER);
536
+ assertChartOptions(opts.customUnit > 0, `${path}.customUnit must be greater than 0.`);
537
+ }
538
+ }
539
+ /**
540
+ * Normalise a user-facing hex colour into a structured {@link ChartColor}.
541
+ * Accepts `"#RRGGBB"` / `"RRGGBB"` and the optional 8-digit
542
+ * `"RRGGBBAA"` form. The alpha byte, when present, is decoded into
543
+ * `color.alpha` on the OOXML 0–100000 scale (0 = fully transparent,
544
+ * 100000 = fully opaque) rather than discarded. Throws
545
+ * `ChartOptionsError` when the input is not a valid hex triplet so the
546
+ * caller sees the mistake at the assignment site rather than via a
547
+ * downstream XML parser rejection.
548
+ */
549
+ export function hexToColor(hex) {
550
+ const cleaned = hex.replace(/^#/, "").toUpperCase();
551
+ if (!/^[0-9A-F]{6}([0-9A-F]{2})?$/.test(cleaned)) {
552
+ throw new ChartOptionsError(`Invalid hex colour: ${JSON.stringify(hex)}. Expected 6-digit (or 8-digit with alpha) hex like "#FF0000".`);
553
+ }
554
+ const color = { srgb: cleaned.slice(0, 6) };
555
+ if (cleaned.length === 8) {
556
+ // 8-digit form: trailing 2 bytes encode alpha on the 0–255 scale.
557
+ // `ChartColor.alpha` stores OOXML's 0–100000 integer; convert and
558
+ // round so the wire value is an integer, matching Excel's output.
559
+ const alphaByte = parseInt(cleaned.slice(6, 8), 16);
560
+ color.alpha = Math.round((alphaByte / 255) * 100000);
561
+ }
562
+ return color;
563
+ }
564
+ /**
565
+ * Escape XML text content while stripping characters forbidden by
566
+ * XML 1.0. Without the strip step, a chart built from user input
567
+ * containing `\b` / `\f` / other C0 control characters would produce
568
+ * an XML-invalid `<c:v>` or `<c:f>` payload that strict readers
569
+ * refuse to parse. Preserved: `\t`, `\n`, `\r` (the only C0 chars
570
+ * XML 1.0 allows in content).
571
+ */
572
+ function buildPivotSourceXml(source) {
573
+ const name = typeof source === "string" ? source : source.name;
574
+ const fmtId = typeof source === "string" ? 0 : (source.fmtId ?? 0);
575
+ if (!name) {
576
+ throw new ChartOptionsError("Pivot chart source name is required.");
577
+ }
578
+ if (!Number.isInteger(fmtId) || fmtId < 0) {
579
+ throw new ChartOptionsError("Pivot chart source fmtId must be a non-negative integer.");
580
+ }
581
+ // Pivot chart options used to be embedded inside `<c:pivotSource>` under a
582
+ // private `xmlns:excelts` namespace; Excel never recognised that and the
583
+ // parser never read it back. Options are now routed into
584
+ // `ChartModel.pivotOptions` (see {@link ChartModel.pivotOptions}) and
585
+ // serialised as MS standard `c14:pivotOptions` inside chartSpace's extLst.
586
+ return `<c:pivotSource><c:name>${escapeXml(name)}</c:name><c:fmtId val="${fmtId}"/></c:pivotSource>`;
587
+ }
588
+ /**
589
+ * Convert a simplified AddShapeFillOptions (or a pre-built ShapeProperties)
590
+ * into a structured ShapeProperties object. Returns undefined when input is
591
+ * undefined.
592
+ */
593
+ /**
594
+ * Normalise a user-facing shape-fill option bundle (hex-string fill,
595
+ * hex-string border, borderWidth in points, gradient, pattern, …) into a
596
+ * structured {@link ShapeProperties}. Passes through already-structured
597
+ * shapes unchanged so callers can mix the two forms freely.
598
+ *
599
+ * Exported so `chart-ex-builder` can reuse the exact same normalisation
600
+ * for ChartEx `spPr` options — previously ChartEx only accepted the
601
+ * fully-structured form, which was an API asymmetry.
602
+ */
603
+ export function toShapeProperties(input) {
604
+ if (!input) {
605
+ return undefined;
606
+ }
607
+ // If it already looks like a ShapeProperties (has fill/line/effectList/_rawXml
608
+ // but no hex-string "fill" field), shallow-clone rather than return
609
+ // the caller's reference. Every downstream consumer treats the
610
+ // returned object as owned (e.g. `applyChartSeriesOptionsPatch`
611
+ // deletes `_rawXml` on it; combo-group builders overwrite inner
612
+ // fields), and leaking the caller's object into the model would
613
+ // mean subsequent patches on one chart silently mutate the
614
+ // caller's options blob — and if that blob was reused across
615
+ // multiple `addChart(...)` calls, every later chart would see the
616
+ // stripped / mutated state. The clone is shallow because `fill` /
617
+ // `line` sub-trees are themselves replaced wholesale by the
618
+ // downstream patchers when they change; deeper aliasing is not
619
+ // currently a hazard.
620
+ if (isShapeProperties(input)) {
621
+ return { ...input };
622
+ }
623
+ const opts = input;
624
+ const spPr = {};
625
+ if (opts.noFill) {
626
+ spPr.fill = { noFill: true };
627
+ }
628
+ else if (opts.fill) {
629
+ spPr.fill = { solid: hexToColor(opts.fill) };
630
+ }
631
+ else if (opts.gradient) {
632
+ spPr.fill = { gradient: opts.gradient };
633
+ }
634
+ else if (opts.pattern) {
635
+ spPr.fill = { pattern: opts.pattern };
636
+ }
637
+ if (opts.border || opts.borderWidth !== undefined) {
638
+ spPr.line = {};
639
+ if (opts.border) {
640
+ spPr.line.color = hexToColor(opts.border);
641
+ }
642
+ if (opts.borderWidth !== undefined) {
643
+ // OOXML `a:ln/@w` is `ST_LineWidth` = `xsd:int`. A fractional
644
+ // `borderWidth` (e.g. 0.825pt, or any point value that doesn't
645
+ // round-trip through `n / 12700` cleanly) would interpolate as
646
+ // `"10477.5"`, which strict readers reject. Rounding matches the
647
+ // sibling builders (`buildSeriesSpPr`, etc.).
648
+ spPr.line.width = Math.round(opts.borderWidth * EMU_PER_POINT);
649
+ }
650
+ else if (opts.border) {
651
+ // Mirror chart-ex-builder: when the caller sets a border colour
652
+ // without an explicit width, fall back to 9525 EMU (0.75pt).
653
+ // Without this DrawingML readers treat `<a:ln>` as hairline,
654
+ // which typically disappears on screen.
655
+ spPr.line.width = 9525;
656
+ }
657
+ }
658
+ return Object.keys(spPr).length > 0 ? spPr : undefined;
659
+ }
660
+ function isShapeProperties(v) {
661
+ if (!v || typeof v !== "object") {
662
+ return false;
663
+ }
664
+ const o = v;
665
+ // ShapeProperties has structured `fill` as an object or `line` or `_rawXml`,
666
+ // whereas AddShapeFillOptions.fill is a hex string.
667
+ if ("_rawXml" in o) {
668
+ return true;
669
+ }
670
+ if ("fill" in o && typeof o.fill === "object") {
671
+ return true;
672
+ }
673
+ if ("line" in o && typeof o.line === "object" && !Array.isArray(o.line)) {
674
+ // AddShapeFillOptions does not have `line`; ShapeProperties does.
675
+ return true;
676
+ }
677
+ if ("effectList" in o) {
678
+ return true;
679
+ }
680
+ // Check the remaining `ShapeProperties` fields that distinguish it
681
+ // from `AddShapeFillOptions`. `AddShapeFillOptions` has only
682
+ // `fill` (as hex-string) and `line` (as hex-string); anything else
683
+ // is a `ShapeProperties`-only field. Previously the sniffer missed
684
+ // the 3D/geometry fields entirely — a user passing
685
+ // `{ sp3d: {...} }` or `{ transform: {...} }` alone was
686
+ // misclassified and the fields silently dropped.
687
+ if ("scene3d" in o || "sp3d" in o) {
688
+ return true;
689
+ }
690
+ if ("transform" in o || "presetGeometry" in o || "customGeometry" in o) {
691
+ return true;
692
+ }
693
+ return false;
694
+ }
695
+ function makeSolidFill(hex) {
696
+ return { fill: { solid: hexToColor(hex) } };
697
+ }
698
+ function makeSeriesTx(name) {
699
+ if (name === undefined) {
700
+ return undefined;
701
+ }
702
+ if (typeof name === "string") {
703
+ return { value: name };
704
+ }
705
+ return { strRef: makeStrRef(name.formula) };
706
+ }
707
+ // ---------------------------------------------------------------------------
708
+ // Series-level option builders
709
+ // ---------------------------------------------------------------------------
710
+ function buildSeriesSpPr(opts) {
711
+ // Explicit `spPr` on the options object takes precedence over the sugared form.
712
+ const custom = toShapeProperties(opts.spPr);
713
+ if (custom) {
714
+ return custom;
715
+ }
716
+ let spPr;
717
+ if (opts.fill) {
718
+ spPr = makeSolidFill(opts.fill);
719
+ }
720
+ if (opts.line || opts.lineWidth !== undefined || opts.lineDash) {
721
+ const line = {};
722
+ if (opts.line) {
723
+ line.color = hexToColor(opts.line);
724
+ }
725
+ if (opts.lineWidth !== undefined) {
726
+ line.width = Math.round(opts.lineWidth * EMU_PER_POINT); // pt → EMU
727
+ }
728
+ else if (opts.line) {
729
+ // Mirror chart-ex-builder: when the caller sets a line colour
730
+ // without an explicit width, fall back to 9525 EMU (0.75pt —
731
+ // Excel's default for chart series borders). Without this
732
+ // DrawingML readers treat `<a:ln>` as hairline, which disappears
733
+ // at typical screen DPI and is never what the user means by
734
+ // `line: "#FF0000"`.
735
+ line.width = 9525;
736
+ }
737
+ if (opts.lineDash) {
738
+ line.dash = opts.lineDash;
739
+ }
740
+ spPr = { ...spPr, line };
741
+ }
742
+ return spPr;
743
+ }
744
+ function buildMarkerFromOpts(opts) {
745
+ const m = {};
746
+ if (opts.symbol) {
747
+ m.symbol = opts.symbol;
748
+ }
749
+ if (opts.size !== undefined) {
750
+ m.size = opts.size;
751
+ }
752
+ if (opts.fill || opts.border) {
753
+ const mSpPr = {};
754
+ if (opts.fill) {
755
+ mSpPr.fill = { solid: hexToColor(opts.fill) };
756
+ }
757
+ if (opts.border) {
758
+ // Default to 9525 EMU (0.75pt) — without an explicit width
759
+ // DrawingML treats the outline as hairline and the marker ring
760
+ // typically vanishes at on-screen DPI. Matches the other
761
+ // builder paths that default to the same width.
762
+ mSpPr.line = { color: hexToColor(opts.border), width: 9525 };
763
+ }
764
+ m.spPr = mSpPr;
765
+ }
766
+ return m;
767
+ }
768
+ function buildDataLabelsFromOpts(opts) {
769
+ const dl = {};
770
+ if (opts.showLegendKey !== undefined) {
771
+ dl.showLegendKey = opts.showLegendKey;
772
+ }
773
+ if (opts.showVal !== undefined) {
774
+ dl.showVal = opts.showVal;
775
+ }
776
+ if (opts.showCatName !== undefined) {
777
+ dl.showCatName = opts.showCatName;
778
+ }
779
+ if (opts.showSerName !== undefined) {
780
+ dl.showSerName = opts.showSerName;
781
+ }
782
+ if (opts.showPercent !== undefined) {
783
+ dl.showPercent = opts.showPercent;
784
+ }
785
+ if (opts.showBubbleSize !== undefined) {
786
+ dl.showBubbleSize = opts.showBubbleSize;
787
+ }
788
+ if (opts.showLeaderLines !== undefined) {
789
+ dl.showLeaderLines = opts.showLeaderLines;
790
+ }
791
+ if (opts.position) {
792
+ dl.position = opts.position;
793
+ }
794
+ if (opts.separator !== undefined) {
795
+ dl.separator = opts.separator;
796
+ }
797
+ if (opts.numFmt !== undefined) {
798
+ dl.numFmt = { formatCode: opts.numFmt, sourceLinked: opts.numFmtLinked };
799
+ }
800
+ else if (opts.numFmtLinked !== undefined) {
801
+ // Allow `numFmtLinked` without an explicit `numFmt` to re-link the
802
+ // data-label number format to the source cell. OOXML's `CT_NumFmt`
803
+ // requires `formatCode`, so default it to `General` (the Excel
804
+ // default when `sourceLinked="1"` is emitted without an author-
805
+ // specified format). Previously this branch silently dropped the
806
+ // flag: callers had no way to opt into source-linking on data
807
+ // labels without also supplying a redundant format code.
808
+ dl.numFmt = { formatCode: "General", sourceLinked: opts.numFmtLinked };
809
+ }
810
+ const spPr = toShapeProperties(opts.spPr);
811
+ if (spPr) {
812
+ dl.spPr = spPr;
813
+ }
814
+ if (opts.txPr) {
815
+ dl.txPr = opts.txPr;
816
+ }
817
+ if (opts.entries && opts.entries.length > 0) {
818
+ dl.entries = opts.entries.map(e => buildDataLabelEntryFromOpts(e));
819
+ }
820
+ if (opts.valueFromCells !== undefined) {
821
+ // "Value From Cells" (Excel 2013+). Accept either a bare formula or
822
+ // the full {formula, cache} shape. The cache is filled in later by
823
+ // `fillChartCaches` when the worksheet is available.
824
+ dl.dataLabelsRange =
825
+ typeof opts.valueFromCells === "string"
826
+ ? { formula: opts.valueFromCells }
827
+ : opts.valueFromCells;
828
+ }
829
+ return dl;
830
+ }
831
+ function buildDataLabelEntryFromOpts(opts) {
832
+ const entry = { index: opts.index };
833
+ if (opts.delete) {
834
+ entry.delete = true;
835
+ // OOXML: a deleted label carries only its index; skip other fields.
836
+ return entry;
837
+ }
838
+ if (opts.text !== undefined) {
839
+ if (typeof opts.text === "string") {
840
+ entry.text = {
841
+ paragraphs: [{ runs: [{ text: opts.text }] }]
842
+ };
843
+ }
844
+ else {
845
+ entry.text = opts.text;
846
+ }
847
+ }
848
+ if (opts.position) {
849
+ entry.position = opts.position;
850
+ }
851
+ if (opts.numFmt) {
852
+ entry.numFmt = { formatCode: opts.numFmt, sourceLinked: opts.numFmtLinked };
853
+ }
854
+ else if (opts.numFmtLinked !== undefined) {
855
+ // Allow standalone `numFmtLinked` — see `buildDataLabelsFromOpts`
856
+ // for the matching semantics.
857
+ entry.numFmt = { formatCode: "General", sourceLinked: opts.numFmtLinked };
858
+ }
859
+ const spPr = toShapeProperties(opts.spPr);
860
+ if (spPr) {
861
+ entry.spPr = spPr;
862
+ }
863
+ if (opts.txPr) {
864
+ entry.txPr = opts.txPr;
865
+ }
866
+ if (opts.showVal !== undefined) {
867
+ entry.showVal = opts.showVal;
868
+ }
869
+ if (opts.showCatName !== undefined) {
870
+ entry.showCatName = opts.showCatName;
871
+ }
872
+ if (opts.showSerName !== undefined) {
873
+ entry.showSerName = opts.showSerName;
874
+ }
875
+ if (opts.showPercent !== undefined) {
876
+ entry.showPercent = opts.showPercent;
877
+ }
878
+ if (opts.showBubbleSize !== undefined) {
879
+ entry.showBubbleSize = opts.showBubbleSize;
880
+ }
881
+ if (opts.showLegendKey !== undefined) {
882
+ entry.showLegendKey = opts.showLegendKey;
883
+ }
884
+ return entry;
885
+ }
886
+ function buildTrendlineFromOpts(opts) {
887
+ const t = { type: opts.type };
888
+ if (opts.name !== undefined) {
889
+ t.name = opts.name;
890
+ }
891
+ if (opts.order !== undefined) {
892
+ t.order = opts.order;
893
+ }
894
+ if (opts.period !== undefined) {
895
+ t.period = opts.period;
896
+ }
897
+ if (opts.forward !== undefined) {
898
+ t.forward = opts.forward;
899
+ }
900
+ if (opts.backward !== undefined) {
901
+ t.backward = opts.backward;
902
+ }
903
+ if (opts.intercept !== undefined) {
904
+ t.intercept = opts.intercept;
905
+ }
906
+ if (opts.displayRSqr !== undefined) {
907
+ t.displayRSqr = opts.displayRSqr;
908
+ }
909
+ if (opts.displayEq !== undefined) {
910
+ t.displayEq = opts.displayEq;
911
+ }
912
+ if (opts.line || opts.lineWidth !== undefined || opts.lineDash) {
913
+ const line = {};
914
+ if (opts.line) {
915
+ line.color = hexToColor(opts.line);
916
+ }
917
+ if (opts.lineWidth !== undefined) {
918
+ line.width = Math.round(opts.lineWidth * EMU_PER_POINT);
919
+ }
920
+ if (opts.lineDash) {
921
+ line.dash = opts.lineDash;
922
+ }
923
+ t.spPr = { line };
924
+ }
925
+ if (opts.label) {
926
+ t.trendlineLbl = buildTrendlineLabelFromOpts(opts.label);
927
+ }
928
+ return t;
929
+ }
930
+ function buildTrendlineLabelFromOpts(opts) {
931
+ const lbl = {};
932
+ if (opts.text !== undefined) {
933
+ lbl.text = opts.text;
934
+ }
935
+ if (opts.numFmt !== undefined) {
936
+ lbl.numFmt = { formatCode: opts.numFmt, sourceLinked: opts.numFmtLinked };
937
+ }
938
+ else if (opts.numFmtLinked !== undefined) {
939
+ // Allow standalone `numFmtLinked` — see `buildDataLabelsFromOpts`
940
+ // for the matching semantics.
941
+ lbl.numFmt = { formatCode: "General", sourceLinked: opts.numFmtLinked };
942
+ }
943
+ if (opts.layout) {
944
+ lbl.layout = opts.layout;
945
+ }
946
+ const spPr = toShapeProperties(opts.spPr);
947
+ if (spPr) {
948
+ lbl.spPr = spPr;
949
+ }
950
+ if (opts.txPr) {
951
+ lbl.txPr = opts.txPr;
952
+ }
953
+ return lbl;
954
+ }
955
+ function buildErrorBarsFromOpts(opts) {
956
+ const eb = {
957
+ barDir: opts.barDir ?? "both",
958
+ errValType: opts.type
959
+ };
960
+ if (opts.direction) {
961
+ eb.errDir = opts.direction;
962
+ }
963
+ if (opts.value !== undefined) {
964
+ eb.val = opts.value;
965
+ }
966
+ if (opts.noEndCap !== undefined) {
967
+ eb.noEndCap = opts.noEndCap;
968
+ }
969
+ if (opts.plus) {
970
+ eb.plus = makeNumData(opts.plus);
971
+ }
972
+ if (opts.minus) {
973
+ eb.minus = makeNumData(opts.minus);
974
+ }
975
+ // Line / shape styling
976
+ const customSpPr = toShapeProperties(opts.spPr);
977
+ if (customSpPr) {
978
+ eb.spPr = customSpPr;
979
+ }
980
+ else if (opts.line || opts.lineWidth !== undefined || opts.lineDash) {
981
+ const line = {};
982
+ if (opts.line) {
983
+ line.color = hexToColor(opts.line);
984
+ }
985
+ if (opts.lineWidth !== undefined) {
986
+ line.width = Math.round(opts.lineWidth * EMU_PER_POINT);
987
+ }
988
+ if (opts.lineDash) {
989
+ line.dash = opts.lineDash;
990
+ }
991
+ eb.spPr = { line };
992
+ }
993
+ return eb;
994
+ }
995
+ function buildDataPointFromOpts(opts) {
996
+ const dp = { index: opts.index };
997
+ if (opts.fill || opts.border) {
998
+ const spPr = {};
999
+ if (opts.fill) {
1000
+ spPr.fill = { solid: hexToColor(opts.fill) };
1001
+ }
1002
+ if (opts.border) {
1003
+ spPr.line = { color: hexToColor(opts.border), width: 9525 };
1004
+ }
1005
+ dp.spPr = spPr;
1006
+ }
1007
+ if (opts.explosion !== undefined) {
1008
+ dp.explosion = opts.explosion;
1009
+ }
1010
+ if (opts.bubble3D !== undefined) {
1011
+ dp.bubble3D = opts.bubble3D;
1012
+ }
1013
+ if (opts.marker) {
1014
+ dp.marker = buildMarkerFromOpts(opts.marker);
1015
+ }
1016
+ if (opts.invertIfNegative !== undefined) {
1017
+ dp.invertIfNegative = opts.invertIfNegative;
1018
+ }
1019
+ return dp;
1020
+ }
1021
+ function applySeriesOptions(s, opts, context = {}) {
1022
+ s.spPr = buildSeriesSpPr(opts);
1023
+ if (opts.marker) {
1024
+ s.marker = buildMarkerFromOpts(opts.marker);
1025
+ }
1026
+ if (opts.dataLabels) {
1027
+ s.dataLabels = buildDataLabelsFromOpts(opts.dataLabels);
1028
+ }
1029
+ if (opts.trendline) {
1030
+ const trendlineOpts = Array.isArray(opts.trendline) ? opts.trendline : [opts.trendline];
1031
+ s.trendlines = trendlineOpts.map(buildTrendlineFromOpts);
1032
+ }
1033
+ if (opts.dataPoints) {
1034
+ s.dataPoints = opts.dataPoints.map(buildDataPointFromOpts);
1035
+ }
1036
+ // NOTE: classic chart series have no `txPr` slot in OOXML, so the
1037
+ // field was removed from `AddChartSeriesOptions`. Trendline labels,
1038
+ // axis labels, data labels, and titles all have their own `txPr`
1039
+ // entry points — route run-level text styling through those.
1040
+ if (opts.pictureFill) {
1041
+ applyPictureFillToSeries(s, opts.pictureFill, {
1042
+ supportsPictureOptions: context.supportsPictureOptions
1043
+ });
1044
+ }
1045
+ }
1046
+ /**
1047
+ * Split an `AddShapeFillOptions`-style `pictureFill` option bundle into the
1048
+ * two OOXML artefacts that render the feature:
1049
+ * - `c:pictureOptions` (stretch/stack/apply-to-*) — stored on
1050
+ * `series.pictureOptions`
1051
+ * - `a:blipFill` (the actual image rel) — stored on
1052
+ * `series.spPr.fill.blip`
1053
+ *
1054
+ * Both are updated in a single place so the new-series path
1055
+ * ({@link applySeriesOptions}) and the patch path
1056
+ * ({@link applyChartSeriesOptionsPatch}) cannot diverge.
1057
+ */
1058
+ function applyPictureFillToSeries(series, pictureFill, options = {}) {
1059
+ // `c:pictureOptions` (stretch/stack/applyTo*/scale) is only declared
1060
+ // on `CT_BarSer` per ECMA-376 §21.2.2.162. Non-bar callers get the
1061
+ // `<a:blipFill>` on their `spPr.fill.blip` (which is legal on every
1062
+ // shape), but the caller-supplied `applyToFront` / `fillMode` /
1063
+ // `scale` hints are silently dropped — we would otherwise emit a
1064
+ // `<c:pictureOptions>` that schema validators reject. Surface the
1065
+ // mismatch if the caller set bar-only fields on a non-bar series
1066
+ // rather than letting the data quietly disappear.
1067
+ const barOnlyFieldsUsed = pictureFill.applyToFront !== undefined ||
1068
+ pictureFill.applyToSides !== undefined ||
1069
+ pictureFill.applyToEnd !== undefined ||
1070
+ pictureFill.scale !== undefined;
1071
+ if (options.supportsPictureOptions) {
1072
+ series.pictureOptions = {
1073
+ applyToFront: pictureFill.applyToFront,
1074
+ applyToSides: pictureFill.applyToSides,
1075
+ applyToEnd: pictureFill.applyToEnd,
1076
+ pictureFormat: pictureFill.fillMode,
1077
+ pictureStackUnit: pictureFill.scale
1078
+ };
1079
+ }
1080
+ else if (barOnlyFieldsUsed) {
1081
+ throw new ChartOptionsError("pictureFill.applyToFront / applyToSides / applyToEnd / scale are only valid for bar / bar3D series (mapped to c:pictureOptions in CT_BarSer). Use the plain `fill` / `spPr.fill.blip` form for other series types, or omit the bar-only hints.");
1082
+ }
1083
+ if (pictureFill.image !== undefined || pictureFill.relationshipId) {
1084
+ // Parsed-from-XML series carry their `spPr` as a dual
1085
+ // representation: the structured `fill` / `line` slots are
1086
+ // populated AND `_rawXml` holds the original DrawingML bytes.
1087
+ // The writer short-circuits to `_rawXml` (see
1088
+ // `chart-space-xform._renderSpPr`) whenever it's present, which
1089
+ // means a downstream mutation like this one — which sets
1090
+ // `series.spPr.fill.blip` but can't touch the raw bytes — gets
1091
+ // silently overwritten at save time. The chart rel points at the
1092
+ // new image, the chart XML still carries the old fill. Strip
1093
+ // `_rawXml` here so the structured patch wins and the writer
1094
+ // emits the fresh `<a:blipFill>`.
1095
+ //
1096
+ // We also need to repopulate enough of the structured model that
1097
+ // the dropped `_rawXml` doesn't take authored line / geometry /
1098
+ // effect properties down with it. `parseSpPr` is already called
1099
+ // at load time and stores the structured fields alongside the
1100
+ // raw bytes, so the structured slots still carry whatever the
1101
+ // loaded file had. Nothing extra needed on the clone side.
1102
+ if (series.spPr && typeof series.spPr === "object") {
1103
+ delete series.spPr._rawXml;
1104
+ }
1105
+ series.spPr = series.spPr ?? {};
1106
+ series.spPr.fill = series.spPr.fill ?? {};
1107
+ // Also clear a raw representation that might live on the
1108
+ // existing `fill` object (rare — reserved for `<a:solidFill>`
1109
+ // / `<a:gradFill>` raw captures some parsers produce). The
1110
+ // writer emits a single `<a:*Fill>` child per `<a:spPr>`, so
1111
+ // the new blip must be the only fill in play.
1112
+ delete series.spPr.fill.solid;
1113
+ delete series.spPr.fill.gradient;
1114
+ delete series.spPr.fill.pattern;
1115
+ delete series.spPr.fill.noFill;
1116
+ series.spPr.fill.blip = {
1117
+ fillMode: pictureFill.fillMode === "stack" || pictureFill.fillMode === "stackScale"
1118
+ ? "tile"
1119
+ : "stretch",
1120
+ ...(pictureFill.relationshipId ? { relationshipId: pictureFill.relationshipId } : {}),
1121
+ ...(pictureFill.image !== undefined ? { _pendingImage: pictureFill.image } : {})
1122
+ };
1123
+ }
1124
+ }
1125
+ /**
1126
+ * Populates common category-value series fields (tx, cat, val) shared by
1127
+ * bar, line, pie, area, radar, and surface series builders.
1128
+ */
1129
+ function populateCatValBase(s, opts) {
1130
+ s.tx = makeSeriesTx(opts.name);
1131
+ if (opts.categories) {
1132
+ s.cat = makeAxisData(opts.categories);
1133
+ }
1134
+ if (opts.values) {
1135
+ s.val = makeNumData(opts.values);
1136
+ }
1137
+ }
1138
+ /**
1139
+ * Build a single error-bars entry from options, normalising the
1140
+ * array-vs-single input shape used by non-scatter/bubble series.
1141
+ */
1142
+ function buildSingleErrorBars(opts) {
1143
+ if (!opts) {
1144
+ return undefined;
1145
+ }
1146
+ if (Array.isArray(opts)) {
1147
+ return opts.length > 0 ? buildErrorBarsFromOpts(opts[0]) : undefined;
1148
+ }
1149
+ return buildErrorBarsFromOpts(opts);
1150
+ }
1151
+ function buildBarSeries(opts, idx) {
1152
+ const s = { index: idx, order: idx };
1153
+ populateCatValBase(s, opts);
1154
+ applySeriesOptions(s, opts, { supportsPictureOptions: true });
1155
+ if (opts.invertIfNegative !== undefined) {
1156
+ s.invertIfNegative = opts.invertIfNegative;
1157
+ }
1158
+ s.errorBars = buildSingleErrorBars(opts.errorBars);
1159
+ return s;
1160
+ }
1161
+ function buildLineSeries(opts, idx) {
1162
+ const s = { index: idx, order: idx };
1163
+ populateCatValBase(s, opts);
1164
+ applySeriesOptions(s, opts);
1165
+ if (opts.smooth !== undefined) {
1166
+ s.smooth = opts.smooth;
1167
+ }
1168
+ s.errorBars = buildSingleErrorBars(opts.errorBars);
1169
+ return s;
1170
+ }
1171
+ function buildPieSeries(opts, idx) {
1172
+ const s = { index: idx, order: idx };
1173
+ populateCatValBase(s, opts);
1174
+ applySeriesOptions(s, opts);
1175
+ if (opts.explosion !== undefined) {
1176
+ s.explosion = opts.explosion;
1177
+ }
1178
+ return s;
1179
+ }
1180
+ function buildAreaSeries(opts, idx) {
1181
+ const s = { index: idx, order: idx };
1182
+ populateCatValBase(s, opts);
1183
+ applySeriesOptions(s, opts);
1184
+ s.errorBars = buildSingleErrorBars(opts.errorBars);
1185
+ return s;
1186
+ }
1187
+ function buildScatterSeries(opts, idx) {
1188
+ const s = { index: idx, order: idx };
1189
+ s.tx = makeSeriesTx(opts.name);
1190
+ if (opts.xValues) {
1191
+ s.xVal = makeXAxisData(opts.xValues, opts.xValueType);
1192
+ }
1193
+ if (opts.values) {
1194
+ s.yVal = makeNumData(opts.values);
1195
+ }
1196
+ applySeriesOptions(s, opts);
1197
+ if (opts.smooth !== undefined) {
1198
+ s.smooth = opts.smooth;
1199
+ }
1200
+ if (opts.errorBars) {
1201
+ const ebOpts = Array.isArray(opts.errorBars) ? opts.errorBars : [opts.errorBars];
1202
+ s.errorBars = ebOpts.map(buildErrorBarsFromOpts);
1203
+ }
1204
+ return s;
1205
+ }
1206
+ function buildBubbleSeries(opts, idx) {
1207
+ const s = { index: idx, order: idx };
1208
+ s.tx = makeSeriesTx(opts.name);
1209
+ if (opts.xValues) {
1210
+ s.xVal = makeXAxisData(opts.xValues, opts.xValueType);
1211
+ }
1212
+ if (opts.values) {
1213
+ s.yVal = makeNumData(opts.values);
1214
+ }
1215
+ if (opts.bubbleSize) {
1216
+ s.bubbleSize = makeNumData(opts.bubbleSize);
1217
+ }
1218
+ applySeriesOptions(s, opts);
1219
+ if (opts.invertIfNegative !== undefined) {
1220
+ s.invertIfNegative = opts.invertIfNegative;
1221
+ }
1222
+ if (opts.bubble3D !== undefined) {
1223
+ s.bubble3D = opts.bubble3D;
1224
+ }
1225
+ if (opts.errorBars) {
1226
+ const ebOpts = Array.isArray(opts.errorBars) ? opts.errorBars : [opts.errorBars];
1227
+ s.errorBars = ebOpts.map(buildErrorBarsFromOpts);
1228
+ }
1229
+ return s;
1230
+ }
1231
+ function buildRadarSeries(opts, idx) {
1232
+ const s = { index: idx, order: idx };
1233
+ populateCatValBase(s, opts);
1234
+ applySeriesOptions(s, opts);
1235
+ return s;
1236
+ }
1237
+ function buildSurfaceSeries(opts, idx) {
1238
+ const s = { index: idx, order: idx };
1239
+ populateCatValBase(s, opts);
1240
+ applySeriesOptions(s, opts);
1241
+ return s;
1242
+ }
1243
+ export function buildChartSeriesForType(chartType, options, index) {
1244
+ validateSeriesOptions(chartType, options, "series");
1245
+ if (chartType === "bar" || chartType === "bar3D") {
1246
+ return buildBarSeries(options, index);
1247
+ }
1248
+ if (chartType === "line" || chartType === "line3D" || chartType === "stock") {
1249
+ return buildLineSeries(options, index);
1250
+ }
1251
+ if (chartType === "pie" ||
1252
+ chartType === "pie3D" ||
1253
+ chartType === "doughnut" ||
1254
+ chartType === "ofPie") {
1255
+ return buildPieSeries(options, index);
1256
+ }
1257
+ if (chartType === "area" || chartType === "area3D") {
1258
+ return buildAreaSeries(options, index);
1259
+ }
1260
+ if (chartType === "scatter") {
1261
+ return buildScatterSeries(options, index);
1262
+ }
1263
+ if (chartType === "bubble") {
1264
+ return buildBubbleSeries(options, index);
1265
+ }
1266
+ if (chartType === "radar") {
1267
+ return buildRadarSeries(options, index);
1268
+ }
1269
+ if (chartType === "surface" || chartType === "surface3D") {
1270
+ return buildSurfaceSeries(options, index);
1271
+ }
1272
+ // Exhaustiveness check: every value of `AddChartOptions["type"]` must be
1273
+ // handled above. Falling back to `buildBarSeries` silently would mis-map
1274
+ // any new chart type introduced in the future.
1275
+ const _exhaustive = chartType;
1276
+ throw new ChartOptionsError(`Unsupported chart type: ${String(_exhaustive)}.`);
1277
+ }
1278
+ export function applyChartSeriesOptionsPatch(series, options, chartType) {
1279
+ if (chartType) {
1280
+ validateSeriesPatchOptions(chartType, options, "series");
1281
+ }
1282
+ if (options.name !== undefined) {
1283
+ series.tx = makeSeriesTx(options.name);
1284
+ }
1285
+ if (options.categories !== undefined) {
1286
+ const target = series;
1287
+ // Scatter / bubble series have no category axis — their X axis is
1288
+ // `xVal`. When a patch targets such a series (identified by an
1289
+ // already-populated `xVal` and no `cat`), route `categories`
1290
+ // through `makeXAxisData` so `options.xValueType: "text"` flips
1291
+ // the series from a numeric `xVal` to a labelled one. For every
1292
+ // other series type the patch goes to the structural `cat` slot.
1293
+ if (target.xVal && !target.cat) {
1294
+ target.xVal = makeXAxisData(options.categories, options.xValueType);
1295
+ }
1296
+ else {
1297
+ target.cat = makeAxisData(options.categories);
1298
+ }
1299
+ }
1300
+ if (options.xValues !== undefined) {
1301
+ series.xVal = makeXAxisData(options.xValues, options.xValueType);
1302
+ }
1303
+ if (options.values !== undefined) {
1304
+ const target = series;
1305
+ if (target.yVal && !target.val) {
1306
+ target.yVal = makeNumData(options.values);
1307
+ }
1308
+ else {
1309
+ target.val = makeNumData(options.values);
1310
+ }
1311
+ }
1312
+ if (options.bubbleSize !== undefined) {
1313
+ series.bubbleSize = makeNumData(options.bubbleSize);
1314
+ }
1315
+ if (hasSeriesShapePatch(options)) {
1316
+ const patchShape = buildSeriesSpPr(options);
1317
+ if (options.spPr !== undefined) {
1318
+ // Explicit `spPr` replaces the whole shape — the caller opted in
1319
+ // to a full structured override.
1320
+ series.spPr = patchShape;
1321
+ }
1322
+ else {
1323
+ // Sugared patches (`fill` / `line` / `lineWidth` / `lineDash`)
1324
+ // should update only the affected sub-object AND merge inside the
1325
+ // sub-object so narrow patches (e.g. `lineDash` alone) don't wipe
1326
+ // out the adjacent fields.
1327
+ //
1328
+ // Previously the merge stopped at the top level (`{ ...existing,
1329
+ // line: patchShape.line }`) — so `updateSeries(0, { lineDash: "dash" })`
1330
+ // on a series with `{ line: "#FF0000", lineWidth: 2 }` dropped the
1331
+ // colour AND width because `buildSeriesSpPr({ lineDash: "dash" })`
1332
+ // only sets `line.dash`, and the top-level spread replaced the
1333
+ // whole `line` sub-object with `{ dash: "dash" }`. Deep-merge the
1334
+ // sub-objects so each field survives until the caller explicitly
1335
+ // overwrites it.
1336
+ const existing = series.spPr ?? {};
1337
+ const next = { ...existing };
1338
+ if (patchShape?.fill !== undefined) {
1339
+ next.fill = patchShape.fill;
1340
+ }
1341
+ if (patchShape?.line !== undefined) {
1342
+ next.line = { ...(existing.line ?? {}), ...patchShape.line };
1343
+ }
1344
+ series.spPr = next;
1345
+ }
1346
+ // CRITICAL: clear `_rawXml` so the writer serialises from the
1347
+ // structured fields we just patched. The chart-space writer emits
1348
+ // `_rawXml` verbatim when present (`_renderSpPr` at the top of the
1349
+ // function body in `chart-space-xform.ts`), which meant every
1350
+ // structured mutation was silently overridden by the stale raw
1351
+ // bytes captured at parse time. After this clear the next save
1352
+ // re-serialises the full shape tree from the structured fields.
1353
+ if (series.spPr && "_rawXml" in series.spPr) {
1354
+ delete series.spPr._rawXml;
1355
+ }
1356
+ }
1357
+ if (options.marker !== undefined) {
1358
+ series.marker = buildMarkerFromOpts(options.marker);
1359
+ }
1360
+ if (options.dataLabels !== undefined) {
1361
+ series.dataLabels = buildDataLabelsFromOpts(options.dataLabels);
1362
+ }
1363
+ if (options.trendline !== undefined) {
1364
+ const trendlineOpts = Array.isArray(options.trendline)
1365
+ ? options.trendline
1366
+ : [options.trendline];
1367
+ series.trendlines =
1368
+ trendlineOpts.map(buildTrendlineFromOpts);
1369
+ }
1370
+ if (options.dataPoints !== undefined) {
1371
+ series.dataPoints =
1372
+ options.dataPoints.map(buildDataPointFromOpts);
1373
+ }
1374
+ if (options.errorBars !== undefined) {
1375
+ const errorBars = Array.isArray(options.errorBars) ? options.errorBars : [options.errorBars];
1376
+ // Validate each error-bar config independently. Previously the
1377
+ // patch path relied on the outer `validateSeriesPatchOptions` call
1378
+ // at the top of this function, but that skip when `chartType` is
1379
+ // omitted. `CT_ErrBars` requires `errValType`, and without a
1380
+ // validator an options object missing `type` would silently emit
1381
+ // `<c:errValType/>` (no attribute) → schema-invalid output.
1382
+ for (const eb of errorBars) {
1383
+ validateErrorBarsOptions(eb, "series.errorBars");
1384
+ }
1385
+ const built = errorBars.map(buildErrorBarsFromOpts);
1386
+ series.errorBars =
1387
+ chartType === "scatter" || chartType === "bubble" ? built : built[0];
1388
+ }
1389
+ // NOTE: classic chart series have no `txPr` slot in OOXML — see the
1390
+ // `AddChartSeriesOptions` type comment. The field was removed from
1391
+ // the options bag so this patch branch is gone as well.
1392
+ if (options.pictureFill !== undefined) {
1393
+ applyPictureFillToSeries(series, options.pictureFill, {
1394
+ supportsPictureOptions: chartType === "bar" || chartType === "bar3D"
1395
+ });
1396
+ }
1397
+ if (options.smooth !== undefined) {
1398
+ series.smooth = options.smooth;
1399
+ }
1400
+ if (options.invertIfNegative !== undefined) {
1401
+ series.invertIfNegative =
1402
+ options.invertIfNegative;
1403
+ }
1404
+ if (options.explosion !== undefined) {
1405
+ series.explosion = options.explosion;
1406
+ }
1407
+ if (options.bubble3D !== undefined) {
1408
+ series.bubble3D = options.bubble3D;
1409
+ }
1410
+ }
1411
+ function hasSeriesShapePatch(options) {
1412
+ return (options.spPr !== undefined ||
1413
+ options.fill !== undefined ||
1414
+ options.line !== undefined ||
1415
+ options.lineWidth !== undefined ||
1416
+ options.lineDash !== undefined);
1417
+ }
1418
+ function buildTitle(input) {
1419
+ if (typeof input === "string") {
1420
+ return {
1421
+ text: {
1422
+ paragraphs: [{ runs: [{ text: input }] }]
1423
+ },
1424
+ overlay: false
1425
+ };
1426
+ }
1427
+ if ("formula" in input) {
1428
+ return {
1429
+ strRef: makeStrRef(input.formula),
1430
+ overlay: false
1431
+ };
1432
+ }
1433
+ // ChartRichText
1434
+ return {
1435
+ text: input,
1436
+ overlay: false
1437
+ };
1438
+ }
1439
+ function buildDataTableFromOpts(opts) {
1440
+ if (!opts) {
1441
+ return undefined;
1442
+ }
1443
+ if (opts === true) {
1444
+ return { showHorzBorder: true, showVertBorder: true, showOutline: true, showKeys: true };
1445
+ }
1446
+ return {
1447
+ showHorzBorder: opts.showHorzBorder,
1448
+ showVertBorder: opts.showVertBorder,
1449
+ showOutline: opts.showOutline,
1450
+ showKeys: opts.showKeys
1451
+ };
1452
+ }
1453
+ function buildUpDownBarsFromOpts(opts) {
1454
+ if (!opts) {
1455
+ return undefined;
1456
+ }
1457
+ if (opts === true) {
1458
+ return { gapWidth: 150 };
1459
+ }
1460
+ const udb = { gapWidth: opts.gapWidth ?? 150 };
1461
+ const upBars = toShapeProperties(opts.upBars);
1462
+ if (upBars) {
1463
+ udb.upBars = upBars;
1464
+ }
1465
+ const downBars = toShapeProperties(opts.downBars);
1466
+ if (downBars) {
1467
+ udb.downBars = downBars;
1468
+ }
1469
+ return udb;
1470
+ }
1471
+ function buildLegend(opts) {
1472
+ if (opts.showLegend === false) {
1473
+ return undefined;
1474
+ }
1475
+ return {
1476
+ legendPos: opts.legendPosition ?? "b",
1477
+ overlay: false
1478
+ };
1479
+ }
1480
+ /**
1481
+ * Apply user-specified axis options to a built axis.
1482
+ */
1483
+ function applyAxisOptions(axis, opts) {
1484
+ if (!opts) {
1485
+ return;
1486
+ }
1487
+ if (opts.title !== undefined) {
1488
+ // Replace the title text but preserve any previously-applied
1489
+ // `titleOptions` (layout, overlay, spPr, txPr) attached to
1490
+ // `axis.title`. Combo charts call `applyAxisOptions` repeatedly on
1491
+ // a shared axis (see `buildChartTypeGroup` reuse paths), and a
1492
+ // wholesale replacement here discarded every field except the new
1493
+ // text. We graft the new title runs onto the existing frame.
1494
+ const fresh = buildTitle(opts.title);
1495
+ axis.title = axis.title
1496
+ ? {
1497
+ ...axis.title,
1498
+ strRef: fresh.strRef,
1499
+ text: fresh.text,
1500
+ rawTx: fresh.rawTx
1501
+ }
1502
+ : fresh;
1503
+ }
1504
+ if (opts.titleOptions) {
1505
+ if (!axis.title) {
1506
+ axis.title = { overlay: false };
1507
+ }
1508
+ applyTitleOptions(axis.title, opts.titleOptions);
1509
+ }
1510
+ if (opts.numFmt !== undefined) {
1511
+ // Merge onto any prior `numFmt` so a later call that supplies
1512
+ // `opts.numFmt` without `opts.numFmtLinked` doesn't reset
1513
+ // `sourceLinked` back to `undefined`. Same class of bug as the
1514
+ // title replacement above — triggered when combo-chart flows
1515
+ // apply options to a shared axis in multiple passes.
1516
+ axis.numFmt = {
1517
+ ...axis.numFmt,
1518
+ formatCode: opts.numFmt,
1519
+ ...(opts.numFmtLinked !== undefined ? { sourceLinked: opts.numFmtLinked } : {})
1520
+ };
1521
+ }
1522
+ if (opts.min !== undefined || opts.max !== undefined || opts.orientation || opts.logBase) {
1523
+ if (!axis.scaling) {
1524
+ axis.scaling = {};
1525
+ }
1526
+ if (opts.min !== undefined) {
1527
+ axis.scaling.min = opts.min;
1528
+ }
1529
+ if (opts.max !== undefined) {
1530
+ axis.scaling.max = opts.max;
1531
+ }
1532
+ if (opts.orientation) {
1533
+ axis.scaling.orientation = opts.orientation;
1534
+ }
1535
+ if (opts.logBase !== undefined) {
1536
+ axis.scaling.logBase = opts.logBase;
1537
+ }
1538
+ }
1539
+ if (opts.majorUnit !== undefined && axis.axisType === "val") {
1540
+ axis.majorUnit = opts.majorUnit;
1541
+ }
1542
+ if (opts.minorUnit !== undefined && axis.axisType === "val") {
1543
+ axis.minorUnit = opts.minorUnit;
1544
+ }
1545
+ if (opts.majorTickMark) {
1546
+ axis.majorTickMark = opts.majorTickMark;
1547
+ }
1548
+ if (opts.minorTickMark) {
1549
+ axis.minorTickMark = opts.minorTickMark;
1550
+ }
1551
+ if (opts.tickLblPos) {
1552
+ axis.tickLblPos = opts.tickLblPos;
1553
+ }
1554
+ // Major gridlines: the explicit `majorGridlines` boolean is an on/off
1555
+ // switch that must win over any `majorGridlinesStyle`. Callers who
1556
+ // pass both `{ majorGridlines: false, majorGridlinesStyle: { … } }`
1557
+ // mean "hide them, even though I've authored a style for the ON
1558
+ // state" — dropping the style and emitting nothing is the right
1559
+ // call. The previous code checked the boolean in an `else if`, so
1560
+ // an explicit `false` was silently ignored whenever a style was
1561
+ // supplied and the gridlines stayed drawn.
1562
+ const majorGridlinesStyle = toShapeProperties(opts.majorGridlinesStyle);
1563
+ if (opts.majorGridlines === false) {
1564
+ axis.majorGridlines = undefined;
1565
+ }
1566
+ else if (majorGridlinesStyle) {
1567
+ axis.majorGridlines = majorGridlinesStyle;
1568
+ }
1569
+ else if (opts.majorGridlines === true) {
1570
+ axis.majorGridlines = {};
1571
+ }
1572
+ const minorGridlinesStyle = toShapeProperties(opts.minorGridlinesStyle);
1573
+ if (opts.minorGridlines === false) {
1574
+ axis.minorGridlines = undefined;
1575
+ }
1576
+ else if (minorGridlinesStyle) {
1577
+ axis.minorGridlines = minorGridlinesStyle;
1578
+ }
1579
+ else if (opts.minorGridlines === true) {
1580
+ axis.minorGridlines = {};
1581
+ }
1582
+ if (opts.hidden !== undefined) {
1583
+ axis.delete = opts.hidden;
1584
+ }
1585
+ if (opts.crossBetween !== undefined && axis.axisType === "val") {
1586
+ axis.crossBetween = opts.crossBetween;
1587
+ }
1588
+ // Text properties — structured txPr takes priority over textRotation
1589
+ if (opts.txPr) {
1590
+ axis.txPr = opts.txPr;
1591
+ }
1592
+ else if (opts.textRotation !== undefined) {
1593
+ // `a:bodyPr/@rot` is `ST_Angle` = `xsd:int`. Round so a caller
1594
+ // passing fractional degrees (or a value like 1.05° that IEEE 754
1595
+ // turns into 63000.000000000004) doesn't inject `"NaN"` /
1596
+ // `"63000.00000000001"` as an attribute value.
1597
+ axis.txPr = { rotation: Math.round(opts.textRotation * 60000) };
1598
+ }
1599
+ if (opts.lblAlgn !== undefined && axis.axisType === "cat") {
1600
+ axis.lblAlgn = opts.lblAlgn;
1601
+ }
1602
+ if (opts.lblOffset !== undefined && axis.axisType === "cat") {
1603
+ axis.lblOffset = opts.lblOffset;
1604
+ }
1605
+ if (opts.tickLblSkip !== undefined && axis.axisType === "cat") {
1606
+ axis.tickLblSkip = opts.tickLblSkip;
1607
+ }
1608
+ if (opts.tickMarkSkip !== undefined && axis.axisType === "cat") {
1609
+ axis.tickMarkSkip = opts.tickMarkSkip;
1610
+ }
1611
+ if (opts.crosses !== undefined) {
1612
+ axis.crosses = opts.crosses;
1613
+ }
1614
+ if (opts.crossesAt !== undefined) {
1615
+ axis.crossesAt = opts.crossesAt;
1616
+ }
1617
+ if (axis.axisType === "val") {
1618
+ const valAx = axis;
1619
+ if (opts.displayUnits !== undefined ||
1620
+ opts.customUnit !== undefined ||
1621
+ opts.displayUnitsLabel !== undefined) {
1622
+ valAx.dispUnits = valAx.dispUnits ?? {};
1623
+ if (opts.displayUnits !== undefined) {
1624
+ valAx.dispUnits.builtInUnit = opts.displayUnits;
1625
+ }
1626
+ if (opts.customUnit !== undefined) {
1627
+ valAx.dispUnits.custUnit = opts.customUnit;
1628
+ }
1629
+ if (opts.displayUnitsLabel !== undefined) {
1630
+ valAx.dispUnits.label = buildTitle(opts.displayUnitsLabel);
1631
+ }
1632
+ }
1633
+ }
1634
+ // Date-axis-specific units
1635
+ if (axis.axisType === "date") {
1636
+ const dateAx = axis;
1637
+ if (opts.baseTimeUnit !== undefined) {
1638
+ dateAx.baseTimeUnit = opts.baseTimeUnit;
1639
+ }
1640
+ if (opts.majorTimeUnit !== undefined) {
1641
+ dateAx.majorTimeUnit = opts.majorTimeUnit;
1642
+ }
1643
+ if (opts.minorTimeUnit !== undefined) {
1644
+ dateAx.minorTimeUnit = opts.minorTimeUnit;
1645
+ }
1646
+ }
1647
+ // Structured spPr takes priority over line-only shortcuts
1648
+ const customSpPr = toShapeProperties(opts.spPr);
1649
+ if (customSpPr) {
1650
+ axis.spPr = customSpPr;
1651
+ }
1652
+ else if (opts.lineColor || opts.lineWidth !== undefined || opts.lineDash) {
1653
+ const line = {};
1654
+ if (opts.lineColor) {
1655
+ line.color = hexToColor(opts.lineColor);
1656
+ }
1657
+ if (opts.lineWidth !== undefined) {
1658
+ line.width = Math.round(opts.lineWidth * EMU_PER_POINT); // pt to EMU
1659
+ }
1660
+ if (opts.lineDash) {
1661
+ line.dash = opts.lineDash;
1662
+ }
1663
+ if (!axis.spPr) {
1664
+ axis.spPr = {};
1665
+ }
1666
+ axis.spPr.line = line;
1667
+ }
1668
+ }
1669
+ function buildCatValAxes(axIds) {
1670
+ const catAxId = axIds.alloc();
1671
+ const valAxId = axIds.alloc();
1672
+ return {
1673
+ catAx: {
1674
+ axisType: "cat",
1675
+ axId: catAxId,
1676
+ scaling: { orientation: "minMax" },
1677
+ delete: false,
1678
+ axPos: "b",
1679
+ crossAx: valAxId,
1680
+ crosses: "autoZero",
1681
+ auto: true,
1682
+ lblAlgn: "ctr",
1683
+ lblOffset: 100
1684
+ },
1685
+ valAx: {
1686
+ axisType: "val",
1687
+ axId: valAxId,
1688
+ scaling: { orientation: "minMax" },
1689
+ delete: false,
1690
+ axPos: "l",
1691
+ crossAx: catAxId,
1692
+ crosses: "autoZero",
1693
+ crossBetween: "between",
1694
+ majorGridlines: {}
1695
+ }
1696
+ };
1697
+ }
1698
+ function buildValValAxes(axIds) {
1699
+ const xAxId = axIds.alloc();
1700
+ const yAxId = axIds.alloc();
1701
+ return {
1702
+ xAx: {
1703
+ axisType: "val",
1704
+ axId: xAxId,
1705
+ scaling: { orientation: "minMax" },
1706
+ delete: false,
1707
+ axPos: "b",
1708
+ crossAx: yAxId,
1709
+ crosses: "autoZero"
1710
+ },
1711
+ yAx: {
1712
+ axisType: "val",
1713
+ axId: yAxId,
1714
+ scaling: { orientation: "minMax" },
1715
+ delete: false,
1716
+ axPos: "l",
1717
+ crossAx: xAxId,
1718
+ crosses: "autoZero",
1719
+ majorGridlines: {}
1720
+ }
1721
+ };
1722
+ }
1723
+ function buildCatValSerAxes(axIds) {
1724
+ const { catAx, valAx } = buildCatValAxes(axIds);
1725
+ const serAxId = axIds.alloc();
1726
+ // serAx crosses the catAx
1727
+ const serAx = {
1728
+ axisType: "ser",
1729
+ axId: serAxId,
1730
+ scaling: { orientation: "minMax" },
1731
+ delete: false,
1732
+ axPos: "b",
1733
+ crossAx: catAx.axId,
1734
+ crosses: "autoZero"
1735
+ };
1736
+ return { catAx, valAx, serAx };
1737
+ }
1738
+ function buildChartTypeGroup(opts, seriesOpts, axIds) {
1739
+ const type = opts.type;
1740
+ let result;
1741
+ switch (type) {
1742
+ case "bar": {
1743
+ const { catAx, valAx } = buildCatValAxes(axIds);
1744
+ const barDir = opts.barDir ?? "col";
1745
+ // Horizontal bar charts (`barDir="bar"`) swap the axis
1746
+ // directions: the category axis is on the left (vertical),
1747
+ // value axis at the bottom (horizontal). Excel itself emits
1748
+ // `axPos="l"` / `axPos="b"` respectively in that case.
1749
+ // `buildCatValAxes` produces the column-chart defaults
1750
+ // (`catAx.axPos="b"`, `valAx.axPos="l"`), which were left
1751
+ // unchanged for horizontal bar charts — the resulting XML
1752
+ // still rendered in Excel because Excel infers orientation
1753
+ // from `c:barDir`, but the renderer's `pickAxis` (position-
1754
+ // based) picked the wrong axis for gridlines / tick labels on
1755
+ // horizontal bars built via `addBarChart`.
1756
+ //
1757
+ // We deliberately do NOT move `majorGridlines` between axes —
1758
+ // `<c:majorGridlines/>` on a value axis means "draw gridlines
1759
+ // perpendicular to the value axis at every tick". When the
1760
+ // value axis is horizontal (bottom), the renderer correctly
1761
+ // projects those as vertical strokes because it picks up
1762
+ // gridlines from the X-axis slot (by `axPos`), not by
1763
+ // axis-type.
1764
+ if (barDir === "bar") {
1765
+ catAx.axPos = "l";
1766
+ valAx.axPos = "b";
1767
+ }
1768
+ const group = {
1769
+ type,
1770
+ barDir,
1771
+ grouping: opts.grouping ?? "clustered",
1772
+ varyColors: opts.varyColors,
1773
+ series: seriesOpts.map(buildBarSeries),
1774
+ gapWidth: opts.gapWidth ?? 150,
1775
+ overlap: opts.overlap,
1776
+ serLines: opts.serLines ? {} : undefined,
1777
+ axisIds: [catAx.axId, valAx.axId]
1778
+ };
1779
+ result = { group, axes: [catAx, valAx] };
1780
+ break;
1781
+ }
1782
+ case "bar3D": {
1783
+ const { catAx, valAx, serAx } = buildCatValSerAxes(axIds);
1784
+ const barDir = opts.barDir ?? "col";
1785
+ if (barDir === "bar") {
1786
+ catAx.axPos = "l";
1787
+ valAx.axPos = "b";
1788
+ }
1789
+ // `CT_Bar3DChart` does NOT accept `overlap` or `serLines` — both
1790
+ // are 2-D-only. Reject them loud here so the options validator
1791
+ // catches the mistake before the writer silently drops them.
1792
+ if (opts.overlap !== undefined) {
1793
+ throw new ChartOptionsError('bar3D charts do not support `overlap` (valid only on 2-D `bar`). Remove the field or switch to `type: "bar"`.');
1794
+ }
1795
+ if (opts.serLines !== undefined) {
1796
+ throw new ChartOptionsError('bar3D charts do not support `serLines` (valid only on 2-D `bar`). Remove the field or switch to `type: "bar"`.');
1797
+ }
1798
+ const group = {
1799
+ type,
1800
+ barDir,
1801
+ grouping: opts.grouping ?? "clustered",
1802
+ varyColors: opts.varyColors,
1803
+ series: seriesOpts.map(buildBarSeries),
1804
+ gapWidth: opts.gapWidth ?? 150,
1805
+ gapDepth: opts.gapDepth,
1806
+ shape: opts.shape,
1807
+ axisIds: [catAx.axId, valAx.axId, serAx.axId]
1808
+ };
1809
+ result = { group, axes: [catAx, valAx, serAx] };
1810
+ break;
1811
+ }
1812
+ case "line": {
1813
+ const { catAx, valAx } = buildCatValAxes(axIds);
1814
+ const group = {
1815
+ type,
1816
+ grouping: opts.grouping ?? "standard",
1817
+ varyColors: opts.varyColors,
1818
+ series: seriesOpts.map(buildLineSeries),
1819
+ marker: opts.showMarker ?? true,
1820
+ smooth: opts.smooth,
1821
+ hiLowLines: opts.hiLowLines ? {} : undefined,
1822
+ upDownBars: buildUpDownBarsFromOpts(opts.upDownBars),
1823
+ dropLines: opts.dropLines ? {} : undefined,
1824
+ axisIds: [catAx.axId, valAx.axId]
1825
+ };
1826
+ result = { group, axes: [catAx, valAx] };
1827
+ break;
1828
+ }
1829
+ case "line3D": {
1830
+ const { catAx, valAx, serAx } = buildCatValSerAxes(axIds);
1831
+ // `CT_Line3DChart` does NOT accept `marker`, `smooth`,
1832
+ // `hiLowLines`, or `upDownBars` — all 2-D-only.
1833
+ // Rejected upstream in validateChartLevelOptions.
1834
+ const group = {
1835
+ type,
1836
+ grouping: opts.grouping ?? "standard",
1837
+ varyColors: opts.varyColors,
1838
+ series: seriesOpts.map(buildLineSeries),
1839
+ dropLines: opts.dropLines ? {} : undefined,
1840
+ gapDepth: opts.gapDepth,
1841
+ axisIds: [catAx.axId, valAx.axId, serAx.axId]
1842
+ };
1843
+ result = { group, axes: [catAx, valAx, serAx] };
1844
+ break;
1845
+ }
1846
+ case "pie":
1847
+ case "pie3D": {
1848
+ const group = {
1849
+ type,
1850
+ varyColors: opts.varyColors ?? true,
1851
+ series: seriesOpts.map(buildPieSeries),
1852
+ firstSliceAng: opts.firstSliceAng ?? 0
1853
+ };
1854
+ result = { group, axes: [] };
1855
+ break;
1856
+ }
1857
+ case "doughnut": {
1858
+ const group = {
1859
+ type: "doughnut",
1860
+ varyColors: opts.varyColors ?? true,
1861
+ series: seriesOpts.map(buildPieSeries),
1862
+ firstSliceAng: opts.firstSliceAng ?? 0,
1863
+ holeSize: opts.holeSize ?? 50
1864
+ };
1865
+ result = { group, axes: [] };
1866
+ break;
1867
+ }
1868
+ case "area": {
1869
+ const { catAx, valAx } = buildCatValAxes(axIds);
1870
+ const group = {
1871
+ type,
1872
+ grouping: opts.grouping ?? "standard",
1873
+ varyColors: opts.varyColors,
1874
+ series: seriesOpts.map(buildAreaSeries),
1875
+ dropLines: opts.dropLines ? {} : undefined,
1876
+ axisIds: [catAx.axId, valAx.axId]
1877
+ };
1878
+ result = { group, axes: [catAx, valAx] };
1879
+ break;
1880
+ }
1881
+ case "area3D": {
1882
+ const { catAx, valAx, serAx } = buildCatValSerAxes(axIds);
1883
+ const group = {
1884
+ type,
1885
+ grouping: opts.grouping ?? "standard",
1886
+ varyColors: opts.varyColors,
1887
+ series: seriesOpts.map(buildAreaSeries),
1888
+ dropLines: opts.dropLines ? {} : undefined,
1889
+ // `CT_Area3DChart` carries `gapDepth`; pass it through from
1890
+ // options. The equivalent lines for `bar3D` / `line3D` already
1891
+ // did this — the omission here silently dropped the option.
1892
+ gapDepth: opts.gapDepth,
1893
+ axisIds: [catAx.axId, valAx.axId, serAx.axId]
1894
+ };
1895
+ result = { group, axes: [catAx, valAx, serAx] };
1896
+ break;
1897
+ }
1898
+ case "scatter": {
1899
+ const { xAx, yAx } = buildValValAxes(axIds);
1900
+ const group = {
1901
+ type: "scatter",
1902
+ scatterStyle: opts.scatterStyle ?? "lineMarker",
1903
+ varyColors: opts.varyColors,
1904
+ series: seriesOpts.map(buildScatterSeries),
1905
+ axisIds: [xAx.axId, yAx.axId]
1906
+ };
1907
+ result = { group, axes: [xAx, yAx] };
1908
+ break;
1909
+ }
1910
+ case "bubble": {
1911
+ const { xAx, yAx } = buildValValAxes(axIds);
1912
+ const group = {
1913
+ type: "bubble",
1914
+ varyColors: opts.varyColors,
1915
+ series: seriesOpts.map(buildBubbleSeries),
1916
+ bubbleScale: opts.bubbleScale,
1917
+ showNegBubbles: opts.showNegBubbles,
1918
+ sizeRepresents: opts.sizeRepresents,
1919
+ axisIds: [xAx.axId, yAx.axId]
1920
+ };
1921
+ result = { group, axes: [xAx, yAx] };
1922
+ break;
1923
+ }
1924
+ case "radar": {
1925
+ const { catAx, valAx } = buildCatValAxes(axIds);
1926
+ const group = {
1927
+ type: "radar",
1928
+ radarStyle: opts.radarStyle ?? "marker",
1929
+ varyColors: opts.varyColors,
1930
+ series: seriesOpts.map(buildRadarSeries),
1931
+ axisIds: [catAx.axId, valAx.axId]
1932
+ };
1933
+ result = { group, axes: [catAx, valAx] };
1934
+ break;
1935
+ }
1936
+ case "stock": {
1937
+ // `CT_StockChart` has no `varyColors` attribute per schema — see
1938
+ // `StockChartGroup` in types.ts. Reject the option here rather
1939
+ // than silently dropping it at emit time so the mistake
1940
+ // surfaces at authoring.
1941
+ if (opts.varyColors !== undefined) {
1942
+ throw new ChartOptionsError("stock charts do not support `varyColors` (not in CT_StockChart). Remove the field or switch to a line / bar / area chart.");
1943
+ }
1944
+ const { catAx, valAx } = buildCatValAxes(axIds);
1945
+ const group = {
1946
+ type: "stock",
1947
+ series: seriesOpts.map(buildLineSeries),
1948
+ hiLowLines: opts.hiLowLines ? {} : undefined,
1949
+ upDownBars: buildUpDownBarsFromOpts(opts.upDownBars),
1950
+ dropLines: opts.dropLines ? {} : undefined,
1951
+ axisIds: [catAx.axId, valAx.axId]
1952
+ };
1953
+ result = { group, axes: [catAx, valAx] };
1954
+ break;
1955
+ }
1956
+ case "surface":
1957
+ case "surface3D": {
1958
+ const { catAx, valAx, serAx } = buildCatValSerAxes(axIds);
1959
+ const group = {
1960
+ type,
1961
+ wireframe: opts.wireframe,
1962
+ series: seriesOpts.map(buildSurfaceSeries),
1963
+ axisIds: [catAx.axId, valAx.axId, serAx.axId]
1964
+ };
1965
+ if (opts.bandFormats && opts.bandFormats.length > 0) {
1966
+ group.bandFormats = opts.bandFormats.map(bf => {
1967
+ const spPr = toShapeProperties(bf.spPr);
1968
+ return { index: bf.index, spPr: spPr ?? {} };
1969
+ });
1970
+ }
1971
+ result = { group, axes: [catAx, valAx, serAx] };
1972
+ break;
1973
+ }
1974
+ case "ofPie": {
1975
+ const group = {
1976
+ type: "ofPie",
1977
+ ofPieType: opts.ofPieType ?? "pie",
1978
+ varyColors: opts.varyColors ?? true,
1979
+ series: seriesOpts.map(buildPieSeries),
1980
+ gapWidth: opts.gapWidth,
1981
+ splitType: opts.splitType,
1982
+ splitPos: opts.splitPos,
1983
+ secondPieSize: opts.secondPieSize,
1984
+ serLines: opts.serLines ? {} : undefined
1985
+ };
1986
+ result = { group, axes: [] };
1987
+ break;
1988
+ }
1989
+ default: {
1990
+ const _exhaustive = type;
1991
+ throw new ChartOptionsError(`Unsupported chart type: ${String(_exhaustive)}.`);
1992
+ }
1993
+ }
1994
+ // Post-process: apply group-level data labels
1995
+ if (opts.dataLabels) {
1996
+ result.group.dataLabels = buildDataLabelsFromOpts(opts.dataLabels);
1997
+ }
1998
+ // Post-process: apply axis options
1999
+ if (result.axes.length > 0) {
2000
+ // For cat+val axes, apply categoryAxis options to first cat/date axis,
2001
+ // and valueAxis options to first val axis.
2002
+ // For scatter/bubble (val+val), categoryAxis → first val (x), valueAxis → second val (y).
2003
+ const catAx = result.axes.find(a => a.axisType === "cat" || a.axisType === "date");
2004
+ const valAx = result.axes.find(a => a.axisType === "val");
2005
+ if (catAx) {
2006
+ applyAxisOptions(catAx, opts.categoryAxis);
2007
+ const vAx = result.axes.find(a => a.axisType === "val");
2008
+ if (vAx) {
2009
+ applyAxisOptions(vAx, opts.valueAxis);
2010
+ }
2011
+ }
2012
+ else if (valAx) {
2013
+ // scatter/bubble: x axis = first val, y axis = second val
2014
+ applyAxisOptions(valAx, opts.categoryAxis);
2015
+ const secondVal = result.axes.find(a => a.axisType === "val" && a.axId !== valAx.axId);
2016
+ if (secondVal) {
2017
+ applyAxisOptions(secondVal, opts.valueAxis);
2018
+ }
2019
+ }
2020
+ }
2021
+ return result;
2022
+ }
2023
+ /**
2024
+ * Finalize a ChartModel from a PlotArea and shared options.
2025
+ */
2026
+ function finalizeChartModel(plotArea, opts) {
2027
+ const chart = {
2028
+ plotArea,
2029
+ plotVisOnly: opts.plotVisOnly ?? true,
2030
+ dispBlanksAs: opts.displayBlanksAs ?? "gap"
2031
+ };
2032
+ if (opts.showDLblsOverMax !== undefined) {
2033
+ chart.showDLblsOverMax = opts.showDLblsOverMax;
2034
+ }
2035
+ if (opts.pivotSource) {
2036
+ // Don't mutate caller-owned `opts.pivotSource` — `extractPivotOptions`
2037
+ // already handles the merge priority between
2038
+ // `opts.pivotChartOptions` (explicit) and `pivotSource.options`
2039
+ // (embedded). Writing back here produced surprising side-effects
2040
+ // when callers reused the same `pivotSource` object across charts.
2041
+ chart.pivotFormats = [{ index: 0 }];
2042
+ }
2043
+ // Title handling has three mutually exclusive shapes:
2044
+ //
2045
+ // 1. `title === null` → explicit suppression. Emit
2046
+ // `autoTitleDeleted="1"` so Excel records the user removed the
2047
+ // auto-title. Do NOT build a title frame even if `titleOptions`
2048
+ // was also provided — the explicit `null` wins over layout /
2049
+ // style hints.
2050
+ // 2. `title` truthy → build the title, optionally apply
2051
+ // `titleOptions` on top.
2052
+ // 3. `title` absent, `titleOptions` set → layout / style for the
2053
+ // auto-generated title. Uncommon but valid.
2054
+ // 4. Everything else → leave `autoTitleDeleted` undefined so
2055
+ // the writer omits it, matching Excel's behaviour for a fresh
2056
+ // unmodified chart.
2057
+ //
2058
+ // Checking `title === null` before `if (opts.title)` is important —
2059
+ // `if (null)` is falsy, so reversing the order landed an explicit
2060
+ // `null` in the `titleOptions`-only branch that built an empty title
2061
+ // frame.
2062
+ if (opts.title === null) {
2063
+ chart.autoTitleDeleted = true;
2064
+ }
2065
+ else if (opts.title) {
2066
+ chart.title = buildTitle(opts.title);
2067
+ if (opts.titleOptions) {
2068
+ applyTitleOptions(chart.title, opts.titleOptions);
2069
+ }
2070
+ chart.autoTitleDeleted = false;
2071
+ }
2072
+ else if (opts.titleOptions) {
2073
+ // Layout/style without title text is unusual but allowed
2074
+ chart.title = { overlay: false };
2075
+ applyTitleOptions(chart.title, opts.titleOptions);
2076
+ chart.autoTitleDeleted = false;
2077
+ }
2078
+ // else: leave autoTitleDeleted undefined so the writer omits it,
2079
+ // matching Excel's behaviour for a fresh unmodified chart — the
2080
+ // automatic title appears unless the user explicitly removes it.
2081
+ const legend = buildLegend(opts);
2082
+ if (legend) {
2083
+ chart.legend = legend;
2084
+ if (opts.legendOptions) {
2085
+ applyLegendOptions(legend, opts.legendOptions);
2086
+ }
2087
+ }
2088
+ // Plot area options (layout, background)
2089
+ if (opts.plotAreaOptions) {
2090
+ if (opts.plotAreaOptions.layout) {
2091
+ plotArea.layout = opts.plotAreaOptions.layout;
2092
+ }
2093
+ const plotSpPr = toShapeProperties(opts.plotAreaOptions.spPr);
2094
+ if (plotSpPr) {
2095
+ plotArea.spPr = plotSpPr;
2096
+ }
2097
+ }
2098
+ if (opts.view3D) {
2099
+ chart.view3D = opts.view3D;
2100
+ }
2101
+ // 3D walls / floor
2102
+ const floor = toShapeProperties(opts.floor);
2103
+ if (floor) {
2104
+ chart.floor = floor;
2105
+ }
2106
+ const sideWall = toShapeProperties(opts.sideWall);
2107
+ if (sideWall) {
2108
+ chart.sideWall = sideWall;
2109
+ }
2110
+ const backWall = toShapeProperties(opts.backWall);
2111
+ if (backWall) {
2112
+ chart.backWall = backWall;
2113
+ }
2114
+ return {
2115
+ chart,
2116
+ style: opts.style,
2117
+ roundedCorners: false,
2118
+ lang: "en-US",
2119
+ pivotSource: opts.pivotSource ? buildPivotSourceXml(opts.pivotSource) : undefined,
2120
+ pivotOptions: extractPivotOptions(opts.pivotSource, opts.pivotChartOptions)
2121
+ };
2122
+ }
2123
+ /**
2124
+ * Resolve the effective {@link PivotChartOptions} for a model built from
2125
+ * {@link AddChartOptions}.
2126
+ *
2127
+ * Accepts two redundant inputs so callers can pass the structured metadata
2128
+ * via either the top-level `pivotChartOptions` field or the `pivotSource`
2129
+ * object (its `options` sub-field, retained for ergonomic clustering).
2130
+ * When both are set the top-level value wins — this matches the precedence
2131
+ * used elsewhere in `chart-builder.ts` when the same setting has two
2132
+ * spellings.
2133
+ *
2134
+ * Returns `undefined` when no options are provided so the writer can skip
2135
+ * emitting an empty `c14:pivotOptions` element.
2136
+ */
2137
+ function extractPivotOptions(source, explicit) {
2138
+ if (explicit) {
2139
+ return explicit;
2140
+ }
2141
+ if (source && typeof source === "object" && source.options) {
2142
+ return source.options;
2143
+ }
2144
+ return undefined;
2145
+ }
2146
+ function applyTitleOptions(title, opts) {
2147
+ if (opts.layout) {
2148
+ title.layout = opts.layout;
2149
+ }
2150
+ if (opts.overlay !== undefined) {
2151
+ title.overlay = opts.overlay;
2152
+ }
2153
+ const spPr = toShapeProperties(opts.spPr);
2154
+ if (spPr) {
2155
+ title.spPr = spPr;
2156
+ }
2157
+ if (opts.txPr) {
2158
+ title.txPr = opts.txPr;
2159
+ }
2160
+ }
2161
+ function applyLegendOptions(legend, opts) {
2162
+ if (opts.layout) {
2163
+ legend.layout = opts.layout;
2164
+ }
2165
+ if (opts.overlay !== undefined) {
2166
+ legend.overlay = opts.overlay;
2167
+ }
2168
+ const spPr = toShapeProperties(opts.spPr);
2169
+ if (spPr) {
2170
+ legend.spPr = spPr;
2171
+ }
2172
+ if (opts.txPr) {
2173
+ legend.txPr = opts.txPr;
2174
+ }
2175
+ if (opts.entries && opts.entries.length > 0) {
2176
+ legend.legendEntries = opts.entries.map(e => {
2177
+ const entry = { index: e.index };
2178
+ if (e.hidden) {
2179
+ entry.delete = true;
2180
+ }
2181
+ if (e.txPr) {
2182
+ entry.txPr = e.txPr;
2183
+ }
2184
+ return entry;
2185
+ });
2186
+ }
2187
+ }
2188
+ /**
2189
+ * Build a full ChartModel from the simplified AddChartOptions.
2190
+ */
2191
+ export function buildChartModel(opts) {
2192
+ validateChartOptions(opts);
2193
+ const seriesOpts = opts.series ?? [];
2194
+ const axIds = new AxIdAllocator();
2195
+ const { group: chartTypeGroup, axes } = buildChartTypeGroup(opts, seriesOpts, axIds);
2196
+ const plotArea = {
2197
+ chartTypes: [chartTypeGroup],
2198
+ axes,
2199
+ dataTable: buildDataTableFromOpts(opts.dataTable)
2200
+ };
2201
+ return finalizeChartModel(plotArea, opts);
2202
+ }
2203
+ /**
2204
+ * Build a combo chart model with multiple chart type groups.
2205
+ *
2206
+ * Each group can optionally be plotted on secondary axes.
2207
+ * The builder creates primary axes for the first group that needs
2208
+ * them, and secondary axes for any group with `useSecondaryAxis: true`.
2209
+ */
2210
+ export function buildComboChartModel(opts) {
2211
+ validateComboChartOptions(opts);
2212
+ const axIds = new AxIdAllocator();
2213
+ const chartTypeGroups = [];
2214
+ const allAxes = [];
2215
+ // Create primary axes (shared by all groups without useSecondaryAxis)
2216
+ let primaryCatAx;
2217
+ let primaryValAx;
2218
+ let primarySerAx;
2219
+ let primaryXAx;
2220
+ let primaryYAx;
2221
+ // Create secondary axes (shared by all groups with useSecondaryAxis)
2222
+ let secondaryCatAx;
2223
+ let secondaryValAx;
2224
+ let secondarySerAx;
2225
+ let secondaryXAx;
2226
+ let secondaryYAx;
2227
+ for (const groupOpts of opts.groups) {
2228
+ const seriesOpts = groupOpts.series ?? [];
2229
+ const { group, axes } = buildChartTypeGroup(groupOpts, seriesOpts, axIds);
2230
+ // Detect serAx (3D chart types produce 3 axes: catAx + valAx + serAx)
2231
+ const hasSerAx = axes.length >= 3 && axes[2].axisType === "ser";
2232
+ if (axes.length > 0 && groupOpts.useSecondaryAxis) {
2233
+ // Secondary axis group: create secondary axes if not yet created
2234
+ const isCatVal = axes[0].axisType === "cat";
2235
+ if (isCatVal) {
2236
+ if (!secondaryCatAx) {
2237
+ const sCatId = axIds.alloc();
2238
+ const sValId = axIds.alloc();
2239
+ secondaryCatAx = {
2240
+ axisType: "cat",
2241
+ axId: sCatId,
2242
+ scaling: { orientation: "minMax" },
2243
+ delete: true, // secondary cat axis is typically hidden
2244
+ axPos: "b",
2245
+ crossAx: sValId,
2246
+ crosses: "autoZero",
2247
+ auto: true,
2248
+ lblAlgn: "ctr",
2249
+ lblOffset: 100
2250
+ };
2251
+ secondaryValAx = {
2252
+ axisType: "val",
2253
+ axId: sValId,
2254
+ scaling: { orientation: "minMax" },
2255
+ delete: false,
2256
+ axPos: "r", // right side
2257
+ crossAx: sCatId,
2258
+ crosses: "max", // cross at max of secondary cat axis
2259
+ crossBetween: "between"
2260
+ };
2261
+ allAxes.push(secondaryCatAx, secondaryValAx);
2262
+ }
2263
+ // Apply the group's axis options onto the shared secondary
2264
+ // axes. Without this, the `categoryAxis` / `valueAxis` fields
2265
+ // on a second (or third, …) secondary-axis group were silently
2266
+ // discarded along with the auto-built axes — `numFmt`,
2267
+ // `majorUnit`, `title`, `orientation`, etc. never reached the
2268
+ // shared axis object.
2269
+ applyAxisOptions(secondaryCatAx, groupOpts.categoryAxis);
2270
+ applyAxisOptions(secondaryValAx, groupOpts.valueAxis);
2271
+ if (hasSerAx) {
2272
+ // 3D secondary: create or reuse secondary serAx
2273
+ if (!secondarySerAx) {
2274
+ const sSerAxId = axIds.alloc();
2275
+ secondarySerAx = {
2276
+ axisType: "ser",
2277
+ axId: sSerAxId,
2278
+ scaling: { orientation: "minMax" },
2279
+ delete: false,
2280
+ axPos: "b",
2281
+ crossAx: secondaryCatAx.axId,
2282
+ crosses: "autoZero"
2283
+ };
2284
+ allAxes.push(secondarySerAx);
2285
+ }
2286
+ group.axisIds = [secondaryCatAx.axId, secondaryValAx.axId, secondarySerAx.axId];
2287
+ }
2288
+ else {
2289
+ group.axisIds = [secondaryCatAx.axId, secondaryValAx.axId];
2290
+ }
2291
+ }
2292
+ else {
2293
+ // Scatter/bubble secondary axes (valAx + valAx).
2294
+ //
2295
+ // `crossBetween` is only valid when the value axis crosses a
2296
+ // *category* axis — it specifies the tick-label alignment
2297
+ // relative to category boundaries (`between` / `midCat`). On a
2298
+ // val/val pair it has no defined meaning and strict OOXML
2299
+ // validators flag it. The primary scatter axes in
2300
+ // `buildValValAxes` deliberately omit it, so emit the secondary
2301
+ // scatter axes the same way to stay round-trip consistent.
2302
+ if (!secondaryXAx) {
2303
+ const sXId = axIds.alloc();
2304
+ const sYId = axIds.alloc();
2305
+ secondaryXAx = {
2306
+ axisType: "val",
2307
+ axId: sXId,
2308
+ scaling: { orientation: "minMax" },
2309
+ delete: true,
2310
+ axPos: "b",
2311
+ crossAx: sYId,
2312
+ crosses: "autoZero"
2313
+ };
2314
+ secondaryYAx = {
2315
+ axisType: "val",
2316
+ axId: sYId,
2317
+ scaling: { orientation: "minMax" },
2318
+ delete: false,
2319
+ axPos: "r",
2320
+ crossAx: sXId,
2321
+ crosses: "max"
2322
+ };
2323
+ allAxes.push(secondaryXAx, secondaryYAx);
2324
+ }
2325
+ // `categoryAxis` / `valueAxis` map to scatter x / y respectively
2326
+ // (mirroring the primary scatter path in `buildChartTypeGroup`).
2327
+ applyAxisOptions(secondaryXAx, groupOpts.categoryAxis);
2328
+ applyAxisOptions(secondaryYAx, groupOpts.valueAxis);
2329
+ group.axisIds = [secondaryXAx.axId, secondaryYAx.axId];
2330
+ }
2331
+ // Don't add the auto-generated axes from buildChartTypeGroup
2332
+ }
2333
+ else if (axes.length > 0) {
2334
+ // Primary axis group
2335
+ const isCatVal = axes[0].axisType === "cat";
2336
+ if (isCatVal) {
2337
+ if (!primaryCatAx) {
2338
+ primaryCatAx = axes[0];
2339
+ primaryValAx = axes[1];
2340
+ allAxes.push(primaryCatAx, primaryValAx);
2341
+ if (hasSerAx) {
2342
+ primarySerAx = axes[2];
2343
+ allAxes.push(primarySerAx);
2344
+ }
2345
+ }
2346
+ else {
2347
+ // Reuse primary axes — but apply the current group's axis
2348
+ // options onto the shared objects so its customisations
2349
+ // aren't silently discarded with the throw-away auto-built
2350
+ // axes. Previously only the FIRST group's `categoryAxis` /
2351
+ // `valueAxis` reached the output; every subsequent group's
2352
+ // overrides were dropped on the floor.
2353
+ applyAxisOptions(primaryCatAx, groupOpts.categoryAxis);
2354
+ applyAxisOptions(primaryValAx, groupOpts.valueAxis);
2355
+ if (hasSerAx) {
2356
+ // 3D group needs serAx — create one if the primary set didn't have it
2357
+ if (!primarySerAx) {
2358
+ const serAxId = axIds.alloc();
2359
+ primarySerAx = {
2360
+ axisType: "ser",
2361
+ axId: serAxId,
2362
+ scaling: { orientation: "minMax" },
2363
+ delete: false,
2364
+ axPos: "b",
2365
+ crossAx: primaryCatAx.axId,
2366
+ crosses: "autoZero"
2367
+ };
2368
+ allAxes.push(primarySerAx);
2369
+ }
2370
+ group.axisIds = [primaryCatAx.axId, primaryValAx.axId, primarySerAx.axId];
2371
+ }
2372
+ else {
2373
+ group.axisIds = [primaryCatAx.axId, primaryValAx.axId];
2374
+ }
2375
+ }
2376
+ }
2377
+ else {
2378
+ // Scatter/bubble
2379
+ if (!primaryXAx) {
2380
+ primaryXAx = axes[0];
2381
+ primaryYAx = axes[1];
2382
+ allAxes.push(primaryXAx, primaryYAx);
2383
+ }
2384
+ else {
2385
+ // Same rationale as the cat/val reuse path above — apply this
2386
+ // group's scatter axis options onto the shared val/val pair.
2387
+ applyAxisOptions(primaryXAx, groupOpts.categoryAxis);
2388
+ applyAxisOptions(primaryYAx, groupOpts.valueAxis);
2389
+ group.axisIds = [primaryXAx.axId, primaryYAx.axId];
2390
+ }
2391
+ }
2392
+ }
2393
+ chartTypeGroups.push(group);
2394
+ }
2395
+ // Renumber series index/order globally across all groups.
2396
+ // OOXML requires c:idx and c:order to be unique within the entire chart.
2397
+ // Only renumber if indices are the default per-group values (0, 1, 2...) —
2398
+ // i.e. they would collide across groups. If the user has already assigned
2399
+ // explicit globally-unique indices, leave them untouched (P4.2 fix).
2400
+ if (indicesWouldCollide(chartTypeGroups)) {
2401
+ let globalIdx = 0;
2402
+ for (const grp of chartTypeGroups) {
2403
+ for (const s of grp.series) {
2404
+ s.index = globalIdx;
2405
+ s.order = globalIdx;
2406
+ globalIdx++;
2407
+ }
2408
+ }
2409
+ }
2410
+ const plotArea = {
2411
+ chartTypes: chartTypeGroups,
2412
+ axes: allAxes,
2413
+ dataTable: buildDataTableFromOpts(opts.dataTable)
2414
+ };
2415
+ return finalizeChartModel(plotArea, opts);
2416
+ }
2417
+ /**
2418
+ * Check whether any two groups have colliding series indices.
2419
+ * When true, the combo builder renumbers all series to guarantee uniqueness.
2420
+ */
2421
+ function indicesWouldCollide(groups) {
2422
+ const seen = new Set();
2423
+ for (const g of groups) {
2424
+ for (const s of g.series) {
2425
+ if (seen.has(s.index)) {
2426
+ return true;
2427
+ }
2428
+ seen.add(s.index);
2429
+ }
2430
+ }
2431
+ return false;
2432
+ }