@cj-tech-master/excelts 9.2.1 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +25 -2
  2. package/README_zh.md +29 -6
  3. package/dist/browser/index.browser.d.ts +1 -1
  4. package/dist/browser/index.browser.js +4 -0
  5. package/dist/browser/index.d.ts +1 -1
  6. package/dist/browser/index.js +4 -0
  7. package/dist/browser/modules/excel/cell.d.ts +17 -3
  8. package/dist/browser/modules/excel/cell.js +170 -22
  9. package/dist/browser/modules/excel/defined-names.d.ts +96 -1
  10. package/dist/browser/modules/excel/defined-names.js +411 -21
  11. package/dist/browser/modules/excel/image.d.ts +11 -0
  12. package/dist/browser/modules/excel/image.js +24 -1
  13. package/dist/browser/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  14. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +14 -0
  15. package/dist/browser/modules/excel/stream/workbook-reader.d.ts +2 -1
  16. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  17. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +48 -1
  18. package/dist/browser/modules/excel/stream/workbook-writer.d.ts +3 -2
  19. package/dist/browser/modules/excel/stream/worksheet-reader.js +17 -1
  20. package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +39 -6
  21. package/dist/browser/modules/excel/stream/worksheet-writer.js +45 -5
  22. package/dist/browser/modules/excel/table.js +15 -2
  23. package/dist/browser/modules/excel/types.d.ts +133 -2
  24. package/dist/browser/modules/excel/utils/col-cache.d.ts +1 -0
  25. package/dist/browser/modules/excel/utils/col-cache.js +15 -0
  26. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +3 -3
  27. package/dist/browser/modules/excel/utils/drawing-utils.js +4 -0
  28. package/dist/browser/modules/excel/utils/external-link-formula.d.ts +76 -0
  29. package/dist/browser/modules/excel/utils/external-link-formula.js +208 -0
  30. package/dist/browser/modules/excel/utils/iterate-stream.d.ts +9 -3
  31. package/dist/browser/modules/excel/utils/iterate-stream.js +3 -1
  32. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +19 -0
  33. package/dist/browser/modules/excel/utils/ooxml-paths.js +37 -2
  34. package/dist/browser/modules/excel/utils/shared-strings.d.ts +8 -3
  35. package/dist/browser/modules/excel/utils/shared-strings.js +21 -2
  36. package/dist/browser/modules/excel/utils/workbook-protection.d.ts +30 -0
  37. package/dist/browser/modules/excel/utils/workbook-protection.js +30 -0
  38. package/dist/browser/modules/excel/workbook.browser.d.ts +257 -6
  39. package/dist/browser/modules/excel/workbook.browser.js +318 -34
  40. package/dist/browser/modules/excel/workbook.d.ts +1 -1
  41. package/dist/browser/modules/excel/worksheet.d.ts +3 -1
  42. package/dist/browser/modules/excel/worksheet.js +21 -2
  43. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +15 -0
  44. package/dist/browser/modules/excel/xlsx/rel-type.js +16 -1
  45. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  46. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  47. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  48. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  49. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  50. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  51. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  52. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  53. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  54. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  55. package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  56. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  57. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  58. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  59. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  60. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  61. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  62. package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  63. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  64. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  65. package/dist/browser/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  66. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  67. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  68. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  69. package/dist/browser/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  70. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  71. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +410 -20
  72. package/dist/browser/modules/excel/xlsx/xlsx.d.ts +7 -4
  73. package/dist/browser/modules/excel/xlsx/xlsx.js +4 -5
  74. package/dist/browser/modules/formula/compile/address-utils.d.ts +62 -0
  75. package/dist/browser/modules/formula/compile/address-utils.js +83 -0
  76. package/dist/browser/modules/formula/compile/binder.d.ts +42 -0
  77. package/dist/browser/modules/formula/compile/binder.js +487 -0
  78. package/dist/browser/modules/formula/compile/bound-ast.d.ts +230 -0
  79. package/dist/browser/modules/formula/compile/bound-ast.js +80 -0
  80. package/dist/browser/modules/formula/compile/compiled-formula.d.ts +137 -0
  81. package/dist/browser/modules/formula/compile/compiled-formula.js +383 -0
  82. package/dist/browser/modules/formula/compile/dependency-analysis.d.ts +93 -0
  83. package/dist/browser/modules/formula/compile/dependency-analysis.js +432 -0
  84. package/dist/browser/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  85. package/dist/browser/modules/formula/compile/structured-ref-utils.js +136 -0
  86. package/dist/browser/modules/formula/default-syntax-probe.d.ts +79 -0
  87. package/dist/browser/modules/formula/default-syntax-probe.js +83 -0
  88. package/dist/browser/modules/formula/functions/_date-context.d.ts +4 -0
  89. package/dist/browser/modules/formula/functions/_date-context.js +29 -0
  90. package/dist/browser/modules/formula/functions/_shared.d.ts +121 -0
  91. package/dist/browser/modules/formula/functions/_shared.js +381 -0
  92. package/dist/browser/modules/formula/functions/conditional.d.ts +27 -0
  93. package/dist/browser/modules/formula/functions/conditional.js +343 -0
  94. package/dist/browser/modules/formula/functions/database.d.ts +37 -0
  95. package/dist/browser/modules/formula/functions/database.js +274 -0
  96. package/dist/browser/modules/formula/functions/date.d.ts +61 -0
  97. package/dist/browser/modules/formula/functions/date.js +855 -0
  98. package/dist/browser/modules/formula/functions/dynamic-array.d.ts +23 -0
  99. package/dist/browser/modules/formula/functions/dynamic-array.js +860 -0
  100. package/dist/browser/modules/formula/functions/engineering.d.ts +57 -0
  101. package/dist/browser/modules/formula/functions/engineering.js +1128 -0
  102. package/dist/browser/modules/formula/functions/financial.d.ts +202 -0
  103. package/dist/browser/modules/formula/functions/financial.js +2296 -0
  104. package/dist/browser/modules/formula/functions/lookup.d.ts +18 -0
  105. package/dist/browser/modules/formula/functions/lookup.js +886 -0
  106. package/dist/browser/modules/formula/functions/math.d.ts +114 -0
  107. package/dist/browser/modules/formula/functions/math.js +1406 -0
  108. package/dist/browser/modules/formula/functions/statistical.d.ts +193 -0
  109. package/dist/browser/modules/formula/functions/statistical.js +3390 -0
  110. package/dist/browser/modules/formula/functions/text.d.ts +86 -0
  111. package/dist/browser/modules/formula/functions/text.js +1845 -0
  112. package/dist/browser/modules/formula/host-registry.d.ts +53 -0
  113. package/dist/browser/modules/formula/host-registry.js +69 -0
  114. package/dist/browser/modules/formula/index.d.ts +39 -0
  115. package/dist/browser/modules/formula/index.js +49 -0
  116. package/dist/browser/modules/formula/install.d.ts +62 -0
  117. package/dist/browser/modules/formula/install.js +88 -0
  118. package/dist/browser/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  119. package/dist/browser/modules/formula/integration/apply-writeback-plan.js +210 -0
  120. package/dist/browser/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  121. package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +616 -0
  122. package/dist/browser/modules/formula/integration/calculate-formulas.d.ts +67 -0
  123. package/dist/browser/modules/formula/integration/calculate-formulas.js +68 -0
  124. package/dist/browser/modules/formula/integration/formula-instance.d.ts +64 -0
  125. package/dist/browser/modules/formula/integration/formula-instance.js +79 -0
  126. package/dist/browser/modules/formula/integration/workbook-adapter.d.ts +26 -0
  127. package/dist/browser/modules/formula/integration/workbook-adapter.js +324 -0
  128. package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  129. package/dist/browser/modules/formula/integration/workbook-snapshot.js +77 -0
  130. package/dist/browser/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  131. package/dist/browser/modules/formula/materialize/build-writeback-plan.js +473 -0
  132. package/dist/browser/modules/formula/materialize/spill-engine.d.ts +9 -0
  133. package/dist/browser/modules/formula/materialize/spill-engine.js +38 -0
  134. package/dist/browser/modules/formula/materialize/types.d.ts +179 -0
  135. package/dist/browser/modules/formula/materialize/types.js +29 -0
  136. package/dist/browser/modules/formula/materialize/writeback-plan.d.ts +167 -0
  137. package/dist/browser/modules/formula/materialize/writeback-plan.js +27 -0
  138. package/dist/browser/modules/formula/runtime/evaluator.d.ts +151 -0
  139. package/dist/browser/modules/formula/runtime/evaluator.js +2291 -0
  140. package/dist/browser/modules/formula/runtime/function-registry.d.ts +47 -0
  141. package/dist/browser/modules/formula/runtime/function-registry.js +840 -0
  142. package/dist/browser/modules/formula/runtime/values.d.ts +211 -0
  143. package/dist/browser/modules/formula/runtime/values.js +385 -0
  144. package/dist/browser/modules/formula/syntax/ast.d.ts +129 -0
  145. package/dist/browser/modules/formula/syntax/ast.js +28 -0
  146. package/dist/browser/modules/formula/syntax/parser.d.ts +18 -0
  147. package/dist/browser/modules/formula/syntax/parser.js +439 -0
  148. package/dist/browser/modules/formula/syntax/token-types.d.ts +153 -0
  149. package/dist/browser/modules/formula/syntax/token-types.js +59 -0
  150. package/dist/browser/modules/formula/syntax/tokenizer.d.ts +10 -0
  151. package/dist/browser/modules/formula/syntax/tokenizer.js +1074 -0
  152. package/dist/browser/modules/pdf/excel-bridge.js +9 -0
  153. package/dist/cjs/index.js +4 -0
  154. package/dist/cjs/modules/excel/cell.js +170 -22
  155. package/dist/cjs/modules/excel/defined-names.js +411 -21
  156. package/dist/cjs/modules/excel/image.js +24 -1
  157. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +14 -0
  158. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +48 -1
  159. package/dist/cjs/modules/excel/stream/worksheet-reader.js +17 -1
  160. package/dist/cjs/modules/excel/stream/worksheet-writer.js +45 -5
  161. package/dist/cjs/modules/excel/table.js +15 -2
  162. package/dist/cjs/modules/excel/utils/col-cache.js +15 -0
  163. package/dist/cjs/modules/excel/utils/drawing-utils.js +4 -0
  164. package/dist/cjs/modules/excel/utils/external-link-formula.js +212 -0
  165. package/dist/cjs/modules/excel/utils/iterate-stream.js +3 -1
  166. package/dist/cjs/modules/excel/utils/ooxml-paths.js +42 -2
  167. package/dist/cjs/modules/excel/utils/shared-strings.js +21 -2
  168. package/dist/cjs/modules/excel/utils/workbook-protection.js +33 -0
  169. package/dist/cjs/modules/excel/workbook.browser.js +318 -34
  170. package/dist/cjs/modules/excel/worksheet.js +20 -1
  171. package/dist/cjs/modules/excel/xlsx/rel-type.js +16 -1
  172. package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  173. package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +333 -0
  174. package/dist/cjs/modules/excel/xlsx/xform/book/external-reference-xform.js +27 -0
  175. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  176. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-protection-xform.js +69 -0
  177. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  178. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +18 -0
  179. package/dist/cjs/modules/excel/xlsx/xform/core/metadata-xform.js +161 -0
  180. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +108 -0
  181. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  182. package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  183. package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  184. package/dist/cjs/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  185. package/dist/cjs/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +83 -0
  186. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  187. package/dist/cjs/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  188. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +408 -18
  189. package/dist/cjs/modules/excel/xlsx/xlsx.js +4 -5
  190. package/dist/cjs/modules/formula/compile/address-utils.js +89 -0
  191. package/dist/cjs/modules/formula/compile/binder.js +489 -0
  192. package/dist/cjs/modules/formula/compile/bound-ast.js +68 -0
  193. package/dist/cjs/modules/formula/compile/compiled-formula.js +387 -0
  194. package/dist/cjs/modules/formula/compile/dependency-analysis.js +437 -0
  195. package/dist/cjs/modules/formula/compile/structured-ref-utils.js +141 -0
  196. package/dist/cjs/modules/formula/default-syntax-probe.js +87 -0
  197. package/dist/cjs/modules/formula/functions/_date-context.js +33 -0
  198. package/dist/cjs/modules/formula/functions/_shared.js +396 -0
  199. package/dist/cjs/modules/formula/functions/conditional.js +354 -0
  200. package/dist/cjs/modules/formula/functions/database.js +288 -0
  201. package/dist/cjs/modules/formula/functions/date.js +883 -0
  202. package/dist/cjs/modules/formula/functions/dynamic-array.js +881 -0
  203. package/dist/cjs/modules/formula/functions/engineering.js +1183 -0
  204. package/dist/cjs/modules/formula/functions/financial.js +2348 -0
  205. package/dist/cjs/modules/formula/functions/lookup.js +902 -0
  206. package/dist/cjs/modules/formula/functions/math.js +1487 -0
  207. package/dist/cjs/modules/formula/functions/statistical.js +3488 -0
  208. package/dist/cjs/modules/formula/functions/text.js +1889 -0
  209. package/dist/cjs/modules/formula/host-registry.js +75 -0
  210. package/dist/cjs/modules/formula/index.js +58 -0
  211. package/dist/cjs/modules/formula/install.js +93 -0
  212. package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +213 -0
  213. package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +619 -0
  214. package/dist/cjs/modules/formula/integration/calculate-formulas.js +71 -0
  215. package/dist/cjs/modules/formula/integration/formula-instance.js +82 -0
  216. package/dist/cjs/modules/formula/integration/workbook-adapter.js +327 -0
  217. package/dist/cjs/modules/formula/integration/workbook-snapshot.js +84 -0
  218. package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +475 -0
  219. package/dist/cjs/modules/formula/materialize/spill-engine.js +42 -0
  220. package/dist/cjs/modules/formula/materialize/types.js +32 -0
  221. package/dist/cjs/modules/formula/materialize/writeback-plan.js +28 -0
  222. package/dist/cjs/modules/formula/runtime/evaluator.js +2298 -0
  223. package/dist/cjs/modules/formula/runtime/function-registry.js +846 -0
  224. package/dist/cjs/modules/formula/runtime/values.js +385 -0
  225. package/dist/cjs/modules/formula/syntax/ast.js +8 -0
  226. package/dist/cjs/modules/formula/syntax/parser.js +440 -0
  227. package/dist/cjs/modules/formula/syntax/token-types.js +32 -0
  228. package/dist/cjs/modules/formula/syntax/tokenizer.js +1076 -0
  229. package/dist/cjs/modules/pdf/excel-bridge.js +9 -0
  230. package/dist/esm/index.browser.js +4 -0
  231. package/dist/esm/index.js +4 -0
  232. package/dist/esm/modules/excel/cell.js +170 -22
  233. package/dist/esm/modules/excel/defined-names.js +411 -21
  234. package/dist/esm/modules/excel/image.js +24 -1
  235. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +14 -0
  236. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +48 -1
  237. package/dist/esm/modules/excel/stream/worksheet-reader.js +17 -1
  238. package/dist/esm/modules/excel/stream/worksheet-writer.js +45 -5
  239. package/dist/esm/modules/excel/table.js +15 -2
  240. package/dist/esm/modules/excel/utils/col-cache.js +15 -0
  241. package/dist/esm/modules/excel/utils/drawing-utils.js +4 -0
  242. package/dist/esm/modules/excel/utils/external-link-formula.js +208 -0
  243. package/dist/esm/modules/excel/utils/iterate-stream.js +3 -1
  244. package/dist/esm/modules/excel/utils/ooxml-paths.js +37 -2
  245. package/dist/esm/modules/excel/utils/shared-strings.js +21 -2
  246. package/dist/esm/modules/excel/utils/workbook-protection.js +30 -0
  247. package/dist/esm/modules/excel/workbook.browser.js +318 -34
  248. package/dist/esm/modules/excel/worksheet.js +21 -2
  249. package/dist/esm/modules/excel/xlsx/rel-type.js +16 -1
  250. package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  251. package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  252. package/dist/esm/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  253. package/dist/esm/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  254. package/dist/esm/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  255. package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  256. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  257. package/dist/esm/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  258. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  259. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  260. package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  261. package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  262. package/dist/esm/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  263. package/dist/esm/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  264. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  265. package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  266. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +410 -20
  267. package/dist/esm/modules/excel/xlsx/xlsx.js +4 -5
  268. package/dist/esm/modules/formula/compile/address-utils.js +83 -0
  269. package/dist/esm/modules/formula/compile/binder.js +487 -0
  270. package/dist/esm/modules/formula/compile/bound-ast.js +80 -0
  271. package/dist/esm/modules/formula/compile/compiled-formula.js +383 -0
  272. package/dist/esm/modules/formula/compile/dependency-analysis.js +432 -0
  273. package/dist/esm/modules/formula/compile/structured-ref-utils.js +136 -0
  274. package/dist/esm/modules/formula/default-syntax-probe.js +83 -0
  275. package/dist/esm/modules/formula/functions/_date-context.js +29 -0
  276. package/dist/esm/modules/formula/functions/_shared.js +381 -0
  277. package/dist/esm/modules/formula/functions/conditional.js +343 -0
  278. package/dist/esm/modules/formula/functions/database.js +274 -0
  279. package/dist/esm/modules/formula/functions/date.js +855 -0
  280. package/dist/esm/modules/formula/functions/dynamic-array.js +860 -0
  281. package/dist/esm/modules/formula/functions/engineering.js +1128 -0
  282. package/dist/esm/modules/formula/functions/financial.js +2296 -0
  283. package/dist/esm/modules/formula/functions/lookup.js +886 -0
  284. package/dist/esm/modules/formula/functions/math.js +1406 -0
  285. package/dist/esm/modules/formula/functions/statistical.js +3390 -0
  286. package/dist/esm/modules/formula/functions/text.js +1845 -0
  287. package/dist/esm/modules/formula/host-registry.js +69 -0
  288. package/dist/esm/modules/formula/index.js +49 -0
  289. package/dist/esm/modules/formula/install.js +88 -0
  290. package/dist/esm/modules/formula/integration/apply-writeback-plan.js +210 -0
  291. package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +616 -0
  292. package/dist/esm/modules/formula/integration/calculate-formulas.js +68 -0
  293. package/dist/esm/modules/formula/integration/formula-instance.js +79 -0
  294. package/dist/esm/modules/formula/integration/workbook-adapter.js +324 -0
  295. package/dist/esm/modules/formula/integration/workbook-snapshot.js +77 -0
  296. package/dist/esm/modules/formula/materialize/build-writeback-plan.js +473 -0
  297. package/dist/esm/modules/formula/materialize/spill-engine.js +38 -0
  298. package/dist/esm/modules/formula/materialize/types.js +29 -0
  299. package/dist/esm/modules/formula/materialize/writeback-plan.js +27 -0
  300. package/dist/esm/modules/formula/runtime/evaluator.js +2291 -0
  301. package/dist/esm/modules/formula/runtime/function-registry.js +840 -0
  302. package/dist/esm/modules/formula/runtime/values.js +385 -0
  303. package/dist/esm/modules/formula/syntax/ast.js +28 -0
  304. package/dist/esm/modules/formula/syntax/parser.js +439 -0
  305. package/dist/esm/modules/formula/syntax/token-types.js +59 -0
  306. package/dist/esm/modules/formula/syntax/tokenizer.js +1074 -0
  307. package/dist/esm/modules/pdf/excel-bridge.js +9 -0
  308. package/dist/iife/excelts.iife.js +2302 -373
  309. package/dist/iife/excelts.iife.js.map +1 -1
  310. package/dist/iife/excelts.iife.min.js +34 -34
  311. package/dist/types/index.browser.d.ts +1 -1
  312. package/dist/types/index.d.ts +1 -1
  313. package/dist/types/modules/excel/cell.d.ts +17 -3
  314. package/dist/types/modules/excel/defined-names.d.ts +96 -1
  315. package/dist/types/modules/excel/image.d.ts +11 -0
  316. package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  317. package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
  318. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  319. package/dist/types/modules/excel/stream/workbook-writer.d.ts +3 -2
  320. package/dist/types/modules/excel/stream/worksheet-writer.d.ts +39 -6
  321. package/dist/types/modules/excel/types.d.ts +133 -2
  322. package/dist/types/modules/excel/utils/col-cache.d.ts +1 -0
  323. package/dist/types/modules/excel/utils/drawing-utils.d.ts +3 -3
  324. package/dist/types/modules/excel/utils/external-link-formula.d.ts +76 -0
  325. package/dist/types/modules/excel/utils/iterate-stream.d.ts +9 -3
  326. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +19 -0
  327. package/dist/types/modules/excel/utils/shared-strings.d.ts +8 -3
  328. package/dist/types/modules/excel/utils/workbook-protection.d.ts +30 -0
  329. package/dist/types/modules/excel/workbook.browser.d.ts +257 -6
  330. package/dist/types/modules/excel/workbook.d.ts +1 -1
  331. package/dist/types/modules/excel/worksheet.d.ts +3 -1
  332. package/dist/types/modules/excel/xlsx/rel-type.d.ts +15 -0
  333. package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  334. package/dist/types/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  335. package/dist/types/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  336. package/dist/types/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  337. package/dist/types/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  338. package/dist/types/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  339. package/dist/types/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  340. package/dist/types/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  341. package/dist/types/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  342. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  343. package/dist/types/modules/excel/xlsx/xlsx.d.ts +7 -4
  344. package/dist/types/modules/formula/compile/address-utils.d.ts +62 -0
  345. package/dist/types/modules/formula/compile/binder.d.ts +42 -0
  346. package/dist/types/modules/formula/compile/bound-ast.d.ts +230 -0
  347. package/dist/types/modules/formula/compile/compiled-formula.d.ts +137 -0
  348. package/dist/types/modules/formula/compile/dependency-analysis.d.ts +93 -0
  349. package/dist/types/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  350. package/dist/types/modules/formula/default-syntax-probe.d.ts +79 -0
  351. package/dist/types/modules/formula/functions/_date-context.d.ts +4 -0
  352. package/dist/types/modules/formula/functions/_shared.d.ts +121 -0
  353. package/dist/types/modules/formula/functions/conditional.d.ts +27 -0
  354. package/dist/types/modules/formula/functions/database.d.ts +37 -0
  355. package/dist/types/modules/formula/functions/date.d.ts +61 -0
  356. package/dist/types/modules/formula/functions/dynamic-array.d.ts +23 -0
  357. package/dist/types/modules/formula/functions/engineering.d.ts +57 -0
  358. package/dist/types/modules/formula/functions/financial.d.ts +202 -0
  359. package/dist/types/modules/formula/functions/lookup.d.ts +18 -0
  360. package/dist/types/modules/formula/functions/math.d.ts +114 -0
  361. package/dist/types/modules/formula/functions/statistical.d.ts +193 -0
  362. package/dist/types/modules/formula/functions/text.d.ts +86 -0
  363. package/dist/types/modules/formula/host-registry.d.ts +53 -0
  364. package/dist/types/modules/formula/index.d.ts +39 -0
  365. package/dist/types/modules/formula/install.d.ts +62 -0
  366. package/dist/types/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  367. package/dist/types/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  368. package/dist/types/modules/formula/integration/calculate-formulas.d.ts +67 -0
  369. package/dist/types/modules/formula/integration/formula-instance.d.ts +64 -0
  370. package/dist/types/modules/formula/integration/workbook-adapter.d.ts +26 -0
  371. package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  372. package/dist/types/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  373. package/dist/types/modules/formula/materialize/spill-engine.d.ts +9 -0
  374. package/dist/types/modules/formula/materialize/types.d.ts +179 -0
  375. package/dist/types/modules/formula/materialize/writeback-plan.d.ts +167 -0
  376. package/dist/types/modules/formula/runtime/evaluator.d.ts +151 -0
  377. package/dist/types/modules/formula/runtime/function-registry.d.ts +47 -0
  378. package/dist/types/modules/formula/runtime/values.d.ts +211 -0
  379. package/dist/types/modules/formula/syntax/ast.d.ts +129 -0
  380. package/dist/types/modules/formula/syntax/parser.d.ts +18 -0
  381. package/dist/types/modules/formula/syntax/token-types.d.ts +153 -0
  382. package/dist/types/modules/formula/syntax/tokenizer.d.ts +10 -0
  383. package/package.json +28 -28
