@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
@@ -0,0 +1,619 @@
1
+ "use strict";
2
+ /**
3
+ * Formula Calculation Implementation
4
+ *
5
+ * The pipeline that implements the snapshot → compile → evaluate →
6
+ * materialize → apply architecture.
7
+ *
8
+ * ## Pipeline Steps
9
+ *
10
+ * 1. **Snapshot** — `buildWorkbookSnapshot()` creates an immutable snapshot
11
+ * of the entire workbook.
12
+ * 2. **Normalize** — `collectFormulaInstances()` extracts all formula cells
13
+ * into uniform `FormulaInstance` objects.
14
+ * 3. **Parse** — Each formula's source text is tokenized and parsed into an AST.
15
+ * 4. **Compile** — The binder transforms each AST into a `BoundExpr` tree,
16
+ * resolving names, structured references, and sheet references.
17
+ * 5. **Dependency Analysis** — Static dependencies are extracted from bound
18
+ * expressions and a topological evaluation order is computed.
19
+ * 6. **Evaluate** — Formulas are evaluated in dependency order using the
20
+ * evaluator which operates on `BoundExpr` and produces `RuntimeValue`.
21
+ * 7. **Materialize** — Evaluation results are converted into a `WritebackPlan`.
22
+ * 8. **Apply** — The plan is applied to the live workbook.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.calculateFormulasImpl = calculateFormulasImpl;
26
+ const address_utils_1 = require("../compile/address-utils");
27
+ const binder_1 = require("../compile/binder");
28
+ const compiled_formula_1 = require("../compile/compiled-formula");
29
+ const dependency_analysis_1 = require("../compile/dependency-analysis");
30
+ const _date_context_1 = require("../functions/_date-context");
31
+ const build_writeback_plan_1 = require("../materialize/build-writeback-plan");
32
+ const spill_engine_1 = require("../materialize/spill-engine");
33
+ const evaluator_1 = require("../runtime/evaluator");
34
+ const values_1 = require("../runtime/values");
35
+ const parser_1 = require("../syntax/parser");
36
+ const tokenizer_1 = require("../syntax/tokenizer");
37
+ const apply_writeback_plan_1 = require("./apply-writeback-plan");
38
+ const formula_instance_1 = require("./formula-instance");
39
+ const workbook_adapter_1 = require("./workbook-adapter");
40
+ const workbook_snapshot_1 = require("./workbook-snapshot");
41
+ // ============================================================================
42
+ // Persistent Caches (keyed by workbook — survive across invocations)
43
+ // ============================================================================
44
+ /**
45
+ * Persistent AST cache: formula text → parsed AstNode.
46
+ * Since AST is a pure function of formula text, this is safe to cache
47
+ * across calculation cycles. Keyed by workbook to allow GC.
48
+ *
49
+ * The inner `Map` is bounded by `AST_CACHE_MAX_ENTRIES` using simple LRU
50
+ * eviction (least-recently-used key removed when full). This prevents a
51
+ * long-lived workbook that churns through unique formula texts — e.g.
52
+ * templated generation that embeds timestamps — from growing the cache
53
+ * without bound. See `parseFormulaText` for the hit-path bookkeeping.
54
+ */
55
+ const AST_CACHE_MAX_ENTRIES = 10000;
56
+ const persistentAstCache = new WeakMap();
57
+ function getPersistentAstCache(workbook) {
58
+ let cache = persistentAstCache.get(workbook);
59
+ if (!cache) {
60
+ cache = new Map();
61
+ persistentAstCache.set(workbook, cache);
62
+ }
63
+ return cache;
64
+ }
65
+ // ============================================================================
66
+ // Main: Formula Calculation Implementation
67
+ // ============================================================================
68
+ /**
69
+ * Recalculate all formula cells using the new pipeline.
70
+ *
71
+ * This implements the full snapshot → compile → evaluate → materialize → apply
72
+ * architecture. The workbook is mutated only at the final apply step.
73
+ */
74
+ function calculateFormulasImpl(workbook) {
75
+ // ── Step 1: Snapshot ──
76
+ const snapshot = (0, workbook_adapter_1.buildWorkbookSnapshot)(workbook);
77
+ // Propagate the workbook-wide `date1904` mode to the module-local date
78
+ // context used by date/time/financial/text formula functions. Those
79
+ // functions have a context-free `NativeFn` signature and cannot receive
80
+ // the flag through an argument, so we thread it via a setter instead.
81
+ // See functions/_date-context.ts for the threading rationale and the
82
+ // concurrency caveat.
83
+ (0, _date_context_1.setDate1904)(snapshot.properties.date1904 ?? false);
84
+ // ── Step 2: Normalize ──
85
+ const instances = (0, formula_instance_1.collectFormulaInstances)(snapshot);
86
+ if (instances.length === 0) {
87
+ // Clean up stale spills even when there are no formulas
88
+ cleanupStaleSpillsIfNeeded(workbook, snapshot);
89
+ return;
90
+ }
91
+ // ── Step 3: Parse ──
92
+ // Use persistent AST cache — formula text → AST is a pure function,
93
+ // so parsed ASTs can be safely reused across calculation cycles.
94
+ const astCache = getPersistentAstCache(workbook);
95
+ for (const inst of instances) {
96
+ parseFormulaText(inst.sourceText, astCache);
97
+ }
98
+ // ── Step 4: Compile (Bind) ──
99
+ const compiledMap = new Map();
100
+ const results = new Map();
101
+ for (const inst of instances) {
102
+ const compiled = compileFormula(inst, astCache, snapshot);
103
+ const key = (0, workbook_snapshot_1.formulaCellKey)(inst.sheetName, inst.row, inst.col);
104
+ if ("reason" in compiled) {
105
+ // Parse or bind failure — produce an explicit error result.
106
+ // #CALC! for engine-level failures, #NAME? for parse errors that
107
+ // may indicate an unsupported construct.
108
+ results.set(key, compiled.reason === "parse" ? values_1.ERRORS.NAME : values_1.ERRORS.CALC);
109
+ }
110
+ else {
111
+ compiledMap.set(key, compiled);
112
+ }
113
+ }
114
+ // ── Step 5: Dependency Analysis + Topological Sort ──
115
+ // Build a producer map so that formulas depending on cells that are:
116
+ // (a) CSE target range slaves, or
117
+ // (b) previous-cycle spill ghost cells
118
+ // correctly get ordered after their producing formula.
119
+ const producerMap = new Map();
120
+ // CSE: distribute targetRef across all slave cells → master key
121
+ for (const [masterKey, cf] of compiledMap) {
122
+ const inst = cf.instance;
123
+ if (inst.kind === "cse" && inst.targetRef) {
124
+ const rng = (0, address_utils_1.parseRefRange)(inst.targetRef);
125
+ if (rng) {
126
+ for (let r = rng.top; r <= rng.bottom; r++) {
127
+ for (let c = rng.left; c <= rng.right; c++) {
128
+ const slaveKey = (0, workbook_snapshot_1.formulaCellKey)(inst.sheetName, r, c);
129
+ if (slaveKey !== masterKey) {
130
+ producerMap.set(slaveKey, masterKey);
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ // Dynamic array spill: use previous-cycle spill regions as static hint
138
+ // for dependency ordering. The actual spill may differ this cycle — if the
139
+ // master formula is no longer a dynamic-array producer, skip it so stale
140
+ // ghost cells don't introduce false edges.
141
+ const persistentSpills = (0, spill_engine_1.getPersistentSpillMap)(workbook);
142
+ for (const [, region] of persistentSpills) {
143
+ const ws = snapshot.worksheetsById.get(region.worksheetId);
144
+ if (!ws) {
145
+ continue;
146
+ }
147
+ const masterKey = (0, workbook_snapshot_1.formulaCellKey)(ws.name, region.sourceRow, region.sourceCol);
148
+ const masterCf = compiledMap.get(masterKey);
149
+ if (!masterCf) {
150
+ continue; // source formula no longer exists
151
+ }
152
+ // Only remap if the master is still a dynamic-array formula this cycle
153
+ const isStillDynamic = masterCf.instance.isDynamicArray || masterCf.isDynamicArrayFunction;
154
+ if (!isStillDynamic) {
155
+ continue;
156
+ }
157
+ for (let r = 0; r < region.rows; r++) {
158
+ for (let c = 0; c < region.cols; c++) {
159
+ if (r === 0 && c === 0) {
160
+ continue; // skip source
161
+ }
162
+ const ghostKey = (0, workbook_snapshot_1.formulaCellKey)(ws.name, region.sourceRow + r, region.sourceCol + c);
163
+ if (!producerMap.has(ghostKey)) {
164
+ producerMap.set(ghostKey, masterKey);
165
+ }
166
+ }
167
+ }
168
+ }
169
+ // Build the dependency graph with producer remapping.
170
+ let graph = (0, dependency_analysis_1.buildDependencyGraphFromDeps)(compiledMap, producerMap);
171
+ let evalOrder = (0, dependency_analysis_1.topologicalSort)(graph);
172
+ // ── Step 6: Evaluate ──
173
+ const session = new evaluator_1.EvalSession();
174
+ const ctx = {
175
+ snapshot,
176
+ compiledFormulas: compiledMap,
177
+ currentSheet: snapshot.worksheets[0]?.name ?? ""
178
+ };
179
+ // Evaluate in topological order
180
+ evaluateInOrder(evalOrder, compiledMap, results, ctx, session);
181
+ // ── Step 6b: Merge dynamic dependencies and re-evaluate if needed ──
182
+ // After the first pass, formulas with INDIRECT/OFFSET have recorded their
183
+ // actual runtime cell accesses in session.dynamicDeps. Merge these edges
184
+ // into the graph and re-evaluate any formulas whose dependencies changed.
185
+ if (session.dynamicDeps.size > 0) {
186
+ const mergeResult = (0, dependency_analysis_1.mergeDynamicDeps)(graph, session.dynamicDeps);
187
+ if (mergeResult.changed) {
188
+ const prevCircularKeys = graph.circularKeys;
189
+ graph = mergeResult.graph;
190
+ evalOrder = (0, dependency_analysis_1.topologicalSort)(graph);
191
+ // Collect formulas that gained new deps AND their transitive dependents.
192
+ // Without clearing dependents, downstream cells could see stale values.
193
+ const toClear = new Set();
194
+ const queue = [];
195
+ for (const [formulaKey] of session.dynamicDeps) {
196
+ if (!toClear.has(formulaKey)) {
197
+ toClear.add(formulaKey);
198
+ queue.push(formulaKey);
199
+ }
200
+ }
201
+ // If the merge introduced new circular refs, include all new members too
202
+ for (const key of graph.circularKeys) {
203
+ if (!prevCircularKeys.has(key) && !toClear.has(key)) {
204
+ toClear.add(key);
205
+ queue.push(key);
206
+ }
207
+ }
208
+ // BFS through reverse edges to find all transitive dependents
209
+ let head = 0;
210
+ while (head < queue.length) {
211
+ const key = queue[head++];
212
+ const deps = graph.dependedBy.get(key);
213
+ if (deps) {
214
+ for (const depKey of deps) {
215
+ if (!toClear.has(depKey)) {
216
+ toClear.add(depKey);
217
+ queue.push(depKey);
218
+ }
219
+ }
220
+ }
221
+ }
222
+ // Clear all affected formulas
223
+ for (const key of toClear) {
224
+ session.resultCache.delete(key);
225
+ results.delete(key);
226
+ }
227
+ // Formula-based name results may depend on cell values that just changed
228
+ session.nameCache.clear();
229
+ // Re-evaluate the full order (evaluateInOrder skips already-computed cells)
230
+ evaluateInOrder(evalOrder, compiledMap, results, ctx, session);
231
+ }
232
+ }
233
+ // ── Iterative Calculation for Circular References ──
234
+ const iterateEnabled = snapshot.calcProperties.iterate === true;
235
+ if (iterateEnabled && graph.circularKeys.size > 0) {
236
+ runIterativeCalc(evalOrder, graph, compiledMap, results, ctx, session, snapshot);
237
+ reevaluateDownstreamOfCircular(evalOrder, graph, compiledMap, results, ctx, session);
238
+ }
239
+ // ── Step 7: Materialize (Build Writeback Plan) ──
240
+ const previousSpills = (0, spill_engine_1.getPersistentSpillMap)(workbook);
241
+ const previousGhosts = (0, spill_engine_1.getGhostSnapshots)(workbook);
242
+ const plan = (0, build_writeback_plan_1.buildWritebackPlan)(snapshot, [...compiledMap.values()], results, previousSpills, previousGhosts);
243
+ // ── Step 8: Apply ──
244
+ (0, apply_writeback_plan_1.applyWritebackPlan)(workbook, plan);
245
+ }
246
+ // ============================================================================
247
+ // Helper: Evaluate Formulas in Order
248
+ // ============================================================================
249
+ /**
250
+ * Evaluate compiled formulas in the given topological order.
251
+ *
252
+ * For each formula in `evalOrder`:
253
+ * - If already in `results` (from a previous pass or compile failure), skip.
254
+ * - Volatile formulas always re-evaluate (bypass scalar cache).
255
+ * - CSE / dynamic array formulas use `evaluateFormulaRaw`.
256
+ * - Normal scalar formulas use `evaluateFormula` with cache.
257
+ */
258
+ function evaluateInOrder(evalOrder, compiledMap, results, ctx, session) {
259
+ for (const key of evalOrder) {
260
+ // Skip if already computed (e.g. compile failure → #CALC!, or previous pass)
261
+ if (results.has(key)) {
262
+ continue;
263
+ }
264
+ const compiled = compiledMap.get(key);
265
+ if (!compiled) {
266
+ continue;
267
+ }
268
+ const inst = compiled.instance;
269
+ const isCSE = inst.kind === "cse" && inst.targetRef;
270
+ const isDynamic = inst.isDynamicArray || compiled.isDynamicArrayFunction;
271
+ // Volatile formulas always re-evaluate — bypass cache
272
+ if (compiled.isVolatile) {
273
+ session.resultCache.delete(key);
274
+ }
275
+ if (isCSE || isDynamic) {
276
+ try {
277
+ const raw = (0, evaluator_1.evaluateFormulaRaw)(compiled, ctx, session);
278
+ results.set(key, raw);
279
+ if (isCSE && inst.targetRef) {
280
+ populateCSECache(inst, raw, session);
281
+ }
282
+ }
283
+ catch {
284
+ results.set(key, values_1.ERRORS.CALC);
285
+ }
286
+ }
287
+ else {
288
+ if (!compiled.isVolatile) {
289
+ const cachedResult = session.resultCache.get(key);
290
+ if (cachedResult !== undefined) {
291
+ results.set(key, cachedResult.scalar);
292
+ continue;
293
+ }
294
+ }
295
+ try {
296
+ const scalar = (0, evaluator_1.evaluateFormula)(compiled, ctx, session);
297
+ results.set(key, scalar);
298
+ }
299
+ catch {
300
+ results.set(key, values_1.ERRORS.CALC);
301
+ }
302
+ }
303
+ }
304
+ }
305
+ // ============================================================================
306
+ // Helper: Parse Formula Text
307
+ // ============================================================================
308
+ // Sentinel cached in the AST map to record a failed parse. Using a distinct
309
+ // object means callers that do an explicit identity check against this value
310
+ // can short-circuit before any truthy branch; it is never exposed outside the
311
+ // cache so cannot be mistaken for a real AST by downstream consumers.
312
+ const PARSE_FAILED_SENTINEL = {};
313
+ /**
314
+ * Touch a cache entry to move it to the MRU (most-recently-used) position.
315
+ * Relies on `Map`'s guaranteed insertion-order iteration: delete + re-set
316
+ * pushes the entry to the end of the iteration order without changing its
317
+ * value identity. Only called on cache hits.
318
+ */
319
+ function touchAstCacheEntry(astCache, formula, ast) {
320
+ astCache.delete(formula);
321
+ astCache.set(formula, ast);
322
+ }
323
+ /**
324
+ * Insert a new entry into the AST cache, evicting the least-recently-used
325
+ * entry if the cache is at capacity. The LRU entry is the first key returned
326
+ * by `Map.keys()` iteration, which corresponds to the oldest insertion/touch.
327
+ */
328
+ function insertAstCacheEntry(astCache, formula, ast) {
329
+ if (astCache.size >= AST_CACHE_MAX_ENTRIES) {
330
+ // Evict one entry before adding the new one. `Map.keys().next().value`
331
+ // is the least-recently-inserted (or -touched) key — O(1) access.
332
+ const oldestKey = astCache.keys().next().value;
333
+ if (oldestKey !== undefined) {
334
+ astCache.delete(oldestKey);
335
+ }
336
+ }
337
+ astCache.set(formula, ast);
338
+ }
339
+ function parseFormulaText(formula, astCache) {
340
+ const cached = astCache.get(formula);
341
+ if (cached === PARSE_FAILED_SENTINEL) {
342
+ // Touch so that a repeatedly-evaluated failing formula doesn't get
343
+ // evicted and re-parsed (and re-failed) every cycle.
344
+ touchAstCacheEntry(astCache, formula, PARSE_FAILED_SENTINEL);
345
+ return null;
346
+ }
347
+ if (cached) {
348
+ touchAstCacheEntry(astCache, formula, cached);
349
+ return cached;
350
+ }
351
+ try {
352
+ const tokens = (0, tokenizer_1.tokenize)(formula);
353
+ const ast = (0, parser_1.parse)(tokens);
354
+ insertAstCacheEntry(astCache, formula, ast);
355
+ return ast;
356
+ }
357
+ catch {
358
+ insertAstCacheEntry(astCache, formula, PARSE_FAILED_SENTINEL);
359
+ return null;
360
+ }
361
+ }
362
+ function compileFormula(inst, astCache, snapshot) {
363
+ const ast = astCache.get(inst.sourceText);
364
+ if (!ast) {
365
+ return { reason: "parse", formula: inst.sourceText };
366
+ }
367
+ const bindCtx = {
368
+ snapshot,
369
+ currentSheet: inst.sheetName
370
+ };
371
+ try {
372
+ const bound = (0, binder_1.bind)(ast, bindCtx);
373
+ // Build a name resolver that parses formula-based defined names
374
+ // so their deps and dynamic-ref flags propagate to the outer formula.
375
+ const nameDepCache = new Map();
376
+ const nameResolver = upperName => {
377
+ // Include sheet in cache key for scope-aware resolution
378
+ const cacheKey = `${upperName}\0${inst.sheetName}`;
379
+ if (nameDepCache.has(cacheKey)) {
380
+ return nameDepCache.get(cacheKey);
381
+ }
382
+ // Prevent infinite recursion
383
+ nameDepCache.set(cacheKey, undefined);
384
+ // Use scope-aware resolution (sheet-local → workbook-global)
385
+ const dn = (0, workbook_snapshot_1.resolveDefinedName)(snapshot.definedNames, upperName, inst.sheetName);
386
+ if (!dn || dn.ranges.length !== 1) {
387
+ return undefined;
388
+ }
389
+ const rangeStr = dn.ranges[0];
390
+ // Only process formula-based names (not cell/range refs)
391
+ if ((0, address_utils_1.parseRefRange)(rangeStr)) {
392
+ return undefined;
393
+ }
394
+ try {
395
+ const nameTokens = (0, tokenizer_1.tokenize)(rangeStr);
396
+ const nameAst = (0, parser_1.parse)(nameTokens);
397
+ const nameBound = (0, binder_1.bind)(nameAst, { snapshot, currentSheet: inst.sheetName });
398
+ const nameDeps = (0, compiled_formula_1.extractStaticDeps)(nameBound, snapshot, nameResolver);
399
+ const nameAnalysis = (0, compiled_formula_1.analyzeExpr)(nameBound, nameResolver);
400
+ const result = {
401
+ deps: nameDeps,
402
+ hasDynamicRefs: nameAnalysis.hasDynamicRefs,
403
+ // Propagate volatility so a defined-name body containing NOW()/
404
+ // RAND() correctly invalidates the outer formula's session
405
+ // cache on every calculation pass.
406
+ isVolatile: nameAnalysis.isVolatile
407
+ };
408
+ nameDepCache.set(cacheKey, result);
409
+ return result;
410
+ }
411
+ catch {
412
+ return undefined;
413
+ }
414
+ };
415
+ const staticDeps = (0, compiled_formula_1.extractStaticDeps)(bound, snapshot, nameResolver);
416
+ const analysis = (0, compiled_formula_1.analyzeExpr)(bound, nameResolver);
417
+ return {
418
+ instance: inst,
419
+ bound,
420
+ staticDeps,
421
+ isVolatile: analysis.isVolatile,
422
+ hasDynamicRefs: analysis.hasDynamicRefs,
423
+ containsLambda: analysis.containsLambda,
424
+ isDynamicArrayFunction: (0, compiled_formula_1.detectDynamicArrayFunction)(ast, bound),
425
+ isSubtotalOutput: (0, compiled_formula_1.detectSubtotalOutput)(ast, bound)
426
+ };
427
+ }
428
+ catch {
429
+ return { reason: "bind", formula: inst.sourceText, sheet: inst.sheetName };
430
+ }
431
+ }
432
+ // ============================================================================
433
+ // Helper: Cleanup Stale Spills
434
+ // ============================================================================
435
+ function cleanupStaleSpillsIfNeeded(workbook, snapshot) {
436
+ const previousSpills = (0, spill_engine_1.getPersistentSpillMap)(workbook);
437
+ if (previousSpills.size === 0) {
438
+ return;
439
+ }
440
+ // No formula cells → all spills are stale
441
+ const plan = (0, build_writeback_plan_1.buildWritebackPlan)(snapshot, [], new Map(), previousSpills, (0, spill_engine_1.getGhostSnapshots)(workbook));
442
+ (0, apply_writeback_plan_1.applyWritebackPlan)(workbook, plan);
443
+ }
444
+ // ============================================================================
445
+ // Helper: Populate CSE Session Cache
446
+ // ============================================================================
447
+ /**
448
+ * For CSE array formulas, immediately populate the session cache for all
449
+ * cells in the target range. This ensures that when other formulas reference
450
+ * cells within a CSE range, they see the correct distributed values instead
451
+ * of re-evaluating independently.
452
+ */
453
+ function populateCSECache(inst, result, session) {
454
+ const ref = inst.targetRef;
455
+ if (!ref) {
456
+ return;
457
+ }
458
+ const range = (0, address_utils_1.parseRefRange)(ref);
459
+ if (!range) {
460
+ return;
461
+ }
462
+ const { top, left, bottom, right } = range;
463
+ const numRows = bottom - top + 1;
464
+ const numCols = right - left + 1;
465
+ if (result.kind === 5 /* RVKind.Array */) {
466
+ for (let r = 0; r < numRows; r++) {
467
+ for (let c = 0; c < numCols; c++) {
468
+ const cellKey = (0, workbook_snapshot_1.formulaCellKey)(inst.sheetName, top + r, left + c);
469
+ const val = result.rows[r]?.[c];
470
+ const sv = val ?? values_1.BLANK;
471
+ session.resultCache.set(cellKey, { scalar: sv, raw: sv });
472
+ }
473
+ }
474
+ }
475
+ else {
476
+ // Scalar — fill entire range
477
+ const scalar = result.kind === 4 /* RVKind.Error */ ||
478
+ result.kind === 1 /* RVKind.Number */ ||
479
+ result.kind === 2 /* RVKind.String */ ||
480
+ result.kind === 3 /* RVKind.Boolean */
481
+ ? result
482
+ : values_1.BLANK;
483
+ for (let r = 0; r < numRows; r++) {
484
+ for (let c = 0; c < numCols; c++) {
485
+ const cellKey = (0, workbook_snapshot_1.formulaCellKey)(inst.sheetName, top + r, left + c);
486
+ session.resultCache.set(cellKey, { scalar, raw: scalar });
487
+ }
488
+ }
489
+ }
490
+ }
491
+ // ============================================================================
492
+ // Iterative calculation (for circular references)
493
+ // ============================================================================
494
+ /**
495
+ * Drive the iterative-calculation loop for the cells that participate in
496
+ * cycles. Pre-computes the transitive downstream set once, then on each
497
+ * iteration:
498
+ * 1. invalidates the cached result of circular cells and their descendants;
499
+ * 2. seeds `circularFallback` from the previous iteration's numbers;
500
+ * 3. re-evaluates each circular cell and tracks the maximum absolute change.
501
+ *
502
+ * Exits early when all cells converge within `iterateDelta`, or after
503
+ * `iterateCount` iterations. The `circularFallback` map is cleared on exit
504
+ * so subsequent (non-iterative) evaluation paths revert to the zero-seed
505
+ * fallback behaviour.
506
+ */
507
+ function runIterativeCalc(evalOrder, graph, compiledMap, results, ctx, session, snapshot) {
508
+ const maxIter = snapshot.calcProperties.iterateCount ?? 100;
509
+ const delta = snapshot.calcProperties.iterateDelta ?? 0.001;
510
+ const circularKeys = [];
511
+ for (const key of evalOrder) {
512
+ if (graph.circularKeys.has(key)) {
513
+ circularKeys.push(key);
514
+ }
515
+ }
516
+ // Transitive downstream of circularKeys — cells upstream of every cycle
517
+ // are stable across iterations, so their cached values remain valid.
518
+ const circularAndDownstream = new Set(graph.circularKeys);
519
+ const downstreamQueue = [...graph.circularKeys];
520
+ let downstreamHead = 0;
521
+ while (downstreamHead < downstreamQueue.length) {
522
+ const key = downstreamQueue[downstreamHead++];
523
+ const deps = graph.dependedBy.get(key);
524
+ if (!deps) {
525
+ continue;
526
+ }
527
+ for (const depKey of deps) {
528
+ if (!circularAndDownstream.has(depKey)) {
529
+ circularAndDownstream.add(depKey);
530
+ downstreamQueue.push(depKey);
531
+ }
532
+ }
533
+ }
534
+ for (let iter = 0; iter < maxIter; iter++) {
535
+ let maxChange = 0;
536
+ // Clear only circular cells and their transitive downstream.
537
+ for (const key of circularAndDownstream) {
538
+ session.resultCache.delete(key);
539
+ }
540
+ // Defined-name cache: cleared wholesale because formula-based names may
541
+ // indirectly reference circular cells, and tracking which names touch
542
+ // which cells would complicate the engine substantially.
543
+ session.nameCache.clear();
544
+ // Seed fallback from previous results
545
+ for (const key of circularKeys) {
546
+ const compiled = compiledMap.get(key);
547
+ if (!compiled) {
548
+ continue;
549
+ }
550
+ const prev = results.get(key);
551
+ if (prev !== undefined && prev.kind !== 4 /* RVKind.Error */) {
552
+ session.circularFallback.set(key, prev);
553
+ }
554
+ else {
555
+ session.circularFallback.set(key, (0, values_1.rvNumber)(0));
556
+ }
557
+ }
558
+ for (const key of circularKeys) {
559
+ const compiled = compiledMap.get(key);
560
+ if (!compiled) {
561
+ continue;
562
+ }
563
+ try {
564
+ const oldResult = results.get(key);
565
+ const newResult = (0, evaluator_1.evaluateFormula)(compiled, ctx, session);
566
+ results.set(key, newResult);
567
+ session.circularFallback.set(key, newResult);
568
+ if (oldResult && oldResult.kind === 1 /* RVKind.Number */ && newResult.kind === 1 /* RVKind.Number */) {
569
+ maxChange = Math.max(maxChange, Math.abs(newResult.value - oldResult.value));
570
+ }
571
+ }
572
+ catch {
573
+ // Iterative evaluation threw — set error and continue convergence.
574
+ results.set(key, values_1.ERRORS.CALC);
575
+ }
576
+ }
577
+ if (maxChange <= delta) {
578
+ break;
579
+ }
580
+ }
581
+ session.circularFallback.clear();
582
+ }
583
+ /**
584
+ * After iterative calculation has converged, cells that sit on the non-
585
+ * circular side but depend transitively on a circular cell still hold stale
586
+ * values from the first pass (which used the fallback zero-seed). Find them
587
+ * and re-evaluate, preserving topological order.
588
+ */
589
+ function reevaluateDownstreamOfCircular(evalOrder, graph, compiledMap, results, ctx, session) {
590
+ const affected = new Set();
591
+ const queue = [...graph.circularKeys];
592
+ let head = 0;
593
+ while (head < queue.length) {
594
+ const key = queue[head++];
595
+ const deps = graph.dependedBy.get(key);
596
+ if (!deps) {
597
+ continue;
598
+ }
599
+ for (const depKey of deps) {
600
+ if (!graph.circularKeys.has(depKey) && !affected.has(depKey)) {
601
+ affected.add(depKey);
602
+ queue.push(depKey);
603
+ }
604
+ }
605
+ }
606
+ if (affected.size === 0) {
607
+ return;
608
+ }
609
+ for (const key of affected) {
610
+ session.resultCache.delete(key);
611
+ results.delete(key);
612
+ }
613
+ session.nameCache.clear();
614
+ // Only re-evaluate the affected subset; filtering preserves the
615
+ // topological ordering within that subset while skipping the (already
616
+ // computed) non-affected cells entirely.
617
+ const filteredOrder = evalOrder.filter(k => affected.has(k));
618
+ evaluateInOrder(filteredOrder, compiledMap, results, ctx, session);
619
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Formula Calculation Engine
4
+ *
5
+ * Provides `calculateFormulas()` as the primary function-style entry
6
+ * point. The same work runs when a host calls
7
+ * `Workbook.calculateFormulas()` — both paths dispatch through the
8
+ * engine registered via `installFormulaEngine()`.
9
+ *
10
+ * ## Architecture
11
+ *
12
+ * 1. **Snapshot** — immutable capture of all workbook state
13
+ * 2. **Normalize** — uniform FormulaInstance objects
14
+ * 3. **Parse** — tokenize → AST
15
+ * 4. **Compile** — bind AST → BoundExpr (resolve names, structured refs, sheets)
16
+ * 5. **Dependency Analysis** — topological sort
17
+ * 6. **Evaluate** — execute BoundExpr with RuntimeValue system
18
+ * 7. **Materialize** — build declarative WritebackPlan
19
+ * 8. **Apply** — write plan to live workbook
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.calculateFormulas = calculateFormulas;
23
+ const calculate_formulas_impl_1 = require("./calculate-formulas-impl");
24
+ /**
25
+ * Recalculate all formula cells in a workbook.
26
+ *
27
+ * Evaluates every formula cell using the built-in calculation engine
28
+ * and updates each cell's `result` value. Formulas are evaluated lazily
29
+ * with recursive dependency resolution, memoization, and circular
30
+ * reference detection.
31
+ *
32
+ * All evaluation state is scoped to this invocation — concurrent calls
33
+ * for different workbooks are safe.
34
+ *
35
+ * **Supported formula features:**
36
+ * - Cell references: `A1`, `$B$2`, `Sheet1!A1`, `'Sheet Name'!A1:B10`
37
+ * - Operators: `+ - * / ^`, `& (concat)`, `= <> < > <= >=`, `%`
38
+ * - 433 built-in functions across math, text, logical, date, lookup,
39
+ * statistical, financial, dynamic-array, database and engineering
40
+ * categories.
41
+ * - Shared formulas, array constants, nested expressions
42
+ * - Dynamic array spill: FILTER, SORT, UNIQUE, SORTBY results are
43
+ * written to adjacent cells. #SPILL! error if target cells are occupied.
44
+ * - CSE array formulas: `{=formula}` with a ref range distribute results
45
+ * across the designated range.
46
+ * - Array arithmetic broadcasting: `{1,2,3} + {4;5;6}` produces a 3x3 matrix.
47
+ * - Implicit intersection: range references in scalar context pick the
48
+ * value from the formula cell's row or column.
49
+ *
50
+ * **Unsupported formula behavior:**
51
+ * - If a formula uses a function the engine does not implement, the engine
52
+ * returns `#NAME?`. However, if the cell already has a cached result
53
+ * (e.g., pre-computed by Excel when the XLSX was saved), that cached
54
+ * result is **preserved** — the engine will not overwrite usable data.
55
+ * - If no cached result exists, the cell's result becomes `#NAME?`.
56
+ *
57
+ * **Volatile functions:**
58
+ * - `RAND`, `RANDBETWEEN`, `NOW`, `TODAY` are re-evaluated on every call.
59
+ * This is intentional — these functions are expected to produce fresh values.
60
+ *
61
+ * **Side effects:**
62
+ * - This function **mutates** the workbook by updating formula cells' `result`
63
+ * property in-place. For dynamic array formulas, adjacent cells are also
64
+ * written with spill results. If you need the original cached results
65
+ * preserved, clone the workbook before calling this function.
66
+ *
67
+ * @param workbook - The workbook whose formulas should be recalculated
68
+ */
69
+ function calculateFormulas(workbook) {
70
+ (0, calculate_formulas_impl_1.calculateFormulasImpl)(workbook);
71
+ }