@cj-tech-master/excelts 1.6.3 → 2.0.0-canary.20251228013952.4f2c3c6

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 (400) hide show
  1. package/README.md +139 -24
  2. package/README_zh.md +140 -26
  3. package/dist/browser/excelts.esm.js +18468 -0
  4. package/dist/browser/excelts.esm.js.map +1 -0
  5. package/dist/browser/excelts.esm.min.js +125 -0
  6. package/dist/browser/excelts.iife.js +13107 -47146
  7. package/dist/browser/excelts.iife.js.map +1 -1
  8. package/dist/browser/excelts.iife.min.js +24 -106
  9. package/dist/cjs/csv/csv-core.js +701 -0
  10. package/dist/cjs/csv/csv-stream.js +646 -0
  11. package/dist/cjs/csv/csv.base.js +137 -0
  12. package/dist/cjs/csv/csv.browser.js +68 -0
  13. package/dist/cjs/csv/csv.js +218 -162
  14. package/dist/cjs/doc/anchor.js +2 -2
  15. package/dist/cjs/doc/cell.js +22 -22
  16. package/dist/cjs/doc/column.js +28 -7
  17. package/dist/cjs/doc/data-validations.js +3 -3
  18. package/dist/cjs/doc/defined-names.js +13 -13
  19. package/dist/cjs/doc/image.js +7 -7
  20. package/dist/cjs/doc/modelcontainer.js +2 -2
  21. package/dist/cjs/doc/note.js +2 -2
  22. package/dist/cjs/doc/pivot-table.js +5 -5
  23. package/dist/cjs/doc/range.js +11 -11
  24. package/dist/cjs/doc/row.js +16 -16
  25. package/dist/cjs/doc/table.js +5 -5
  26. package/dist/cjs/doc/workbook.base.js +211 -0
  27. package/dist/cjs/doc/workbook.browser.js +62 -0
  28. package/dist/cjs/doc/workbook.js +68 -179
  29. package/dist/cjs/doc/worksheet.js +45 -41
  30. package/dist/cjs/index.js +49 -32
  31. package/dist/cjs/stream/xlsx/hyperlink-reader.js +6 -6
  32. package/dist/cjs/stream/xlsx/sheet-comments-writer.js +12 -12
  33. package/dist/cjs/stream/xlsx/sheet-rels-writer.js +4 -4
  34. package/dist/cjs/stream/xlsx/workbook-reader.js +22 -22
  35. package/dist/cjs/stream/xlsx/workbook-writer.js +38 -38
  36. package/dist/cjs/stream/xlsx/worksheet-reader.js +17 -17
  37. package/dist/cjs/stream/xlsx/worksheet-writer.js +67 -60
  38. package/dist/cjs/utils/browser-buffer.js +75 -0
  39. package/dist/cjs/utils/cell-format.js +2 -2
  40. package/dist/cjs/utils/cell-matrix.js +5 -5
  41. package/dist/cjs/utils/datetime.js +499 -0
  42. package/dist/cjs/utils/encryptor.browser.js +240 -0
  43. package/dist/cjs/utils/parse-sax.js +1191 -13
  44. package/dist/cjs/utils/shared-formula.js +5 -5
  45. package/dist/cjs/utils/sheet-utils.js +13 -13
  46. package/dist/cjs/utils/stream-buf.browser.js +355 -0
  47. package/dist/cjs/utils/stream-buf.js +5 -5
  48. package/dist/cjs/utils/unzip/extract.js +11 -11
  49. package/dist/cjs/utils/unzip/index.js +21 -21
  50. package/dist/cjs/utils/unzip/parse-extra-field.js +3 -3
  51. package/dist/cjs/utils/unzip/parse.js +16 -16
  52. package/dist/cjs/utils/unzip/zip-parser.js +14 -3
  53. package/dist/cjs/utils/utils.base.js +161 -0
  54. package/dist/cjs/utils/utils.browser.js +89 -0
  55. package/dist/cjs/utils/utils.js +46 -154
  56. package/dist/cjs/utils/xml-stream.js +3 -3
  57. package/dist/cjs/utils/zip/compress.base.js +88 -0
  58. package/dist/cjs/utils/zip/compress.browser.js +127 -0
  59. package/dist/cjs/utils/zip/compress.js +18 -198
  60. package/dist/cjs/utils/zip/crc32.browser.js +88 -0
  61. package/dist/cjs/utils/zip/deflate-fallback.js +575 -0
  62. package/dist/cjs/utils/zip/index.js +17 -17
  63. package/dist/cjs/utils/zip/streaming-zip.js +264 -0
  64. package/dist/cjs/utils/zip/zip-builder.js +10 -10
  65. package/dist/cjs/utils/zip-stream.browser.js +135 -0
  66. package/dist/cjs/utils/zip-stream.js +4 -4
  67. package/dist/cjs/xlsx/xform/base-xform.js +4 -4
  68. package/dist/cjs/xlsx/xform/book/defined-name-xform.js +4 -4
  69. package/dist/cjs/xlsx/xform/book/sheet-xform.js +4 -4
  70. package/dist/cjs/xlsx/xform/book/workbook-calc-properties-xform.js +2 -2
  71. package/dist/cjs/xlsx/xform/book/workbook-pivot-cache-xform.js +2 -2
  72. package/dist/cjs/xlsx/xform/book/workbook-properties-xform.js +2 -2
  73. package/dist/cjs/xlsx/xform/book/workbook-view-xform.js +2 -2
  74. package/dist/cjs/xlsx/xform/book/workbook-xform.js +24 -24
  75. package/dist/cjs/xlsx/xform/comment/comment-xform.js +4 -4
  76. package/dist/cjs/xlsx/xform/comment/comments-xform.js +6 -6
  77. package/dist/cjs/xlsx/xform/comment/style/vml-position-xform.js +2 -2
  78. package/dist/cjs/xlsx/xform/comment/style/vml-protection-xform.js +2 -2
  79. package/dist/cjs/xlsx/xform/comment/vml-anchor-xform.js +2 -2
  80. package/dist/cjs/xlsx/xform/comment/vml-client-data-xform.js +10 -10
  81. package/dist/cjs/xlsx/xform/comment/vml-notes-xform.js +6 -6
  82. package/dist/cjs/xlsx/xform/comment/vml-shape-xform.js +6 -6
  83. package/dist/cjs/xlsx/xform/comment/vml-textbox-xform.js +2 -2
  84. package/dist/cjs/xlsx/xform/composite-xform.js +2 -2
  85. package/dist/cjs/xlsx/xform/core/app-heading-pairs-xform.js +2 -2
  86. package/dist/cjs/xlsx/xform/core/app-titles-of-parts-xform.js +2 -2
  87. package/dist/cjs/xlsx/xform/core/app-xform.js +11 -11
  88. package/dist/cjs/xlsx/xform/core/content-types-xform.js +4 -4
  89. package/dist/cjs/xlsx/xform/core/core-xform.js +23 -23
  90. package/dist/cjs/xlsx/xform/core/relationship-xform.js +2 -2
  91. package/dist/cjs/xlsx/xform/core/relationships-xform.js +6 -6
  92. package/dist/cjs/xlsx/xform/drawing/base-cell-anchor-xform.js +2 -2
  93. package/dist/cjs/xlsx/xform/drawing/blip-fill-xform.js +4 -4
  94. package/dist/cjs/xlsx/xform/drawing/blip-xform.js +2 -2
  95. package/dist/cjs/xlsx/xform/drawing/c-nv-pic-pr-xform.js +2 -2
  96. package/dist/cjs/xlsx/xform/drawing/c-nv-pr-xform.js +6 -6
  97. package/dist/cjs/xlsx/xform/drawing/cell-position-xform.js +7 -7
  98. package/dist/cjs/xlsx/xform/drawing/drawing-xform.js +10 -10
  99. package/dist/cjs/xlsx/xform/drawing/ext-lst-xform.js +2 -2
  100. package/dist/cjs/xlsx/xform/drawing/ext-xform.js +2 -2
  101. package/dist/cjs/xlsx/xform/drawing/hlink-click-xform.js +2 -2
  102. package/dist/cjs/xlsx/xform/drawing/nv-pic-pr-xform.js +6 -6
  103. package/dist/cjs/xlsx/xform/drawing/one-cell-anchor-xform.js +10 -10
  104. package/dist/cjs/xlsx/xform/drawing/pic-xform.js +9 -9
  105. package/dist/cjs/xlsx/xform/drawing/two-cell-anchor-xform.js +9 -9
  106. package/dist/cjs/xlsx/xform/list-xform.js +2 -2
  107. package/dist/cjs/xlsx/xform/pivot-table/cache-field-xform.js +5 -5
  108. package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +3 -3
  109. package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +10 -10
  110. package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-records-xform.js +9 -9
  111. package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +10 -11
  112. package/dist/cjs/xlsx/xform/sheet/auto-filter-xform.js +4 -4
  113. package/dist/cjs/xlsx/xform/sheet/cell-xform.js +65 -65
  114. package/dist/cjs/xlsx/xform/sheet/cf/cf-rule-xform.js +27 -27
  115. package/dist/cjs/xlsx/xform/sheet/cf/cfvo-xform.js +3 -3
  116. package/dist/cjs/xlsx/xform/sheet/cf/color-scale-xform.js +6 -6
  117. package/dist/cjs/xlsx/xform/sheet/cf/conditional-formatting-xform.js +6 -6
  118. package/dist/cjs/xlsx/xform/sheet/cf/conditional-formattings-xform.js +4 -4
  119. package/dist/cjs/xlsx/xform/sheet/cf/databar-xform.js +6 -6
  120. package/dist/cjs/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +5 -5
  121. package/dist/cjs/xlsx/xform/sheet/cf/formula-xform.js +2 -2
  122. package/dist/cjs/xlsx/xform/sheet/cf/icon-set-xform.js +11 -11
  123. package/dist/cjs/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +3 -3
  124. package/dist/cjs/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +11 -12
  125. package/dist/cjs/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +4 -4
  126. package/dist/cjs/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +8 -8
  127. package/dist/cjs/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +6 -6
  128. package/dist/cjs/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +26 -26
  129. package/dist/cjs/xlsx/xform/sheet/cf-ext/f-ext-xform.js +2 -2
  130. package/dist/cjs/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +14 -14
  131. package/dist/cjs/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +2 -2
  132. package/dist/cjs/xlsx/xform/sheet/col-breaks-xform.js +38 -0
  133. package/dist/cjs/xlsx/xform/sheet/col-xform.js +6 -6
  134. package/dist/cjs/xlsx/xform/sheet/data-validations-xform.js +18 -18
  135. package/dist/cjs/xlsx/xform/sheet/dimension-xform.js +2 -2
  136. package/dist/cjs/xlsx/xform/sheet/drawing-xform.js +2 -2
  137. package/dist/cjs/xlsx/xform/sheet/ext-lst-xform.js +5 -5
  138. package/dist/cjs/xlsx/xform/sheet/header-footer-xform.js +2 -2
  139. package/dist/cjs/xlsx/xform/sheet/hyperlink-xform.js +2 -2
  140. package/dist/cjs/xlsx/xform/sheet/merge-cell-xform.js +2 -2
  141. package/dist/cjs/xlsx/xform/sheet/merges.js +8 -8
  142. package/dist/cjs/xlsx/xform/sheet/outline-properties-xform.js +2 -2
  143. package/dist/cjs/xlsx/xform/sheet/page-breaks-xform.js +15 -3
  144. package/dist/cjs/xlsx/xform/sheet/page-margins-xform.js +2 -2
  145. package/dist/cjs/xlsx/xform/sheet/page-setup-properties-xform.js +2 -2
  146. package/dist/cjs/xlsx/xform/sheet/page-setup-xform.js +2 -2
  147. package/dist/cjs/xlsx/xform/sheet/picture-xform.js +2 -2
  148. package/dist/cjs/xlsx/xform/sheet/print-options-xform.js +2 -2
  149. package/dist/cjs/xlsx/xform/sheet/row-breaks-xform.js +15 -17
  150. package/dist/cjs/xlsx/xform/sheet/row-xform.js +11 -11
  151. package/dist/cjs/xlsx/xform/sheet/sheet-format-properties-xform.js +2 -2
  152. package/dist/cjs/xlsx/xform/sheet/sheet-properties-xform.js +8 -8
  153. package/dist/cjs/xlsx/xform/sheet/sheet-protection-xform.js +2 -2
  154. package/dist/cjs/xlsx/xform/sheet/sheet-view-xform.js +4 -4
  155. package/dist/cjs/xlsx/xform/sheet/table-part-xform.js +2 -2
  156. package/dist/cjs/xlsx/xform/sheet/worksheet-xform.js +75 -70
  157. package/dist/cjs/xlsx/xform/simple/boolean-xform.js +2 -2
  158. package/dist/cjs/xlsx/xform/simple/date-xform.js +2 -2
  159. package/dist/cjs/xlsx/xform/simple/float-xform.js +2 -2
  160. package/dist/cjs/xlsx/xform/simple/integer-xform.js +2 -2
  161. package/dist/cjs/xlsx/xform/simple/string-xform.js +2 -2
  162. package/dist/cjs/xlsx/xform/static-xform.js +4 -4
  163. package/dist/cjs/xlsx/xform/strings/phonetic-text-xform.js +6 -6
  164. package/dist/cjs/xlsx/xform/strings/rich-text-xform.js +6 -6
  165. package/dist/cjs/xlsx/xform/strings/shared-string-xform.js +8 -8
  166. package/dist/cjs/xlsx/xform/strings/shared-strings-xform.js +6 -6
  167. package/dist/cjs/xlsx/xform/strings/text-xform.js +2 -2
  168. package/dist/cjs/xlsx/xform/style/alignment-xform.js +8 -8
  169. package/dist/cjs/xlsx/xform/style/border-xform.js +8 -8
  170. package/dist/cjs/xlsx/xform/style/color-xform.js +2 -2
  171. package/dist/cjs/xlsx/xform/style/dxf-xform.js +14 -14
  172. package/dist/cjs/xlsx/xform/style/fill-xform.js +9 -9
  173. package/dist/cjs/xlsx/xform/style/font-xform.js +22 -22
  174. package/dist/cjs/xlsx/xform/style/numfmt-xform.js +5 -5
  175. package/dist/cjs/xlsx/xform/style/protection-xform.js +2 -2
  176. package/dist/cjs/xlsx/xform/style/style-xform.js +6 -6
  177. package/dist/cjs/xlsx/xform/style/styles-xform.js +39 -39
  178. package/dist/cjs/xlsx/xform/style/underline-xform.js +2 -2
  179. package/dist/cjs/xlsx/xform/table/auto-filter-xform.js +4 -4
  180. package/dist/cjs/xlsx/xform/table/custom-filter-xform.js +2 -2
  181. package/dist/cjs/xlsx/xform/table/filter-column-xform.js +9 -9
  182. package/dist/cjs/xlsx/xform/table/filter-xform.js +2 -2
  183. package/dist/cjs/xlsx/xform/table/table-column-xform.js +2 -2
  184. package/dist/cjs/xlsx/xform/table/table-style-info-xform.js +2 -2
  185. package/dist/cjs/xlsx/xform/table/table-xform.js +12 -12
  186. package/dist/cjs/xlsx/xlsx.base.js +742 -0
  187. package/dist/cjs/xlsx/xlsx.browser.js +162 -0
  188. package/dist/cjs/xlsx/xlsx.js +118 -892
  189. package/dist/esm/csv/csv-core.js +694 -0
  190. package/dist/esm/csv/csv-stream.js +638 -0
  191. package/dist/esm/csv/csv.base.js +127 -0
  192. package/dist/esm/csv/csv.browser.js +65 -0
  193. package/dist/esm/csv/csv.js +181 -159
  194. package/dist/esm/doc/column.js +21 -0
  195. package/dist/esm/doc/workbook.base.js +207 -0
  196. package/dist/esm/doc/workbook.browser.js +59 -0
  197. package/dist/esm/doc/workbook.js +64 -175
  198. package/dist/esm/doc/worksheet.js +4 -0
  199. package/dist/esm/index.browser.js +33 -1
  200. package/dist/esm/index.js +23 -8
  201. package/dist/esm/local.js +0 -1
  202. package/dist/esm/stream/xlsx/workbook-writer.js +1 -1
  203. package/dist/esm/stream/xlsx/worksheet-writer.js +8 -1
  204. package/dist/esm/utils/browser-buffer.js +67 -0
  205. package/dist/esm/utils/datetime.js +493 -0
  206. package/dist/esm/utils/encryptor.browser.js +237 -0
  207. package/dist/esm/utils/parse-sax.js +1188 -12
  208. package/dist/esm/utils/stream-buf.browser.js +352 -0
  209. package/dist/esm/utils/unzip/zip-parser.js +11 -0
  210. package/dist/esm/utils/utils.base.js +142 -0
  211. package/dist/esm/utils/utils.browser.js +68 -0
  212. package/dist/esm/utils/utils.js +15 -123
  213. package/dist/esm/utils/zip/compress.base.js +83 -0
  214. package/dist/esm/utils/zip/compress.browser.js +121 -0
  215. package/dist/esm/utils/zip/compress.js +16 -164
  216. package/dist/esm/utils/zip/crc32.browser.js +82 -0
  217. package/dist/esm/utils/zip/deflate-fallback.js +570 -0
  218. package/dist/esm/utils/zip/streaming-zip.js +259 -0
  219. package/dist/esm/utils/zip-stream.browser.js +132 -0
  220. package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +2 -3
  221. package/dist/esm/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +2 -3
  222. package/dist/esm/xlsx/xform/sheet/col-breaks-xform.js +35 -0
  223. package/dist/esm/xlsx/xform/sheet/page-breaks-xform.js +13 -1
  224. package/dist/esm/xlsx/xform/sheet/row-breaks-xform.js +11 -13
  225. package/dist/esm/xlsx/xform/sheet/worksheet-xform.js +7 -2
  226. package/dist/esm/xlsx/xlsx.base.js +739 -0
  227. package/dist/esm/xlsx/xlsx.browser.js +159 -0
  228. package/dist/esm/xlsx/xlsx.js +114 -888
  229. package/dist/types/csv/csv-core.d.ts +207 -0
  230. package/dist/types/csv/csv-stream.d.ts +114 -0
  231. package/dist/types/csv/csv.base.d.ts +62 -0
  232. package/dist/types/csv/csv.browser.d.ts +33 -0
  233. package/dist/types/csv/csv.d.ts +97 -71
  234. package/dist/types/doc/anchor.d.ts +1 -1
  235. package/dist/types/doc/cell.d.ts +7 -7
  236. package/dist/types/doc/column.d.ts +9 -3
  237. package/dist/types/doc/defined-names.d.ts +4 -4
  238. package/dist/types/doc/image.d.ts +2 -2
  239. package/dist/types/doc/modelcontainer.d.ts +1 -1
  240. package/dist/types/doc/pivot-table.d.ts +1 -1
  241. package/dist/types/doc/range.d.ts +1 -1
  242. package/dist/types/doc/row.d.ts +3 -3
  243. package/dist/types/doc/table.d.ts +2 -2
  244. package/dist/types/doc/workbook.base.d.ts +111 -0
  245. package/dist/types/doc/workbook.browser.d.ts +38 -0
  246. package/dist/types/doc/workbook.d.ts +62 -92
  247. package/dist/types/doc/worksheet.d.ts +12 -10
  248. package/dist/types/index.browser.d.ts +19 -5
  249. package/dist/types/index.d.ts +24 -23
  250. package/dist/types/local.d.ts +0 -1
  251. package/dist/types/stream/xlsx/hyperlink-reader.d.ts +1 -1
  252. package/dist/types/stream/xlsx/workbook-reader.d.ts +4 -4
  253. package/dist/types/stream/xlsx/workbook-writer.d.ts +7 -7
  254. package/dist/types/stream/xlsx/worksheet-reader.d.ts +5 -5
  255. package/dist/types/stream/xlsx/worksheet-writer.d.ts +11 -9
  256. package/dist/types/types.d.ts +6 -0
  257. package/dist/types/utils/browser-buffer.d.ts +28 -0
  258. package/dist/types/utils/col-cache.d.ts +1 -1
  259. package/dist/types/utils/datetime.d.ts +56 -0
  260. package/dist/types/utils/encryptor.browser.d.ts +28 -0
  261. package/dist/types/utils/parse-sax.d.ts +108 -1
  262. package/dist/types/utils/sheet-utils.d.ts +3 -3
  263. package/dist/types/utils/stream-buf.browser.d.ts +41 -0
  264. package/dist/types/utils/unzip/extract.d.ts +6 -6
  265. package/dist/types/utils/unzip/index.d.ts +8 -8
  266. package/dist/types/utils/unzip/parse.d.ts +3 -3
  267. package/dist/types/utils/unzip/zip-parser.d.ts +5 -0
  268. package/dist/types/utils/utils.base.d.ts +29 -0
  269. package/dist/types/utils/utils.browser.d.ts +29 -0
  270. package/dist/types/utils/utils.d.ts +6 -25
  271. package/dist/types/utils/zip/compress.base.d.ts +45 -0
  272. package/dist/types/utils/zip/compress.browser.d.ts +63 -0
  273. package/dist/types/utils/zip/compress.d.ts +13 -45
  274. package/dist/types/utils/zip/crc32.browser.d.ts +52 -0
  275. package/dist/types/utils/zip/deflate-fallback.d.ts +39 -0
  276. package/dist/types/utils/zip/index.d.ts +5 -5
  277. package/dist/types/utils/zip/streaming-zip.d.ts +96 -0
  278. package/dist/types/utils/zip/zip-builder.d.ts +1 -1
  279. package/dist/types/utils/zip-stream.browser.d.ts +39 -0
  280. package/dist/types/xlsx/xform/base-xform.d.ts +1 -1
  281. package/dist/types/xlsx/xform/book/defined-name-xform.d.ts +1 -1
  282. package/dist/types/xlsx/xform/book/sheet-xform.d.ts +1 -1
  283. package/dist/types/xlsx/xform/book/workbook-calc-properties-xform.d.ts +1 -1
  284. package/dist/types/xlsx/xform/book/workbook-pivot-cache-xform.d.ts +1 -1
  285. package/dist/types/xlsx/xform/book/workbook-properties-xform.d.ts +1 -1
  286. package/dist/types/xlsx/xform/book/workbook-view-xform.d.ts +1 -1
  287. package/dist/types/xlsx/xform/book/workbook-xform.d.ts +2 -2
  288. package/dist/types/xlsx/xform/comment/comment-xform.d.ts +2 -2
  289. package/dist/types/xlsx/xform/comment/comments-xform.d.ts +2 -2
  290. package/dist/types/xlsx/xform/comment/style/vml-position-xform.d.ts +1 -1
  291. package/dist/types/xlsx/xform/comment/style/vml-protection-xform.d.ts +1 -1
  292. package/dist/types/xlsx/xform/comment/vml-anchor-xform.d.ts +1 -1
  293. package/dist/types/xlsx/xform/comment/vml-client-data-xform.d.ts +1 -1
  294. package/dist/types/xlsx/xform/comment/vml-notes-xform.d.ts +1 -1
  295. package/dist/types/xlsx/xform/comment/vml-shape-xform.d.ts +1 -1
  296. package/dist/types/xlsx/xform/comment/vml-textbox-xform.d.ts +1 -1
  297. package/dist/types/xlsx/xform/composite-xform.d.ts +1 -1
  298. package/dist/types/xlsx/xform/core/app-heading-pairs-xform.d.ts +1 -1
  299. package/dist/types/xlsx/xform/core/app-titles-of-parts-xform.d.ts +1 -1
  300. package/dist/types/xlsx/xform/core/app-xform.d.ts +1 -1
  301. package/dist/types/xlsx/xform/core/content-types-xform.d.ts +1 -1
  302. package/dist/types/xlsx/xform/core/core-xform.d.ts +1 -1
  303. package/dist/types/xlsx/xform/core/relationship-xform.d.ts +1 -1
  304. package/dist/types/xlsx/xform/core/relationships-xform.d.ts +1 -1
  305. package/dist/types/xlsx/xform/drawing/base-cell-anchor-xform.d.ts +1 -1
  306. package/dist/types/xlsx/xform/drawing/blip-fill-xform.d.ts +2 -2
  307. package/dist/types/xlsx/xform/drawing/blip-xform.d.ts +1 -1
  308. package/dist/types/xlsx/xform/drawing/c-nv-pic-pr-xform.d.ts +1 -1
  309. package/dist/types/xlsx/xform/drawing/c-nv-pr-xform.d.ts +1 -1
  310. package/dist/types/xlsx/xform/drawing/cell-position-xform.d.ts +2 -2
  311. package/dist/types/xlsx/xform/drawing/drawing-xform.d.ts +1 -1
  312. package/dist/types/xlsx/xform/drawing/ext-lst-xform.d.ts +1 -1
  313. package/dist/types/xlsx/xform/drawing/ext-xform.d.ts +1 -1
  314. package/dist/types/xlsx/xform/drawing/hlink-click-xform.d.ts +1 -1
  315. package/dist/types/xlsx/xform/drawing/nv-pic-pr-xform.d.ts +1 -1
  316. package/dist/types/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -1
  317. package/dist/types/xlsx/xform/drawing/pic-xform.d.ts +1 -1
  318. package/dist/types/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +1 -1
  319. package/dist/types/xlsx/xform/list-xform.d.ts +1 -1
  320. package/dist/types/xlsx/xform/pivot-table/cache-field-xform.d.ts +1 -1
  321. package/dist/types/xlsx/xform/pivot-table/pivot-cache-definition-xform.d.ts +3 -3
  322. package/dist/types/xlsx/xform/pivot-table/pivot-cache-records-xform.d.ts +2 -2
  323. package/dist/types/xlsx/xform/pivot-table/pivot-table-xform.d.ts +1 -1
  324. package/dist/types/xlsx/xform/sheet/auto-filter-xform.d.ts +1 -1
  325. package/dist/types/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  326. package/dist/types/xlsx/xform/sheet/cf/cf-rule-xform.d.ts +6 -6
  327. package/dist/types/xlsx/xform/sheet/cf/cfvo-xform.d.ts +1 -1
  328. package/dist/types/xlsx/xform/sheet/cf/color-scale-xform.d.ts +3 -3
  329. package/dist/types/xlsx/xform/sheet/cf/conditional-formatting-xform.d.ts +1 -1
  330. package/dist/types/xlsx/xform/sheet/cf/conditional-formattings-xform.d.ts +2 -2
  331. package/dist/types/xlsx/xform/sheet/cf/databar-xform.d.ts +3 -3
  332. package/dist/types/xlsx/xform/sheet/cf/ext-lst-ref-xform.d.ts +1 -1
  333. package/dist/types/xlsx/xform/sheet/cf/formula-xform.d.ts +1 -1
  334. package/dist/types/xlsx/xform/sheet/cf/icon-set-xform.d.ts +2 -2
  335. package/dist/types/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.d.ts +1 -1
  336. package/dist/types/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.d.ts +3 -3
  337. package/dist/types/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.d.ts +2 -2
  338. package/dist/types/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.d.ts +3 -3
  339. package/dist/types/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.d.ts +2 -2
  340. package/dist/types/xlsx/xform/sheet/cf-ext/databar-ext-xform.d.ts +3 -3
  341. package/dist/types/xlsx/xform/sheet/cf-ext/f-ext-xform.d.ts +1 -1
  342. package/dist/types/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.d.ts +3 -3
  343. package/dist/types/xlsx/xform/sheet/cf-ext/sqref-ext-xform.d.ts +1 -1
  344. package/dist/types/xlsx/xform/sheet/col-breaks-xform.d.ts +16 -0
  345. package/dist/types/xlsx/xform/sheet/col-xform.d.ts +1 -1
  346. package/dist/types/xlsx/xform/sheet/data-validations-xform.d.ts +1 -1
  347. package/dist/types/xlsx/xform/sheet/dimension-xform.d.ts +1 -1
  348. package/dist/types/xlsx/xform/sheet/drawing-xform.d.ts +1 -1
  349. package/dist/types/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -1
  350. package/dist/types/xlsx/xform/sheet/header-footer-xform.d.ts +1 -1
  351. package/dist/types/xlsx/xform/sheet/hyperlink-xform.d.ts +1 -1
  352. package/dist/types/xlsx/xform/sheet/merge-cell-xform.d.ts +1 -1
  353. package/dist/types/xlsx/xform/sheet/outline-properties-xform.d.ts +1 -1
  354. package/dist/types/xlsx/xform/sheet/page-breaks-xform.d.ts +5 -1
  355. package/dist/types/xlsx/xform/sheet/page-margins-xform.d.ts +1 -1
  356. package/dist/types/xlsx/xform/sheet/page-setup-properties-xform.d.ts +1 -1
  357. package/dist/types/xlsx/xform/sheet/page-setup-xform.d.ts +1 -1
  358. package/dist/types/xlsx/xform/sheet/picture-xform.d.ts +1 -1
  359. package/dist/types/xlsx/xform/sheet/print-options-xform.d.ts +1 -1
  360. package/dist/types/xlsx/xform/sheet/row-breaks-xform.d.ts +5 -1
  361. package/dist/types/xlsx/xform/sheet/row-xform.d.ts +1 -1
  362. package/dist/types/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -1
  363. package/dist/types/xlsx/xform/sheet/sheet-properties-xform.d.ts +1 -1
  364. package/dist/types/xlsx/xform/sheet/sheet-protection-xform.d.ts +1 -1
  365. package/dist/types/xlsx/xform/sheet/sheet-view-xform.d.ts +1 -1
  366. package/dist/types/xlsx/xform/sheet/table-part-xform.d.ts +1 -1
  367. package/dist/types/xlsx/xform/sheet/worksheet-xform.d.ts +1 -1
  368. package/dist/types/xlsx/xform/simple/boolean-xform.d.ts +1 -1
  369. package/dist/types/xlsx/xform/simple/date-xform.d.ts +1 -1
  370. package/dist/types/xlsx/xform/simple/float-xform.d.ts +1 -1
  371. package/dist/types/xlsx/xform/simple/integer-xform.d.ts +1 -1
  372. package/dist/types/xlsx/xform/simple/string-xform.d.ts +1 -1
  373. package/dist/types/xlsx/xform/static-xform.d.ts +1 -1
  374. package/dist/types/xlsx/xform/strings/phonetic-text-xform.d.ts +1 -1
  375. package/dist/types/xlsx/xform/strings/rich-text-xform.d.ts +3 -3
  376. package/dist/types/xlsx/xform/strings/shared-string-xform.d.ts +1 -1
  377. package/dist/types/xlsx/xform/strings/shared-strings-xform.d.ts +2 -2
  378. package/dist/types/xlsx/xform/strings/text-xform.d.ts +1 -1
  379. package/dist/types/xlsx/xform/style/alignment-xform.d.ts +1 -1
  380. package/dist/types/xlsx/xform/style/border-xform.d.ts +2 -2
  381. package/dist/types/xlsx/xform/style/color-xform.d.ts +1 -1
  382. package/dist/types/xlsx/xform/style/dxf-xform.d.ts +1 -1
  383. package/dist/types/xlsx/xform/style/fill-xform.d.ts +2 -2
  384. package/dist/types/xlsx/xform/style/font-xform.d.ts +1 -1
  385. package/dist/types/xlsx/xform/style/numfmt-xform.d.ts +1 -1
  386. package/dist/types/xlsx/xform/style/protection-xform.d.ts +1 -1
  387. package/dist/types/xlsx/xform/style/style-xform.d.ts +3 -3
  388. package/dist/types/xlsx/xform/style/styles-xform.d.ts +2 -2
  389. package/dist/types/xlsx/xform/style/underline-xform.d.ts +1 -1
  390. package/dist/types/xlsx/xform/table/auto-filter-xform.d.ts +2 -2
  391. package/dist/types/xlsx/xform/table/custom-filter-xform.d.ts +1 -1
  392. package/dist/types/xlsx/xform/table/filter-column-xform.d.ts +2 -2
  393. package/dist/types/xlsx/xform/table/filter-xform.d.ts +1 -1
  394. package/dist/types/xlsx/xform/table/table-column-xform.d.ts +1 -1
  395. package/dist/types/xlsx/xform/table/table-style-info-xform.d.ts +1 -1
  396. package/dist/types/xlsx/xform/table/table-xform.d.ts +1 -1
  397. package/dist/types/xlsx/xlsx.base.d.ts +134 -0
  398. package/dist/types/xlsx/xlsx.browser.d.ts +31 -0
  399. package/dist/types/xlsx/xlsx.d.ts +20 -80
  400. package/package.json +16 -39
