@sqlrooms/cells 0.29.0-rc.1 → 0.29.0-rc.10

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 (144) hide show
  1. package/LICENSE.md +2 -1
  2. package/README.md +8 -8
  3. package/dist/cellsSlice.d.ts.map +1 -1
  4. package/dist/cellsSlice.js +305 -264
  5. package/dist/cellsSlice.js.map +1 -1
  6. package/dist/components/AggregationSelector.d.ts +8 -0
  7. package/dist/components/AggregationSelector.d.ts.map +1 -0
  8. package/dist/components/AggregationSelector.js +13 -0
  9. package/dist/components/AggregationSelector.js.map +1 -0
  10. package/dist/components/CellSourceSelector.d.ts +12 -0
  11. package/dist/components/CellSourceSelector.d.ts.map +1 -0
  12. package/dist/components/CellSourceSelector.js +34 -0
  13. package/dist/components/CellSourceSelector.js.map +1 -0
  14. package/dist/components/ChartTypeSelector.d.ts +8 -0
  15. package/dist/components/ChartTypeSelector.d.ts.map +1 -0
  16. package/dist/components/ChartTypeSelector.js +13 -0
  17. package/dist/components/ChartTypeSelector.js.map +1 -0
  18. package/dist/components/CollapsibleSectionButton.d.ts +10 -0
  19. package/dist/components/CollapsibleSectionButton.d.ts.map +1 -0
  20. package/dist/components/CollapsibleSectionButton.js +10 -0
  21. package/dist/components/CollapsibleSectionButton.js.map +1 -0
  22. package/dist/components/ColorSelector.d.ts +24 -0
  23. package/dist/components/ColorSelector.d.ts.map +1 -0
  24. package/dist/components/ColorSelector.js +17 -0
  25. package/dist/components/ColorSelector.js.map +1 -0
  26. package/dist/components/FieldSelector.d.ts +11 -0
  27. package/dist/components/FieldSelector.d.ts.map +1 -0
  28. package/dist/components/FieldSelector.js +11 -0
  29. package/dist/components/FieldSelector.js.map +1 -0
  30. package/dist/components/FieldTypeIcon.d.ts +8 -0
  31. package/dist/components/FieldTypeIcon.d.ts.map +1 -0
  32. package/dist/components/FieldTypeIcon.js +27 -0
  33. package/dist/components/FieldTypeIcon.js.map +1 -0
  34. package/dist/components/InputCellContent.d.ts.map +1 -1
  35. package/dist/components/InputCellContent.js +3 -3
  36. package/dist/components/InputCellContent.js.map +1 -1
  37. package/dist/components/SqlCellConnectionSelector.d.ts +9 -0
  38. package/dist/components/SqlCellConnectionSelector.d.ts.map +1 -0
  39. package/dist/components/SqlCellConnectionSelector.js +21 -0
  40. package/dist/components/SqlCellConnectionSelector.js.map +1 -0
  41. package/dist/components/SqlCellContent.d.ts.map +1 -1
  42. package/dist/components/SqlCellContent.js +31 -160
  43. package/dist/components/SqlCellContent.js.map +1 -1
  44. package/dist/components/SqlCellDependentsMenu.d.ts +11 -0
  45. package/dist/components/SqlCellDependentsMenu.d.ts.map +1 -0
  46. package/dist/components/SqlCellDependentsMenu.js +62 -0
  47. package/dist/components/SqlCellDependentsMenu.js.map +1 -0
  48. package/dist/components/SqlCellEditor.d.ts +14 -0
  49. package/dist/components/SqlCellEditor.d.ts.map +1 -0
  50. package/dist/components/SqlCellEditor.js +17 -0
  51. package/dist/components/SqlCellEditor.js.map +1 -0
  52. package/dist/components/SqlCellResultNameEditor.d.ts +8 -0
  53. package/dist/components/SqlCellResultNameEditor.d.ts.map +1 -0
  54. package/dist/components/SqlCellResultNameEditor.js +38 -0
  55. package/dist/components/SqlCellResultNameEditor.js.map +1 -0
  56. package/dist/components/SqlCellResults.d.ts +17 -0
  57. package/dist/components/SqlCellResults.d.ts.map +1 -0
  58. package/dist/components/SqlCellResults.js +44 -0
  59. package/dist/components/SqlCellResults.js.map +1 -0
  60. package/dist/components/SqlCellRunButton.d.ts +5 -6
  61. package/dist/components/SqlCellRunButton.d.ts.map +1 -1
  62. package/dist/components/SqlCellRunButton.js +11 -7
  63. package/dist/components/SqlCellRunButton.js.map +1 -1
  64. package/dist/components/SqlQueryPreview.d.ts +9 -0
  65. package/dist/components/SqlQueryPreview.d.ts.map +1 -0
  66. package/dist/components/SqlQueryPreview.js +14 -0
  67. package/dist/components/SqlQueryPreview.js.map +1 -0
  68. package/dist/components/TextCellContent.d.ts.map +1 -1
  69. package/dist/components/TextCellContent.js +24 -7
  70. package/dist/components/TextCellContent.js.map +1 -1
  71. package/dist/components/VegaCellContent.d.ts +0 -1
  72. package/dist/components/VegaCellContent.d.ts.map +1 -1
  73. package/dist/components/VegaCellContent.js +28 -49
  74. package/dist/components/VegaCellContent.js.map +1 -1
  75. package/dist/components/VegaCellHeader.d.ts +8 -0
  76. package/dist/components/VegaCellHeader.d.ts.map +1 -0
  77. package/dist/components/VegaCellHeader.js +30 -0
  78. package/dist/components/VegaCellHeader.js.map +1 -0
  79. package/dist/components/VegaConfigPanel.d.ts.map +1 -1
  80. package/dist/components/VegaConfigPanel.js +23 -64
  81. package/dist/components/VegaConfigPanel.js.map +1 -1
  82. package/dist/dagUtils.d.ts +10 -9
  83. package/dist/dagUtils.d.ts.map +1 -1
  84. package/dist/dagUtils.js +76 -50
  85. package/dist/dagUtils.js.map +1 -1
  86. package/dist/defaultCellRegistry.d.ts.map +1 -1
  87. package/dist/defaultCellRegistry.js +82 -39
  88. package/dist/defaultCellRegistry.js.map +1 -1
  89. package/dist/execution.d.ts.map +1 -1
  90. package/dist/execution.js +27 -20
  91. package/dist/execution.js.map +1 -1
  92. package/dist/helpers.d.ts +21 -28
  93. package/dist/helpers.d.ts.map +1 -1
  94. package/dist/helpers.js +77 -90
  95. package/dist/helpers.js.map +1 -1
  96. package/dist/hooks/useVegaCellDataSource.d.ts +18 -0
  97. package/dist/hooks/useVegaCellDataSource.d.ts.map +1 -0
  98. package/dist/hooks/useVegaCellDataSource.js +40 -0
  99. package/dist/hooks/useVegaCellDataSource.js.map +1 -0
  100. package/dist/hooks/useVegaCellQuery.d.ts +12 -0
  101. package/dist/hooks/useVegaCellQuery.d.ts.map +1 -0
  102. package/dist/hooks/useVegaCellQuery.js +12 -0
  103. package/dist/hooks/useVegaCellQuery.js.map +1 -0
  104. package/dist/index.d.ts +2 -3
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +2 -3
  107. package/dist/index.js.map +1 -1
  108. package/dist/resultRelationPolicy.d.ts +2 -2
  109. package/dist/resultRelationPolicy.d.ts.map +1 -1
  110. package/dist/resultRelationPolicy.js +9 -1
  111. package/dist/resultRelationPolicy.js.map +1 -1
  112. package/dist/sqlHelpers.d.ts +8 -8
  113. package/dist/sqlHelpers.d.ts.map +1 -1
  114. package/dist/sqlHelpers.js +16 -12
  115. package/dist/sqlHelpers.js.map +1 -1
  116. package/dist/types.d.ts +113 -70
  117. package/dist/types.d.ts.map +1 -1
  118. package/dist/types.js +22 -13
  119. package/dist/types.js.map +1 -1
  120. package/dist/useValidateResultName.d.ts +34 -0
  121. package/dist/useValidateResultName.d.ts.map +1 -0
  122. package/dist/useValidateResultName.js +111 -0
  123. package/dist/useValidateResultName.js.map +1 -0
  124. package/dist/utils.d.ts +10 -2
  125. package/dist/utils.d.ts.map +1 -1
  126. package/dist/utils.js +20 -4
  127. package/dist/utils.js.map +1 -1
  128. package/dist/vegaSelectionUtils.d.ts +14 -0
  129. package/dist/vegaSelectionUtils.d.ts.map +1 -0
  130. package/dist/vegaSelectionUtils.js +97 -0
  131. package/dist/vegaSelectionUtils.js.map +1 -0
  132. package/dist/vegaSpecBuilder.d.ts +34 -0
  133. package/dist/vegaSpecBuilder.d.ts.map +1 -0
  134. package/dist/vegaSpecBuilder.js +90 -0
  135. package/dist/vegaSpecBuilder.js.map +1 -0
  136. package/package.json +20 -21
  137. package/dist/components/DeleteSheetModal.d.ts +0 -9
  138. package/dist/components/DeleteSheetModal.d.ts.map +0 -1
  139. package/dist/components/DeleteSheetModal.js +0 -6
  140. package/dist/components/DeleteSheetModal.js.map +0 -1
  141. package/dist/components/SheetsTabBar.d.ts +0 -6
  142. package/dist/components/SheetsTabBar.d.ts.map +0 -1
  143. package/dist/components/SheetsTabBar.js +0 -57
  144. package/dist/components/SheetsTabBar.js.map +0 -1
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAKtB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;AAEnC,uBAAuB;AACvB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAGjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CAC9B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;CAC7B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CAC9B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IACrD,SAAS;IACT,WAAW;IACX,aAAa;CACd,CAAC,CAAC;AAGH,eAAe;AACf,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACrC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,8CAA8C;IACjF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAGH,gBAAgB;AAChB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CAC7B,CAAC,CAAC;AAGH,gBAAgB;AAChB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,0EAA0E;IACxG,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,uCAAuC;IACnE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAGH,sBAAsB;AACtB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAClC,KAAK,EAAE,UAAU;CAClB,CAAC,CAAC;AAGH,wBAAwB;AACxB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;CACpC,CAAC,CAAC;AAMH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACtB,IAAI,EAAE,WAAW;CAClB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACvB,IAAI,EAAE,YAAY;CACnB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACvB,IAAI,EAAE,YAAY;CACnB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxB,IAAI,EAAE,aAAa;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC;AACrC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AAEzC,qBAAqB;AACrB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;CACpC,CAAC,CAAC;AAuDH,2BAA2B;AAC3B,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AAG/D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGzD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS;IAC7B,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE;CAC1B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACnE,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACjE,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC/D,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,mCAAmC;IAC7E,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,eAAe;IACjD,UAAU,EAAE,eAAe,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC;AAGH,kBAAkB;AAClB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACtB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACjD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;CACzB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;AAmCpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/C,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAoFH,MAAM,UAAU,SAAS,CAAC,IAAU;IAClC,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;AAC/B,CAAC","sourcesContent":["import type {DbSliceState} from '@sqlrooms/db';\nimport type {BaseRoomStoreState} from '@sqlrooms/room-store';\nimport type * as arrow from 'apache-arrow';\nimport type React from 'react';\nimport {z} from 'zod';\n\n/** Cell types */\nexport type BuiltInCellType = 'sql' | 'text' | 'vega' | 'input';\nexport type CellType = BuiltInCellType | (string & {});\nexport const CellType = z.string();\n\n/** Input Cell types */\nexport const InputTypes = z.enum(['text', 'slider', 'dropdown']);\nexport type InputTypes = z.infer<typeof InputTypes>;\n\nexport const InputText = z.object({\n kind: z.literal(InputTypes.enum.text),\n varName: z.string(),\n value: z.string().default(''),\n});\nexport type InputText = z.infer<typeof InputText>;\n\nexport const InputSlider = z.object({\n kind: z.literal(InputTypes.enum.slider),\n varName: z.string(),\n min: z.number().default(0),\n max: z.number().default(100),\n step: z.number().default(1),\n value: z.number().default(0),\n});\nexport type InputSlider = z.infer<typeof InputSlider>;\n\nexport const InputDropdown = z.object({\n kind: z.literal(InputTypes.enum.dropdown),\n varName: z.string(),\n options: z.array(z.string()).default([]),\n value: z.string().default(''),\n});\nexport type InputDropdown = z.infer<typeof InputDropdown>;\n\nexport const InputUnion = z.discriminatedUnion('kind', [\n InputText,\n InputSlider,\n InputDropdown,\n]);\nexport type InputUnion = z.infer<typeof InputUnion>;\n\n/** SQL Cell */\nexport const SqlCellData = z.object({\n title: z.string().default('Untitled'),\n sql: z.string().default(''),\n resultName: z.string().optional(), // SQL-friendly identifier for the result view\n connectorId: z.string().optional(),\n});\nexport type SqlCellData = z.infer<typeof SqlCellData>;\n\n/** Text Cell */\nexport const TextCellData = z.object({\n title: z.string().default('Text'),\n text: z.string().default(''),\n});\nexport type TextCellData = z.infer<typeof TextCellData>;\n\n/** Vega Cell */\nexport const VegaCellData = z.object({\n title: z.string().default('Chart'),\n sqlId: z.string().optional(), // In notebook, it links to another cell. In canvas, it might be the same.\n sql: z.string().optional(), // In canvas, it often has its own SQL.\n vegaSpec: z.any().optional(),\n});\nexport type VegaCellData = z.infer<typeof VegaCellData>;\n\n/** Input Cell Data */\nexport const InputCellData = z.object({\n title: z.string().default('Input'),\n input: InputUnion,\n});\nexport type InputCellData = z.infer<typeof InputCellData>;\n\n/** Unified Cell Data */\nexport const CellData = z.object({\n type: CellType,\n data: z.record(z.string(), z.any()),\n});\nexport type CellData = {\n type: CellType;\n data: Record<string, any>;\n};\n\nexport const SqlCell = z.object({\n id: z.string(),\n type: z.literal('sql'),\n data: SqlCellData,\n});\nexport type SqlCell = z.infer<typeof SqlCell>;\n\nexport const TextCell = z.object({\n id: z.string(),\n type: z.literal('text'),\n data: TextCellData,\n});\nexport type TextCell = z.infer<typeof TextCell>;\n\nexport const VegaCell = z.object({\n id: z.string(),\n type: z.literal('vega'),\n data: VegaCellData,\n});\nexport type VegaCell = z.infer<typeof VegaCell>;\n\nexport const InputCell = z.object({\n id: z.string(),\n type: z.literal('input'),\n data: InputCellData,\n});\nexport type InputCell = z.infer<typeof InputCell>;\nexport const SqlCellSchema = SqlCell;\nexport const TextCellSchema = TextCell;\nexport const VegaCellSchema = VegaCell;\nexport const InputCellSchema = InputCell;\n\n/** Canonical Cell */\nexport const Cell = z.object({\n id: z.string(),\n type: CellType,\n data: z.record(z.string(), z.any()),\n});\nexport type Cell = {\n id: string;\n type: CellType;\n data: Record<string, any>;\n};\n\n/** Unified Cell Registry */\nexport type CellContainerProps = {\n header?: React.ReactNode;\n content: React.ReactNode;\n footer?: React.ReactNode;\n};\n\n/** Type for SQL AST parsing function from DuckDB slice */\nexport type SqlSelectToJsonFn = (sql: string) => Promise<{\n error: boolean;\n error_type?: string;\n statements?: unknown[];\n}>;\n\nexport type CellRegistryItem<TCell extends Cell = Cell> = {\n type: string;\n title: string;\n createCell: (id: string) => TCell;\n renderCell: (props: {\n id: string;\n cell: TCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n }) => React.ReactElement;\n /** Find dependencies for DAG using AST-enabled async resolution. */\n findDependencies: (args: {\n cell: TCell;\n cells: Record<string, Cell>;\n sheetId: string;\n sqlSelectToJson: SqlSelectToJsonFn;\n }) => Promise<string[]>;\n /** Optional: custom execution logic (defaults to SQL execution for sql type) */\n runCell?: (args: {\n id: string;\n opts?: {cascade?: boolean; schemaName?: string};\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => Promise<void>;\n /** Optional: rename the result view when resultName changes */\n renameResult?: (args: {\n id: string;\n oldResultView: string;\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => Promise<void>;\n};\n\nexport type CellRegistry = Record<string, CellRegistryItem<any>>;\n\n/** Sheet and Edge types */\nexport const SheetType = z.enum(['notebook', 'canvas', 'app']);\nexport type SheetType = z.infer<typeof SheetType>;\n\nexport const EdgeKind = z.enum(['dependency', 'manual']);\nexport type EdgeKind = z.infer<typeof EdgeKind>;\n\nexport const Edge = z.object({\n id: z.string(),\n source: z.string(), // cellId\n target: z.string(), // cellId\n kind: EdgeKind.optional(),\n});\nexport type Edge = z.infer<typeof Edge>;\n\nexport const SheetGraphCache = z.object({\n dependencies: z.record(z.string(), z.array(z.string())).default({}),\n dependents: z.record(z.string(), z.array(z.string())).default({}),\n contentHashByCell: z.record(z.string(), z.string()).optional(),\n});\nexport type SheetGraphCache = z.infer<typeof SheetGraphCache>;\n\nexport const Sheet = z.object({\n id: z.string(),\n type: SheetType,\n title: z.string(),\n schemaName: z.string().optional(),\n cellIds: z.array(z.string()).default([]), // Which cells belong to this sheet\n edges: z.array(Edge).default([]), // Dependencies\n graphCache: SheetGraphCache.optional(),\n});\nexport type Sheet = z.infer<typeof Sheet>;\n\n/** Cell Status */\nexport const SqlCellStatus = z.object({\n type: z.literal('sql'),\n status: z.enum(['idle', 'running', 'success', 'cancel', 'error']),\n lastError: z.string().optional(),\n referencedTables: z.array(z.string()).default([]),\n resultName: z.string().optional(),\n resultView: z.string().optional(),\n resultRelationType: z.enum(['view', 'table']).optional(),\n lastRunTime: z.number().optional(),\n});\nexport type SqlCellStatus = z.infer<typeof SqlCellStatus>;\n\nexport const OtherCellStatus = z.object({\n type: z.literal('other'),\n});\nexport type OtherCellStatus = z.infer<typeof OtherCellStatus>;\n\nexport const CellStatus = z.union([SqlCellStatus, OtherCellStatus]);\nexport type CellStatus = z.infer<typeof CellStatus>;\n\n/** SQL execution results */\nexport type SqlRunResult = {\n resultName?: string;\n referencedTables?: string[];\n lastRunTime?: number;\n};\n\nexport type SqlRunCallbacks = {\n onStart?: () => void;\n onSuccess?: (result: SqlRunResult) => void;\n onError?: (message: string) => void;\n onFinally?: () => void;\n};\n\nexport type SqlRenderInput = {\n varName: string;\n value: string | number;\n};\n\nexport type SqlDependencyOptions = {\n inputTypes?: string[];\n sqlTypes?: string[];\n};\n\nexport type SqlCellRunStatus =\n | {\n state: 'idle' | 'running' | 'success' | 'cancel' | 'error';\n message?: string;\n resultName?: string;\n }\n | undefined;\n\nexport const CellsSliceConfig = z.object({\n data: z.record(z.string(), Cell).default({}),\n sheets: z.record(z.string(), Sheet).default({}),\n sheetOrder: z.array(z.string()).default([]),\n currentSheetId: z.string().optional(),\n});\nexport type CellsSliceConfig = z.infer<typeof CellsSliceConfig>;\n\nexport type CellsSliceOptions = {\n config?: Partial<CellsSliceConfig>;\n cellRegistry: CellRegistry;\n supportedSheetTypes?: SheetType[];\n};\n\n/** Data stored for a cell's query result */\nexport type CellResultData = {\n arrowTable: arrow.Table;\n totalRows: number;\n};\n\nexport type CellsSliceState = {\n cells: {\n config: CellsSliceConfig;\n status: Record<string, CellStatus>;\n activeAbortControllers: Record<string, AbortController>;\n cellRegistry: CellRegistry;\n supportedSheetTypes: SheetType[];\n /** Monotonic counter per cell, incremented when a new execution result arrives. Used to trigger pagination reset and re-render. */\n resultVersion: Record<string, number>;\n /** Monotonic counter per cell, incremented when a pagination/sorting fetch completes. Used to trigger re-render without resetting pagination. */\n pageVersion: Record<string, number>;\n\n // Cell CRUD\n addCell: (sheetId: string, cell: Cell, index?: number) => Promise<void>;\n removeCell: (id: string) => void;\n updateCell: (\n id: string,\n updater: (cell: Cell) => Cell,\n opts?: {cascade?: boolean},\n ) => Promise<void>;\n\n // Sheet CRUD\n addSheet: (title?: string, type?: SheetType) => string;\n removeSheet: (sheetId: string) => void;\n closeSheet: (sheetId: string) => void;\n openSheet: (sheetId: string) => void;\n setSheetOrder: (sheetOrder: string[]) => void;\n renameSheet: (sheetId: string, title: string) => void;\n setCurrentSheet: (sheetId: string) => void;\n\n // Edge management\n addEdge: (sheetId: string, edge: Omit<Edge, 'id'>) => void;\n removeEdge: (sheetId: string, edgeId: string) => void;\n updateEdgesFromSql: (sheetId: string, cellId: string) => Promise<void>;\n\n // Execution\n runCell: (\n id: string,\n opts?: {cascade?: boolean; schemaName?: string},\n ) => Promise<void>;\n cancelCell: (id: string) => void;\n invalidateCellStatus: (id: string) => void;\n\n // Cell result cache\n setCellResult: (id: string, data: CellResultData) => void;\n setCellResultPage: (id: string, data: CellResultData) => void;\n getCellResult: (id: string) => CellResultData | undefined;\n clearCellResult: (id: string) => void;\n fetchCellResultPage: (\n id: string,\n pagination: {pageIndex: number; pageSize: number},\n sorting?: {id: string; desc: boolean}[],\n ) => Promise<void>;\n\n // DAG methods\n getDownstream: (sheetId: string, sourceCellId: string) => string[];\n getRootCells: (sheetId: string) => string[];\n runAllCellsCascade: (sheetId: string) => Promise<void>;\n runDownstreamCascade: (\n sheetId: string,\n sourceCellId: string,\n ) => Promise<void>;\n };\n};\n\nexport type CellsRootState = BaseRoomStoreState &\n DbSliceState &\n CellsSliceState;\n\nexport function isSqlCell(cell: Cell): cell is SqlCell {\n return cell.type === 'sql';\n}\n\nexport function isTextCell(cell: Cell): cell is TextCell {\n return cell.type === 'text';\n}\n\nexport function isVegaCell(cell: Cell): cell is VegaCell {\n return cell.type === 'vega';\n}\n\nexport function isInputCell(cell: Cell): cell is InputCell {\n return cell.type === 'input';\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type {DbSliceState} from '@sqlrooms/db';\nimport type {BaseRoomStoreState, SliceFunctions} from '@sqlrooms/room-store';\nimport type * as arrow from 'apache-arrow';\nimport type React from 'react';\nimport {z} from 'zod';\n\n/** Cell types */\nexport type BuiltInCellType = 'sql' | 'text' | 'vega' | 'input';\nexport type CellType = BuiltInCellType | (string & {});\nexport const CellType = z.string();\n\n/** Input Cell types */\nexport const InputTypes = z.enum(['text', 'slider', 'dropdown']);\nexport type InputTypes = z.infer<typeof InputTypes>;\n\nexport const InputText = z.object({\n kind: z.literal(InputTypes.enum.text),\n varName: z.string(),\n value: z.string().default(''),\n});\nexport type InputText = z.infer<typeof InputText>;\n\nexport const InputSlider = z.object({\n kind: z.literal(InputTypes.enum.slider),\n varName: z.string(),\n min: z.number().default(0),\n max: z.number().default(100),\n step: z.number().default(1),\n value: z.number().default(0),\n});\nexport type InputSlider = z.infer<typeof InputSlider>;\n\nexport const InputDropdown = z.object({\n kind: z.literal(InputTypes.enum.dropdown),\n varName: z.string(),\n options: z.array(z.string()).default([]),\n value: z.string().default(''),\n});\nexport type InputDropdown = z.infer<typeof InputDropdown>;\n\nexport const InputUnion = z.discriminatedUnion('kind', [\n InputText,\n InputSlider,\n InputDropdown,\n]);\nexport type InputUnion = z.infer<typeof InputUnion>;\n\n/** SQL Cell */\nexport const SqlCellData = z.object({\n title: z.string().default('Untitled'),\n sql: z.string().default(''),\n resultName: z.string().optional(), // SQL-friendly identifier for the result view\n connectorId: z.string().optional(),\n});\nexport type SqlCellData = z.infer<typeof SqlCellData>;\n\n/** Text Cell */\nexport const TextCellData = z.object({\n title: z.string().default('Text'),\n text: z.string().default(''),\n});\nexport type TextCellData = z.infer<typeof TextCellData>;\n\n/** Field type category for cross-filter predicates */\nexport type BrushFieldType = 'numeric' | 'temporal' | 'string';\n\n/** Cross-filter configuration for Vega chart cells */\nexport const CrossFilterConfig = z.object({\n enabled: z.boolean().default(true),\n brushField: z.string().optional(),\n brushFieldType: z\n .enum(['numeric', 'temporal', 'string'])\n .optional() as z.ZodOptional<z.ZodType<BrushFieldType>>,\n});\nexport type CrossFilterConfig = z.infer<typeof CrossFilterConfig>;\n\n/** Vega Cell */\nexport const VegaCellData = z.object({\n title: z.string().default('Chart'),\n sqlId: z.string().optional(), // In notebook, it links to another cell. In canvas, it might be the same.\n tableRef: z.string().optional(), // Direct table reference, e.g. \"main.flights\"\n sql: z.string().optional(), // In canvas, it often has its own SQL.\n vegaSpec: z.any().optional(),\n crossFilter: CrossFilterConfig.default({enabled: true}),\n});\nexport type VegaCellData = z.infer<typeof VegaCellData>;\n\n/** Input Cell Data */\nexport const InputCellData = z.object({\n title: z.string().default('Input'),\n input: InputUnion,\n});\nexport type InputCellData = z.infer<typeof InputCellData>;\n\n/** Unified Cell Data */\nexport const CellData = z.object({\n type: CellType,\n data: z.record(z.string(), z.any()),\n});\nexport type CellData = {\n type: CellType;\n data: Record<string, any>;\n};\n\nexport const SqlCell = z.object({\n id: z.string(),\n type: z.literal('sql'),\n data: SqlCellData,\n});\nexport type SqlCell = z.infer<typeof SqlCell>;\n\nexport const TextCell = z.object({\n id: z.string(),\n type: z.literal('text'),\n data: TextCellData,\n});\nexport type TextCell = z.infer<typeof TextCell>;\n\nexport const VegaCell = z.object({\n id: z.string(),\n type: z.literal('vega'),\n data: VegaCellData,\n});\nexport type VegaCell = z.infer<typeof VegaCell>;\n\nexport const InputCell = z.object({\n id: z.string(),\n type: z.literal('input'),\n data: InputCellData,\n});\nexport type InputCell = z.infer<typeof InputCell>;\nexport const SqlCellSchema = SqlCell;\nexport const TextCellSchema = TextCell;\nexport const VegaCellSchema = VegaCell;\nexport const InputCellSchema = InputCell;\n\n/** Canonical Cell */\nexport const Cell = z.object({\n id: z.string(),\n type: CellType,\n data: z.record(z.string(), z.any()),\n});\nexport type Cell = {\n id: string;\n type: CellType;\n data: Record<string, any>;\n};\n\n/** Unified Cell Registry */\nexport type CellContainerProps = {\n header?: React.ReactNode;\n content: React.ReactNode;\n footer?: React.ReactNode;\n showHeader?: boolean;\n};\n\n/** Type for SQL AST parsing function from DuckDB slice */\nexport type SqlSelectToJsonFn = (sql: string) => Promise<{\n error: boolean;\n error_type?: string;\n statements?: unknown[];\n}>;\n\n/** Return type from findDependencies: cell IDs and optional table names. */\nexport type CellDependencies = {\n cellIds: string[];\n tableNames?: string[];\n};\n\nexport type CreateCellArgs = {\n id: string;\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n};\n\nexport type CellRegistryItem<TCell extends Cell = Cell> = {\n type: string;\n title: string;\n createCell: (args: CreateCellArgs) => TCell;\n renderCell: (props: {\n id: string;\n cell: TCell;\n renderContainer: (props: CellContainerProps) => React.ReactElement;\n }) => React.ReactElement;\n /** Find dependencies for DAG using AST-enabled async resolution. */\n findDependencies: (args: {\n cell: TCell;\n cells: Record<string, Cell>;\n artifactId: string;\n sqlSelectToJson: SqlSelectToJsonFn;\n }) => Promise<string[] | CellDependencies>;\n /** Optional: custom execution logic (defaults to SQL execution for sql type) */\n runCell?: (args: {\n id: string;\n opts?: {cascade?: boolean; schemaName?: string};\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => Promise<void>;\n /** Optional: rename the result view when resultName changes */\n renameResult?: (args: {\n id: string;\n oldResultView: string;\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => Promise<void>;\n\n /** Return initial CellStatus when a cell is first added. Default: {type:'other'} */\n createStatus?: (id: string) => CellStatus;\n /** Called once during cells.initialize() for each cell of this type. Reset ephemeral runtime state after hydration. */\n onInitialize?: (args: {\n id: string;\n status: CellStatus | undefined;\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => void;\n /** Called when cell is removed. Clean up DuckDB relations, caches, etc. */\n onRemove?: (args: {\n id: string;\n status: CellStatus | undefined;\n get: () => CellsRootState;\n set: (updater: (state: CellsRootState) => CellsRootState) => void;\n }) => Promise<void> | void;\n /** Detect whether an updateCell change is semantically significant for this cell type. */\n hasSemanticChange?: (oldCell: TCell, newCell: TCell) => boolean;\n /** Reset status to idle/stale. Called by invalidateCellStatus. If not provided, status is set to {type:'other'}. */\n invalidateStatus?: (currentStatus: CellStatus) => CellStatus;\n /** Collect DuckDB relation names that should be dropped when this cell is removed. */\n getRelationsToDrop?: (status: CellStatus) => string[];\n /** Record an error on the cell status during cascade execution. */\n recordError?: (currentStatus: CellStatus, message: string) => CellStatus;\n /** Return the query relation name for paged fetches, if applicable. */\n getResultRelation?: (status: CellStatus) => string | undefined;\n};\n\nexport type CellRegistry = Record<string, CellRegistryItem<any>>;\n\nexport const EdgeKind = z.enum(['dependency', 'manual']);\nexport type EdgeKind = z.infer<typeof EdgeKind>;\n\nexport const Edge = z.object({\n id: z.string(),\n source: z.string(), // cellId\n target: z.string(), // cellId\n kind: EdgeKind.optional(),\n});\nexport type Edge = z.infer<typeof Edge>;\n\nexport const CellArtifactGraphCache = z.object({\n dependencies: z.record(z.string(), z.array(z.string())).default({}),\n dependents: z.record(z.string(), z.array(z.string())).default({}),\n contentHashByCell: z.record(z.string(), z.string()).optional(),\n tableDependencies: z.record(z.string(), z.array(z.string())).default({}),\n});\nexport type CellArtifactGraphCache = z.infer<typeof CellArtifactGraphCache>;\n\nexport const CellArtifactRuntime = z.object({\n id: z.string(),\n schemaName: z.string().optional(),\n cellIds: z.array(z.string()).default([]),\n edges: z.array(Edge).default([]),\n graphCache: CellArtifactGraphCache.optional(),\n});\nexport type CellArtifactRuntime = z.infer<typeof CellArtifactRuntime>;\n\n/** Cell Status */\nexport const SqlCellStatus = z.object({\n type: z.literal('sql'),\n status: z.enum(['idle', 'running', 'success', 'cancel', 'error']),\n lastError: z.string().optional(),\n referencedTables: z.array(z.string()).default([]),\n resultName: z.string().optional(),\n resultView: z.string().optional(),\n resultRelationType: z.enum(['view', 'table']).optional(),\n lastRunTime: z.number().optional(),\n});\nexport type SqlCellStatus = z.infer<typeof SqlCellStatus>;\n\nexport const OtherCellStatus = z.object({\n type: z.literal('other'),\n});\nexport type OtherCellStatus = z.infer<typeof OtherCellStatus>;\n\n/** Extensible cell status -- each cell type defines its own shape with a discriminating `type` field. */\nexport type CellStatus = {type: string; [key: string]: unknown};\n\n/** SQL execution results */\nexport type SqlRunResult = {\n resultName?: string;\n referencedTables?: string[];\n lastRunTime?: number;\n};\n\nexport type SqlRunCallbacks = {\n onStart?: () => void;\n onSuccess?: (result: SqlRunResult) => void;\n onError?: (message: string) => void;\n onFinally?: () => void;\n};\n\nexport type SqlRenderInput = {\n varName: string;\n value: string | number;\n};\n\nexport type SqlDependencyOptions = {\n inputTypes?: string[];\n sqlTypes?: string[];\n};\n\nexport type SqlCellRunStatus =\n | {\n state: 'idle' | 'running' | 'success' | 'cancel' | 'error';\n message?: string;\n resultName?: string;\n }\n | undefined;\n\nexport const CellsSliceConfig = z.object({\n data: z.record(z.string(), Cell).default({}),\n artifacts: z.record(z.string(), CellArtifactRuntime).default({}),\n /** Which database schemas' tables are eligible for direct table dependencies. */\n tableDepSchemas: z.array(z.string()).default(['main']),\n});\nexport type CellsSliceConfig = z.infer<typeof CellsSliceConfig>;\n\nexport type CellsSliceOptions = {\n config?: Partial<CellsSliceConfig>;\n cellRegistry: CellRegistry;\n};\n\n/** Data stored for a cell's query result */\nexport type CellResultData = {\n arrowTable: arrow.Table;\n totalRows: number;\n};\n\n/** Cross-filter selection value emitted by a Vega chart brush */\nexport type CrossFilterSelection = {\n field: string;\n fieldType?: BrushFieldType;\n type: 'interval' | 'point';\n value: unknown;\n};\n\nexport type CellsSliceState = {\n cells: SliceFunctions & {\n config: CellsSliceConfig;\n status: Record<string, CellStatus>;\n activeAbortControllers: Record<string, AbortController>;\n cellRegistry: CellRegistry;\n /** Monotonic counter per cell, incremented when a new execution result arrives. Used to trigger pagination reset and re-render. */\n resultVersion: Record<string, number>;\n /** Monotonic counter per cell, incremented when a pagination/sorting fetch completes. Used to trigger re-render without resetting pagination. */\n pageVersion: Record<string, number>;\n\n /**\n * Ephemeral cross-filter selections (not persisted).\n * Outer key: sqlId (the shared data source), inner key: chartCellId.\n */\n crossFilterSelections: Record<\n string,\n Record<string, CrossFilterSelection | null>\n >;\n setCrossFilterSelection: (\n chartCellId: string,\n sqlId: string,\n selection: CrossFilterSelection | null,\n ) => void;\n getCrossFilterPredicate: (\n chartCellId: string,\n sqlId: string,\n ) => string | null;\n clearCrossFilterGroup: (sqlId: string) => void;\n\n // Cell CRUD\n ensureArtifact: (\n artifactId: string,\n options?: {schemaName?: string},\n ) => void;\n removeArtifact: (artifactId: string) => void;\n addCell: (artifactId: string, cell: Cell, index?: number) => Promise<void>;\n removeCell: (id: string) => void;\n updateCell: (\n id: string,\n updater: (cell: Cell) => Cell,\n opts?: {cascade?: boolean},\n ) => Promise<void>;\n\n // Edge management\n addEdge: (artifactId: string, edge: Omit<Edge, 'id'>) => void;\n removeEdge: (artifactId: string, edgeId: string) => void;\n updateEdgesFromSql: (artifactId: string, cellId: string) => Promise<void>;\n\n // Execution\n runCell: (\n id: string,\n opts?: {cascade?: boolean; schemaName?: string},\n ) => Promise<void>;\n cancelCell: (id: string) => void;\n invalidateCellStatus: (id: string) => void;\n\n // Cell result cache\n setCellResult: (id: string, data: CellResultData) => void;\n setCellResultPage: (id: string, data: CellResultData) => void;\n getCellResult: (id: string) => CellResultData | undefined;\n clearCellResult: (id: string) => void;\n fetchCellResultPage: (\n id: string,\n pagination: {pageIndex: number; pageSize: number},\n sorting?: {id: string; desc: boolean}[],\n ) => Promise<void>;\n\n // DAG methods\n getArtifactIdForCell: (cellId: string) => string | undefined;\n getDownstream: (artifactId: string, sourceCellId: string) => string[];\n getRootCells: (artifactId: string) => string[];\n runAllCellsCascade: (artifactId: string) => Promise<void>;\n runDownstreamCascade: (\n artifactId: string,\n sourceCellId: string,\n ) => Promise<void>;\n };\n // Slice lifecycle\n initialize?: () => Promise<void>;\n};\n\nexport type CellsRootState = BaseRoomStoreState &\n DbSliceState &\n CellsSliceState;\n\nexport function isSqlCell(cell: Cell): cell is SqlCell {\n return cell.type === 'sql';\n}\n\nexport function isTextCell(cell: Cell): cell is TextCell {\n return cell.type === 'text';\n}\n\nexport function isVegaCell(cell: Cell): cell is VegaCell {\n return cell.type === 'vega';\n}\n\nexport function isInputCell(cell: Cell): cell is InputCell {\n return cell.type === 'input';\n}\n\nexport function isSqlCellStatus(\n status: CellStatus | undefined,\n): status is SqlCellStatus {\n return status?.type === 'sql';\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type { Cell } from './types';
2
+ /**
3
+ * Validates whether a proposed result name is available for a SQL cell.
4
+ *
5
+ * Returns a human-readable error message if the name is taken or would cause
6
+ * problems, or `null` if the name is acceptable.
7
+ *
8
+ * Checks performed (in order):
9
+ * 1. Basic validation (empty, valid SQL identifier)
10
+ * 2. Not already used by another SQL cell in the same sheet (name collision).
11
+ * 3. Not conflicting with a main-schema table name (would shadow real data).
12
+ * 4. Not creating a self-reference cycle (SQL references the proposed name).
13
+ */
14
+ export declare function validateResultName(opts: {
15
+ proposedName: string;
16
+ currentCellId: string;
17
+ currentCellSql: string;
18
+ sheetCellIds: string[];
19
+ cells: Record<string, Cell>;
20
+ mainSchemaTableNames: ReadonlyArray<string>;
21
+ convertToValidName: (name: string) => string;
22
+ }): string | null;
23
+ /**
24
+ * Hook to validate SQL cell result names.
25
+ * Returns an error message if invalid, or null if valid.
26
+ *
27
+ * Performs all validation checks via validateResultName:
28
+ * 1. Basic validation (empty, valid SQL identifier)
29
+ * 2. Name collision with other cells
30
+ * 3. Conflict with main-schema tables
31
+ * 4. Self-reference cycle detection
32
+ */
33
+ export declare function useValidateResultName(cellId: string, name: string): string | null;
34
+ //# sourceMappingURL=useValidateResultName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useValidateResultName.d.ts","sourceRoot":"","sources":["../src/useValidateResultName.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,IAAI,EAAc,MAAM,SAAS,CAAC;AA4B/C;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC9C,GAAG,MAAM,GAAG,IAAI,CAwDhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAyCf"}
@@ -0,0 +1,111 @@
1
+ import { convertToValidColumnOrTableName } from '@sqlrooms/utils';
2
+ import { useMemo } from 'react';
3
+ import { useCellsStore } from './hooks';
4
+ import { getEffectiveResultName, isValidSqlIdentifier } from './utils';
5
+ function escapeRegExp(s) {
6
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
7
+ }
8
+ /**
9
+ * Strips single-quoted SQL string literals from text so that identifier
10
+ * checks don't produce false positives on quoted string content.
11
+ * Handles escaped single-quotes inside literals (e.g. 'it''s fine').
12
+ */
13
+ function stripStringLiterals(sql) {
14
+ return sql.replace(/'(?:[^']|'')*'/g, "''");
15
+ }
16
+ function containsIdentifier(text, name) {
17
+ // The lookbehind includes '.' so that qualified names like `schema.my_result`
18
+ // are NOT matched — we only want to detect unqualified references.
19
+ // The lookahead intentionally omits '.' so that column-access expressions like
20
+ // `my_result.column` ARE matched (they reference the `my_result` table).
21
+ const pattern = new RegExp(`(?<![a-zA-Z0-9_.])${escapeRegExp(name)}(?![a-zA-Z0-9_])`, 'i');
22
+ return pattern.test(stripStringLiterals(text));
23
+ }
24
+ /**
25
+ * Validates whether a proposed result name is available for a SQL cell.
26
+ *
27
+ * Returns a human-readable error message if the name is taken or would cause
28
+ * problems, or `null` if the name is acceptable.
29
+ *
30
+ * Checks performed (in order):
31
+ * 1. Basic validation (empty, valid SQL identifier)
32
+ * 2. Not already used by another SQL cell in the same sheet (name collision).
33
+ * 3. Not conflicting with a main-schema table name (would shadow real data).
34
+ * 4. Not creating a self-reference cycle (SQL references the proposed name).
35
+ */
36
+ export function validateResultName(opts) {
37
+ const { proposedName, currentCellId, currentCellSql, sheetCellIds, cells, mainSchemaTableNames, convertToValidName, } = opts;
38
+ const trimmedName = proposedName.trim();
39
+ // 1. Basic validation first
40
+ if (!trimmedName) {
41
+ return 'Cannot be empty';
42
+ }
43
+ if (!isValidSqlIdentifier(trimmedName)) {
44
+ return 'Must be a valid SQL identifier';
45
+ }
46
+ const nameLower = trimmedName.toLowerCase();
47
+ // 2. Check for name collision with other SQL cells in the same sheet
48
+ for (const cellId of sheetCellIds) {
49
+ if (cellId === currentCellId) {
50
+ continue;
51
+ }
52
+ const cell = cells[cellId];
53
+ if (!cell || cell.type !== 'sql') {
54
+ continue;
55
+ }
56
+ const otherName = getEffectiveResultName(cell.data, convertToValidName);
57
+ if (otherName.toLowerCase() === nameLower) {
58
+ return 'Already used by another cell';
59
+ }
60
+ }
61
+ // 3. Check for conflict with main-schema table names
62
+ if (mainSchemaTableNames.some((t) => t.toLowerCase() === nameLower)) {
63
+ return 'Conflicts with existing table';
64
+ }
65
+ // 4. Check for self-reference cycle: the cell's SQL references the proposed name
66
+ if (containsIdentifier(currentCellSql, trimmedName)) {
67
+ return 'Name creates a dependency cycle';
68
+ }
69
+ return null;
70
+ }
71
+ /**
72
+ * Hook to validate SQL cell result names.
73
+ * Returns an error message if invalid, or null if valid.
74
+ *
75
+ * Performs all validation checks via validateResultName:
76
+ * 1. Basic validation (empty, valid SQL identifier)
77
+ * 2. Name collision with other cells
78
+ * 3. Conflict with main-schema tables
79
+ * 4. Self-reference cycle detection
80
+ */
81
+ export function useValidateResultName(cellId, name) {
82
+ const artifactId = useCellsStore((s) => s.cells.getArtifactIdForCell(cellId));
83
+ const cellsData = useCellsStore((s) => s.cells.config.data);
84
+ const artifacts = useCellsStore((s) => s.cells.config.artifacts);
85
+ const tableSchemas = useCellsStore((s) => s.db.tables);
86
+ const currentCell = cellsData[cellId];
87
+ const currentCellSql = currentCell?.type === 'sql' ? currentCell.data.sql : '';
88
+ const artifactCellIds = useMemo(() => (artifactId ? (artifacts[artifactId]?.cellIds ?? []) : []), [artifactId, artifacts]);
89
+ const mainSchemaTableNames = useMemo(() => tableSchemas
90
+ .filter((t) => (t.table.schema ?? t.schema) === 'main')
91
+ .map((t) => t.table.table ?? t.tableName), [tableSchemas]);
92
+ return useMemo(() => {
93
+ return validateResultName({
94
+ proposedName: name,
95
+ currentCellId: cellId,
96
+ currentCellSql,
97
+ sheetCellIds: artifactCellIds,
98
+ cells: cellsData,
99
+ mainSchemaTableNames,
100
+ convertToValidName: convertToValidColumnOrTableName,
101
+ });
102
+ }, [
103
+ name,
104
+ cellId,
105
+ currentCellSql,
106
+ artifactCellIds,
107
+ cellsData,
108
+ mainSchemaTableNames,
109
+ ]);
110
+ }
111
+ //# sourceMappingURL=useValidateResultName.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useValidateResultName.js","sourceRoot":"","sources":["../src/useValidateResultName.ts"],"names":[],"mappings":"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","sourcesContent":["import {convertToValidColumnOrTableName} from '@sqlrooms/utils';\nimport {useMemo} from 'react';\nimport {useCellsStore} from './hooks';\nimport type {Cell, SqlCellData} from './types';\nimport {getEffectiveResultName, isValidSqlIdentifier} from './utils';\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Strips single-quoted SQL string literals from text so that identifier\n * checks don't produce false positives on quoted string content.\n * Handles escaped single-quotes inside literals (e.g. 'it''s fine').\n */\nfunction stripStringLiterals(sql: string): string {\n return sql.replace(/'(?:[^']|'')*'/g, \"''\");\n}\n\nfunction containsIdentifier(text: string, name: string): boolean {\n // The lookbehind includes '.' so that qualified names like `schema.my_result`\n // are NOT matched — we only want to detect unqualified references.\n // The lookahead intentionally omits '.' so that column-access expressions like\n // `my_result.column` ARE matched (they reference the `my_result` table).\n const pattern = new RegExp(\n `(?<![a-zA-Z0-9_.])${escapeRegExp(name)}(?![a-zA-Z0-9_])`,\n 'i',\n );\n return pattern.test(stripStringLiterals(text));\n}\n\n/**\n * Validates whether a proposed result name is available for a SQL cell.\n *\n * Returns a human-readable error message if the name is taken or would cause\n * problems, or `null` if the name is acceptable.\n *\n * Checks performed (in order):\n * 1. Basic validation (empty, valid SQL identifier)\n * 2. Not already used by another SQL cell in the same sheet (name collision).\n * 3. Not conflicting with a main-schema table name (would shadow real data).\n * 4. Not creating a self-reference cycle (SQL references the proposed name).\n */\nexport function validateResultName(opts: {\n proposedName: string;\n currentCellId: string;\n currentCellSql: string;\n sheetCellIds: string[];\n cells: Record<string, Cell>;\n mainSchemaTableNames: ReadonlyArray<string>;\n convertToValidName: (name: string) => string;\n}): string | null {\n const {\n proposedName,\n currentCellId,\n currentCellSql,\n sheetCellIds,\n cells,\n mainSchemaTableNames,\n convertToValidName,\n } = opts;\n\n const trimmedName = proposedName.trim();\n\n // 1. Basic validation first\n if (!trimmedName) {\n return 'Cannot be empty';\n }\n\n if (!isValidSqlIdentifier(trimmedName)) {\n return 'Must be a valid SQL identifier';\n }\n\n const nameLower = trimmedName.toLowerCase();\n\n // 2. Check for name collision with other SQL cells in the same sheet\n for (const cellId of sheetCellIds) {\n if (cellId === currentCellId) {\n continue;\n }\n\n const cell = cells[cellId];\n if (!cell || cell.type !== 'sql') {\n continue;\n }\n\n const otherName = getEffectiveResultName(\n cell.data as SqlCellData,\n convertToValidName,\n );\n\n if (otherName.toLowerCase() === nameLower) {\n return 'Already used by another cell';\n }\n }\n\n // 3. Check for conflict with main-schema table names\n if (mainSchemaTableNames.some((t) => t.toLowerCase() === nameLower)) {\n return 'Conflicts with existing table';\n }\n\n // 4. Check for self-reference cycle: the cell's SQL references the proposed name\n if (containsIdentifier(currentCellSql, trimmedName)) {\n return 'Name creates a dependency cycle';\n }\n\n return null;\n}\n\n/**\n * Hook to validate SQL cell result names.\n * Returns an error message if invalid, or null if valid.\n *\n * Performs all validation checks via validateResultName:\n * 1. Basic validation (empty, valid SQL identifier)\n * 2. Name collision with other cells\n * 3. Conflict with main-schema tables\n * 4. Self-reference cycle detection\n */\nexport function useValidateResultName(\n cellId: string,\n name: string,\n): string | null {\n const artifactId = useCellsStore((s) => s.cells.getArtifactIdForCell(cellId));\n const cellsData = useCellsStore((s) => s.cells.config.data);\n const artifacts = useCellsStore((s) => s.cells.config.artifacts);\n const tableSchemas = useCellsStore((s) => s.db.tables);\n\n const currentCell = cellsData[cellId];\n const currentCellSql =\n currentCell?.type === 'sql' ? currentCell.data.sql : '';\n\n const artifactCellIds = useMemo(\n () => (artifactId ? (artifacts[artifactId]?.cellIds ?? []) : []),\n [artifactId, artifacts],\n );\n\n const mainSchemaTableNames = useMemo(\n () =>\n tableSchemas\n .filter((t) => (t.table.schema ?? t.schema) === 'main')\n .map((t) => t.table.table ?? t.tableName),\n [tableSchemas],\n );\n\n return useMemo(() => {\n return validateResultName({\n proposedName: name,\n currentCellId: cellId,\n currentCellSql,\n sheetCellIds: artifactCellIds,\n cells: cellsData,\n mainSchemaTableNames,\n convertToValidName: convertToValidColumnOrTableName,\n });\n }, [\n name,\n cellId,\n currentCellSql,\n artifactCellIds,\n cellsData,\n mainSchemaTableNames,\n ]);\n}\n"]}
package/dist/utils.d.ts CHANGED
@@ -11,7 +11,15 @@ export declare function isValidSqlIdentifier(name: string): boolean;
11
11
  */
12
12
  export declare function getEffectiveResultName(data: SqlCellData, convertToValidName: (name: string) => string): string;
13
13
  /**
14
- * Generates a stable SQL schema name for a sheet id.
14
+ * Generates a stable SQL schema name for an artifact id.
15
15
  */
16
- export declare function getSheetSchemaName(sheetId: string): string;
16
+ export declare function getArtifactSchemaName(artifactId: string): string;
17
+ /**
18
+ * Extracts a preview from SQL query - first non-empty line and whether there are more lines.
19
+ * Returns empty firstLine if the SQL is empty or contains only whitespace.
20
+ */
21
+ export declare function getSqlQueryPreview(sql: string): {
22
+ firstLine: string;
23
+ hasMoreLines: boolean;
24
+ };
17
25
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAEzC,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,CAAC,CAE7D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG1D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,SAAS,CAAC;AAEzC,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,CAAC,CAE7D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAC3C,MAAM,CAeR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB,CAaA"}
package/dist/utils.js CHANGED
@@ -26,10 +26,26 @@ export function getEffectiveResultName(data, convertToValidName) {
26
26
  return normalizedTitle;
27
27
  }
28
28
  /**
29
- * Generates a stable SQL schema name for a sheet id.
29
+ * Generates a stable SQL schema name for an artifact id.
30
30
  */
31
- export function getSheetSchemaName(sheetId) {
32
- const normalized = sheetId.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();
33
- return `sheet_${normalized}`;
31
+ export function getArtifactSchemaName(artifactId) {
32
+ const normalized = artifactId.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();
33
+ return `artifact_${normalized}`;
34
+ }
35
+ /**
36
+ * Extracts a preview from SQL query - first non-empty line and whether there are more lines.
37
+ * Returns empty firstLine if the SQL is empty or contains only whitespace.
38
+ */
39
+ export function getSqlQueryPreview(sql) {
40
+ const [firstLine, ...rest] = sql
41
+ .split('\n')
42
+ .filter((line) => line.trim() !== '');
43
+ if (!firstLine) {
44
+ return { firstLine: '', hasMoreLines: false };
45
+ }
46
+ return {
47
+ firstLine,
48
+ hasMoreLines: rest.length > 0,
49
+ };
34
50
  }
35
51
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAI,KAAoB;IAC/C,OAAO,KAAK,KAAK,SAAS,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAiB,EACjB,kBAA4C;IAE5C,IAAI,IAAI,CAAC,UAAU,IAAI,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAErE,6DAA6D;IAC7D,sDAAsD;IACtD,MAAM,eAAe,GAAG,eAAe,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC7E,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxE,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IACxE,OAAO,SAAS,UAAU,EAAE,CAAC;AAC/B,CAAC","sourcesContent":["import type {SqlCellData} from './types';\n\nexport function isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n\n/**\n * Validates that a string is a valid SQL identifier.\n * Must start with a letter or underscore, followed by letters, digits, or underscores.\n */\nexport function isValidSqlIdentifier(name: string): boolean {\n return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);\n}\n\n/**\n * Gets the effective result name for a SQL cell.\n * Returns explicit resultName if valid, otherwise auto-generates from title.\n */\nexport function getEffectiveResultName(\n data: SqlCellData,\n convertToValidName: (name: string) => string,\n): string {\n if (data.resultName && isValidSqlIdentifier(data.resultName)) {\n return data.resultName;\n }\n\n const normalizedTitle = convertToValidName(data.title).toLowerCase();\n\n // Keep SQL default titles mapped to a neutral result_* name:\n // \"SQL 1\" -> \"result_1\", \"SQL Query 2\" -> \"result_2\".\n const sqlDefaultMatch = normalizedTitle.match(/^sql(?:_query)?(?:_(\\d+))?$/);\n if (sqlDefaultMatch) {\n return sqlDefaultMatch[1] ? `result_${sqlDefaultMatch[1]}` : 'result';\n }\n\n return normalizedTitle;\n}\n\n/**\n * Generates a stable SQL schema name for a sheet id.\n */\nexport function getSheetSchemaName(sheetId: string): string {\n const normalized = sheetId.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\n return `sheet_${normalized}`;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAI,KAAoB;IAC/C,OAAO,KAAK,KAAK,SAAS,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAiB,EACjB,kBAA4C;IAE5C,IAAI,IAAI,CAAC,UAAU,IAAI,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAErE,6DAA6D;IAC7D,sDAAsD;IACtD,MAAM,eAAe,GAAG,eAAe,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC7E,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxE,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3E,OAAO,YAAY,UAAU,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAI5C,MAAM,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG;SAC7B,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAExC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAC,SAAS,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAC,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,SAAS;QACT,YAAY,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC;KAC9B,CAAC;AACJ,CAAC","sourcesContent":["import type {SqlCellData} from './types';\n\nexport function isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n\n/**\n * Validates that a string is a valid SQL identifier.\n * Must start with a letter or underscore, followed by letters, digits, or underscores.\n */\nexport function isValidSqlIdentifier(name: string): boolean {\n return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);\n}\n\n/**\n * Gets the effective result name for a SQL cell.\n * Returns explicit resultName if valid, otherwise auto-generates from title.\n */\nexport function getEffectiveResultName(\n data: SqlCellData,\n convertToValidName: (name: string) => string,\n): string {\n if (data.resultName && isValidSqlIdentifier(data.resultName)) {\n return data.resultName;\n }\n\n const normalizedTitle = convertToValidName(data.title).toLowerCase();\n\n // Keep SQL default titles mapped to a neutral result_* name:\n // \"SQL 1\" -> \"result_1\", \"SQL Query 2\" -> \"result_2\".\n const sqlDefaultMatch = normalizedTitle.match(/^sql(?:_query)?(?:_(\\d+))?$/);\n if (sqlDefaultMatch) {\n return sqlDefaultMatch[1] ? `result_${sqlDefaultMatch[1]}` : 'result';\n }\n\n return normalizedTitle;\n}\n\n/**\n * Generates a stable SQL schema name for an artifact id.\n */\nexport function getArtifactSchemaName(artifactId: string): string {\n const normalized = artifactId.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\n return `artifact_${normalized}`;\n}\n\n/**\n * Extracts a preview from SQL query - first non-empty line and whether there are more lines.\n * Returns empty firstLine if the SQL is empty or contains only whitespace.\n */\nexport function getSqlQueryPreview(sql: string): {\n firstLine: string;\n hasMoreLines: boolean;\n} {\n const [firstLine, ...rest] = sql\n .split('\\n')\n .filter((line) => line.trim() !== '');\n\n if (!firstLine) {\n return {firstLine: '', hasMoreLines: false};\n }\n\n return {\n firstLine,\n hasMoreLines: rest.length > 0,\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { CrossFilterSelection } from './types';
2
+ /**
3
+ * The standard Vega param name used for brush selections
4
+ * in cross-filter-enabled charts.
5
+ */
6
+ export declare const BRUSH_PARAM_NAME = "brush";
7
+ /**
8
+ * Build a SQL WHERE clause fragment from an array of sibling cross-filter
9
+ * selections. Returns `null` when there are no active selections.
10
+ *
11
+ * Supports interval selections (BETWEEN) and point selections (IN).
12
+ */
13
+ export declare function buildCrossFilterPredicate(selections: Array<CrossFilterSelection | null | undefined>): string | null;
14
+ //# sourceMappingURL=vegaSelectionUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vegaSelectionUtils.d.ts","sourceRoot":"","sources":["../src/vegaSelectionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAC;AA8FxC;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,KAAK,CAAC,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC,GACzD,MAAM,GAAG,IAAI,CAiBf"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The standard Vega param name used for brush selections
3
+ * in cross-filter-enabled charts.
4
+ */
5
+ export const BRUSH_PARAM_NAME = 'brush';
6
+ /**
7
+ * Escapes a field name for use in SQL by wrapping in double quotes
8
+ * and escaping embedded double quotes.
9
+ */
10
+ function escapeFieldName(field) {
11
+ return `"${field.replace(/"/g, '""')}"`;
12
+ }
13
+ /**
14
+ * Escapes a string value for use in SQL by escaping single quotes.
15
+ */
16
+ function escapeSqlString(str) {
17
+ return str.replace(/'/g, "''");
18
+ }
19
+ /**
20
+ * Formats a value for use in SQL (numbers as-is, strings quoted and escaped).
21
+ */
22
+ function formatSqlValue(value) {
23
+ if (typeof value === 'number') {
24
+ return String(value);
25
+ }
26
+ return `'${escapeSqlString(String(value))}'`;
27
+ }
28
+ /**
29
+ * Builds a SQL BETWEEN clause for interval selections.
30
+ * Returns null if the range is invalid.
31
+ */
32
+ function buildIntervalClause(quotedField, selection) {
33
+ const range = selection.value;
34
+ if (!Array.isArray(range) || range.length !== 2) {
35
+ return null;
36
+ }
37
+ const [lo, hi] = range;
38
+ if (typeof lo === 'number' && typeof hi === 'number') {
39
+ if (selection.fieldType === 'temporal') {
40
+ return `${quotedField} BETWEEN epoch_ms(${Math.round(lo)}) AND epoch_ms(${Math.round(hi)})`;
41
+ }
42
+ return `${quotedField} BETWEEN ${lo} AND ${hi}`;
43
+ }
44
+ if (typeof lo === 'string' && typeof hi === 'string') {
45
+ const loEsc = escapeSqlString(lo);
46
+ const hiEsc = escapeSqlString(hi);
47
+ return `${quotedField} BETWEEN '${loEsc}' AND '${hiEsc}'`;
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * Builds a SQL IN clause for point selections.
53
+ * Returns null if the values array is empty or invalid.
54
+ */
55
+ function buildPointClause(quotedField, selection) {
56
+ const values = selection.value;
57
+ if (!Array.isArray(values) || values.length === 0) {
58
+ return null;
59
+ }
60
+ const commaSeparated = values.map(formatSqlValue).join(', ');
61
+ return `${quotedField} IN (${commaSeparated})`;
62
+ }
63
+ /**
64
+ * Builds a SQL clause for a single selection based on its type.
65
+ * Returns null if the selection type is unknown or the clause cannot be built.
66
+ */
67
+ function buildClause(quotedField, selection) {
68
+ switch (selection.type) {
69
+ case 'interval':
70
+ return buildIntervalClause(quotedField, selection);
71
+ case 'point':
72
+ return buildPointClause(quotedField, selection);
73
+ default:
74
+ return null;
75
+ }
76
+ }
77
+ /**
78
+ * Build a SQL WHERE clause fragment from an array of sibling cross-filter
79
+ * selections. Returns `null` when there are no active selections.
80
+ *
81
+ * Supports interval selections (BETWEEN) and point selections (IN).
82
+ */
83
+ export function buildCrossFilterPredicate(selections) {
84
+ const clauses = [];
85
+ for (const selection of selections) {
86
+ if (!selection || selection.value == null) {
87
+ continue;
88
+ }
89
+ const quotedField = escapeFieldName(selection.field);
90
+ const clause = buildClause(quotedField, selection);
91
+ if (clause) {
92
+ clauses.push(clause);
93
+ }
94
+ }
95
+ return clauses.length > 0 ? clauses.join(' AND ') : null;
96
+ }
97
+ //# sourceMappingURL=vegaSelectionUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vegaSelectionUtils.js","sourceRoot":"","sources":["../src/vegaSelectionUtils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC;;;GAGG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,WAAmB,EACnB,SAA+B;IAE/B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;IAEvB,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QACrD,IAAI,SAAS,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YACvC,OAAO,GAAG,WAAW,qBAAqB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC;QAC9F,CAAC;QACD,OAAO,GAAG,WAAW,YAAY,EAAE,QAAQ,EAAE,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;QAClC,OAAO,GAAG,WAAW,aAAa,KAAK,UAAU,KAAK,GAAG,CAAC;IAC5D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACvB,WAAmB,EACnB,SAA+B;IAE/B,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC;IAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,GAAG,WAAW,QAAQ,cAAc,GAAG,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAClB,WAAmB,EACnB,SAA+B;IAE/B,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,KAAK,UAAU;YACb,OAAO,mBAAmB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACrD,KAAK,OAAO;YACV,OAAO,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAClD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAA0D;IAE1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAEnD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC","sourcesContent":["import type {CrossFilterSelection} from './types';\n\n/**\n * The standard Vega param name used for brush selections\n * in cross-filter-enabled charts.\n */\nexport const BRUSH_PARAM_NAME = 'brush';\n\n/**\n * Escapes a field name for use in SQL by wrapping in double quotes\n * and escaping embedded double quotes.\n */\nfunction escapeFieldName(field: string): string {\n return `\"${field.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Escapes a string value for use in SQL by escaping single quotes.\n */\nfunction escapeSqlString(str: string): string {\n return str.replace(/'/g, \"''\");\n}\n\n/**\n * Formats a value for use in SQL (numbers as-is, strings quoted and escaped).\n */\nfunction formatSqlValue(value: unknown): string {\n if (typeof value === 'number') {\n return String(value);\n }\n return `'${escapeSqlString(String(value))}'`;\n}\n\n/**\n * Builds a SQL BETWEEN clause for interval selections.\n * Returns null if the range is invalid.\n */\nfunction buildIntervalClause(\n quotedField: string,\n selection: CrossFilterSelection,\n): string | null {\n const range = selection.value;\n if (!Array.isArray(range) || range.length !== 2) {\n return null;\n }\n\n const [lo, hi] = range;\n\n if (typeof lo === 'number' && typeof hi === 'number') {\n if (selection.fieldType === 'temporal') {\n return `${quotedField} BETWEEN epoch_ms(${Math.round(lo)}) AND epoch_ms(${Math.round(hi)})`;\n }\n return `${quotedField} BETWEEN ${lo} AND ${hi}`;\n }\n\n if (typeof lo === 'string' && typeof hi === 'string') {\n const loEsc = escapeSqlString(lo);\n const hiEsc = escapeSqlString(hi);\n return `${quotedField} BETWEEN '${loEsc}' AND '${hiEsc}'`;\n }\n\n return null;\n}\n\n/**\n * Builds a SQL IN clause for point selections.\n * Returns null if the values array is empty or invalid.\n */\nfunction buildPointClause(\n quotedField: string,\n selection: CrossFilterSelection,\n): string | null {\n const values = selection.value;\n if (!Array.isArray(values) || values.length === 0) {\n return null;\n }\n\n const commaSeparated = values.map(formatSqlValue).join(', ');\n\n return `${quotedField} IN (${commaSeparated})`;\n}\n\n/**\n * Builds a SQL clause for a single selection based on its type.\n * Returns null if the selection type is unknown or the clause cannot be built.\n */\nfunction buildClause(\n quotedField: string,\n selection: CrossFilterSelection,\n): string | null {\n switch (selection.type) {\n case 'interval':\n return buildIntervalClause(quotedField, selection);\n case 'point':\n return buildPointClause(quotedField, selection);\n default:\n return null;\n }\n}\n\n/**\n * Build a SQL WHERE clause fragment from an array of sibling cross-filter\n * selections. Returns `null` when there are no active selections.\n *\n * Supports interval selections (BETWEEN) and point selections (IN).\n */\nexport function buildCrossFilterPredicate(\n selections: Array<CrossFilterSelection | null | undefined>,\n): string | null {\n const clauses: string[] = [];\n\n for (const selection of selections) {\n if (!selection || selection.value == null) {\n continue;\n }\n\n const quotedField = escapeFieldName(selection.field);\n const clause = buildClause(quotedField, selection);\n\n if (clause) {\n clauses.push(clause);\n }\n }\n\n return clauses.length > 0 ? clauses.join(' AND ') : null;\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type { BrushFieldType } from './types';
2
+ /**
3
+ * Read the flat encoding/mark values from either a flat spec or a
4
+ * dual-layer cross-filter spec so the config panel dropdowns reflect
5
+ * the current state regardless of spec shape.
6
+ */
7
+ export declare function readSpecValues(spec: any): {
8
+ mark: string | undefined;
9
+ xField: string | undefined;
10
+ yField: string | undefined;
11
+ yAggregate: string | undefined;
12
+ color: string | undefined;
13
+ };
14
+ /**
15
+ * Build a dual-layer Vega-Lite spec with a brush selection param on the
16
+ * background layer and a filter transform on the foreground layer.
17
+ */
18
+ export declare function buildCrossFilterSpec(opts: {
19
+ mark: string;
20
+ xField?: string;
21
+ xFieldType?: BrushFieldType;
22
+ yField?: string;
23
+ yAggregate?: string;
24
+ color?: string;
25
+ }): any;
26
+ /** Build a simple flat spec (no cross-filtering). */
27
+ export declare function buildFlatSpec(opts: {
28
+ mark: string;
29
+ xField?: string;
30
+ yField?: string;
31
+ yAggregate?: string;
32
+ color?: string;
33
+ }): any;
34
+ //# sourceMappingURL=vegaSpecBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vegaSpecBuilder.d.ts","sourceRoot":"","sources":["../src/vegaSpecBuilder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,GAAG;IACzC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAmBA;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,GAAG,CA4CN;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,GAAG,CAQN"}
@@ -0,0 +1,90 @@
1
+ import { BRUSH_PARAM_NAME } from './vegaSelectionUtils';
2
+ /**
3
+ * Read the flat encoding/mark values from either a flat spec or a
4
+ * dual-layer cross-filter spec so the config panel dropdowns reflect
5
+ * the current state regardless of spec shape.
6
+ */
7
+ export function readSpecValues(spec) {
8
+ if (spec?.layer && Array.isArray(spec.layer)) {
9
+ const fg = spec.layer[1] ?? spec.layer[0];
10
+ const bg = spec.layer[0];
11
+ return {
12
+ mark: fg?.mark ?? bg?.mark,
13
+ xField: fg?.encoding?.x?.field ?? bg?.encoding?.x?.field,
14
+ yField: fg?.encoding?.y?.field ?? bg?.encoding?.y?.field,
15
+ yAggregate: fg?.encoding?.y?.aggregate ?? bg?.encoding?.y?.aggregate,
16
+ color: fg?.encoding?.color?.value,
17
+ };
18
+ }
19
+ return {
20
+ mark: spec?.mark,
21
+ xField: spec?.encoding?.x?.field,
22
+ yField: spec?.encoding?.y?.field,
23
+ yAggregate: spec?.encoding?.y?.aggregate,
24
+ color: spec?.encoding?.color?.value,
25
+ };
26
+ }
27
+ /**
28
+ * Build a dual-layer Vega-Lite spec with a brush selection param on the
29
+ * background layer and a filter transform on the foreground layer.
30
+ */
31
+ export function buildCrossFilterSpec(opts) {
32
+ const { mark, xField, xFieldType, yField, yAggregate, color } = opts;
33
+ const xEnc = xField
34
+ ? {
35
+ field: xField,
36
+ ...(xFieldType === 'numeric' ? { bin: { maxbins: 20 } } : {}),
37
+ }
38
+ : undefined;
39
+ const yEnc = yField
40
+ ? { field: yField, aggregate: yAggregate ?? 'sum' }
41
+ : yAggregate === 'count'
42
+ ? { aggregate: 'count' }
43
+ : undefined;
44
+ const encoding = {};
45
+ if (xEnc)
46
+ encoding.x = xEnc;
47
+ if (yEnc)
48
+ encoding.y = yEnc;
49
+ return {
50
+ layer: [
51
+ {
52
+ params: [
53
+ {
54
+ name: BRUSH_PARAM_NAME,
55
+ select: { type: 'interval', encodings: ['x'] },
56
+ },
57
+ ],
58
+ mark,
59
+ encoding: {
60
+ ...encoding,
61
+ color: { value: '#ddd' },
62
+ },
63
+ },
64
+ {
65
+ transform: [{ filter: { param: BRUSH_PARAM_NAME } }],
66
+ mark,
67
+ encoding: {
68
+ ...encoding,
69
+ ...(color ? { color: { value: color } } : {}),
70
+ },
71
+ },
72
+ ],
73
+ padding: 20,
74
+ };
75
+ }
76
+ /** Build a simple flat spec (no cross-filtering). */
77
+ export function buildFlatSpec(opts) {
78
+ const { mark, xField, yField, yAggregate, color } = opts;
79
+ const encoding = {};
80
+ if (xField)
81
+ encoding.x = { field: xField };
82
+ if (yField)
83
+ encoding.y = { field: yField, aggregate: yAggregate ?? 'sum' };
84
+ else if (yAggregate === 'count')
85
+ encoding.y = { aggregate: 'count' };
86
+ if (color)
87
+ encoding.color = { value: color };
88
+ return { mark, encoding, padding: 20 };
89
+ }
90
+ //# sourceMappingURL=vegaSpecBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vegaSpecBuilder.js","sourceRoot":"","sources":["../src/vegaSpecBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["import {BRUSH_PARAM_NAME} from './vegaSelectionUtils';\nimport type {BrushFieldType} from './types';\n\n/**\n * Read the flat encoding/mark values from either a flat spec or a\n * dual-layer cross-filter spec so the config panel dropdowns reflect\n * the current state regardless of spec shape.\n */\nexport function readSpecValues(spec: any): {\n mark: string | undefined;\n xField: string | undefined;\n yField: string | undefined;\n yAggregate: string | undefined;\n color: string | undefined;\n} {\n if (spec?.layer && Array.isArray(spec.layer)) {\n const fg = spec.layer[1] ?? spec.layer[0];\n const bg = spec.layer[0];\n return {\n mark: fg?.mark ?? bg?.mark,\n xField: fg?.encoding?.x?.field ?? bg?.encoding?.x?.field,\n yField: fg?.encoding?.y?.field ?? bg?.encoding?.y?.field,\n yAggregate: fg?.encoding?.y?.aggregate ?? bg?.encoding?.y?.aggregate,\n color: fg?.encoding?.color?.value,\n };\n }\n return {\n mark: spec?.mark,\n xField: spec?.encoding?.x?.field,\n yField: spec?.encoding?.y?.field,\n yAggregate: spec?.encoding?.y?.aggregate,\n color: spec?.encoding?.color?.value,\n };\n}\n\n/**\n * Build a dual-layer Vega-Lite spec with a brush selection param on the\n * background layer and a filter transform on the foreground layer.\n */\nexport function buildCrossFilterSpec(opts: {\n mark: string;\n xField?: string;\n xFieldType?: BrushFieldType;\n yField?: string;\n yAggregate?: string;\n color?: string;\n}): any {\n const {mark, xField, xFieldType, yField, yAggregate, color} = opts;\n const xEnc: any = xField\n ? {\n field: xField,\n ...(xFieldType === 'numeric' ? {bin: {maxbins: 20}} : {}),\n }\n : undefined;\n const yEnc: any = yField\n ? {field: yField, aggregate: yAggregate ?? 'sum'}\n : yAggregate === 'count'\n ? {aggregate: 'count'}\n : undefined;\n\n const encoding: any = {};\n if (xEnc) encoding.x = xEnc;\n if (yEnc) encoding.y = yEnc;\n\n return {\n layer: [\n {\n params: [\n {\n name: BRUSH_PARAM_NAME,\n select: {type: 'interval', encodings: ['x']},\n },\n ],\n mark,\n encoding: {\n ...encoding,\n color: {value: '#ddd'},\n },\n },\n {\n transform: [{filter: {param: BRUSH_PARAM_NAME}}],\n mark,\n encoding: {\n ...encoding,\n ...(color ? {color: {value: color}} : {}),\n },\n },\n ],\n padding: 20,\n };\n}\n\n/** Build a simple flat spec (no cross-filtering). */\nexport function buildFlatSpec(opts: {\n mark: string;\n xField?: string;\n yField?: string;\n yAggregate?: string;\n color?: string;\n}): any {\n const {mark, xField, yField, yAggregate, color} = opts;\n const encoding: any = {};\n if (xField) encoding.x = {field: xField};\n if (yField) encoding.y = {field: yField, aggregate: yAggregate ?? 'sum'};\n else if (yAggregate === 'count') encoding.y = {aggregate: 'count'};\n if (color) encoding.color = {value: color};\n return {mark, encoding, padding: 20};\n}\n"]}