@@ -15,16 +15,19 @@ const zip_parser_1 = require("../../archive/unzip/zip-parser.js");
15
15
  const stream_1 = require("../../archive/zip/stream.js");
16
16
  const errors_1 = require("../errors.js");
17
17
  const drawing_utils_1 = require("../utils/drawing-utils.js");
18
+ const external_link_formula_1 = require("../utils/external-link-formula.js");
18
19
  const ooxml_paths_1 = require("../utils/ooxml-paths.js");
19
20
  const passthrough_manager_1 = require("../utils/passthrough-manager.js");
20
21
  const stream_buf_1 = require("../utils/stream-buf.js");
21
22
  const rel_type_1 = require("./rel-type.js");
23
+ const external_link_xform_1 = require("./xform/book/external-link-xform.js");
22
24
  const workbook_xform_1 = require("./xform/book/workbook-xform.js");
23
25
  const comments_xform_1 = require("./xform/comment/comments-xform.js");
24
26
  const app_xform_1 = require("./xform/core/app-xform.js");
25
27
  const content_types_xform_1 = require("./xform/core/content-types-xform.js");
26
28
  const core_xform_1 = require("./xform/core/core-xform.js");
27
29
  const feature_property_bag_xform_1 = require("./xform/core/feature-property-bag-xform.js");
