@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,12 +15,14 @@ import { filterDrawingAnchors } from "../utils/drawing-utils.js";
15
15
  import { drawingPath, drawingRelsPath, mediaPath, OOXML_PATHS, OOXML_REL_TARGETS, worksheetRelTarget } from "../utils/ooxml-paths.js";
16
16
  import { SharedStrings } from "../utils/shared-strings.js";
17
17
  import { StreamBuf } from "../utils/stream-buf.js";
18
+ import { buildWorkbookProtection } from "../utils/workbook-protection.js";
18
19
  import { RelType } from "../xlsx/rel-type.js";
19
20
  import { WorkbookXform } from "../xlsx/xform/book/workbook-xform.js";
20
21
  import { AppXform } from "../xlsx/xform/core/app-xform.js";
21
22
  import { ContentTypesXform } from "../xlsx/xform/core/content-types-xform.js";
22
23
  import { CoreXform } from "../xlsx/xform/core/core-xform.js";
23
24
  import { FeaturePropertyBagXform } from "../xlsx/xform/core/feature-property-bag-xform.js";
25
+ import { MetadataXform } from "../xlsx/xform/core/metadata-xform.js";
24
26
  import { RelationshipsXform } from "../xlsx/xform/core/relationships-xform.js";
25
27
  import { DrawingXform } from "../xlsx/xform/drawing/drawing-xform.js";
26
28
  import { SharedStringsXform } from "../xlsx/xform/strings/shared-strings-xform.js";
