@marimo-team/frontend 0.16.1 → 0.16.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 (310) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-2wVcyvDj.js → ConnectedDataExplorerComponent-Brtw1DxF.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-D2j6i0hv.js → ImageComparisonComponent-Dxl-PbZX.js} +1 -1
  3. package/dist/assets/{VegaLite-BckFaf2D.js → VegaLite-BXQF0Cx_.js} +1 -1
  4. package/dist/assets/_baseEach-BjSm9ht3.js +1 -0
  5. package/dist/assets/_baseMap-CV4Ezmtf.js +1 -0
  6. package/dist/assets/_baseUniq-Ci9yZGxz.js +1 -0
  7. package/dist/assets/{_createAggregator-C5CVY-0t.js → _createAggregator-VFK9K2d9.js} +1 -1
  8. package/dist/assets/{agent-panel-RGLNjkYe.js → agent-panel-BoscVLCT.js} +7 -7
  9. package/dist/assets/{any-language-editor-DjuXwGCA.js → any-language-editor-ChaY_VUU.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-Dyj4ds_R.js → architectureDiagram-W76B3OCA-CueUUFYd.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-Dt2aKpPf.js → between-horizontal-start-DAHqmLYT.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-o-i7DDvN.js → blockDiagram-QIGZ2CNN-BYYygyWn.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-DGHEwWrx.js → c4Diagram-FPNF74CW-DAz3xEh1.js} +1 -1
  14. package/dist/assets/channel-6SqQ2U_X.js +1 -0
  15. package/dist/assets/chat-panel-DJkOLrw9.js +3 -0
  16. package/dist/assets/{chunk-4BX2VUAB-BJecb-Ri.js → chunk-4BX2VUAB-8g-RyHdt.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-CAATkc4w.js → chunk-55IACEB6-iWZZ8Mt6.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-DPuNbQ-f.js → chunk-FMBD7UC4-knjss4wk.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-C8TWVLiH.js → chunk-K7UQS3LO-DVIwPBgZ.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-DiZZ09q4.js → chunk-QN33PNHL-CBU8pN6I.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-BIUM7usu.js → chunk-QZHKN3VN-5ljElUF4.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-vGTArPBG.js → chunk-TVAH2DTR-DkIdGINc.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-D2KRqp_x.js → chunk-TZMSLE5B-CIFOSTqh.js} +1 -1
  24. package/dist/assets/{circle-play-cjeNez0N.js → circle-play-BOdsbq5u.js} +1 -1
  25. package/dist/assets/classDiagram-KNZD7YFC-DVqXcTYf.js +1 -0
  26. package/dist/assets/classDiagram-v2-RKCZMP56-DVqXcTYf.js +1 -0
  27. package/dist/assets/{clear-button-C97JtAez.js → clear-button-GAjXl0CQ.js} +1 -1
  28. package/dist/assets/clone-DSDb0xen.js +1 -0
  29. package/dist/assets/command-palette-BUXkqoLh.js +1 -0
  30. package/dist/assets/{common-Du9rSOwD.js → common-DahoYqdi.js} +1 -1
  31. package/dist/assets/{compile-CZXqyOxa.js → compile-Bg8uJ7vm.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-CqUN5Y9b.js → cose-bilkent-S5V4N54A-z_0gqD9K.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-RJqTI9DM.js → dagre-5GWH7T2D-BMt7CNXL.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-DZN0q1LV.js → data-grid-overlay-editor-Ctn4XtXx.js} +1 -1
  35. package/dist/assets/datasources-panel-C7sqRIHs.js +1 -0
  36. package/dist/assets/{dependency-graph-panel-CEog_O7V.js → dependency-graph-panel-DNajptzv.js} +4 -4
  37. package/dist/assets/{diagram-N5W7TBWH-D-l4zZ9d.js → diagram-N5W7TBWH-BzwvLvAy.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-CCOmBUt-.js → diagram-QEK2KX5R-DRLJ56FS.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-C_I_9jnZ.js → diagram-S2PKOQOG-Bf8x4KTU.js} +1 -1
  40. package/dist/assets/{documentation-panel-C1BtMZ3M.js → documentation-panel-Dm6Ozl67.js} +1 -1
  41. package/dist/assets/{edit-page-B-oevUZ9.js → edit-page-CGc9EjuG.js} +53 -42
  42. package/dist/assets/{ellipsis-vertical-BEb-J8z6.js → ellipsis-vertical-Bj1YXvZe.js} +1 -1
  43. package/dist/assets/{empty-state-C99UyDE3.js → empty-state-CYev-D31.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-BePOLi5M.js → erDiagram-AWTI2OKA-DmgzgN_I.js} +1 -1
  45. package/dist/assets/{error-panel-Bs34jXFh.js → error-panel-BYG4twCa.js} +1 -1
  46. package/dist/assets/{file-explorer-panel-Ck6UL861.js → file-explorer-panel-BSMiOApi.js} +1 -1
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-BgjFu5l7.js → flowDiagram-PVAE7QVJ-BdRKkajr.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-YOPb3XSV.js → ganttDiagram-OWAHRB6G-lfRAMnq_.js} +5 -5
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-CGhqaDTy.js → gitGraphDiagram-NY62KEGX-CQVTIrHF.js} +1 -1
  50. package/dist/assets/{glide-data-editor-9QUH6iso.js → glide-data-editor-D5A4pou7.js} +4 -4
  51. package/dist/assets/{graph-DQQFGrho.js → graph-CBNo279v.js} +1 -1
  52. package/dist/assets/{home-page-DRKpPCrF.js → home-page-CmdznBJR.js} +2 -2
  53. package/dist/assets/{index-SGLNXrGP.js → index-0dfGh-Gj.js} +1 -1
  54. package/dist/assets/{index-aE43R74q.js → index-BDYVSSzB.js} +1 -1
  55. package/dist/assets/{index-BJNCMUmG.js → index-B_KyDZ94.js} +1 -1
  56. package/dist/assets/{index-BjgnbONl.js → index-Bfy-I_lW.js} +1 -1
  57. package/dist/assets/{index-CUFv_thQ.js → index-Bh98Tp-z.js} +1 -1
  58. package/dist/assets/{index-C2MD0vgD.js → index-BhroIwBL.js} +1 -1
  59. package/dist/assets/{index-DdnKZNxM.js → index-BtQtesaI.js} +1 -1
  60. package/dist/assets/index-C0iXCvyY.css +1 -0
  61. package/dist/assets/index-C1SHFMCp.js +581 -0
  62. package/dist/assets/{index-C_tkBKNO.js → index-C6DWtSls.js} +1 -1
  63. package/dist/assets/{index-Aeo6WiK7.js → index-C71cdkH-.js} +1 -1
  64. package/dist/assets/{index-G5QZppK2.js → index-CT_FTqvK.js} +1 -1
  65. package/dist/assets/{index-B8jXZ12t.js → index-CU5rRr66.js} +1 -1
  66. package/dist/assets/{index-BAbIIxHU.js → index-Cb6duXQm.js} +1 -1
  67. package/dist/assets/{index-BW3k9Gss.js → index-D23e9zQj.js} +1 -1
  68. package/dist/assets/index-DUGecC2Z.js +68 -0
  69. package/dist/assets/{index-CFKO7WXI.js → index-DcGIOAQi.js} +1 -1
  70. package/dist/assets/{index-ClzeQrN7.js → index-PJfa9qXY.js} +1 -1
  71. package/dist/assets/{index-C1ez98sk.js → index-SPslPC2B.js} +1 -1
  72. package/dist/assets/{index-BprjMYH5.js → index-VPQlo4Uz.js} +1 -1
  73. package/dist/assets/{index-CfaDbEdi.js → index-qbTLKWyG.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-DBu8p9gd.js +2 -0
  75. package/dist/assets/{isEmpty-D-4c7sMv.js → isEmpty-CnOLuQIv.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-C94u3Mv3.js → journeyDiagram-BIP6EPQ6-6U_vHJBH.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-BEXYFzz7.js → kanban-definition-6OIFK2YF-DgnR14ys.js} +1 -1
  78. package/dist/assets/{layout-Bz2BJ2ru.js → layout-RHmq4fP9.js} +1 -1
  79. package/dist/assets/{linear-D8s7K76e.js → linear-CLdOVPGV.js} +1 -1
  80. package/dist/assets/links-Dd1icsEk.js +7 -0
  81. package/dist/assets/{logs-panel-DC7wpmPz.js → logs-panel-CjbuhBLx.js} +1 -1
  82. package/dist/assets/{markdown-renderer-DRdSWR9X.js → markdown-renderer-X5YJvAZq.js} +3 -3
  83. package/dist/assets/{mermaid-Y3x4hmD0.js → mermaid-Bl2T5oEC.js} +1 -1
  84. package/dist/assets/{mermaid.core-DzthE35Y.js → mermaid.core-CfukBvGI.js} +4 -4
  85. package/dist/assets/min-BXIes1Za.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-DktvuLe1.js → mindmap-definition-Q6HEUPPD-BXCjP4Lu.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-BEfwI1IT.js → number-overlay-editor-BUyqkSes.js} +1 -1
  88. package/dist/assets/{outline-panel-CdsnAy2w.js → outline-panel-BvGcPKdd.js} +1 -1
  89. package/dist/assets/{packages-panel-DiTA-d_D.js → packages-panel-BichDQWG.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-DQDNQ-de.js → pieDiagram-ADFJNKIX-CMzJFIJM.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-0kgIXc2-.js → quadrantDiagram-LMRXKWRM-CfGssUlO.js} +1 -1
  92. package/dist/assets/{react-plotly-DJqqfM7c.js → react-plotly-DR3hV0HW.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-B5rb0ypd.js → requirementDiagram-4UW4RH46-CfrFolth.js} +1 -1
  94. package/dist/assets/{run-page-CFmLrv1R.js → run-page-Bqd_4ePD.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-Dom7IlnF.js → sankeyDiagram-GR3RE2ED-D_UttKU0.js} +1 -1
  96. package/dist/assets/{scratchpad-panel-CuHWpHO8.js → scratchpad-panel-D5N15ji1.js} +1 -1
  97. package/dist/assets/secrets-panel-BpbnAO4R.js +1 -0
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-PNJWXQbw.js → sequenceDiagram-C3RYC4MD-MdfQQApP.js} +1 -1
  99. package/dist/assets/{slides-component-CJgaTRZ0.js → slides-component-C0z7rXmk.js} +1 -1
  100. package/dist/assets/{snippets-panel-B2EC1txM.js → snippets-panel-wlpZ_Wzx.js} +1 -1
  101. package/dist/assets/sortBy-BW_zNHP6.js +1 -0
  102. package/dist/assets/{state-CWict9RU.js → state-CDooX-dk.js} +1 -1
  103. package/dist/assets/{stateDiagram-KXAO66HF-BE58aJnr.js → stateDiagram-KXAO66HF-H7kfw3ot.js} +1 -1
  104. package/dist/assets/stateDiagram-v2-UMBNRL4Z-YMeb9qMR.js +1 -0
  105. package/dist/assets/{storage-DRaR04wR.js → storage-b1QCapTq.js} +6 -6
  106. package/dist/assets/{terminal-BX3Su5q7.js → terminal-CPV44BXz.js} +1 -1
  107. package/dist/assets/{time-hUzZfpNE.js → time-DDy3xv5Y.js} +1 -1
  108. package/dist/assets/{timeline-definition-XQNQX7LJ-CqQP9t51.js → timeline-definition-XQNQX7LJ-J-cPRT2_.js} +1 -1
  109. package/dist/assets/{tracing-B10Q1n-L.js → tracing-3eHHRUiJ.js} +2 -2
  110. package/dist/assets/{tracing-panel-Du8WCnno.js → tracing-panel-BMgy3D7d.js} +2 -2
  111. package/dist/assets/{trash-B81GTiv6.js → trash--tonOuDe.js} +1 -1
  112. package/dist/assets/{tree-6vW2ogkh.js → tree-ouIGEsVg.js} +1 -1
  113. package/dist/assets/{treemap-75Q7IDZK-CdwDwwsz.js → treemap-75Q7IDZK-CzJTJ_3R.js} +20 -20
  114. package/dist/assets/{variable-panel-D5qgJI7k.js → variable-panel-sFTn4Oih.js} +1 -1
  115. package/dist/assets/{vega-component-DJaJWMJM.js → vega-component-BkPkzX9r.js} +1 -1
  116. package/dist/assets/{xychartDiagram-6GGTOJPD-WFtXqaM9.js → xychartDiagram-6GGTOJPD-BZ8WOb_8.js} +1 -1
  117. package/dist/index.html +10 -3
  118. package/package.json +8 -8
  119. package/src/__mocks__/common.ts +5 -3
  120. package/src/__mocks__/notebook.ts +2 -2
  121. package/src/__mocks__/requests.ts +1 -0
  122. package/src/__tests__/main.test.tsx +2 -2
  123. package/src/components/ai/ai-provider-icon.tsx +2 -0
  124. package/src/components/app-config/ai-config.tsx +32 -1
  125. package/src/components/app-config/common.tsx +2 -2
  126. package/src/components/app-config/user-config-form.tsx +26 -0
  127. package/src/components/audio/audio-recorder.tsx +0 -1
  128. package/src/components/chat/acp/blocks.tsx +2 -2
  129. package/src/components/chat/acp/thread.tsx +3 -5
  130. package/src/components/chat/acp/utils.ts +5 -5
  131. package/src/components/chat/chat-panel.tsx +1 -1
  132. package/src/components/data-table/__tests__/columns.test.tsx +38 -0
  133. package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
  134. package/src/components/data-table/cell-hover-template/feature.ts +1 -1
  135. package/src/components/data-table/cell-hover-template/types.ts +1 -1
  136. package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
  137. package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
  138. package/src/components/data-table/charts/components/chart-items.tsx +1 -1
  139. package/src/components/data-table/charts/components/form-fields.tsx +2 -2
  140. package/src/components/data-table/charts/constants.ts +1 -1
  141. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  142. package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
  143. package/src/components/data-table/columns.tsx +22 -3
  144. package/src/components/data-table/data-table.tsx +35 -3
  145. package/src/components/data-table/date-popover.tsx +1 -1
  146. package/src/components/data-table/download-actions.tsx +1 -1
  147. package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
  148. package/src/components/data-table/renderers.tsx +22 -13
  149. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
  150. package/src/components/data-table/schemas.ts +16 -0
  151. package/src/components/data-table/types.ts +4 -3
  152. package/src/components/datasources/column-preview.tsx +9 -6
  153. package/src/components/debugger/debugger-code.tsx +1 -1
  154. package/src/components/dependency-graph/custom-node.tsx +15 -6
  155. package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
  156. package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
  157. package/src/components/dependency-graph/dependency-graph.tsx +1 -1
  158. package/src/components/dependency-graph/elements.ts +7 -7
  159. package/src/components/dependency-graph/utils/changes.ts +4 -4
  160. package/src/components/editor/Cell.tsx +7 -1
  161. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  162. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
  163. package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
  164. package/src/components/editor/columns/storage.ts +1 -1
  165. package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
  166. package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
  167. package/src/components/editor/database/add-database-form.tsx +11 -0
  168. package/src/components/editor/database/as-code.ts +104 -5
  169. package/src/components/editor/database/schemas.ts +36 -18
  170. package/src/components/editor/errors/auto-fix.tsx +12 -2
  171. package/src/components/editor/errors/sql-validation-errors.tsx +40 -0
  172. package/src/components/editor/navigation/clipboard.ts +2 -2
  173. package/src/components/editor/output/ConsoleOutput.tsx +14 -2
  174. package/src/components/editor/output/JsonOutput.tsx +1 -1
  175. package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
  176. package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
  177. package/src/components/editor/renderers/grid-layout/types.ts +2 -2
  178. package/src/components/editor/renderers/plugins.ts +1 -1
  179. package/src/components/editor/renderers/types.ts +1 -1
  180. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
  181. package/src/components/forms/form.tsx +5 -5
  182. package/src/components/ui/links.tsx +1 -0
  183. package/src/core/ai/__tests__/model-registry.test.ts +0 -10
  184. package/src/core/ai/context/providers/cell-output.ts +1 -18
  185. package/src/core/ai/context/providers/error.ts +2 -2
  186. package/src/core/ai/ids/ids.ts +1 -0
  187. package/src/core/ai/model-registry.ts +2 -1
  188. package/src/core/cells/cells.ts +5 -5
  189. package/src/core/cells/logs.ts +1 -1
  190. package/src/core/cells/types.ts +1 -1
  191. package/src/core/codemirror/__tests__/format.test.ts +6 -0
  192. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  193. package/src/core/codemirror/editing/commands.ts +2 -2
  194. package/src/core/codemirror/find-replace/navigate.ts +1 -1
  195. package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
  196. package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
  197. package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
  198. package/src/core/codemirror/language/languages/markdown.ts +4 -1
  199. package/src/core/codemirror/language/languages/sql/banner-validation-errors.ts +85 -0
  200. package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
  201. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
  202. package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
  203. package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
  204. package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
  205. package/src/core/codemirror/language/languages/sql/sql.ts +218 -4
  206. package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
  207. package/src/core/codemirror/language/panel/panel.tsx +8 -2
  208. package/src/core/codemirror/language/panel/sql.tsx +86 -4
  209. package/src/core/codemirror/language/utils/ast.ts +3 -3
  210. package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
  211. package/src/core/codemirror/lsp/lens.ts +4 -4
  212. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  213. package/src/core/codemirror/lsp/types.ts +1 -1
  214. package/src/core/codemirror/markdown/completions.ts +1 -1
  215. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  216. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  217. package/src/core/config/config-schema.ts +1 -0
  218. package/src/core/config/feature-flag.tsx +6 -2
  219. package/src/core/datasets/request-registry.ts +24 -1
  220. package/src/core/dom/events.ts +1 -1
  221. package/src/core/dom/outline.ts +2 -2
  222. package/src/core/dom/uiregistry.ts +2 -8
  223. package/src/core/errors/__tests__/errors.test.ts +22 -4
  224. package/src/core/errors/errors.ts +29 -1
  225. package/src/core/errors/state.ts +1 -1
  226. package/src/core/islands/bridge.ts +1 -0
  227. package/src/core/islands/main.ts +3 -2
  228. package/src/core/islands/parse.ts +1 -3
  229. package/src/core/kernel/messages.ts +2 -1
  230. package/src/core/network/CachingRequestRegistry.ts +74 -0
  231. package/src/core/network/DeferredRequestRegistry.ts +3 -1
  232. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
  233. package/src/core/network/requests-network.ts +7 -0
  234. package/src/core/network/requests-static.ts +1 -0
  235. package/src/core/network/requests-toasting.ts +1 -0
  236. package/src/core/network/types.ts +3 -1
  237. package/src/core/variables/state.ts +2 -2
  238. package/src/core/wasm/__tests__/state.test.ts +1 -1
  239. package/src/core/wasm/bridge.ts +5 -0
  240. package/src/core/websocket/useMarimoWebSocket.tsx +9 -2
  241. package/src/custom.d.ts +1 -1
  242. package/src/hooks/useCellRenderCount.ts +1 -0
  243. package/src/hooks/useResizeHandle.ts +4 -1
  244. package/src/plugins/core/RenderHTML.tsx +1 -2
  245. package/src/plugins/core/registerReactComponent.tsx +23 -19
  246. package/src/plugins/impl/DataTablePlugin.tsx +18 -6
  247. package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
  248. package/src/plugins/impl/RefreshPlugin.tsx +1 -1
  249. package/src/plugins/impl/SliderPlugin.tsx +4 -0
  250. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
  251. package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
  252. package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
  253. package/src/plugins/impl/anywidget/model.ts +2 -3
  254. package/src/plugins/impl/data-editor/types.ts +1 -1
  255. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  256. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
  257. package/src/plugins/impl/data-frames/types.ts +1 -1
  258. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  259. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  260. package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
  261. package/src/plugins/impl/vega/loader.ts +1 -1
  262. package/src/plugins/impl/vega/vega-component.tsx +1 -1
  263. package/src/plugins/impl/vega/vega-loader.ts +2 -2
  264. package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
  265. package/src/plugins/layout/RoutesPlugin.tsx +1 -2
  266. package/src/plugins/plugins.ts +2 -2
  267. package/src/stories/dataframe.stories.tsx +2 -0
  268. package/src/utils/Logger.ts +1 -1
  269. package/src/utils/__tests__/data-views.test.ts +30 -68
  270. package/src/utils/__tests__/dom.test.ts +167 -0
  271. package/src/utils/__tests__/id-tree.test.ts +49 -1
  272. package/src/utils/__tests__/storage.test.ts +1 -1
  273. package/src/utils/__tests__/traceback.test.ts +13 -2
  274. package/src/utils/arrays.ts +1 -1
  275. package/src/utils/createReducer.ts +1 -5
  276. package/src/utils/data-views.ts +6 -19
  277. package/src/utils/dom.ts +55 -0
  278. package/src/utils/edit-distance.ts +1 -1
  279. package/src/utils/fileToBase64.ts +1 -1
  280. package/src/utils/id-tree.tsx +20 -18
  281. package/src/utils/json/base64.ts +13 -0
  282. package/src/utils/json/json-parser.ts +2 -2
  283. package/src/utils/lru.ts +4 -0
  284. package/src/utils/mergeRefs.ts +1 -1
  285. package/src/utils/objects.ts +3 -3
  286. package/src/utils/pluralize.ts +1 -1
  287. package/src/utils/routes.ts +2 -2
  288. package/src/utils/sets.ts +1 -1
  289. package/src/utils/traceback.ts +45 -15
  290. package/src/utils/tracer.ts +11 -9
  291. package/dist/assets/_baseEach-CvTX9w0Y.js +0 -1
  292. package/dist/assets/_baseMap-CtlwA90f.js +0 -1
  293. package/dist/assets/_baseUniq-BKktIGQ1.js +0 -1
  294. package/dist/assets/channel-Co6iMgWq.js +0 -1
  295. package/dist/assets/chat-panel-9alr8FS4.js +0 -3
  296. package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +0 -1
  297. package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +0 -1
  298. package/dist/assets/clone-BMP0PsTa.js +0 -1
  299. package/dist/assets/command-palette-B93Pjcky.js +0 -1
  300. package/dist/assets/datasources-panel-v7H3cR0p.js +0 -1
  301. package/dist/assets/index-2252nrk6.js +0 -68
  302. package/dist/assets/index-C7CoaNFb.js +0 -578
  303. package/dist/assets/index-DadI618h.css +0 -1
  304. package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +0 -2
  305. package/dist/assets/links-BpXlz1GG.js +0 -7
  306. package/dist/assets/min-BBO3-1Hg.js +0 -1
  307. package/dist/assets/secrets-panel-CfHc5YD0.js +0 -1
  308. package/dist/assets/sortBy-DZnlX29-.js +0 -1
  309. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +0 -1
  310. package/src/__tests__/lru.test.ts +0 -74