30
+ const metadata_xform_1 = require("./xform/core/metadata-xform.js");
28
31
  const relationships_xform_1 = require("./xform/core/relationships-xform.js");
29
32
  const ctrl_prop_xform_1 = require("./xform/drawing/ctrl-prop-xform.js");
30
33
  const drawing_xform_1 = require("./xform/drawing/drawing-xform.js");
@@ -245,6 +248,31 @@ class StreamingZipWriterAdapter {
245
248
  }
246
249
  }
247
250
  StreamingZipWriterAdapter.textEncoder = new TextEncoder();
251
+ /**
252
+ * Extract the trailing integer from a workbook-rels Target like
253
+ * `"externalLinks/externalLink12.xml"` (a path relative to `xl/`). Mirror
254
+ * of {@link getExternalLinkIndexFromPath} which takes the full
255
+ * `xl/externalLinks/…` form. Used during reconcile to bridge the
256
+ * workbook.xml.rels entry to the parsed externalLinkN.xml part.
257
+ */
258
+ function externalLinkIndexFromRelTarget(target) {
259
+ const match = /(?:^|\/)externalLink(\d+)[.]xml$/.exec(target);
260
+ return match ? parseInt(match[1], 10) : undefined;
261
+ }
262
+ /**
263
+ * Add `sheetName` to an ExternalLinkModel's `sheetNames` list if it isn't
264
+ * already present. Ordering is preserved — the first-seen sheet wins
265
+ * position 0, which matches what Excel does when writing externalLinks
266
+ * itself.
267
+ */
268
+ function upsertSheet(link, sheetName) {
269
+ if (!sheetName) {
270
+ return;
271
+ }
272
+ if (!link.sheetNames.includes(sheetName)) {
273
+ link.sheetNames.push(sheetName);
274
+ }
275
+ }
248
276
  /**
249
277
  * XLSX class - handles Excel file operations
250
278
  * Works in both Node.js and Browser environments
@@ -313,10 +341,12 @@ class XLSX {
313
341
  await this.addDrawings(zip, model);
314
342
  await this.addTables(zip, model);
315
343
  await this.addPivotTables(zip, model);
344
+ await this.addExternalLinks(zip, model);
316
345
  this.addPassthrough(zip, model);
317
346
  await this.addThemes(zip, model);
318
347
  await this.addStyles(zip, model);
319
348
  await this.addFeaturePropertyBag(zip, model);
349
+ await this.addMetadata(zip, model);
320
350
  await this.addMedia(zip, model);
321
351
  await this.addApp(zip, model);
322
352
  await this.addCore(zip, model);
@@ -366,32 +396,44 @@ class XLSX {
366
396
  return this._finalize(zip);
367
397
  }
368
398
  /**
369
- * Load workbook from buffer/ArrayBuffer/Uint8Array
399
+ * Load a workbook from binary data.
400
+ *
401
+ * Accepted inputs:
402
+ * - `Uint8Array` (and `Buffer`, which is a Uint8Array at runtime)
403
+ * - `ArrayBuffer` / `SharedArrayBuffer`
404
+ * - Any `ArrayBufferView` (DataView, Int8Array, Float32Array, …) — the
405
+ * underlying bytes are reinterpreted as a zip archive
406
+ * - `string` — treated as base64-encoded data when `options.base64 === true`;
407
+ * raw binary cannot be round-tripped through a JS string and is rejected
408
+ * to prevent silent corruption.
370
409
  */
