@svgrid/enterprise 3.0.2 → 3.0.3

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 (364) hide show
  1. package/LICENSE +94 -24
  2. package/README.md +36 -4
  3. package/dist/SvAdvancedFilter.svelte +1 -1
  4. package/dist/SvAlertsManager.svelte +2 -1
  5. package/dist/SvBoard.svelte +2 -1
  6. package/dist/SvExportMenu.svelte +4 -1
  7. package/dist/SvExportMenu.svelte.d.ts +0 -13
  8. package/dist/SvExpressionEditor.svelte +3 -3
  9. package/dist/SvFormulaBar.svelte +94 -20
  10. package/dist/SvFormulaBar.svelte.d.ts +7 -0
  11. package/dist/SvGridAlerts.svelte +49 -9
  12. package/dist/SvGridBoard.svelte +13 -8
  13. package/dist/SvGridBulkEditDrawer.svelte +26 -2
  14. package/dist/SvGridEditPanel.svelte +3 -0
  15. package/dist/SvGridScheduler.svelte +69 -40
  16. package/dist/SvGridSelectionBar.svelte +10 -3
  17. package/dist/SvPivotDesigner.svelte +198 -40
  18. package/dist/SvPivotDesigner.svelte.d.ts +27 -20
  19. package/dist/SvSheet.svelte +4043 -243
  20. package/dist/SvSheet.svelte.d.ts +76 -3
  21. package/dist/SvSheetChartSetup.svelte +151 -0
  22. package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
  23. package/dist/SvSheetComment.svelte +216 -31
  24. package/dist/SvSheetComment.svelte.d.ts +11 -11
  25. package/dist/SvSheetConditionalFormat.svelte +28 -31
  26. package/dist/SvSheetDataValidation.svelte +66 -42
  27. package/dist/SvSheetEditRanges.svelte +217 -0
  28. package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
  29. package/dist/SvSheetErrors.svelte +125 -0
  30. package/dist/SvSheetErrors.svelte.d.ts +20 -0
  31. package/dist/SvSheetEvaluate.svelte +133 -0
  32. package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
  33. package/dist/SvSheetFilterMenu.svelte +137 -34
  34. package/dist/SvSheetFilterMenu.svelte.d.ts +5 -0
  35. package/dist/SvSheetFindReplace.svelte +19 -19
  36. package/dist/SvSheetFormatCells.svelte +125 -81
  37. package/dist/SvSheetGoalSeek.svelte +17 -16
  38. package/dist/SvSheetInsertFunction.svelte +15 -13
  39. package/dist/SvSheetIteration.svelte +81 -0
  40. package/dist/SvSheetIteration.svelte.d.ts +10 -0
  41. package/dist/SvSheetLink.svelte +99 -0
  42. package/dist/SvSheetLink.svelte.d.ts +17 -0
  43. package/dist/SvSheetListPicker.svelte +4 -2
  44. package/dist/SvSheetListPicker.svelte.d.ts +0 -6
  45. package/dist/SvSheetManageRules.svelte +20 -18
  46. package/dist/SvSheetNameManager.svelte +17 -15
  47. package/dist/SvSheetPageSetup.svelte +159 -0
  48. package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
  49. package/dist/SvSheetPasteSpecial.svelte +22 -20
  50. package/dist/SvSheetPivot.svelte +220 -0
  51. package/dist/SvSheetPivot.svelte.d.ts +21 -0
  52. package/dist/SvSheetProtectSheet.svelte +81 -0
  53. package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
  54. package/dist/SvSheetRemoveDuplicates.svelte +13 -10
  55. package/dist/SvSheetRibbon.svelte +104 -51
  56. package/dist/SvSheetSizeDialog.svelte +4 -2
  57. package/dist/SvSheetSort.svelte +218 -0
  58. package/dist/SvSheetSort.svelte.d.ts +28 -0
  59. package/dist/SvSheetSparklines.svelte +135 -0
  60. package/dist/SvSheetSparklines.svelte.d.ts +14 -0
  61. package/dist/SvSheetTable.svelte +160 -0
  62. package/dist/SvSheetTable.svelte.d.ts +24 -0
  63. package/dist/SvSheetTabs.svelte +161 -31
  64. package/dist/SvSheetTabs.svelte.d.ts +22 -8
  65. package/dist/SvSheetTextToColumns.svelte +20 -20
  66. package/dist/SvSheetValidationAlert.svelte +8 -6
  67. package/dist/advanced-filter-enable.js +1 -1
  68. package/dist/alerts/alert-engine.d.ts +6 -0
  69. package/dist/alerts/alert-engine.js +21 -4
  70. package/dist/alerts/alert-formats.js +2 -0
  71. package/dist/alerts/alert-types.d.ts +1 -1
  72. package/dist/alerts.d.ts +1 -1
  73. package/dist/alerts.js +2 -2
  74. package/dist/board.js +2 -2
  75. package/dist/bulk-edit.d.ts +3 -1
  76. package/dist/bulk-edit.js +1 -1
  77. package/dist/cdn/svgrid-enterprise.svelte-external.js +39827 -16429
  78. package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
  79. package/dist/designer/assets/{SvChartMenu-D9hEeHar.js → SvChartMenu-BDoeqGz6.js} +1 -1
  80. package/dist/designer/assets/{SvDateTimePicker-DARvKUL2.js → SvDateTimePicker-DCPg7WGN.js} +1 -1
  81. package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
  82. package/dist/designer/assets/{SvGridChart-B8j1SSy3.js → SvGridChart-Cy1ATrWh.js} +2 -2
  83. package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
  84. package/dist/designer/assets/{SvGridChartPanel-pT6ITc2P.js → SvGridChartPanel-CATdVc9X.js} +3 -3
  85. package/dist/designer/assets/{SvGridChartView-bg281UA1.js → SvGridChartView-CmsZtCED.js} +1 -1
  86. package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
  87. package/dist/designer/assets/{SvTabs-UFCMTHXS.js → SvTabs-2mHC6oaz.js} +1 -1
  88. package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
  89. package/dist/designer/assets/{chart-cIPUsbM5.js → chart-Cn7MnNqA.js} +1 -1
  90. package/dist/designer/assets/{chart-panel-messages-DtTxpBUU.js → chart-panel-messages-Dz7PTIqT.js} +1 -1
  91. package/dist/designer/assets/{chart-summary-Czu_5epb.js → chart-summary-BD1qYB2R.js} +1 -1
  92. package/dist/designer/assets/{chart-trend-D5I5VEe8.js → chart-trend-B8xr5LuD.js} +1 -1
  93. package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
  94. package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
  95. package/dist/designer/assets/{focus-trap-CAreAhlU.js → focus-trap-V2-6Fy9I.js} +1 -1
  96. package/dist/designer/assets/{index-DwU7CAMm.js → index-D5bVbuzI.js} +317 -315
  97. package/dist/designer/assets/index-_JVFxt02.css +1 -0
  98. package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
  99. package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
  100. package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
  101. package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
  102. package/dist/designer/index.html +17 -16
  103. package/dist/export-pdf.d.ts +75 -0
  104. package/dist/export-pdf.js +216 -15
  105. package/dist/export.js +10 -2
  106. package/dist/gantt/SvGridGantt.svelte +2890 -0
  107. package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
  108. package/dist/gantt/gantt-config.d.ts +73 -0
  109. package/dist/gantt/gantt-config.js +1 -0
  110. package/dist/gantt/gantt-critical-path.d.ts +67 -0
  111. package/dist/gantt/gantt-critical-path.js +207 -0
  112. package/dist/gantt/gantt-model.d.ts +257 -0
  113. package/dist/gantt/gantt-model.js +651 -0
  114. package/dist/gantt/gantt-resources.d.ts +59 -0
  115. package/dist/gantt/gantt-resources.js +71 -0
  116. package/dist/gantt/gantt.d.ts +7 -0
  117. package/dist/gantt/gantt.js +36 -0
  118. package/dist/gantt/index.d.ts +15 -0
  119. package/dist/gantt/index.js +22 -0
  120. package/dist/gantt/timeline-arrows.d.ts +102 -0
  121. package/dist/gantt/timeline-arrows.js +181 -0
  122. package/dist/import.d.ts +2 -2
  123. package/dist/import.js +1 -1
  124. package/dist/index.d.ts +34 -7
  125. package/dist/index.js +44 -7
  126. package/dist/install.js +8 -1
  127. package/dist/license-core.d.ts +17 -1
  128. package/dist/license-core.js +16 -5
  129. package/dist/license.d.ts +18 -2
  130. package/dist/license.js +71 -6
  131. package/dist/node/studio.js +140 -8
  132. package/dist/pivot-enable.js +2 -2
  133. package/dist/scheduler-dependencies.d.ts +35 -0
  134. package/dist/scheduler-dependencies.js +36 -1
  135. package/dist/scheduler.js +2 -2
  136. package/dist/selection-bar.js +2 -2
  137. package/dist/server/SvGroupCell.svelte +213 -0
  138. package/dist/server/SvGroupCell.svelte.d.ts +62 -0
  139. package/dist/server/SvRowGroupPanel.svelte +322 -0
  140. package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
  141. package/dist/server/enable.d.ts +17 -0
  142. package/dist/server/enable.js +49 -0
  143. package/dist/server/index.d.ts +22 -0
  144. package/dist/server/index.js +24 -0
  145. package/dist/server/messages.d.ts +45 -0
  146. package/dist/server/messages.js +35 -0
  147. package/dist/server/server-group-model.d.ts +104 -0
  148. package/dist/server/server-group-model.js +272 -0
  149. package/dist/server/server-pivot.d.ts +46 -0
  150. package/dist/server/server-pivot.js +57 -0
  151. package/dist/server/server-row-model.d.ts +547 -0
  152. package/dist/server/server-row-model.js +1551 -0
  153. package/dist/server/server-selection.d.ts +99 -0
  154. package/dist/server/server-selection.js +215 -0
  155. package/dist/server/svgrid-adapter.d.ts +155 -0
  156. package/dist/server/svgrid-adapter.js +202 -0
  157. package/dist/sheet/ast.d.ts +45 -1
  158. package/dist/sheet/ast.js +14 -0
  159. package/dist/sheet/auto-filter.d.ts +58 -4
  160. package/dist/sheet/auto-filter.js +159 -11
  161. package/dist/sheet/autocomplete.d.ts +9 -0
  162. package/dist/sheet/autocomplete.js +90 -4
  163. package/dist/sheet/cell-images.d.ts +39 -0
  164. package/dist/sheet/cell-images.js +90 -0
  165. package/dist/sheet/cell-types.d.ts +58 -0
  166. package/dist/sheet/cell-types.js +96 -0
  167. package/dist/sheet/coerce.d.ts +40 -0
  168. package/dist/sheet/coerce.js +170 -3
  169. package/dist/sheet/comments.d.ts +43 -9
  170. package/dist/sheet/comments.js +85 -27
  171. package/dist/sheet/conditional-formats.d.ts +29 -6
  172. package/dist/sheet/conditional-formats.js +37 -12
  173. package/dist/sheet/csv.d.ts +32 -0
  174. package/dist/sheet/csv.js +158 -0
  175. package/dist/sheet/culture.d.ts +87 -0
  176. package/dist/sheet/culture.js +247 -0
  177. package/dist/sheet/delta.d.ts +102 -0
  178. package/dist/sheet/delta.js +203 -0
  179. package/dist/sheet/deps.d.ts +45 -1
  180. package/dist/sheet/deps.js +77 -2
  181. package/dist/sheet/document.d.ts +106 -4
  182. package/dist/sheet/document.js +204 -3
  183. package/dist/sheet/engine.d.ts +67 -0
  184. package/dist/sheet/engine.js +19 -0
  185. package/dist/sheet/entry.d.ts +8 -4
  186. package/dist/sheet/entry.js +171 -21
  187. package/dist/sheet/error-check.d.ts +49 -0
  188. package/dist/sheet/error-check.js +83 -0
  189. package/dist/sheet/evaluate-steps.d.ts +48 -0
  190. package/dist/sheet/evaluate-steps.js +196 -0
  191. package/dist/sheet/evaluate.d.ts +67 -0
  192. package/dist/sheet/evaluate.js +725 -13
  193. package/dist/sheet/filter-files.d.ts +37 -0
  194. package/dist/sheet/filter-files.js +465 -0
  195. package/dist/sheet/format-store.d.ts +15 -0
  196. package/dist/sheet/format-store.js +11 -1
  197. package/dist/sheet/from-rows.d.ts +14 -0
  198. package/dist/sheet/from-rows.js +50 -0
  199. package/dist/sheet/function-catalog.d.ts +1 -1
  200. package/dist/sheet/function-catalog.js +296 -5
  201. package/dist/sheet/functions.js +363 -91
  202. package/dist/sheet/index.d.ts +35 -8
  203. package/dist/sheet/index.js +35 -8
  204. package/dist/sheet/links.d.ts +57 -0
  205. package/dist/sheet/links.js +174 -0
  206. package/dist/sheet/messages.d.ts +778 -0
  207. package/dist/sheet/messages.js +806 -0
  208. package/dist/sheet/number-format.d.ts +52 -5
  209. package/dist/sheet/number-format.js +465 -68
  210. package/dist/sheet/objects.d.ts +106 -0
  211. package/dist/sheet/objects.js +149 -0
  212. package/dist/sheet/ods-document.d.ts +44 -0
  213. package/dist/sheet/ods-document.js +1275 -0
  214. package/dist/sheet/open-file.d.ts +26 -0
  215. package/dist/sheet/open-file.js +56 -0
  216. package/dist/sheet/outline.d.ts +82 -0
  217. package/dist/sheet/outline.js +228 -0
  218. package/dist/sheet/packs/array.d.ts +16 -0
  219. package/dist/sheet/packs/array.js +172 -0
  220. package/dist/sheet/packs/database.d.ts +42 -0
  221. package/dist/sheet/packs/database.js +142 -0
  222. package/dist/sheet/packs/engineering.d.ts +2 -0
  223. package/dist/sheet/packs/engineering.js +296 -0
  224. package/dist/sheet/packs/financial.d.ts +5 -0
  225. package/dist/sheet/packs/financial.js +220 -0
  226. package/dist/sheet/packs/math-stats.d.ts +2 -0
  227. package/dist/sheet/packs/math-stats.js +372 -0
  228. package/dist/sheet/packs/special.d.ts +44 -0
  229. package/dist/sheet/packs/special.js +187 -0
  230. package/dist/sheet/packs/stats-dist.d.ts +2 -0
  231. package/dist/sheet/packs/stats-dist.js +785 -0
  232. package/dist/sheet/packs/text-date.d.ts +2 -0
  233. package/dist/sheet/packs/text-date.js +332 -0
  234. package/dist/sheet/packs/trig.d.ts +2 -0
  235. package/dist/sheet/packs/trig.js +73 -0
  236. package/dist/sheet/page-setup.d.ts +73 -0
  237. package/dist/sheet/page-setup.js +73 -0
  238. package/dist/sheet/parse.js +42 -10
  239. package/dist/sheet/paste-special.d.ts +22 -0
  240. package/dist/sheet/paste-special.js +14 -5
  241. package/dist/sheet/pivot-range.d.ts +160 -0
  242. package/dist/sheet/pivot-range.js +333 -0
  243. package/dist/sheet/presence.d.ts +73 -0
  244. package/dist/sheet/presence.js +79 -0
  245. package/dist/sheet/print.d.ts +104 -0
  246. package/dist/sheet/print.js +169 -0
  247. package/dist/sheet/protection.d.ts +55 -1
  248. package/dist/sheet/protection.js +55 -2
  249. package/dist/sheet/rects.d.ts +1 -1
  250. package/dist/sheet/refs.d.ts +48 -0
  251. package/dist/sheet/refs.js +155 -8
  252. package/dist/sheet/ribbon-icons.d.ts +1 -1
  253. package/dist/sheet/ribbon-icons.js +186 -0
  254. package/dist/sheet/ribbon.d.ts +1 -1
  255. package/dist/sheet/ribbon.js +324 -23
  256. package/dist/sheet/sheet-kinds.d.ts +74 -0
  257. package/dist/sheet/sheet-kinds.js +91 -0
  258. package/dist/sheet/shortcuts.d.ts +13 -3
  259. package/dist/sheet/shortcuts.js +63 -12
  260. package/dist/sheet/sort.d.ts +51 -0
  261. package/dist/sheet/sort.js +107 -0
  262. package/dist/sheet/sparklines.d.ts +111 -0
  263. package/dist/sheet/sparklines.js +204 -0
  264. package/dist/sheet/table-styles.d.ts +74 -0
  265. package/dist/sheet/table-styles.js +152 -0
  266. package/dist/sheet/tables.d.ts +19 -0
  267. package/dist/sheet/tables.js +31 -0
  268. package/dist/sheet/tokenize.d.ts +18 -1
  269. package/dist/sheet/tokenize.js +60 -9
  270. package/dist/sheet/validation.d.ts +16 -0
  271. package/dist/sheet/validation.js +37 -0
  272. package/dist/sheet/workbook.d.ts +148 -3
  273. package/dist/sheet/workbook.js +742 -31
  274. package/dist/sheet/xls-cfb.d.ts +32 -0
  275. package/dist/sheet/xls-cfb.js +290 -0
  276. package/dist/sheet/xls-document.d.ts +10 -0
  277. package/dist/sheet/xls-document.js +1243 -0
  278. package/dist/sheet/xls-formula.d.ts +40 -0
  279. package/dist/sheet/xls-formula.js +569 -0
  280. package/dist/sheet/xlsx-document.d.ts +108 -0
  281. package/dist/sheet/xlsx-document.js +1849 -0
  282. package/dist/sheet/xlsx-drawing.d.ts +99 -0
  283. package/dist/sheet/xlsx-drawing.js +420 -0
  284. package/dist/sheet-enable.js +6 -7
  285. package/dist/sheet-text.d.ts +7 -0
  286. package/dist/sheet-text.js +29 -0
  287. package/dist/sources/auth-supabase.js +2 -2
  288. package/dist/sources/realtime-supabase.js +2 -2
  289. package/dist/sources/rest.d.ts +6 -2
  290. package/dist/sources/rest.js +42 -7
  291. package/dist/sources/supabase.d.ts +10 -1
  292. package/dist/sources/supabase.js +73 -40
  293. package/dist/studio/emit-project.js +14 -1
  294. package/dist/studio/index.js +1 -1
  295. package/dist/studio/project.d.ts +11 -2
  296. package/dist/studio/project.js +5 -2
  297. package/dist/studio/ui-components.generated.js +107 -2
  298. package/dist/sveltekit/in-memory.d.ts +2 -2
  299. package/dist/sveltekit/in-memory.js +125 -4
  300. package/dist/sveltekit/index.d.ts +1 -1
  301. package/dist/sveltekit/index.js +1 -1
  302. package/dist/sveltekit/query-plan.d.ts +50 -4
  303. package/dist/sveltekit/query-plan.js +25 -3
  304. package/dist/sveltekit/sql-source.d.ts +6 -0
  305. package/dist/sveltekit/sql-source.js +34 -6
  306. package/dist/sveltekit/sql.d.ts +31 -0
  307. package/dist/sveltekit/sql.js +135 -25
  308. package/dist/sveltekit/transport.d.ts +10 -2
  309. package/dist/sveltekit/transport.js +30 -6
  310. package/dist/upgrade-prompt.d.ts +1 -1
  311. package/dist/version.d.ts +1 -1
  312. package/dist/version.js +1 -1
  313. package/dist/watermark.js +35 -2
  314. package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
  315. package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
  316. package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
  317. package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
  318. package/dist/wc/SvField-B_kurx_P.js +149 -0
  319. package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
  320. package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
  321. package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
  322. package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
  323. package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
  324. package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
  325. package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
  326. package/dist/wc/SvModal-DrfOYYyX.js +189 -0
  327. package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
  328. package/dist/wc/chart-6OXlybVT.js +4341 -0
  329. package/dist/wc/chart-export-CeSADGfi.js +135 -0
  330. package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
  331. package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
  332. package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
  333. package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
  334. package/dist/wc/client-DQIzjDBG.js +3064 -0
  335. package/dist/wc/column-resize-DUPgynvc.js +101 -0
  336. package/dist/wc/date-format-DS-z_h9v.js +1130 -0
  337. package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
  338. package/dist/wc/editor-contract-peBDxir_.js +22 -0
  339. package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
  340. package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
  341. package/dist/wc/list-option-DrRyivWp.js +82 -0
  342. package/dist/wc/popover-WsGlvtQv.js +69 -0
  343. package/dist/wc/positioning-BiKLfu1E.js +112 -0
  344. package/dist/wc/react.d.ts +41 -0
  345. package/dist/wc/react.js +90 -0
  346. package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
  347. package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
  348. package/dist/wc/row-resize-limG_N1z.js +111 -0
  349. package/dist/wc/sv-sheet-element.d.ts +97 -0
  350. package/dist/wc/sv-sheet-element.js +44213 -0
  351. package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
  352. package/dist/wc/validate-BqDthkNr.js +88 -0
  353. package/dist/wc/vue.d.ts +31 -0
  354. package/dist/wc/vue.js +75 -0
  355. package/package.json +30 -5
  356. package/dist/designer/assets/GridMenus-BlsvL_aU.js +0 -8
  357. package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +0 -4
  358. package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +0 -1
  359. package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
  360. package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
  361. package/dist/designer/assets/index-CMFgAoVV.css +0 -1
  362. package/dist/designer/assets/row-resize-DLktcqUK.js +0 -1
  363. package/dist/designer/assets/src-EdI3Xqds.js +0 -58
  364. package/dist/designer/assets/validate-h-aslRV9.js +0 -1