@@ -5,23 +5,32 @@ import { insertTab } from "@codemirror/commands";
5
5
  import { type SQLDialect, type SQLNamespace, sql } from "@codemirror/lang-sql";
6
6
  import type { EditorState, Extension } from "@codemirror/state";
7
7
  import { Compartment } from "@codemirror/state";
8
- import { type EditorView, keymap } from "@codemirror/view";
8
+ import { EditorView, keymap } from "@codemirror/view";
9
9
  import type { SyntaxNode, TreeCursor } from "@lezer/common";
10
10
  import { parser } from "@lezer/python";
11
11
  import {
12
12
  defaultSqlHoverTheme,
13
13
  NodeSqlParser,
14
+ type NodeSqlParserResult,
14
15
  type SupportedDialects as ParserDialects,
16
+ type SqlParseError,
15
17
  sqlExtension,
16
18
  } from "@marimo-team/codemirror-sql";
17
19
  import { DuckDBDialect } from "@marimo-team/codemirror-sql/dialects";
18
20
  import dedent from "string-dedent";
21
+ import { cellIdState } from "@/core/codemirror/cells/state";
19
22
  import { getFeatureFlag } from "@/core/config/feature-flag";
20
23
  import {
21
24
  dataSourceConnectionsAtom,
22
25
  setLatestEngineSelected,
23
26
  } from "@/core/datasets/data-source-connections";