371
410
  async load(data, options) {
372
- let buffer;
373
- // Validate input
374
- const isBuffer = typeof Buffer !== "undefined" ? Buffer.isBuffer(data) : false;
375
- if (!data ||
376
- (typeof data === "object" &&
377
- !isBuffer &&
378
- !(data instanceof Uint8Array) &&
379
- !(data instanceof ArrayBuffer))) {
411
+ if (data === null || data === undefined) {
380
412
  throw new errors_1.ExcelFileError("<input>", "read", "Can't read the data of 'the loaded zip file'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?");
381
413
  }
382
- // Handle base64 input
383
- if (options && options.base64) {
384
- buffer = (0, utils_1.base64ToUint8Array)(data.toString());
414
+ let buffer;
415
+ if (typeof data === "string") {
416
+ // Strings must be base64-encoded — binary zip bytes cannot be round-tripped
417
+ // through a JS string without corruption. Require the explicit opt-in.
418
+ if (!options?.base64) {
419
+ throw new errors_1.ExcelFileError("<input>", "read", "Can't read the data of 'the loaded zip file'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ? " +
420
+ "String input requires options.base64 === true (base64-encoded zip archive).");
421
+ }
422
+ buffer = (0, utils_1.base64ToUint8Array)(data);
423
+ }
424
+ else if (data instanceof Uint8Array) {
425
+ // Covers Buffer (Node) and any typed-array view whose element size is 1.
426
+ buffer = data;
385
427
  }
386
428
  else if (data instanceof ArrayBuffer) {
387
429
  buffer = new Uint8Array(data);
388
430
  }
389
- else if (data instanceof Uint8Array) {
390
- buffer = data;
431
+ else if (ArrayBuffer.isView(data)) {
432
+ // DataView, Int8Array, Float32Array, … — view onto an underlying buffer.
433
+ buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
391
434
  }
392
435
  else {
393
- // Node.js Buffer or other array-like
394
- buffer = new Uint8Array(data);
436
+ throw new errors_1.ExcelFileError("<input>", "read", "Can't read the data of 'the loaded zip file'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?");
395
437
  }
396
438
  return this.loadBuffer(buffer, options);
397
439
  }
@@ -438,7 +480,15 @@ class XLSX {
438
480
  pivotCacheDefinitions: {},
439
481
  pivotCacheRecords: {},
440
482
  // Passthrough storage for unknown/unsupported files (charts, etc.)
441
- passthrough: {}
483
+ passthrough: {},
484
+ // External workbook links — parsed from xl/externalLinks/externalLinkN.xml
485
+ // during _processDefaultEntry, then reconciled into a dense
486
+ // ExternalLinkModel[] by reconcile() using workbookRels + <externalReferences>.
487
+ externalLinksByIndex: {},
488
+ // Raw rels from each externalLinkN.rels file, keyed by index.
489
+ // Contains the actual Target path (e.g. "测试.xlsx", "file:///...")
490
+ // and TargetMode ("External" / "Internal").
491
+ externalLinkRelsByIndex: {}
442
492
  };
443
493
  }
444
494
  /**
@@ -498,8 +548,12 @@ class XLSX {
498
548
  model.definedNames = workbook.definedNames;
499
549
  model.views = workbook.views;
500
550
  model.properties = workbook.properties;
551
+ model.protection = workbook.protection;
501
552
  model.calcProperties = workbook.calcProperties;
502
553
  model.pivotCaches = workbook.pivotCaches;
554
+ // Pass-through the ordered list of <externalReference> rIds. These
555
+ // get resolved into a dense externalLinks[] during reconcile().
556
+ model.externalReferences = workbook.externalReferences;
503
557
  return true;
504
558
  }
505
559
  case ooxml_paths_1.OOXML_PATHS.xlSharedStrings:
@@ -528,6 +582,14 @@ class XLSX {
528
582
  model.styles = new styles_xform_1.StylesXform();
529
583
  await model.styles.parseStream(stream);
530
584
  return true;
585
+ case ooxml_paths_1.OOXML_PATHS.xlMetadata: {
586
+ const metadataXform = new metadata_xform_1.MetadataXform();
587
+ const metadataResult = await metadataXform.parseStream(stream);
588
+ if (metadataResult) {
589
+ model.metadata = metadataResult;
590
+ }
591
+ return true;
592
+ }
531
593
  default:
532
594
  return false;
533
595
  }
@@ -698,12 +760,21 @@ class XLSX {
698
760
  comments: model.comments,
699
761
  tables: model.tables,
700
762
  vmlDrawings: model.vmlDrawings,
701
- pivotTables: model.pivotTablesIndexed
763
+ pivotTables: model.pivotTablesIndexed,
764
+ hasDynamicArrayMetadata: !!model.metadata?.hasDynamicArrays,
765
+ dynamicArrayCmIndices: model.metadata?.dynamicArrayCmIndices
702
766
  };
703
767
  model.worksheets.forEach((worksheet) => {
704
768
  worksheet.relationships = model.worksheetRels[worksheet.sheetNo];
705
769
  worksheetXform.reconcile(worksheet, sheetOptions);
706
770
  });
771
+ // Reconcile external workbook links before workbookRels / externalReferences
772
+ // are dropped. Joins 3 sources:
773
+ // 1. model.externalReferences — ordered list of { rId } from workbook.xml
774
+ // 2. model.workbookRels — maps rId → target path (inside xl/)
775
+ // 3. model.externalLinksByIndex — parsed externalLinkN.xml parts
776
+ // 4. model.externalLinkRelsByIndex — parsed externalLinkN.xml.rels parts
777
+ this._reconcileExternalLinks(model);
707
778
  // delete unnecessary parts
708
779
  delete model.worksheetHash;
709
780
  delete model.worksheetRels;
@@ -719,6 +790,180 @@ class XLSX {
719
790
  delete model.drawingRels;
720
791
  delete model.vmlDrawings;
721
792
  delete model.pivotTableRels;
793
+ delete model.metadata;
794
+ // Internal-only scratch fields consumed by _reconcileExternalLinks.
795
+ delete model.externalReferences;
796
+ delete model.externalLinksByIndex;
797
+ delete model.externalLinkRelsByIndex;
798
+ }
799
+ /**
800
+ * Join the three on-disk sources that together describe external workbook
801
+ * references into a single dense `model.externalLinks: ExternalLinkModel[]`.
802
+ *
803
+ * Sources:
804
+ * - `<externalReferences>` list in workbook.xml (declaration order)
805
+ * - `xl/_rels/workbook.xml.rels` (rId → internal path)
806
+ * - `xl/externalLinks/externalLink{N}.xml` (sheet names, cached values)
807
+ * - `xl/externalLinks/_rels/externalLink{N}.xml.rels` (target, TargetMode)
808
+ *
809
+ * The 1-based index of each resulting ExternalLinkModel matches the `[N]`
810
+ * used in formula strings — this is the single source of truth formula
811
+ * code should rely on.
812
+ */
813
+ _reconcileExternalLinks(model) {
814
+ const refs = model.externalReferences;
815
+ if (!refs || refs.length === 0) {
816
+ // Even when workbook.xml has no <externalReferences>, we may still
817
+ // have parsed externalLink parts (e.g. orphaned files); those are
818
+ // dropped silently rather than generating synthesised indices.
819
+ if (!model.externalLinks) {
820
+ model.externalLinks = [];
821
+ }
822
+ return;
823
+ }
824
+ const rels = (model.workbookRels ?? []);
825
+ const relById = new Map();
826
+ for (const rel of rels) {
827
+ if (rel.Type === rel_type_1.RelType.ExternalLink) {
828
+ relById.set(rel.Id, rel);
829
+ }
830
+ }
831
+ const externalLinks = [];
832
+ for (let i = 0; i < refs.length; i++) {
833
+ const ref = refs[i];
834
+ const rel = relById.get(ref.rId);
835
+ if (!rel) {
836
+ // Broken reference — <externalReference> points at an rId that is
837
+ // not of type ExternalLink. We skip silently; the formula engine
838
+ // will see the now-missing index and fall back to #REF! as before.
839
+ continue;
840
+ }
841
+ // The rel Target is a path inside xl/ like "externalLinks/externalLink1.xml".
842
+ // Extract the trailing index to look up the parsed part.
843
+ const partIndex = externalLinkIndexFromRelTarget(rel.Target);
844
+ if (partIndex === undefined) {
845
+ continue;
846
+ }
847
+ const parsed = model.externalLinksByIndex[partIndex];
848
+ const partRels = (model.externalLinkRelsByIndex[partIndex] ?? []);
849
+ // Locate the externalLinkPath rel (should be unique within a part).
850
+ const pathRel = partRels.find(r => r.Type === rel_type_1.RelType.ExternalLinkPath) ??
851
+ partRels.find(r => r.TargetMode === "External");
852
+ externalLinks.push({
853
+ index: i + 1,
854
+ rId: ref.rId,
855
+ target: pathRel?.Target ?? "",
856
+ targetMode: pathRel?.TargetMode ?? "External",
857
+ sheetNames: parsed?.sheetNames ?? [],
858
+ cachedValues: parsed?.cachedValues ?? {}
859
+ });
860
+ }
861
+ model.externalLinks = externalLinks;
862
+ }
863
+ /**
864
+ * Write-time pass that brings the workbook model into a shape the writer
865
+ * can serialise cleanly. Two concerns:
866
+ *
867
+ * 1. Build the final external-link list for this write, combining
868
+ * user-declared links (`wb.externalLinks`) with auto-discovered
869
+ * ones from previous writes (cached on the Workbook). The result
870
+ * is assigned to `model.externalLinks` and consumed by the writer;
871
+ * `wb.externalLinks` is **not** modified.
872
+ *
873
+ * 2. Scan every formula cell for `[Book]Sheet!` prefixes. Filename-form
874
+ * references that don't match an existing link trigger
875
+ * `_recordAutoExternalLink()` on the Workbook, which adds the target
876
+ * to the private writer cache (so subsequent writes are fixed-point
877
+ * stable) but leaves `wb.externalLinks` untouched.
878
+ *
879
+ * 3. Rewrite every external-ref formula so it uses the numeric `[N]`
880
+ * form, the canonical OOXML storage form. This mutation lands on
881
+ * the cell's model object — matching the library's existing
882
+ * write-time pattern for `ssId`, `styleId`, `si`, and `cm`.
883
+ * Subsequent writes see the `[N]` form directly and resolve it
884
+ * against `model.externalLinks`, giving idempotent output.
885
+ */
886
+ _normaliseExternalLinks(model) {
887
+ // Start from user-declared links, honouring their declaration order.
888
+ const links = this.workbook._collectExternalLinksForWrite();
889
+ // Fast lookup: case-insensitive target → link object in `links`.
890
+ const byTarget = new Map();
891
+ for (const link of links) {
892
+ if (link.target) {
893
+ byTarget.set(link.target.toLowerCase(), link);
894
+ }
895
+ }
896
+ const scratch = { links, byTarget, workbook: this.workbook };
897
+ for (const worksheet of model.worksheets ?? []) {
898
+ for (const row of worksheet.rows ?? []) {
899
+ for (const cell of row.cells ?? []) {
900
+ if (typeof cell?.formula === "string" && cell.formula.length > 0) {
901
+ cell.formula = this._normaliseFormulaExternalRefs(cell.formula, scratch);
902
+ }
903
+ if (typeof cell?.sharedFormula === "string" && cell.sharedFormula.length > 0) {
904
+ // Shared-formula clones typically carry the master's *address*
905
+ // here, not a formula body — they won't match the ref regex.
906
+ // Masters carry the formula on `.formula` (handled above).
907
+ // We rewrite defensively in case a caller stored an actual
908
+ // formula string here.
909
+ cell.sharedFormula = this._normaliseFormulaExternalRefs(cell.sharedFormula, scratch);
910
+ }
911
+ }
912
+ }
913
+ }
914
+ model.externalLinks = links;
915
+ }
916
+ /**
917
+ * Rewrite a single formula so every external-ref prefix uses the numeric
918
+ * `[N]` form. When an unknown filename-form reference is found we record
919
+ * it on the workbook's private writer cache (so the next write can still
920
+ * resolve it) and append a local link to `scratch.links` so subsequent
921
+ * refs in the same formula see the freshly-assigned index.
922
+ */
923
+ _normaliseFormulaExternalRefs(formula, scratch) {
924
+ // rewriteExternalRefs internally calls findExternalRefs and returns
925
+ // the original string unchanged when there are no matches — no need
926
+ // for a separate guard scan here.
927
+ return (0, external_link_formula_1.rewriteExternalRefs)(formula, ref => {
928
+ // Numeric ref: accept if it resolves, otherwise preserve verbatim so
929
+ // Excel surfaces `#REF!` at load time — same as the old behaviour
930
+ // for truly broken references.
931
+ if (ref.numeric) {
932
+ if (ref.index !== null && ref.index >= 1 && ref.index <= scratch.links.length) {
933
+ upsertSheet(scratch.links[ref.index - 1], ref.sheet);
934
+ return ref.index;
935
+ }
936
+ return null;
937
+ }
938
+ // Filename form — look up or auto-register.
939
+ const key = ref.workbook.toLowerCase();
940
+ let link = scratch.byTarget.get(key);
941
+ if (!link) {
942
+ const index = scratch.workbook._recordAutoExternalLink(ref.workbook, ref.sheet);
943
+ link = {
944
+ index,
945
+ target: ref.workbook,
946
+ targetMode: "External",
947
+ sheetNames: ref.sheet ? [ref.sheet] : [],
948
+ cachedValues: {}
949
+ };
950
+ // Keep the local writer list dense: insert at its future position.
951
+ // `_recordAutoExternalLink` guarantees `index` is user.length + cache.size
952
+ // at the time of insertion, which equals `scratch.links.length + 1`
953
+ // whenever we walk formulas sequentially.
954
+ scratch.links.push(link);
955
+ scratch.byTarget.set(key, link);
956
+ }
957
+ else {
958
+ upsertSheet(link, ref.sheet);
959
+ // Keep the workbook cache's sheetNames in sync so subsequent
960
+ // writes see the accumulated set.
961
+ if (ref.sheet) {
962
+ scratch.workbook._recordAutoExternalLink(ref.workbook, ref.sheet);
963
+ }
964
+ }
965
+ return link.index;
966
+ });
722
967
  }
723
968
  /**
724
969
  * Reconcile pivot tables by linking them to worksheets and their cache data.
@@ -974,6 +1219,29 @@ class XLSX {
974
1219
  model.pivotCacheRecords[name] = cacheRecords;
975
1220
  }
976
1221
  }
1222
+ /**
1223
+ * Parse `xl/externalLinks/externalLink{N}.xml` into the intermediate
1224
+ * ParsedExternalLink shape. Reconciliation (joining with the rels file
1225
+ * and the workbook's `<externalReferences>` list) happens later in
1226
+ * {@link reconcile}.
1227
+ */
1228
+ async _processExternalLinkEntry(stream, model, index) {
1229
+ const xform = new external_link_xform_1.ExternalLinkXform();
1230
+ const parsed = await xform.parseStream(stream);
1231
+ if (parsed) {
1232
+ model.externalLinksByIndex[index] = parsed;
1233
+ }
1234
+ }
1235
+ /**
1236
+ * Parse `xl/externalLinks/_rels/externalLink{N}.xml.rels`. The Target /
1237
+ * TargetMode carried here is what Excel uses to locate the actual external
1238
+ * file at open time, so we must preserve it verbatim (including relative
1239
+ * paths like `"测试.xlsx"`).
1240
+ */
1241
+ async _processExternalLinkRelsEntry(stream, model, index) {
1242
+ const relationships = await this.parseRels(stream);
1243
+ model.externalLinkRelsByIndex[index] = relationships ?? [];
1244
+ }
977
1245
  // ===========================================================================
978
1246
  // loadFromFiles - shared logic for loading from pre-extracted ZIP data
979
1247
  // ===========================================================================
@@ -1085,6 +1353,20 @@ class XLSX {
1085
1353
  await this._processPivotCacheRecordsEntry(stream, model, pivotCacheRecordsName);
1086
1354
  return true;
1087
1355
  }
1356
+ // External workbook links: xl/externalLinks/externalLinkN.xml and its
1357
+ // sibling _rels file. Both parts are required to reconstruct the
1358
+ // ExternalLinkModel (the .xml carries sheet names + cached values; the
1359
+ // .rels carries the target path and TargetMode).
1360
+ const externalLinkIndex = (0, ooxml_paths_1.getExternalLinkIndexFromPath)(entryName);
1361
+ if (externalLinkIndex !== undefined) {
1362
+ await this._processExternalLinkEntry(stream, model, externalLinkIndex);
1363
+ return true;
1364
+ }
1365
+ const externalLinkRelsIndex = (0, ooxml_paths_1.getExternalLinkIndexFromRelsPath)(entryName);
1366
+ if (externalLinkRelsIndex !== undefined) {
1367
+ await this._processExternalLinkRelsEntry(stream, model, externalLinkRelsIndex);
1368
+ return true;
1369
+ }
1088
1370
  // Store passthrough files (charts, etc.) for preservation
1089
1371
  if (passthrough_manager_1.PassthroughManager.isPassthroughPath(entryName)) {
1090
1372
  // If raw data is available (loadFromFiles path), use it directly
@@ -1166,6 +1448,14 @@ class XLSX {
1166
1448
  Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookFeaturePropertyBag
1167
1449
  });
1168
1450
  }
1451
+ // Add metadata relationship for dynamic array formulas
1452
+ if (model.hasDynamicArrayFormulas) {
1453
+ relationships.push({
1454
+ Id: `rId${count++}`,
1455
+ Type: XLSX.RelType.SheetMetadata,
1456
+ Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookMetadata
1457
+ });
1458
+ }
1169
1459
  // R9-B6: Deduplicate pivot cache relationships by cacheId. When multiple pivot
1170
1460
  // tables share the same cache, only one workbook relationship should be created.
1171
1461
  // Also assigns rId to each pivot table (R9-B7: typed on PivotTable interface).
@@ -1195,6 +1485,26 @@ class XLSX {
1195
1485
  Target: (0, ooxml_paths_1.worksheetRelTarget)(worksheet.fileIndex)
1196
1486
  });
