@svgrid/enterprise 3.0.1 → 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 (445) 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 +680 -0
  10. package/dist/SvFormulaBar.svelte.d.ts +69 -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 +263 -54
  18. package/dist/SvPivotDesigner.svelte.d.ts +27 -20
  19. package/dist/SvRibbonIcon.svelte +46 -0
  20. package/dist/SvRibbonIcon.svelte.d.ts +17 -0
  21. package/dist/SvSchemaChart.svelte +4 -2
  22. package/dist/SvSheet.svelte +7914 -0
  23. package/dist/SvSheet.svelte.d.ts +215 -0
  24. package/dist/SvSheetChartSetup.svelte +151 -0
  25. package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
  26. package/dist/SvSheetComment.svelte +283 -0
  27. package/dist/SvSheetComment.svelte.d.ts +22 -0
  28. package/dist/SvSheetConditionalFormat.svelte +159 -0
  29. package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
  30. package/dist/SvSheetDataValidation.svelte +273 -0
  31. package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
  32. package/dist/SvSheetEditRanges.svelte +217 -0
  33. package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
  34. package/dist/SvSheetErrors.svelte +125 -0
  35. package/dist/SvSheetErrors.svelte.d.ts +20 -0
  36. package/dist/SvSheetEvaluate.svelte +133 -0
  37. package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
  38. package/dist/SvSheetFilterMenu.svelte +320 -0
  39. package/dist/SvSheetFilterMenu.svelte.d.ts +22 -0
  40. package/dist/SvSheetFindReplace.svelte +132 -0
  41. package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
  42. package/dist/SvSheetFormatCells.svelte +465 -0
  43. package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
  44. package/dist/SvSheetGoalSeek.svelte +145 -0
  45. package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
  46. package/dist/SvSheetInsertFunction.svelte +149 -0
  47. package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
  48. package/dist/SvSheetIteration.svelte +81 -0
  49. package/dist/SvSheetIteration.svelte.d.ts +10 -0
  50. package/dist/SvSheetLink.svelte +99 -0
  51. package/dist/SvSheetLink.svelte.d.ts +17 -0
  52. package/dist/SvSheetListPicker.svelte +91 -0
  53. package/dist/SvSheetListPicker.svelte.d.ts +10 -0
  54. package/dist/SvSheetManageRules.svelte +187 -0
  55. package/dist/SvSheetManageRules.svelte.d.ts +16 -0
  56. package/dist/SvSheetNameManager.svelte +227 -0
  57. package/dist/SvSheetNameManager.svelte.d.ts +11 -0
  58. package/dist/SvSheetPageSetup.svelte +159 -0
  59. package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
  60. package/dist/SvSheetPasteSpecial.svelte +107 -0
  61. package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
  62. package/dist/SvSheetPivot.svelte +220 -0
  63. package/dist/SvSheetPivot.svelte.d.ts +21 -0
  64. package/dist/SvSheetProtectSheet.svelte +81 -0
  65. package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
  66. package/dist/SvSheetRemoveDuplicates.svelte +152 -0
  67. package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
  68. package/dist/SvSheetRibbon.svelte +1254 -0
  69. package/dist/SvSheetRibbon.svelte.d.ts +34 -0
  70. package/dist/SvSheetSizeDialog.svelte +60 -0
  71. package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
  72. package/dist/SvSheetSort.svelte +218 -0
  73. package/dist/SvSheetSort.svelte.d.ts +28 -0
  74. package/dist/SvSheetSparklines.svelte +135 -0
  75. package/dist/SvSheetSparklines.svelte.d.ts +14 -0
  76. package/dist/SvSheetTable.svelte +160 -0
  77. package/dist/SvSheetTable.svelte.d.ts +24 -0
  78. package/dist/SvSheetTabs.svelte +571 -0
  79. package/dist/SvSheetTabs.svelte.d.ts +50 -0
  80. package/dist/SvSheetTabs.test-harness.svelte.d.ts +17 -0
  81. package/dist/SvSheetTabs.test-harness.svelte.js +22 -0
  82. package/dist/SvSheetTextToColumns.svelte +172 -0
  83. package/dist/SvSheetTextToColumns.svelte.d.ts +13 -0
  84. package/dist/SvSheetValidationAlert.svelte +85 -0
  85. package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
  86. package/dist/advanced-filter-enable.js +1 -1
  87. package/dist/alerts/alert-engine.d.ts +6 -0
  88. package/dist/alerts/alert-engine.js +21 -4
  89. package/dist/alerts/alert-formats.js +2 -0
  90. package/dist/alerts/alert-types.d.ts +1 -1
  91. package/dist/alerts.d.ts +1 -1
  92. package/dist/alerts.js +2 -2
  93. package/dist/board.js +2 -2
  94. package/dist/bulk-edit.d.ts +3 -1
  95. package/dist/bulk-edit.js +1 -1
  96. package/dist/cdn/svgrid-enterprise.svelte-external.js +43538 -6539
  97. package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
  98. package/dist/designer/assets/SvChartMenu-BDoeqGz6.js +1 -0
  99. package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
  100. package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
  101. package/dist/designer/assets/SvDateTimePicker-DCPg7WGN.js +1 -0
  102. package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
  103. package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
  104. package/dist/designer/assets/SvGridChart-Cy1ATrWh.js +3 -0
  105. package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
  106. package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
  107. package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
  108. package/dist/designer/assets/SvGridChartPanel-CATdVc9X.js +4 -0
  109. package/dist/designer/assets/{SvGridChartView-DUc-1RUf.css → SvGridChartView-7msfnWZT.css} +1 -1
  110. package/dist/designer/assets/SvGridChartView-CmsZtCED.js +1 -0
  111. package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
  112. package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
  113. package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
  114. package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
  115. package/dist/designer/assets/SvTabs-2mHC6oaz.js +1 -0
  116. package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
  117. package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
  118. package/dist/designer/assets/chart-Cn7MnNqA.js +1 -0
  119. package/dist/designer/assets/chart-export-B6bkQ3X8.js +11 -0
  120. package/dist/designer/assets/chart-export-pdf-BbA28-gt.js +11 -0
  121. package/dist/designer/assets/chart-panel-messages-Dz7PTIqT.js +1 -0
  122. package/dist/designer/assets/chart-summary-BD1qYB2R.js +1 -0
  123. package/dist/designer/assets/chart-trend-B8xr5LuD.js +1 -0
  124. package/dist/designer/assets/chart-validate-BMqM-qkF.js +1 -0
  125. package/dist/designer/assets/column-resize-BYDzR1Ve.js +1 -0
  126. package/dist/designer/assets/date-format-B8JbEtIG.js +1 -0
  127. package/dist/designer/assets/date-format-DKS-z0xS.css +1 -0
  128. package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
  129. package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
  130. package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
  131. package/dist/designer/assets/focus-trap-V2-6Fy9I.js +1 -0
  132. package/dist/designer/assets/{index-C_a9Cj8Y.js → index-D5bVbuzI.js} +318 -315
  133. package/dist/designer/assets/index-_JVFxt02.css +1 -0
  134. package/dist/designer/assets/list-option-BP_dWS66.js +1 -0
  135. package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
  136. package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
  137. package/dist/designer/assets/src-CITpcm6b.js +1 -0
  138. package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
  139. package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
  140. package/dist/designer/index.html +29 -19
  141. package/dist/export-pdf.d.ts +164 -0
  142. package/dist/export-pdf.js +346 -15
  143. package/dist/export.js +25 -10
  144. package/dist/gantt/SvGridGantt.svelte +2890 -0
  145. package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
  146. package/dist/gantt/gantt-config.d.ts +73 -0
  147. package/dist/gantt/gantt-config.js +1 -0
  148. package/dist/gantt/gantt-critical-path.d.ts +67 -0
  149. package/dist/gantt/gantt-critical-path.js +207 -0
  150. package/dist/gantt/gantt-model.d.ts +257 -0
  151. package/dist/gantt/gantt-model.js +651 -0
  152. package/dist/gantt/gantt-resources.d.ts +59 -0
  153. package/dist/gantt/gantt-resources.js +71 -0
  154. package/dist/gantt/gantt.d.ts +7 -0
  155. package/dist/gantt/gantt.js +36 -0
  156. package/dist/gantt/index.d.ts +15 -0
  157. package/dist/gantt/index.js +22 -0
  158. package/dist/gantt/timeline-arrows.d.ts +102 -0
  159. package/dist/gantt/timeline-arrows.js +181 -0
  160. package/dist/import.d.ts +2 -2
  161. package/dist/import.js +1 -1
  162. package/dist/index.d.ts +93 -3
  163. package/dist/index.js +107 -3
  164. package/dist/install.js +13 -1
  165. package/dist/license-core.d.ts +17 -1
  166. package/dist/license-core.js +16 -5
  167. package/dist/license.d.ts +18 -2
  168. package/dist/license.js +71 -6
  169. package/dist/node/studio.js +203 -9
  170. package/dist/pivot-chart.d.ts +25 -1
  171. package/dist/pivot-chart.js +25 -69
  172. package/dist/pivot-enable.js +2 -2
  173. package/dist/scheduler-dependencies.d.ts +35 -0
  174. package/dist/scheduler-dependencies.js +36 -1
  175. package/dist/scheduler.js +2 -2
  176. package/dist/selection-bar.js +2 -2
  177. package/dist/server/SvGroupCell.svelte +213 -0
  178. package/dist/server/SvGroupCell.svelte.d.ts +62 -0
  179. package/dist/server/SvRowGroupPanel.svelte +322 -0
  180. package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
  181. package/dist/server/enable.d.ts +17 -0
  182. package/dist/server/enable.js +49 -0
  183. package/dist/server/index.d.ts +22 -0
  184. package/dist/server/index.js +24 -0
  185. package/dist/server/messages.d.ts +45 -0
  186. package/dist/server/messages.js +35 -0
  187. package/dist/server/server-group-model.d.ts +104 -0
  188. package/dist/server/server-group-model.js +272 -0
  189. package/dist/server/server-pivot.d.ts +46 -0
  190. package/dist/server/server-pivot.js +57 -0
  191. package/dist/server/server-row-model.d.ts +547 -0
  192. package/dist/server/server-row-model.js +1551 -0
  193. package/dist/server/server-selection.d.ts +99 -0
  194. package/dist/server/server-selection.js +215 -0
  195. package/dist/server/svgrid-adapter.d.ts +155 -0
  196. package/dist/server/svgrid-adapter.js +202 -0
  197. package/dist/sheet/address.d.ts +43 -0
  198. package/dist/sheet/address.js +81 -0
  199. package/dist/sheet/ast.d.ts +138 -0
  200. package/dist/sheet/ast.js +70 -0
  201. package/dist/sheet/auto-filter.d.ts +120 -0
  202. package/dist/sheet/auto-filter.js +295 -0
  203. package/dist/sheet/autocomplete.d.ts +51 -0
  204. package/dist/sheet/autocomplete.js +248 -0
  205. package/dist/sheet/cell-images.d.ts +39 -0
  206. package/dist/sheet/cell-images.js +90 -0
  207. package/dist/sheet/cell-types.d.ts +58 -0
  208. package/dist/sheet/cell-types.js +96 -0
  209. package/dist/sheet/coerce.d.ts +71 -0
  210. package/dist/sheet/coerce.js +289 -0
  211. package/dist/sheet/commands.d.ts +89 -0
  212. package/dist/sheet/commands.js +230 -0
  213. package/dist/sheet/comments.d.ts +63 -0
  214. package/dist/sheet/comments.js +131 -0
  215. package/dist/sheet/conditional-formats.d.ts +167 -0
  216. package/dist/sheet/conditional-formats.js +341 -0
  217. package/dist/sheet/csv.d.ts +32 -0
  218. package/dist/sheet/csv.js +158 -0
  219. package/dist/sheet/culture.d.ts +87 -0
  220. package/dist/sheet/culture.js +247 -0
  221. package/dist/sheet/delta.d.ts +102 -0
  222. package/dist/sheet/delta.js +203 -0
  223. package/dist/sheet/deps.d.ts +104 -0
  224. package/dist/sheet/deps.js +274 -0
  225. package/dist/sheet/document.d.ts +252 -0
  226. package/dist/sheet/document.js +465 -0
  227. package/dist/sheet/edit-keys.d.ts +14 -0
  228. package/dist/sheet/edit-keys.js +40 -0
  229. package/dist/sheet/engine.d.ts +67 -0
  230. package/dist/sheet/engine.js +19 -0
  231. package/dist/sheet/entry.d.ts +35 -0
  232. package/dist/sheet/entry.js +226 -0
  233. package/dist/sheet/error-check.d.ts +49 -0
  234. package/dist/sheet/error-check.js +83 -0
  235. package/dist/sheet/evaluate-steps.d.ts +48 -0
  236. package/dist/sheet/evaluate-steps.js +196 -0
  237. package/dist/sheet/evaluate.d.ts +128 -0
  238. package/dist/sheet/evaluate.js +1049 -0
  239. package/dist/sheet/filter-files.d.ts +37 -0
  240. package/dist/sheet/filter-files.js +465 -0
  241. package/dist/sheet/find-replace.d.ts +62 -0
  242. package/dist/sheet/find-replace.js +152 -0
  243. package/dist/sheet/format-store.d.ts +114 -0
  244. package/dist/sheet/format-store.js +243 -0
  245. package/dist/sheet/freeze.d.ts +54 -0
  246. package/dist/sheet/freeze.js +58 -0
  247. package/dist/sheet/from-rows.d.ts +14 -0
  248. package/dist/sheet/from-rows.js +50 -0
  249. package/dist/sheet/function-catalog.d.ts +10 -0
  250. package/dist/sheet/function-catalog.js +385 -0
  251. package/dist/sheet/functions.d.ts +28 -0
  252. package/dist/sheet/functions.js +634 -0
  253. package/dist/sheet/goal-seek.d.ts +73 -0
  254. package/dist/sheet/goal-seek.js +153 -0
  255. package/dist/sheet/index.d.ts +80 -0
  256. package/dist/sheet/index.js +80 -0
  257. package/dist/sheet/links.d.ts +57 -0
  258. package/dist/sheet/links.js +174 -0
  259. package/dist/sheet/merges.d.ts +71 -0
  260. package/dist/sheet/merges.js +137 -0
  261. package/dist/sheet/messages.d.ts +778 -0
  262. package/dist/sheet/messages.js +806 -0
  263. package/dist/sheet/names.d.ts +31 -0
  264. package/dist/sheet/names.js +87 -0
  265. package/dist/sheet/navigate.d.ts +52 -0
  266. package/dist/sheet/navigate.js +135 -0
  267. package/dist/sheet/number-format.d.ts +110 -0
  268. package/dist/sheet/number-format.js +905 -0
  269. package/dist/sheet/objects.d.ts +106 -0
  270. package/dist/sheet/objects.js +149 -0
  271. package/dist/sheet/ods-document.d.ts +44 -0
  272. package/dist/sheet/ods-document.js +1275 -0
  273. package/dist/sheet/open-file.d.ts +26 -0
  274. package/dist/sheet/open-file.js +56 -0
  275. package/dist/sheet/outline.d.ts +82 -0
  276. package/dist/sheet/outline.js +228 -0
  277. package/dist/sheet/packs/array.d.ts +16 -0
  278. package/dist/sheet/packs/array.js +172 -0
  279. package/dist/sheet/packs/database.d.ts +42 -0
  280. package/dist/sheet/packs/database.js +142 -0
  281. package/dist/sheet/packs/engineering.d.ts +2 -0
  282. package/dist/sheet/packs/engineering.js +296 -0
  283. package/dist/sheet/packs/financial.d.ts +5 -0
  284. package/dist/sheet/packs/financial.js +220 -0
  285. package/dist/sheet/packs/math-stats.d.ts +2 -0
  286. package/dist/sheet/packs/math-stats.js +372 -0
  287. package/dist/sheet/packs/special.d.ts +44 -0
  288. package/dist/sheet/packs/special.js +187 -0
  289. package/dist/sheet/packs/stats-dist.d.ts +2 -0
  290. package/dist/sheet/packs/stats-dist.js +785 -0
  291. package/dist/sheet/packs/text-date.d.ts +2 -0
  292. package/dist/sheet/packs/text-date.js +332 -0
  293. package/dist/sheet/packs/trig.d.ts +2 -0
  294. package/dist/sheet/packs/trig.js +73 -0
  295. package/dist/sheet/page-setup.d.ts +73 -0
  296. package/dist/sheet/page-setup.js +73 -0
  297. package/dist/sheet/palette.d.ts +19 -0
  298. package/dist/sheet/palette.js +84 -0
  299. package/dist/sheet/parse.d.ts +13 -0
  300. package/dist/sheet/parse.js +140 -0
  301. package/dist/sheet/paste-special.d.ts +186 -0
  302. package/dist/sheet/paste-special.js +601 -0
  303. package/dist/sheet/pivot-range.d.ts +160 -0
  304. package/dist/sheet/pivot-range.js +333 -0
  305. package/dist/sheet/presence.d.ts +73 -0
  306. package/dist/sheet/presence.js +79 -0
  307. package/dist/sheet/print.d.ts +104 -0
  308. package/dist/sheet/print.js +169 -0
  309. package/dist/sheet/protection.d.ts +75 -0
  310. package/dist/sheet/protection.js +101 -0
  311. package/dist/sheet/rects.d.ts +45 -0
  312. package/dist/sheet/rects.js +112 -0
  313. package/dist/sheet/refs.d.ts +130 -0
  314. package/dist/sheet/refs.js +413 -0
  315. package/dist/sheet/ribbon-icons.d.ts +31 -0
  316. package/dist/sheet/ribbon-icons.js +536 -0
  317. package/dist/sheet/ribbon.d.ts +173 -0
  318. package/dist/sheet/ribbon.js +1054 -0
  319. package/dist/sheet/sheet-kinds.d.ts +74 -0
  320. package/dist/sheet/sheet-kinds.js +91 -0
  321. package/dist/sheet/shortcuts.d.ts +174 -0
  322. package/dist/sheet/shortcuts.js +674 -0
  323. package/dist/sheet/sort.d.ts +51 -0
  324. package/dist/sheet/sort.js +107 -0
  325. package/dist/sheet/sparklines.d.ts +111 -0
  326. package/dist/sheet/sparklines.js +204 -0
  327. package/dist/sheet/structure.d.ts +87 -0
  328. package/dist/sheet/structure.js +166 -0
  329. package/dist/sheet/table-styles.d.ts +74 -0
  330. package/dist/sheet/table-styles.js +152 -0
  331. package/dist/sheet/tables.d.ts +89 -0
  332. package/dist/sheet/tables.js +178 -0
  333. package/dist/sheet/tokenize.d.ts +71 -0
  334. package/dist/sheet/tokenize.js +355 -0
  335. package/dist/sheet/transforms.d.ts +76 -0
  336. package/dist/sheet/transforms.js +154 -0
  337. package/dist/sheet/validation.d.ts +108 -0
  338. package/dist/sheet/validation.js +278 -0
  339. package/dist/sheet/workbook.d.ts +217 -0
  340. package/dist/sheet/workbook.js +1120 -0
  341. package/dist/sheet/xls-cfb.d.ts +32 -0
  342. package/dist/sheet/xls-cfb.js +290 -0
  343. package/dist/sheet/xls-document.d.ts +10 -0
  344. package/dist/sheet/xls-document.js +1243 -0
  345. package/dist/sheet/xls-formula.d.ts +40 -0
  346. package/dist/sheet/xls-formula.js +569 -0
  347. package/dist/sheet/xlsx-document.d.ts +108 -0
  348. package/dist/sheet/xlsx-document.js +1849 -0
  349. package/dist/sheet/xlsx-drawing.d.ts +99 -0
  350. package/dist/sheet/xlsx-drawing.js +420 -0
  351. package/dist/sheet-enable.d.ts +6 -0
  352. package/dist/sheet-enable.js +45 -0
  353. package/dist/sheet-text.d.ts +7 -0
  354. package/dist/sheet-text.js +29 -0
  355. package/dist/sources/auth-supabase.js +2 -2
  356. package/dist/sources/realtime-supabase.js +2 -2
  357. package/dist/sources/rest.d.ts +6 -2
  358. package/dist/sources/rest.js +42 -7
  359. package/dist/sources/supabase.d.ts +10 -1
  360. package/dist/sources/supabase.js +73 -40
  361. package/dist/studio/emit-project.js +14 -1
  362. package/dist/studio/index.js +1 -1
  363. package/dist/studio/project.d.ts +11 -2
  364. package/dist/studio/project.js +5 -2
  365. package/dist/studio/ui-components.generated.js +170 -3
  366. package/dist/sveltekit/in-memory.d.ts +2 -2
  367. package/dist/sveltekit/in-memory.js +125 -4
  368. package/dist/sveltekit/index.d.ts +1 -1
  369. package/dist/sveltekit/index.js +1 -1
  370. package/dist/sveltekit/query-plan.d.ts +50 -4
  371. package/dist/sveltekit/query-plan.js +25 -3
  372. package/dist/sveltekit/sql-source.d.ts +6 -0
  373. package/dist/sveltekit/sql-source.js +34 -6
  374. package/dist/sveltekit/sql.d.ts +31 -0
  375. package/dist/sveltekit/sql.js +135 -25
  376. package/dist/sveltekit/transport.d.ts +10 -2
  377. package/dist/sveltekit/transport.js +30 -6
  378. package/dist/upgrade-prompt.d.ts +1 -1
  379. package/dist/version.d.ts +1 -1
  380. package/dist/version.js +1 -1
  381. package/dist/watermark.js +35 -2
  382. package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
  383. package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
  384. package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
  385. package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
  386. package/dist/wc/SvField-B_kurx_P.js +149 -0
  387. package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
  388. package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
  389. package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
  390. package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
  391. package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
  392. package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
  393. package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
  394. package/dist/wc/SvModal-DrfOYYyX.js +189 -0
  395. package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
  396. package/dist/wc/chart-6OXlybVT.js +4341 -0
  397. package/dist/wc/chart-export-CeSADGfi.js +135 -0
  398. package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
  399. package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
  400. package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
  401. package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
  402. package/dist/wc/client-DQIzjDBG.js +3064 -0
  403. package/dist/wc/column-resize-DUPgynvc.js +101 -0
  404. package/dist/wc/date-format-DS-z_h9v.js +1130 -0
  405. package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
  406. package/dist/wc/editor-contract-peBDxir_.js +22 -0
  407. package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
  408. package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
  409. package/dist/wc/list-option-DrRyivWp.js +82 -0
  410. package/dist/wc/popover-WsGlvtQv.js +69 -0
  411. package/dist/wc/positioning-BiKLfu1E.js +112 -0
  412. package/dist/wc/react.d.ts +41 -0
  413. package/dist/wc/react.js +90 -0
  414. package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
  415. package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
  416. package/dist/wc/row-resize-limG_N1z.js +111 -0
  417. package/dist/wc/sv-sheet-element.d.ts +97 -0
  418. package/dist/wc/sv-sheet-element.js +44213 -0
  419. package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
  420. package/dist/wc/validate-BqDthkNr.js +88 -0
  421. package/dist/wc/vue.d.ts +31 -0
  422. package/dist/wc/vue.js +75 -0
  423. package/package.json +36 -6
  424. package/dist/designer/assets/GridMenus-B1JtIN21.js +0 -8
  425. package/dist/designer/assets/SvDateRangeInput-CjO7nn_x.js +0 -1
  426. package/dist/designer/assets/SvDateTimePicker-ByBD_ov6.js +0 -1
  427. package/dist/designer/assets/SvField-YDLipR6O.css +0 -1
  428. package/dist/designer/assets/SvField-cj1PFNgZ.js +0 -1
  429. package/dist/designer/assets/SvGridCellEditor-0W1L2hJ1.js +0 -2
  430. package/dist/designer/assets/SvGridChart-DBOR4xcz.js +0 -2
  431. package/dist/designer/assets/SvGridChart-fkMWeh1J.css +0 -1
  432. package/dist/designer/assets/SvGridChartPanel-symrhNnR.js +0 -11
  433. package/dist/designer/assets/SvGridChartView-BmRxq6mU.js +0 -1
  434. package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
  435. package/dist/designer/assets/SvListBox-1oUF6Iav.js +0 -110
  436. package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
  437. package/dist/designer/assets/chart-DXFganU8.js +0 -1
  438. package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
  439. package/dist/designer/assets/date-format-DGagAqRc.css +0 -1
  440. package/dist/designer/assets/date-format-onlYDsrY.js +0 -1
  441. package/dist/designer/assets/easing-zaypKrr0.js +0 -3
  442. package/dist/designer/assets/index-k2stW6L8.css +0 -1
  443. package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
  444. package/dist/designer/assets/src-D9p27OGC.js +0 -58
  445. package/dist/designer/assets/validate-h-aslRV9.js +0 -1