@@ -16,7 +16,25 @@
16
16
  import { FormulaError, isError, err, } from './ast.js';
17
17
  import { toNumber, toBool, toText, looseEquals, compare } from './coerce.js';
18
18
  import { withCustomFunctions } from './functions.js';
19
+ import { ARRAY_FUNCTIONS } from './packs/array.js';
20
+ import { colToLetters } from './address.js';
21
+ import { parseFormula } from './parse.js';
19
22
  import { resolveTableRange, columnIndexOf, } from './tables.js';
23
+ const isLambda = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && 'lambda' in v;
24
+ const isGrid = (v) => Array.isArray(v);
25
+ /** The names a lambda helper takes its function in. */
26
+ const LAMBDA_HELPERS = new Set(['MAP', 'BYROW', 'BYCOL', 'REDUCE', 'SCAN', 'MAKEARRAY']);
27
+ /** A local binding, by name, case-insensitively as Excel reads a name. */
28
+ function localOf(ctx, name) {
29
+ return ctx.locals?.get(name.toUpperCase());
30
+ }
31
+ /** The same context with more names bound over it. */
32
+ function withLocals(ctx, added) {
33
+ const next = new Map(ctx.locals ?? []);
34
+ for (const [name, value] of added)
35
+ next.set(name.toUpperCase(), value);
36
+ return { ...ctx, locals: next };
37
+ }
20
38
  function rangeGrid(from, to, ctx) {
21
39
  const sheet = from.sheet ?? to.sheet;
22
40
  const r1 = Math.min(from.row ?? 0, to.row ?? from.row ?? 0);
@@ -56,12 +74,159 @@ function binary(op, l, r) {
56
74
  }
57
75
  /** Functions handled before the table, because their arguments must not all
58
76
  * be evaluated up front. */
59
- const SHORT_CIRCUIT = new Set(['IF', 'IFS', 'IFERROR', 'IFNA', 'SWITCH']);
77
+ const SHORT_CIRCUIT = new Set(['IF', 'IFS', 'IFERROR', 'IFNA', 'SWITCH', 'ISERROR', 'ISERR', 'ISNA']);
78
+ /** Functions that PRODUCE a reference rather than a value. In scalar position
79
+ * they read as their top-left cell, as a range does; as an argument they
80
+ * expand to the range, so =SUM(OFFSET(A1,0,0,3,1)) adds three cells. */
81
+ const REFERENCE_FUNCTIONS = new Set(['OFFSET', 'INDIRECT']);
82
+ /**
83
+ * The rectangle a node stands for: a cell, a range (open-ended ones closed
84
+ * at the last used row), a name that refers to one, or a reference
85
+ * function's result. Null for anything that is a plain value.
86
+ */
87
+ function referenceOf(node, ctx) {
88
+ switch (node.k) {
89
+ case 'ref':
90
+ return { sheet: node.ref.sheet, r1: node.ref.row ?? 0, c1: node.ref.col, r2: node.ref.row ?? 0, c2: node.ref.col };
91
+ case 'range': {
92
+ const sheet = node.from.sheet ?? node.to.sheet;
93
+ const r1 = Math.min(node.from.row ?? 0, node.to.row ?? node.from.row ?? 0);
94
+ const r2 = node.to.row === null || node.from.row === null ? ctx.lastRow(sheet) : Math.max(node.from.row, node.to.row);
95
+ return { sheet, r1, c1: Math.min(node.from.col, node.to.col), r2, c2: Math.max(node.from.col, node.to.col) };
96
+ }
97
+ case 'name': {
98
+ const target = nameTarget(node.name, ctx);
99
+ return target ? referenceOf(target, ctx) : null;
100
+ }
101
+ case 'fn':
102
+ return REFERENCE_FUNCTIONS.has(node.name) ? referenceCall(node, ctx) : null;
103
+ case 'table': {
104
+ // A structured reference is a rectangle too, so SUBTOTAL(109,[Qty])
105
+ // in a totals row skips the rows a filter folds, as Excel's does,
106
+ // rather than reading the column's first cell as a scalar.
107
+ const rect = tableRectOf(node, ctx);
108
+ return rect ? { sheet: rect.sheet, r1: rect.firstRow, c1: rect.firstCol, r2: rect.lastRow, c2: rect.lastCol } : null;
109
+ }
110
+ case 'spill':
111
+ return spillRectOf(node, ctx);
112
+ default:
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * The rectangle a spilled-range operator (`A1#`) stands for: the array the
118
+ * anchor currently spills. Null when the cell is not a spill anchor, which
119
+ * the callers turn into #REF!, the way Excel does for `A1#` on a cell that
120
+ * holds no dynamic array.
121
+ */
122
+ function spillRectOf(node, ctx) {
123
+ const rect = ctx.spillRect?.(node.ref.sheet, node.ref.row ?? 0, node.ref.col);
124
+ return rect ? { sheet: node.ref.sheet, r1: rect[0], c1: rect[1], r2: rect[2], c2: rect[3] } : null;
125
+ }
126
+ /**
127
+ * Every value a 3D reference reads: the cell or rectangle on each sheet in
128
+ * the tab range, in sheet order. Null when a sheet name is unknown, which the
129
+ * callers turn into #REF!. Aggregates take the flat list, so a nested
130
+ * rectangle spans sheet by sheet.
131
+ */
132
+ function values3d(node, ctx) {
133
+ const sheets = ctx.sheetsBetween?.(node.sheetFrom, node.sheetTo);
134
+ if (!sheets)
135
+ return null;
136
+ const r1 = Math.min(node.from.row ?? 0, node.to.row ?? 0);
137
+ const r2 = Math.max(node.from.row ?? 0, node.to.row ?? 0);
138
+ const c1 = Math.min(node.from.col, node.to.col);
139
+ const c2 = Math.max(node.from.col, node.to.col);
140
+ const out = [];
141
+ for (const s of sheets) {
142
+ for (let r = r1; r <= r2; r += 1) {
143
+ for (let c = c1; c <= c2; c += 1)
144
+ out.push(ctx.resolve(s, r, c));
145
+ }
146
+ }
147
+ return out;
148
+ }
149
+ function rectGrid(rect, ctx) {
150
+ return rangeGrid({ sheet: rect.sheet, row: rect.r1, col: rect.c1, rowAbs: false, colAbs: false }, { sheet: rect.sheet, row: rect.r2, col: rect.c2, rowAbs: false, colAbs: false }, ctx);
151
+ }
152
+ const scalarArg = (node, ctx) => (node ? evalNode(node, ctx) : '');
153
+ const optNumber = (node, ctx, fallback) => {
154
+ if (!node || node.k === 'empty')
155
+ return fallback;
156
+ const v = evalNode(node, ctx);
157
+ if (isError(v))
158
+ throw new FormulaError(v.error);
159
+ return v === '' ? fallback : toNumber(v);
160
+ };
161
+ /** OFFSET and INDIRECT: the rectangle they name, or a throw for the error. */
162
+ function referenceCall(node, ctx) {
163
+ const { name, args } = node;
164
+ if (name === 'INDIRECT') {
165
+ const text = scalarArg(args[0], ctx);
166
+ if (isError(text))
167
+ throw new FormulaError(text.error);
168
+ const a1 = args[1] && args[1].k !== 'empty' ? toBool(evalNode(args[1], ctx)) : true;
169
+ if (!a1)
170
+ throw new FormulaError('#REF!');
171
+ let parsed;
172
+ try {
173
+ parsed = parseFormula(`=${toText(text).trim()}`);
174
+ }
175
+ catch {
176
+ throw new FormulaError('#REF!');
177
+ }
178
+ const rect = parsed.k === 'ref' || parsed.k === 'range' || parsed.k === 'name' ? referenceOf(parsed, ctx) : null;
179
+ if (!rect)
180
+ throw new FormulaError('#REF!');
181
+ return rect;
182
+ }
183
+ // OFFSET(reference, rows, cols, [height], [width])
184
+ const base = args[0] ? referenceOf(args[0], ctx) : null;
185
+ if (!base)
186
+ throw new FormulaError('#VALUE!');
187
+ const rows = Math.trunc(optNumber(args[1], ctx, 0));
188
+ const cols = Math.trunc(optNumber(args[2], ctx, 0));
189
+ const height = Math.trunc(optNumber(args[3], ctx, base.r2 - base.r1 + 1));
190
+ const width = Math.trunc(optNumber(args[4], ctx, base.c2 - base.c1 + 1));
191
+ if (height <= 0 || width <= 0)
192
+ throw new FormulaError('#REF!');
193
+ const r1 = base.r1 + rows;
194
+ const c1 = base.c1 + cols;
195
+ if (r1 < 0 || c1 < 0)
196
+ throw new FormulaError('#REF!');
197
+ return { sheet: base.sheet, r1, c1, r2: r1 + height - 1, c2: c1 + width - 1 };
198
+ }
199
+ /** ROW, COLUMN and ADDRESS: about a reference, not its value. */
200
+ function positionCall(node, ctx) {
201
+ const { name, args } = node;
202
+ if (name === 'ADDRESS') {
203
+ const row = Math.trunc(toNumber(scalarArg(args[0], ctx)));
204
+ const col = Math.trunc(toNumber(scalarArg(args[1], ctx)));
205
+ const abs = Math.trunc(optNumber(args[2], ctx, 1));
206
+ if (row < 1 || col < 1 || abs < 1 || abs > 4)
207
+ return err('#VALUE!');
208
+ const sheet = args[4] && args[4].k !== 'empty' ? toText(scalarArg(args[4], ctx)) : '';
209
+ const rowText = `${abs === 1 || abs === 2 ? '$' : ''}${row}`;
210
+ const colText = `${abs === 1 || abs === 3 ? '$' : ''}${colToLetters(col - 1)}`;
211
+ const prefix = sheet ? (/^[A-Za-z_][A-Za-z0-9_]*$/.test(sheet) ? `${sheet}!` : `'${sheet.replace(/'/g, "''")}'!`) : '';
212
+ return `${prefix}${colText}${rowText}`;
213
+ }
214
+ const target = args[0] && args[0].k !== 'empty' ? referenceOf(args[0], ctx) : null;
215
+ if (!target) {
216
+ const here = ctx.currentCell;
217
+ if (!here)
218
+ return err('#VALUE!');
219
+ return name === 'ROW' ? here.row + 1 : here.col + 1;
220
+ }
221
+ return name === 'ROW' ? target.r1 + 1 : target.c1 + 1;
222
+ }
60
223
  function evalNode(node, ctx) {
61
224
  switch (node.k) {
62
225
  case 'num': return node.v;
63
226
  case 'str': return node.v;
64
227
  case 'bool': return node.v;
228
+ case 'err': return err(node.v);
229
+ case 'empty': return '';
65
230
  case 'ref':
66
231
  return ctx.resolve(node.ref.sheet, node.ref.row ?? 0, node.ref.col);
67
232
  case 'range': {
@@ -70,7 +235,33 @@ function evalNode(node, ctx) {
70
235
  const grid = rangeGrid(node.from, node.to, ctx);
71
236
  return grid[0]?.[0] ?? '';
72
237
  }
238
+ case 'spill': {
239
+ // The spilled range in scalar position is its top-left, the anchor's
240
+ // own value; a cell that anchors no array is #REF!.
241
+ const rect = spillRectOf(node, ctx);
242
+ return rect ? ctx.resolve(rect.sheet, rect.r1, rect.c1) : err('#REF!');
243
+ }
244
+ case 'ref3d': {
245
+ // In scalar position a 3D reference reads the cell on the first sheet
246
+ // of the range, the way an ordinary range collapses to its top-left.
247
+ const vals = values3d(node, ctx);
248
+ if (!vals)
249
+ return err('#REF!');
250
+ return vals[0] ?? '';
251
+ }
73
252
  case 'name': {
253
+ // A name bound inside the formula wins over the workbook's own, which
254
+ // is what makes `=LET(x, 2, x * 3)` mean 6 on a sheet that has an `x`.
255
+ const local = localOf(ctx, node.name);
256
+ if (local !== undefined) {
257
+ // A lambda that is never called is #CALC!, as Excel shows it; a
258
+ // grid in scalar position reads as its top-left cell.
259
+ if (isLambda(local))
260
+ return err('#CALC!');
261
+ if (isGrid(local))
262
+ return local[0]?.[0] ?? '';
263
+ return local;
264
+ }
74
265
  const target = nameTarget(node.name, ctx);
75
266
  if (target)
76
267
  return evalNode(target, ctx);
@@ -109,7 +300,7 @@ function evalNode(node, ctx) {
109
300
  * naming a column that was renamed is an ordinary thing to find in a sheet,
110
301
  * and one broken total should not take the rest of the workbook with it.
111
302
  */
112
- function tableRectOf(node, ctx) {
303
+ export function tableRectOf(node, ctx) {
113
304
  const here = ctx.currentCell;
114
305
  const table = node.table
115
306
  ? ctx.findTable?.(node.table)
@@ -175,6 +366,64 @@ function nameTarget(name, ctx) {
175
366
  return node;
176
367
  }
177
368
  /** Functions whose arguments must not all be evaluated up front. */
369
+ /**
370
+ * `SUBTOTAL(code, ref1, ...)`: the aggregate Excel's AutoFilter is built on.
371
+ *
372
+ * The code names the function - 1 AVERAGE, 2 COUNT, 3 COUNTA, 4 MAX, 5 MIN,
373
+ * 6 PRODUCT, 7 STDEV, 8 STDEVP, 9 SUM, 10 VAR, 11 VARP - and a hundred more
374
+ * means "and leave out the rows hidden by hand as well". A filtered-out row
375
+ * is left out either way, which is what makes a total under a filtered list
376
+ * follow the filter, and why a table's totals row is written with this
377
+ * rather than with SUM. A cell holding a SUBTOTAL of its own is skipped, so
378
+ * a grand total over subtotals counts each row once.
379
+ */
380
+ const SUBTOTAL_FUNCTIONS = {
381
+ 1: 'AVERAGE', 2: 'COUNT', 3: 'COUNTA', 4: 'MAX', 5: 'MIN', 6: 'PRODUCT',
382
+ 7: 'STDEV', 8: 'STDEVP', 9: 'SUM', 10: 'VAR', 11: 'VARP',
383
+ };
384
+ function subtotalCall(node, ctx) {
385
+ const first = node.args[0];
386
+ if (!first)
387
+ return err('#VALUE!');
388
+ const codeValue = evalNode(first, ctx);
389
+ if (isError(codeValue))
390
+ return codeValue;
391
+ const code = Math.trunc(toNumber(codeValue));
392
+ const ignoreHandHidden = code > 100;
393
+ const fnName = SUBTOTAL_FUNCTIONS[ignoreHandHidden ? code - 100 : code];
394
+ if (!fnName)
395
+ return err('#VALUE!');
396
+ const table = ctx.functions ?? withCustomFunctions(undefined);
397
+ const fn = table[fnName];
398
+ if (!fn)
399
+ return err('#NAME?');
400
+ const perArg = [];
401
+ for (const arg of node.args.slice(1)) {
402
+ const rect = referenceOf(arg, ctx);
403
+ if (!rect) {
404
+ // A plain value or an expression: nothing is hidden about it.
405
+ perArg.push([evalNode(arg, ctx)]);
406
+ continue;
407
+ }
408
+ const values = [];
409
+ for (let r = rect.r1; r <= rect.r2; r += 1) {
410
+ const how = ctx.hiddenRow?.(rect.sheet, r) ?? null;
411
+ if (how === 'filter' || (how === 'hand' && ignoreHandHidden))
412
+ continue;
413
+ for (let c = rect.c1; c <= rect.c2; c += 1) {
414
+ if (ctx.isSubtotal?.(rect.sheet, r, c))
415
+ continue;
416
+ values.push(ctx.resolve(rect.sheet, r, c));
417
+ }
418
+ }
419
+ perArg.push(values);
420
+ }
421
+ const flat = perArg.flat();
422
+ for (const v of flat)
423
+ if (isError(v))
424
+ return v;
425
+ return fn({ flat, args: perArg, grids: perArg.map(() => null) });
426
+ }
178
427
  function evalCall(node, ctx) {
179
428
  const { name, args } = node;
180
429
  // Every short-circuiting function below indexes its arguments directly.
@@ -182,6 +431,26 @@ function evalCall(node, ctx) {
182
431
  // TypeError escapes the boundary this module promises never to throw past.
183
432
  if (SHORT_CIRCUIT.has(name) && args.length === 0)
184
433
  return err('#VALUE!');
434
+ // LET, LAMBDA and the helpers that take one see the AST rather than
435
+ // evaluated arguments: a lambda IS its body, and a name bound by LET has
436
+ // to exist before the expression that reads it is evaluated.
437
+ if (name === 'LET')
438
+ return evalLet(args, ctx);
439
+ // The call the parser builds for `LAMBDA(x, x * 2)(5)`: the callee first,
440
+ // then the arguments it is called with.
441
+ if (name === '(')
442
+ return scalarOf(bindingOf(node, ctx));
443
+ if (name === 'LAMBDA')
444
+ return err('#CALC!');
445
+ if (LAMBDA_HELPERS.has(name)) {
446
+ const grid = lambdaCall(node, ctx);
447
+ return Array.isArray(grid) ? grid[0]?.[0] ?? '' : grid;
448
+ }
449
+ // `=LET(double, LAMBDA(x, x * 2), double(21))`: a call on a name the
450
+ // formula bound rather than on a function the library ships.
451
+ const bound = localOf(ctx, name);
452
+ if (isLambda(bound))
453
+ return applyLambda(bound, args.map((a) => bindingOf(a, ctx)), ctx);
185
454
  if (name === 'IF') {
186
455
  const cond = evalNode(args[0], ctx);
187
456
  if (isError(cond))
@@ -191,6 +460,26 @@ function evalCall(node, ctx) {
191
460
  return toBool(cond);
192
461
  return evalNode(branch, ctx);
193
462
  }
463
+ if (name === 'ISERROR' || name === 'ISERR' || name === 'ISNA') {
464
+ let code = null;
465
+ try {
466
+ const v = evalNode(args[0], ctx);
467
+ if (isError(v))
468
+ code = v.error;
469
+ }
470
+ catch (e) {
471
+ if (!(e instanceof FormulaError))
472
+ throw e;
473
+ code = e.code;
474
+ }
475
+ if (code === null)
476
+ return false;
477
+ if (name === 'ISNA')
478
+ return code === '#N/A';
479
+ if (name === 'ISERR')
480
+ return code !== '#N/A';
481
+ return true;
482
+ }
194
483
  if (name === 'IFERROR' || name === 'IFNA') {
195
484
  try {
196
485
  const v = evalNode(args[0], ctx);
@@ -232,14 +521,335 @@ function evalCall(node, ctx) {
232
521
  // A trailing odd argument is the default.
233
522
  return i < args.length ? evalNode(args[i], ctx) : err('#N/A');
234
523
  }
524
+ if (name === 'SUBTOTAL')
525
+ return subtotalCall(node, ctx);
526
+ if (name === 'ROW' || name === 'COLUMN' || name === 'ADDRESS')
527
+ return positionCall(node, ctx);
528
+ if (REFERENCE_FUNCTIONS.has(name)) {
529
+ // In scalar position a reference collapses to its top-left cell.
530
+ const rect = referenceCall(node, ctx);
531
+ return ctx.resolve(rect.sheet, rect.r1, rect.c1);
532
+ }
533
+ if (ARRAY_FUNCTIONS[name]) {
534
+ // In scalar position a grid reads as its top-left cell; the workbook
535
+ // asks `evaluateSpill` for the whole of it.
536
+ const grid = arrayCall(node, ctx);
537
+ return Array.isArray(grid) ? grid[0]?.[0] ?? '' : grid;
538
+ }
235
539
  const table = ctx.functions ?? withCustomFunctions(undefined);
236
540
  const fn = table[name];
237
541
  if (!fn)
238
542
  return err('#NAME?');
239
- // Evaluate every argument, keeping range shape for the lookups that need it.
543
+ const { perArg, grids } = collectArgs(args, ctx);
544
+ const flat = perArg.flat();
545
+ // An error anywhere in the arguments propagates, except for the counting
546
+ // functions, which Excel lets see errors in their range, and TYPE, whose
547
+ // whole job is to report that an error IS one (it answers 16).
548
+ if (name !== 'COUNTA' && name !== 'COUNTBLANK' && name !== 'TYPE') {
549
+ for (const v of flat)
550
+ if (isError(v))
551
+ return v;
552
+ }
553
+ const payload = { flat, args: perArg, grids };
554
+ return fn(payload);
555
+ }
556
+ /**
557
+ * `LET(name1, value1, [name2, value2, ...], calculation)`.
558
+ *
559
+ * Each value is evaluated in the scope built so far, so a later binding can
560
+ * read an earlier one, and the calculation sees them all. A binding holds a
561
+ * GRID where its expression is one, which is what lets `LET(r, A1:A9,
562
+ * SUM(r))` add the range rather than its first cell.
563
+ */
564
+ function evalLet(args, ctx) {
565
+ if (args.length < 3 || args.length % 2 === 0)
566
+ return err('#VALUE!');
567
+ let scope = ctx;
568
+ for (let i = 0; i + 1 < args.length - 1; i += 2) {
569
+ const nameNode = args[i];
570
+ if (nameNode.k !== 'name')
571
+ return err('#VALUE!');
572
+ scope = withLocals(scope, [[nameNode.name, bindingOf(args[i + 1], scope)]]);
573
+ }
574
+ const result = bindingOf(args[args.length - 1], scope);
575
+ if (isLambda(result))
576
+ return err('#CALC!');
577
+ if (isGrid(result))
578
+ return result[0]?.[0] ?? '';
579
+ return result;
580
+ }
581
+ /** The grid a LET's calculation stands for, or null when it is one value. */
582
+ function letGrid(args, ctx) {
583
+ if (args.length < 3 || args.length % 2 === 0)
584
+ return null;
585
+ let scope = ctx;
586
+ for (let i = 0; i + 1 < args.length - 1; i += 2) {
587
+ const nameNode = args[i];
588
+ if (nameNode.k !== 'name')
589
+ return null;
590
+ scope = withLocals(scope, [[nameNode.name, bindingOf(args[i + 1], scope)]]);
591
+ }
592
+ const result = bindingOf(args[args.length - 1], scope);
593
+ return isGrid(result) ? result : null;
594
+ }
595
+ /** What a name is bound to: a lambda, a grid, or a plain value. */
596
+ function bindingOf(node, ctx) {
597
+ if (node.k === 'fn' && node.name === 'LAMBDA')
598
+ return lambdaOf(node, ctx);
599
+ if (node.k === 'fn' && node.name === '(') {
600
+ const fn = lambdaArg(node.args[0], ctx);
601
+ if (!fn)
602
+ return err('#VALUE!');
603
+ return callLambda(fn, node.args.slice(1).map((a) => bindingOf(a, ctx)), ctx);
604
+ }
605
+ if (node.k === 'fn') {
606
+ const bound = localOf(ctx, node.name);
607
+ if (isLambda(bound))
608
+ return callLambda(bound, node.args.map((a) => bindingOf(a, ctx)), ctx);
609
+ }
610
+ if (node.k === 'name') {
611
+ const local = localOf(ctx, node.name);
612
+ if (local !== undefined)
613
+ return local;
614
+ }
615
+ // Arithmetic over ranges is a grid too, cell by cell: `B2:B6 * D2:D6` is
616
+ // what a REDUCE or a BYROW is usually handed.
617
+ if ((node.k === 'binary' || node.k === 'unary') && hasArray(node, ctx))
618
+ return gridOf(node, ctx);
619
+ const grid = hasArray(node, ctx) ? rangeValues(node, ctx) : null;
620
+ if (grid && (grid.length > 1 || (grid[0]?.length ?? 0) > 1))
621
+ return grid;
622
+ return evalNode(node, ctx);
623
+ }
624
+ /** The lambda a `LAMBDA(p1, ..., body)` node stands for, closed over `ctx`. */
625
+ function lambdaOf(node, ctx) {
626
+ const args = node.args;
627
+ if (args.length < 1)
628
+ return err('#VALUE!');
629
+ const params = [];
630
+ for (let i = 0; i < args.length - 1; i += 1) {
631
+ const p = args[i];
632
+ if (p.k !== 'name')
633
+ return err('#VALUE!');
634
+ params.push(p.name);
635
+ }
636
+ return { lambda: true, params, body: args[args.length - 1], scope: ctx.locals };
637
+ }
638
+ /**
639
+ * Call a lambda, keeping whatever it answers with: a value, a grid, or
640
+ * another lambda, which is what a curried `LAMBDA(x, LAMBDA(y, x + y))`
641
+ * gives back.
642
+ */
643
+ function callLambda(fn, values, ctx) {
644
+ // Excel is strict about the count: too few is #VALUE!, and so is too many.
645
+ if (values.length !== fn.params.length)
646
+ return err('#VALUE!');
647
+ const scope = withLocals({ ...ctx, locals: fn.scope }, fn.params.map((p, i) => [p, values[i]]));
648
+ return bindingOf(fn.body, scope);
649
+ }
650
+ /** The same, in a place that wants one value. */
651
+ function applyLambda(fn, values, ctx) {
652
+ return scalarOf(callLambda(fn, values, ctx));
653
+ }
654
+ /** A binding where one value is wanted: a lambda is #CALC!, a grid its corner. */
655
+ function scalarOf(binding) {
656
+ if (isLambda(binding))
657
+ return err('#CALC!');
658
+ if (isGrid(binding))
659
+ return binding[0]?.[0] ?? '';
660
+ return binding;
661
+ }
662
+ /** The lambda an argument names: written there, or bound to a name. */
663
+ function lambdaArg(node, ctx) {
664
+ if (!node)
665
+ return null;
666
+ if (node.k === 'fn' && node.name === 'LAMBDA') {
667
+ const made = lambdaOf(node, ctx);
668
+ return isLambda(made) ? made : null;
669
+ }
670
+ if (node.k === 'name') {
671
+ const local = localOf(ctx, node.name);
672
+ if (isLambda(local))
673
+ return local;
674
+ return null;
675
+ }
676
+ // A call that answers with another lambda: `LAMBDA(x, LAMBDA(y, x + y))(2)`.
677
+ if (node.k === 'fn' && (node.name === '(' || isLambda(localOf(ctx, node.name)))) {
678
+ const made = bindingOf(node, ctx);
679
+ return isLambda(made) ? made : null;
680
+ }
681
+ return null;
682
+ }
683
+ /** An argument as a grid, one cell wide where it is a plain value. */
684
+ function gridArgOf(node, ctx) {
685
+ if (!node)
686
+ return [['']];
687
+ const binding = bindingOf(node, ctx);
688
+ if (isGrid(binding))
689
+ return binding;
690
+ if (isLambda(binding))
691
+ return [[err('#CALC!')]];
692
+ return [[binding]];
693
+ }
694
+ /**
695
+ * Excel's lambda helpers, which is where a lambda earns its keep:
696
+ *
697
+ * MAP(array, ..., fn) every cell through the function
698
+ * BYROW(array, fn) one answer per row, as a column
699
+ * BYCOL(array, fn) one answer per column, as a row
700
+ * REDUCE(init, array, fn) folded to one value, accumulator first
701
+ * SCAN(init, array, fn) the same, keeping every step
702
+ * MAKEARRAY(rows, cols, fn) built from the row and column numbers
703
+ */
704
+ function lambdaCall(node, ctx) {
705
+ const { name, args } = node;
706
+ const fn = lambdaArg(args[args.length - 1], ctx);
707
+ if (!fn)
708
+ return err('#VALUE!');
709
+ if (name === 'MAKEARRAY') {
710
+ const rows = Math.trunc(toNumber(evalNode(args[0] ?? { k: 'num', v: 0 }, ctx)));
711
+ const cols = Math.trunc(toNumber(evalNode(args[1] ?? { k: 'num', v: 0 }, ctx)));
712
+ if (!(rows > 0) || !(cols > 0))
713
+ return err('#VALUE!');
714
+ if (rows * cols > 1000000)
715
+ return err('#NUM!');
716
+ return Array.from({ length: rows }, (_, r) => Array.from({ length: cols }, (_, c) => applyLambda(fn, [r + 1, c + 1], ctx)));
717
+ }
718
+ if (name === 'MAP') {
719
+ const grids = args.slice(0, -1).map((a) => gridArgOf(a, ctx));
720
+ if (!grids.length)
721
+ return err('#VALUE!');
722
+ const rows = grids[0].length;
723
+ const cols = grids[0][0]?.length ?? 0;
724
+ // Every array has to be the same shape, as Excel asks.
725
+ for (const g of grids)
726
+ if (g.length !== rows || (g[0]?.length ?? 0) !== cols)
727
+ return err('#VALUE!');
728
+ return Array.from({ length: rows }, (_, r) => Array.from({ length: cols }, (_, c) => applyLambda(fn, grids.map((g) => g[r]?.[c] ?? ''), ctx)));
729
+ }
730
+ if (name === 'BYROW' || name === 'BYCOL') {
731
+ const grid = gridArgOf(args[0], ctx);
732
+ if (name === 'BYROW') {
733
+ // Each row goes in as a grid one row tall, and the answers come back
734
+ // as a column, which is the shape Excel spills.
735
+ return grid.map((row) => [applyLambda(fn, [[row]], ctx)]);
736
+ }
737
+ // Each column goes in as a grid one column wide, answers along a row.
738
+ return [transposeGrid(grid).map((col) => applyLambda(fn, [col.map((v) => [v])], ctx))];
739
+ }
740
+ // REDUCE and SCAN: the accumulator, then each cell in reading order.
741
+ const grid = gridArgOf(args[1], ctx);
742
+ let acc = args[0] ? evalNode(args[0], ctx) : '';
743
+ const steps = [];
744
+ for (const row of grid) {
745
+ const line = [];
746
+ for (const cell of row) {
747
+ acc = applyLambda(fn, [acc, cell], ctx);
748
+ line.push(acc);
749
+ }
750
+ steps.push(line);
751
+ }
752
+ return name === 'SCAN' ? steps : acc;
753
+ }
754
+ /** A grid with its rows and columns swapped. */
755
+ function transposeGrid(grid) {
756
+ const cols = grid.reduce((m, row) => Math.max(m, row.length), 0);
757
+ return Array.from({ length: cols }, (_, c) => grid.map((row) => row[c] ?? ''));
758
+ }
759
+ /** Whether a node stands for a grid: a range, an array or reference function, a name to one, or arithmetic over those. */
760
+ function hasArray(node, ctx, depth = 0) {
761
+ switch (node.k) {
762
+ case 'range': return true;
763
+ case 'spill': return true;
764
+ case 'name': {
765
+ if (isGrid(localOf(ctx, node.name)))
766
+ return true;
767
+ const target = depth < 8 ? nameTarget(node.name, ctx) : null;
768
+ return target ? hasArray(target, ctx, depth + 1) : false;
769
+ }
770
+ case 'fn': return REFERENCE_FUNCTIONS.has(node.name) || Boolean(ARRAY_FUNCTIONS[node.name]) || LAMBDA_HELPERS.has(node.name) || node.name === 'LET';
771
+ case 'binary': return hasArray(node.left, ctx, depth) || hasArray(node.right, ctx, depth);
772
+ case 'unary': return hasArray(node.arg, ctx, depth);
773
+ default: return false;
774
+ }
775
+ }
776
+ /**
777
+ * A node as a grid, with Excel's broadcasting: a side that is one row, one
778
+ * column or one cell stretches to the other's shape, and where both are
779
+ * bigger and differ the cells past the shorter side are #N/A.
780
+ */
781
+ function gridOf(node, ctx) {
782
+ if (node.k === 'binary') {
783
+ const l = gridOf(node.left, ctx);
784
+ const r = gridOf(node.right, ctx);
785
+ return broadcast(l, r, (a, b) => {
786
+ if (isError(a))
787
+ return a;
788
+ if (isError(b))
789
+ return b;
790
+ try {
791
+ return binary(node.op, a, b);
792
+ }
793
+ catch (e) {
794
+ if (e instanceof FormulaError)
795
+ return err(e.code);
796
+ throw e;
797
+ }
798
+ });
799
+ }
800
+ if (node.k === 'unary') {
801
+ return gridOf(node.arg, ctx).map((row) => row.map((v) => {
802
+ if (isError(v))
803
+ return v;
804
+ try {
805
+ return node.op === '-' ? -toNumber(v) : node.op === '%' ? toNumber(v) / 100 : toNumber(v);
806
+ }
807
+ catch (e) {
808
+ if (e instanceof FormulaError)
809
+ return err(e.code);
810
+ throw e;
811
+ }
812
+ }));
813
+ }
814
+ const grid = rangeValues(node, ctx);
815
+ return grid ?? [[evalNode(node, ctx)]];
816
+ }
817
+ function broadcast(l, r, op) {
818
+ const lr = l.length, lc = l[0]?.length ?? 0;
819
+ const rr = r.length, rc = r[0]?.length ?? 0;
820
+ const rows = lr === 1 ? rr : rr === 1 ? lr : Math.max(lr, rr);
821
+ const cols = lc === 1 ? rc : rc === 1 ? lc : Math.max(lc, rc);
822
+ const pick = (g, gr, gc, i, j) => {
823
+ const y = gr === 1 ? 0 : i;
824
+ const x = gc === 1 ? 0 : j;
825
+ if (y >= gr || x >= gc)
826
+ return err('#N/A');
827
+ return g[y]?.[x] ?? '';
828
+ };
829
+ return Array.from({ length: rows }, (_, i) => Array.from({ length: cols }, (_, j) => op(pick(l, lr, lc, i, j), pick(r, rr, rc, i, j))));
830
+ }
831
+ /** An array function's answer: a grid, or a value where it had none to give. */
832
+ function arrayCall(node, ctx) {
833
+ const { perArg, grids } = collectArgs(node.args, ctx);
834
+ // Errors stay inside the array: FILTER and SORT carry an error cell
835
+ // through as Excel does, and decide for themselves about the rest.
836
+ return ARRAY_FUNCTIONS[node.name]({ flat: perArg.flat(), args: perArg, grids });
837
+ }
838
+ /** Every argument evaluated, keeping range shape for the functions that need it. */
839
+ function collectArgs(args, ctx) {
240
840
  const perArg = [];
241
841
  const grids = [];
242
842
  for (const given of args) {
843
+ // A name bound inside the formula, by LET or as a lambda's parameter,
844
+ // hands over its grid: `LET(r, A1:C1, SUM(r))` adds the range.
845
+ if (given.k === 'name') {
846
+ const local = localOf(ctx, given.name);
847
+ if (isGrid(local)) {
848
+ grids.push(local);
849
+ perArg.push(local.flat());
850
+ continue;
851
+ }
852
+ }
243
853
  // A name stands for whatever it was defined as. Substituting the node
244
854
  // here, before the shape check, is what lets `Sales` in =SUM(Sales) be a
245
855
  // whole column rather than the top-left cell a scalar read would give.
@@ -249,6 +859,13 @@ function evalCall(node, ctx) {
249
859
  grids.push(grid);
250
860
  perArg.push(grid.flat());
251
861
  }
862
+ else if (arg.k === 'fn' && REFERENCE_FUNCTIONS.has(arg.name)) {
863
+ // OFFSET and INDIRECT hand their whole rectangle to the caller, so
864
+ // =SUM(OFFSET(A1,0,0,3,1)) adds three cells rather than one.
865
+ const grid = rectGrid(referenceCall(arg, ctx), ctx);
866
+ grids.push(grid);
867
+ perArg.push(grid.flat());
868
+ }
252
869
  else if (arg.k === 'table') {
253
870
  // A structured reference expands exactly as a range does, which is
254
871
  // what makes =SUM(Orders[Amount]) work.
@@ -262,21 +879,67 @@ function evalCall(node, ctx) {
262
879
  perArg.push(grid.flat());
263
880
  }
264
881
  }
882
+ else if (arg.k === 'spill') {
883
+ // The spilled range hands the whole array to the caller, so
884
+ // =SUM(E1#) adds every cell the dynamic array reaches.
885
+ const rect = spillRectOf(arg, ctx);
886
+ if (!rect) {
887
+ grids.push(null);
888
+ perArg.push([err('#REF!')]);
889
+ }
890
+ else {
891
+ const grid = rectGrid(rect, ctx);
892
+ grids.push(grid);
893
+ perArg.push(grid.flat());
894
+ }
895
+ }
896
+ else if (arg.k === 'ref3d') {
897
+ // A 3D reference hands over its cell on every sheet in the range, so
898
+ // =SUM(Sheet1:Sheet3!A1) adds the same cell down the tabs.
899
+ const vals = values3d(arg, ctx);
900
+ grids.push(null);
901
+ perArg.push(vals ?? [err('#REF!')]);
902
+ }
903
+ else if (arg.k === 'fn' && ARRAY_FUNCTIONS[arg.name]) {
904
+ // An array function nested in another hands over its grid, so
905
+ // =SORT(FILTER(...)) and =SUM(SEQUENCE(10)) work.
906
+ const grid = arrayCall(arg, ctx);
907
+ if (Array.isArray(grid)) {
908
+ grids.push(grid);
909
+ perArg.push(grid.flat());
910
+ }
911
+ else {
912
+ grids.push(null);
913
+ perArg.push([grid]);
914
+ }
915
+ }
916
+ else if (arg.k === 'fn' && LAMBDA_HELPERS.has(arg.name)) {
917
+ // And so do the lambda helpers: =SUM(MAP(A1:A9, LAMBDA(v, v * 2))) is
918
+ // the sum of every doubled value, not of the first one. REDUCE hands
919
+ // back one value rather than a grid, which is the same branch.
920
+ const grid = lambdaCall(arg, ctx);
921
+ if (Array.isArray(grid)) {
922
+ grids.push(grid);
923
+ perArg.push(grid.flat());
924
+ }
925
+ else {
926
+ grids.push(null);
927
+ perArg.push([grid]);
928
+ }
929
+ }
930
+ else if ((arg.k === 'binary' || arg.k === 'unary') && hasArray(arg, ctx)) {
931
+ // Arithmetic over a range is a grid, cell by cell: the `B2:B9>3` a
932
+ // FILTER takes, or `A1:A9*2` on its own.
933
+ const grid = gridOf(arg, ctx);
934
+ grids.push(grid);
935
+ perArg.push(grid.flat());
936
+ }
265
937
  else {
266
938
  grids.push(null);
267
939
  perArg.push([evalNode(arg, ctx)]);
268
940
  }
269
941
  }
270
- const flat = perArg.flat();
271
- // An error anywhere in the arguments propagates, except for the counting
272
- // functions, which Excel lets see errors in their range.
273
- if (name !== 'COUNTA' && name !== 'COUNTBLANK') {
274
- for (const v of flat)
275
- if (isError(v))
276
- return v;
277
- }
278
- const payload = { flat, args: perArg, grids };
279
- return fn(payload);
942
+ return { perArg, grids };
280
943
  }
281
944
  /**
282
945
  * Evaluate a parsed formula. Never throws: a `FormulaError` raised anywhere
@@ -293,10 +956,32 @@ export function rangeValues(node, ctx) {
293
956
  return rangeGrid(node.from, node.to, ctx);
294
957
  if (node.k === 'ref')
295
958
  return [[ctx.resolve(node.ref.sheet, node.ref.row ?? 0, node.ref.col)]];
959
+ if (node.k === 'spill') {
960
+ const rect = spillRectOf(node, ctx);
961
+ return rect ? rectGrid(rect, ctx) : [[err('#REF!')]];
962
+ }
296
963
  if (node.k === 'name') {
964
+ const local = localOf(ctx, node.name);
965
+ if (isGrid(local))
966
+ return local;
297
967
  const target = nameTarget(node.name, ctx);
298
968
  return target ? rangeValues(target, ctx) : null;
299
969
  }
970
+ if (node.k === 'fn' && REFERENCE_FUNCTIONS.has(node.name))
971
+ return rectGrid(referenceCall(node, ctx), ctx);
972
+ if (node.k === 'fn' && ARRAY_FUNCTIONS[node.name]) {
973
+ const grid = arrayCall(node, ctx);
974
+ return Array.isArray(grid) ? grid : [[grid]];
975
+ }
976
+ if (node.k === 'fn' && LAMBDA_HELPERS.has(node.name)) {
977
+ const grid = lambdaCall(node, ctx);
978
+ return Array.isArray(grid) ? grid : [[grid]];
979
+ }
980
+ // `=LET(r, A1:A9, SORT(r))` spills what its calculation is.
981
+ if (node.k === 'fn' && node.name === 'LET') {
982
+ const grid = letGrid(node.args, ctx);
983
+ return grid ?? [[evalNode(node, ctx)]];
984
+ }
300
985
  return null;
301
986
  }
302
987
  catch (e) {
@@ -305,6 +990,33 @@ export function rangeValues(node, ctx) {
305
990
  throw e;
306
991
  }
307
992
  }
993
+ /**
994
+ * The grid a formula spills, or null when it is a plain value: a range on
995
+ * its own (`=A1:A5`), a name that refers to one, a reference function's
996
+ * rectangle, or an array function's answer, when that is more than one
997
+ * cell. A throw inside is the error the cell shows, and no spill.
998
+ */
999
+ export function evaluateSpill(node, ctx) {
1000
+ try {
1001
+ let grid = null;
1002
+ if (node.k === 'range' || node.k === 'name' || node.k === 'spill'
1003
+ || (node.k === 'fn' && (REFERENCE_FUNCTIONS.has(node.name) || ARRAY_FUNCTIONS[node.name] || LAMBDA_HELPERS.has(node.name) || node.name === 'LET'))) {
1004
+ grid = rangeValues(node, ctx);
1005
+ }
1006
+ else if ((node.k === 'binary' || node.k === 'unary') && hasArray(node, ctx)) {
1007
+ grid = gridOf(node, ctx);
1008
+ }
1009
+ if (!grid || (grid.length === 1 && (grid[0]?.length ?? 0) <= 1))
1010
+ return null;
1011
+ const width = grid.reduce((m, row) => Math.max(m, row.length), 0);
1012
+ return grid.map((row) => Array.from({ length: width }, (_, i) => row[i] ?? ''));
1013
+ }
1014
+ catch (e) {
1015
+ if (e instanceof FormulaError)
1016
+ return null;
1017
+ throw e;
1018
+ }
1019
+ }
308
1020
  export function evaluate(node, ctx) {
309
1021
  try {
310
1022
  return evalNode(node, ctx);