1197
1487
  });
1488
+ // External workbook link rels are written AFTER worksheets on purpose:
1489
+ // Excel tolerates either order, but stable ordering (worksheets then
1490
+ // externalLinks) keeps the emitted workbook.xml.rels diff-friendly for
1491
+ // round-trip tests. Each external link becomes a regular Relationship
1492
+ // entry targeting `externalLinks/externalLinkN.xml` inside `xl/`; the
1493
+ // actual external file path is pointed at by the nested
1494
+ // externalLinkN.xml.rels part written by addExternalLinks().
1495
+ //
1496
+ // The list items here are the deep-copies produced by
1497
+ // `_normaliseExternalLinks` — assigning `link.rId` is safe and does not
1498
+ // leak into the user's Workbook.externalLinks.
1499
+ const externalLinks = (model.externalLinks ?? []);
1500
+ for (const link of externalLinks) {
1501
+ link.rId = `rId${count++}`;
1502
+ relationships.push({
1503
+ Id: link.rId,
1504
+ Type: XLSX.RelType.ExternalLink,
1505
+ Target: (0, ooxml_paths_1.externalLinkRelTargetFromWorkbook)(link.index)
1506
+ });
1507
+ }
1198
1508
  const xform = new relationships_xform_1.RelationshipsXform();