24
- import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
27
+ import {
28
+ type ConnectionName,
29
+ DUCKDB_ENGINE,
30
+ INTERNAL_SQL_ENGINES,
31
+ } from "@/core/datasets/engines";
32
+ import { ValidateSQL } from "@/core/datasets/request-registry";
33
+ import type { ValidateSQLResult } from "@/core/kernel/messages";
25
34
  import { store } from "@/core/state/jotai";
26
35
  import { resolvedThemeAtom } from "@/theme/useTheme";
27
36
  import { Logger } from "@/utils/Logger";
@@ -32,11 +41,16 @@ import { parseArgsKwargs } from "../../utils/ast";
32
41
  import { indentOneTab } from "../../utils/indentOneTab";
33
42
  import type { QuotePrefixKind } from "../../utils/quotes";
34
43
  import { MarkdownLanguageAdapter } from "../markdown";
44
+ import {
45
+ clearSqlValidationError,
46
+ setSqlValidationError,
47
+ } from "./banner-validation-errors";
35
48
  import {
36
49
  customKeywordCompletionSource,
37
50
  tablesCompletionSource,
38
51
  } from "./completion-sources";
39
52
  import { SCHEMA_CACHE } from "./completion-store";
53
+ import { getSQLMode, type SQLMode } from "./sql-mode";
40
54
 
