@rowsncolumns/toolkit 24.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/LICENSE.md +100 -0
  2. package/Readme.md +27 -0
  3. package/dist/cjs/autofilter-condition.d.ts +43 -0
  4. package/dist/cjs/autofilter-condition.d.ts.map +1 -0
  5. package/dist/cjs/autofilter-condition.js +155 -0
  6. package/dist/cjs/csv-export.d.ts +49 -0
  7. package/dist/cjs/csv-export.d.ts.map +1 -0
  8. package/dist/cjs/csv-export.js +142 -0
  9. package/dist/cjs/csv-import-worker.d.ts +16 -0
  10. package/dist/cjs/csv-import-worker.d.ts.map +1 -0
  11. package/dist/cjs/csv-import-worker.js +60 -0
  12. package/dist/cjs/csv-import.d.ts +38 -0
  13. package/dist/cjs/csv-import.d.ts.map +1 -0
  14. package/dist/cjs/csv-import.js +166 -0
  15. package/dist/cjs/csv-parser/helpers.d.ts +14 -0
  16. package/dist/cjs/csv-parser/helpers.d.ts.map +1 -0
  17. package/dist/cjs/csv-parser/helpers.js +145 -0
  18. package/dist/cjs/csv-parser/types.d.ts +66 -0
  19. package/dist/cjs/csv-parser/types.d.ts.map +1 -0
  20. package/dist/cjs/csv-parser/types.js +14 -0
  21. package/dist/cjs/csv-parser/worker.d.ts +2 -0
  22. package/dist/cjs/csv-parser/worker.d.ts.map +1 -0
  23. package/dist/cjs/csv-parser/worker.js +200 -0
  24. package/dist/cjs/excel-export.d.ts +11 -0
  25. package/dist/cjs/excel-export.d.ts.map +1 -0
  26. package/dist/cjs/excel-export.js +22 -0
  27. package/dist/cjs/excel-import-session.d.ts +51 -0
  28. package/dist/cjs/excel-import-session.d.ts.map +1 -0
  29. package/dist/cjs/excel-import-session.js +307 -0
  30. package/dist/cjs/excel-import-worker.d.ts +7 -0
  31. package/dist/cjs/excel-import-worker.d.ts.map +1 -0
  32. package/dist/cjs/excel-import-worker.js +119 -0
  33. package/dist/cjs/excel-parser/builtin-numfmts.d.ts +24 -0
  34. package/dist/cjs/excel-parser/builtin-numfmts.d.ts.map +1 -0
  35. package/dist/cjs/excel-parser/builtin-numfmts.js +63 -0
  36. package/dist/cjs/excel-parser/cfb-decryptor.d.ts +53 -0
  37. package/dist/cjs/excel-parser/cfb-decryptor.d.ts.map +1 -0
  38. package/dist/cjs/excel-parser/cfb-decryptor.js +553 -0
  39. package/dist/cjs/excel-parser/cfb-encryptor.d.ts +23 -0
  40. package/dist/cjs/excel-parser/cfb-encryptor.d.ts.map +1 -0
  41. package/dist/cjs/excel-parser/cfb-encryptor.js +200 -0
  42. package/dist/cjs/excel-parser/dv-cell-stamp.d.ts +29 -0
  43. package/dist/cjs/excel-parser/dv-cell-stamp.d.ts.map +1 -0
  44. package/dist/cjs/excel-parser/dv-cell-stamp.js +239 -0
  45. package/dist/cjs/excel-parser/helpers.d.ts +28 -0
  46. package/dist/cjs/excel-parser/helpers.d.ts.map +1 -0
  47. package/dist/cjs/excel-parser/helpers.js +188 -0
  48. package/dist/cjs/excel-parser/interface.d.ts +179 -0
  49. package/dist/cjs/excel-parser/interface.d.ts.map +1 -0
  50. package/dist/cjs/excel-parser/interface.js +1 -0
  51. package/dist/cjs/excel-parser/plugins/base/index.d.ts +31 -0
  52. package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -0
  53. package/dist/cjs/excel-parser/plugins/base/index.js +101 -0
  54. package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
  55. package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
  56. package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.js +488 -0
  57. package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts +15 -0
  58. package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
  59. package/dist/cjs/excel-parser/plugins/ods/data-validations.js +353 -0
  60. package/dist/cjs/excel-parser/plugins/ods/formula.d.ts +8 -0
  61. package/dist/cjs/excel-parser/plugins/ods/formula.d.ts.map +1 -0
  62. package/dist/cjs/excel-parser/plugins/ods/formula.js +82 -0
  63. package/dist/cjs/excel-parser/plugins/ods/index.d.ts +122 -0
  64. package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -0
  65. package/dist/cjs/excel-parser/plugins/ods/index.js +3642 -0
  66. package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts +25 -0
  67. package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
  68. package/dist/cjs/excel-parser/plugins/ods/sparklines.js +221 -0
  69. package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +60 -0
  70. package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -0
  71. package/dist/cjs/excel-parser/plugins/ods/styles.js +808 -0
  72. package/dist/cjs/excel-parser/plugins/ods/types.d.ts +7 -0
  73. package/dist/cjs/excel-parser/plugins/ods/types.d.ts.map +1 -0
  74. package/dist/cjs/excel-parser/plugins/ods/types.js +1 -0
  75. package/dist/cjs/excel-parser/plugins/xls/index.d.ts +5 -0
  76. package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -0
  77. package/dist/cjs/excel-parser/plugins/xls/index.js +19 -0
  78. package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
  79. package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
  80. package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.js +49 -0
  81. package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts +117 -0
  82. package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
  83. package/dist/cjs/excel-parser/plugins/xlsb/index.js +2972 -0
  84. package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
  85. package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
  86. package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.js +527 -0
  87. package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts +5 -0
  88. package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
  89. package/dist/cjs/excel-parser/plugins/xlsm/index.js +10 -0
  90. package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +60 -0
  91. package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
  92. package/dist/cjs/excel-parser/plugins/xlsx/charts.js +2178 -0
  93. package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
  94. package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
  95. package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.js +620 -0
  96. package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
  97. package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
  98. package/dist/cjs/excel-parser/plugins/xlsx/data-validations.js +515 -0
  99. package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
  100. package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
  101. package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +941 -0
  102. package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +320 -0
  103. package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
  104. package/dist/cjs/excel-parser/plugins/xlsx/index.js +6056 -0
  105. package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
  106. package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
  107. package/dist/cjs/excel-parser/plugins/xlsx/numfmt.js +3 -0
  108. package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
  109. package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
  110. package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +342 -0
  111. package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
  112. package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
  113. package/dist/cjs/excel-parser/plugins/xlsx/relationships.js +26 -0
  114. package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
  115. package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
  116. package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.js +59 -0
  117. package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +44 -0
  118. package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
  119. package/dist/cjs/excel-parser/plugins/xlsx/styles.js +1377 -0
  120. package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts +50 -0
  121. package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
  122. package/dist/cjs/excel-parser/plugins/xlsx/theme.js +150 -0
  123. package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
  124. package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
  125. package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.js +141 -0
  126. package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
  127. package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
  128. package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.js +407 -0
  129. package/dist/cjs/excel-parser/registry.d.ts +5 -0
  130. package/dist/cjs/excel-parser/registry.d.ts.map +1 -0
  131. package/dist/cjs/excel-parser/registry.js +21 -0
  132. package/dist/cjs/excel-parser/style-registry.d.ts +51 -0
  133. package/dist/cjs/excel-parser/style-registry.d.ts.map +1 -0
  134. package/dist/cjs/excel-parser/style-registry.js +175 -0
  135. package/dist/cjs/excel-parser/theme-default.d.ts +3 -0
  136. package/dist/cjs/excel-parser/theme-default.d.ts.map +1 -0
  137. package/dist/cjs/excel-parser/theme-default.js +19 -0
  138. package/dist/cjs/excel-parser/types.d.ts +365 -0
  139. package/dist/cjs/excel-parser/types.d.ts.map +1 -0
  140. package/dist/cjs/excel-parser/types.js +59 -0
  141. package/dist/cjs/excel-parser/utils.d.ts +6 -0
  142. package/dist/cjs/excel-parser/utils.d.ts.map +1 -0
  143. package/dist/cjs/excel-parser/utils.js +30 -0
  144. package/dist/cjs/excel-parser/workbook.d.ts +51 -0
  145. package/dist/cjs/excel-parser/workbook.d.ts.map +1 -0
  146. package/dist/cjs/excel-parser/workbook.js +317 -0
  147. package/dist/cjs/excel-parser/worker.d.ts +2 -0
  148. package/dist/cjs/excel-parser/worker.d.ts.map +1 -0
  149. package/dist/cjs/excel-parser/worker.js +1149 -0
  150. package/dist/cjs/excel-parser/zip-parser-streaming.d.ts +13 -0
  151. package/dist/cjs/excel-parser/zip-parser-streaming.d.ts.map +1 -0
  152. package/dist/cjs/excel-parser/zip-parser-streaming.js +200 -0
  153. package/dist/cjs/excel-parser/zip-parser.d.ts +11 -0
  154. package/dist/cjs/excel-parser/zip-parser.d.ts.map +1 -0
  155. package/dist/cjs/excel-parser/zip-parser.js +49 -0
  156. package/dist/cjs/exporter/invalid-data-validation.d.ts +19 -0
  157. package/dist/cjs/exporter/invalid-data-validation.d.ts.map +1 -0
  158. package/dist/cjs/exporter/invalid-data-validation.js +39 -0
  159. package/dist/cjs/exporter/ods/ods-export.d.ts +26 -0
  160. package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -0
  161. package/dist/cjs/exporter/ods/ods-export.js +3714 -0
  162. package/dist/cjs/exporter/ods/sparkline-builder.d.ts +33 -0
  163. package/dist/cjs/exporter/ods/sparkline-builder.d.ts.map +1 -0
  164. package/dist/cjs/exporter/ods/sparkline-builder.js +221 -0
  165. package/dist/cjs/exporter/xlsx/chart-builder.d.ts +3 -0
  166. package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -0
  167. package/dist/cjs/exporter/xlsx/chart-builder.js +1901 -0
  168. package/dist/cjs/exporter/xlsx/chart-templates.d.ts +1781 -0
  169. package/dist/cjs/exporter/xlsx/chart-templates.d.ts.map +1 -0
  170. package/dist/cjs/exporter/xlsx/chart-templates.js +1798 -0
  171. package/dist/cjs/exporter/xlsx/future-functions.d.ts +10 -0
  172. package/dist/cjs/exporter/xlsx/future-functions.d.ts.map +1 -0
  173. package/dist/cjs/exporter/xlsx/future-functions.js +264 -0
  174. package/dist/cjs/exporter/xlsx/pivot-builder.d.ts +58 -0
  175. package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -0
  176. package/dist/cjs/exporter/xlsx/pivot-builder.js +277 -0
  177. package/dist/cjs/exporter/xlsx/power-query-builder.d.ts +26 -0
  178. package/dist/cjs/exporter/xlsx/power-query-builder.d.ts.map +1 -0
  179. package/dist/cjs/exporter/xlsx/power-query-builder.js +306 -0
  180. package/dist/cjs/exporter/xlsx/slicer-builder.d.ts +11 -0
  181. package/dist/cjs/exporter/xlsx/slicer-builder.d.ts.map +1 -0
  182. package/dist/cjs/exporter/xlsx/slicer-builder.js +87 -0
  183. package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts +61 -0
  184. package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
  185. package/dist/cjs/exporter/xlsx/sparkline-builder.js +489 -0
  186. package/dist/cjs/exporter/xlsx/style-builder.d.ts +93 -0
  187. package/dist/cjs/exporter/xlsx/style-builder.d.ts.map +1 -0
  188. package/dist/cjs/exporter/xlsx/style-builder.js +813 -0
  189. package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
  190. package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
  191. package/dist/cjs/exporter/xlsx/threaded-comments-builder.js +189 -0
  192. package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +121 -0
  193. package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -0
  194. package/dist/cjs/exporter/xlsx/xlsx-export.js +4596 -0
  195. package/dist/cjs/helpers/theme-xml-generator.d.ts +8 -0
  196. package/dist/cjs/helpers/theme-xml-generator.d.ts.map +1 -0
  197. package/dist/cjs/helpers/theme-xml-generator.js +33 -0
  198. package/dist/cjs/helpers.d.ts +34 -0
  199. package/dist/cjs/helpers.d.ts.map +1 -0
  200. package/dist/cjs/helpers.js +189 -0
  201. package/dist/cjs/index.d.ts +16 -0
  202. package/dist/cjs/index.d.ts.map +1 -0
  203. package/dist/cjs/index.js +15 -0
  204. package/dist/cjs/indexed-colors.d.ts +2 -0
  205. package/dist/cjs/indexed-colors.d.ts.map +1 -0
  206. package/dist/cjs/indexed-colors.js +75 -0
  207. package/dist/cjs/ods-export.d.ts +24 -0
  208. package/dist/cjs/ods-export.d.ts.map +1 -0
  209. package/dist/cjs/ods-export.js +23 -0
  210. package/dist/cjs/parse.d.ts +24 -0
  211. package/dist/cjs/parse.d.ts.map +1 -0
  212. package/dist/cjs/parse.js +68 -0
  213. package/dist/cjs/power-query.d.ts +41 -0
  214. package/dist/cjs/power-query.d.ts.map +1 -0
  215. package/dist/cjs/power-query.js +22 -0
  216. package/dist/cjs/server.d.ts +9 -0
  217. package/dist/cjs/server.d.ts.map +1 -0
  218. package/dist/cjs/server.js +8 -0
  219. package/dist/cjs/theme1.d.ts +3 -0
  220. package/dist/cjs/theme1.d.ts.map +1 -0
  221. package/dist/cjs/theme1.js +2 -0
  222. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
  223. package/dist/cjs/types.d.ts +14 -0
  224. package/dist/cjs/types.d.ts.map +1 -0
  225. package/dist/cjs/types.js +14 -0
  226. package/dist/cjs/vitest.config.d.ts +3 -0
  227. package/dist/cjs/vitest.config.d.ts.map +1 -0
  228. package/dist/cjs/vitest.config.js +16 -0
  229. package/dist/esm/autofilter-condition.d.ts +43 -0
  230. package/dist/esm/autofilter-condition.d.ts.map +1 -0
  231. package/dist/esm/autofilter-condition.js +145 -0
  232. package/dist/esm/csv-export.d.ts +49 -0
  233. package/dist/esm/csv-export.d.ts.map +1 -0
  234. package/dist/esm/csv-export.js +126 -0
  235. package/dist/esm/csv-import-worker.d.ts +16 -0
  236. package/dist/esm/csv-import-worker.d.ts.map +1 -0
  237. package/dist/esm/csv-import-worker.js +60 -0
  238. package/dist/esm/csv-import.d.ts +38 -0
  239. package/dist/esm/csv-import.d.ts.map +1 -0
  240. package/dist/esm/csv-import.js +132 -0
  241. package/dist/esm/csv-parser/helpers.d.ts +14 -0
  242. package/dist/esm/csv-parser/helpers.d.ts.map +1 -0
  243. package/dist/esm/csv-parser/helpers.js +0 -0
  244. package/dist/esm/csv-parser/types.d.ts +66 -0
  245. package/dist/esm/csv-parser/types.d.ts.map +1 -0
  246. package/dist/esm/csv-parser/types.js +14 -0
  247. package/dist/esm/csv-parser/worker.d.ts +2 -0
  248. package/dist/esm/csv-parser/worker.d.ts.map +1 -0
  249. package/dist/esm/csv-parser/worker.js +154 -0
  250. package/dist/esm/excel-export.d.ts +11 -0
  251. package/dist/esm/excel-export.d.ts.map +1 -0
  252. package/dist/esm/excel-export.js +13 -0
  253. package/dist/esm/excel-import-session.d.ts +51 -0
  254. package/dist/esm/excel-import-session.d.ts.map +1 -0
  255. package/dist/esm/excel-import-session.js +255 -0
  256. package/dist/esm/excel-import-worker.d.ts +7 -0
  257. package/dist/esm/excel-import-worker.d.ts.map +1 -0
  258. package/dist/esm/excel-import-worker.js +116 -0
  259. package/dist/esm/excel-parser/builtin-numfmts.d.ts +24 -0
  260. package/dist/esm/excel-parser/builtin-numfmts.d.ts.map +1 -0
  261. package/dist/esm/excel-parser/builtin-numfmts.js +59 -0
  262. package/dist/esm/excel-parser/cfb-decryptor.d.ts +53 -0
  263. package/dist/esm/excel-parser/cfb-decryptor.d.ts.map +1 -0
  264. package/dist/esm/excel-parser/cfb-decryptor.js +493 -0
  265. package/dist/esm/excel-parser/cfb-encryptor.d.ts +23 -0
  266. package/dist/esm/excel-parser/cfb-encryptor.d.ts.map +1 -0
  267. package/dist/esm/excel-parser/cfb-encryptor.js +181 -0
  268. package/dist/esm/excel-parser/dv-cell-stamp.d.ts +29 -0
  269. package/dist/esm/excel-parser/dv-cell-stamp.d.ts.map +1 -0
  270. package/dist/esm/excel-parser/dv-cell-stamp.js +155 -0
  271. package/dist/esm/excel-parser/helpers.d.ts +28 -0
  272. package/dist/esm/excel-parser/helpers.d.ts.map +1 -0
  273. package/dist/esm/excel-parser/helpers.js +160 -0
  274. package/dist/esm/excel-parser/interface.d.ts +179 -0
  275. package/dist/esm/excel-parser/interface.d.ts.map +1 -0
  276. package/dist/esm/excel-parser/interface.js +1 -0
  277. package/dist/esm/excel-parser/plugins/base/index.d.ts +31 -0
  278. package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -0
  279. package/dist/esm/excel-parser/plugins/base/index.js +64 -0
  280. package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
  281. package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
  282. package/dist/esm/excel-parser/plugins/ods/conditional-formatting.js +405 -0
  283. package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts +15 -0
  284. package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
  285. package/dist/esm/excel-parser/plugins/ods/data-validations.js +331 -0
  286. package/dist/esm/excel-parser/plugins/ods/formula.d.ts +8 -0
  287. package/dist/esm/excel-parser/plugins/ods/formula.d.ts.map +1 -0
  288. package/dist/esm/excel-parser/plugins/ods/formula.js +82 -0
  289. package/dist/esm/excel-parser/plugins/ods/index.d.ts +122 -0
  290. package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -0
  291. package/dist/esm/excel-parser/plugins/ods/index.js +2896 -0
  292. package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts +25 -0
  293. package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
  294. package/dist/esm/excel-parser/plugins/ods/sparklines.js +188 -0
  295. package/dist/esm/excel-parser/plugins/ods/styles.d.ts +60 -0
  296. package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -0
  297. package/dist/esm/excel-parser/plugins/ods/styles.js +732 -0
  298. package/dist/esm/excel-parser/plugins/ods/types.d.ts +7 -0
  299. package/dist/esm/excel-parser/plugins/ods/types.d.ts.map +1 -0
  300. package/dist/esm/excel-parser/plugins/ods/types.js +1 -0
  301. package/dist/esm/excel-parser/plugins/xls/index.d.ts +5 -0
  302. package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -0
  303. package/dist/esm/excel-parser/plugins/xls/index.js +7 -0
  304. package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
  305. package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
  306. package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.js +48 -0
  307. package/dist/esm/excel-parser/plugins/xlsb/index.d.ts +117 -0
  308. package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
  309. package/dist/esm/excel-parser/plugins/xlsb/index.js +2339 -0
  310. package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
  311. package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
  312. package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.js +522 -0
  313. package/dist/esm/excel-parser/plugins/xlsm/index.d.ts +5 -0
  314. package/dist/esm/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
  315. package/dist/esm/excel-parser/plugins/xlsm/index.js +6 -0
  316. package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +60 -0
  317. package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
  318. package/dist/esm/excel-parser/plugins/xlsx/charts.js +2036 -0
  319. package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
  320. package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
  321. package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.js +621 -0
  322. package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
  323. package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
  324. package/dist/esm/excel-parser/plugins/xlsx/data-validations.js +493 -0
  325. package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
  326. package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
  327. package/dist/esm/excel-parser/plugins/xlsx/drawing.js +905 -0
  328. package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +320 -0
  329. package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
  330. package/dist/esm/excel-parser/plugins/xlsx/index.js +4654 -0
  331. package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
  332. package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
  333. package/dist/esm/excel-parser/plugins/xlsx/numfmt.js +3 -0
  334. package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
  335. package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
  336. package/dist/esm/excel-parser/plugins/xlsx/pivots.js +254 -0
  337. package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
  338. package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
  339. package/dist/esm/excel-parser/plugins/xlsx/relationships.js +13 -0
  340. package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
  341. package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
  342. package/dist/esm/excel-parser/plugins/xlsx/sheet-views.js +64 -0
  343. package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +44 -0
  344. package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
  345. package/dist/esm/excel-parser/plugins/xlsx/styles.js +1365 -0
  346. package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts +50 -0
  347. package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
  348. package/dist/esm/excel-parser/plugins/xlsx/theme.js +127 -0
  349. package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
  350. package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
  351. package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.js +103 -0
  352. package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
  353. package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
  354. package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.js +399 -0
  355. package/dist/esm/excel-parser/registry.d.ts +5 -0
  356. package/dist/esm/excel-parser/registry.d.ts.map +1 -0
  357. package/dist/esm/excel-parser/registry.js +20 -0
  358. package/dist/esm/excel-parser/style-registry.d.ts +51 -0
  359. package/dist/esm/excel-parser/style-registry.d.ts.map +1 -0
  360. package/dist/esm/excel-parser/style-registry.js +163 -0
  361. package/dist/esm/excel-parser/theme-default.d.ts +3 -0
  362. package/dist/esm/excel-parser/theme-default.d.ts.map +1 -0
  363. package/dist/esm/excel-parser/theme-default.js +19 -0
  364. package/dist/esm/excel-parser/types.d.ts +365 -0
  365. package/dist/esm/excel-parser/types.d.ts.map +1 -0
  366. package/dist/esm/excel-parser/types.js +59 -0
  367. package/dist/esm/excel-parser/utils.d.ts +6 -0
  368. package/dist/esm/excel-parser/utils.d.ts.map +1 -0
  369. package/dist/esm/excel-parser/utils.js +25 -0
  370. package/dist/esm/excel-parser/workbook.d.ts +51 -0
  371. package/dist/esm/excel-parser/workbook.d.ts.map +1 -0
  372. package/dist/esm/excel-parser/workbook.js +192 -0
  373. package/dist/esm/excel-parser/worker.d.ts +2 -0
  374. package/dist/esm/excel-parser/worker.d.ts.map +1 -0
  375. package/dist/esm/excel-parser/worker.js +862 -0
  376. package/dist/esm/excel-parser/zip-parser-streaming.d.ts +13 -0
  377. package/dist/esm/excel-parser/zip-parser-streaming.d.ts.map +1 -0
  378. package/dist/esm/excel-parser/zip-parser-streaming.js +119 -0
  379. package/dist/esm/excel-parser/zip-parser.d.ts +11 -0
  380. package/dist/esm/excel-parser/zip-parser.d.ts.map +1 -0
  381. package/dist/esm/excel-parser/zip-parser.js +43 -0
  382. package/dist/esm/exporter/invalid-data-validation.d.ts +19 -0
  383. package/dist/esm/exporter/invalid-data-validation.d.ts.map +1 -0
  384. package/dist/esm/exporter/invalid-data-validation.js +37 -0
  385. package/dist/esm/exporter/ods/ods-export.d.ts +26 -0
  386. package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -0
  387. package/dist/esm/exporter/ods/ods-export.js +3238 -0
  388. package/dist/esm/exporter/ods/sparkline-builder.d.ts +33 -0
  389. package/dist/esm/exporter/ods/sparkline-builder.d.ts.map +1 -0
  390. package/dist/esm/exporter/ods/sparkline-builder.js +165 -0
  391. package/dist/esm/exporter/xlsx/chart-builder.d.ts +3 -0
  392. package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -0
  393. package/dist/esm/exporter/xlsx/chart-builder.js +1805 -0
  394. package/dist/esm/exporter/xlsx/chart-templates.d.ts +1781 -0
  395. package/dist/esm/exporter/xlsx/chart-templates.d.ts.map +1 -0
  396. package/dist/esm/exporter/xlsx/chart-templates.js +1798 -0
  397. package/dist/esm/exporter/xlsx/future-functions.d.ts +10 -0
  398. package/dist/esm/exporter/xlsx/future-functions.d.ts.map +1 -0
  399. package/dist/esm/exporter/xlsx/future-functions.js +264 -0
  400. package/dist/esm/exporter/xlsx/pivot-builder.d.ts +58 -0
  401. package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -0
  402. package/dist/esm/exporter/xlsx/pivot-builder.js +230 -0
  403. package/dist/esm/exporter/xlsx/power-query-builder.d.ts +26 -0
  404. package/dist/esm/exporter/xlsx/power-query-builder.d.ts.map +1 -0
  405. package/dist/esm/exporter/xlsx/power-query-builder.js +257 -0
  406. package/dist/esm/exporter/xlsx/slicer-builder.d.ts +11 -0
  407. package/dist/esm/exporter/xlsx/slicer-builder.d.ts.map +1 -0
  408. package/dist/esm/exporter/xlsx/slicer-builder.js +84 -0
  409. package/dist/esm/exporter/xlsx/sparkline-builder.d.ts +61 -0
  410. package/dist/esm/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
  411. package/dist/esm/exporter/xlsx/sparkline-builder.js +437 -0
  412. package/dist/esm/exporter/xlsx/style-builder.d.ts +93 -0
  413. package/dist/esm/exporter/xlsx/style-builder.d.ts.map +1 -0
  414. package/dist/esm/exporter/xlsx/style-builder.js +795 -0
  415. package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
  416. package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
  417. package/dist/esm/exporter/xlsx/threaded-comments-builder.js +175 -0
  418. package/dist/esm/exporter/xlsx/xlsx-export.d.ts +121 -0
  419. package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -0
  420. package/dist/esm/exporter/xlsx/xlsx-export.js +4062 -0
  421. package/dist/esm/helpers/theme-xml-generator.d.ts +8 -0
  422. package/dist/esm/helpers/theme-xml-generator.d.ts.map +1 -0
  423. package/dist/esm/helpers/theme-xml-generator.js +33 -0
  424. package/dist/esm/helpers.d.ts +34 -0
  425. package/dist/esm/helpers.d.ts.map +1 -0
  426. package/dist/esm/helpers.js +182 -0
  427. package/dist/esm/index.d.ts +16 -0
  428. package/dist/esm/index.d.ts.map +1 -0
  429. package/dist/esm/index.js +15 -0
  430. package/dist/esm/indexed-colors.d.ts +2 -0
  431. package/dist/esm/indexed-colors.d.ts.map +1 -0
  432. package/dist/esm/indexed-colors.js +75 -0
  433. package/dist/esm/ods-export.d.ts +24 -0
  434. package/dist/esm/ods-export.d.ts.map +1 -0
  435. package/dist/esm/ods-export.js +12 -0
  436. package/dist/esm/parse.d.ts +24 -0
  437. package/dist/esm/parse.d.ts.map +1 -0
  438. package/dist/esm/parse.js +55 -0
  439. package/dist/esm/power-query.d.ts +41 -0
  440. package/dist/esm/power-query.d.ts.map +1 -0
  441. package/dist/esm/power-query.js +19 -0
  442. package/dist/esm/server.d.ts +9 -0
  443. package/dist/esm/server.d.ts.map +1 -0
  444. package/dist/esm/server.js +8 -0
  445. package/dist/esm/theme1.d.ts +3 -0
  446. package/dist/esm/theme1.d.ts.map +1 -0
  447. package/dist/esm/theme1.js +2 -0
  448. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
  449. package/dist/esm/types.d.ts +14 -0
  450. package/dist/esm/types.d.ts.map +1 -0
  451. package/dist/esm/types.js +14 -0
  452. package/dist/esm/vitest.config.d.ts +3 -0
  453. package/dist/esm/vitest.config.d.ts.map +1 -0
  454. package/dist/esm/vitest.config.js +16 -0
  455. package/package.json +62 -0
  456. package/xlsx.d.ts +52 -0