1199
1509
  await this._renderToZip(zip, ooxml_paths_1.OOXML_PATHS.xlWorkbookRels, xform, relationships);
1200
1510
  }
@@ -1204,6 +1514,14 @@ class XLSX {
1204
1514
  }
1205
1515
  await this._renderToZip(zip, ooxml_paths_1.OOXML_PATHS.xlFeaturePropertyBag, new feature_property_bag_xform_1.FeaturePropertyBagXform(), {});
1206
1516
  }
1517
+ async addMetadata(zip, model) {
1518
+ if (!model.hasDynamicArrayFormulas) {
1519
+ return;
1520
+ }
1521
+ await this._renderToZip(zip, ooxml_paths_1.OOXML_PATHS.xlMetadata, new metadata_xform_1.MetadataXform(), {
1522
+ dynamicArrayCount: model.dynamicArrayCount
1523
+ });
1524
+ }
1207
1525
  async addSharedStrings(zip, model) {
1208
1526
  if (model.sharedStrings && model.sharedStrings.count) {
1209
1527
  await this._renderToZip(zip, ooxml_paths_1.OOXML_PATHS.xlSharedStrings, model.sharedStrings, model.sharedStrings.model);
@@ -1319,6 +1637,41 @@ class XLSX {
1319
1637
  }
1320
1638
  }
1321
1639
  }