@@ -0,0 +1,1120 @@
1
+ /**
2
+ * The workbook: several named sheets that can read each other.
3
+ *
4
+ * The engine already parsed `Orders!A1` and `'Price list'!A1:C9` from the day
5
+ * it was promoted, because demo 119 had them. What was missing is the thing
6
+ * those references point AT. This is that model, plus the recalculation that
7
+ * has to span sheets once they can.
8
+ *
9
+ * Cells hold raw text and nothing else. Everything derived - the computed
10
+ * value, the dependency edges, the display string - is recomputed from it, so
11
+ * there is exactly one copy of the truth and no way for a cached value to
12
+ * disagree with the formula above it.
13
+ */
14
+ import { parseFormula } from './parse.js';
15
+ import { evaluate, rangeValues, tableRectOf } from './evaluate.js';
16
+ import { withCustomFunctions } from './functions.js';
17
+ import { isError, typedError } from './ast.js';
18
+ import { createDependencyGraph, precedentsOf, isVolatile, cellKey, parseCellKey } from './deps.js';
19
+ import { createTableRegistry, isValidTableName, shiftTables } from './tables.js';
20
+ import { createNames } from './names.js';
21
+ import { fixupReferences, renameSheetReferences, repointReferences } from './refs.js';
22
+ import { builtinEngine } from './engine.js';
23
+ export const DEFAULT_ITERATION = { enabled: false, maxIterations: 100, maxChange: 0.001 };
24
+ /** Excel's text prefix. A cell typed as `'007` holds the text `007`: the
25
+ * apostrophe says "what follows is text", and it is not part of the value,
26
+ * so it is never displayed, printed, exported or compared. */
27
+ export const TEXT_PREFIX = "'";
28
+ /** The value a typed text stands for once the prefix is taken off. */
29
+ export const withoutTextPrefix = (text) => text.startsWith(TEXT_PREFIX) ? text.slice(1) : text;
30
+ /** A name Excel would accept for a sheet. */
31
+ export function isValidSheetName(name) {
32
+ if (name.trim() === '' || name.length > 31)
33
+ return false;
34
+ // Excel forbids these because they are the reference grammar.
35
+ return !/[:\\/?*[\]]/.test(name);
36
+ }
37
+ /** `Sheet1`, `Sheet2`, ... skipping any that already exist. */
38
+ function nextSheetName(taken) {
39
+ const used = new Set(taken.map((n) => n.toLowerCase()));
40
+ for (let i = 1;; i += 1) {
41
+ const candidate = `Sheet${i}`;
42
+ if (!used.has(candidate.toLowerCase()))
43
+ return candidate;
44
+ }
45
+ }
46
+ /** Iteration settings with the defaults filled in and the numbers sane. */
47
+ export function cleanIteration(next) {
48
+ const passes = Math.round(Number(next?.maxIterations ?? DEFAULT_ITERATION.maxIterations));
49
+ const change = Number(next?.maxChange ?? DEFAULT_ITERATION.maxChange);
50
+ return {
51
+ enabled: next?.enabled === true,
52
+ maxIterations: Number.isFinite(passes) ? Math.min(Math.max(passes, 1), 32767) : DEFAULT_ITERATION.maxIterations,
53
+ maxChange: Number.isFinite(change) && change >= 0 ? change : DEFAULT_ITERATION.maxChange,
54
+ };
55
+ }
56
+ /**
57
+ * How far a cell moved between two passes. Two numbers are their distance;
58
+ * anything else has moved either not at all or immeasurably, and an
59
+ * immeasurable move keeps the loop going until the passes run out.
60
+ */
61
+ function moved(before, after) {
62
+ if (typeof before === 'number' && typeof after === 'number')
63
+ return Math.abs(after - before);
64
+ if (before === undefined)
65
+ return Infinity;
66
+ if (isError(before) || isError(after)) {
67
+ return isError(before) && isError(after) && before.error === after.error ? 0 : Infinity;
68
+ }
69
+ return before === after ? 0 : Infinity;
70
+ }
71
+ export function createWorkbook(initial = [{ name: 'Sheet1', cells: [] }], options = {}) {
72
+ const order = [];
73
+ /** What the shell is hiding, for SUBTOTAL. Null until it says. */
74
+ let hiddenRows = null;
75
+ /** Whether any cell holds a SUBTOTAL, so a filter click can skip the
76
+ * recalculation when nothing reads what is hidden. Null when unknown. */
77
+ let subtotalsHere = null;
78
+ const byName = new Map();
79
+ const graph = createDependencyGraph();
80
+ /**
81
+ * The workbook's tables. The parser has always read a structured
82
+ * reference (`Orders[Amount]`, `[@Qty]`); this is what makes one resolve,
83
+ * because a reference like that means nothing until something says where
84
+ * the table is.
85
+ */
86
+ const rawTables = createTableRegistry(options.tables);
87
+ /**
88
+ * The registry as the workbook hands it out: every change drops the
89
+ * cached values and settles again.
90
+ *
91
+ * A table decides what `Orders[Amount]` means, so defining one, removing
92
+ * one or growing one changes the answer of every formula that mentions
93
+ * it. Without this, a table defined after the cells were read leaves each
94
+ * of those formulas showing the `#REF!` it worked out when there was no
95
+ * table, which is the first thing anyone hits.
96
+ */
97
+ const tables = {
98
+ get: (name) => rawTables.get(name),
99
+ list: () => rawTables.list(),
100
+ at: (sheet, row, col) => rawTables.at(sheet, row, col),
101
+ define(table) { rawTables.define(table); afterTables(); },
102
+ remove(name) { const gone = rawTables.remove(name); if (gone)
103
+ afterTables(); return gone; },
104
+ growToInclude(sheet, row, col) { const grew = rawTables.growToInclude(sheet, row, col); if (grew)
105
+ afterTables(); return grew; },
106
+ clear() { rawTables.clear(); afterTables(); },
107
+ };
108
+ /**
109
+ * `Orders2`, `Orders3`, ...: a table name nothing has taken yet.
110
+ *
111
+ * A short name plus a number can read as a cell reference (`T2`), which
112
+ * Excel refuses as a table name and so does the registry, so those fall
113
+ * back to Excel's own `Table2`.
114
+ */
115
+ function freeTableName(base) {
116
+ const taken = new Set(rawTables.list().map((t) => t.name.toLowerCase()));
117
+ const root = base.replace(/\d+$/, '') || 'Table';
118
+ for (let i = 2;; i += 1) {
119
+ for (const candidate of [`${root}${i}`, `Table${i}`]) {
120
+ if (!taken.has(candidate.toLowerCase()) && isValidTableName(candidate))
121
+ return candidate;
122
+ }
123
+ }
124
+ }
125
+ function afterTables() {
126
+ dropAll();
127
+ loadEngine();
128
+ settleAll();
129
+ }
130
+ const functions = withCustomFunctions(options.functions);
131
+ const engine = options.engine ?? builtinEngine();
132
+ /** Computed values, keyed the same way the graph is. Rebuilt lazily and
133
+ * invalidated by every write, so it can never hold a value whose formula
134
+ * has since changed. */
135
+ const values = new Map();
136
+ /** Cells currently being resolved, for cycle detection. */
137
+ const visiting = new Set();
138
+ /** Iterative calculation, and the value each cell had on the pass before:
139
+ * what a cell in a cycle reads for itself while iteration is on, and what
140
+ * the convergence test measures against. */
141
+ let iteration = cleanIteration(options.iteration);
142
+ const previous = new Map();
143
+ /** Cells whose formula is volatile (INDIRECT, OFFSET, RAND, NOW ...):
144
+ * recomputed on every write, since the graph cannot see what they read. */
145
+ const volatile = new Set();
146
+ /** Parsed formulas, keyed by their TEXT rather than their position: a
147
+ * column of =A1*2 filled down is one parse, not one per row. */
148
+ const astCache = new Map();
149
+ // Changing what a name refers to changes every formula that uses it, and
150
+ // the dependency graph only knows the CELLS a name pointed at when the
151
+ // formula was last evaluated. Dropping the cache is the honest answer:
152
+ // names change rarely, and a full recompute costs less than one stale total.
153
+ /**
154
+ * Dynamic arrays. A formula whose answer is a grid spills it over the
155
+ * cells below and to the right: `spills` keeps each anchor's rectangle,
156
+ * `spilledBy` points every covered cell back at its anchor, and a covered
157
+ * cell reads its value from the anchor's grid while its own text stays
158
+ * blank, as in Excel. An anchor whose rectangle runs into a cell that
159
+ * holds text, or into another spill, shows #SPILL! and sits in `blocked`
160
+ * until a write frees the way.
161
+ */
162
+ const spills = new Map();
163
+ const spilledBy = new Map();
164
+ const blocked = new Set();
165
+ /** Cells whose value a spill just changed under them, to compute once the write settles. */
166
+ const pending = new Set();
167
+ const names = (() => {
168
+ const inner = createNames();
169
+ const drop = () => { dropAll(); settleAll(); };
170
+ return {
171
+ ...inner,
172
+ define: (name, refersTo) => { inner.define(name, refersTo); drop(); },
173
+ remove: (name) => { inner.remove(name); drop(); },
174
+ hydrate: (entries) => { inner.hydrate(entries); drop(); },
175
+ clear: () => { inner.clear(); drop(); },
176
+ };
177
+ })();
178
+ let active = '';
179
+ function sheetCells(name) {
180
+ return byName.get(name.toLowerCase());
181
+ }
182
+ /** Resolve a sheet reference. A null sheet means the one being evaluated,
183
+ * which the resolver tracks as it descends. */
184
+ function resolveSheetName(sheet, self) {
185
+ return sheet ?? self;
186
+ }
187
+ /** The sheets from `from` to `to` in tab order, inclusive, for a 3D
188
+ * reference; null when either name is not a sheet. */
189
+ function sheetsInRange(from, to) {
190
+ const lower = order.map((n) => n.toLowerCase());
191
+ const i = lower.indexOf(from.toLowerCase());
192
+ const j = lower.indexOf(to.toLowerCase());
193
+ if (i < 0 || j < 0)
194
+ return null;
195
+ return i <= j ? order.slice(i, j + 1) : order.slice(j, i + 1);
196
+ }
197
+ function parseCached(text) {
198
+ if (astCache.has(text))
199
+ return astCache.get(text) ?? null;
200
+ let ast;
201
+ try {
202
+ ast = parseFormula(text);
203
+ }
204
+ catch {
205
+ ast = null;
206
+ }
207
+ astCache.set(text, ast);
208
+ return ast;
209
+ }
210
+ function contextFor(self, override, at) {
211
+ return {
212
+ currentCell: at ? { sheet: self, row: at.row, col: at.col } : undefined,
213
+ resolve: (sheet, row, col) => {
214
+ const name = resolveSheetName(sheet, self);
215
+ // A validation rule reads the cell it is checking as the text being
216
+ // entered, which is not in the sheet yet; nothing else is overridden.
217
+ if (override && name === self && row === override.row && col === override.col)
218
+ return literal(override.text);
219
+ return compute(name, row, col);
220
+ },
221
+ lastRow: (sheet) => Math.max(rowCount(resolveSheetName(sheet, self)) - 1, 0),
222
+ spillRect: (sheet, row, col) => {
223
+ // The array anchored here, computed first so a formula that reads
224
+ // `A1#` sees the spill even on the pass that establishes it. Only an
225
+ // anchor has an entry; a covered cell or a plain value gives null,
226
+ // which the operator reads as #REF!.
227
+ const name = resolveSheetName(sheet, self);
228
+ compute(name, row, col);
229
+ const rect = spills.get(cellKey(name, row, col));
230
+ return rect ? [rect.r1, rect.c1, rect.r2, rect.c2] : null;
231
+ },
232
+ sheetsBetween: (from, to) => sheetsInRange(from, to),
233
+ resolveNameNode: (name) => names.resolve(name),
234
+ findTable: (name) => rawTables.get(name),
235
+ tableAt: (sheet, row, col) => rawTables.at(resolveSheetName(sheet, self), row, col),
236
+ hiddenRow: hiddenRows ? (sheet, row) => hiddenRows(resolveSheetName(sheet, self), row) : undefined,
237
+ isSubtotal: (sheet, row, col) => {
238
+ const text = sheetCells(resolveSheetName(sheet, self))?.[row]?.[col] ?? '';
239
+ return /^\s*=\s*SUBTOTAL\s*\(/i.test(text);
240
+ },
241
+ functions,
242
+ };
243
+ }
244
+ /** The engine's copy of the cells, for an engine that keeps one. */
245
+ function loadEngine() {
246
+ engine.load?.(order.map((name) => ({ name, cells: sheetCells(name).map((r) => [...r]) })));
247
+ }
248
+ /** Forget every derived thing: values, edges, volatility, spills. */
249
+ function dropAll() {
250
+ // Cells may have been replaced wholesale, so the SUBTOTAL flag is stale.
251
+ subtotalsHere = null;
252
+ values.clear();
253
+ previous.clear();
254
+ graph.clear();
255
+ volatile.clear();
256
+ spills.clear();
257
+ spilledBy.clear();
258
+ blocked.clear();
259
+ pending.clear();
260
+ }
261
+ const SUBTOTAL_TEXT = /^\s*=[\s\S]*SUBTOTAL\s*\(/i;
262
+ /** Whether any cell in the workbook holds a SUBTOTAL. Worked out once and
263
+ * forgotten again whenever a write could change the answer. */
264
+ function hasSubtotal() {
265
+ if (subtotalsHere !== null)
266
+ return subtotalsHere;
267
+ let found = false;
268
+ for (const sheet of order) {
269
+ const cells = sheetCells(sheet);
270
+ for (const line of cells) {
271
+ for (const text of line) {
272
+ if (text && SUBTOTAL_TEXT.test(text)) {
273
+ found = true;
274
+ break;
275
+ }
276
+ }
277
+ if (found)
278
+ break;
279
+ }
280
+ if (found)
281
+ break;
282
+ }
283
+ subtotalsHere = found;
284
+ return found;
285
+ }
286
+ /** Whether a key holds a formula, for the settling passes. */
287
+ function isFormulaKey(key) {
288
+ const at = parseCellKey(key);
289
+ return (sheetCells(at.sheet ?? '')?.[at.row]?.[at.col] ?? '').trim().startsWith('=');
290
+ }
291
+ /**
292
+ * Compute every formula in the workbook, so every spill is on record
293
+ * before any cell it covers is read. Lazy evaluation alone would leave a
294
+ * covered cell blank when it is read before its anchor, which a repaint
295
+ * from the top of a scrolled sheet does.
296
+ */
297
+ function settleAll() {
298
+ for (const other of order) {
299
+ const cells = sheetCells(other) ?? [];
300
+ for (let r = 0; r < cells.length; r += 1) {
301
+ const line = cells[r];
302
+ for (let c = 0; c < line.length; c += 1)
303
+ if (line[c].trim().startsWith('='))
304
+ compute(other, r, c);
305
+ }
306
+ }
307
+ settlePending();
308
+ runIterations();
309
+ }
310
+ /**
311
+ * Run the cycles until they stop moving.
312
+ *
313
+ * Everything in a cycle, and everything downstream of one, is recomputed
314
+ * from the values it last had; a pass that moves no cell by more than
315
+ * `maxChange` is the last one, and so is pass number `maxIterations`. This
316
+ * is Excel's model exactly: it does not promise convergence, it promises a
317
+ * bounded number of tries and whatever they reached.
318
+ */
319
+ function runIterations() {
320
+ if (!iteration.enabled)
321
+ return [];
322
+ const seeds = graph.cycles();
323
+ if (seeds.length === 0)
324
+ return [];
325
+ // Cycle members are downstream of each other, so `dirtyFrom` already
326
+ // includes them; the union is for a seed whose readers were never
327
+ // evaluated.
328
+ const affected = [...new Set([...seeds, ...graph.dirtyFrom(seeds)])];
329
+ for (let pass = 0; pass < Math.max(1, iteration.maxIterations); pass += 1) {
330
+ const before = new Map();
331
+ for (const key of affected) {
332
+ before.set(key, values.get(key) ?? previous.get(key));
333
+ values.delete(key);
334
+ }
335
+ let worst = 0;
336
+ for (const key of affected) {
337
+ const at = parseCellKey(key);
338
+ const after = compute(at.sheet ?? '', at.row, at.col);
339
+ worst = Math.max(worst, moved(before.get(key), after));
340
+ }
341
+ if (worst <= iteration.maxChange)
342
+ break;
343
+ }
344
+ return affected;
345
+ }
346
+ /** Compute what a spill changed under other formulas, until nothing is left. */
347
+ function settlePending() {
348
+ const done = [];
349
+ while (pending.size) {
350
+ const batch = [...pending];
351
+ pending.clear();
352
+ for (const key of batch) {
353
+ const at = parseCellKey(key);
354
+ compute(at.sheet ?? '', at.row, at.col);
355
+ done.push(key);
356
+ }
357
+ }
358
+ return done;
359
+ }
360
+ /** Drop an anchor's spill; the covered cells' values and edges go with it. */
361
+ function clearSpill(anchor) {
362
+ const rect = spills.get(anchor);
363
+ if (!rect)
364
+ return [];
365
+ spills.delete(anchor);
366
+ const at = parseCellKey(anchor);
367
+ const covered = [];
368
+ for (let r = rect.r1; r <= rect.r2; r += 1) {
369
+ for (let c = rect.c1; c <= rect.c2; c += 1) {
370
+ if (r === at.row && c === at.col)
371
+ continue;
372
+ const key = cellKey(at.sheet, r, c);
373
+ if (spilledBy.get(key) !== anchor)
374
+ continue;
375
+ spilledBy.delete(key);
376
+ values.delete(key);
377
+ graph.setPrecedents(key, null);
378
+ covered.push(key);
379
+ }
380
+ }
381
+ return covered;
382
+ }
383
+ /**
384
+ * Record an anchor's grid over its rectangle, or refuse it. Returns the
385
+ * anchor's own value: the grid's top-left cell, or #SPILL! when a cell
386
+ * in the way holds text or belongs to another spill.
387
+ */
388
+ function recordSpill(anchor, sheet, row, col, grid) {
389
+ const cells = sheetCells(sheet);
390
+ const rect = { r1: row, c1: col, r2: row + grid.length - 1, c2: col + (grid[0]?.length ?? 1) - 1 };
391
+ for (let r = rect.r1; r <= rect.r2; r += 1) {
392
+ for (let c = rect.c1; c <= rect.c2; c += 1) {
393
+ if (r === row && c === col)
394
+ continue;
395
+ const key = cellKey(sheet, r, c);
396
+ const owner = spilledBy.get(key);
397
+ if ((cells[r]?.[c] ?? '').trim() !== '' || (owner !== undefined && owner !== anchor)) {
398
+ for (const k of clearSpill(anchor))
399
+ pending.add(k);
400
+ blocked.add(anchor);
401
+ return { error: '#SPILL!' };
402
+ }
403
+ }
404
+ }
405
+ blocked.delete(anchor);
406
+ const before = spills.get(anchor);
407
+ const stillCovered = new Set();
408
+ for (let r = rect.r1; r <= rect.r2; r += 1) {
409
+ for (let c = rect.c1; c <= rect.c2; c += 1) {
410
+ if (r === row && c === col)
411
+ continue;
412
+ const key = cellKey(sheet, r, c);
413
+ stillCovered.add(key);
414
+ const fresh = spilledBy.get(key) !== anchor;
415
+ spilledBy.set(key, anchor);
416
+ values.set(key, grid[r - row]?.[c - col] ?? '');
417
+ graph.setPrecedents(key, [anchor]);
418
+ // Reported as changed, and a formula that read this cell while it
419
+ // was blank has a stale value.
420
+ pending.add(key);
421
+ if (fresh)
422
+ for (const k of graph.dirtyFrom([key]))
423
+ if (k !== key) {
424
+ values.delete(k);
425
+ pending.add(k);
426
+ }
427
+ }
428
+ }
429
+ // The cells the old rectangle covered and the new one does not read blank again.
430
+ if (before) {
431
+ for (let r = before.r1; r <= before.r2; r += 1) {
432
+ for (let c = before.c1; c <= before.c2; c += 1) {
433
+ const key = cellKey(sheet, r, c);
434
+ if (stillCovered.has(key) || spilledBy.get(key) !== anchor)
435
+ continue;
436
+ spilledBy.delete(key);
437
+ values.delete(key);
438
+ graph.setPrecedents(key, null);
439
+ pending.add(key);
440
+ for (const k of graph.dirtyFrom([key]))
441
+ if (k !== key) {
442
+ values.delete(k);
443
+ pending.add(k);
444
+ }
445
+ }
446
+ }
447
+ }
448
+ spills.set(anchor, rect);
449
+ return grid[0]?.[0] ?? '';
450
+ }
451
+ /**
452
+ * How deep a cell's value may be resolved by recursion before the chain is
453
+ * primed from the far end instead. A running-balance column is a chain as
454
+ * long as the sheet, and evaluating the last cell of one by recursion
455
+ * overflows the JavaScript stack somewhere past a thousand rows, which the
456
+ * evaluator turns into a `#NUM!`. Priming keeps the depth flat, so the
457
+ * only limit left is the sheet's own size.
458
+ */
459
+ const DEEP = 150;
460
+ let depth = 0;
461
+ /**
462
+ * Compute what a cell reads, furthest first, so the cell itself resolves
463
+ * against cached values rather than by recursing through the chain. The
464
+ * precedents are the ones the graph recorded at the last evaluation, which
465
+ * is exactly the chain a re-evaluation is about to walk again.
466
+ */
467
+ function primeChain(from) {
468
+ const seen = new Set([from]);
469
+ const chain = [from];
470
+ const stack = [from];
471
+ while (stack.length) {
472
+ const cur = stack.pop();
473
+ for (const p of graph.precedentsOf(cur)) {
474
+ if (seen.has(p) || values.get(p) !== undefined)
475
+ continue;
476
+ seen.add(p);
477
+ chain.push(p);
478
+ stack.push(p);
479
+ }
480
+ }
481
+ for (let i = chain.length - 1; i >= 1; i -= 1) {
482
+ const key = chain[i];
483
+ if (values.get(key) !== undefined)
484
+ continue;
485
+ const at = parseCellKey(key);
486
+ compute(at.sheet ?? '', at.row, at.col);
487
+ }
488
+ }
489
+ function compute(sheet, row, col) {
490
+ const cells = sheetCells(sheet);
491
+ if (!cells)
492
+ return { error: '#REF!' };
493
+ if (row < 0 || col < 0)
494
+ return { error: '#REF!' };
495
+ // Anything past the written area is BLANK. A sheet has no size in this
496
+ // model beyond what has been typed into it, so there is no edge to fall
497
+ // off: =SUM(A1:A100) over a twelve-row sheet is an ordinary thing to
498
+ // write, and returning #REF! for the empty rows would poison the total.
499
+ //
500
+ // #REF! is reserved for the two cases that really are broken: a sheet
501
+ // that does not exist, and a negative index, which is what a reference
502
+ // shifted off the top by a delete becomes.
503
+ const key = cellKey(sheet, row, col);
504
+ const cached = values.get(key);
505
+ if (cached !== undefined)
506
+ return cached;
507
+ if (row >= cells.length || col >= (cells[row]?.length ?? 0)) {
508
+ // Past the written area, unless a spill reaches here.
509
+ const anchor = spilledBy.get(key);
510
+ if (anchor === undefined)
511
+ return '';
512
+ const at = parseCellKey(anchor);
513
+ compute(at.sheet ?? sheet, at.row, at.col);
514
+ return values.get(key) ?? '';
515
+ }
516
+ if (visiting.has(key)) {
517
+ // The cell is being asked for itself. Without iteration that is the
518
+ // error; with it, the loop is meant, and the answer is what this cell
519
+ // was worth on the last pass, starting from 0 as Excel does.
520
+ if (!iteration.enabled)
521
+ return { error: '#CYCLE!' };
522
+ return previous.get(key) ?? 0;
523
+ }
524
+ // Deep enough that recursion is a risk: resolve what this cell reads from
525
+ // the far end first, and come back to it with everything cached.
526
+ if (depth >= DEEP)
527
+ primeChain(key);
528
+ visiting.add(key);
529
+ depth += 1;
530
+ const text = (cells[row]?.[col] ?? '').trim();
531
+ let value;
532
+ if (text === '') {
533
+ // A blank cell shows what an array formula spills into it.
534
+ const anchor = spilledBy.get(key);
535
+ if (anchor !== undefined) {
536
+ const at = parseCellKey(anchor);
537
+ compute(at.sheet ?? sheet, at.row, at.col);
538
+ const spilled = values.get(key);
539
+ if (spilled !== undefined) {
540
+ visiting.delete(key);
541
+ depth -= 1;
542
+ return spilled;
543
+ }
544
+ }
545
+ value = '';
546
+ }
547
+ else if (text.startsWith('=')) {
548
+ const ast = parseCached(text);
549
+ // The graph, the volatile set and the spill ranges are read off the
550
+ // reference grammar, which is Excel's whatever evaluates it, so they
551
+ // stay right for any engine. Only the value and the grid are asked for.
552
+ const result = engine.evaluate(text, { sheet, row, col }, {
553
+ context: contextFor(sheet, undefined, { row, col }),
554
+ parse: parseCached,
555
+ });
556
+ value = result.value;
557
+ const grid = isError(value) ? null : result.spill ?? null;
558
+ if (grid)
559
+ value = recordSpill(key, sheet, row, col, grid);
560
+ else if (spills.has(key))
561
+ for (const k of clearSpill(key))
562
+ pending.add(k);
563
+ if (ast) {
564
+ if (isVolatile(ast))
565
+ volatile.add(key);
566
+ else
567
+ volatile.delete(key);
568
+ graph.setPrecedents(key, precedentsOf(ast, { sheet }, (s) => Math.max(rowCount(s ?? sheet) - 1, 0), (name) => names.resolve(name),
569
+ // A structured reference's cells, so a total over a table is
570
+ // recalculated when a cell inside the table is typed. Best effort:
571
+ // a reference that cannot be resolved records no precedents rather
572
+ // than taking the cell's value down with it, since the value has
573
+ // already been worked out by the time this runs.
574
+ (node) => {
575
+ try {
576
+ return tableRectOf(node, contextFor(sheet, undefined, { row, col }));
577
+ }
578
+ catch {
579
+ return null;
580
+ }
581
+ },
582
+ // The cells a spilled-range operator covers right now. The anchor
583
+ // has just been computed by this same pass, so its rectangle is on
584
+ // record; reading it here (rather than recomputing) keeps the
585
+ // dependency extraction free of side effects.
586
+ (node) => {
587
+ const name = resolveSheetName(node.ref.sheet, sheet);
588
+ const rect = spills.get(cellKey(name, node.ref.row ?? 0, node.ref.col));
589
+ return rect ? { sheet: name, r1: rect.r1, c1: rect.c1, r2: rect.r2, c2: rect.c2 } : null;
590
+ },
591
+ // The sheets a 3D reference spans, so it recalculates when the cell
592
+ // on any of them is typed into.
593
+ (from, to) => sheetsInRange(from, to)));
594
+ }
595
+ else {
596
+ graph.setPrecedents(key, null);
597
+ volatile.delete(key);
598
+ }
599
+ }
600
+ else if (text.startsWith(TEXT_PREFIX)) {
601
+ // Excel's apostrophe: what follows is text, whatever it looks like,
602
+ // and the apostrophe itself is not part of it. It is the only way to
603
+ // keep a leading zero, a part number that reads as a date, or the
604
+ // text of a formula in a cell.
605
+ value = text.slice(1);
606
+ }
607
+ else {
608
+ const n = Number(text);
609
+ const upper = text.toUpperCase();
610
+ value = text !== '' && Number.isFinite(n) ? n
611
+ : upper === 'TRUE' ? true
612
+ : upper === 'FALSE' ? false
613
+ : typedError(text) ?? text;
614
+ }
615
+ visiting.delete(key);
616
+ depth -= 1;
617
+ values.set(key, value);
618
+ if (iteration.enabled)
619
+ previous.set(key, value);
620
+ return value;
621
+ }
622
+ /** What typed text is worth when it is not a formula: a number, a boolean or itself. */
623
+ function literal(text) {
624
+ const t = text.trim();
625
+ if (t === '')
626
+ return '';
627
+ if (t.startsWith(TEXT_PREFIX))
628
+ return t.slice(1);
629
+ if (t.startsWith('='))
630
+ return t;
631
+ const n = Number(t);
632
+ const upper = t.toUpperCase();
633
+ return Number.isFinite(n) ? n
634
+ : upper === 'TRUE' ? true
635
+ : upper === 'FALSE' ? false
636
+ : typedError(t) ?? t;
637
+ }
638
+ function rowCount(sheet) {
639
+ return sheetCells(sheet)?.length ?? 0;
640
+ }
641
+ function colCount(sheet) {
642
+ const cells = sheetCells(sheet);
643
+ if (!cells)
644
+ return 0;
645
+ return cells.reduce((max, row) => Math.max(max, row.length), 0);
646
+ }
647
+ /** Drop cached values for a cell and everything downstream of it, and
648
+ * for every volatile cell and its readers, which any write may affect. */
649
+ function invalidate(keys) {
650
+ const touched = [...keys];
651
+ for (const key of keys)
652
+ values.delete(key);
653
+ for (const key of volatile) {
654
+ if (values.delete(key))
655
+ touched.push(key);
656
+ }
657
+ for (const key of graph.dirtyFrom([...keys, ...volatile])) {
658
+ values.delete(key);
659
+ touched.push(key);
660
+ }
661
+ return touched;
662
+ }
663
+ /** Every listener on raw writes, plus the option that is one of them. */
664
+ const writeListeners = new Set();
665
+ function emitWrite(change) {
666
+ options.onWrite?.(change);
667
+ for (const listener of writeListeners)
668
+ listener(change);
669
+ }
670
+ function reportRecalc(keys) {
671
+ const cb = options.onRecalc;
672
+ if (!cb || keys.length === 0)
673
+ return;
674
+ cb(keys.map((key) => {
675
+ const gap = key.indexOf(' ');
676
+ const gap2 = key.indexOf(' ', gap + 1);
677
+ const row = Number(key.slice(0, gap));
678
+ const col = Number(key.slice(gap + 1, gap2));
679
+ const sheet = key.slice(gap2 + 1);
680
+ return { sheet, row, col, value: compute(sheet, row, col) };
681
+ }));
682
+ }
683
+ const workbook = {
684
+ get sheets() { return [...order]; },
685
+ get active() { return active; },
686
+ get names() { return names; },
687
+ get tables() { return tables; },
688
+ setActive(name) {
689
+ if (sheetCells(name))
690
+ active = order.find((n) => n.toLowerCase() === name.toLowerCase()) ?? active;
691
+ },
692
+ addSheet(name, at) {
693
+ const chosen = name ?? nextSheetName(order);
694
+ if (!isValidSheetName(chosen)) {
695
+ throw new Error(`"${chosen}" is not a valid sheet name: it must be 1 to 31 characters and must not contain : \\ / ? * [ ]`);
696
+ }
697
+ if (sheetCells(chosen))
698
+ throw new Error(`a sheet named "${chosen}" already exists`);
699
+ byName.set(chosen.toLowerCase(), []);
700
+ const index = at === undefined ? order.length : Math.max(0, Math.min(at, order.length));
701
+ order.splice(index, 0, chosen);
702
+ active = chosen;
703
+ loadEngine();
704
+ return chosen;
705
+ },
706
+ removeSheet(name) {
707
+ const index = order.findIndex((n) => n.toLowerCase() === name.toLowerCase());
708
+ // A workbook with no sheets has nowhere to put the cursor, and Excel
709
+ // refuses the same way.
710
+ if (index < 0 || order.length <= 1)
711
+ return false;
712
+ const [removed] = order.splice(index, 1);
713
+ byName.delete(removed.toLowerCase());
714
+ // The tables that lived on it go with it: a table on a sheet that is
715
+ // gone resolves to cells that are gone.
716
+ for (const table of rawTables.list()) {
717
+ if (table.sheet.toLowerCase() === removed.toLowerCase())
718
+ rawTables.remove(table.name);
719
+ }
720
+ // Every cached value may have read the sheet that just went.
721
+ dropAll();
722
+ loadEngine();
723
+ if (active.toLowerCase() === removed.toLowerCase()) {
724
+ active = order[Math.min(index, order.length - 1)] ?? order[0];
725
+ }
726
+ settleAll();
727
+ return true;
728
+ },
729
+ renameSheet(from, to) {
730
+ const index = order.findIndex((n) => n.toLowerCase() === from.toLowerCase());
731
+ if (index < 0 || !isValidSheetName(to))
732
+ return false;
733
+ if (from.toLowerCase() !== to.toLowerCase() && sheetCells(to))
734
+ return false;
735
+ const cells = sheetCells(from);
736
+ byName.delete(from.toLowerCase());
737
+ byName.set(to.toLowerCase(), cells);
738
+ order[index] = to;
739
+ if (active.toLowerCase() === from.toLowerCase())
740
+ active = to;
741
+ // Every formula and name that pointed at the old name points at the
742
+ // new one, as in Excel; otherwise =Orders!B2 on Summary read #REF!
743
+ // the moment Orders became Sales. The rewrite goes through the parser,
744
+ // so a string literal holding the old name is not touched.
745
+ for (const [, sheet] of byName) {
746
+ for (const line of sheet) {
747
+ for (let c = 0; c < line.length; c += 1) {
748
+ const next = renameSheetReferences(line[c], from, to);
749
+ if (typeof next === 'string')
750
+ line[c] = next;
751
+ }
752
+ }
753
+ }
754
+ for (const entry of names.list()) {
755
+ const next = renameSheetReferences(entry.refersTo, from, to);
756
+ if (typeof next === 'string' && next !== entry.refersTo)
757
+ names.define(entry.name, next);
758
+ }
759
+ // A table names the sheet it sits on, and a structured reference
760
+ // resolves through that name. Leaving it behind turned every
761
+ // `=SUM(Orders[Amount])` into #REF! the moment the sheet was renamed.
762
+ for (const table of rawTables.list()) {
763
+ if (table.sheet.toLowerCase() === from.toLowerCase())
764
+ rawTables.define({ ...table, sheet: to });
765
+ }
766
+ dropAll();
767
+ loadEngine();
768
+ settleAll();
769
+ return true;
770
+ },
771
+ moveSheet(name, to) {
772
+ const index = order.findIndex((n) => n.toLowerCase() === name.toLowerCase());
773
+ if (index < 0)
774
+ return false;
775
+ const [moved] = order.splice(index, 1);
776
+ order.splice(Math.max(0, Math.min(to, order.length)), 0, moved);
777
+ return true;
778
+ },
779
+ copySheet(from, to) {
780
+ const index = order.findIndex((n) => n.toLowerCase() === from.toLowerCase());
781
+ const source = sheetCells(from);
782
+ if (index < 0 || !source)
783
+ return null;
784
+ let name = to;
785
+ if (name === undefined) {
786
+ const base = order[index];
787
+ for (let i = 2;; i += 1) {
788
+ const candidate = `${base} (${i})`;
789
+ if (!sheetCells(candidate) && isValidSheetName(candidate)) {
790
+ name = candidate;
791
+ break;
792
+ }
793
+ if (i > 1000)
794
+ return null;
795
+ }
796
+ }
797
+ if (!isValidSheetName(name) || sheetCells(name))
798
+ return null;
799
+ byName.set(name.toLowerCase(), source.map((line) => [...line]));
800
+ order.splice(index + 1, 0, name);
801
+ active = name;
802
+ // A table belongs to its sheet, so the copy gets one of its own, as
803
+ // Excel's Move or Copy does. Without it the copied cells keep their
804
+ // `[@Qty]` formulas with no table to resolve them, and every one of
805
+ // them reads #REF!.
806
+ for (const table of rawTables.list()) {
807
+ if (table.sheet.toLowerCase() !== from.toLowerCase())
808
+ continue;
809
+ rawTables.define({ ...table, sheet: name, name: freeTableName(table.name) });
810
+ }
811
+ // Nothing cached read the new sheet yet, but a formula elsewhere
812
+ // that reads a whole column of it by name cannot exist either, so
813
+ // only the graph needs the new cells' precedents, which compute
814
+ // records on first read. An engine with a copy of the cells does
815
+ // need the new sheet.
816
+ loadEngine();
817
+ return name;
818
+ },
819
+ getRaw(sheet, row, col) {
820
+ return sheetCells(sheet)?.[row]?.[col] ?? '';
821
+ },
822
+ setRaw(sheet, row, col, text) {
823
+ const cells = sheetCells(sheet);
824
+ if (!cells || row < 0 || col < 0)
825
+ return;
826
+ while (cells.length <= row)
827
+ cells.push([]);
828
+ const line = cells[row];
829
+ while (line.length <= col)
830
+ line.push('');
831
+ if (line[col] === text)
832
+ return;
833
+ if (SUBTOTAL_TEXT.test(text) || SUBTOTAL_TEXT.test(line[col] ?? ''))
834
+ subtotalsHere = null;
835
+ line[col] = text;
836
+ engine.write?.(sheet, row, col, text);
837
+ emitWrite({ sheet: order.find((n) => n.toLowerCase() === sheet.toLowerCase()) ?? sheet, row, col, text });
838
+ const key = cellKey(sheet, row, col);
839
+ const keys = [key];
840
+ // A cell that is no longer a formula reads nothing, and spills nothing.
841
+ if (!text.trim().startsWith('=')) {
842
+ graph.setPrecedents(key, null);
843
+ volatile.delete(key);
844
+ }
845
+ if (spills.has(key))
846
+ keys.push(...clearSpill(key));
847
+ // Text landing in a spilled cell blocks its anchor; a cell going
848
+ // blank may free one that was blocked.
849
+ const anchor = spilledBy.get(key);
850
+ if (anchor !== undefined)
851
+ keys.push(anchor);
852
+ keys.push(...blocked);
853
+ const touched = invalidate(keys);
854
+ // The written cell and the anchors it touched compute now, so a new
855
+ // or changed spill is on record before anything reads under it;
856
+ // plain dependents wait for their next read, as before.
857
+ for (const k of keys)
858
+ if (isFormulaKey(k)) {
859
+ const at = parseCellKey(k);
860
+ compute(at.sheet ?? sheet, at.row, at.col);
861
+ }
862
+ reportRecalc([...new Set([...touched, ...settlePending(), ...runIterations()])]);
863
+ },
864
+ getValue(sheet, row, col) {
865
+ return compute(sheet, row, col);
866
+ },
867
+ evaluateText(sheet, text, override, at) {
868
+ const t = text.trim();
869
+ if (t === '')
870
+ return '';
871
+ if (t.startsWith('=')) {
872
+ if (!sheetCells(sheet))
873
+ return { error: '#REF!' };
874
+ const ast = parseCached(t);
875
+ // The cell the text is read for, so ROW() and COLUMN() and a
876
+ // [@Column] reference mean something in a rule's formula.
877
+ return ast ? evaluate(ast, contextFor(sheet, override, at ?? (override ? { row: override.row, col: override.col } : undefined))) : { error: '#PARSE!' };
878
+ }
879
+ return literal(t);
880
+ },
881
+ evaluateRange(sheet, text) {
882
+ const t = text.trim();
883
+ if (!t.startsWith('=') || !sheetCells(sheet))
884
+ return null;
885
+ const ast = parseCached(t);
886
+ return ast ? rangeValues(ast, contextFor(sheet)) : null;
887
+ },
888
+ snapshot(sheet) {
889
+ const rows = rowCount(sheet);
890
+ const cols = colCount(sheet);
891
+ const out = [];
892
+ for (let r = 0; r < rows; r += 1) {
893
+ const line = [];
894
+ for (let c = 0; c < cols; c += 1)
895
+ line.push(compute(sheet, r, c));
896
+ out.push(line);
897
+ }
898
+ return out;
899
+ },
900
+ repointAfterMove(move) {
901
+ if (!sheetCells(move.sheet) || !sheetCells(move.toSheet))
902
+ return;
903
+ if (move.dRow === 0 && move.dCol === 0 && move.sheet === move.toSheet)
904
+ return;
905
+ let touched = false;
906
+ // The whole workbook: another sheet's =Orders!A5 names a moved cell
907
+ // just as a local reference does.
908
+ for (const other of order) {
909
+ const cells = sheetCells(other);
910
+ for (let r = 0; r < cells.length; r += 1) {
911
+ const line = cells[r];
912
+ for (let c = 0; c < line.length; c += 1) {
913
+ const text = line[c] ?? '';
914
+ if (!text.startsWith('='))
915
+ continue;
916
+ const next = repointReferences(text, move, other);
917
+ if (typeof next === 'string' && next !== text) {
918
+ line[c] = next;
919
+ touched = true;
920
+ }
921
+ }
922
+ }
923
+ }
924
+ // A name has no home sheet, so only a qualified reference can match.
925
+ for (const entry of names.list()) {
926
+ const next = repointReferences(entry.refersTo, move, null);
927
+ if (typeof next === 'string' && next !== entry.refersTo) {
928
+ names.define(entry.name, next);
929
+ touched = true;
930
+ }
931
+ }
932
+ if (!touched)
933
+ return;
934
+ dropAll();
935
+ astCache.clear();
936
+ loadEngine();
937
+ settleAll();
938
+ },
939
+ applyStructuralEdit(sheet, edit) {
940
+ const target = sheetCells(sheet);
941
+ if (!target || edit.count <= 0)
942
+ return;
943
+ // The tables move with their cells, so a structured reference keeps
944
+ // meaning the same column after a row is inserted above the table.
945
+ const moved = shiftTables(rawTables.list(), sheet, edit);
946
+ rawTables.clear();
947
+ for (const table of moved)
948
+ rawTables.define(table);
949
+ // Rewrite every formula in the WORKBOOK, not just this sheet: another
950
+ // sheet may hold =Orders!A5, and inserting a row in Orders has to move
951
+ // it exactly as if it were local.
952
+ for (const other of order) {
953
+ const cells = sheetCells(other);
954
+ for (let r = 0; r < cells.length; r += 1) {
955
+ const line = cells[r];
956
+ for (let c = 0; c < line.length; c += 1) {
957
+ const text = line[c] ?? '';
958
+ if (!text.startsWith('='))
959
+ continue;
960
+ // Only references INTO this sheet move: an unqualified one on
961
+ // another sheet belongs to that sheet's geometry, which did not
962
+ // change, and a reference on THIS sheet that names another sheet
963
+ // belongs to that one. The scope tells the rewriter both.
964
+ if (other !== sheet && !text.includes(`${sheet}!`) && !text.includes(`'${sheet}'!`))
965
+ continue;
966
+ const next = fixupReferences(text, edit, { sheet, self: other });
967
+ if (typeof next === 'string')
968
+ line[c] = next;
969
+ }
970
+ }
971
+ }
972
+ // A name has no home sheet, so only one that names this sheet moves.
973
+ // NetSales = Orders!$I$2:$I$25 must not shift because a column went
974
+ // into Summary.
975
+ for (const entry of names.list()) {
976
+ const next = fixupReferences(entry.refersTo, edit, { sheet, self: null });
977
+ if (typeof next === 'string' && next !== entry.refersTo)
978
+ names.define(entry.name, next);
979
+ }
980
+ const blankRow = () => [];
981
+ if (edit.kind === 'insertRows') {
982
+ target.splice(edit.at, 0, ...Array.from({ length: edit.count }, blankRow));
983
+ }
984
+ else if (edit.kind === 'deleteRows') {
985
+ target.splice(edit.at, edit.count);
986
+ }
987
+ else if (edit.kind === 'insertCols') {
988
+ for (const line of target) {
989
+ if (line.length >= edit.at)
990
+ line.splice(edit.at, 0, ...Array(edit.count).fill(''));
991
+ }
992
+ }
993
+ else {
994
+ for (const line of target) {
995
+ if (line.length > edit.at)
996
+ line.splice(edit.at, edit.count);
997
+ }
998
+ }
999
+ dropAll();
1000
+ astCache.clear();
1001
+ loadEngine();
1002
+ settleAll();
1003
+ },
1004
+ precedents(sheet, row, col) {
1005
+ const name = order.find((n) => n.toLowerCase() === sheet.toLowerCase());
1006
+ if (!name)
1007
+ return [];
1008
+ // Computing the cell records what it reads.
1009
+ compute(name, row, col);
1010
+ return graph.precedentsOf(cellKey(name, row, col)).map((key) => {
1011
+ const at = parseCellKey(key);
1012
+ return { sheet: at.sheet ?? name, row: at.row, col: at.col };
1013
+ });
1014
+ },
1015
+ dependents(sheet, row, col) {
1016
+ const name = order.find((n) => n.toLowerCase() === sheet.toLowerCase());
1017
+ if (!name)
1018
+ return [];
1019
+ // A formula that was never evaluated has no edge yet: evaluate every
1020
+ // formula once so the graph is whole.
1021
+ for (const other of order) {
1022
+ const cells = sheetCells(other) ?? [];
1023
+ for (let r = 0; r < cells.length; r += 1) {
1024
+ const line = cells[r];
1025
+ for (let c = 0; c < line.length; c += 1)
1026
+ if (line[c].trim().startsWith('='))
1027
+ compute(other, r, c);
1028
+ }
1029
+ }
1030
+ return graph.dependentsOf(cellKey(name, row, col)).map((key) => {
1031
+ const at = parseCellKey(key);
1032
+ return { sheet: at.sheet ?? name, row: at.row, col: at.col };
1033
+ });
1034
+ },
1035
+ subscribeWrites(listener) {
1036
+ writeListeners.add(listener);
1037
+ return () => { writeListeners.delete(listener); };
1038
+ },
1039
+ setHiddenRows(source) {
1040
+ hiddenRows = source;
1041
+ // Only SUBTOTAL reads what is hidden, and nothing in the dependency
1042
+ // graph can see that it changed - so everything is recomputed, but
1043
+ // only when there is a SUBTOTAL to recompute.
1044
+ if (!hasSubtotal())
1045
+ return;
1046
+ dropAll();
1047
+ settleAll();
1048
+ },
1049
+ recalculate() {
1050
+ dropAll();
1051
+ loadEngine();
1052
+ settleAll();
1053
+ },
1054
+ get iteration() { return { ...iteration }; },
1055
+ setIteration(next) {
1056
+ const wanted = cleanIteration({ ...iteration, ...next });
1057
+ if (wanted.enabled === iteration.enabled && wanted.maxIterations === iteration.maxIterations && wanted.maxChange === iteration.maxChange)
1058
+ return;
1059
+ iteration = wanted;
1060
+ // Turning it on turns #CYCLE! into a number, and turning it off turns
1061
+ // the number back into #CYCLE!, so every cached value is suspect.
1062
+ dropAll();
1063
+ settleAll();
1064
+ },
1065
+ spillOf(sheet, row, col) {
1066
+ const name = order.find((n) => n.toLowerCase() === sheet.toLowerCase());
1067
+ if (!name)
1068
+ return null;
1069
+ compute(name, row, col);
1070
+ const key = cellKey(name, row, col);
1071
+ const anchor = spills.has(key) ? key : spilledBy.get(key);
1072
+ if (anchor === undefined)
1073
+ return null;
1074
+ const rect = spills.get(anchor);
1075
+ if (!rect)
1076
+ return null;
1077
+ const at = parseCellKey(anchor);
1078
+ return { anchor: { row: at.row, col: at.col }, rect: [rect.r1, rect.c1, rect.r2, rect.c2] };
1079
+ },
1080
+ spills(sheet) {
1081
+ const name = order.find((n) => n.toLowerCase() === sheet.toLowerCase());
1082
+ if (!name)
1083
+ return [];
1084
+ settleAll();
1085
+ const out = [];
1086
+ for (const [anchor, rect] of spills) {
1087
+ const at = parseCellKey(anchor);
1088
+ if ((at.sheet ?? '').toLowerCase() !== name.toLowerCase())
1089
+ continue;
1090
+ out.push({ row: at.row, col: at.col, rect: [rect.r1, rect.c1, rect.r2, rect.c2] });
1091
+ }
1092
+ return out.sort((a, b) => a.row - b.row || a.col - b.col);
1093
+ },
1094
+ rowCount,
1095
+ colCount,
1096
+ serialize() {
1097
+ const list = rawTables.list();
1098
+ return {
1099
+ sheets: order.map((name) => ({ name, cells: sheetCells(name).map((r) => [...r]) })),
1100
+ active,
1101
+ names: names.serialize(),
1102
+ // Absent rather than empty in a workbook with no tables, so a saved
1103
+ // document from before they existed reads the same either way.
1104
+ ...(list.length ? { tables: list.map((t) => ({ ...t })) } : {}),
1105
+ // Written only when it is on, so a document saved by a workbook that
1106
+ // never heard of iteration reads back identically.
1107
+ ...(iteration.enabled ? { iteration: { ...iteration } } : {}),
1108
+ };
1109
+ },
1110
+ };
1111
+ for (const sheet of initial.length > 0 ? initial : [{ name: 'Sheet1', cells: [] }]) {
1112
+ byName.set(sheet.name.toLowerCase(), sheet.cells.map((r) => [...r]));
1113
+ order.push(sheet.name);
1114
+ }
1115
+ active = order[0] ?? '';
1116
+ loadEngine();
1117
+ settleAll();
1118
+ return workbook;
1119
+ }
1120
+ export { isError };