@@ -1,27 +1,21 @@
1
+ /**
2
+ * XLSX - Node.js version with full functionality
3
+ *
4
+ * Extends XLSXBase with:
5
+ * - readFile: Read from file path
6
+ * - writeFile: Write to file path
7
+ * - read: Read from stream
8
+ * - write: Write to stream
9
+ * - load: Load from buffer
10
+ * - writeBuffer: Write to buffer
11
+ */
1
12
  import fs from "fs";
2
- import { Unzip, UnzipInflate } from "fflate";
3
13
  import { PassThrough } from "stream";
14
+ import { ZipParser } from "../utils/unzip/zip-parser.js";
4
15
  import { ZipWriter } from "../utils/zip-stream.js";
5
16
  import { StreamBuf } from "../utils/stream-buf.js";
6
17
  import { fileExists, bufferToString } from "../utils/utils.js";
7
- import { XmlStream } from "../utils/xml-stream.js";
8
- import { StylesXform } from "./xform/style/styles-xform.js";
9
- import { CoreXform } from "./xform/core/core-xform.js";
10
- import { SharedStringsXform } from "./xform/strings/shared-strings-xform.js";
11
- import { RelationshipsXform } from "./xform/core/relationships-xform.js";
12
- import { ContentTypesXform } from "./xform/core/content-types-xform.js";
13
- import { AppXform } from "./xform/core/app-xform.js";
14
- import { WorkbookXform } from "./xform/book/workbook-xform.js";
15
- import { WorkSheetXform } from "./xform/sheet/worksheet-xform.js";
16
- import { DrawingXform } from "./xform/drawing/drawing-xform.js";
17
- import { TableXform } from "./xform/table/table-xform.js";
18
- import { PivotCacheRecordsXform } from "./xform/pivot-table/pivot-cache-records-xform.js";
19
- import { PivotCacheDefinitionXform } from "./xform/pivot-table/pivot-cache-definition-xform.js";
20
- import { PivotTableXform } from "./xform/pivot-table/pivot-table-xform.js";
21
- import { CommentsXform } from "./xform/comment/comments-xform.js";
22
- import { VmlNotesXform } from "./xform/comment/vml-notes-xform.js";
23
- import { theme1Xml } from "./xml/theme1.js";
24
- import { RelType } from "./rel-type.js";
18
+ import { XLSXBase } from "./xlsx.base.js";
25
19
  function fsReadFileAsync(filename, options) {
26
20
  return new Promise((resolve, reject) => {
27
21
  fs.readFile(filename, options, (error, data) => {
@@ -34,14 +28,32 @@ function fsReadFileAsync(filename, options) {
34
28
  });
35
29
  });
36
30
  }
37
- class XLSX {
38
- constructor(workbook) {
39
- this.workbook = workbook;
40
- }
41
- // ===============================================================================
42
- // Workbook
43
- // =========================================================================
44
- // Read
31
+ class XLSX extends XLSXBase {
32
+ // ===========================================================================
33
+ // Abstract method implementations
34
+ // ===========================================================================
35
+ createStreamBuf() {
36
+ return new StreamBuf();
37
+ }
38
+ createBinaryStream(data) {
39
+ const stream = new PassThrough();
40
+ stream.end(Buffer.from(data));
41
+ return stream;
42
+ }
43
+ createTextStream(content) {
44
+ const stream = new PassThrough({
45
+ readableObjectMode: true,
46
+ writableObjectMode: true
47
+ });
48
+ stream.end(content);
49
+ return stream;
50
+ }
51
+ bufferToString(data) {
52
+ return bufferToString(data);
53
+ }
54
+ // ===========================================================================
55
+ // Node.js specific: File operations
56
+ // ===========================================================================
45
57
  async readFile(filename, options) {
46
58
  if (!(await fileExists(filename))) {
47
59
  throw new Error(`File not found: ${filename}`);
@@ -57,425 +69,102 @@ class XLSX {
57
69
  throw error;
58
70
  }
59
71
  }
60
- parseRels(stream) {
61
- const xform = new RelationshipsXform();
62
- return xform.parseStream(stream);
63
- }
64
- parseWorkbook(stream) {
65
- const xform = new WorkbookXform();
66
- return xform.parseStream(stream);
67
- }
68
- parseSharedStrings(stream) {
69
- const xform = new SharedStringsXform();
70
- return xform.parseStream(stream);
71
- }
72
- reconcile(model, options) {
73
- const workbookXform = new WorkbookXform();
74
- const worksheetXform = new WorkSheetXform(options);
75
- const drawingXform = new DrawingXform();
76
- const tableXform = new TableXform();
77
- workbookXform.reconcile(model);
78
- // reconcile drawings with their rels
79
- const drawingOptions = {
80
- media: model.media,
81
- mediaIndex: model.mediaIndex
82
- };
83
- Object.keys(model.drawings).forEach(name => {
84
- const drawing = model.drawings[name];
85
- const drawingRel = model.drawingRels[name];
86
- if (drawingRel) {
87
- drawingOptions.rels = drawingRel.reduce((o, rel) => {
88
- o[rel.Id] = rel;
89
- return o;
90
- }, {});
91
- (drawing.anchors || []).forEach((anchor) => {
92
- const hyperlinks = anchor.picture && anchor.picture.hyperlinks;
93
- if (hyperlinks && drawingOptions.rels[hyperlinks.rId]) {
94
- hyperlinks.hyperlink = drawingOptions.rels[hyperlinks.rId].Target;
95
- delete hyperlinks.rId;
96
- }
97
- });
98
- drawingXform.reconcile(drawing, drawingOptions);
99
- }
100
- });
101
- // reconcile tables with the default styles
102
- const tableOptions = {
103
- styles: model.styles
104
- };
105
- Object.values(model.tables).forEach((table) => {
106
- tableXform.reconcile(table, tableOptions);
107
- });
108
- // Reconcile pivot tables - link pivot tables to worksheets and cache data
109
- this._reconcilePivotTables(model);
110
- const sheetOptions = {
111
- styles: model.styles,
112
- sharedStrings: model.sharedStrings,
113
- media: model.media,
114
- mediaIndex: model.mediaIndex,
115
- date1904: model.properties && model.properties.date1904,
116
- drawings: model.drawings,
117
- comments: model.comments,
118
- tables: model.tables,
119
- vmlDrawings: model.vmlDrawings,
120
- pivotTables: model.pivotTablesIndexed
121
- };
122
- model.worksheets.forEach((worksheet) => {
123
- worksheet.relationships = model.worksheetRels[worksheet.sheetNo];
124
- worksheetXform.reconcile(worksheet, sheetOptions);
125
- });
126
- // delete unnecessary parts
127
- delete model.worksheetHash;
128
- delete model.worksheetRels;
129
- delete model.globalRels;
130
- delete model.sharedStrings;
131
- delete model.workbookRels;
132
- delete model.sheetDefs;
133
- delete model.styles;
134
- delete model.mediaIndex;
135
- delete model.drawings;
136
- delete model.drawingRels;
137
- delete model.vmlDrawings;
138
- // Clean up raw pivot table data after reconciliation
139
- delete model.pivotTableRels;
140
- delete model.pivotCacheDefinitionRels;
141
- }
142
- /**
143
- * Reconcile pivot tables by linking them to worksheets and their cache data.
144
- * This builds a complete pivot table model ready for writing.
145
- */
146
- _reconcilePivotTables(model) {
147
- // Skip if no pivot tables were loaded (object is empty or undefined)
148
- const rawPivotTables = model.pivotTables || {};
149
- if (typeof rawPivotTables !== "object" || Object.keys(rawPivotTables).length === 0) {
150
- // Ensure pivotTables is an empty array (not an object)
151
- model.pivotTables = [];
152
- // Also create an empty indexed object for worksheet reconciliation
153
- model.pivotTablesIndexed = {};
154
- return;
155
- }
156
- // Build mapping from definition name to cacheId
157
- const definitionToCacheId = this._buildDefinitionToCacheIdMap(model);
158
- // Build a map of cache IDs to their definitions and records
159
- const cacheMap = new Map();
160
- // Process cache definitions
161
- Object.entries(model.pivotCacheDefinitions || {}).forEach(([name, definition]) => {
162
- // Get the cacheId from the mapping (derived from workbook.xml pivotCaches)
163
- const cacheId = definitionToCacheId.get(name);
164
- if (cacheId !== undefined) {
165
- const recordsName = name.replace("Definition", "Records");
166
- cacheMap.set(cacheId, {
167
- definition,
168
- records: model.pivotCacheRecords?.[recordsName],
169
- definitionName: name
170
- });
171
- }
172
- });
173
- // Process pivot tables and link to worksheets
174
- const loadedPivotTables = [];
175
- // Create indexed object for worksheet reconciliation (keyed by relative path)
176
- const pivotTablesIndexed = {};
177
- Object.entries(rawPivotTables).forEach(([pivotName, pivotTable]) => {
178
- const pt = pivotTable;
179
- const tableNumber = this._extractTableNumber(pivotName);
180
- // Get cache data for this pivot table
181
- const cacheData = cacheMap.get(pt.cacheId);
182
- // Build complete pivot table model
183
- const completePivotTable = {
184
- // Core model data
185
- ...pt,
186
- tableNumber,
187
- // Link to cache data
188
- cacheDefinition: cacheData?.definition,
189
- cacheRecords: cacheData?.records,
190
- // Reconstruct cacheFields from definition for compatibility
191
- cacheFields: cacheData?.definition?.cacheFields || [],
192
- // Determine rows, columns, values from parsed data
193
- rows: pt.rowFields.filter(f => f >= 0),
194
- columns: pt.colFields.filter(f => f >= 0 && f !== -2),
195
- values: pt.dataFields.map(df => df.fld),
196
- // Determine metric from dataFields
197
- metric: this._determineMetric(pt.dataFields),
198
- // Preserve formatting options
199
- applyWidthHeightFormats: pt.applyWidthHeightFormats || "0"
200
- };
201
- loadedPivotTables.push(completePivotTable);
202
- // Index by relative path for worksheet reconciliation
203
- pivotTablesIndexed[`../pivotTables/${pivotName}.xml`] = completePivotTable;
204
- });
205
- // Sort by table number to maintain order
206
- loadedPivotTables.sort((a, b) => a.tableNumber - b.tableNumber);
207
- // Replace pivotTables object with the processed array
208
- // This is what the Workbook model setter expects
209
- model.pivotTables = loadedPivotTables;
210
- // Also keep indexed version for worksheet reconciliation
211
- model.pivotTablesIndexed = pivotTablesIndexed;
212
- // Also keep as loadedPivotTables for backward compatibility
213
- model.loadedPivotTables = loadedPivotTables;
214
- }
215
- /**
216
- * Extract table number from pivot table name (e.g., "pivotTable1" -> 1)
217
- */
218
- _extractTableNumber(name) {
219
- const match = name.match(/pivotTable(\d+)/);
220
- return match ? parseInt(match[1], 10) : 1;
221
- }
222
- /**
223
- * Build a mapping from rId to cacheId using pivotCaches from workbook.xml
224
- * and workbookRels to determine which definition file corresponds to which cacheId
225
- */
226
- _buildCacheIdMap(model) {
227
- const rIdToCacheId = new Map();
228
- // pivotCaches from workbook.xml contains {cacheId, rId} mappings
229
- const pivotCaches = model.pivotCaches || [];
230
- for (const cache of pivotCaches) {
231
- if (cache.cacheId && cache.rId) {
232
- rIdToCacheId.set(cache.rId, parseInt(cache.cacheId, 10));
233
- }
234
- }
235
- return rIdToCacheId;
236
- }
237
- /**
238
- * Build a mapping from definition name to cacheId
239
- */
240
- _buildDefinitionToCacheIdMap(model) {
241
- const definitionToCacheId = new Map();
242
- const rIdToCacheId = this._buildCacheIdMap(model);
243
- const workbookRels = model.workbookRels || [];
244
- // Map workbook rels to get definitionNumber -> cacheId mapping
245
- for (const rel of workbookRels) {
246
- if (rel.Type === XLSX.RelType.PivotCacheDefinition && rel.Target) {
247
- // Extract definition number from target (e.g., "pivotCache/pivotCacheDefinition1.xml" -> 1)
248
- const match = rel.Target.match(/pivotCacheDefinition(\d+)\.xml/);
249
- if (match) {
250
- const defName = `pivotCacheDefinition${match[1]}`;
251
- const cacheId = rIdToCacheId.get(rel.Id);
252
- if (cacheId !== undefined) {
253
- definitionToCacheId.set(defName, cacheId);
254
- }
255
- }
256
- }
257
- }
258
- return definitionToCacheId;
259
- }
260
- /**
261
- * Determine the aggregation metric from dataFields
262
- */
263
- _determineMetric(dataFields) {
264
- if (dataFields.length > 0 && dataFields[0].subtotal === "count") {
265
- return "count";
266
- }
267
- return "sum";
268
- }
269
- async _processWorksheetEntry(stream, model, sheetNo, options, path) {
270
- const xform = new WorkSheetXform(options);
271
- const worksheet = await xform.parseStream(stream);
272
- if (!worksheet) {
273
- throw new Error(`Failed to parse worksheet ${path}`);
274
- }
275
- worksheet.sheetNo = sheetNo;
276
- model.worksheetHash[path] = worksheet;
277
- model.worksheets.push(worksheet);
278
- }
279
- async _processCommentEntry(stream, model, name) {
280
- const xform = new CommentsXform();
281
- const comments = await xform.parseStream(stream);
282
- model.comments[`../${name}.xml`] = comments;
283
- }
284
- async _processTableEntry(stream, model, name) {
285
- const xform = new TableXform();
286
- const table = await xform.parseStream(stream);
287
- model.tables[`../tables/${name}.xml`] = table;
288
- }
289
- async _processWorksheetRelsEntry(stream, model, sheetNo) {
290
- const xform = new RelationshipsXform();
291
- const relationships = await xform.parseStream(stream);
292
- model.worksheetRels[sheetNo] = relationships;
293
- }
294
- async _processMediaEntry(stream, model, filename) {
295
- const lastDot = filename.lastIndexOf(".");
296
- // if we can't determine extension, ignore it
297
- if (lastDot >= 1) {
298
- const extension = filename.substr(lastDot + 1);
299
- const name = filename.substr(0, lastDot);
300
- await new Promise((resolve, reject) => {
301
- const streamBuf = new StreamBuf();
302
- const cleanup = () => {
303
- stream.removeListener("error", onError);
304
- streamBuf.removeListener("error", onError);
305
- streamBuf.removeListener("finish", onFinish);
306
- };
307
- const onFinish = () => {
308
- cleanup();
309
- model.mediaIndex[filename] = model.media.length;
310
- model.mediaIndex[name] = model.media.length;
311
- const medium = {
312
- type: "image",
313
- name,
314
- extension,
315
- buffer: streamBuf.toBuffer()
316
- };
317
- model.media.push(medium);
318
- resolve();
319
- };
320
- const onError = (error) => {
321
- cleanup();
322
- reject(error);
323
- };
324
- streamBuf.once("finish", onFinish);
325
- stream.on("error", onError);
326
- streamBuf.on("error", onError);
327
- stream.pipe(streamBuf);
328
- });
329
- }
330
- }
331
- async _processDrawingEntry(entry, model, name) {
332
- const xform = new DrawingXform();
333
- const drawing = await xform.parseStream(entry);
334
- model.drawings[name] = drawing;
335
- }
336
- async _processDrawingRelsEntry(entry, model, name) {
337
- const xform = new RelationshipsXform();
338
- const relationships = await xform.parseStream(entry);
339
- model.drawingRels[name] = relationships;
340
- }
341
- async _processVmlDrawingEntry(entry, model, name) {
342
- const xform = new VmlNotesXform();
343
- const vmlDrawing = await xform.parseStream(entry);
344
- model.vmlDrawings[`../drawings/${name}.vml`] = vmlDrawing;
345
- }
346
- async _processThemeEntry(stream, model, name) {
347
- await new Promise((resolve, reject) => {
348
- // TODO: stream entry into buffer and store the xml in the model.themes[]
349
- const streamBuf = new StreamBuf();
72
+ writeFile(filename, options) {
73
+ const stream = fs.createWriteStream(filename);
74
+ return new Promise((resolve, reject) => {
350
75
  const cleanup = () => {
76
+ stream.removeListener("finish", onFinish);
351
77
  stream.removeListener("error", onError);
352
- streamBuf.removeListener("error", onError);
353
- streamBuf.removeListener("finish", onFinish);
354
78
  };
355
79
  const onFinish = () => {
356
80
  cleanup();
357
- model.themes[name] = streamBuf.read().toString();
358
81
  resolve();
359
82
  };
360
- const onError = (err) => {
83
+ const onError = (error) => {
361
84
  cleanup();
362
- reject(err);
85
+ reject(error);
363
86
  };
364
- streamBuf.once("finish", onFinish);
87
+ stream.once("finish", onFinish);
365
88
  stream.on("error", onError);
366
- streamBuf.on("error", onError);
367
- stream.pipe(streamBuf);
89
+ this.write(stream, options)
90
+ .then(() => {
91
+ stream.end();
92
+ })
93
+ .catch(err => {
94
+ cleanup();
95
+ reject(err);
96
+ });
368
97
  });
369
98
  }
370
- async _processPivotTableEntry(stream, model, name) {
371
- const xform = new PivotTableXform();
372
- const pivotTable = await xform.parseStream(stream);
373
- if (pivotTable) {
374
- model.pivotTables[name] = pivotTable;
375
- }
376
- }
377
- async _processPivotTableRelsEntry(stream, model, name) {
378
- const xform = new RelationshipsXform();
379
- const relationships = await xform.parseStream(stream);
380
- model.pivotTableRels[name] = relationships;
381
- }
382
- async _processPivotCacheDefinitionEntry(stream, model, name) {
383
- const xform = new PivotCacheDefinitionXform();
384
- const cacheDefinition = await xform.parseStream(stream);
385
- if (cacheDefinition) {
386
- model.pivotCacheDefinitions[name] = cacheDefinition;
387
- }
388
- }
389
- async _processPivotCacheDefinitionRelsEntry(stream, model, name) {
390
- const xform = new RelationshipsXform();
391
- const relationships = await xform.parseStream(stream);
392
- model.pivotCacheDefinitionRels[name] = relationships;
393
- }
394
- async _processPivotCacheRecordsEntry(stream, model, name) {
395
- const xform = new PivotCacheRecordsXform();
396
- const cacheRecords = await xform.parseStream(stream);
397
- if (cacheRecords) {
398
- model.pivotCacheRecords[name] = cacheRecords;
399
- }
400
- }
99
+ // ===========================================================================
100
+ // Node.js specific: Stream operations
101
+ // ===========================================================================
401
102
  async read(stream, options) {
402
- // Use streaming unzip with fflate
403
- const allFiles = {};
103
+ // Collect all stream data into a single buffer
104
+ const chunks = [];
404
105
  await new Promise((resolve, reject) => {
405
- let filesProcessed = 0;
406
- let zipEnded = false;
407
- let filesStarted = 0;
408
- const cleanup = () => {
409
- stream.removeListener("data", onData);
410
- stream.removeListener("end", onEnd);
411
- stream.removeListener("error", onError);
412
- };
413
- const checkCompletion = () => {
414
- if (zipEnded && filesProcessed === filesStarted) {
415
- cleanup();
416
- resolve();
417
- }
418
- };
419
- const unzipper = new Unzip((file) => {
420
- filesStarted++;
421
- const fileChunks = [];
422
- let totalLength = 0;
423
- file.ondata = (err, data, final) => {
424
- if (err) {
425
- cleanup();
426
- reject(err);
427
- return;
428
- }
429
- if (data) {
430
- fileChunks.push(data);
431
- totalLength += data.length;
432
- }
433
- if (final) {
434
- // Optimize for single chunk case
435
- if (fileChunks.length === 1) {
436
- allFiles[file.name] = fileChunks[0];
437
- }
438
- else if (fileChunks.length > 1) {
439
- const fullData = new Uint8Array(totalLength);
440
- let offset = 0;
441
- for (const chunk of fileChunks) {
442
- fullData.set(chunk, offset);
443
- offset += chunk.length;
444
- }
445
- allFiles[file.name] = fullData;
446
- }
447
- else {
448
- allFiles[file.name] = new Uint8Array(0);
449
- }
450
- filesProcessed++;
451
- fileChunks.length = 0;
452
- checkCompletion();
453
- }
454
- };
455
- file.start();
456
- });
457
- unzipper.register(UnzipInflate);
458
106
  const onData = (chunk) => {
459
- unzipper.push(chunk);
107
+ chunks.push(chunk);
460
108
  };
461
109
  const onEnd = () => {
462
- unzipper.push(new Uint8Array(0), true);
463
- zipEnded = true;
464
- checkCompletion();
110
+ stream.removeListener("data", onData);
111
+ stream.removeListener("end", onEnd);
112
+ stream.removeListener("error", onError);
113
+ resolve();
465
114
  };
466
115
  const onError = (err) => {
467
- cleanup();
116
+ stream.removeListener("data", onData);
117
+ stream.removeListener("end", onEnd);
118
+ stream.removeListener("error", onError);
468
119
  reject(err);
469
120
  };
470
121
  stream.on("data", onData);
471
122
  stream.on("end", onEnd);
472
123
  stream.on("error", onError);
473
124
  });
125
+ // Combine chunks into a single buffer
126
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
127
+ const buffer = new Uint8Array(totalLength);
128
+ let offset = 0;
129
+ for (const chunk of chunks) {
130
+ buffer.set(chunk, offset);
131
+ offset += chunk.length;
132
+ }
133
+ // Use native ZipParser for extraction
134
+ const parser = new ZipParser(buffer);
135
+ const filesMap = await parser.extractAll();
136
+ // Convert Map to Record for loadFromFiles
137
+ const allFiles = {};
138
+ for (const [path, content] of filesMap) {
139
+ allFiles[path] = content;
140
+ }
474
141
  return this.loadFromFiles(allFiles, options);
475
142
  }
143
+ async write(stream, options) {
144
+ options = options || {};
145
+ const { model } = this.workbook;
146
+ const zip = new ZipWriter(options.zip);
147
+ zip.pipe(stream);
148
+ this.prepareModel(model, options);
149
+ await this.addContentTypes(zip, model);
150
+ await this.addOfficeRels(zip, model);
151
+ await this.addWorkbookRels(zip, model);
152
+ await this.addWorksheets(zip, model);
153
+ await this.addSharedStrings(zip, model);
154
+ this.addDrawings(zip, model);
155
+ this.addTables(zip, model);
156
+ this.addPivotTables(zip, model);
157
+ await Promise.all([this.addThemes(zip, model), this.addStyles(zip, model)]);
158
+ await this.addMedia(zip, model);
159
+ await Promise.all([this.addApp(zip, model), this.addCore(zip, model)]);
160
+ await this.addWorkbook(zip, model);
161
+ return this._finalize(zip);
162
+ }
163
+ // ===========================================================================
164
+ // Node.js specific: Buffer operations
165
+ // ===========================================================================
476
166
  async load(data, options) {
477
167
  let buffer;
478
- // Validate input type
479
168
  if (!data ||
480
169
  (typeof data === "object" &&
481
170
  !Buffer.isBuffer(data) &&
@@ -489,299 +178,18 @@ class XLSX {
489
178
  else {
490
179
  buffer = data;
491
180
  }
492
- // Create a fake stream from buffer for consistency
493
- const PassThroughStream = PassThrough;
494
- const stream = new PassThroughStream();
181
+ const stream = new PassThrough();
495
182
  stream.end(buffer);
496
183
  return this.read(stream, options);
497
184
  }
498
- async loadFromFiles(zipData, options) {
499
- const model = {
500
- worksheets: [],
501
- worksheetHash: {},
502
- worksheetRels: [],
503
- themes: {},
504
- media: [],
505
- mediaIndex: {},
506
- drawings: {},
507
- drawingRels: {},
508
- comments: {},
509
- tables: {},
510
- vmlDrawings: {},
511
- // Pivot table storage for loaded files
512
- pivotTables: {},
513
- pivotTableRels: {},
514
- pivotCacheDefinitions: {},
515
- pivotCacheDefinitionRels: {},
516
- pivotCacheRecords: {}
517
- };
518
- // Convert fflate format to JSZip-like structure for compatibility
519
- const entries = Object.keys(zipData).map(name => ({
520
- name,
521
- dir: name.endsWith("/"),
522
- data: zipData[name]
523
- }));
524
- for (const entry of entries) {
525
- if (!entry.dir) {
526
- let entryName = entry.name;
527
- if (entryName[0] === "/") {
528
- entryName = entryName.substr(1);
529
- }
530
- let stream;
531
- if (entryName.match(/xl\/media\//) ||
532
- // themes are not parsed as stream
533
- entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/)) {
534
- stream = new PassThrough();
535
- stream.end(Buffer.from(entry.data));
536
- }
537
- else {
538
- // use object mode to avoid buffer-string convention
539
- stream = new PassThrough({
540
- readableObjectMode: true,
541
- writableObjectMode: true
542
- });
543
- const content = bufferToString(Buffer.from(entry.data));
544
- stream.end(content);
545
- }
546
- let match;
547
- match = entryName.match(/xl\/worksheets\/sheet(\d+)[.]xml/);
548
- if (match) {
549
- const sheetNo = parseInt(match[1], 10);
550
- await this._processWorksheetEntry(stream, model, sheetNo, options, entryName);
551
- }
552
- else {
553
- switch (entryName) {
554
- case "_rels/.rels":
555
- model.globalRels = await this.parseRels(stream);
556
- break;
557
- case "xl/workbook.xml": {
558
- const workbook = await this.parseWorkbook(stream);
559
- model.sheets = workbook.sheets;
560
- model.definedNames = workbook.definedNames;
561
- model.views = workbook.views;
562
- model.properties = workbook.properties;
563
- model.calcProperties = workbook.calcProperties;
564
- // pivotCaches contains the mapping from rId to cacheId
565
- // needed for linking pivot tables to their cache data
566
- model.pivotCaches = workbook.pivotCaches;
567
- break;
568
- }
569
- case "xl/sharedStrings.xml":
570
- model.sharedStrings = new SharedStringsXform();
571
- await model.sharedStrings.parseStream(stream);
572
- break;
573
- case "xl/_rels/workbook.xml.rels":
574
- model.workbookRels = await this.parseRels(stream);
575
- break;
576
- case "docProps/app.xml": {
577
- const appXform = new AppXform();
578
- const appProperties = await appXform.parseStream(stream);
579
- model.company = appProperties.company;
580
- model.manager = appProperties.manager;
581
- break;
582
- }
583
- case "docProps/core.xml": {
584
- const coreXform = new CoreXform();
585
- const coreProperties = await coreXform.parseStream(stream);
586
- Object.assign(model, coreProperties);
587
- break;
588
- }
589
- case "xl/styles.xml":
590
- model.styles = new StylesXform();
591
- await model.styles.parseStream(stream);
592
- break;
593
- default: {
594
- match = entryName.match(/xl\/worksheets\/_rels\/sheet(\d+)[.]xml[.]rels/);
595
- if (match) {
596
- const sheetNo = parseInt(match[1], 10);
597
- await this._processWorksheetRelsEntry(stream, model, sheetNo);
598
- break;
599
- }
600
- match = entryName.match(/xl\/media\/([a-zA-Z0-9]+[.][a-zA-Z0-9]{3,4})$/);
601
- if (match) {
602
- await this._processMediaEntry(stream, model, match[1]);
603
- break;
604
- }
605
- match = entryName.match(/xl\/drawings\/(drawing\d+)[.]xml/);
606
- if (match) {
607
- await this._processDrawingEntry(stream, model, match[1]);
608
- break;
609
- }
610
- match = entryName.match(/xl\/drawings\/_rels\/(drawing\d+)[.]xml[.]rels/);
611
- if (match) {
612
- await this._processDrawingRelsEntry(stream, model, match[1]);
613
- break;
614
- }
615
- match = entryName.match(/xl\/drawings\/(vmlDrawing\d+)[.]vml/);
616
- if (match) {
617
- await this._processVmlDrawingEntry(stream, model, match[1]);
618
- break;
619
- }
620
- match = entryName.match(/xl\/comments(\d+)[.]xml/);
621
- if (match) {
622
- await this._processCommentEntry(stream, model, `comments${match[1]}`);
623
- break;
624
- }
625
- match = entryName.match(/xl\/tables\/(table\d+)[.]xml/);
626
- if (match) {
627
- await this._processTableEntry(stream, model, match[1]);
628
- break;
629
- }
630
- match = entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/);
631
- if (match) {
632
- await this._processThemeEntry(stream, model, match[1]);
633
- break;
634
- }
635
- // Pivot table files
636
- match = entryName.match(/xl\/pivotTables\/(pivotTable\d+)[.]xml/);
637
- if (match) {
638
- await this._processPivotTableEntry(stream, model, match[1]);
639
- break;
640
- }
641
- match = entryName.match(/xl\/pivotTables\/_rels\/(pivotTable\d+)[.]xml[.]rels/);
642
- if (match) {
643
- await this._processPivotTableRelsEntry(stream, model, match[1]);
644
- break;
645
- }
646
- // Pivot cache files
647
- match = entryName.match(/xl\/pivotCache\/(pivotCacheDefinition\d+)[.]xml/);
648
- if (match) {
649
- await this._processPivotCacheDefinitionEntry(stream, model, match[1]);
650
- break;
651
- }
652
- match = entryName.match(/xl\/pivotCache\/_rels\/(pivotCacheDefinition\d+)[.]xml[.]rels/);
653
- if (match) {
654
- await this._processPivotCacheDefinitionRelsEntry(stream, model, match[1]);
655
- break;
656
- }
657
- match = entryName.match(/xl\/pivotCache\/(pivotCacheRecords\d+)[.]xml/);
658
- if (match) {
659
- await this._processPivotCacheRecordsEntry(stream, model, match[1]);
660
- break;
661
- }
662
- }
663
- }
664
- }
665
- }
666
- }
667
- this.reconcile(model, options);
668
- // apply model
669
- this.workbook.model = model;
670
- return this.workbook;
671
- }
672
- // =========================================================================
673
- // Write
674
- async addContentTypes(zip, model) {
675
- const xform = new ContentTypesXform();
676
- const xml = xform.toXml(model);
677
- zip.append(xml, { name: "[Content_Types].xml" });
678
- }
679
- async addApp(zip, model) {
680
- const xform = new AppXform();
681
- const xml = xform.toXml(model);
682
- zip.append(xml, { name: "docProps/app.xml" });
683
- }
684
- async addCore(zip, model) {
685
- const xform = new CoreXform();
686
- zip.append(xform.toXml(model), { name: "docProps/core.xml" });
687
- }
688
- async addThemes(zip, model) {
689
- const themes = model.themes || { theme1: theme1Xml };
690
- Object.keys(themes).forEach(name => {
691
- const xml = themes[name];
692
- const path = `xl/theme/${name}.xml`;
693
- zip.append(xml, { name: path });
694
- });
695
- }
696
- async addOfficeRels(zip, _model) {
697
- const xform = new RelationshipsXform();
698
- const xml = xform.toXml([
699
- { Id: "rId1", Type: XLSX.RelType.OfficeDocument, Target: "xl/workbook.xml" },
700
- { Id: "rId2", Type: XLSX.RelType.CoreProperties, Target: "docProps/core.xml" },
701
- { Id: "rId3", Type: XLSX.RelType.ExtenderProperties, Target: "docProps/app.xml" }
702
- ]);
703
- zip.append(xml, { name: "_rels/.rels" });
704
- }
705
- async addWorkbookRels(zip, model) {
706
- let count = 1;
707
- const relationships = [
708
- { Id: `rId${count++}`, Type: XLSX.RelType.Styles, Target: "styles.xml" },
709
- { Id: `rId${count++}`, Type: XLSX.RelType.Theme, Target: "theme/theme1.xml" }
710
- ];
711
- if (model.sharedStrings.count) {
712
- relationships.push({
713
- Id: `rId${count++}`,
714
- Type: XLSX.RelType.SharedStrings,
715
- Target: "sharedStrings.xml"
716
- });
717
- }
718
- // Add relationships for all pivot tables
719
- (model.pivotTables || []).forEach((pivotTable) => {
720
- pivotTable.rId = `rId${count++}`;
721
- relationships.push({
722
- Id: pivotTable.rId,
723
- Type: XLSX.RelType.PivotCacheDefinition,
724
- Target: `pivotCache/pivotCacheDefinition${pivotTable.tableNumber}.xml`
725
- });
726
- });
727
- model.worksheets.forEach((worksheet, index) => {
728
- // Use sequential index (1-based) for file naming, not worksheet.id (sheetId)
729
- // sheetId can be non-sequential (e.g., 1, 3, 5) which would create gaps in filenames
730
- worksheet.rId = `rId${count++}`;
731
- worksheet.fileIndex = index + 1; // Store for use in addWorksheets and content types
732
- relationships.push({
733
- Id: worksheet.rId,
734
- Type: XLSX.RelType.Worksheet,
735
- Target: `worksheets/sheet${worksheet.fileIndex}.xml`
736
- });
737
- });
738
- const xform = new RelationshipsXform();
739
- const xml = xform.toXml(relationships);
740
- zip.append(xml, { name: "xl/_rels/workbook.xml.rels" });
741
- }
742
- async addSharedStrings(zip, model) {
743
- if (model.sharedStrings && model.sharedStrings.count) {
744
- zip.append(model.sharedStrings.xml, { name: "xl/sharedStrings.xml" });
745
- }
746
- }
747
- async addStyles(zip, model) {
748
- const { xml } = model.styles;
749
- if (xml) {
750
- zip.append(xml, { name: "xl/styles.xml" });
751
- }
752
- }
753
- async addWorkbook(zip, model) {
754
- const xform = new WorkbookXform();
755
- zip.append(xform.toXml(model), { name: "xl/workbook.xml" });
756
- }
757
- async addWorksheets(zip, model) {
758
- // preparation phase
759
- const worksheetXform = new WorkSheetXform();
760
- const relationshipsXform = new RelationshipsXform();
761
- const commentsXform = new CommentsXform();
762
- const vmlNotesXform = new VmlNotesXform();
763
- // write sheets
764
- model.worksheets.forEach((worksheet, index) => {
765
- // Use fileIndex if set by addWorkbookRels, otherwise use index + 1
766
- const fileIndex = worksheet.fileIndex || index + 1;
767
- let xmlStream = new XmlStream();
768
- worksheetXform.render(xmlStream, worksheet);
769
- zip.append(xmlStream.xml, { name: `xl/worksheets/sheet${fileIndex}.xml` });
770
- if (worksheet.rels && worksheet.rels.length) {
771
- xmlStream = new XmlStream();
772
- relationshipsXform.render(xmlStream, worksheet.rels);
773
- zip.append(xmlStream.xml, { name: `xl/worksheets/_rels/sheet${fileIndex}.xml.rels` });
774
- }
775
- if (worksheet.comments.length > 0) {
776
- xmlStream = new XmlStream();
777
- commentsXform.render(xmlStream, worksheet);
778
- zip.append(xmlStream.xml, { name: `xl/comments${fileIndex}.xml` });
779
- xmlStream = new XmlStream();
780
- vmlNotesXform.render(xmlStream, worksheet);
781
- zip.append(xmlStream.xml, { name: `xl/drawings/vmlDrawing${fileIndex}.vml` });
782
- }
783
- });
185
+ async writeBuffer(options) {
186
+ const stream = new StreamBuf();
187
+ await this.write(stream, options);
188
+ return stream.read();
784
189
  }
190
+ // ===========================================================================
191
+ // Node.js specific: Media handling with file support
192
+ // ===========================================================================
785
193
  async addMedia(zip, model) {
786
194
  await Promise.all(model.media.map(async (medium) => {
787
195
  if (medium.type === "image") {
@@ -802,187 +210,5 @@ class XLSX {
802
210
  throw new Error("Unsupported media");
803
211
  }));
804
212
  }
805
- addDrawings(zip, model) {
806
- const drawingXform = new DrawingXform();
807
- const relsXform = new RelationshipsXform();
808
- model.worksheets.forEach((worksheet) => {
809
- const { drawing } = worksheet;
810
- if (drawing) {
811
- drawingXform.prepare(drawing);
812
- let xml = drawingXform.toXml(drawing);
813
- zip.append(xml, { name: `xl/drawings/${drawing.name}.xml` });
814
- xml = relsXform.toXml(drawing.rels);
815
- zip.append(xml, { name: `xl/drawings/_rels/${drawing.name}.xml.rels` });
816
- }
817
- });
818
- }
819
- addTables(zip, model) {
820
- const tableXform = new TableXform();
821
- model.worksheets.forEach((worksheet) => {
822
- const { tables } = worksheet;
823
- tables.forEach((table) => {
824
- tableXform.prepare(table, {});
825
- const tableXml = tableXform.toXml(table);
826
- zip.append(tableXml, { name: `xl/tables/${table.target}` });
827
- });
828
- });
829
- }
830
- addPivotTables(zip, model) {
831
- if (!model.pivotTables.length) {
832
- return;
833
- }
834
- const pivotCacheRecordsXform = new PivotCacheRecordsXform();
835
- const pivotCacheDefinitionXform = new PivotCacheDefinitionXform();
836
- const pivotTableXform = new PivotTableXform();
837
- const relsXform = new RelationshipsXform();
838
- // Generate files for each pivot table
839
- model.pivotTables.forEach((pivotTable) => {
840
- const n = pivotTable.tableNumber;
841
- // For loaded pivot tables, use the stored cache data
842
- // For new pivot tables, use the source data
843
- const isLoaded = pivotTable.isLoaded;
844
- if (isLoaded) {
845
- // Loaded pivot table - use stored cache definition and records
846
- if (pivotTable.cacheDefinition) {
847
- const xml = pivotCacheDefinitionXform.toXml(pivotTable.cacheDefinition);
848
- zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
849
- }
850
- if (pivotTable.cacheRecords) {
851
- const xml = pivotCacheRecordsXform.toXml(pivotTable.cacheRecords);
852
- zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
853
- }
854
- }
855
- else {
856
- // New pivot table - generate from source
857
- let xml = pivotCacheRecordsXform.toXml(pivotTable);
858
- zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
859
- xml = pivotCacheDefinitionXform.toXml(pivotTable);
860
- zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
861
- }
862
- // pivot cache definition rels (same for both)
863
- let xml = relsXform.toXml([
864
- {
865
- Id: "rId1",
866
- Type: XLSX.RelType.PivotCacheRecords,
867
- Target: `pivotCacheRecords${n}.xml`
868
- }
869
- ]);
870
- zip.append(xml, { name: `xl/pivotCache/_rels/pivotCacheDefinition${n}.xml.rels` });
871
- // pivot table
872
- xml = pivotTableXform.toXml(pivotTable);
873
- zip.append(xml, { name: `xl/pivotTables/pivotTable${n}.xml` });
874
- xml = relsXform.toXml([
875
- {
876
- Id: "rId1",
877
- Type: XLSX.RelType.PivotCacheDefinition,
878
- Target: `../pivotCache/pivotCacheDefinition${n}.xml`
879
- }
880
- ]);
881
- zip.append(xml, { name: `xl/pivotTables/_rels/pivotTable${n}.xml.rels` });
882
- });
883
- }
884
- _finalize(zip) {
885
- return new Promise((resolve, reject) => {
886
- zip.on("finish", () => {
887
- resolve(this);
888
- });
889
- zip.on("error", reject);
890
- zip.finalize();
891
- });
892
- }
893
- prepareModel(model, options) {
894
- // ensure following properties have sane values
895
- model.creator = model.creator || "ExcelTS";
896
- model.lastModifiedBy = model.lastModifiedBy || "ExcelTS";
897
- model.created = model.created || new Date();
898
- model.modified = model.modified || new Date();
899
- model.useSharedStrings =
900
- options.useSharedStrings !== undefined ? options.useSharedStrings : true;
901
- model.useStyles = options.useStyles !== undefined ? options.useStyles : true;
902
- // Manage the shared strings
903
- model.sharedStrings = new SharedStringsXform();
904
- // add a style manager to handle cell formats, fonts, etc.
905
- model.styles = model.useStyles ? new StylesXform(true) : new StylesXform.Mock();
906
- // prepare all of the things before the render
907
- const workbookXform = new WorkbookXform();
908
- const worksheetXform = new WorkSheetXform();
909
- workbookXform.prepare(model);
910
- const worksheetOptions = {
911
- sharedStrings: model.sharedStrings,
912
- styles: model.styles,
913
- date1904: model.properties.date1904,
914
- drawingsCount: 0,
915
- media: model.media
916
- };
917
- worksheetOptions.drawings = model.drawings = [];
918
- worksheetOptions.commentRefs = model.commentRefs = [];
919
- let tableCount = 0;
920
- model.tables = [];
921
- model.worksheets.forEach((worksheet) => {
922
- // assign unique filenames to tables
923
- worksheet.tables.forEach((table) => {
924
- tableCount++;
925
- table.target = `table${tableCount}.xml`;
926
- table.id = tableCount;
927
- model.tables.push(table);
928
- });
929
- worksheetXform.prepare(worksheet, worksheetOptions);
930
- });
931
- // TODO: workbook drawing list
932
- }
933
- async write(stream, options) {
934
- options = options || {};
935
- const { model } = this.workbook;
936
- const zip = new ZipWriter(options.zip);
937
- zip.pipe(stream);
938
- this.prepareModel(model, options);
939
- // render
940
- await this.addContentTypes(zip, model);
941
- await this.addOfficeRels(zip, model);
942
- await this.addWorkbookRels(zip, model);
943
- await this.addWorksheets(zip, model);
944
- await this.addSharedStrings(zip, model); // always after worksheets
945
- this.addDrawings(zip, model);
946
- this.addTables(zip, model);
947
- this.addPivotTables(zip, model);
948
- await Promise.all([this.addThemes(zip, model), this.addStyles(zip, model)]);
949
- await this.addMedia(zip, model);
950
- await Promise.all([this.addApp(zip, model), this.addCore(zip, model)]);
951
- await this.addWorkbook(zip, model);
952
- return this._finalize(zip);
953
- }
954
- writeFile(filename, options) {
955
- const stream = fs.createWriteStream(filename);
956
- return new Promise((resolve, reject) => {
957
- const cleanup = () => {
958
- stream.removeListener("finish", onFinish);
959
- stream.removeListener("error", onError);
960
- };
961
- const onFinish = () => {
962
- cleanup();
963
- resolve();
964
- };
965
- const onError = (error) => {
966
- cleanup();
967
- reject(error);
968
- };
969
- stream.once("finish", onFinish);
970
- stream.on("error", onError);
971
- this.write(stream, options)
972
- .then(() => {
973
- stream.end();
974
- })
975
- .catch(err => {
976
- cleanup();
977
- reject(err);
978
- });
979
- });
980
- }
981
- async writeBuffer(options) {
982
- const stream = new StreamBuf();
983
- await this.write(stream, options);
984
- return stream.read();
985
- }
986
213
  }
987
- XLSX.RelType = RelType;
988
214
  export { XLSX };