41
55
  const DEFAULT_DIALECT = DuckDBDialect;
42
56
  const DEFAULT_PARSER_DIALECT = "DuckDB";
@@ -64,12 +78,15 @@ export class SQLLanguageAdapter
64
78
  {
65
79
  readonly type = "sql";
66
80
  sqlLinterEnabled: boolean;
81
+ sqlModeEnabled: boolean;
67
82
 
68
83
  constructor() {
69
84
  try {
70
85
  this.sqlLinterEnabled = getFeatureFlag("sql_linter");
86
+ this.sqlModeEnabled = getFeatureFlag("sql_mode");
71
87
  } catch {
72
88
  this.sqlLinterEnabled = false;
89
+ this.sqlModeEnabled = false;
73
90
  }
74
91
  }
75
92
 
@@ -230,7 +247,7 @@ export class SQLLanguageAdapter
230
247
 
231
248
  if (this.sqlLinterEnabled) {
232
249
  const theme = store.get(resolvedThemeAtom);
233
- const parser = new NodeSqlParser({
250
+ const parser = new CustomSqlParser({
234
251
  getParserOptions: (state: EditorState) => {
235
252
  return {
236
253
  database: guessParserDialect(state) ?? DEFAULT_PARSER_DIALECT,
@@ -262,13 +279,103 @@ export class SQLLanguageAdapter
262
279
  theme: defaultSqlHoverTheme(theme),
263
280
  },
264
281
  }),
282
+ EditorView.updateListener.of((update) => {
283
+ if (update.focusChanged) {
284
+ parser.setFocusState(update.view.hasFocus);
285
+ }
286
+ }),
265
287
  );
266
288
  }
267
289
 
290
+ if (this.sqlModeEnabled) {
291
+ extensions.push(sqlValidationExtension());
292
+ }
293
+
268
294
  return extensions;
269
295
  }
270
296
  }
271
297
 
298
+ class CustomSqlParser extends NodeSqlParser {
299
+ private validationTimeout: number | null = null;
300
+ private readonly VALIDATION_DELAY_MS = 300; // Wait 300ms after user stops typing
301
+ private isFocused = false; // Only validate if the editor is focused
302
+
303
+ setFocusState(focused: boolean) {
304
+ this.isFocused = focused;
305
+ }
306
+
307
+ private async validateWithDelay(
308
+ sql: string,
309
+ engine: string,
310
+ dialect: ParserDialects | null,
311
+ ): Promise<SqlParseError[]> {
312
+ // Clear any existing delay call
313
+ if (this.validationTimeout) {
314
+ window.clearTimeout(this.validationTimeout);
315
+ }
316
+
317
+ // Set up a new request to be called after the delay
318
+ return new Promise((resolve) => {
319
+ this.validationTimeout = window.setTimeout(async () => {
320
+ // Only validate if the editor is still focused
321
+ if (!this.isFocused) {
322
+ resolve([]);
323
+ return;
324
+ }
325
+
326
+ try {
327
+ const sqlMode = getSQLMode();
328
+ const result = await validateSQL(sql, engine, dialect, sqlMode);
329
+ if (result.error) {
330
+ Logger.error("Failed to validate SQL", { error: result.error });
331
+ resolve([]);
332
+ return;
333
+ }
334
+ resolve(result.parse_result?.errors ?? []);
335
+ } catch (error) {
336
+ Logger.error("Failed to validate SQL", { error });
337
+ resolve([]);
338
+ }
339
+ }, this.VALIDATION_DELAY_MS);
340
+ });
341
+ }
342
+
343
+ override async validateSql(
344
+ sql: string,
345
+ opts: { state: EditorState },
346
+ ): Promise<SqlParseError[]> {
347
+ const metadata = getSQLMetadata(opts.state);
348
+
349
+ // Only validate if the editor is focused
350
+ if (!this.isFocused) {
351
+ return [];
352
+ }
353
+
354
+ // Only perform custom validation for DuckDB
355
+ if (!INTERNAL_SQL_ENGINES.has(metadata.engine)) {
356
+ return super.validateSql(sql, opts);
357
+ }
358
+
359
+ const dialect = guessParserDialect(opts.state);
360
+ return this.validateWithDelay(sql, metadata.engine, dialect);
361
+ }
362
+
363
+ override async parse(
364
+ sql: string,
365
+ opts: { state: EditorState },
366
+ ): Promise<NodeSqlParserResult> {
367
+ const metadata = getSQLMetadata(opts.state);
368
+ const engine = metadata.engine;
369
+
370
+ // For now, always return success for DuckDB
371
+ if (engine === DUCKDB_ENGINE) {
372
+ return { success: true, errors: [] };
373
+ }
374
+
375
+ return super.parse(sql, opts);
376
+ }
377
+ }
378
+
272
379
  /**
273
380
  * Update the SQL dialect in the editor view.
274
381
  */
@@ -315,9 +422,14 @@ function getSchema(view: EditorView): SQLNamespace {
315
422
  function guessParserDialect(state: EditorState): ParserDialects | null {
316
423
  const metadata = getSQLMetadata(state);
317
424
  const connectionName = metadata.engine;
425
+ return connectionNameToParserDialect(connectionName);
426
+ }
427
+
428
+ function connectionNameToParserDialect(
429
+ connectionName: ConnectionName,
430
+ ): ParserDialects | null {
318
431
  const dialect =
319
432
  SCHEMA_CACHE.getInternalDialect(connectionName)?.toLowerCase();
320
-
321
433
  switch (dialect) {
322
434
  case "postgresql":
323
435
  case "postgres":
@@ -543,3 +655,105 @@ function safeDedent(code: string): string {
543
655
  return code;
544
656
  }
545
657
  }
658
+
659
+ const SQL_VALIDATION_DEBOUNCE_MS = 300;
660
+
661
+ /**
662
+ * Custom extension to run SQL queries in EXPLAIN mode on keypress.
663
+ */
664
+ function sqlValidationExtension(): Extension {
665
+ let debounceTimeout: number | undefined;
666
+ let lastValidationRequest: string | null = null;
667
+
668
+ return EditorView.updateListener.of((update) => {
669
+ // Only run validation if the document has changed
670
+ if (!update.docChanged) {
671
+ return;
672
+ }
673
+
674
+ // Only run validation if the SQL mode is set to validate
675
+ const sqlMode = getSQLMode();
676
+ if (sqlMode !== "validate") {
677
+ return;
678
+ }
679
+
680
+ const metadata = getSQLMetadata(update.state);
681
+ const connectionName = metadata.engine;
682
+
683
+ // Currently only DuckDB is supported
684
+ if (!INTERNAL_SQL_ENGINES.has(connectionName)) {
685
+ return;
686
+ }
687
+
688
+ const doc = update.state.doc;
689
+ const sqlContent = doc.toString();
690
+
691
+ // Clear existing timeout
692
+ if (debounceTimeout) {
693
+ window.clearTimeout(debounceTimeout);
694
+ }
695
+
696
+ // Debounce the validation call
697
+ debounceTimeout = window.setTimeout(async () => {
698
+ // Skip if content hasn't changed since last validation
699
+ if (lastValidationRequest === sqlContent) {
700
+ return;
701
+ }
702
+
703
+ lastValidationRequest = sqlContent;
704
+ const cellId = update.view.state.facet(cellIdState);
705
+
706
+ if (sqlContent === "") {
707
+ clearSqlValidationError(cellId);
708
+ return;
709
+ }
710
+
711
+ try {
712
+ const dialect = connectionNameToParserDialect(connectionName);
713
+ const sqlMode = getSQLMode();
714
+ const result = await validateSQL(
715
+ sqlContent,
716
+ connectionName,
717
+ dialect,
718
+ sqlMode,
719
+ );
720
+ const validateResult = result.validate_result;
721
+
722
+ if (validateResult?.error_message) {
723
+ setSqlValidationError({
724
+ cellId,
725
+ errorMessage: validateResult.error_message,
726
+ dialect,
727
+ });
728
+ } else {
729
+ clearSqlValidationError(cellId);
730
+ }
731
+ } catch (error) {
732
+ Logger.error("Failed to validate SQL", { error });
733
+ }
734
+ }, SQL_VALIDATION_DEBOUNCE_MS);
735
+ });
736
+ }
737
+
738
+ /**
739
+ * Determine if we should only parse or validate an SQL query.
740
+ * The endpoint is cached, so we should use the same mode for all validation requests.
741
+ */
742
+ async function validateSQL(
743
+ sql: string,
744
+ engine: string,
745
+ dialect: ParserDialects | null,
746
+ sqlMode: SQLMode,
747
+ ): Promise<ValidateSQLResult> {
748
+ const result = await ValidateSQL.request({
749
+ onlyParse: sqlMode === "default",
750
+ engine,
751
+ dialect,
752
+ query: sql,
753
+ });
754
+
755
+ if (result.error) {
756
+ throw new Error(result.error);
757
+ }
758
+ return result;
759
+ }
@@ -18,8 +18,11 @@ import {
18
18
  } from "@marimo-team/codemirror-sql/dialects";
19
19
  import type { DataSourceConnection } from "@/core/kernel/messages";
20
20
 
21
+ /**
22
+ * Guess the CodeMirror SQL dialect from the backend connection dialect.
23
+ */
21
24
  export function guessDialect(
22
- connection: DataSourceConnection,
25
+ connection: Pick<DataSourceConnection, "dialect">,
23
26
  ): SQLDialect | undefined {
24
27
  switch (connection.dialect) {
25
28
  case "postgresql":
@@ -5,7 +5,8 @@ import { Button } from "@/components/ui/button";
5
5
  import { Checkbox } from "@/components/ui/checkbox";
6
6
  import { Tooltip, TooltipProvider } from "@/components/ui/tooltip";
7
7
  import { normalizeName } from "@/core/cells/names";
8
- import type { ConnectionName } from "@/core/datasets/engines";
8
+ import { getFeatureFlag } from "@/core/config/feature-flag";
9
+ import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
9
10
  import { useAutoGrowInputProps } from "@/hooks/useAutoGrowInputProps";
10
11
  import { formatSQL } from "../../format";
11
12
  import { languageAdapterState } from "../extension";
@@ -22,7 +23,7 @@ import {
22
23
  import type { LanguageMetadataOf } from "../types";
23
24
  import type { QuotePrefixKind } from "../utils/quotes";
24
25
  import { getQuotePrefix, MarkdownQuotePrefixTooltip } from "./markdown";
25
- import { SQLEngineSelect } from "./sql";
26
+ import { SQLEngineSelect, SQLModeSelect } from "./sql";
26
27
 
27
28
  const Divider = () => <div className="h-4 border-r border-border" />;
28
29
 
@@ -70,6 +71,8 @@ export const LanguagePanelComponent: React.FC<{
70
71
  updateSQLDialectFromConnection(view, engine);
71
72
  };
72
73
 
74
+ const sqlModeEnabled = getFeatureFlag("sql_mode");
75
+
73
76
  actions = (
74
77
  <div className="flex flex-1 gap-2 items-center">
75
78
  <label className="flex gap-2 items-center">
@@ -95,6 +98,9 @@ export const LanguagePanelComponent: React.FC<{
95
98
  onChange={switchEngine}
96
99
  />
97
100
  <div className="flex items-center gap-2 ml-auto">
101
+ {sqlModeEnabled && metadata.engine === DUCKDB_ENGINE && (
102
+ <SQLModeSelect />
103
+ )}
98
104
  <Tooltip content="Format SQL">
99
105
  <Button
100
106
  variant="text"
@@ -1,9 +1,16 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
+ import type { SelectTriggerProps } from "@radix-ui/react-select";
3
4
  import { useAtomValue } from "jotai";
4
- import { AlertCircle, CircleHelpIcon } from "lucide-react";
5
+ import {
6
+ AlertCircle,
7
+ CircleHelpIcon,
8
+ DatabaseBackup,
9
+ SearchCheck,
10
+ } from "lucide-react";
5
11
  import { transformDisplayName } from "@/components/databases/display";
6
12
  import { DatabaseLogo } from "@/components/databases/icon";
13
+ import { Button } from "@/components/ui/button";
7
14
  import {
8
15
  Select,
9
16
  SelectContent,
@@ -14,6 +21,7 @@ import {
14
21
  SelectTrigger,
15
22
  SelectValue,
16
23
  } from "@/components/ui/select";
24
+ import { Tooltip } from "@/components/ui/tooltip";
17
25
  import {
18
26
  dataConnectionsMapAtom,
19
27
  setLatestEngineSelected,
@@ -24,6 +32,8 @@ import {
24
32
  } from "@/core/datasets/engines";
25
33
  import type { DataSourceConnection } from "@/core/kernel/messages";
26
34
  import { useNonce } from "@/hooks/useNonce";
35
+ import { clearAllSqlValidationErrors } from "../languages/sql/banner-validation-errors";
36
+ import { type SQLMode, useSQLMode } from "../languages/sql/sql-mode";
27
37
 
28
38
  interface SelectProps {
29
39
  selectedEngine: ConnectionName;
@@ -77,7 +87,7 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
77
87
  <SelectItem key={connection.name} value={connection.name}>
78
88
  <div className="flex items-center gap-1">
79
89
  <DatabaseLogo className="h-3 w-3" name={connection.dialect} />
80
- <span className="truncate">
90
+ <span className="truncate ml-0.5">
81
91
  {transformDisplayName(connection.display_name)}
82
92
  </span>
83
93
  </div>
@@ -88,9 +98,9 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
88
98
  return (
89
99
  <div className="flex flex-row gap-1 items-center">
90
100
  <Select value={selectedEngine} onValueChange={handleSelectEngine}>
91
- <SelectTrigger className="text-xs border-border shadow-none! ring-0! h-4.5 px-1.5">
101
+ <SQLSelectTrigger>
92
102
  <SelectValue placeholder="Select an engine" />
93
- </SelectTrigger>
103
+ </SQLSelectTrigger>
94
104
  <SelectContent>
95
105
  <SelectGroup>
96
106
  <SelectLabel>Database connections</SelectLabel>
@@ -130,3 +140,75 @@ export const SQLEngineSelect: React.FC<SelectProps> = ({
130
140
  const HELP_KEY = "__help__";
131
141
  const HELP_URL =
132
142
  "http://docs.marimo.io/guides/working_with_data/sql/#connecting-to-a-custom-database";
143
+
144
+ export const SQLModeSelect: React.FC = () => {
145
+ const { sqlMode, setSQLMode } = useSQLMode();
146
+
147
+ const handleToggleMode = () => {
148
+ const nextMode = sqlMode === "validate" ? "default" : "validate";
149
+ if (nextMode === "default") {
150
+ clearAllSqlValidationErrors();
151
+ }
152
+ setSQLMode(nextMode);
153
+ };
154
+
155
+ const getModeIcon = (mode: SQLMode) => {
156
+ return mode === "validate" ? (
157
+ <SearchCheck className="h-3 w-3" />
158
+ ) : (
159
+ <DatabaseBackup className="h-3 w-3" />
160
+ );
161
+ };
162
+
163
+ const getTooltipContent = (mode: SQLMode) => {
164
+ return mode === "validate" ? (
165
+ <div className="text-xs">
166
+ <div className="font-semibold mb-1 flex flex-row items-center gap-1">
167
+ <SearchCheck className="h-3 w-3" />
168
+ Validate Mode
169
+ </div>
170
+ <p>Queries are validated as you write them</p>
171
+ </div>
172
+ ) : (
173
+ <div className="text-xs">
174
+ <div className="font-semibold mb-1 flex flex-row items-center gap-1">
175
+ <DatabaseBackup className="h-3 w-3" />
176
+ Default Mode
177
+ </div>
178
+ <p>Standard editing</p>
179
+ </div>
180
+ );
181
+ };
182
+
183
+ return (
184
+ <div className="flex flex-row gap-1 items-center">
185
+ <Tooltip delayDuration={300} content={getTooltipContent(sqlMode)}>
186
+ <Button
187
+ variant="ghost"
188
+ size="sm"
189
+ onClick={handleToggleMode}
190
+ className="h-5 px-1.5 text-xs border-border shadow-none hover:bg-accent"
191
+ >
192
+ {getModeIcon(sqlMode)}
193
+ <span className="ml-1">
194
+ {sqlMode === "validate" ? "Validate" : "Default"}
195
+ </span>
196
+ </Button>
197
+ </Tooltip>
198
+ </div>
199
+ );
200
+ };
201
+
202
+ const SQLSelectTrigger: React.FC<SelectTriggerProps> = ({
203
+ children,
204
+ ...props
205
+ }) => {
206
+ return (
207
+ <SelectTrigger
208
+ className="text-xs border-border shadow-none! ring-0! h-5 px-1.5 hover:bg-accent transition-colors"
209
+ {...props}
210
+ >
211
+ {children}
212
+ </SelectTrigger>
213
+ );
214
+ };
@@ -10,7 +10,7 @@ export function parseArgsKwargs(
10
10
  code: string,
11
11
  ): {
12
12
  args: SyntaxNode[];
13
- kwargs: Array<{ key: string; value: string }>;
13
+ kwargs: { key: string; value: string }[];
14
14
  } {
15
15
  // Check we are in an ArgList
16
16
  const name = argCursor.name;
@@ -54,8 +54,8 @@ function parseArgs(argCursor: TreeCursor): SyntaxNode[] {
54
54
  function parseKwargs(
55
55
  argCursor: TreeCursor,
56
56
  code: string,
57
- ): Array<{ key: string; value: string }> {
58
- const kwargs: Array<{ key: string; value: string }> = [];
57
+ ): { key: string; value: string }[] {
58
+ const kwargs: { key: string; value: string }[] = [];
59
59
  let name = argCursor.name;
60
60
 
61
61
  do {
@@ -115,7 +115,7 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
115
115
 
116
116
  async textDocumentCodeAction(
117
117
  params: LSP.CodeActionParams,
118
- ): Promise<Array<LSP.Command | LSP.CodeAction> | null> {
118
+ ): Promise<(LSP.Command | LSP.CodeAction)[] | null> {
119
119
  const client = this.firstWithCapability("codeActionProvider");
120
120
  if (client) {
121
121
  return client.textDocumentCodeAction(params);
@@ -206,9 +206,9 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
206
206
  }
207
207
 
208
208
  function mergeCompletions(
209
- results: Array<
210
- PromiseSettledResult<LSP.CompletionList | LSP.CompletionItem[] | null>
211
- >,
209
+ results: PromiseSettledResult<
210
+ LSP.CompletionList | LSP.CompletionItem[] | null
211
+ >[],
212
212
  ): LSP.CompletionList {
213
213
  const completions: LSP.CompletionItem[] = [];
214
214
  let isIncomplete = false;
@@ -22,10 +22,10 @@ export interface NotebookLens {
22
22
  reversePosition: (position: LSP.Position, cellId: CellId) => LSP.Position;
23
23
 
24
24
  /** Clip a range to the given cell */
25
- getEditsForNewText: (newText: string) => Array<{
25
+ getEditsForNewText: (newText: string) => {
26
26
  cellId: CellId;
27
27
  text: string;
28
- }>;
28
+ }[];
29
29
 
30
30
  /** Check if a range falls within the given cell */
31
31
  isInRange: (range: LSP.Range, cellId: CellId) => boolean;
@@ -84,10 +84,10 @@ export function createNotebookLens(
84
84
  throw new Error("Cannot apply rename when there are new lines");
85
85
  }
86
86
 
87
- const edits: Array<{
87
+ const edits: {
88
88
  cellId: CellId;
89
89
  text: string;
90
- }> = [];
90
+ }[] = [];
91
91
 
92
92
  for (const [cellId, code] of Objects.entries(codes)) {
93
93
  if (!cellLineOffsets.has(cellId)) {
@@ -300,7 +300,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
300
300
 
301
301
  textDocumentCodeAction(
302
302
  params: LSP.CodeActionParams,
303
- ): Promise<Array<LSP.Command | LSP.CodeAction> | null> {
303
+ ): Promise<(LSP.Command | LSP.CodeAction)[] | null> {
304
304
  const disabledCodeAction = true;
305
305
  if (disabledCodeAction) {
306
306
  return Promise.resolve(null);
@@ -49,7 +49,7 @@ export function isClientWithNotify(
49
49
  export function isClientWithPlugins(
50
50
  client: ILanguageServerClient,
51
51
  ): client is ILanguageServerClient & {
52
- plugins: Array<{ documentUri: string; view?: EditorView }>;
52
+ plugins: { documentUri: string; view?: EditorView }[];
53
53
  } {
54
54
  return "plugins" in client;
55
55
  }
@@ -133,7 +133,7 @@ const latexSymbolCompletionSource: CompletionSource = (context) => {
133
133
 
134
134
  // Common LaTeX symbols with their UTF-8 equivalents
135
135
  const getLatexSymbolList = once((): Completion[] => {
136
- const symbols: Array<[string, string, string]> = [
136
+ const symbols: [string, string, string][] = [
137
137
  // Greek letters
138
138
  ["alpha", "α", "Greek small letter alpha"],
139
139
  ["beta", "β", "Greek small letter beta"],
@@ -67,7 +67,7 @@ export function findReactiveVariables(options: {
67
67
  // Maps to track variable declarations and scopes
68
68
  const allDeclarations = new Map<number, Set<string>>(); // scope position -> variable names
69
69
  const scopeTypes = new Map<number, string>(); // scope position -> scope type (e.g., "ClassDefinition")
70
- const classLevelDeclarations = new Map<number, Array<[string, number]>>(); // class scope -> [varName, position] pairs
70
+ const classLevelDeclarations = new Map<number, [string, number][]>(); // class scope -> [varName, position] pairs
71
71
 
72
72
  // Class-level variables require special handling because they're evaluated sequentially
73
73
  // A variable is only available after its assignment statement completes
@@ -555,7 +555,7 @@ function extractAssignmentTargets(
555
555
  state: EditorState;
556
556
  allDeclarations: Map<number, Set<string>>;
557
557
  scopeTypes: Map<number, string>;
558
- classLevelDeclarations: Map<number, Array<[string, number]>>;
558
+ classLevelDeclarations: Map<number, [string, number][]>;
559
559
  assignmentPosition: number;
560
560
  },
561
561
  ) {
@@ -302,7 +302,7 @@ const parseAwarenessUpdate = (
302
302
  removed: PeerID[];
303
303
  },
304
304
  scopeId: ScopeId,
305
- ): Array<StateEffect<CursorEffect>> => {
305
+ ): StateEffect<CursorEffect>[] => {
306
306
  const effects = [];
307
307
  const { updated, added } = arg;
308
308
  for (const update of [...updated, ...added]) {
@@ -163,6 +163,7 @@ export const UserConfigSchema = z
163
163
  anthropic: AiConfigSchema.optional(),
164
164
  google: AiConfigSchema.optional(),
165
165
  ollama: AiConfigSchema.optional(),
166
+ openrouter: AiConfigSchema.optional(),
166
167
  open_ai_compatible: AiConfigSchema.optional(),
167
168
  azure: AiConfigSchema.optional(),
168
169
  bedrock: z
@@ -12,8 +12,10 @@ export interface ExperimentalFeatures {
12
12
  rtc_v2: boolean;
13
13
  performant_table_charts: boolean;
14
14
  mcp_docs: boolean;
15
+ chat_modes: boolean;
15
16
  sql_linter: boolean;
16
17
  external_agents: boolean;
18
+ sql_mode: boolean;
17
19
  // Add new feature flags here
18
20
  }
19
21
 
@@ -24,15 +26,17 @@ const defaultValues: ExperimentalFeatures = {
24
26
  rtc_v2: false,
25
27
  performant_table_charts: false,
26
28
  mcp_docs: false,
27
- sql_linter: false,
29
+ chat_modes: false,
30
+ sql_linter: true,
28
31
  external_agents: import.meta.env.DEV,
32
+ sql_mode: false,
29
33
  };
30
34
 
31
35
  export function getFeatureFlag<T extends keyof ExperimentalFeatures>(
32
36
  feature: T,
33
37
  ): ExperimentalFeatures[T] {
34
38
  return (
35
- (getResolvedMarimoConfig().experimental?.[
39
+ (getResolvedMarimoConfig()?.experimental?.[
36
40
  feature
37
41
  ] as ExperimentalFeatures[T]) ?? defaultValues[feature]
38
42
  );