@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,1076 @@
1
+ "use strict";
2
+ /**
3
+ * Formula Tokenizer
4
+ *
5
+ * Converts an Excel formula string into a stream of tokens.
6
+ * Supports cell references (A1, $A$1), ranges (A1:B10),
7
+ * cross-sheet references (Sheet1!A1), operators, function calls,
8
+ * numbers, strings, booleans, and error literals.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.tokenize = tokenize;
12
+ // ============================================================================
13
+ // Character Helpers
14
+ // ============================================================================
15
+ function isDigit(ch) {
16
+ return ch >= "0" && ch <= "9";
17
+ }
18
+ // Matches a single Unicode letter (any script). Used by `isAlpha` for the
19
+ // non-ASCII path so that defined names in Chinese, Japanese, Korean, Cyrillic,
20
+ // Greek, etc. tokenise correctly (e.g. `=销售额+10`).
21
+ //
22
+ // Note: JavaScript strings are UTF-16, so `formula[i]` yields a single code
23
+ // unit. This regex correctly identifies any BMP letter. Astral-plane letters
24
+ // (U+10000+) require surrogate-pair handling which would be more invasive;
25
+ // BMP coverage is sufficient for virtually all real-world named ranges.
26
+ const UNICODE_LETTER = /\p{L}/u;
27
+ function isAlpha(ch) {
28
+ // ASCII fast path — the overwhelming majority of Excel formulas.
29
+ if ((ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z")) {
30
+ return true;
31
+ }
32
+ // Any other ASCII character (digits, punctuation, control) is not a letter.
33
+ if (ch.charCodeAt(0) < 128) {
34
+ return false;
35
+ }
36
+ // Non-ASCII: defer to Unicode letter classification.
37
+ return UNICODE_LETTER.test(ch);
38
+ }
39
+ function isAlphaNumOrUnderscore(ch) {
40
+ return isAlpha(ch) || isDigit(ch) || ch === "_" || ch === ".";
41
+ }
42
+ /**
43
+ * ASCII-only alpha check. Cell column letters are A–Z only — a Unicode
44
+ * identifier like `销售额` must never be misread as a column. Use this inside
45
+ * `parseCellRef` and other strictly-A1-notation parsers; use `isAlpha` for
46
+ * general identifier lexing where Unicode letters are valid.
47
+ */
48
+ function isAsciiAlpha(ch) {
49
+ return (ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z");
50
+ }
51
+ /**
52
+ * Cheap lookahead: does position `i` in `s` start a plausible cell or
53
+ * range reference? We only need to distinguish "this is a ref" from
54
+ * "this is anything else" — good enough to disambiguate 3D sheet
55
+ * references (`Q1:Q4!A1`) from name references.
56
+ *
57
+ * Accepts: `$?[A-Z]+$?\d+`-shaped prefixes, whole-column `$?[A-Z]+`,
58
+ * and whole-row `$?\d+`. Anything else (identifiers, punctuation,
59
+ * quotes) returns false.
60
+ */
61
+ function looksLikeCellRefStart(s, i) {
62
+ const len = s.length;
63
+ let j = i;
64
+ if (j < len && s[j] === "$") {
65
+ j++;
66
+ }
67
+ // Either letters first (cell / col) or digits first (whole row)
68
+ if (j < len && isAsciiAlpha(s[j])) {
69
+ // Consume up to 3 letters (Excel column max "XFD"). More than 3
70
+ // consecutive letters means it's not a column ref.
71
+ let letters = 0;
72
+ while (j < len && isAsciiAlpha(s[j]) && letters < 4) {
73
+ j++;
74
+ letters++;
75
+ }
76
+ if (letters === 0 || letters > 3) {
77
+ return false;
78
+ }
79
+ // Optional $digits for an A1-style cell ref; pure letters are a
80
+ // whole-column ref, also valid.
81
+ if (j < len && s[j] === "$") {
82
+ j++;
83
+ }
84
+ // At minimum the following char should be a digit or a delimiter
85
+ // that closes a whole-column ref (`:` / `,` / `)` / operators).
86
+ if (j < len && s[j] >= "0" && s[j] <= "9") {
87
+ return true;
88
+ }
89
+ return true; // whole-column ref, e.g. `A:A` or bare `A`
90
+ }
91
+ if (j < len && s[j] >= "0" && s[j] <= "9") {
92
+ // Whole-row ref (e.g. `1:5`)
93
+ return true;
94
+ }
95
+ return false;
96
+ }
97
+ /**
98
+ * Advance past a run of spaces and tabs. Used inside bracketed structured
99
+ * reference parsing where only horizontal whitespace is significant (newlines
100
+ * and carriage returns are not expected inside `[...]` tokens).
101
+ */
102
+ function skipHorizontalWhitespace(s, i, len) {
103
+ while (i < len && (s[i] === " " || s[i] === "\t")) {
104
+ i++;
105
+ }
106
+ return i;
107
+ }
108
+ // ============================================================================
109
+ // Error Literal Detection
110
+ // ============================================================================
111
+ /**
112
+ * Known Excel error literals. The constant below is sorted longest-first at
113
+ * module load so greedy longest-match in `matchErrorLiteral` is always
114
+ * correct — future entries can be added in any order.
115
+ */
116
+ const ERROR_LITERALS = [
117
+ "#GETTING_DATA",
118
+ "#BLOCKED!",
119
+ "#CONNECT!",
120
+ "#UNKNOWN!",
121
+ "#SPILL!",
122
+ "#VALUE!",
123
+ "#FIELD!",
124
+ "#DIV/0!",
125
+ "#NAME?",
126
+ "#NULL!",
127
+ "#CALC!",
128
+ "#BUSY!",
129
+ "#REF!",
130
+ "#NUM!",
131
+ "#N/A"
132
+ ].sort((a, b) => b.length - a.length);
133
+ /**
134
+ * Try to match a known Excel error literal at `pos` (which must point at `#`).
135
+ * Matches case-insensitively and greedily (longest list entry wins).
136
+ * Returns the canonical (upper-cased) value and end index, or null on no match.
137
+ */
138
+ function matchErrorLiteral(formula, pos) {
139
+ for (const lit of ERROR_LITERALS) {
140
+ const end = pos + lit.length;
141
+ if (end > formula.length) {
142
+ continue;
143
+ }
144
+ const slice = formula.slice(pos, end);
145
+ if (slice.toUpperCase() === lit) {
146
+ return { value: lit, end };
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ // ============================================================================
152
+ // Cell Reference Detection
153
+ // ============================================================================
154
+ /**
155
+ * Check if a string is a valid cell reference (like A1, $B$2, XFD1048576).
156
+ * Returns null if not a cell ref, otherwise returns parsed info.
157
+ */
158
+ function parseCellRef(s) {
159
+ let i = 0;
160
+ let colAbsolute = false;
161
+ let rowAbsolute = false;
162
+ if (i < s.length && s[i] === "$") {
163
+ colAbsolute = true;
164
+ i++;
165
+ }
166
+ const colStart = i;
167
+ while (i < s.length && isAsciiAlpha(s[i])) {
168
+ i++;
169
+ }
170
+ const colPart = s.slice(colStart, i).toUpperCase();
171
+ if (colPart.length === 0 || colPart.length > 3) {
172
+ return null;
173
+ }
174
+ // Validate column is <= XFD
175
+ if (colPart.length === 3 && colPart > "XFD") {
176
+ return null;
177
+ }
178
+ if (i < s.length && s[i] === "$") {
179
+ rowAbsolute = true;
180
+ i++;
181
+ }
182
+ const rowStart = i;
183
+ while (i < s.length && isDigit(s[i])) {
184
+ i++;
185
+ }
186
+ const rowPart = s.slice(rowStart, i);
187
+ if (rowPart.length === 0 || i !== s.length) {
188
+ return null;
189
+ }
190
+ const rowNum = parseInt(rowPart, 10);
191
+ if (rowNum < 1 || rowNum > 1048576) {
192
+ return null;
193
+ }
194
+ return { col: colPart, row: rowPart, colAbsolute, rowAbsolute };
195
+ }
196
+ // ============================================================================
197
+ // Structured Reference Bracket Parser
198
+ // ============================================================================
199
+ /** Valid special items in structured references */
200
+ const STRUCTURED_REF_SPECIALS = new Set(["#All", "#Data", "#Headers", "#Totals", "#This Row"]);
201
+ /**
202
+ * Parse the bracketed portion of a structured reference starting at position `pos`.
203
+ * `pos` must point to the opening `[`.
204
+ *
205
+ * Handles:
206
+ * [Column] → simple column
207
+ * [#Headers] → special item
208
+ * [[#Headers],[Column]] → nested: special + column
209
+ * [[#This Row],[Column]] → nested: special + column
210
+ * [[Col1]:[Col2]] → column range
211
+ * [@Column] → shorthand for [#This Row],[Column]
212
+ * [@[Column]] → alternative shorthand
213
+ *
214
+ * Returns parsed specials, columns, and the position after the closing `]`.
215
+ */
216
+ function parseStructuredRefBrackets(formula, pos) {
217
+ const len = formula.length;
218
+ if (pos >= len || formula[pos] !== "[") {
219
+ throw new Error("Expected '[' at position " + pos);
220
+ }
221
+ const specials = [];
222
+ const columns = [];
223
+ let i = pos + 1; // skip opening [
224
+ // Skip whitespace inside brackets
225
+ i = skipHorizontalWhitespace(formula, i, len);
226
+ // Check for @ shorthand: [@Column] or [@[Column]]
227
+ if (i < len && formula[i] === "@") {
228
+ specials.push("#This Row");
229
+ i++; // skip @
230
+ // Skip whitespace
231
+ i = skipHorizontalWhitespace(formula, i, len);
232
+ if (i < len && formula[i] === "[") {
233
+ // [@[Column]] form — inner bracketed column name
234
+ i++; // skip [
235
+ const colName = readBracketedItem(formula, i);
236
+ columns.push(colName.value);
237
+ i = colName.end; // after inner ]
238
+ }
239
+ else if (i < len && formula[i] !== "]") {
240
+ // [@Column] form — unbracketed column name until ]
241
+ const start = i;
242
+ while (i < len && formula[i] !== "]") {
243
+ i++;
244
+ }
245
+ const name = formula.slice(start, i).trim();
246
+ if (name.length > 0) {
247
+ columns.push(name);
248
+ }
249
+ }
250
+ // Skip whitespace before closing ]
251
+ i = skipHorizontalWhitespace(formula, i, len);
252
+ if (i < len && formula[i] === "]") {
253
+ i++; // skip closing ]
254
+ }
255
+ return { specials, columns, end: i };
256
+ }
257
+ // Check for nested brackets: [[...],[...]] or [[Col1]:[Col2]]
258
+ if (i < len && formula[i] === "[") {
259
+ // Parse comma-separated inner bracket items
260
+ while (i < len && formula[i] === "[") {
261
+ const item = readBracketedItem(formula, i + 1);
262
+ const value = item.value;
263
+ i = item.end; // after the inner ]
264
+ if (STRUCTURED_REF_SPECIALS.has(value)) {
265
+ specials.push(value);
266
+ }
267
+ else {
268
+ columns.push(value);
269
+ }
270
+ // Skip whitespace
271
+ i = skipHorizontalWhitespace(formula, i, len);
272
+ // Check for : (column range) or , (next item)
273
+ if (i < len && formula[i] === ":") {
274
+ i++; // skip :
275
+ // Skip whitespace
276
+ i = skipHorizontalWhitespace(formula, i, len);
277
+ // Next must be a [Column]
278
+ if (i < len && formula[i] === "[") {
279
+ const item2 = readBracketedItem(formula, i + 1);
280
+ columns.push(item2.value);
281
+ i = item2.end;
282
+ }
283
+ // Skip whitespace
284
+ i = skipHorizontalWhitespace(formula, i, len);
285
+ }
286
+ else if (i < len && formula[i] === ",") {
287
+ i++; // skip ,
288
+ // Skip whitespace
289
+ i = skipHorizontalWhitespace(formula, i, len);
290
+ }
291
+ }
292
+ // Skip whitespace before closing ]
293
+ i = skipHorizontalWhitespace(formula, i, len);
294
+ if (i < len && formula[i] === "]") {
295
+ i++; // skip outer closing ]
296
+ }
297
+ return { specials, columns, end: i };
298
+ }
299
+ // Check for special item: [#Headers], [#Data], etc.
300
+ if (i < len && formula[i] === "#") {
301
+ const start = i;
302
+ while (i < len && formula[i] !== "]") {
303
+ i++;
304
+ }
305
+ const value = formula.slice(start, i).trim();
306
+ if (STRUCTURED_REF_SPECIALS.has(value)) {
307
+ specials.push(value);
308
+ }
309
+ else {
310
+ // Unknown `[#Something]` is an error, not a silent no-op. Stash
311
+ // the invalid string so the binder can route it to #NAME?; doing
312
+ // this the other way (returning an empty specials+columns) would
313
+ // alias to the default data range and silently mis-evaluate. We
314
+ // use a sentinel prefix that can never match a real special so
315
+ // downstream code distinguishes it unambiguously.
316
+ specials.push(`#__INVALID__:${value}`);
317
+ }
318
+ if (i < len && formula[i] === "]") {
319
+ i++; // skip closing ]
320
+ }
321
+ return { specials, columns, end: i };
322
+ }
323
+ // Simple column reference: [Column]
324
+ const start = i;
325
+ while (i < len && formula[i] !== "]") {
326
+ i++;
327
+ }
328
+ const name = formula.slice(start, i).trim();
329
+ if (name.length > 0) {
330
+ columns.push(name);
331
+ }
332
+ if (i < len && formula[i] === "]") {
333
+ i++; // skip closing ]
334
+ }
335
+ return { specials, columns, end: i };
336
+ }
337
+ /**
338
+ * Read a single bracketed item starting after the opening `[`.
339
+ * Returns the text content and position after the closing `]`.
340
+ * Handles nested `'` escaping within bracket content (Excel uses `'` to escape
341
+ * special chars like `]`, `[`, `#` inside column names — but this is rare).
342
+ */
343
+ function readBracketedItem(formula, pos) {
344
+ const len = formula.length;
345
+ let i = pos;
346
+ let result = "";
347
+ while (i < len && formula[i] !== "]") {
348
+ if (formula[i] === "'" && i + 1 < len) {
349
+ // Escape: the next character is literal
350
+ result += formula[i + 1];
351
+ i += 2;
352
+ }
353
+ else {
354
+ result += formula[i];
355
+ i++;
356
+ }
357
+ }
358
+ if (i < len && formula[i] === "]") {
359
+ i++; // skip ]
360
+ }
361
+ return { value: result.trim(), end: i };
362
+ }
363
+ // ============================================================================
364
+ // Tokenizer
365
+ // ============================================================================
366
+ function tokenize(formula) {
367
+ const tokens = [];
368
+ let i = 0;
369
+ const len = formula.length;
370
+ // Track whether previous token could produce a value
371
+ // (used to distinguish unary vs binary +/-)
372
+ function lastTokenIsValue() {
373
+ if (tokens.length === 0) {
374
+ return false;
375
+ }
376
+ const last = tokens[tokens.length - 1];
377
+ return (last.type === 1 /* TokenType.Number */ ||
378
+ last.type === 2 /* TokenType.String */ ||
379
+ last.type === 3 /* TokenType.Boolean */ ||
380
+ last.type === 5 /* TokenType.CellRef */ ||
381
+ last.type === 6 /* TokenType.Range */ ||
382
+ last.type === 11 /* TokenType.CloseParen */ ||
383
+ last.type === 16 /* TokenType.CloseBrace */ ||
384
+ last.type === 14 /* TokenType.Percent */ ||
385
+ last.type === 19 /* TokenType.Name */ ||
386
+ last.type === 4 /* TokenType.Error */ ||
387
+ last.type === 20 /* TokenType.ColRange */ ||
388
+ last.type === 21 /* TokenType.RowRange */ ||
389
+ last.type === 22 /* TokenType.StructuredRef */);
390
+ }
391
+ /**
392
+ * True if the previous token produces a reference (cell / range / area).
393
+ * Used to detect Excel's intersection operator — a whitespace character
394
+ * that separates two refs (e.g. `A1:A10 B1:B10`).
395
+ *
396
+ * Intentionally narrower than {@link lastTokenIsValue}: scalars (numbers,
397
+ * strings, booleans, errors) are not references, so whitespace that
398
+ * follows them must not be treated as an intersection operator.
399
+ */
400
+ function lastTokenIsRef() {
401
+ if (tokens.length === 0) {
402
+ return false;
403
+ }
404
+ const last = tokens[tokens.length - 1];
405
+ return (last.type === 5 /* TokenType.CellRef */ ||
406
+ last.type === 6 /* TokenType.Range */ ||
407
+ last.type === 20 /* TokenType.ColRange */ ||
408
+ last.type === 21 /* TokenType.RowRange */ ||
409
+ last.type === 22 /* TokenType.StructuredRef */ ||
410
+ last.type === 11 /* TokenType.CloseParen */ ||
411
+ last.type === 19 /* TokenType.Name */);
412
+ }
413
+ /**
414
+ * True if `ch` can start a reference-producing token: a cell ref, range,
415
+ * sheet-qualified ref (`Sheet!`, `'Sheet'!`), named range, external ref,
416
+ * or a parenthesised ref expression.
417
+ */
418
+ function couldStartRef(ch) {
419
+ return isAlpha(ch) || ch === "$" || ch === "_" || ch === "'" || ch === "[" || ch === "(";
420
+ }
421
+ while (i < len) {
422
+ const ch = formula[i];
423
+ // Whitespace — normally ignored, but between two refs it is Excel's
424
+ // intersection operator (e.g. `A1:A10 B1:B10` → intersection of areas).
425
+ if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r") {
426
+ // Consume every consecutive whitespace character in one go.
427
+ while (i < len) {
428
+ const c = formula[i];
429
+ if (c === " " || c === "\t" || c === "\n" || c === "\r") {
430
+ i++;
431
+ }
432
+ else {
433
+ break;
434
+ }
435
+ }
436
+ // Emit an intersection token only when the previous token is a ref
437
+ // AND the next character can start another ref. Emits at most one
438
+ // token per whitespace run.
439
+ if (i < len && lastTokenIsRef() && couldStartRef(formula[i])) {
440
+ tokens.push({ type: 24 /* TokenType.Intersect */ });
441
+ }
442
+ continue;
443
+ }
444
+ // String literals
445
+ if (ch === '"') {
446
+ i++; // skip opening quote
447
+ let str = "";
448
+ let closed = false;
449
+ while (i < len) {
450
+ if (formula[i] === '"') {
451
+ if (i + 1 < len && formula[i + 1] === '"') {
452
+ // Escaped quote
453
+ str += '"';
454
+ i += 2;
455
+ }
456
+ else {
457
+ i++; // skip closing quote
458
+ closed = true;
459
+ break;
460
+ }
461
+ }
462
+ else {
463
+ str += formula[i];
464
+ i++;
465
+ }
466
+ }
467
+ if (!closed) {
468
+ // Unterminated string literal — reject at tokenize time so we
469
+ // never hand the parser a truncated value that could alias to a
470
+ // different formula. Excel rejects this outright.
471
+ throw new Error(`Unterminated string literal at position ${i}`);
472
+ }
473
+ tokens.push({ type: 2 /* TokenType.String */, value: str });
474
+ continue;
475
+ }
476
+ // Error literals (#N/A, #REF!, #DIV/0!, etc.)
477
+ // Match greedily against the known Excel error literals (case-insensitive),
478
+ // preferring the longest match so that "#N/A" isn't parsed as "#N" + "/A".
479
+ if (ch === "#") {
480
+ const matched = matchErrorLiteral(formula, i);
481
+ if (matched) {
482
+ tokens.push({ type: 4 /* TokenType.Error */, value: matched.value });
483
+ i = matched.end;
484
+ continue;
485
+ }
486
+ // Fallback: consume through any unknown `#...` token and emit it
487
+ // as a #NAME? error. Unknown error literals (`#FOOBAR!`) are what
488
+ // Excel itself surfaces as #NAME?, and consumers downstream
489
+ // whitelist a fixed set of error codes — letting arbitrary strings
490
+ // like `#FOOBAR!` or bare `#` leak through breaks their enum
491
+ // checks. Normalising to #NAME? here keeps error propagation safe.
492
+ i++;
493
+ while (i < len &&
494
+ formula[i] !== " " &&
495
+ formula[i] !== "," &&
496
+ formula[i] !== ")" &&
497
+ formula[i] !== "+" &&
498
+ formula[i] !== "-" &&
499
+ formula[i] !== "*" &&
500
+ formula[i] !== "/" &&
501
+ formula[i] !== "^" &&
502
+ formula[i] !== "&" &&
503
+ formula[i] !== "=" &&
504
+ formula[i] !== "<" &&
505
+ formula[i] !== ">" &&
506
+ formula[i] !== "}") {
507
+ i++;
508
+ }
509
+ tokens.push({ type: 4 /* TokenType.Error */, value: "#NAME?" });
510
+ continue;
511
+ }
512
+ // External workbook reference: [Book.xlsx]Sheet!A1
513
+ // When [ appears and is NOT preceded by a value token (not array literal context),
514
+ // consume the bracketed workbook name and subsequent sheet!ref as a Name token.
515
+ // This allows the engine to fall back to cached results gracefully.
516
+ //
517
+ // But: a bare [...] can also be a standalone structured reference
518
+ // ([@Col], [#Headers], [[#This Row],[Col]], [Column Name]). Only treat it
519
+ // as an external ref when it really is followed by a `Sheet!` suffix;
520
+ // otherwise fall through to the structured-reference branch below.
521
+ if (ch === "[" && !lastTokenIsValue()) {
522
+ // Peek at first non-whitespace char after [ — @ or # always means a
523
+ // structured reference, never an external workbook reference.
524
+ const peek = skipHorizontalWhitespace(formula, i + 1, len);
525
+ const firstCh = peek < len ? formula[peek] : "";
526
+ const looksStructured = firstCh === "@" || firstCh === "#" || firstCh === "[";
527
+ if (!looksStructured) {
528
+ // Try to parse as an external ref: [WorkbookName]Sheet!...
529
+ let scan = i + 1;
530
+ let hasClose = false;
531
+ while (scan < len) {
532
+ if (formula[scan] === "]") {
533
+ hasClose = true;
534
+ scan++;
535
+ break;
536
+ }
537
+ scan++;
538
+ }
539
+ // Validate: after the closing ], we must see a sheet name (or quoted
540
+ // sheet name) followed by `!`. Otherwise this isn't an external ref.
541
+ let isExternal = false;
542
+ if (hasClose && scan < len) {
543
+ let p = scan;
544
+ if (formula[p] === "'") {
545
+ // Quoted sheet name — scan to matching '
546
+ p++;
547
+ while (p < len) {
548
+ if (formula[p] === "'") {
549
+ if (p + 1 < len && formula[p + 1] === "'") {
550
+ p += 2;
551
+ }
552
+ else {
553
+ p++;
554
+ break;
555
+ }
556
+ }
557
+ else {
558
+ p++;
559
+ }
560
+ }
561
+ if (p < len && formula[p] === "!") {
562
+ isExternal = true;
563
+ }
564
+ }
565
+ else {
566
+ // Unquoted sheet name — identifier chars, then !
567
+ const sheetStart = p;
568
+ while (p < len && (isAlphaNumOrUnderscore(formula[p]) || formula[p] === "$")) {
569
+ p++;
570
+ }
571
+ if (p > sheetStart && p < len && formula[p] === "!") {
572
+ isExternal = true;
573
+ }
574
+ }
575
+ }
576
+ if (isExternal) {
577
+ // External workbook references are unsupported — consume the full
578
+ // ref syntax (including any `:CELL` range suffix) so downstream
579
+ // tokens aren't polluted, then emit a single `#REF!` error token.
580
+ // The boundary logic preserved here matches the pre-simplification
581
+ // tokenizer exactly so the range of characters consumed is stable.
582
+ i = scan;
583
+ while (i < len &&
584
+ formula[i] !== "+" &&
585
+ formula[i] !== "-" &&
586
+ formula[i] !== "*" &&
587
+ formula[i] !== "/" &&
588
+ formula[i] !== "^" &&
589
+ formula[i] !== "&" &&
590
+ formula[i] !== "=" &&
591
+ formula[i] !== "<" &&
592
+ formula[i] !== ">" &&
593
+ formula[i] !== ")" &&
594
+ formula[i] !== "," &&
595
+ formula[i] !== " " &&
596
+ formula[i] !== "}" &&
597
+ formula[i] !== ":" &&
598
+ formula[i] !== "%" &&
599
+ formula[i] !== ";" &&
600
+ formula[i] !== "{") {
601
+ i++;
602
+ }
603
+ // Extend consumption through `:CELL` if this is a range form
604
+ // like [Book]Sheet!A1:A5. Without this, `:` would split the
605
+ // external ref and pollute downstream tokens.
606
+ if (i < len && formula[i] === ":") {
607
+ let q = i + 1;
608
+ // Optional $ absolute markers, column letters, optional $, row digits
609
+ if (q < len && formula[q] === "$") {
610
+ q++;
611
+ }
612
+ const colStart = q;
613
+ while (q < len && isAsciiAlpha(formula[q])) {
614
+ q++;
615
+ }
616
+ if (q > colStart) {
617
+ if (q < len && formula[q] === "$") {
618
+ q++;
619
+ }
620
+ const rowStart = q;
621
+ while (q < len && isDigit(formula[q])) {
622
+ q++;
623
+ }
624
+ if (q > rowStart) {
625
+ // Valid `:CELL` suffix — consume it as part of the ref
626
+ i = q;
627
+ }
628
+ }
629
+ }
630
+ tokens.push({ type: 4 /* TokenType.Error */, value: "#REF!" });
631
+ continue;
632
+ }
633
+ // Not an external ref — fall through to the structured-reference
634
+ // branch below, which handles bare [Column Name] etc.
635
+ }
636
+ }
637
+ // Array constant braces
638
+ if (ch === "{") {
639
+ tokens.push({ type: 15 /* TokenType.OpenBrace */ });
640
+ i++;
641
+ continue;
642
+ }
643
+ if (ch === "}") {
644
+ tokens.push({ type: 16 /* TokenType.CloseBrace */ });
645
+ i++;
646
+ continue;
647
+ }
648
+ // Semicolons (array row separator)
649
+ if (ch === ";") {
650
+ tokens.push({ type: 17 /* TokenType.Semicolon */ });
651
+ i++;
652
+ continue;
653
+ }
654
+ // Numbers (and potential whole-row ranges like 1:5)
655
+ if (isDigit(ch) || (ch === "." && i + 1 < len && isDigit(formula[i + 1]))) {
656
+ const start = i;
657
+ while (i < len && isDigit(formula[i])) {
658
+ i++;
659
+ }
660
+ // Check for whole-row range: pure integer followed by : and another integer
661
+ const isInteger = i > start && formula[start] !== "." && i < len && formula[i] === ":";
662
+ if (isInteger) {
663
+ const row1Str = formula.slice(start, i);
664
+ const row1 = parseInt(row1Str, 10);
665
+ if (row1 >= 1 && row1 <= 1048576) {
666
+ const colonPos = i;
667
+ i++; // skip :
668
+ // Optional $ before second row number
669
+ const start2 = i;
670
+ if (i < len && formula[i] === "$") {
671
+ i++;
672
+ }
673
+ const rowStart2 = i;
674
+ while (i < len && isDigit(formula[i])) {
675
+ i++;
676
+ }
677
+ if (i > rowStart2) {
678
+ const row2Str = formula.slice(rowStart2, i);
679
+ const row2 = parseInt(row2Str, 10);
680
+ if (row2 >= 1 && row2 <= 1048576) {
681
+ tokens.push({
682
+ type: 21 /* TokenType.RowRange */,
683
+ value: row1Str + ":" + formula.slice(start2, i)
684
+ });
685
+ continue;
686
+ }
687
+ }
688
+ // Not a valid row range, backtrack
689
+ i = colonPos;
690
+ }
691
+ }
692
+ // Fractional part — only consume the `.` when at least one digit
693
+ // follows. This prevents "1..2" from being tokenised as "1." + ".2"
694
+ // with the first `.` silently absorbed into the integer number.
695
+ if (i < len && formula[i] === "." && i + 1 < len && isDigit(formula[i + 1])) {
696
+ i++;
697
+ while (i < len && isDigit(formula[i])) {
698
+ i++;
699
+ }
700
+ }
701
+ // Scientific notation. Only commit to consuming `e[+-]?` when at least
702
+ // one digit actually follows — otherwise restore position and stop the
703
+ // number here, so `1e` or `1e+` don't parse as the number `1`.
704
+ if (i < len && (formula[i] === "E" || formula[i] === "e")) {
705
+ const expStart = i;
706
+ let j = i + 1;
707
+ if (j < len && (formula[j] === "+" || formula[j] === "-")) {
708
+ j++;
709
+ }
710
+ if (j < len && isDigit(formula[j])) {
711
+ // Commit: consume e, optional sign, and the digit run.
712
+ i = j;
713
+ while (i < len && isDigit(formula[i])) {
714
+ i++;
715
+ }
716
+ }
717
+ else {
718
+ // Not a valid exponent — leave the `e`/`E` for the identifier lexer.
719
+ i = expStart;
720
+ }
721
+ }
722
+ tokens.push({ type: 1 /* TokenType.Number */, value: formula.slice(start, i) });
723
+ continue;
724
+ }
725
+ // Quoted sheet name: 'Sheet Name'! or 3D ref 'Sheet1:Sheet3'!
726
+ if (ch === "'") {
727
+ i++; // skip opening quote
728
+ let sheetName = "";
729
+ while (i < len) {
730
+ if (formula[i] === "'") {
731
+ if (i + 1 < len && formula[i + 1] === "'") {
732
+ sheetName += "'";
733
+ i += 2;
734
+ }
735
+ else {
736
+ i++; // skip closing quote
737
+ break;
738
+ }
739
+ }
740
+ else {
741
+ sheetName += formula[i];
742
+ i++;
743
+ }
744
+ }
745
+ // Expect ! after
746
+ if (i < len && formula[i] === "!") {
747
+ i++; // skip !
748
+ }
749
+ // Check for 3D reference: sheetName contains an unquoted colon separating two sheet names
750
+ // e.g. 'Sheet1:Sheet3' → startSheet="Sheet1", endSheet="Sheet3"
751
+ const colonIdx = sheetName.indexOf(":");
752
+ if (colonIdx > 0 && colonIdx < sheetName.length - 1) {
753
+ const startSheet = sheetName.slice(0, colonIdx);
754
+ const endSheet = sheetName.slice(colonIdx + 1);
755
+ tokens.push({
756
+ type: 7 /* TokenType.SheetRef */,
757
+ sheetName: startSheet,
758
+ endSheetName: endSheet
759
+ });
760
+ }
761
+ else {
762
+ tokens.push({
763
+ type: 7 /* TokenType.SheetRef */,
764
+ sheetName
765
+ });
766
+ }
767
+ continue;
768
+ }
769
+ // Standalone structured reference: [@Column] or [[#This Row],[Column]]
770
+ if (ch === "[") {
771
+ const sr = parseStructuredRefBrackets(formula, i);
772
+ tokens.push({
773
+ type: 22 /* TokenType.StructuredRef */,
774
+ tableName: "",
775
+ columns: sr.columns,
776
+ specials: sr.specials
777
+ });
778
+ i = sr.end;
779
+ continue;
780
+ }
781
+ // Identifiers: cell refs, function names, booleans, named ranges, sheet refs
782
+ if (isAlpha(ch) || ch === "$" || ch === "_") {
783
+ const start = i;
784
+ // Collect $-prefixed or alpha-numeric identifier
785
+ while (i < len && (isAlphaNumOrUnderscore(formula[i]) || formula[i] === "$")) {
786
+ i++;
787
+ }
788
+ const word = formula.slice(start, i);
789
+ // Check for sheet reference: WORD!
790
+ if (i < len && formula[i] === "!") {
791
+ i++; // skip !
792
+ tokens.push({
793
+ type: 7 /* TokenType.SheetRef */,
794
+ sheetName: word
795
+ });
796
+ continue;
797
+ }
798
+ // Check for 3D sheet reference: WORD:WORD!<ref>
799
+ // (e.g. Sheet1:Sheet3!A1, Q1:Q4!A1).
800
+ //
801
+ // Priority rule: when we see `WORD:WORD!` followed by an actual
802
+ // cell/range reference, that whole prefix is a 3D SheetRef —
803
+ // even when the first WORD looks like a cell reference on its
804
+ // own (sheet names like "Q1" are common). Previously we bailed
805
+ // out of this branch whenever `parseCellRef(word) !== null`,
806
+ // which left workbooks with sheets named Q1..Q4 unable to use
807
+ // 3D formulas.
808
+ //
809
+ // The fallback path below (RangeRef for `A1:B2`-shaped inputs)
810
+ // still fires when there is NO `!` — the lookahead disambiguates
811
+ // the two cases cleanly.
812
+ if (i < len && formula[i] === ":") {
813
+ const colonPos3D = i;
814
+ let j = i + 1;
815
+ // Collect the second sheet name (alphanumeric + underscore + .)
816
+ while (j < len && (isAlphaNumOrUnderscore(formula[j]) || formula[j] === "$")) {
817
+ j++;
818
+ }
819
+ if (j > colonPos3D + 1 && j < len && formula[j] === "!") {
820
+ const endSheet = formula.slice(colonPos3D + 1, j);
821
+ // Peek past `!` — accept the 3D reading only if a recognisable
822
+ // cell or range reference follows. Otherwise fall through
823
+ // so `A1:A3` (no trailing `!`) keeps its RangeRef reading.
824
+ const afterBang = j + 1;
825
+ if (afterBang < len && looksLikeCellRefStart(formula, afterBang)) {
826
+ i = afterBang; // skip past !
827
+ tokens.push({
828
+ type: 7 /* TokenType.SheetRef */,
829
+ sheetName: word,
830
+ endSheetName: endSheet
831
+ });
832
+ continue;
833
+ }
834
+ }
835
+ }
836
+ // Check for structured reference: WORD[...]
837
+ if (i < len && formula[i] === "[") {
838
+ const sr = parseStructuredRefBrackets(formula, i);
839
+ tokens.push({
840
+ type: 22 /* TokenType.StructuredRef */,
841
+ tableName: word,
842
+ columns: sr.columns,
843
+ specials: sr.specials
844
+ });
845
+ i = sr.end;
846
+ continue;
847
+ }
848
+ // Check for function call: WORD(
849
+ if (i < len && formula[i] === "(") {
850
+ tokens.push({ type: 8 /* TokenType.Function */, name: word.toUpperCase() });
851
+ // Don't consume the '(' — it will be consumed in the next iteration
852
+ continue;
853
+ }
854
+ // Check for boolean literals
855
+ const upper = word.toUpperCase();
856
+ if (upper === "TRUE" || upper === "FALSE") {
857
+ tokens.push({ type: 3 /* TokenType.Boolean */, value: upper });
858
+ continue;
859
+ }
860
+ // Check for cell reference
861
+ const ref = parseCellRef(word);
862
+ if (ref) {
863
+ const cellToken = {
864
+ type: 5 /* TokenType.CellRef */,
865
+ col: ref.col,
866
+ row: ref.row,
867
+ colAbsolute: ref.colAbsolute,
868
+ rowAbsolute: ref.rowAbsolute
869
+ };
870
+ tokens.push(cellToken);
871
+ // Check if this is part of a range (A1:B2)
872
+ if (i < len && formula[i] === ":") {
873
+ // Peek ahead for another cell ref
874
+ const colonPos = i;
875
+ i++; // skip :
876
+ const rangeStart = i;
877
+ while (i < len && (isAlphaNumOrUnderscore(formula[i]) || formula[i] === "$")) {
878
+ i++;
879
+ }
880
+ const secondWord = formula.slice(rangeStart, i);
881
+ const ref2 = parseCellRef(secondWord);
882
+ if (ref2) {
883
+ // It's a range — replace the last CellRef token with a Range token
884
+ tokens[tokens.length - 1] = {
885
+ type: 6 /* TokenType.Range */,
886
+ value: (ref.colAbsolute ? "$" : "") +
887
+ ref.col +
888
+ (ref.rowAbsolute ? "$" : "") +
889
+ ref.row +
890
+ ":" +
891
+ (ref2.colAbsolute ? "$" : "") +
892
+ ref2.col +
893
+ (ref2.rowAbsolute ? "$" : "") +
894
+ ref2.row
895
+ };
896
+ }
897
+ else {
898
+ // Not a valid range, push : as operator and backtrack
899
+ i = colonPos; // backtrack — let : be handled normally
900
+ }
901
+ }
902
+ continue;
903
+ }
904
+ // Otherwise it's a named range / defined name — but check for whole-column range first (A:B, $A:$B)
905
+ // A whole-column ref looks like: [pure-alpha or $+alpha] followed by ':'
906
+ if (i < len && formula[i] === ":") {
907
+ // Check if 'word' is a pure column reference (optional $ + letters only, no digits)
908
+ const colRefMatch = /^(\$?)([A-Za-z]{1,3})$/.exec(word);
909
+ if (colRefMatch) {
910
+ const col1Abs = colRefMatch[1] === "$";
911
+ const col1 = colRefMatch[2].toUpperCase();
912
+ // Validate column <= XFD
913
+ if (col1.length <= 3 && (col1.length < 3 || col1 <= "XFD")) {
914
+ const colonPos = i;
915
+ i++; // skip :
916
+ // Read the second column ref
917
+ const start2 = i;
918
+ if (i < len && formula[i] === "$") {
919
+ i++;
920
+ }
921
+ const colStart2 = i;
922
+ while (i < len && isAsciiAlpha(formula[i])) {
923
+ i++;
924
+ }
925
+ // Ensure it's ONLY letters (no digits follow = not a cell ref)
926
+ const afterLetters = i;
927
+ const isFollowedByDigit = i < len && isDigit(formula[i]);
928
+ if (!isFollowedByDigit && afterLetters > colStart2) {
929
+ const part2 = formula.slice(start2, i);
930
+ const col2Match = /^(\$?)([A-Za-z]{1,3})$/.exec(part2);
931
+ if (col2Match) {
932
+ const col2 = col2Match[2].toUpperCase();
933
+ if (col2.length <= 3 && (col2.length < 3 || col2 <= "XFD")) {
934
+ tokens.push({
935
+ type: 20 /* TokenType.ColRange */,
936
+ value: (col1Abs ? "$" : "") + col1 + ":" + part2.toUpperCase()
937
+ });
938
+ continue;
939
+ }
940
+ }
941
+ }
942
+ // Not a valid column range, backtrack
943
+ i = colonPos;
944
+ }
945
+ }
946
+ // Check for absolute whole-row range: $1:$5
947
+ const absRowMatch = /^(\$)(\d+)$/.exec(word);
948
+ if (absRowMatch) {
949
+ const row1 = parseInt(absRowMatch[2], 10);
950
+ if (row1 >= 1 && row1 <= 1048576) {
951
+ const colonPos = i;
952
+ i++; // skip :
953
+ const start2 = i;
954
+ if (i < len && formula[i] === "$") {
955
+ i++;
956
+ }
957
+ const rowStart2 = i;
958
+ while (i < len && isDigit(formula[i])) {
959
+ i++;
960
+ }
961
+ if (i > rowStart2) {
962
+ const row2 = parseInt(formula.slice(rowStart2, i), 10);
963
+ if (row2 >= 1 && row2 <= 1048576) {
964
+ tokens.push({
965
+ type: 21 /* TokenType.RowRange */,
966
+ value: word + ":" + formula.slice(start2, i)
967
+ });
968
+ continue;
969
+ }
970
+ }
971
+ i = colonPos;
972
+ }
973
+ }
974
+ }
975
+ tokens.push({ type: 19 /* TokenType.Name */, value: word });
976
+ continue;
977
+ }
978
+ // Operators and punctuation
979
+ if (ch === "(") {
980
+ tokens.push({ type: 10 /* TokenType.OpenParen */ });
981
+ i++;
982
+ continue;
983
+ }
984
+ if (ch === ")") {
985
+ tokens.push({ type: 11 /* TokenType.CloseParen */ });
986
+ i++;
987
+ continue;
988
+ }
989
+ if (ch === ",") {
990
+ tokens.push({ type: 12 /* TokenType.Comma */ });
991
+ i++;
992
+ continue;
993
+ }
994
+ if (ch === ":") {
995
+ tokens.push({ type: 13 /* TokenType.Colon */ });
996
+ i++;
997
+ continue;
998
+ }
999
+ if (ch === "%") {
1000
+ tokens.push({ type: 14 /* TokenType.Percent */ });
1001
+ i++;
1002
+ continue;
1003
+ }
1004
+ // Multi-character operators
1005
+ if (ch === "<") {
1006
+ if (i + 1 < len && formula[i + 1] === "=") {
1007
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "<=" });
1008
+ i += 2;
1009
+ continue;
1010
+ }
1011
+ if (i + 1 < len && formula[i + 1] === ">") {
1012
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "<>" });
1013
+ i += 2;
1014
+ continue;
1015
+ }
1016
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "<" });
1017
+ i++;
1018
+ continue;
1019
+ }
1020
+ if (ch === ">") {
1021
+ if (i + 1 < len && formula[i + 1] === "=") {
1022
+ tokens.push({ type: 9 /* TokenType.Operator */, value: ">=" });
1023
+ i += 2;
1024
+ continue;
1025
+ }
1026
+ tokens.push({ type: 9 /* TokenType.Operator */, value: ">" });
1027
+ i++;
1028
+ continue;
1029
+ }
1030
+ if (ch === "=") {
1031
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "=" });
1032
+ i++;
1033
+ continue;
1034
+ }
1035
+ if (ch === "&") {
1036
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "&" });
1037
+ i++;
1038
+ continue;
1039
+ }
1040
+ if (ch === "^") {
1041
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "^" });
1042
+ i++;
1043
+ continue;
1044
+ }
1045
+ if (ch === "*") {
1046
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "*" });
1047
+ i++;
1048
+ continue;
1049
+ }
1050
+ if (ch === "/") {
1051
+ tokens.push({ type: 9 /* TokenType.Operator */, value: "/" });
1052
+ i++;
1053
+ continue;
1054
+ }
1055
+ // + and - : unary or binary
1056
+ if (ch === "+" || ch === "-") {
1057
+ if (!lastTokenIsValue()) {
1058
+ tokens.push({ type: 18 /* TokenType.UnaryPrefix */, value: ch });
1059
+ }
1060
+ else {
1061
+ tokens.push({ type: 9 /* TokenType.Operator */, value: ch });
1062
+ }
1063
+ i++;
1064
+ continue;
1065
+ }
1066
+ // @ implicit intersection prefix (Excel 365)
1067
+ if (ch === "@") {
1068
+ tokens.push({ type: 23 /* TokenType.AtSign */ });
1069
+ i++;
1070
+ continue;
1071
+ }
1072
+ // Unknown character — skip
1073
+ i++;
1074
+ }
1075
+ return tokens;
1076
+ }