@@ -0,0 +1,2339 @@
1
+ import { getCellXfsKey, ssfFormat, uuid } from "@rowsncolumns/utils";
2
+ import { IndexedColors } from "@rowsncolumns/utils";
3
+ import { XMLParser } from "fast-xml-parser";
4
+ import { get } from "lodash-es";
5
+ import { parseRgce } from "./rgce-parser";
6
+ import { StreamingZipParser } from "../../zip-parser-streaming";
7
+ import { createFilterSpecsFromAutoFilter, excelColumnWidthToPixels, getRangeFromAddressRef, } from "../../helpers";
8
+ import { defaultSpreadsheetTheme } from "../../theme-default";
9
+ import { BaseWorkbookPlugin } from "../base/index";
10
+ import { processChart } from "../xlsx/charts";
11
+ import { processAnchors } from "../xlsx/drawing";
12
+ import { readAllRecordHeaders } from "./biff-record-reader";
13
+ import { standardExcelFormatCodeById } from "../xlsx/numfmt";
14
+ import { extractThemeColors, extractThemeFonts, generateDarkThemeColors, } from "../xlsx/theme";
15
+ const RT = {
16
+ BrtCellRk: 0x0002,
17
+ BrtCellBlank: 0x0001,
18
+ BrtCellError: 0x0003,
19
+ BrtCellBool: 0x0004,
20
+ BrtCellReal: 0x0005,
21
+ BrtCellSt: 0x0006,
22
+ BrtCellIsst: 0x0007,
23
+ BrtFmlaString: 0x0008,
24
+ BrtFmlaNum: 0x0009,
25
+ BrtFmlaBool: 0x000a,
26
+ BrtFmlaError: 0x000b,
27
+ BrtShortBlank: 0x000c,
28
+ BrtShortRk: 0x000d,
29
+ BrtShortError: 0x000e,
30
+ BrtShortBool: 0x000f,
31
+ BrtShortReal: 0x0010,
32
+ BrtShortSt: 0x0011,
33
+ BrtShortIsst: 0x0012,
34
+ BrtSSTItem: 0x0013,
35
+ BrtRowHdr: 0x0000,
36
+ BrtMergeCell: 0x00b0,
37
+ BrtFmt: 0x002c,
38
+ BrtFont: 0x002b,
39
+ BrtFill: 0x002d,
40
+ BrtBorder: 0x002e,
41
+ BrtXF: 0x002f,
42
+ BrtColInfo: 0x003c,
43
+ BrtBeginFonts: 0x0263,
44
+ BrtEndFonts: 0x0264,
45
+ BrtBeginFills: 0x025b,
46
+ BrtEndFills: 0x025c,
47
+ BrtBeginBorders: 0x0265,
48
+ BrtEndBorders: 0x0266,
49
+ BrtBeginFmts: 0x0267,
50
+ BrtEndFmts: 0x0268,
51
+ BrtBeginCellStyleXFs: 0x0272,
52
+ BrtEndCellStyleXFs: 0x0273,
53
+ BrtBeginCellXFs: 0x0269,
54
+ BrtEndCellXFs: 0x026a,
55
+ BrtBundleSh: 0x009c,
56
+ BrtSupBookSrc: 0x0163,
57
+ BrtSupSelf: 0x0165,
58
+ BrtSupSame: 0x0166,
59
+ BrtExternSheet: 0x016a,
60
+ BrtDrawing: 0x0226,
61
+ BrtBeginAFilter: 0x00a1,
62
+ BrtListPart: 0x0295,
63
+ BrtWsView: 0x0089,
64
+ BrtPane: 0x0097,
65
+ BrtName: 0x0027,
66
+ BrtBeginConditionalFormatting: 0x01e5,
67
+ BrtEndConditionalFormatting: 0x01e6,
68
+ BrtBeginCFRule: 0x01e7,
69
+ BrtEndCFRule: 0x01e8,
70
+ BrtBeginDVals: 0x0105,
71
+ BrtEndDVals: 0x0106,
72
+ BrtBeginDVal: 0x0103,
73
+ BrtEndDVal: 0x0104,
74
+ BrtWbProp: 0x0099,
75
+ BrtCalcProp: 0x009d,
76
+ BrtShrFmla: 0x0018,
77
+ BrtCFRule: 0x01df,
78
+ BrtDVal: 0x0103,
79
+ };
80
+ class Reader {
81
+ view;
82
+ offset = 0;
83
+ bytes;
84
+ constructor(bytes) {
85
+ this.bytes = bytes;
86
+ this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
87
+ }
88
+ readUInt8() {
89
+ const value = this.view.getUint8(this.offset);
90
+ this.offset += 1;
91
+ return value;
92
+ }
93
+ readUInt16LE() {
94
+ const value = this.view.getUint16(this.offset, true);
95
+ this.offset += 2;
96
+ return value;
97
+ }
98
+ readInt16LE() {
99
+ const value = this.view.getInt16(this.offset, true);
100
+ this.offset += 2;
101
+ return value;
102
+ }
103
+ readUInt32LE() {
104
+ const value = this.view.getUint32(this.offset, true);
105
+ this.offset += 4;
106
+ return value;
107
+ }
108
+ readInt32LE() {
109
+ const value = this.view.getInt32(this.offset, true);
110
+ this.offset += 4;
111
+ return value;
112
+ }
113
+ readFloat64LE() {
114
+ const value = this.view.getFloat64(this.offset, true);
115
+ this.offset += 8;
116
+ return value;
117
+ }
118
+ readUtf16Chars(charCount) {
119
+ if (charCount <= 0)
120
+ return "";
121
+ const byteCount = charCount * 2;
122
+ const slice = this.bytes.subarray(this.offset, this.offset + byteCount);
123
+ this.offset += byteCount;
124
+ return new TextDecoder("utf-16le").decode(slice);
125
+ }
126
+ readXLWideString() {
127
+ const cch = this.readUInt32LE();
128
+ return cch === 0 ? "" : this.readUtf16Chars(cch);
129
+ }
130
+ readXLNullableWideString() {
131
+ const cch = this.readUInt32LE();
132
+ return cch === 0 || cch === 0xffffffff ? "" : this.readUtf16Chars(cch);
133
+ }
134
+ }
135
+ const normalizePath = (path) => path.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\/+/, "");
136
+ const resolveRelativePath = (basePath, target) => {
137
+ if (target.startsWith("/")) {
138
+ return normalizePath(target);
139
+ }
140
+ const baseParts = normalizePath(basePath).split("/");
141
+ baseParts.pop();
142
+ const parts = target.split("/");
143
+ for (const part of parts) {
144
+ if (!part || part === ".")
145
+ continue;
146
+ if (part === "..") {
147
+ baseParts.pop();
148
+ }
149
+ else {
150
+ baseParts.push(part);
151
+ }
152
+ }
153
+ return normalizePath(baseParts.join("/"));
154
+ };
155
+ const parseBundleSheet = (payload) => {
156
+ const reader = new Reader(payload);
157
+ const hidden = reader.readUInt32LE();
158
+ const tabId = reader.readUInt32LE();
159
+ const rid = reader.readXLNullableWideString();
160
+ const title = reader.readXLWideString();
161
+ return { hidden, tabId, rid, title };
162
+ };
163
+ const parseRowHeader = (payload) => {
164
+ const reader = new Reader(payload);
165
+ const row = reader.readUInt32LE() + 1;
166
+ reader.readUInt32LE(); // ixfe
167
+ const miyRw = reader.readUInt16LE();
168
+ reader.readUInt8(); // top/bottom padding
169
+ const flags = reader.readUInt8();
170
+ return {
171
+ row,
172
+ hidden: Boolean(flags & 0x10),
173
+ hpt: Boolean(flags & 0x20) ? miyRw / 20 : undefined,
174
+ };
175
+ };
176
+ const parseMergeRange = (payload) => {
177
+ const reader = new Reader(payload);
178
+ const sRow = reader.readUInt32LE() + 1;
179
+ const eRow = reader.readUInt32LE() + 1;
180
+ const sCol = reader.readUInt32LE() + 1;
181
+ const eCol = reader.readUInt32LE() + 1;
182
+ return {
183
+ startRowIndex: sRow,
184
+ endRowIndex: eRow,
185
+ startColumnIndex: sCol,
186
+ endColumnIndex: eCol,
187
+ };
188
+ };
189
+ const parseRange = (payload) => parseMergeRange(payload);
190
+ const normalizeSheetTabIndex = (value) => value === 0xffff || value === 0xffffffff ? -1 : value;
191
+ const parseBrtExternSheet = (payload) => {
192
+ const parseEntries = (startOffset, entrySize, readEntry) => {
193
+ if (startOffset > payload.length)
194
+ return [];
195
+ const bytes = payload.subarray(startOffset);
196
+ if (bytes.length === 0 || bytes.length % entrySize !== 0) {
197
+ return [];
198
+ }
199
+ const reader = new Reader(bytes);
200
+ const out = [];
201
+ while (reader.offset + entrySize <= reader.bytes.length) {
202
+ out.push(readEntry(reader));
203
+ }
204
+ return out;
205
+ };
206
+ const read12 = (reader) => ({
207
+ iSupBook: reader.readUInt32LE(),
208
+ itabFirst: normalizeSheetTabIndex(reader.readUInt32LE()),
209
+ itabLast: normalizeSheetTabIndex(reader.readUInt32LE()),
210
+ });
211
+ const read6 = (reader) => ({
212
+ iSupBook: reader.readUInt16LE(),
213
+ itabFirst: normalizeSheetTabIndex(reader.readUInt16LE()),
214
+ itabLast: normalizeSheetTabIndex(reader.readUInt16LE()),
215
+ });
216
+ const direct12 = parseEntries(0, 12, read12);
217
+ if (direct12.length > 0)
218
+ return direct12;
219
+ if (payload.length >= 4) {
220
+ const reader = new Reader(payload);
221
+ const count = reader.readUInt32LE();
222
+ const withCount12 = parseEntries(4, 12, read12);
223
+ if (withCount12.length === count && withCount12.length > 0) {
224
+ return withCount12;
225
+ }
226
+ }
227
+ const direct6 = parseEntries(0, 6, read6);
228
+ if (direct6.length > 0)
229
+ return direct6;
230
+ if (payload.length >= 2) {
231
+ const reader = new Reader(payload);
232
+ const count = reader.readUInt16LE();
233
+ const withCount6 = parseEntries(2, 6, read6);
234
+ if (withCount6.length === count && withCount6.length > 0) {
235
+ return withCount6;
236
+ }
237
+ }
238
+ return [];
239
+ };
240
+ const parseBrtShrFmla = (payload) => {
241
+ if (payload.length < 20)
242
+ return null;
243
+ const reader = new Reader(payload);
244
+ const startRowZero = reader.readUInt32LE();
245
+ const endRowZero = reader.readUInt32LE();
246
+ const startColZero = reader.readUInt32LE();
247
+ const endColZero = reader.readUInt32LE();
248
+ // cce can be preceded by small metadata in some files; try a few offsets.
249
+ const candidateOffsets = [16, 18, 20, 24];
250
+ let rgceBytes;
251
+ for (const offset of candidateOffsets) {
252
+ if (offset + 4 > payload.length)
253
+ continue;
254
+ const cce = new DataView(payload.buffer, payload.byteOffset + offset, 4).getUint32(0, true);
255
+ if (cce <= 0)
256
+ continue;
257
+ const start = offset + 4;
258
+ const end = start + cce;
259
+ if (end <= payload.length) {
260
+ rgceBytes = payload.subarray(start, end);
261
+ break;
262
+ }
263
+ }
264
+ if (!rgceBytes || rgceBytes.length === 0)
265
+ return null;
266
+ return {
267
+ startRow: startRowZero + 1,
268
+ endRow: endRowZero + 1,
269
+ startCol: startColZero + 1,
270
+ endCol: endColZero + 1,
271
+ rgceBytes,
272
+ };
273
+ };
274
+ const parseWsView = (payload) => {
275
+ const reader = new Reader(payload);
276
+ const flags = reader.readUInt16LE();
277
+ // Bit 1 (0x0002): fShowGridLines - if 0, gridlines are hidden
278
+ const showGridLines = (flags & 0x0002) !== 0;
279
+ return { showGridLines };
280
+ };
281
+ const parsePane = (payload) => {
282
+ const reader = new Reader(payload);
283
+ const xSplit = reader.readFloat64LE();
284
+ const ySplit = reader.readFloat64LE();
285
+ reader.readUInt32LE(); // rwTop
286
+ reader.readUInt32LE(); // colLeft
287
+ const pnnAcct = reader.readUInt8();
288
+ // Frozen panes have pnnAcct set to specific values
289
+ const isFrozen = pnnAcct > 0;
290
+ return {
291
+ frozenColumnCount: isFrozen && xSplit > 0 ? Math.round(xSplit) : 0,
292
+ frozenRowCount: isFrozen && ySplit > 0 ? Math.round(ySplit) : 0,
293
+ };
294
+ };
295
+ export const parseBrtNamePayload = (payload, resolveSheetNameByXti) => {
296
+ try {
297
+ const reader = new Reader(payload);
298
+ const flags = reader.readUInt32LE();
299
+ const fHidden = (flags & 0x00000001) !== 0;
300
+ reader.readUInt8(); // chKey
301
+ const itab = reader.readUInt32LE(); // sheet index (0xFFFFFFFF for workbook scope)
302
+ // Read the name string
303
+ if (reader.offset + 4 > payload.length) {
304
+ return null; // Not enough data
305
+ }
306
+ const name = reader.readXLWideString();
307
+ // NameParsedFormula: cce (UInt32) followed by cce bytes of Rgce
308
+ let formula = "";
309
+ if (reader.offset + 4 <= payload.length) {
310
+ const cce = reader.readUInt32LE();
311
+ if (cce > 0 && reader.offset + cce <= payload.length) {
312
+ const rgceBytes = payload.subarray(reader.offset, reader.offset + cce);
313
+ formula = parseRgce(rgceBytes, resolveSheetNameByXti);
314
+ }
315
+ }
316
+ return {
317
+ name,
318
+ formula,
319
+ hidden: fHidden,
320
+ sheetIndex: itab === 0xffffffff ? undefined : itab,
321
+ };
322
+ }
323
+ catch (err) {
324
+ // If parsing fails, return null to skip this named range
325
+ return null;
326
+ }
327
+ };
328
+ /**
329
+ * Parse the `BrtWbProp` workbook-properties record (MS-XLSB 2.4.312).
330
+ * The payload starts with a 32-bit flags field; `fDate1904` is bit 0 of the
331
+ * first flag byte and switches the workbook's date serials to the 1904 epoch
332
+ * (Mac-origin workbooks), shifting every date by 1462 days.
333
+ */
334
+ export const parseBrtWbPropPayload = (payload) => {
335
+ if (payload.length < 1) {
336
+ return null;
337
+ }
338
+ return {
339
+ use1904: (payload[0] & 0x01) !== 0,
340
+ };
341
+ };
342
+ const parseBrtCalcPropPayload = (payload) => {
343
+ try {
344
+ const reader = new Reader(payload);
345
+ reader.readUInt32LE(); // recalcID
346
+ const flags = reader.readUInt16LE();
347
+ const fFullCalcOnLoad = (flags & 0x0002) !== 0;
348
+ const fIter = (flags & 0x0008) !== 0;
349
+ const fForceFullCalc = (flags & 0x0100) !== 0;
350
+ const cCalcCount = reader.readUInt32LE(); // iteration count
351
+ const xnumDelta = reader.readFloat64LE(); // iteration delta
352
+ return {
353
+ fullCalcOnLoad: fFullCalcOnLoad || fForceFullCalc,
354
+ iterate: fIter,
355
+ iterateCount: cCalcCount,
356
+ iterateDelta: xnumDelta,
357
+ };
358
+ }
359
+ catch (err) {
360
+ // If parsing fails, return default values
361
+ return null;
362
+ }
363
+ };
364
+ /**
365
+ * Parse conditional formatting range and rules from BrtBeginConditionalFormatting
366
+ */
367
+ const parseBrtBeginConditionalFormatting = (payload) => {
368
+ try {
369
+ const reader = new Reader(payload);
370
+ // Read the range reference (sqref)
371
+ const sqref = reader.readXLWideString();
372
+ return { sqref };
373
+ }
374
+ catch {
375
+ return null;
376
+ }
377
+ };
378
+ /**
379
+ * Parse CF rule from BrtCFRule / BrtBeginCFRule
380
+ */
381
+ const parseBrtCFRule = (payload) => {
382
+ try {
383
+ const reader = new Reader(payload);
384
+ const flags = reader.readUInt32LE();
385
+ const ruleType = reader.readUInt8(); // CF rule type
386
+ const dxfId = reader.readInt32LE(); // DXF format ID (-1 if none)
387
+ const priority = reader.readUInt32LE();
388
+ // Parse flags
389
+ const stopIfTrue = (flags & 0x02) !== 0;
390
+ // For now, return basic structure
391
+ // Full implementation would parse formulas, operators, values based on rule type
392
+ return {
393
+ ruleType,
394
+ dxfId: dxfId >= 0 ? dxfId : undefined,
395
+ priority,
396
+ stopIfTrue,
397
+ };
398
+ }
399
+ catch {
400
+ return null;
401
+ }
402
+ };
403
+ /**
404
+ * Parse data validation from BrtBeginDVal
405
+ */
406
+ const parseBrtBeginDVal = (payload) => {
407
+ try {
408
+ const reader = new Reader(payload);
409
+ const flags = reader.readUInt32LE();
410
+ // Parse validation type and operator
411
+ const valType = reader.readUInt8(); // 0=none, 1=whole, 2=decimal, 3=list, 4=date, 5=time, 6=textLength, 7=custom
412
+ const operator = reader.readUInt8(); // 0=between, 1=notBetween, 2=equal, 3=notEqual, etc.
413
+ // Parse flags
414
+ const ignoreBlank = (flags & 0x01) !== 0;
415
+ const inCellDropdown = (flags & 0x02) === 0; // Inverted logic
416
+ const showInputMessage = (flags & 0x04) !== 0;
417
+ const showErrorMessage = (flags & 0x08) !== 0;
418
+ // Error style: 0=stop, 1=warning, 2=information
419
+ const errorStyle = (flags >> 4) & 0x03;
420
+ // Read strings
421
+ const promptTitle = reader.readXLWideString();
422
+ const errorTitle = reader.readXLWideString();
423
+ const prompt = reader.readXLWideString();
424
+ const error = reader.readXLWideString();
425
+ // Range would be in the parent record or following data
426
+ // For now, return parsed data
427
+ return {
428
+ valType,
429
+ operator,
430
+ ignoreBlank,
431
+ inCellDropdown,
432
+ showInputMessage,
433
+ showErrorMessage,
434
+ errorStyle,
435
+ promptTitle,
436
+ errorTitle,
437
+ prompt,
438
+ error,
439
+ };
440
+ }
441
+ catch {
442
+ return null;
443
+ }
444
+ };
445
+ const parseRkNumber = (payload, offset) => {
446
+ const b0 = payload[offset];
447
+ const fX100 = (b0 & 1) !== 0;
448
+ const fInt = (b0 & 2) !== 0;
449
+ let value;
450
+ if (fInt) {
451
+ const view = new DataView(payload.buffer, payload.byteOffset + offset, payload.byteLength - offset);
452
+ value = (view.getInt32(0, true) >> 2);
453
+ }
454
+ else {
455
+ const out = new Uint8Array(8);
456
+ out.set(payload.subarray(offset, offset + 4), 4);
457
+ out[4] &= 0xfc;
458
+ value = new DataView(out.buffer).getFloat64(0, true);
459
+ }
460
+ return fX100 ? value / 100 : value;
461
+ };
462
+ const XLSB_FILL_PATTERN_NAMES = [
463
+ "none",
464
+ "solid",
465
+ "mediumGray",
466
+ "darkGray",
467
+ "lightGray",
468
+ "darkHorizontal",
469
+ "darkVertical",
470
+ "darkDown",
471
+ "darkUp",
472
+ "darkGrid",
473
+ "darkTrellis",
474
+ "lightHorizontal",
475
+ "lightVertical",
476
+ "lightDown",
477
+ "lightUp",
478
+ "lightGrid",
479
+ "lightTrellis",
480
+ "gray125",
481
+ "gray0625",
482
+ ];
483
+ const getNumberFormatType = (pattern) => {
484
+ const lower = pattern.toLowerCase();
485
+ if (lower.includes("yy") || lower.includes("dd"))
486
+ return "DATE";
487
+ if (lower.includes("h:") || lower.includes("am/pm"))
488
+ return "TIME";
489
+ if (lower.includes("%"))
490
+ return "PERCENT";
491
+ if (lower.includes("$") ||
492
+ lower.includes("€") ||
493
+ lower.includes("£") ||
494
+ lower.includes("¥")) {
495
+ return "CURRENCY";
496
+ }
497
+ if (lower.includes("0") || lower.includes("#"))
498
+ return "NUMBER";
499
+ return "GENERAL";
500
+ };
501
+ const parseCellFromRecord = (type, payload, row, prevCol, resolveSheetNameByXti, resolveSharedFormula, parseFormula = true) => {
502
+ if (row <= 0)
503
+ return null;
504
+ const reader = new Reader(payload);
505
+ let colZero;
506
+ let styleRef;
507
+ const isShort = type === RT.BrtShortRk ||
508
+ type === RT.BrtShortError ||
509
+ type === RT.BrtShortBool ||
510
+ type === RT.BrtShortReal ||
511
+ type === RT.BrtShortSt ||
512
+ type === RT.BrtShortIsst;
513
+ if (isShort) {
514
+ styleRef = reader.readUInt16LE() + (reader.readUInt8() << 16);
515
+ reader.readUInt8();
516
+ colZero = prevCol + 1;
517
+ }
518
+ else {
519
+ colZero = reader.readUInt32LE();
520
+ styleRef = reader.readUInt16LE() + (reader.readUInt8() << 16);
521
+ reader.readUInt8();
522
+ }
523
+ if (type === RT.BrtCellIsst || type === RT.BrtShortIsst) {
524
+ const sharedStringIndex = reader.readUInt32LE();
525
+ return {
526
+ row,
527
+ col: colZero + 1,
528
+ styleRef,
529
+ kind: "s",
530
+ value: sharedStringIndex,
531
+ sharedStringIndex,
532
+ };
533
+ }
534
+ if (type === RT.BrtCellBlank || type === RT.BrtShortBlank) {
535
+ return {
536
+ row,
537
+ col: colZero + 1,
538
+ styleRef,
539
+ kind: "blank",
540
+ value: "",
541
+ };
542
+ }
543
+ const readFormula = () => {
544
+ if (!parseFormula)
545
+ return undefined;
546
+ const candidateStarts = [
547
+ reader.offset - 2,
548
+ reader.offset,
549
+ reader.offset + 2,
550
+ reader.offset + 4,
551
+ reader.offset + 6,
552
+ reader.offset + 8,
553
+ reader.offset + 10,
554
+ reader.offset + 12,
555
+ ].filter((start, idx, arr) => start >= 0 && arr.indexOf(start) === idx);
556
+ const decodeAt = (start, cceSize) => {
557
+ if (cceSize === 4) {
558
+ if (start + 4 > payload.length)
559
+ return undefined;
560
+ const cce = new DataView(payload.buffer, payload.byteOffset + start, 4).getUint32(0, true);
561
+ if (cce <= 0)
562
+ return undefined;
563
+ const rgceStart = start + 4;
564
+ const rgceEnd = rgceStart + cce;
565
+ if (rgceEnd > payload.length)
566
+ return undefined;
567
+ return payload.subarray(rgceStart, rgceEnd);
568
+ }
569
+ if (start + 2 > payload.length)
570
+ return undefined;
571
+ const cce = new DataView(payload.buffer, payload.byteOffset + start, 2).getUint16(0, true);
572
+ if (cce <= 0)
573
+ return undefined;
574
+ const rgceStart = start + 2;
575
+ const rgceEnd = rgceStart + cce;
576
+ if (rgceEnd > payload.length)
577
+ return undefined;
578
+ return payload.subarray(rgceStart, rgceEnd);
579
+ };
580
+ const tryResolve = (parsed) => {
581
+ const expMatch = parsed.match(/^__PTGEXP__:(\d+):(\d+)$/);
582
+ if (!expMatch)
583
+ return parsed;
584
+ if (!resolveSharedFormula)
585
+ return undefined;
586
+ const sourceRow = Number(expMatch[1]);
587
+ const sourceCol = Number(expMatch[2]);
588
+ return resolveSharedFormula(sourceRow, sourceCol, row, colZero + 1);
589
+ };
590
+ for (const start of candidateStarts) {
591
+ for (const cceSize of [4, 2]) {
592
+ const rgceBytes = decodeAt(start, cceSize);
593
+ if (!rgceBytes || rgceBytes.length === 0)
594
+ continue;
595
+ const parsed = parseRgce(rgceBytes, resolveSheetNameByXti, { row, col: colZero + 1 }, true);
596
+ if (!parsed)
597
+ continue;
598
+ const resolved = tryResolve(parsed);
599
+ if (resolved && resolved.length > 0) {
600
+ return resolved;
601
+ }
602
+ }
603
+ }
604
+ return undefined;
605
+ };
606
+ if (type === RT.BrtFmlaNum) {
607
+ const value = reader.readFloat64LE();
608
+ reader.readUInt16LE(); // flags
609
+ const formula = readFormula();
610
+ return {
611
+ row,
612
+ col: colZero + 1,
613
+ styleRef,
614
+ kind: "n",
615
+ value,
616
+ formula,
617
+ };
618
+ }
619
+ if (type === RT.BrtFmlaString) {
620
+ const value = reader.readXLWideString();
621
+ reader.readUInt16LE(); // flags
622
+ const formula = readFormula();
623
+ return {
624
+ row,
625
+ col: colZero + 1,
626
+ styleRef,
627
+ kind: "str",
628
+ value,
629
+ formula,
630
+ };
631
+ }
632
+ if (type === RT.BrtFmlaBool) {
633
+ const value = reader.readUInt8() !== 0;
634
+ reader.readUInt8(); // padding
635
+ reader.readUInt16LE(); // flags
636
+ const formula = readFormula();
637
+ return {
638
+ row,
639
+ col: colZero + 1,
640
+ styleRef,
641
+ kind: "b",
642
+ value,
643
+ formula,
644
+ };
645
+ }
646
+ if (type === RT.BrtFmlaError) {
647
+ const value = reader.readUInt8();
648
+ reader.readUInt8(); // padding
649
+ reader.readUInt16LE(); // flags
650
+ const formula = readFormula();
651
+ return {
652
+ row,
653
+ col: colZero + 1,
654
+ styleRef,
655
+ kind: "e",
656
+ value,
657
+ formula,
658
+ };
659
+ }
660
+ if (type === RT.BrtCellSt || type === RT.BrtShortSt) {
661
+ return {
662
+ row,
663
+ col: colZero + 1,
664
+ styleRef,
665
+ kind: "str",
666
+ value: reader.readXLWideString(),
667
+ };
668
+ }
669
+ if (type === RT.BrtCellReal || type === RT.BrtShortReal) {
670
+ return {
671
+ row,
672
+ col: colZero + 1,
673
+ styleRef,
674
+ kind: "n",
675
+ value: reader.readFloat64LE(),
676
+ };
677
+ }
678
+ if (type === RT.BrtCellRk || type === RT.BrtShortRk) {
679
+ return {
680
+ row,
681
+ col: colZero + 1,
682
+ styleRef,
683
+ kind: "n",
684
+ value: parseRkNumber(payload, reader.offset),
685
+ };
686
+ }
687
+ if (type === RT.BrtCellBool || type === RT.BrtShortBool) {
688
+ return {
689
+ row,
690
+ col: colZero + 1,
691
+ styleRef,
692
+ kind: "b",
693
+ value: reader.readUInt8() !== 0,
694
+ };
695
+ }
696
+ if (type === RT.BrtCellError || type === RT.BrtShortError) {
697
+ return {
698
+ row,
699
+ col: colZero + 1,
700
+ styleRef,
701
+ kind: "e",
702
+ value: reader.readUInt8(),
703
+ };
704
+ }
705
+ return null;
706
+ };
707
+ const parseBrtColor = (reader) => {
708
+ const d = reader.readUInt8();
709
+ const xColorType = d >>> 1;
710
+ const index = reader.readUInt8();
711
+ const tintRaw = reader.readInt16LE();
712
+ const r = reader.readUInt8();
713
+ const g = reader.readUInt8();
714
+ const b = reader.readUInt8();
715
+ reader.readUInt8(); // alpha
716
+ const tint = tintRaw === 0 ? undefined : tintRaw > 0 ? tintRaw / 32767 : tintRaw / 32768;
717
+ if (xColorType === 2) {
718
+ return `#${[r, g, b]
719
+ .map((v) => v.toString(16).padStart(2, "0"))
720
+ .join("")
721
+ .toUpperCase()}`;
722
+ }
723
+ if (xColorType === 3) {
724
+ return {
725
+ theme: index,
726
+ ...(tint != null ? { tint } : {}),
727
+ };
728
+ }
729
+ if (xColorType === 1 && index === 64) {
730
+ return { theme: 1 };
731
+ }
732
+ if (xColorType === 1) {
733
+ return IndexedColors[index];
734
+ }
735
+ return undefined;
736
+ };
737
+ const parseBrtFill = (payload) => {
738
+ const reader = new Reader(payload);
739
+ const fill = reader.readUInt32LE();
740
+ const result = {
741
+ patternType: XLSB_FILL_PATTERN_NAMES[fill] ?? (fill === 0x28 ? "gradient" : undefined),
742
+ };
743
+ if (fill !== 0x28 && payload.length >= 20) {
744
+ result.fgColor = parseBrtColor(reader);
745
+ parseBrtColor(reader);
746
+ }
747
+ return result;
748
+ };
749
+ const parseBrtFmt = (payload) => {
750
+ const reader = new Reader(payload);
751
+ const id = reader.readUInt16LE();
752
+ const formatCode = reader.readXLWideString();
753
+ return { id, formatCode };
754
+ };
755
+ const parseBrtXf = (payload) => {
756
+ const reader = new Reader(payload);
757
+ const parentId = reader.readUInt16LE();
758
+ const numFmtId = reader.readUInt16LE();
759
+ const fontId = reader.readUInt16LE();
760
+ const fillId = reader.readUInt16LE();
761
+ const borderId = payload.length >= 10 ? reader.readUInt16LE() : 0;
762
+ const result = { parentId, numFmtId, fontId, fillId, borderId };
763
+ // Parse alignment if enough data is available
764
+ if (payload.length >= 14) {
765
+ const trot = reader.readUInt8(); // text rotation
766
+ const indent = reader.readUInt8();
767
+ const flags = reader.readUInt16LE();
768
+ // Extract alignment from flags (bits 0-2: horizontal, bits 3-5: vertical)
769
+ const alH = flags & 0x07; // bits 0-2
770
+ const alV = (flags >> 3) & 0x07; // bits 3-5
771
+ const fWrap = (flags >> 6) & 0x01; // bit 6
772
+ // Map horizontal alignment
773
+ const horizontalAlignments = [
774
+ "general",
775
+ "left",
776
+ "center",
777
+ "right",
778
+ "fill",
779
+ "justify",
780
+ "centerContinuous",
781
+ "distributed",
782
+ ];
783
+ if (alH > 0 && alH < horizontalAlignments.length) {
784
+ result.horizontalAlignment = horizontalAlignments[alH];
785
+ }
786
+ // Map vertical alignment
787
+ const verticalAlignments = [
788
+ "top",
789
+ "middle",
790
+ "bottom",
791
+ "justify",
792
+ "distributed",
793
+ ];
794
+ if (alV > 0 && alV < verticalAlignments.length) {
795
+ const mapped = verticalAlignments[alV];
796
+ result.verticalAlignment = mapped === "middle" ? "middle" : mapped;
797
+ }
798
+ // Wrap text
799
+ if (fWrap) {
800
+ result.wrapText = true;
801
+ }
802
+ // Text rotation
803
+ if (trot === 0xff) {
804
+ result.textRotation = "vertical";
805
+ }
806
+ else if (trot > 0 && trot <= 90) {
807
+ result.textRotation = trot;
808
+ }
809
+ else if (trot >= 91 && trot <= 180) {
810
+ result.textRotation = -(trot - 90);
811
+ }
812
+ // Indent
813
+ if (indent > 0) {
814
+ result.indent = indent;
815
+ }
816
+ }
817
+ return result;
818
+ };
819
+ const parseBrtColInfo = (payload) => {
820
+ const reader = new Reader(payload);
821
+ const startCol = reader.readUInt32LE() + 1;
822
+ const endCol = reader.readUInt32LE() + 1;
823
+ const coldx = reader.readUInt32LE();
824
+ reader.readUInt32LE(); // ixfe/style
825
+ const flags = reader.readUInt16LE();
826
+ const hidden = (flags & 0x01) !== 0;
827
+ const customWidth = (flags & 0x02) !== 0;
828
+ const widthChars = coldx / 256;
829
+ const size = excelColumnWidthToPixels(widthChars);
830
+ return { startCol, endCol, hidden, customWidth, size };
831
+ };
832
+ const parseBrtListPartRelId = (payload) => {
833
+ const reader = new Reader(payload);
834
+ return reader.readXLNullableWideString();
835
+ };
836
+ const parseBrtFont = (payload) => {
837
+ const reader = new Reader(payload);
838
+ const size = reader.readUInt16LE() / 20;
839
+ const flags = reader.readUInt8();
840
+ reader.readUInt8(); // reserved
841
+ reader.readUInt16LE(); // bold weight
842
+ reader.readUInt16LE(); // script style
843
+ const underline = reader.readUInt8();
844
+ reader.readUInt8(); // family
845
+ reader.readUInt8(); // charset
846
+ reader.readUInt8(); // reserved
847
+ const color = parseBrtColor(reader);
848
+ reader.readUInt8(); // scheme
849
+ const name = reader.readXLWideString();
850
+ return {
851
+ ...(name ? { name } : {}),
852
+ ...(Number.isFinite(size) ? { size } : {}),
853
+ ...(flags & 0x01 ? { bold: true } : {}),
854
+ ...(flags & 0x02 ? { italic: true } : {}),
855
+ ...(flags & 0x08 ? { strikethrough: true } : {}),
856
+ ...(underline !== 0 ? { underline: true } : {}),
857
+ ...(color ? { color } : {}),
858
+ };
859
+ };
860
+ const XLSB_BORDER_STYLE_MAP = {
861
+ 1: { style: "solid", width: 1 },
862
+ 2: { style: "solid_medium", width: 2 },
863
+ 3: { style: "dashed", width: 1 },
864
+ 4: { style: "dotted", width: 1 },
865
+ 5: { style: "solid_thick", width: 3 },
866
+ 6: { style: "double", width: 2 },
867
+ 7: { style: "thin", width: 1 },
868
+ 8: { style: "dashed", width: 2 },
869
+ 9: { style: "dashed", width: 1 },
870
+ 10: { style: "dashed", width: 2 },
871
+ 11: { style: "dotted", width: 1 },
872
+ 12: { style: "dotted", width: 2 },
873
+ 13: { style: "dashed", width: 2 },
874
+ };
875
+ const parseBrtBorder = (payload) => {
876
+ if (payload.length < 41)
877
+ return {};
878
+ const reader = new Reader(payload);
879
+ reader.readUInt8(); // diagonal flags
880
+ const side = () => {
881
+ const styleId = reader.readUInt8();
882
+ reader.readUInt8(); // reserved
883
+ const color = parseBrtColor(reader);
884
+ const mapped = XLSB_BORDER_STYLE_MAP[styleId];
885
+ if (!mapped)
886
+ return undefined;
887
+ return {
888
+ style: mapped.style,
889
+ width: mapped.width,
890
+ ...(color ? { color } : {}),
891
+ };
892
+ };
893
+ const top = side();
894
+ const bottom = side();
895
+ const left = side();
896
+ const right = side();
897
+ side(); // diagonal, unused
898
+ return {
899
+ ...(top ? { top } : {}),
900
+ ...(right ? { right } : {}),
901
+ ...(bottom ? { bottom } : {}),
902
+ ...(left ? { left } : {}),
903
+ };
904
+ };
905
+ const resolveXf = (styles, xfIndex) => {
906
+ const xf = styles.cellXfs[xfIndex];
907
+ if (!xf)
908
+ return undefined;
909
+ const parent = styles.styleXfs[xf.parentId];
910
+ if (!parent)
911
+ return xf;
912
+ const inheritIndex = (child, base) => child ?? base;
913
+ // Special handling for numFmtId: when child is 0 and parent has a non-zero format,
914
+ // inherit from parent. This handles cases where minimal XF records (without apply flags)
915
+ // use 0 to indicate "inherit from parent" rather than explicitly using format 0 (General).
916
+ const inheritNumFmtId = (child, base) => {
917
+ if (child === 0 && base !== 0) {
918
+ return base;
919
+ }
920
+ return child ?? base;
921
+ };
922
+ return {
923
+ parentId: xf.parentId,
924
+ numFmtId: inheritNumFmtId(xf.numFmtId, parent.numFmtId),
925
+ fontId: inheritIndex(xf.fontId, parent.fontId),
926
+ fillId: inheritIndex(xf.fillId, parent.fillId),
927
+ borderId: inheritIndex(xf.borderId, parent.borderId),
928
+ horizontalAlignment: xf.horizontalAlignment ?? parent.horizontalAlignment,
929
+ verticalAlignment: xf.verticalAlignment ?? parent.verticalAlignment,
930
+ wrapText: xf.wrapText ?? parent.wrapText,
931
+ textRotation: xf.textRotation ?? parent.textRotation,
932
+ indent: xf.indent ?? parent.indent,
933
+ };
934
+ };
935
+ const toCellData = (parsed, styles, sharedStrings, enableCellXfsRegistry, enableSharedStrings, cellXfs) => {
936
+ const xf = resolveXf(styles, parsed.styleRef);
937
+ const format = {};
938
+ const pattern = xf
939
+ ? styles.numberFormats.get(xf.numFmtId) ??
940
+ standardExcelFormatCodeById.get(xf.numFmtId)
941
+ : undefined;
942
+ if (pattern) {
943
+ format.numberFormat = {
944
+ type: getNumberFormatType(pattern),
945
+ pattern,
946
+ };
947
+ }
948
+ if (xf?.fillId != null) {
949
+ const fill = styles.fills[xf.fillId];
950
+ if (fill?.fgColor && fill.patternType === "solid") {
951
+ format.backgroundColor = fill.fgColor;
952
+ }
953
+ }
954
+ if (xf?.fontId != null) {
955
+ const font = styles.fonts[xf.fontId];
956
+ if (font) {
957
+ const textFormat = {
958
+ ...(font.name ? { fontFamily: font.name } : {}),
959
+ ...(font.size != null ? { fontSize: font.size } : {}),
960
+ ...(font.bold ? { bold: true } : {}),
961
+ ...(font.italic ? { italic: true } : {}),
962
+ ...(font.underline ? { underline: true } : {}),
963
+ ...(font.strikethrough ? { strikethrough: true } : {}),
964
+ ...(font.color ? { color: font.color } : {}),
965
+ };
966
+ if (Object.keys(textFormat).length > 0) {
967
+ format.textFormat = textFormat;
968
+ }
969
+ }
970
+ }
971
+ if (xf?.borderId != null) {
972
+ const border = styles.borders[xf.borderId];
973
+ if (border && Object.keys(border).length > 0) {
974
+ format.borders = border;
975
+ }
976
+ }
977
+ // Apply alignment properties
978
+ // Only set valid alignment values (left, right, center for horizontal; top, middle, bottom for vertical)
979
+ if (xf?.horizontalAlignment) {
980
+ const validHorizontal = ["left", "right", "center"];
981
+ if (validHorizontal.includes(xf.horizontalAlignment)) {
982
+ format.horizontalAlignment = xf.horizontalAlignment;
983
+ }
984
+ }
985
+ if (xf?.verticalAlignment) {
986
+ const validVertical = ["top", "middle", "bottom"];
987
+ if (validVertical.includes(xf.verticalAlignment)) {
988
+ format.verticalAlignment = xf.verticalAlignment;
989
+ }
990
+ }
991
+ if (xf?.wrapText) {
992
+ format.wrapStrategy = "wrap";
993
+ }
994
+ if (xf?.textRotation !== undefined) {
995
+ format.textRotation = xf.textRotation;
996
+ }
997
+ if (xf?.indent !== undefined && xf.indent > 0) {
998
+ format.indent = xf.indent;
999
+ }
1000
+ const hasFormat = Object.keys(format).length > 0;
1001
+ const style = enableCellXfsRegistry && hasFormat
1002
+ ? { sid: `xlsb:${parsed.styleRef}` }
1003
+ : undefined;
1004
+ if (style && !cellXfs.has(style.sid)) {
1005
+ cellXfs.set(style.sid, format);
1006
+ }
1007
+ if (parsed.kind === "s") {
1008
+ const idx = parsed.sharedStringIndex ?? Number(parsed.value);
1009
+ const text = sharedStrings[idx] ?? "";
1010
+ if (enableSharedStrings) {
1011
+ return {
1012
+ ...(style
1013
+ ? { ef: style, uf: style }
1014
+ : hasFormat
1015
+ ? { ef: format, uf: format }
1016
+ : {}),
1017
+ ss: String(idx),
1018
+ };
1019
+ }
1020
+ return {
1021
+ ...(style
1022
+ ? { ef: style, uf: style }
1023
+ : hasFormat
1024
+ ? { ef: format, uf: format }
1025
+ : {}),
1026
+ ue: { sv: text },
1027
+ ev: { sv: text },
1028
+ fv: text,
1029
+ };
1030
+ }
1031
+ if (parsed.kind === "str") {
1032
+ const text = String(parsed.value);
1033
+ // If there's a formula, use it in ue.fv, otherwise use the text value
1034
+ const ue = parsed.formula ? { fv: `=${parsed.formula}` } : { sv: text };
1035
+ return {
1036
+ ...(style
1037
+ ? { ef: style, uf: style }
1038
+ : hasFormat
1039
+ ? { ef: format, uf: format }
1040
+ : {}),
1041
+ ue,
1042
+ ev: { sv: text },
1043
+ // Skip `fv` for formula cells; renderer derives at paint time.
1044
+ ...(parsed.formula ? {} : { fv: text }),
1045
+ };
1046
+ }
1047
+ if (parsed.kind === "n") {
1048
+ const value = Number(parsed.value);
1049
+ const pattern = format.numberFormat?.pattern ?? "GENERAL";
1050
+ const fv = ssfFormat(pattern, value);
1051
+ // If there's a formula, use it in ue.fv, otherwise use the numeric value
1052
+ const ue = parsed.formula ? { fv: `=${parsed.formula}` } : { nv: value };
1053
+ return {
1054
+ ...(style
1055
+ ? { ef: style, uf: style }
1056
+ : hasFormat
1057
+ ? { ef: format, uf: format }
1058
+ : {}),
1059
+ ue,
1060
+ ev: { nv: value },
1061
+ ...(parsed.formula ? {} : { fv }),
1062
+ };
1063
+ }
1064
+ if (parsed.kind === "b") {
1065
+ const value = Boolean(parsed.value);
1066
+ // If there's a formula, use it in ue.fv, otherwise use the boolean value
1067
+ const ue = parsed.formula ? { fv: `=${parsed.formula}` } : { bv: value };
1068
+ return {
1069
+ ...(style
1070
+ ? { ef: style, uf: style }
1071
+ : hasFormat
1072
+ ? { ef: format, uf: format }
1073
+ : {}),
1074
+ ue,
1075
+ ev: { bv: value },
1076
+ ...(parsed.formula ? {} : { fv: value ? "TRUE" : "FALSE" }),
1077
+ };
1078
+ }
1079
+ if (parsed.kind === "e") {
1080
+ // Error value
1081
+ const errorCodes = {
1082
+ 0x00: "#NULL!",
1083
+ 0x07: "#DIV/0!",
1084
+ 0x0f: "#VALUE!",
1085
+ 0x17: "#REF!",
1086
+ 0x1d: "#NAME?",
1087
+ 0x24: "#NUM!",
1088
+ 0x2a: "#N/A",
1089
+ 0x2b: "#GETTING_DATA",
1090
+ };
1091
+ const code = errorCodes[Number(parsed.value)] || "#VALUE!";
1092
+ const errorExtendedValue = {
1093
+ ev: { type: "Error", name: code, message: code },
1094
+ };
1095
+ // If there's a formula, use it in ue.fv. Errors get a typed
1096
+ // `ev.ev` (not `sv`) so formula propagation treats them as errors.
1097
+ const ue = parsed.formula
1098
+ ? { fv: `=${parsed.formula}` }
1099
+ : errorExtendedValue;
1100
+ return {
1101
+ ...(style
1102
+ ? { ef: style, uf: style }
1103
+ : hasFormat
1104
+ ? { ef: format, uf: format }
1105
+ : {}),
1106
+ ue,
1107
+ ev: errorExtendedValue,
1108
+ ...(parsed.formula ? {} : { fv: code }),
1109
+ };
1110
+ }
1111
+ if (parsed.kind === "blank") {
1112
+ if (!hasFormat && !style)
1113
+ return null;
1114
+ return {
1115
+ ...(style
1116
+ ? { ef: style, uf: style }
1117
+ : hasFormat
1118
+ ? { ef: format, uf: format }
1119
+ : {}),
1120
+ };
1121
+ }
1122
+ return {
1123
+ ...(style
1124
+ ? { ef: style, uf: style }
1125
+ : hasFormat
1126
+ ? { ef: format, uf: format }
1127
+ : {}),
1128
+ ue: { sv: "#VALUE!" },
1129
+ ev: { sv: "#VALUE!" },
1130
+ fv: "#VALUE!",
1131
+ };
1132
+ };
1133
+ const isCellRecord = (type) => type === RT.BrtCellBlank ||
1134
+ type === RT.BrtCellRk ||
1135
+ type === RT.BrtCellError ||
1136
+ type === RT.BrtCellBool ||
1137
+ type === RT.BrtCellReal ||
1138
+ type === RT.BrtCellSt ||
1139
+ type === RT.BrtCellIsst ||
1140
+ type === RT.BrtFmlaString ||
1141
+ type === RT.BrtFmlaNum ||
1142
+ type === RT.BrtFmlaBool ||
1143
+ type === RT.BrtFmlaError ||
1144
+ type === RT.BrtShortBlank ||
1145
+ type === RT.BrtShortRk ||
1146
+ type === RT.BrtShortError ||
1147
+ type === RT.BrtShortBool ||
1148
+ type === RT.BrtShortReal ||
1149
+ type === RT.BrtShortSt ||
1150
+ type === RT.BrtShortIsst;
1151
+ export class XlsbPlugin extends BaseWorkbookPlugin {
1152
+ zipParser = new StreamingZipParser();
1153
+ xmlParser = new XMLParser({
1154
+ ignoreAttributes: false,
1155
+ attributesGroupName: "a$",
1156
+ attributeNamePrefix: "",
1157
+ textNodeName: "t$",
1158
+ trimValues: false,
1159
+ ignoreDeclaration: true,
1160
+ });
1161
+ sheets = [];
1162
+ sharedStrings = [];
1163
+ sharedFormulaMap = new Map();
1164
+ cellXfs = new Map();
1165
+ styles = {
1166
+ numberFormats: new Map(standardExcelFormatCodeById),
1167
+ styleXfs: [],
1168
+ cellXfs: [],
1169
+ fills: [],
1170
+ fonts: [],
1171
+ borders: [],
1172
+ };
1173
+ theme = defaultSpreadsheetTheme;
1174
+ namedRanges = [];
1175
+ calcProp = {};
1176
+ supportingLinks = [];
1177
+ externSheetRefs = [];
1178
+ use1904 = false;
1179
+ async load(buffer, password) {
1180
+ await this.zipParser.load(buffer, password);
1181
+ if (!this.zipParser.has("xl/workbook.bin")) {
1182
+ throw new Error("Invalid XLSB file: xl/workbook.bin not found");
1183
+ }
1184
+ // Initialize shared formula map
1185
+ if (!this.sharedFormulaMap) {
1186
+ this.sharedFormulaMap = new Map();
1187
+ }
1188
+ this.sharedFormulaMap.clear();
1189
+ const workbookBinary = await this.zipParser.getBinary("xl/workbook.bin");
1190
+ const records = readAllRecordHeaders(workbookBinary);
1191
+ const workbookRels = await this.loadWorkbookRelationships();
1192
+ const sheets = [];
1193
+ const namedRanges = [];
1194
+ const supportingLinks = [];
1195
+ let externSheetRefs = [];
1196
+ for (const record of records) {
1197
+ const payload = workbookBinary.subarray(record.dataOffset, record.nextOffset);
1198
+ if (record.type === RT.BrtBundleSh) {
1199
+ const parsed = parseBundleSheet(payload);
1200
+ // Skip veryHidden sheets (hidden === 2) - these are internal sheets not meant for users
1201
+ if (parsed.hidden === 2) {
1202
+ continue;
1203
+ }
1204
+ const relTarget = workbookRels.get(parsed.rid);
1205
+ const path = relTarget
1206
+ ? resolveRelativePath("xl/workbook.bin", relTarget)
1207
+ : undefined;
1208
+ sheets.push({
1209
+ sheetId: parsed.tabId || sheets.length + 1,
1210
+ title: parsed.title || `Sheet${sheets.length + 1}`,
1211
+ hidden: parsed.hidden === 1,
1212
+ rid: parsed.rid,
1213
+ path,
1214
+ rowCount: 0,
1215
+ columnCount: 0,
1216
+ tablePartRelIds: [],
1217
+ merges: [],
1218
+ rowMetadata: [],
1219
+ columnMetadata: [],
1220
+ });
1221
+ }
1222
+ else if (record.type === RT.BrtSupSelf) {
1223
+ supportingLinks.push("self");
1224
+ }
1225
+ else if (record.type === RT.BrtSupSame) {
1226
+ supportingLinks.push("same");
1227
+ }
1228
+ else if (record.type === RT.BrtSupBookSrc) {
1229
+ supportingLinks.push("external");
1230
+ }
1231
+ else if (record.type === RT.BrtExternSheet) {
1232
+ const parsed = parseBrtExternSheet(payload);
1233
+ if (parsed.length > 0) {
1234
+ externSheetRefs = parsed;
1235
+ }
1236
+ }
1237
+ else if (record.type === RT.BrtName) {
1238
+ const namedRange = this.parseBrtName(payload, sheets);
1239
+ if (namedRange) {
1240
+ namedRanges.push(namedRange);
1241
+ }
1242
+ }
1243
+ else if (record.type === RT.BrtCalcProp) {
1244
+ this.parseBrtCalcProp(payload);
1245
+ }
1246
+ else if (record.type === RT.BrtWbProp) {
1247
+ const parsed = parseBrtWbPropPayload(payload);
1248
+ if (parsed) {
1249
+ this.use1904 = parsed.use1904;
1250
+ }
1251
+ }
1252
+ }
1253
+ this.namedRanges = namedRanges;
1254
+ this.supportingLinks = supportingLinks;
1255
+ this.externSheetRefs = externSheetRefs;
1256
+ this.sheets = sheets;
1257
+ this.sharedStrings = await this.loadSharedStrings();
1258
+ this.styles = await this.loadStyles();
1259
+ this.theme = await this.loadTheme();
1260
+ for (const sheet of this.sheets) {
1261
+ if (!sheet.path || !this.zipParser.has(sheet.path))
1262
+ continue;
1263
+ const stats = await this.scanSheetStats(sheet.path);
1264
+ sheet.rowCount = stats.rowCount;
1265
+ sheet.columnCount = stats.columnCount;
1266
+ sheet.merges = stats.merges;
1267
+ sheet.rowMetadata = stats.rowMetadata;
1268
+ sheet.columnMetadata = stats.columnMetadata;
1269
+ sheet.showGridLines = stats.showGridLines;
1270
+ sheet.frozenRowCount = stats.frozenRowCount;
1271
+ sheet.frozenColumnCount = stats.frozenColumnCount;
1272
+ sheet.basicFilterRange = stats.basicFilterRange;
1273
+ sheet.tablePartRelIds = stats.tablePartRelIds;
1274
+ }
1275
+ }
1276
+ dispose() {
1277
+ void this.zipParser.dispose();
1278
+ }
1279
+ async loadWorkbookRelationships() {
1280
+ const relsPath = "xl/_rels/workbook.bin.rels";
1281
+ const relMap = new Map();
1282
+ if (!this.zipParser.has(relsPath)) {
1283
+ return relMap;
1284
+ }
1285
+ const relText = await this.zipParser.getText(relsPath);
1286
+ const rels = this.xmlParser.parse(relText);
1287
+ const relations = get(rels, "Relationships.Relationship") ?? [];
1288
+ const list = Array.isArray(relations) ? relations : [relations];
1289
+ for (const rel of list) {
1290
+ const id = rel?.a$?.Id ?? rel?.Id;
1291
+ const target = rel?.a$?.Target ?? rel?.Target;
1292
+ if (typeof id === "string" && typeof target === "string") {
1293
+ relMap.set(id, target);
1294
+ }
1295
+ }
1296
+ return relMap;
1297
+ }
1298
+ async loadSharedStrings() {
1299
+ const path = "xl/sharedStrings.bin";
1300
+ if (!this.zipParser.has(path))
1301
+ return [];
1302
+ const binary = await this.zipParser.getBinary(path);
1303
+ const records = readAllRecordHeaders(binary);
1304
+ const result = [];
1305
+ for (const record of records) {
1306
+ if (record.type !== RT.BrtSSTItem)
1307
+ continue;
1308
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1309
+ const reader = new Reader(payload);
1310
+ reader.readUInt8(); // flags
1311
+ result.push(reader.readXLWideString());
1312
+ }
1313
+ return result;
1314
+ }
1315
+ async loadStyles() {
1316
+ const path = "xl/styles.bin";
1317
+ const styles = {
1318
+ numberFormats: new Map(standardExcelFormatCodeById),
1319
+ styleXfs: [],
1320
+ cellXfs: [],
1321
+ fills: [],
1322
+ fonts: [],
1323
+ borders: [],
1324
+ };
1325
+ if (!this.zipParser.has(path))
1326
+ return styles;
1327
+ const binary = await this.zipParser.getBinary(path);
1328
+ const records = readAllRecordHeaders(binary);
1329
+ let inCellXfs = false;
1330
+ let inStyleXfs = false;
1331
+ let inFonts = false;
1332
+ let inFills = false;
1333
+ let inBorders = false;
1334
+ let inFmts = false;
1335
+ for (const record of records) {
1336
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1337
+ if (record.type === RT.BrtBeginFonts) {
1338
+ inFonts = true;
1339
+ continue;
1340
+ }
1341
+ if (record.type === RT.BrtEndFonts) {
1342
+ inFonts = false;
1343
+ continue;
1344
+ }
1345
+ if (record.type === RT.BrtBeginFills) {
1346
+ inFills = true;
1347
+ continue;
1348
+ }
1349
+ if (record.type === RT.BrtEndFills) {
1350
+ inFills = false;
1351
+ continue;
1352
+ }
1353
+ if (record.type === RT.BrtBeginBorders) {
1354
+ inBorders = true;
1355
+ continue;
1356
+ }
1357
+ if (record.type === RT.BrtEndBorders) {
1358
+ inBorders = false;
1359
+ continue;
1360
+ }
1361
+ if (record.type === RT.BrtBeginFmts) {
1362
+ inFmts = true;
1363
+ continue;
1364
+ }
1365
+ if (record.type === RT.BrtEndFmts) {
1366
+ inFmts = false;
1367
+ continue;
1368
+ }
1369
+ if (record.type === RT.BrtBeginCellXFs) {
1370
+ inCellXfs = true;
1371
+ continue;
1372
+ }
1373
+ if (record.type === RT.BrtEndCellXFs) {
1374
+ inCellXfs = false;
1375
+ continue;
1376
+ }
1377
+ if (record.type === RT.BrtBeginCellStyleXFs) {
1378
+ inStyleXfs = true;
1379
+ continue;
1380
+ }
1381
+ if (record.type === RT.BrtEndCellStyleXFs) {
1382
+ inStyleXfs = false;
1383
+ continue;
1384
+ }
1385
+ if (record.type === RT.BrtFmt && inFmts) {
1386
+ const { id, formatCode } = parseBrtFmt(payload);
1387
+ styles.numberFormats.set(id, formatCode);
1388
+ continue;
1389
+ }
1390
+ if (record.type === RT.BrtFont && inFonts) {
1391
+ styles.fonts.push(parseBrtFont(payload));
1392
+ continue;
1393
+ }
1394
+ if (record.type === RT.BrtFill && inFills) {
1395
+ styles.fills.push(parseBrtFill(payload));
1396
+ continue;
1397
+ }
1398
+ if (record.type === RT.BrtBorder && inBorders) {
1399
+ styles.borders.push(parseBrtBorder(payload));
1400
+ continue;
1401
+ }
1402
+ if (record.type === RT.BrtXF && inStyleXfs) {
1403
+ styles.styleXfs.push(parseBrtXf(payload));
1404
+ continue;
1405
+ }
1406
+ if (record.type === RT.BrtXF && inCellXfs) {
1407
+ styles.cellXfs.push(parseBrtXf(payload));
1408
+ }
1409
+ }
1410
+ return styles;
1411
+ }
1412
+ async loadTheme() {
1413
+ try {
1414
+ if (!this.zipParser.has("xl/theme/theme1.xml")) {
1415
+ return defaultSpreadsheetTheme;
1416
+ }
1417
+ const themeContent = await this.zipParser.getText("xl/theme/theme1.xml");
1418
+ const themeXml = this.xmlParser.parse(themeContent);
1419
+ const themeName = get(themeXml, "a:theme.a$.name") || "Office";
1420
+ const { primaryFontFamily, headingFontFamily } = extractThemeFonts(themeXml);
1421
+ const themeColors = extractThemeColors(themeXml, defaultSpreadsheetTheme);
1422
+ const darkThemeColors = generateDarkThemeColors(themeColors);
1423
+ return {
1424
+ name: themeName,
1425
+ primaryFontFamily,
1426
+ headingFontFamily,
1427
+ themeColors,
1428
+ darkThemeColors,
1429
+ };
1430
+ }
1431
+ catch {
1432
+ return defaultSpreadsheetTheme;
1433
+ }
1434
+ }
1435
+ getTheme() {
1436
+ return this.theme ?? defaultSpreadsheetTheme;
1437
+ }
1438
+ parseRelIdFromPayload(payload) {
1439
+ const reader = new Reader(payload);
1440
+ const relId = reader.readXLNullableWideString();
1441
+ return relId || undefined;
1442
+ }
1443
+ async loadRelationshipsForPart(basePath) {
1444
+ const base = normalizePath(basePath);
1445
+ const name = base.split("/").pop();
1446
+ if (!name)
1447
+ return new Map();
1448
+ const dir = base.substring(0, base.lastIndexOf("/"));
1449
+ const relsPath = `${dir}/_rels/${name}.rels`;
1450
+ if (!this.zipParser.has(relsPath))
1451
+ return new Map();
1452
+ const relText = await this.zipParser.getText(relsPath);
1453
+ const rels = this.xmlParser.parse(relText);
1454
+ const relations = get(rels, "Relationships.Relationship") ?? [];
1455
+ const list = Array.isArray(relations) ? relations : [relations];
1456
+ const out = new Map();
1457
+ for (const rel of list) {
1458
+ const id = rel?.a$?.Id ?? rel?.Id;
1459
+ const target = rel?.a$?.Target ?? rel?.Target;
1460
+ if (typeof id === "string" && typeof target === "string") {
1461
+ out.set(id, target);
1462
+ }
1463
+ }
1464
+ return out;
1465
+ }
1466
+ async getDrawingPathsForSheet(sheet) {
1467
+ if (!sheet.path || !this.zipParser.has(sheet.path))
1468
+ return [];
1469
+ const binary = await this.zipParser.getBinary(sheet.path);
1470
+ const records = readAllRecordHeaders(binary);
1471
+ const relIds = [];
1472
+ for (const record of records) {
1473
+ if (record.type !== RT.BrtDrawing)
1474
+ continue;
1475
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1476
+ const relId = this.parseRelIdFromPayload(payload);
1477
+ if (relId)
1478
+ relIds.push(relId);
1479
+ }
1480
+ if (relIds.length === 0)
1481
+ return [];
1482
+ const relMap = await this.loadRelationshipsForPart(sheet.path);
1483
+ const paths = [];
1484
+ for (const relId of relIds) {
1485
+ const target = relMap.get(relId);
1486
+ if (!target)
1487
+ continue;
1488
+ paths.push(resolveRelativePath(sheet.path, target));
1489
+ }
1490
+ return Array.from(new Set(paths));
1491
+ }
1492
+ async getTablesFromSheet(sheet) {
1493
+ if (!sheet.path || !sheet.tablePartRelIds.length)
1494
+ return [];
1495
+ const relMap = await this.loadRelationshipsForPart(sheet.path);
1496
+ const tables = [];
1497
+ for (const tableRelId of sheet.tablePartRelIds) {
1498
+ const target = relMap.get(tableRelId);
1499
+ if (!target)
1500
+ continue;
1501
+ const tablePath = resolveRelativePath(sheet.path, target);
1502
+ if (!this.zipParser.has(tablePath))
1503
+ continue;
1504
+ // XLSB workbooks written by Excel store table parts as BIFF12
1505
+ // binaries (xl/tables/tableN.bin) — those need a binary parser and
1506
+ // must not be fed to the XML parser. Only XML table parts (produced
1507
+ // by some third-party writers) are handled here; anything else is
1508
+ // skipped so one table part can never fail the whole import.
1509
+ if (tablePath.endsWith(".bin"))
1510
+ continue;
1511
+ const tableContent = await this.zipParser.getText(tablePath);
1512
+ let tableData;
1513
+ try {
1514
+ tableData = this.xmlParser.parse(tableContent || "");
1515
+ }
1516
+ catch {
1517
+ continue;
1518
+ }
1519
+ const tableDefinition = get(tableData, "table") || get(tableData, "x:table");
1520
+ if (!tableDefinition)
1521
+ continue;
1522
+ const attrs = tableDefinition.a$ || {};
1523
+ const range = getRangeFromAddressRef(attrs.ref);
1524
+ if (!range)
1525
+ continue;
1526
+ const columnDefinitions = get(tableDefinition, "tableColumns.tableColumn") ||
1527
+ get(tableDefinition, "x:tableColumns.x:tableColumn");
1528
+ const columnDefsArray = Array.isArray(columnDefinitions)
1529
+ ? columnDefinitions
1530
+ : columnDefinitions
1531
+ ? [columnDefinitions]
1532
+ : [];
1533
+ const columns = columnDefsArray.map((colDef) => {
1534
+ const name = colDef?.a$?.name || "";
1535
+ const calculatedColumnFormula = get(colDef, "calculatedColumnFormula") ||
1536
+ get(colDef, "x:calculatedColumnFormula");
1537
+ if (calculatedColumnFormula) {
1538
+ return { name, formula: calculatedColumnFormula };
1539
+ }
1540
+ return { name };
1541
+ });
1542
+ const autoFilter = tableDefinition.autoFilter ?? tableDefinition["x:autoFilter"];
1543
+ const filterSpecs = createFilterSpecsFromAutoFilter(autoFilter);
1544
+ const tableStyle = get(tableDefinition, "tableStyleInfo") ||
1545
+ get(tableDefinition, "x:tableStyleInfo") ||
1546
+ {};
1547
+ const tableStyleAttrs = tableStyle.a$ || {};
1548
+ const tableView = {
1549
+ id: attrs.id || uuid(),
1550
+ title: attrs.name || attrs.displayName || `Table_${tables.length + 1}`,
1551
+ sheetId: sheet.sheetId,
1552
+ headerRow: attrs.headerRowCount !== "0",
1553
+ totalRow: attrs.totalsRowCount === "1",
1554
+ showRowStripes: attrs.showRowStripes !== "0",
1555
+ showColumnStripes: attrs.showColumnStripes === "1",
1556
+ showFirstColumn: attrs.showFirstColumn === "1",
1557
+ showLastColumn: attrs.showLastColumn === "1",
1558
+ filterButton: attrs.filterButton !== "0",
1559
+ columns: columns,
1560
+ range,
1561
+ filterSpecs,
1562
+ };
1563
+ if (tableStyleAttrs.name) {
1564
+ tableView.theme = tableStyleAttrs.name;
1565
+ }
1566
+ tables.push(tableView);
1567
+ }
1568
+ return tables;
1569
+ }
1570
+ async scanSheetStats(path) {
1571
+ const binary = await this.zipParser.getBinary(path);
1572
+ const records = readAllRecordHeaders(binary);
1573
+ let currentRow = 0;
1574
+ let maxRow = 0;
1575
+ let maxCol = 0;
1576
+ let prevCol = -1;
1577
+ const merges = [];
1578
+ const rowMetadata = [];
1579
+ const columnMetadata = [];
1580
+ let showGridLines;
1581
+ let frozenRowCount;
1582
+ let frozenColumnCount;
1583
+ let basicFilterRange;
1584
+ const tablePartRelIds = [];
1585
+ for (const record of records) {
1586
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1587
+ if (record.type === RT.BrtWsView) {
1588
+ const view = parseWsView(payload);
1589
+ showGridLines = view.showGridLines;
1590
+ continue;
1591
+ }
1592
+ if (record.type === RT.BrtPane) {
1593
+ const pane = parsePane(payload);
1594
+ if (pane.frozenRowCount > 0)
1595
+ frozenRowCount = pane.frozenRowCount;
1596
+ if (pane.frozenColumnCount > 0)
1597
+ frozenColumnCount = pane.frozenColumnCount;
1598
+ continue;
1599
+ }
1600
+ if (record.type === RT.BrtBeginAFilter) {
1601
+ basicFilterRange = parseRange(payload);
1602
+ continue;
1603
+ }
1604
+ if (record.type === RT.BrtListPart) {
1605
+ const relId = parseBrtListPartRelId(payload);
1606
+ if (relId)
1607
+ tablePartRelIds.push(relId);
1608
+ continue;
1609
+ }
1610
+ if (record.type === RT.BrtRowHdr) {
1611
+ const parsedRow = parseRowHeader(payload);
1612
+ currentRow = parsedRow.row;
1613
+ prevCol = -1;
1614
+ if (currentRow > maxRow)
1615
+ maxRow = currentRow;
1616
+ if (parsedRow.hidden || parsedRow.hpt != null) {
1617
+ rowMetadata[currentRow] = {
1618
+ ...(parsedRow.hidden ? { hiddenByUser: true } : {}),
1619
+ ...(parsedRow.hpt != null
1620
+ ? {
1621
+ size: Math.round((parsedRow.hpt * 96) / 72),
1622
+ resizedByUser: true,
1623
+ }
1624
+ : {}),
1625
+ };
1626
+ }
1627
+ continue;
1628
+ }
1629
+ if (record.type === RT.BrtColInfo) {
1630
+ const parsedCol = parseBrtColInfo(payload);
1631
+ for (let col = parsedCol.startCol; col <= parsedCol.endCol; col++) {
1632
+ const dimensionProps = {};
1633
+ if (parsedCol.hidden)
1634
+ dimensionProps.hiddenByUser = true;
1635
+ if (parsedCol.size > 0) {
1636
+ dimensionProps.size = parsedCol.size;
1637
+ if (parsedCol.customWidth) {
1638
+ dimensionProps.resizedByUser = true;
1639
+ }
1640
+ }
1641
+ if (Object.keys(dimensionProps).length > 0) {
1642
+ columnMetadata[col] = dimensionProps;
1643
+ }
1644
+ }
1645
+ continue;
1646
+ }
1647
+ if (record.type === RT.BrtMergeCell) {
1648
+ const merge = parseMergeRange(payload);
1649
+ merges.push(merge);
1650
+ if (merge.endRowIndex > maxRow)
1651
+ maxRow = merge.endRowIndex;
1652
+ if (merge.endColumnIndex > maxCol)
1653
+ maxCol = merge.endColumnIndex;
1654
+ continue;
1655
+ }
1656
+ if (!isCellRecord(record.type))
1657
+ continue;
1658
+ const parsed = parseCellFromRecord(record.type, payload, currentRow, prevCol, (ixti) => this.resolveSheetNameByXti(ixti), undefined, false);
1659
+ if (!parsed)
1660
+ continue;
1661
+ prevCol = parsed.col - 1;
1662
+ if (parsed.row > maxRow)
1663
+ maxRow = parsed.row;
1664
+ if (parsed.col > maxCol)
1665
+ maxCol = parsed.col;
1666
+ }
1667
+ return {
1668
+ rowCount: maxRow,
1669
+ columnCount: maxCol,
1670
+ merges,
1671
+ rowMetadata,
1672
+ columnMetadata,
1673
+ showGridLines,
1674
+ frozenRowCount,
1675
+ frozenColumnCount,
1676
+ basicFilterRange,
1677
+ tablePartRelIds,
1678
+ };
1679
+ }
1680
+ getSheetCount() {
1681
+ return this.sheets.length;
1682
+ }
1683
+ getSheetNames() {
1684
+ return this.sheets.map((s) => s.title);
1685
+ }
1686
+ resolveSheetNameByXti(ixti) {
1687
+ const sheetNames = this.getSheetNames();
1688
+ const fallback = sheetNames[ixti] ?? sheetNames[ixti - 1];
1689
+ const xti = this.externSheetRefs[ixti];
1690
+ if (!xti)
1691
+ return fallback;
1692
+ const linkType = this.supportingLinks[xti.iSupBook];
1693
+ if (linkType !== "self" && linkType !== "same") {
1694
+ return fallback;
1695
+ }
1696
+ const first = xti.itabFirst;
1697
+ const last = xti.itabLast;
1698
+ if (first < 0 || first >= sheetNames.length)
1699
+ return fallback;
1700
+ if (last < 0 || last >= sheetNames.length)
1701
+ return sheetNames[first];
1702
+ if (first === last)
1703
+ return sheetNames[first];
1704
+ return `${sheetNames[first]}:${sheetNames[last]}`;
1705
+ }
1706
+ async getSheets(minRowCount = 0, minColumnCount = 0) {
1707
+ const tables = [];
1708
+ const sheets = [];
1709
+ for (const sheet of this.sheets) {
1710
+ const sheetTables = await this.getTablesFromSheet(sheet);
1711
+ tables.push(...sheetTables);
1712
+ const matchedFilterSpecs = sheetTables.find((t) => sheet.basicFilterRange &&
1713
+ t.range.startRowIndex === sheet.basicFilterRange.startRowIndex &&
1714
+ t.range.endRowIndex === sheet.basicFilterRange.endRowIndex &&
1715
+ t.range.startColumnIndex ===
1716
+ sheet.basicFilterRange.startColumnIndex &&
1717
+ t.range.endColumnIndex === sheet.basicFilterRange.endColumnIndex)?.filterSpecs;
1718
+ sheets.push({
1719
+ sheetId: sheet.sheetId,
1720
+ title: sheet.title,
1721
+ hidden: sheet.hidden,
1722
+ rowCount: Math.max(minRowCount, sheet.rowCount),
1723
+ columnCount: Math.max(minColumnCount, sheet.columnCount),
1724
+ rowMetadata: sheet.rowMetadata,
1725
+ columnMetadata: sheet.columnMetadata,
1726
+ merges: sheet.merges,
1727
+ ...(sheet.showGridLines !== undefined
1728
+ ? { showGridLines: sheet.showGridLines }
1729
+ : {}),
1730
+ ...(sheet.frozenRowCount !== undefined && sheet.frozenRowCount > 0
1731
+ ? { frozenRowCount: sheet.frozenRowCount }
1732
+ : {}),
1733
+ ...(sheet.frozenColumnCount !== undefined && sheet.frozenColumnCount > 0
1734
+ ? { frozenColumnCount: sheet.frozenColumnCount }
1735
+ : {}),
1736
+ ...(sheet.basicFilterRange
1737
+ ? {
1738
+ basicFilter: {
1739
+ id: uuid(),
1740
+ range: sheet.basicFilterRange,
1741
+ filterSpecs: matchedFilterSpecs ?? [],
1742
+ },
1743
+ }
1744
+ : {}),
1745
+ });
1746
+ }
1747
+ return [sheets, tables];
1748
+ }
1749
+ getSharedStrings() {
1750
+ return this.sharedStrings;
1751
+ }
1752
+ getStyles() {
1753
+ return this.styles;
1754
+ }
1755
+ getFonts() {
1756
+ const out = new Set();
1757
+ for (const font of this.styles.fonts) {
1758
+ if (font.name)
1759
+ out.add(font.name);
1760
+ }
1761
+ return [...out];
1762
+ }
1763
+ getCellXfs() {
1764
+ return this.cellXfs;
1765
+ }
1766
+ registerFormat(format) {
1767
+ const key = getCellXfsKey(format);
1768
+ if (!this.cellXfs.has(key)) {
1769
+ this.cellXfs.set(key, format);
1770
+ }
1771
+ return key;
1772
+ }
1773
+ async *processSheetData(chunkSize = 100, enableCellXfsRegistry = false, enableSharedStrings = true) {
1774
+ const totalSheets = this.sheets.length;
1775
+ for (let index = 0; index < this.sheets.length; index++) {
1776
+ const sheet = this.sheets[index];
1777
+ if (!sheet.path || !this.zipParser.has(sheet.path))
1778
+ continue;
1779
+ const binary = await this.zipParser.getBinary(sheet.path);
1780
+ const records = readAllRecordHeaders(binary);
1781
+ const sharedFormulaBytes = new Map();
1782
+ const sharedFormulaRanges = [];
1783
+ // Pre-scan shared formulas so PtgExp can resolve even when BrtShrFmla
1784
+ // appears later in the record stream.
1785
+ for (const record of records) {
1786
+ if (record.type !== RT.BrtShrFmla)
1787
+ continue;
1788
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1789
+ const parsedShared = parseBrtShrFmla(payload);
1790
+ if (!parsedShared)
1791
+ continue;
1792
+ sharedFormulaBytes.set(`${parsedShared.startRow}:${parsedShared.startCol}`, parsedShared.rgceBytes);
1793
+ sharedFormulaRanges.push(parsedShared);
1794
+ }
1795
+ let currentRow = 0;
1796
+ let prevCol = -1;
1797
+ const rows = new Map();
1798
+ for (const record of records) {
1799
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
1800
+ if (record.type === RT.BrtShrFmla) {
1801
+ continue;
1802
+ }
1803
+ if (record.type === RT.BrtRowHdr) {
1804
+ const parsedRow = parseRowHeader(payload);
1805
+ currentRow = parsedRow.row;
1806
+ prevCol = -1;
1807
+ if (!rows.has(currentRow)) {
1808
+ rows.set(currentRow, { values: [] });
1809
+ }
1810
+ continue;
1811
+ }
1812
+ if (!isCellRecord(record.type))
1813
+ continue;
1814
+ const parsed = parseCellFromRecord(record.type, payload, currentRow, prevCol, (ixti) => this.resolveSheetNameByXti(ixti), (sourceRow, sourceCol, targetRow, targetCol) => {
1815
+ let rgce = sharedFormulaBytes.get(`${sourceRow}:${sourceCol}`);
1816
+ if (!rgce) {
1817
+ const sourceRange = sharedFormulaRanges.find((range) => sourceRow >= range.startRow &&
1818
+ sourceRow <= range.endRow &&
1819
+ sourceCol >= range.startCol &&
1820
+ sourceCol <= range.endCol);
1821
+ rgce = sourceRange?.rgceBytes;
1822
+ }
1823
+ if (!rgce)
1824
+ return undefined;
1825
+ return parseRgce(rgce, (ixti) => this.resolveSheetNameByXti(ixti), {
1826
+ row: targetRow,
1827
+ col: targetCol,
1828
+ }, true); // Enable debug logging
1829
+ });
1830
+ if (!parsed)
1831
+ continue;
1832
+ if (!parsed.formula && sharedFormulaRanges.length > 0) {
1833
+ const sharedRange = sharedFormulaRanges.find((range) => parsed.row >= range.startRow &&
1834
+ parsed.row <= range.endRow &&
1835
+ parsed.col >= range.startCol &&
1836
+ parsed.col <= range.endCol);
1837
+ if (sharedRange) {
1838
+ const resolved = parseRgce(sharedRange.rgceBytes, (ixti) => this.resolveSheetNameByXti(ixti), { row: parsed.row, col: parsed.col }, true);
1839
+ if (resolved) {
1840
+ parsed.formula = resolved;
1841
+ }
1842
+ }
1843
+ }
1844
+ prevCol = parsed.col - 1;
1845
+ let row = rows.get(parsed.row);
1846
+ if (!row) {
1847
+ row = { values: [] };
1848
+ rows.set(parsed.row, row);
1849
+ }
1850
+ row.values[parsed.col] = toCellData(parsed, this.styles, this.sharedStrings, enableCellXfsRegistry, enableSharedStrings, this.cellXfs);
1851
+ }
1852
+ // Apply merge cell formatting
1853
+ // In Excel, merged cells should have formatting from the top-left (anchor) cell
1854
+ // propagated to all cells in the merge range, but borders need special handling
1855
+ for (const merge of sheet.merges) {
1856
+ const topLeftRow = rows.get(merge.startRowIndex);
1857
+ const topLeftCell = topLeftRow?.values?.[merge.startColumnIndex];
1858
+ // Get the format from the top-left cell (if it exists)
1859
+ const sourceFormat = topLeftCell?.ef || topLeftCell?.uf;
1860
+ // Process all cells in the merge range
1861
+ // This ensures the merge structure exists even if there's no explicit formatting
1862
+ for (let r = merge.startRowIndex; r <= merge.endRowIndex; r++) {
1863
+ for (let c = merge.startColumnIndex; c <= merge.endColumnIndex; c++) {
1864
+ // Skip the top-left cell as it already has its data/format
1865
+ if (r === merge.startRowIndex && c === merge.startColumnIndex) {
1866
+ continue;
1867
+ }
1868
+ // Ensure row exists
1869
+ let row = rows.get(r);
1870
+ if (!row) {
1871
+ row = { values: [] };
1872
+ rows.set(r, row);
1873
+ }
1874
+ // Create format without borders for non-anchor cells
1875
+ // Borders should only appear on the outer edges of merged cells, not internally
1876
+ let format = sourceFormat;
1877
+ if (format && typeof format === "object" && "borders" in format) {
1878
+ const { borders, ...formatWithoutBorders } = format;
1879
+ format =
1880
+ Object.keys(formatWithoutBorders).length > 0
1881
+ ? formatWithoutBorders
1882
+ : undefined;
1883
+ }
1884
+ const existingCell = row.values[c];
1885
+ if (existingCell) {
1886
+ // Cell exists - we need to remove borders even if there's no other format
1887
+ // Preserve cell content (values, formulas, etc.) but update formatting
1888
+ const { ef, uf, ...cellContent } = existingCell;
1889
+ if (format) {
1890
+ // Apply the format without borders
1891
+ row.values[c] = {
1892
+ ...cellContent,
1893
+ ef: format,
1894
+ uf: format,
1895
+ };
1896
+ }
1897
+ else {
1898
+ // No format to apply, but remove any existing formatting to clear borders
1899
+ row.values[c] = cellContent;
1900
+ }
1901
+ }
1902
+ else {
1903
+ // Create a blank cell with format (if available) for proper merge rendering
1904
+ if (format) {
1905
+ row.values[c] = {
1906
+ ef: format,
1907
+ uf: format,
1908
+ };
1909
+ }
1910
+ else {
1911
+ // Create a blank cell even without format to preserve merge structure
1912
+ row.values[c] = {};
1913
+ }
1914
+ }
1915
+ }
1916
+ }
1917
+ }
1918
+ const sortedRows = Array.from(rows.entries()).sort((a, b) => a[0] - b[0]);
1919
+ let chunkRows = [];
1920
+ let chunkRowIndices = [];
1921
+ let chunkIndex = 0;
1922
+ let startRowIndex = -1;
1923
+ let endRowIndex = -1;
1924
+ for (const [rowIndex, rowData] of sortedRows) {
1925
+ if (chunkRows.length === 0) {
1926
+ startRowIndex = rowIndex;
1927
+ }
1928
+ chunkRows.push(rowData);
1929
+ chunkRowIndices.push(rowIndex);
1930
+ endRowIndex = rowIndex;
1931
+ if (chunkRows.length >= chunkSize) {
1932
+ yield {
1933
+ sheetId: sheet.sheetId,
1934
+ title: sheet.title,
1935
+ currentSheetIndex: index,
1936
+ totalSheets,
1937
+ chunkIndex,
1938
+ rows: chunkRows,
1939
+ rowIndices: chunkRowIndices,
1940
+ startRowIndex,
1941
+ endRowIndex,
1942
+ totalRows: sheet.rowCount,
1943
+ isLastChunk: false,
1944
+ cellXfs: this.cellXfs,
1945
+ };
1946
+ chunkRows = [];
1947
+ chunkRowIndices = [];
1948
+ chunkIndex += 1;
1949
+ startRowIndex = -1;
1950
+ endRowIndex = -1;
1951
+ }
1952
+ }
1953
+ if (chunkRows.length) {
1954
+ yield {
1955
+ sheetId: sheet.sheetId,
1956
+ title: sheet.title,
1957
+ currentSheetIndex: index,
1958
+ totalSheets,
1959
+ chunkIndex,
1960
+ rows: chunkRows,
1961
+ rowIndices: chunkRowIndices,
1962
+ startRowIndex,
1963
+ endRowIndex,
1964
+ totalRows: sheet.rowCount,
1965
+ isLastChunk: true,
1966
+ cellXfs: this.cellXfs,
1967
+ };
1968
+ }
1969
+ }
1970
+ }
1971
+ async getDrawings() {
1972
+ const drawings = [];
1973
+ for (const sheet of this.sheets) {
1974
+ const drawingPaths = await this.getDrawingPathsForSheet(sheet);
1975
+ for (const drawingPath of drawingPaths) {
1976
+ if (!this.zipParser.has(drawingPath))
1977
+ continue;
1978
+ const drawingContent = await this.zipParser.getText(drawingPath);
1979
+ if (!drawingContent)
1980
+ continue;
1981
+ const drawingXml = this.xmlParser.parse(drawingContent);
1982
+ const oneCellAnchors = get(drawingXml, "xdr:wsDr.xdr:oneCellAnchor") ||
1983
+ get(drawingXml, "wsDr.oneCellAnchor");
1984
+ const twoCellAnchors = get(drawingXml, "xdr:wsDr.xdr:twoCellAnchor") ||
1985
+ get(drawingXml, "wsDr.twoCellAnchor");
1986
+ const absoluteAnchors = get(drawingXml, "xdr:wsDr.xdr:absoluteAnchor") ||
1987
+ get(drawingXml, "wsDr.absoluteAnchor");
1988
+ if (oneCellAnchors) {
1989
+ drawings.push(...(await processAnchors(oneCellAnchors, "oneCellAnchor", drawingPath, sheet.sheetId, this.zipParser, this.xmlParser)));
1990
+ }
1991
+ if (twoCellAnchors) {
1992
+ drawings.push(...(await processAnchors(twoCellAnchors, "twoCellAnchors", drawingPath, sheet.sheetId, this.zipParser, this.xmlParser)));
1993
+ }
1994
+ if (absoluteAnchors) {
1995
+ drawings.push(...(await processAnchors(absoluteAnchors, "absoluteAnchors", drawingPath, sheet.sheetId, this.zipParser, this.xmlParser)));
1996
+ }
1997
+ }
1998
+ }
1999
+ return drawings;
2000
+ }
2001
+ async getCharts() {
2002
+ const charts = [];
2003
+ // sheet-name → sheetId map for cross-sheet ref resolution in chart
2004
+ // formulas (mirrors the xlsx plugin).
2005
+ const sheetIdByName = {};
2006
+ for (const sheet of this.sheets) {
2007
+ if (sheet?.title && sheet?.sheetId !== undefined) {
2008
+ sheetIdByName[String(sheet.title)] = Number(sheet.sheetId);
2009
+ }
2010
+ }
2011
+ const resolveSheetId = (sheetName) => sheetName ? sheetIdByName[String(sheetName)] : undefined;
2012
+ for (const sheet of this.sheets) {
2013
+ const drawingPaths = await this.getDrawingPathsForSheet(sheet);
2014
+ for (const drawingPath of drawingPaths) {
2015
+ if (!this.zipParser.has(drawingPath))
2016
+ continue;
2017
+ const drawingContent = await this.zipParser.getText(drawingPath);
2018
+ if (!drawingContent)
2019
+ continue;
2020
+ const drawingXml = this.xmlParser.parse(drawingContent);
2021
+ const drawingDir = drawingPath.substring(0, drawingPath.lastIndexOf("/"));
2022
+ const drawingName = drawingPath.split("/").pop();
2023
+ if (!drawingName)
2024
+ continue;
2025
+ const drawingRelsPath = `${drawingDir}/_rels/${drawingName}.rels`;
2026
+ if (!this.zipParser.has(drawingRelsPath))
2027
+ continue;
2028
+ const drawingRelsContent = await this.zipParser.getText(drawingRelsPath);
2029
+ const drawingRelsXml = this.xmlParser.parse(drawingRelsContent);
2030
+ const drawingRelsList = get(drawingRelsXml, "Relationships.Relationship") || [];
2031
+ const drawingRelsArray = Array.isArray(drawingRelsList)
2032
+ ? drawingRelsList
2033
+ : [drawingRelsList];
2034
+ const oneCellAnchors = get(drawingXml, "xdr:wsDr.xdr:oneCellAnchor") ||
2035
+ get(drawingXml, "wsDr.oneCellAnchor");
2036
+ const twoCellAnchors = get(drawingXml, "xdr:wsDr.xdr:twoCellAnchor") ||
2037
+ get(drawingXml, "wsDr.twoCellAnchor");
2038
+ const anchors = [
2039
+ ...(Array.isArray(oneCellAnchors)
2040
+ ? oneCellAnchors
2041
+ : oneCellAnchors
2042
+ ? [oneCellAnchors]
2043
+ : []),
2044
+ ...(Array.isArray(twoCellAnchors)
2045
+ ? twoCellAnchors
2046
+ : twoCellAnchors
2047
+ ? [twoCellAnchors]
2048
+ : []),
2049
+ ];
2050
+ for (const anchor of anchors) {
2051
+ const chartId = get(anchor, "xdr:graphicFrame.a:graphic.a:graphicData.c:chart.a$.r:id") || get(anchor, "graphicFrame.graphic.graphicData.chart.a$.r:id");
2052
+ if (!chartId)
2053
+ continue;
2054
+ const chartRel = drawingRelsArray.find((rel) => rel?.a$?.Id === chartId ||
2055
+ rel?.a$?.id === chartId ||
2056
+ rel?.a$?.ID === chartId);
2057
+ if (!chartRel?.a$?.Target)
2058
+ continue;
2059
+ const chart = await processChart(chartRel.a$.Target, drawingPath, anchor, sheet.sheetId, this.zipParser, this.xmlParser, undefined, resolveSheetId);
2060
+ if (chart)
2061
+ charts.push(chart);
2062
+ }
2063
+ }
2064
+ }
2065
+ return charts;
2066
+ }
2067
+ async getConditionalFormatting() {
2068
+ const rules = [];
2069
+ let ruleIdCounter = 0;
2070
+ for (const sheet of this.sheets) {
2071
+ if (!sheet.path || !this.zipParser.has(sheet.path))
2072
+ continue;
2073
+ try {
2074
+ const binary = await this.zipParser.getBinary(sheet.path);
2075
+ const records = readAllRecordHeaders(binary);
2076
+ let inCF = false;
2077
+ let currentCFRanges = null;
2078
+ let cfRuleIndex = 0;
2079
+ for (const record of records) {
2080
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
2081
+ if (record.type === RT.BrtBeginConditionalFormatting) {
2082
+ inCF = true;
2083
+ cfRuleIndex = 0;
2084
+ const parsed = parseBrtBeginConditionalFormatting(payload);
2085
+ currentCFRanges = parsed?.sqref || null;
2086
+ continue;
2087
+ }
2088
+ if (record.type === RT.BrtEndConditionalFormatting) {
2089
+ inCF = false;
2090
+ currentCFRanges = null;
2091
+ continue;
2092
+ }
2093
+ if (inCF && record.type === RT.BrtBeginCFRule && currentCFRanges) {
2094
+ const cfRule = parseBrtCFRule(payload);
2095
+ if (cfRule) {
2096
+ // Parse ranges
2097
+ const rangeAddresses = currentCFRanges.split(" ");
2098
+ const ranges = [];
2099
+ for (const address of rangeAddresses) {
2100
+ const range = getRangeFromAddressRef(address);
2101
+ if (range) {
2102
+ ranges.push({
2103
+ ...range,
2104
+ sheetId: sheet.sheetId,
2105
+ });
2106
+ }
2107
+ }
2108
+ if (ranges.length > 0) {
2109
+ const rule = {
2110
+ id: `${sheet.sheetId}_${ruleIdCounter++}_${cfRuleIndex++}`,
2111
+ ranges,
2112
+ priority: cfRule.priority,
2113
+ };
2114
+ if (cfRule.stopIfTrue) {
2115
+ rule.stopIfTrue = true;
2116
+ }
2117
+ // Note: Full implementation would parse:
2118
+ // - Rule type and convert to booleanRule/gradientRule/topBottomRule/distinctRule
2119
+ // - DXF styles for formatting
2120
+ // - Formulas and values from Rgce data
2121
+ // This is a basic implementation that captures the structure
2122
+ rules.push(rule);
2123
+ }
2124
+ }
2125
+ }
2126
+ }
2127
+ }
2128
+ catch (err) {
2129
+ // Skip sheet if parsing fails
2130
+ console.warn(`Failed to parse CF for sheet ${sheet.title}:`, err);
2131
+ }
2132
+ }
2133
+ return rules;
2134
+ }
2135
+ async getDataValidations() {
2136
+ const validations = [];
2137
+ for (const sheet of this.sheets) {
2138
+ if (!sheet.path || !this.zipParser.has(sheet.path))
2139
+ continue;
2140
+ try {
2141
+ const binary = await this.zipParser.getBinary(sheet.path);
2142
+ const records = readAllRecordHeaders(binary);
2143
+ let inDVals = false;
2144
+ let inDVal = false;
2145
+ let currentDVal = null;
2146
+ let currentRanges = null;
2147
+ for (const record of records) {
2148
+ const payload = binary.subarray(record.dataOffset, record.nextOffset);
2149
+ if (record.type === RT.BrtBeginDVals) {
2150
+ inDVals = true;
2151
+ continue;
2152
+ }
2153
+ if (record.type === RT.BrtEndDVals) {
2154
+ inDVals = false;
2155
+ continue;
2156
+ }
2157
+ if (inDVals && record.type === RT.BrtBeginDVal) {
2158
+ inDVal = true;
2159
+ currentDVal = parseBrtBeginDVal(payload);
2160
+ // Next record should contain the range
2161
+ continue;
2162
+ }
2163
+ if (inDVal && currentDVal) {
2164
+ // Try to parse range from payload
2165
+ // In XLSB, the range typically follows in the same or next record
2166
+ try {
2167
+ const reader = new Reader(payload);
2168
+ const maybeRange = reader.readXLWideString();
2169
+ if (maybeRange && maybeRange.includes(":")) {
2170
+ currentRanges = maybeRange;
2171
+ }
2172
+ }
2173
+ catch {
2174
+ // Not a range, continue
2175
+ }
2176
+ }
2177
+ if (record.type === RT.BrtEndDVal) {
2178
+ inDVal = false;
2179
+ if (currentDVal && currentRanges) {
2180
+ // Parse ranges
2181
+ const rangeAddresses = currentRanges.split(" ");
2182
+ const ranges = [];
2183
+ for (const address of rangeAddresses) {
2184
+ const range = getRangeFromAddressRef(address);
2185
+ if (range) {
2186
+ ranges.push({
2187
+ ...range,
2188
+ sheetId: sheet.sheetId,
2189
+ });
2190
+ }
2191
+ }
2192
+ if (ranges.length > 0) {
2193
+ // Map validation type to condition type
2194
+ const typeMap = {
2195
+ 1: "NUMBER", // whole
2196
+ 2: "NUMBER", // decimal
2197
+ 3: "LIST", // list
2198
+ 4: "DATE", // date
2199
+ 5: "TIME", // time
2200
+ 6: "TEXT_LENGTH", // textLength
2201
+ 7: "CUSTOM_FORMULA", // custom
2202
+ };
2203
+ const validation = {
2204
+ id: uuid(),
2205
+ ranges,
2206
+ };
2207
+ // Add condition if we have a recognized type
2208
+ const conditionType = typeMap[currentDVal.valType];
2209
+ if (conditionType && currentDVal.operator !== undefined) {
2210
+ // Note: Full implementation would parse formulas and create proper BooleanCondition
2211
+ // This is a basic structure
2212
+ }
2213
+ // Add allow blank flag
2214
+ if (currentDVal.ignoreBlank) {
2215
+ validation.allowBlank = true;
2216
+ }
2217
+ // Add input message if present
2218
+ if (currentDVal.showInputMessage &&
2219
+ (currentDVal.promptTitle || currentDVal.prompt)) {
2220
+ validation.inputMessage = {
2221
+ ...(currentDVal.promptTitle
2222
+ ? { title: currentDVal.promptTitle }
2223
+ : {}),
2224
+ ...(currentDVal.prompt
2225
+ ? { message: currentDVal.prompt }
2226
+ : {}),
2227
+ };
2228
+ }
2229
+ // Add error alert if present. showErrorMessage without any
2230
+ // custom title/text still means "reject invalid input with
2231
+ // the default alert", so keep the style-only alert.
2232
+ if (currentDVal.showErrorMessage) {
2233
+ const alertStyles = [
2234
+ "stop",
2235
+ "warning",
2236
+ "information",
2237
+ ];
2238
+ validation.alert = {
2239
+ style: alertStyles[currentDVal.errorStyle] || "stop",
2240
+ ...(currentDVal.errorTitle || currentDVal.error
2241
+ ? {
2242
+ message: {
2243
+ ...(currentDVal.errorTitle
2244
+ ? { title: currentDVal.errorTitle }
2245
+ : {}),
2246
+ ...(currentDVal.error
2247
+ ? { message: currentDVal.error }
2248
+ : {}),
2249
+ },
2250
+ }
2251
+ : {}),
2252
+ };
2253
+ }
2254
+ validations.push(validation);
2255
+ }
2256
+ }
2257
+ currentDVal = null;
2258
+ currentRanges = null;
2259
+ }
2260
+ }
2261
+ }
2262
+ catch (err) {
2263
+ // Skip sheet if parsing fails
2264
+ console.warn(`Failed to parse DV for sheet ${sheet.title}:`, err);
2265
+ }
2266
+ }
2267
+ return validations;
2268
+ }
2269
+ parseBrtName(payload, sheets) {
2270
+ const parsed = parseBrtNamePayload(payload, (ixti) => this.resolveSheetNameByXti(ixti));
2271
+ // Skip if parsing failed or hidden names
2272
+ if (!parsed || parsed.hidden) {
2273
+ return undefined;
2274
+ }
2275
+ // Try to parse the formula as a range reference
2276
+ const gridRange = getRangeFromAddressRef(parsed.formula);
2277
+ // Determine the sheet ID if this is a sheet-scoped name
2278
+ let sheetId;
2279
+ if (parsed.sheetIndex !== undefined && parsed.sheetIndex < sheets.length) {
2280
+ sheetId = sheets[parsed.sheetIndex].sheetId;
2281
+ }
2282
+ // Create the NamedRange object
2283
+ const namedRange = {
2284
+ namedRangeId: uuid(),
2285
+ name: parsed.name,
2286
+ };
2287
+ // Set either range or value depending on what we parsed
2288
+ if (gridRange) {
2289
+ // Convert GridRange to SheetRange by adding sheetId
2290
+ // Use the sheet-scoped sheetId if available, otherwise use the first sheet
2291
+ const rangeSheetId = sheetId ?? (sheets.length > 0 ? sheets[0].sheetId : 1);
2292
+ namedRange.range = {
2293
+ ...gridRange,
2294
+ sheetId: rangeSheetId,
2295
+ };
2296
+ }
2297
+ else if (parsed.formula) {
2298
+ // If we can't parse it as a range, store it as a formula value
2299
+ namedRange.value = parsed.formula;
2300
+ }
2301
+ return namedRange;
2302
+ }
2303
+ parseBrtCalcProp(payload) {
2304
+ const parsed = parseBrtCalcPropPayload(payload);
2305
+ if (!parsed) {
2306
+ return; // Skip if parsing failed
2307
+ }
2308
+ this.calcProp = {
2309
+ fullCalcOnLoad: parsed.fullCalcOnLoad,
2310
+ iterate: parsed.iterate,
2311
+ iterateCount: parsed.iterateCount,
2312
+ iterateDelta: parsed.iterateDelta,
2313
+ };
2314
+ }
2315
+ getNamedRanges() {
2316
+ return this.namedRanges;
2317
+ }
2318
+ requiresRecalc() {
2319
+ return this.calcProp.fullCalcOnLoad ?? false;
2320
+ }
2321
+ /**
2322
+ * `BrtWbProp.fDate1904` shifts every date serial by 1462 days
2323
+ * (Mac-origin workbooks). Defaults to the 1900 epoch when the record is
2324
+ * absent, matching Excel's default behavior for newly-created workbooks.
2325
+ */
2326
+ getUse1904Epoch() {
2327
+ return this.use1904;
2328
+ }
2329
+ getIterativeCalculationOptions() {
2330
+ if (!this.calcProp.iterate) {
2331
+ return undefined;
2332
+ }
2333
+ return {
2334
+ enabled: true,
2335
+ maxIterations: this.calcProp.iterateCount ?? 100,
2336
+ maxChange: this.calcProp.iterateDelta ?? 0.001,
2337
+ };
2338
+ }
2339
+ }