1640
+ /**
1641
+ * Write every external workbook reference into the archive. For each
1642
+ * {@link ExternalLinkModel} in `model.externalLinks` we emit two files:
1643
+ *
1644
+ * xl/externalLinks/externalLink{index}.xml — sheet names + cache
1645
+ * xl/externalLinks/_rels/externalLink{index}.xml.rels — target path
1646
+ *
1647
+ * The target-path rel carries `TargetMode="External"` with a **bare
1648
+ * relative** `Target` whenever the user supplied one. This is the single
1649
+ * line that makes Office / WPS resolve the referenced workbook relative
1650
+ * to the current file's directory (not the `%USERPROFILE%\Documents`
1651
+ * fallback) — the root of the behaviour reported in exceljs#3039.
1652
+ */
1653
+ async addExternalLinks(zip, model) {
1654
+ const externalLinks = (model.externalLinks ?? []);
1655
+ if (externalLinks.length === 0) {
1656
+ return;
1657
+ }
1658
+ const externalLinkXform = new external_link_xform_1.ExternalLinkXform();
1659
+ const relsXform = new relationships_xform_1.RelationshipsXform();
1660
+ for (const link of externalLinks) {
1661
+ await this._renderToZip(zip, (0, ooxml_paths_1.externalLinkPath)(link.index), externalLinkXform, link);
1662
+ // Always rId1 — the externalLink part only ever has a single rel.
1663
+ // `TargetMode="External"` is what flags Office to look the file up
1664
+ // at workbook-open time rather than embed it.
1665
+ await this._renderToZip(zip, (0, ooxml_paths_1.externalLinkRelsPath)(link.index), relsXform, [
1666
+ {
1667
+ Id: "rId1",
1668
+ Type: XLSX.RelType.ExternalLinkPath,
1669
+ Target: link.target,
1670
+ TargetMode: link.targetMode ?? "External"
1671
+ }
1672
+ ]);
1673
+ }
1674
+ }
1322
1675
  /**
1323
1676
  * Write passthrough files (charts, etc.) that were preserved during read.
1324
1677
  * These files are written back unchanged to preserve unsupported features.
@@ -1412,6 +1765,18 @@ class XLSX {
1412
1765
  const workbookXform = new workbook_xform_1.WorkbookXform();
1413
1766
  const worksheetXform = new worksheet_xform_1.WorkSheetXform();
1414
1767
  workbookXform.prepare(model);
1768
+ // Normalise external-workbook references before any formula rendering.
1769
+ // Two jobs:
1770
+ // 1. Scan every formula cell and make sure each referenced workbook
1771
+ // has a matching ExternalLinkModel in `model.externalLinks`, with
1772
+ // a stable 1-based index.
1773
+ // 2. Rewrite formula strings from `[filename.xlsx]Sheet!A1` to
1774
+ // `[N]Sheet!A1`, which is the canonical on-disk form Excel
1775
+ // expects inside `<f>` elements.
1776
+ //
1777
+ // Done once up-front (not per cell) so the index assignment is
1778
+ // deterministic and every cell sees the final externalLinks list.
1779
+ this._normaliseExternalLinks(model);
1415
1780
  const worksheetOptions = {
1416
1781
  sharedStrings: model.sharedStrings,
1417
1782
  styles: model.styles,
@@ -1425,6 +1790,7 @@ class XLSX {
1425
1790
  model.hasHeaderWatermark = false;
1426
1791
  let tableCount = 0;
1427
1792
  model.tables = [];
1793
+ const tableNameMap = new Map(); // name (lowercase) → worksheet name
1428
1794
  model.worksheets.forEach((worksheet, index) => {
1429
1795
  // Assign fileIndex early so that worksheet-xform.prepare() can use it
1430
1796
  // for comment/VML relationship targets and content type names.
@@ -1432,6 +1798,16 @@ class XLSX {
1432
1798
  // using the same fileIndex.
1433
1799
  worksheet.fileIndex = index + 1;
1434
1800
  worksheet.tables.forEach((table) => {
1801
+ // OOXML requires table names to be unique across the entire workbook
1802
+ // (case-insensitive). Detect duplicates early to produce a clear error
1803
+ // instead of generating a corrupt file that Excel must repair.
1804
+ const nameKey = table.name.toLowerCase();
1805
+ const existingSheet = tableNameMap.get(nameKey);
1806
+ if (existingSheet !== undefined) {
1807
+ throw new errors_1.TableError(`Duplicate table name "${table.name}": already used in worksheet "${existingSheet}". ` +
1808
+ `Table names must be unique across the entire workbook (case-insensitive).`);
1809
+ }
1810
+ tableNameMap.set(nameKey, worksheet.name);
1435
1811
  tableCount++;
1436
1812
  table.target = `table${tableCount}.xml`;
1437
1813
  table.id = tableCount;
@@ -1441,6 +1817,20 @@ class XLSX {
1441
1817
  });
1442
1818
  // ContentTypesXform expects this flag
1443
1819
  model.hasCheckboxes = model.styles.hasCheckboxes;
1820
+ // Scan all worksheets for dynamic array formulas.
1821
+ // cm=1 is assigned later by cell-xform.prepare() during worksheet rendering.
1822
+ let dynamicArrayCount = 0;
1823
+ model.worksheets.forEach((worksheet) => {
1824
+ (worksheet.rows ?? []).forEach((row) => {
1825
+ (row.cells ?? []).forEach((cell) => {
1826
+ if (cell.isDynamicArray) {
1827
+ dynamicArrayCount++;
1828
+ }
1829
+ });
1830
+ });
1831
+ });
1832
+ model.hasDynamicArrayFormulas = dynamicArrayCount > 0;
1833
+ model.dynamicArrayCount = dynamicArrayCount;
1444
1834
  // Propagate header watermark flag from worksheet prepare options
1445
1835
  if (worksheetOptions.hasHeaderWatermark) {
1446
1836
  model.hasHeaderWatermark = true;
@@ -103,7 +103,7 @@ class XLSX extends xlsx_browser_1.XLSX {
103
103
  }
104
104
  }
105
105
  catch (e) {
106
- callback(e);
106
+ callback((0, errors_2.toError)(e));
107
107
  }
108
108
  },
109
109
  final(callback) {
@@ -112,13 +112,13 @@ class XLSX extends xlsx_browser_1.XLSX {
112
112
  callback();
113
113
  }
114
114
  catch (e) {
115
- callback(e);
115
+ callback((0, errors_2.toError)(e));
116
116
  }
117
117
  }
118
118
  });
119
119
  const onParserError = (err) => {
120
120
  try {
121
- sink.destroy(err);
121
+ sink.destroy((0, errors_2.toError)(err));
122
122
  }
123
123
  catch {
124
124
  // ignore
@@ -130,8 +130,7 @@ class XLSX extends xlsx_browser_1.XLSX {
130
130
  for await (const entry of XLSX.iterateZipEntries(parser)) {
131
131
  entry.on("error", swallowError);
132
132
  const drain = async () => {
133
- const anyEntry = entry;
134
- if (anyEntry?.readableEnded || anyEntry?.destroyed) {
133
+ if (entry.readableEnded || entry.destroyed) {
135
134
  return;
136
135
  }
137
136
  const draining = entry.autodrain();