@@ -53,6 +55,7 @@ export class WorkbookWriterBase {
53
55
  this.compressionLevel = Math.max(0, Math.min(9, level));
54
56
  this.media = [];
55
57
  this.commentRefs = [];
58
+ this.dynamicArrayCount = 0;
56
59
  this._trueStreaming = options.trueStreaming ?? false;
57
60
  // Create Zip instance
58
61
  this.zip = new Zip((err, data, final) => {
@@ -87,6 +90,18 @@ export class WorkbookWriterBase {
87
90
  get definedNames() {
88
91
  return this._definedNames;
89
92
  }
93
+ /**
94
+ * The default font for the workbook (fontId=0 / "Normal" style).
95
+ * Must be set before any worksheet rows are committed.
96
+ */
97
+ get defaultFont() {
98
+ return this.styles.defaultFont;
99
+ }
100
+ set defaultFont(font) {
101
+ if (this.styles.setDefaultFont) {
102
+ this.styles.setDefaultFont(font);
103
+ }
104
+ }
90
105
  /** @internal */
91
106
  _openStream(path) {
92
107
  const stream = new StreamBuf({
@@ -147,6 +162,7 @@ export class WorkbookWriterBase {
147
162
  this.addSharedStrings(),
148
163
  this.addStyles(),
149
164
  this.addFeaturePropertyBag(),
165
+ this.addMetadata(),
150
166
  this.addWorkbookRels()
151
167
  ]);
152
168
  await this.addWorkbook();
@@ -173,6 +189,19 @@ export class WorkbookWriterBase {
173
189
  getImage(id) {
174
190
  return this.media[id];
175
191
  }
192
+ /**
193
+ * Protect the workbook structure with an optional password.
194
+ * Prevents users from adding, deleting, renaming, moving, or copying worksheets.
195
+ */
196
+ async protect(password, options) {
197
+ this.protection = await buildWorkbookProtection(password, options);
198
+ }
199
+ /**
200
+ * Remove workbook structure protection.
201
+ */
202
+ unprotect() {
203
+ this.protection = undefined;
204
+ }
176
205
  addWorksheet(name, options) {
177
206
  const opts = options || {};
178
207
  const useSharedStrings = opts.useSharedStrings !== undefined ? opts.useSharedStrings : this.useSharedStrings;
@@ -250,7 +279,8 @@ export class WorkbookWriterBase {
250
279
  commentRefs: this.commentRefs,
251
280
  media: this.media,
252
281
  drawings,
253
- hasCheckboxes: this.styles.hasCheckboxes
282
+ hasCheckboxes: this.styles.hasCheckboxes,
283
+ hasDynamicArrayFormulas: this.dynamicArrayCount > 0
254
284
  };
255
285
  const xform = new ContentTypesXform();
256
286
  this._addFile(xform.toXml(model), OOXML_PATHS.contentTypes);
@@ -336,6 +366,14 @@ export class WorkbookWriterBase {
336
366
  }
337
367
  return Promise.resolve();
338
368
  }
369
+ addMetadata() {
370
+ if (this.dynamicArrayCount <= 0) {
371
+ return Promise.resolve();
372
+ }
373
+ const xform = new MetadataXform();
374
+ this._addFile(xform.toXml({ dynamicArrayCount: this.dynamicArrayCount }), OOXML_PATHS.xlMetadata);
375
+ return Promise.resolve();
376
+ }
339
377
  addWorkbookRels() {
340
378
  let count = 1;
341
379
  const relationships = [
@@ -357,6 +395,14 @@ export class WorkbookWriterBase {
357
395
  Target: OOXML_REL_TARGETS.workbookFeaturePropertyBag
358
396
  });
359
397
  }
398
+ // Add metadata relationship for dynamic array formulas
399
+ if (this.dynamicArrayCount > 0) {
400
+ relationships.push({
401
+ Id: `rId${count++}`,
402
+ Type: RelType.SheetMetadata,
403
+ Target: OOXML_REL_TARGETS.workbookMetadata
404
+ });
405
+ }
360
406
  this._worksheets.forEach(ws => {
361
407
  if (ws) {
362
408
  ws.rId = `rId${count++}`;
@@ -379,6 +425,7 @@ export class WorkbookWriterBase {
379
425
  definedNames: this._definedNames.model,
380
426
  views: this.views,
381
427
  properties: {},
428
+ protection: this.protection,
382
429
  calcProperties: {}
383
430
  };
384
431
  return new Promise(resolve => {
@@ -187,10 +187,12 @@ class WorksheetReader extends EventEmitter {
187
187
  case "c":
188
188
  if (row) {
189
189
  const styleAttr = node.attributes.s;
190
+ const cmAttr = node.attributes.cm;
190
191
  c = {
191
192
  ref: node.attributes.r,
192
193
  s: styleAttr !== undefined ? parseInt(styleAttr, 10) : undefined,
193
- t: node.attributes.t
194
+ t: node.attributes.t,
195
+ cm: cmAttr !== undefined ? parseInt(cmAttr, 10) : undefined
194
196
  };
195
197
  }
196
198
  break;
@@ -295,6 +297,20 @@ class WorksheetReader extends EventEmitter {
295
297
  cellValue.result = parseFloat(c.v.text);
296
298
  }
297
299
  }
300
+ // Check if this cell is a dynamic array formula via cm → metadata mapping.
301
+ // Uses the precise dynamicArrayCmIndices set from WorkbookReaderBase,
302
+ // falling back to the coarser hasDynamicArrayMetadata boolean.
303
+ if (c.cm !== undefined) {
304
+ const { workbook: wb } = this;
305
+ if (wb.dynamicArrayCmIndices) {
306
+ if (wb.dynamicArrayCmIndices.has(c.cm)) {
307
+ cellValue.isDynamicArray = true;
308
+ }
309
+ }
310
+ else if (wb.hasDynamicArrayMetadata) {
311
+ cellValue.isDynamicArray = true;
312
+ }
313
+ }
298
314
  cell.value = cellValue;
299
315
  }
300
316
  else if (c.v) {
@@ -26,6 +26,7 @@ import { DrawingXform as DrawingPartXform } from "../xlsx/xform/sheet/drawing-xf
26
26
  import { ExtLstXform } from "../xlsx/xform/sheet/ext-lst-xform.js";
27
27
  import { HeaderFooterXform } from "../xlsx/xform/sheet/header-footer-xform.js";
28
28
  import { HyperlinkXform } from "../xlsx/xform/sheet/hyperlink-xform.js";
29
+ import { IgnoredErrorsXform } from "../xlsx/xform/sheet/ignored-errors-xform.js";
29
30
  import { PageMarginsXform } from "../xlsx/xform/sheet/page-margins-xform.js";
30
31
  import { PageSetupXform } from "../xlsx/xform/sheet/page-setup-xform.js";
31
32
  import { PictureXform } from "../xlsx/xform/sheet/picture-xform.js";
@@ -60,6 +61,7 @@ const xform = {
60
61
  drawing: new DrawingPartXform(),
61
62
  conditionalFormattings: new ConditionalFormattingsXform(),
62
63
  extLst: new ExtLstXform(),
64
+ ignoredErrors: new IgnoredErrorsXform(),
63
65
  headerFooter: new HeaderFooterXform(),
64
66
  rowBreaks: new RowBreaksXform(),
65
67
  colBreaks: new ColBreaksXform()
@@ -100,6 +102,8 @@ class WorksheetWriter {
100
102
  this._siFormulae = 0;
101
103
  // keep a record of conditionalFormattings
102
104
  this.conditionalFormatting = [];
105
+ // ignored errors (suppress green triangles in Excel)
106
+ this.ignoredErrors = [];
103
107
  // keep a record of all row and column pageBreaks
104
108
  this.rowBreaks = [];
105
109
  this.colBreaks = [];
@@ -212,6 +216,8 @@ class WorksheetWriter {
212
216
  this._writeBackground(); // Note: must be after drawing
213
217
  // Legacy Data tag for comments
214
218
  this._writeLegacyData();
219
+ // ignoredErrors must be before extLst
220
+ this._writeIgnoredErrors();
215
221
  // extLst must be the last child element before </worksheet>
216
222
  this._writeExtLst();
217
223
  this._writeCloseWorksheet();
@@ -529,18 +535,33 @@ class WorksheetWriter {
529
535
  }
530
536
  throw new Error(`Invalid image range: "${range}". Expected a range like "A1:C3".`);
531
537
  }
532
- const tl = new Anchor(this, range.tl, 0).model;
533
- const br = range.br ? new Anchor(this, range.br, 0).model : undefined;
538
+ // Absolute positioning (pos + ext, no cell anchors)
539
+ if ("pos" in range && range.pos) {
540
+ return {
541
+ type: "image",
542
+ imageId,
543
+ range: {
544
+ tl: { nativeCol: 0, nativeColOff: 0, nativeRow: 0, nativeRowOff: 0 },
545
+ ext: range.ext,
546
+ pos: range.pos
547
+ },
548
+ hyperlinks: range.hyperlinks
549
+ };
550
+ }
551
+ // Cell-based positioning (tl/br anchors)
552
+ const cellRange = range;
553
+ const tl = new Anchor(this, cellRange.tl, 0).model;
554
+ const br = cellRange.br ? new Anchor(this, cellRange.br, 0).model : undefined;
534
555
  return {
535
556
  type: "image",
536
557
  imageId,
537
558
  range: {
538
559
  tl,
539
560
  br,
540
- ext: range.ext,
541
- editAs: range.editAs
561
+ ext: cellRange.ext,
562
+ editAs: cellRange.editAs
542
563
  },
543
- hyperlinks: range.hyperlinks
564
+ hyperlinks: cellRange.hyperlinks
544
565
  };
545
566
  }
546
567
  // =========================================================================
@@ -617,6 +638,9 @@ class WorksheetWriter {
617
638
  }
618
639
  if (row.hasValues || row.height != null) {
619
640
  const { model } = row;
641
+ if (!model) {
642
+ return;
643
+ }
620
644
  const options = {
621
645
  styles: this._workbook.styles,
622
646
  sharedStrings: this.useSharedStrings ? this._workbook.sharedStrings : undefined,
@@ -628,6 +652,14 @@ class WorksheetWriter {
628
652
  };
629
653
  xform.row.prepare(model, options);
630
654
  this.stream.write(xform.row.toXml(model));
655
+ // Count dynamic array formula cells for metadata generation
656
+ if (model.cells) {
657
+ for (const cell of model.cells) {
658
+ if (cell && cell.isDynamicArray) {
659
+ this._workbook.dynamicArrayCount++;
660
+ }
661
+ }
662
+ }
631
663
  if (options.comments.length) {
632
664
  this.hasComments = true;
633
665
  this._sheetCommentsWriter.addComments(options.comments);
@@ -680,6 +712,11 @@ class WorksheetWriter {
680
712
  const model = { conditionalFormattings: this.conditionalFormatting };
681
713
  this.stream.write(xform.extLst.toXml(model));
682
714
  }
715
+ _writeIgnoredErrors() {
716
+ if (this.ignoredErrors.length > 0) {
717
+ this.stream.write(xform.ignoredErrors.toXml(this.ignoredErrors));
718
+ }
719
+ }
683
720
  _writeRowBreaks() {
684
721
  this.stream.write(xform.rowBreaks.toXml(this.rowBreaks));
685
722
  }
@@ -753,6 +790,9 @@ class WorksheetWriter {
753
790
  if (this._background) {
754
791
  if (this._background.imageId !== undefined) {
755
792
  const image = this._workbook.getImage(this._background.imageId);
793
+ if (!image) {
794
+ return;
795
+ }
756
796
  const pictureId = this._sheetRelsWriter.addMedia({
757
797
  Target: mediaRelTargetFromRels(image.name),
758
798
  Type: RelType.Image
@@ -535,14 +535,27 @@ class Table {
535
535
  this._ensureStyle().showColumnStripes = value;
536
536
  }
537
537
  }
538
+ // SUBTOTAL function codes per OOXML/Excel:
539
+ // 1/101=AVERAGE, 2/102=COUNT, 3/103=COUNTA, 4/104=MAX, 5/105=MIN,
540
+ // 6/106=PRODUCT, 7/107=STDEV, 8/108=STDEVP, 9/109=SUM, 10/110=VAR, 11/111=VARP.
541
+ // The 1xx variants also ignore manually hidden rows — Excel always uses
542
+ // these for totals-row injection. OOXML totalsRowFunction names map to:
543
+ // average → 1 (AVERAGE)
544
+ // countNums → 2 (COUNT, numeric-only)
545
+ // count → 3 (COUNTA)
546
+ // max → 4
547
+ // min → 5
548
+ // stdDev → 7 (sample std dev, per Excel's totals UI)
549
+ // var → 10 (sample variance, per Excel's totals UI)
550
+ // sum → 9
538
551
  Table.SUBTOTAL_FUNCTIONS = {
539
552
  average: 101,
540
553
  countNums: 102,
541
554
  count: 103,
542
555
  max: 104,
543
556
  min: 105,
544
- stdDev: 106,
545
- var: 107,
557
+ stdDev: 107,
558
+ var: 110,
546
559
  sum: 109
547
560
  };
548
561
  export { Table, sanitizeTableName };
@@ -299,6 +299,21 @@ const colCache = {
299
299
  throw new InvalidAddressError(String(args.length), "Can only encode with 2 or 4 arguments");
300
300
  }
301
301
  },
302
+ /**
303
+ * Compare two cell addresses by column then row (numeric order).
304
+ *
305
+ * Returns a negative number if `a` should come before `b`,
306
+ * a positive number if `a` should come after `b`, or zero if equal.
307
+ *
308
+ * This avoids the pitfalls of `localeCompare` which treats addresses
309
+ * as strings (e.g. "C10" < "C2") instead of comparing their numeric
310
+ * column and row components.
311
+ */
312
+ compareAddress(a, b) {
313
+ const addrA = colCache.decodeAddress(a);
314
+ const addrB = colCache.decodeAddress(b);
315
+ return addrA.col - addrB.col || addrA.row - addrB.row;
316
+ },
302
317
  // return true if address is contained within range
303
318
  inRange(range, address) {
304
319
  const [left, top, , right, bottom] = range;
@@ -101,6 +101,10 @@ export function filterDrawingAnchors(anchors) {
101
101
  if (a == null) {
102
102
  return false;
103
103
  }
104
+ // Absolute anchors need a valid picture
105
+ if (a.range?.pos !== undefined) {
106
+ return !!a.picture;
107
+ }
104
108
  // Form controls have range.br and shape properties
105
109
  if (a.range?.br && a.shape) {
106
110
  return true;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Utilities for manipulating the external-workbook prefix in formula strings.
3
+ *
4
+ * Excel formula strings containing external workbook references have the
5
+ * shape `[<workbook>]Sheet!Ref` where `<workbook>` is either
6
+ *
7
+ * - a 1-based numeric index — `[1]Sheet1!A1` (the canonical on-disk form
8
+ * stored inside `<f>` elements of worksheet XML), or
9
+ * - a filename / relative path — `[测试.xlsx]Sheet1!A1` (what Excel
10
+ * displays in the formula bar; not part of the OOXML storage contract,
11
+ * but produced by hand-written formulas and some older tools).
12
+ *
13
+ * When writing, excelts always emits the numeric form — indices map
14
+ * positionally into the workbook's `<externalReferences>` list. When a
15
+ * formula arrives with the filename form, the writer assigns (or reuses) an
16
+ * ExternalLinkModel with that filename as its `target` and rewrites the
17
+ * formula to the numeric form. This matches how Excel itself stores formulas
18
+ * and makes them round-trippable.
19
+ *
20
+ * The quoted variant `'[file.xlsx]Sheet with space'!A1` is handled too — Excel
21
+ * wraps the `[name]Sheet` segment in single quotes when the sheet name needs
22
+ * quoting. The matching logic here recognises both the unquoted and quoted
23
+ * forms, rewriting inside the quotes when needed.
24
+ *
25
+ * Edge cases we explicitly *do not* treat as external refs:
26
+ * - `[@Column]`, `[#Headers]`, `[Column Name]` — table structured refs
27
+ * (no `]Sheet!` tail). The regex requires the `]<sheet>!` follow-up,
28
+ * which structured refs never have.
29
+ * - Array literals `{1,2;3,4}` use `{}`, not `[]`.
30
+ * - String literals `"[Book]Sheet!A1"` — handled by scanning only outside
31
+ * string literal regions.
32
+ */
33
+ // Matches an external-ref prefix in a formula:
34
+ // Group 1 captures the workbook token inside [...], which is either
35
+ // digits-only (numeric form) or a filename that may include path separators
36
+ // when the whole prefix is single-quoted.
37
+ //
38
+ // Two variants:
39
+ // 1. Unquoted: [Book]Sheet!A1 — Windows-filename-safe chars only in
40
+ // workbook token, then identifier sheet name, then !
41
+ // 2. Quoted: '[path/to/Book]Sheet name'!A1 — quoted segment allows
42
+ // paths / spaces / most punctuation inside the brackets; the sheet
43
+ // name inside the quotes can contain anything except `'` (escaped as '')
44
+ //
45
+ // The regex matches through and including the trailing `!` so callers don't
46
+ // have to re-parse the A1/range part.
47
+ // Unquoted form: workbook token must not contain characters that would
48
+ // make the formula string ambiguous ( ] / \ space). This matches what Excel
49
+ // itself writes for the bare-filename case — anything more exotic is
50
+ // written in the quoted form by Excel.
51
+ const UNQUOTED_EXTERNAL_REF = /\[([^\]\\/:*?"<>|\s]+)\]([A-Za-z_\u00A1-\uFFFF][A-Za-z0-9_\u00A1-\uFFFF.]*)!/g;
52
+ // Quoted form: everything inside [] is permissive (any char except `]`),
53
+ // since the outer `'..'` quotes absorb the surrounding formula
54
+ // delimiters. Sheet name inside quotes is likewise permissive (any char
55
+ // except `'`, with `''` representing an escaped quote).
56
+ const QUOTED_EXTERNAL_REF = /'\[([^\]]+)\]((?:''|[^'])+)'!/g;
57
+ /**
58
+ * Scan a formula string for all external-workbook references. String
59
+ * literals (inside `"..."`) are skipped so that a string value like
60
+ * `"[Book]Sheet!A1"` is not misidentified as a ref.
61
+ *
62
+ * The returned matches are in source order. If a formula contains no
63
+ * external refs, the array is empty.
64
+ */
65
+ export function findExternalRefs(formula) {
66
+ // Fast-fail: external refs always include a `[`. Skipping the
67
+ // string-literal scan + two regex passes for plain cell refs (A1+B1,
68
+ // SUM(A1:A5), 99% of real workbooks) saves noticeable time on large
69
+ // sheets with thousands of formulas.
70
+ if (formula.indexOf("[") === -1) {
71
+ return [];
72
+ }
73
+ const matches = [];
74
+ const safeRegions = stringLiteralRegions(formula);
75
+ const addMatch = (start, end, workbook, sheet, quoted, match) => {
76
+ if (insideAnyRegion(start, safeRegions)) {
77
+ return;
78
+ }
79
+ const numeric = /^\d+$/.test(workbook);
80
+ matches.push({
81
+ match,
82
+ workbook,
83
+ numeric,
84
+ index: numeric ? parseInt(workbook, 10) : null,
85
+ sheet: unquoteSheetName(sheet),
86
+ quoted,
87
+ start,
88
+ end
89
+ });
90
+ };
91
+ UNQUOTED_EXTERNAL_REF.lastIndex = 0;
92
+ let m;
93
+ while ((m = UNQUOTED_EXTERNAL_REF.exec(formula)) !== null) {
94
+ addMatch(m.index, m.index + m[0].length, m[1], m[2], false, m[0]);
95
+ }
96
+ QUOTED_EXTERNAL_REF.lastIndex = 0;
97
+ while ((m = QUOTED_EXTERNAL_REF.exec(formula)) !== null) {
98
+ addMatch(m.index, m.index + m[0].length, m[1], m[2], true, m[0]);
99
+ }
100
+ // Sort matches by start offset so callers can process them in source
101
+ // order (needed when rewriting with offset bookkeeping).
102
+ matches.sort((a, b) => a.start - b.start);
103
+ // Deduplicate overlapping matches (the unquoted regex can technically
104
+ // match a prefix of a quoted sheet name in pathological inputs). Take
105
+ // the first of any overlap.
106
+ const out = [];
107
+ let lastEnd = -1;
108
+ for (const ref of matches) {
109
+ if (ref.start >= lastEnd) {
110
+ out.push(ref);
111
+ lastEnd = ref.end;
112
+ }
113
+ }
114
+ return out;
115
+ }
116
+ /**
117
+ * Replace every external-workbook token in `formula` using the supplied
118
+ * resolver. The resolver is called once per match and returns the numeric
119
+ * index to substitute; returning `null` leaves the match unchanged (useful
120
+ * when the caller cannot resolve a particular filename).
121
+ *
122
+ * Returns the rewritten formula. Offsets inside the original formula are
123
+ * adjusted correctly even when multiple rewrites change the total length.
124
+ */
125
+ export function rewriteExternalRefs(formula, resolve) {
126
+ const refs = findExternalRefs(formula);
127
+ if (refs.length === 0) {
128
+ return formula;
129
+ }
130
+ let out = "";
131
+ let cursor = 0;
132
+ for (const ref of refs) {
133
+ const index = resolve(ref);
134
+ if (index === null) {
135
+ continue; // leave this ref alone; cursor stays put
136
+ }
137
+ out += formula.slice(cursor, ref.start);
138
+ // Construct the replacement: keep the quoted/unquoted shape, swap the
139
+ // workbook token for [N], preserve the sheet segment exactly.
140
+ if (ref.quoted) {
141
+ // The quoted variant surrounds `[Book]Sheet` with single quotes,
142
+ // followed by `!`. We swap the [Book] part for [N] and keep the
143
+ // rest (including the closing `'!`) unchanged so sheet-name
144
+ // quoting is preserved exactly.
145
+ const inner = formula.slice(ref.start + 1, ref.end - 2); // between quotes, excluding trailing '!
146
+ out += "'" + inner.replace(/^\[[^\]]*\]/, `[${index}]`) + "'!";
147
+ }
148
+ else {
149
+ out += `[${index}]${ref.match.slice(ref.match.indexOf("]") + 1)}`;
150
+ }
151
+ cursor = ref.end;
152
+ }
153
+ out += formula.slice(cursor);
154
+ return out;
155
+ }
156
+ // ===========================================================================
157
+ // Internal helpers
158
+ // ===========================================================================
159
+ /**
160
+ * Return the spans of string literal regions in a formula, as half-open
161
+ * [start, end) intervals (exclusive of the surrounding quotes themselves).
162
+ * Used to skip external-ref matches that fall inside a string value.
163
+ */
164
+ function stringLiteralRegions(formula) {
165
+ // Fast-fail when the formula has no double-quote at all — very common
166
+ // for pure arithmetic / reference formulas.
167
+ if (formula.indexOf('"') === -1) {
168
+ return [];
169
+ }
170
+ const regions = [];
171
+ const len = formula.length;
172
+ let i = 0;
173
+ while (i < len) {
174
+ if (formula[i] === '"') {
175
+ const start = i;
176
+ i++;
177
+ while (i < len) {
178
+ if (formula[i] === '"') {
179
+ if (i + 1 < len && formula[i + 1] === '"') {
180
+ i += 2; // escaped quote inside string — keep scanning
181
+ continue;
182
+ }
183
+ i++;
184
+ break;
185
+ }
186
+ i++;
187
+ }
188
+ regions.push([start, i]);
189
+ }
190
+ else {
191
+ i++;
192
+ }
193
+ }
194
+ return regions;
195
+ }
196
+ function insideAnyRegion(pos, regions) {
197
+ for (const [a, b] of regions) {
198
+ if (pos >= a && pos < b) {
199
+ return true;
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+ function unquoteSheetName(sheet) {
205
+ // The quoted form captured inside `'..'` may have doubled single quotes
206
+ // that represent a single quote in the logical sheet name.
207
+ return sheet.replace(/''/g, "'");
208
+ }
@@ -39,7 +39,9 @@ async function* iterateStream(stream) {
39
39
  else {
40
40
  stream.pause();
41
41
  const data = contents.shift();
42
- yield data;
42
+ if (data !== undefined) {
43
+ yield data;
44
+ }
43
45
  }
44
46
  if (error) {
45
47
  throw toError(error);
@@ -8,7 +8,8 @@ export const OOXML_PATHS = {
8
8
  xlSharedStrings: "xl/sharedStrings.xml",
9
9
  xlStyles: "xl/styles.xml",
10
10
  xlTheme1: "xl/theme/theme1.xml",
11
- xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml"
11
+ xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml",
12
+ xlMetadata: "xl/metadata.xml"
12
13
  };
13
14
  const worksheetXmlRegex = /^xl\/worksheets\/sheet(\d+)[.]xml$/;
14
15
  const worksheetRelsXmlRegex = /^xl\/worksheets\/_rels\/sheet(\d+)[.]xml[.]rels$/;
@@ -25,6 +26,9 @@ const pivotTableRelsXmlRegex = /^xl\/pivotTables\/_rels\/(pivotTable\d+)[.]xml[.
25
26
  const pivotCacheDefinitionXmlRegex = /^xl\/pivotCache\/(pivotCacheDefinition\d+)[.]xml$/;
26
27
  const pivotCacheDefinitionRelsXmlRegex = /^xl\/pivotCache\/_rels\/(pivotCacheDefinition\d+)[.]xml[.]rels$/;
27
28
  const pivotCacheRecordsXmlRegex = /^xl\/pivotCache\/(pivotCacheRecords\d+)[.]xml$/;
29
+ // External workbook links (xl/externalLinks/externalLink{n}.xml and its rels)
30
+ const externalLinkXmlRegex = /^xl\/externalLinks\/externalLink(\d+)[.]xml$/;
31
+ const externalLinkRelsXmlRegex = /^xl\/externalLinks\/_rels\/externalLink(\d+)[.]xml[.]rels$/;
28
32
  export function normalizeZipPath(path) {
29
33
  return path.startsWith("/") ? path.slice(1) : path;
30
34
  }
@@ -105,6 +109,22 @@ export function getPivotCacheRecordsNameFromPath(path) {
105
109
  const match = pivotCacheRecordsXmlRegex.exec(path);
106
110
  return match ? match[1] : undefined;
107
111
  }
112
+ /**
113
+ * Extract the 1-based index `N` from `xl/externalLinks/externalLink{N}.xml`.
114
+ * Returns the raw integer (e.g. `1` for externalLink1.xml) or undefined.
115
+ */
116
+ export function getExternalLinkIndexFromPath(path) {
117
+ const match = externalLinkXmlRegex.exec(path);
118
+ return match ? parseInt(match[1], 10) : undefined;
119
+ }
120
+ /**
121
+ * Extract the 1-based index `N` from
122
+ * `xl/externalLinks/_rels/externalLink{N}.xml.rels`.
123
+ */
124
+ export function getExternalLinkIndexFromRelsPath(path) {
125
+ const match = externalLinkRelsXmlRegex.exec(path);
126
+ return match ? parseInt(match[1], 10) : undefined;
127
+ }
108
128
  export function toContentTypesPartName(zipPath) {
109
129
  // ContentTypes uses leading slash PartName (e.g. "/xl/workbook.xml").
110
130
  return zipPath.startsWith("/") ? zipPath : `/${zipPath}`;
@@ -167,6 +187,20 @@ export function pivotTablePath(n) {
167
187
  export function pivotTableRelsPath(n) {
168
188
  return `xl/pivotTables/_rels/pivotTable${n}.xml.rels`;
169
189
  }
190
+ // -------- External links --------
191
+ export function externalLinkPath(n) {
192
+ return `xl/externalLinks/externalLink${n}.xml`;
193
+ }
194
+ export function externalLinkRelsPath(n) {
195
+ return `xl/externalLinks/_rels/externalLink${n}.xml.rels`;
196
+ }
197
+ /**
198
+ * Build the `Target` value for an externalLink relationship inside
199
+ * `xl/_rels/workbook.xml.rels` (base: `xl/`).
200
+ */
201
+ export function externalLinkRelTargetFromWorkbook(n) {
202
+ return `externalLinks/externalLink${n}.xml`;
203
+ }
170
204
  export function pivotCacheDefinitionRelTargetFromPivotTable(n) {
171
205
  return `../pivotCache/pivotCacheDefinition${n}.xml`;
172
206
  }
@@ -175,7 +209,8 @@ export const OOXML_REL_TARGETS = {
175
209
  workbookStyles: "styles.xml",
176
210
  workbookSharedStrings: "sharedStrings.xml",
177
211
  workbookTheme1: "theme/theme1.xml",
178
- workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml"
212
+ workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml",
213
+ workbookMetadata: "metadata.xml"
179
214
  };
180
215
  export function pivotCacheDefinitionRelTargetFromWorkbook(n) {
181
216
  // Target inside xl/_rels/workbook.xml.rels (base: xl/)
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Canonical JSON serializer with sorted object keys.
3
+ *
4
+ * Used to derive an insertion-order-independent dedupe key for rich-text
5
+ * shared-string entries. Two semantically identical run/font objects must
6
+ * map to the same key regardless of the order their properties were assigned.
7
+ */
8
+ function canonicalStringify(value) {
9
+ if (value === null || typeof value !== "object") {
10
+ return JSON.stringify(value);
11
+ }
12
+ if (Array.isArray(value)) {
13
+ return `[${value.map(canonicalStringify).join(",")}]`;
14
+ }
15
+ const keys = Object.keys(value).sort();
16
+ const obj = value;
17
+ return `{${keys.map(k => `${JSON.stringify(k)}:${canonicalStringify(obj[k])}`).join(",")}}`;
18
+ }
1
19
  class SharedStrings {
2
20
  constructor() {
3
21
  this._values = [];
@@ -17,9 +35,10 @@ class SharedStrings {
17
35
  return this._values[index];
18
36
  }
19
37
  add(value) {
20
- let index = this._hash[value];
38
+ const key = typeof value === "string" ? `s:${value}` : `r:${canonicalStringify(value.richText)}`;
39
+ let index = this._hash[key];
21
40
  if (index === undefined) {
22
- index = this._hash[value] = this._values.length;
41
+ index = this._hash[key] = this._values.length;
23
42
  this._values.push(value);
24
43
  }
25
44
  this._totalRefs++;