diff --git a/.changeset/itchy-countries-worry.md b/.changeset/itchy-countries-worry.md new file mode 100644 index 0000000000..9374512b23 --- /dev/null +++ b/.changeset/itchy-countries-worry.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/explorer": patch +--- + +Explore page now has a full-featured SQL editor with syntax highlighting, autocomplete, and query validation. diff --git a/packages/explorer/next.config.mjs b/packages/explorer/next.config.mjs index 7811d5e71d..a4f4406e34 100644 --- a/packages/explorer/next.config.mjs +++ b/packages/explorer/next.config.mjs @@ -6,6 +6,7 @@ export default function config() { output: "standalone", webpack: (config) => { config.externals.push("pino-pretty", "lokijs", "encoding"); + config.resolve.fallback = { fs: false }; return config; }, redirects: async () => { diff --git a/packages/explorer/package.json b/packages/explorer/package.json index e24b7e79fb..7198ccf340 100644 --- a/packages/explorer/package.json +++ b/packages/explorer/package.json @@ -44,6 +44,7 @@ "@latticexyz/store-indexer": "workspace:*", "@latticexyz/store-sync": "workspace:*", "@latticexyz/world": "workspace:*", + "@monaco-editor/react": "^4.6.0", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-label": "^2.1.0", @@ -61,13 +62,16 @@ "cmdk": "1.0.0", "debug": "^4.3.4", "lucide-react": "^0.408.0", + "monaco-editor": "^0.52.0", "next": "14.2.5", + "node-sql-parser": "^5.3.3", "nuqs": "^1.19.2", "query-string": "^9.1.0", "react": "^18", "react-dom": "^18", "react-hook-form": "^7.52.1", "sonner": "^1.5.0", + "sql-autocomplete": "^1.1.1", "tailwind-merge": "^1.12.0", "tsup": "^6.7.0", "viem": "catalog:", diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/Explorer.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/Explorer.tsx index e408a7d9e0..f7d19fbf86 100644 --- a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/Explorer.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/Explorer.tsx @@ -38,7 +38,7 @@ export function Explorer() { return ( <> - {indexer.type !== "sqlite" && } + {indexer.type !== "sqlite" && } diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/SQLEditor.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/SQLEditor.tsx index edffb85f7c..22b2a993f1 100644 --- a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/SQLEditor.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/SQLEditor.tsx @@ -1,46 +1,84 @@ +"use client"; + import { PlayIcon } from "lucide-react"; import { useQueryState } from "nuqs"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; +import { Table } from "@latticexyz/config"; +import Editor from "@monaco-editor/react"; import { Button } from "../../../../../../components/ui/Button"; -import { Form, FormControl, FormField, FormItem } from "../../../../../../components/ui/Form"; -import { Input } from "../../../../../../components/ui/Input"; +import { Form, FormField } from "../../../../../../components/ui/Form"; +import { cn } from "../../../../../../utils"; +import { monacoOptions } from "./consts"; +import { useMonacoSuggestions } from "./useMonacoSuggestions"; +import { useQueryValidator } from "./useQueryValidator"; + +type Props = { + table?: Table; +}; + +export function SQLEditor({ table }: Props) { + const [isFocused, setIsFocused] = useState(false); + const [query, setQuery] = useQueryState("query", { defaultValue: "" }); + const validateQuery = useQueryValidator(table); + useMonacoSuggestions(table); -export function SQLEditor() { - const [query, setQuery] = useQueryState("query"); const form = useForm({ defaultValues: { - query: query || "", + query, }, }); const handleSubmit = form.handleSubmit((data) => { - setQuery(data.query); + if (validateQuery(data.query)) { + setQuery(data.query); + } }); useEffect(() => { - form.reset({ query: query || "" }); + form.reset({ query }); }, [query, form]); return (
- -
- ( - - - - - - )} - /> - - -
+ + ( + field.onChange(value)} + onMount={(editor) => { + editor.onDidFocusEditorText(() => { + setIsFocused(true); + }); + + editor.onDidBlurEditorText(() => { + setIsFocused(false); + }); + }} + loading={null} + /> + )} + /> + + ); diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/consts.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/consts.ts new file mode 100644 index 0000000000..cca942027f --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/consts.ts @@ -0,0 +1,41 @@ +import { editor } from "monaco-editor/esm/vs/editor/editor.api"; + +export const monacoOptions: editor.IStandaloneEditorConstructionOptions = { + fontSize: 14, + fontWeight: "normal", + wordWrap: "off", + lineNumbers: "off", + lineNumbersMinChars: 0, + overviewRulerLanes: 0, + overviewRulerBorder: false, + hideCursorInOverviewRuler: true, + lineDecorationsWidth: 0, + glyphMargin: false, + folding: false, + scrollBeyondLastColumn: 0, + scrollbar: { + horizontal: "hidden", + vertical: "hidden", + alwaysConsumeMouseWheel: false, + handleMouseWheel: false, + }, + find: { + addExtraSpaceOnTop: false, + autoFindInSelection: "never", + seedSearchStringFromSelection: "never", + }, + minimap: { enabled: false }, + wordBasedSuggestions: "off", + links: false, + occurrencesHighlight: "off", + cursorStyle: "line-thin", + renderLineHighlight: "none", + contextmenu: false, + roundedSelection: false, + hover: { + delay: 100, + }, + acceptSuggestionOnEnter: "on", + automaticLayout: true, + fixedOverflowWidgets: true, +}; diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoErrorMarker.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoErrorMarker.ts new file mode 100644 index 0000000000..27134fc3dd --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoErrorMarker.ts @@ -0,0 +1,23 @@ +import { useCallback } from "react"; +import { useMonaco } from "@monaco-editor/react"; + +export function useMonacoErrorMarker() { + const monaco = useMonaco(); + return useCallback( + ({ message, startColumn, endColumn }: { message: string; startColumn: number; endColumn: number }) => { + if (monaco) { + monaco.editor.setModelMarkers(monaco.editor.getModels()[0], "sql", [ + { + severity: monaco.MarkerSeverity.Error, + message, + startLineNumber: 1, + startColumn, + endLineNumber: 1, + endColumn, + }, + ]); + } + }, + [monaco], + ); +} diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoSuggestions.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoSuggestions.ts new file mode 100644 index 0000000000..d4c736b8d4 --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useMonacoSuggestions.ts @@ -0,0 +1,60 @@ +import { useEffect } from "react"; +import { Table } from "@latticexyz/config"; +import { useMonaco } from "@monaco-editor/react"; +import { useQueryAutocomplete } from "./useQueryAutocomplete"; + +const monacoSuggestionsMap = { + KEYWORD: "Keyword", + TABLE: "Field", + COLUMN: "Field", +} as const; + +export function useMonacoSuggestions(table?: Table) { + const monaco = useMonaco(); + const queryAutocomplete = useQueryAutocomplete(table); + + useEffect(() => { + if (!monaco) return; + + const provider = monaco.languages.registerCompletionItemProvider("sql", { + triggerCharacters: [" ", ".", ","], + + provideCompletionItems: (model, position) => { + if (!queryAutocomplete) { + return { suggestions: [] }; + } + + const textUntilPosition = model.getValueInRange({ + startLineNumber: 1, + startColumn: 1, + endLineNumber: position.lineNumber, + endColumn: position.column, + }); + + const word = model.getWordUntilPosition(position); + const range = { + startLineNumber: position.lineNumber, + startColumn: word.startColumn, + endLineNumber: position.lineNumber, + endColumn: word.endColumn, + }; + + const suggestions = queryAutocomplete + .autocomplete(textUntilPosition) + .map(({ value, optionType }) => ({ + label: value, + kind: monaco.languages.CompletionItemKind[monacoSuggestionsMap[optionType]], + insertText: value, + range, + // move keyword optionType to the top of suggestions list + sortText: optionType !== "KEYWORD" ? "0" : "1", + })) + .filter(({ label }) => !!label); + + return { suggestions }; + }, + }); + + return () => provider.dispose(); + }, [monaco, queryAutocomplete]); +} diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryAutocomplete.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryAutocomplete.ts new file mode 100644 index 0000000000..14027d594b --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryAutocomplete.ts @@ -0,0 +1,21 @@ +import { useParams } from "next/navigation"; +import { SQLAutocomplete, SQLDialect } from "sql-autocomplete"; +import { Address } from "viem"; +import { useMemo } from "react"; +import { Table } from "@latticexyz/config"; +import { useChain } from "../../../../hooks/useChain"; +import { constructTableName } from "../../../../utils/constructTableName"; + +export function useQueryAutocomplete(table?: Table) { + const { id: chainId } = useChain(); + const { worldAddress } = useParams<{ worldAddress: Address }>(); + + return useMemo(() => { + if (!table || !worldAddress || !chainId) return null; + + const tableName = constructTableName(table, worldAddress as Address, chainId); + const columnNames = Object.keys(table.schema); + + return new SQLAutocomplete(SQLDialect.PLpgSQL, [tableName], columnNames); + }, [table, worldAddress, chainId]); +} diff --git a/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryValidator.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryValidator.ts new file mode 100644 index 0000000000..3603419860 --- /dev/null +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/useQueryValidator.ts @@ -0,0 +1,72 @@ +import { useParams } from "next/navigation"; +import { Parser } from "node-sql-parser"; +import { Address } from "viem"; +import { useCallback } from "react"; +import { Table } from "@latticexyz/config"; +import { useMonaco } from "@monaco-editor/react"; +import { useChain } from "../../../../hooks/useChain"; +import { constructTableName } from "../../../../utils/constructTableName"; +import { useMonacoErrorMarker } from "./useMonacoErrorMarker"; + +const sqlParser = new Parser(); + +export function useQueryValidator(table?: Table) { + const monaco = useMonaco(); + const { worldAddress } = useParams(); + const { id: chainId } = useChain(); + const setErrorMarker = useMonacoErrorMarker(); + + return useCallback( + (value: string) => { + if (!monaco || !table) return true; + + try { + const ast = sqlParser.astify(value); + if ("columns" in ast && Array.isArray(ast.columns)) { + for (const column of ast.columns) { + const columnName = column.expr.column; + if (!Object.keys(table.schema).includes(columnName)) { + setErrorMarker({ + message: `Column '${columnName}' does not exist in the table schema.`, + startColumn: value.indexOf(columnName) + 1, + endColumn: value.indexOf(columnName) + columnName.length + 1, + }); + return false; + } + } + } + + if ("from" in ast && Array.isArray(ast.from)) { + for (const tableInfo of ast.from) { + if ("table" in tableInfo) { + const selectedTableName = tableInfo.table; + const tableName = constructTableName(table, worldAddress as Address, chainId); + + if (selectedTableName !== tableName) { + setErrorMarker({ + message: `Only '${tableName}' is available for this query.`, + startColumn: value.indexOf(selectedTableName) + 1, + endColumn: value.indexOf(selectedTableName) + selectedTableName.length + 1, + }); + return false; + } + } + } + } + + monaco.editor.setModelMarkers(monaco.editor.getModels()[0], "sql", []); + return true; + } catch (error) { + if (error instanceof Error) { + setErrorMarker({ + message: error.message, + startColumn: 1, + endColumn: value.length + 1, + }); + } + return false; + } + }, + [monaco, table, setErrorMarker, worldAddress, chainId], + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0608188316..4702c78d44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,18 +6,6 @@ settings: catalogs: default: - '@ark/attest': - specifier: 0.12.1 - version: 0.12.1 - '@ark/util': - specifier: 0.2.2 - version: 0.2.2 - abitype: - specifier: 1.0.6 - version: 1.0.6 - arktype: - specifier: 2.0.0-beta.6 - version: 2.0.0-beta.6 viem: specifier: 2.21.19 version: 2.21.19 @@ -495,6 +483,9 @@ importers: '@latticexyz/world': specifier: workspace:* version: link:../world + '@monaco-editor/react': + specifier: ^4.6.0 + version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-checkbox': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.2.7)(@types/react@18.2.22)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -546,9 +537,15 @@ importers: lucide-react: specifier: ^0.408.0 version: 0.408.0(react@18.2.0) + monaco-editor: + specifier: ^0.52.0 + version: 0.52.0 next: specifier: 14.2.5 version: 14.2.5(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + node-sql-parser: + specifier: ^5.3.3 + version: 5.3.3 nuqs: specifier: ^1.19.2 version: 1.19.2(next@14.2.5(@babel/core@7.25.2)(@opentelemetry/api@1.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) @@ -567,6 +564,9 @@ importers: sonner: specifier: ^1.5.0 version: 1.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + sql-autocomplete: + specifier: ^1.1.1 + version: 1.1.1 tailwind-merge: specifier: ^1.12.0 version: 1.12.0 @@ -821,10 +821,10 @@ importers: version: 8.3.4 jest: specifier: ^29.3.1 - version: 29.5.0(@types/node@18.15.11) + version: 29.5.0(@types/node@20.12.12) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.21.4)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.21.4))(jest@29.5.0(@types/node@18.15.11))(typescript@5.4.2) + version: 29.0.5(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.12.12))(typescript@5.4.2) tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.47)(typescript@5.4.2) @@ -1200,10 +1200,10 @@ importers: version: 27.4.1 jest: specifier: ^29.3.1 - version: 29.5.0(@types/node@20.12.12) + version: 29.5.0(@types/node@18.15.11) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.12.12))(typescript@5.4.2) + version: 29.0.5(@babel/core@7.21.4)(@jest/types@29.6.3)(babel-jest@29.5.0(@babel/core@7.21.4))(jest@29.5.0(@types/node@18.15.11))(typescript@5.4.2) tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.47)(typescript@5.4.2) @@ -3484,6 +3484,18 @@ packages: resolution: {integrity: sha512-g2REf+xSt0OZfMoNNdC4+/Yy8eP3KUqvIArel54XRFKPoXbHI6+YjFfrLtfykWBjffOp7DTfIc3Kvk5TLfuiyg==} engines: {node: '>=16.0.0'} + '@monaco-editor/loader@1.4.0': + resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==} + peerDependencies: + monaco-editor: '>= 0.21.0 < 1' + + '@monaco-editor/react@4.6.0': + resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@motionone/animation@10.18.0': resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==} @@ -5206,6 +5218,9 @@ packages: '@types/openurl@1.0.0': resolution: {integrity: sha512-fUHH4T8FmEl3NBtGbUYYzMo1Ev47uVCVEGVjVNjorOMzgjls6zH82yr/zqkkcEOHY2HUC5PZ8dRFwGed/NR7wQ==} + '@types/pegjs@0.10.6': + resolution: {integrity: sha512-eLYXDbZWXh2uxf+w8sXS8d6KSoXTswfps6fvCUuVAGN8eRpfe7h9eSRydxiSJvo9Bf+GzifsDOr9TMQlmJdmkw==} + '@types/prettier@2.7.2': resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} @@ -5670,9 +5685,15 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + antlr4-c3@1.1.16: + resolution: {integrity: sha512-3CZQ54JPyo6lkZYDOXaKUsy5KNFucveocvRy+03R7zJQbYOUr4Z6lFeBWzkxJXLitc7yQYe7OHbB6snyp7IJvQ==} + antlr4@4.7.1: resolution: {integrity: sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==} + antlr4ts-sql@1.1.0: + resolution: {integrity: sha512-94+8/+hsPI/OLG0WRGqW88/gqz+xxrSLSz/jGqS8Xl7tYWwUj/cBB4D/QRmNezYLqEaUzMHhTeQn5hzrpC2wNQ==} + antlr4ts@0.5.0-alpha.4: resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} @@ -5917,6 +5938,10 @@ packages: better-sqlite3@8.6.0: resolution: {integrity: sha512-jwAudeiTMTSyby+/SfbHDebShbmC2MCH8mU2+DXi0WJfv13ypEJm47cd3kljmy/H130CazEvkf2Li//ewcMJ1g==} + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -7039,11 +7064,13 @@ packages: eslint@5.16.0: resolution: {integrity: sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==} engines: {node: ^6.14.0 || ^8.10.0 || >=9.10.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@5.0.1: @@ -8868,6 +8895,9 @@ packages: modern-ahocorasick@1.0.1: resolution: {integrity: sha512-yoe+JbhTClckZ67b2itRtistFKf8yPYelHLc7e5xAwtNAXxM6wJTUx2C7QeVSJFDzKT7bCIFyBVybPMKvmB9AA==} + monaco-editor@0.52.0: + resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==} + motion@10.16.2: resolution: {integrity: sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==} @@ -9014,6 +9044,10 @@ packages: node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-sql-parser@5.3.3: + resolution: {integrity: sha512-KRVnneHhy5zaylFmtojHxpXqjmThFSOn7n6x1J/38gTE6NL5Wj/yY7hjbFqpYcpPwIpXM7sFDnvV3ejxmoPAJQ==} + engines: {node: '>=8'} + node-stream-zip@1.15.0: resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} engines: {node: '>=0.12.0'} @@ -10430,6 +10464,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sql-autocomplete@1.1.1: + resolution: {integrity: sha512-0Fz1utcPC5m6qQiFDhIgyqNk8J0DyGBtv59++uUjkjM9vOdv6ugGuM+ZcjY0qyG9ofLmT6wLHSpx+2h6jm0t6Q==} + sql.js@1.8.0: resolution: {integrity: sha512-3HD8pSkZL+5YvYUI8nlvNILs61ALqq34xgmF+BHpqxe68yZIJ1H+sIVIODvni25+CcxHUxDyrTJUL0lE/m7afw==} @@ -10451,6 +10488,9 @@ packages: resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} engines: {node: '>=6'} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -11927,7 +11967,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -11939,7 +11979,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 fast-xml-parser: 4.2.5 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/credential-provider-env@3.535.0': dependencies: @@ -11990,7 +12030,7 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 transitivePeerDependencies: - aws-crt @@ -12031,20 +12071,20 @@ snapshots: '@aws-sdk/types': 3.535.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-logger@3.535.0': dependencies: '@aws-sdk/types': 3.535.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-recursion-detection@3.535.0': dependencies: '@aws-sdk/types': 3.535.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/middleware-user-agent@3.540.0': dependencies: @@ -12052,7 +12092,7 @@ snapshots: '@aws-sdk/util-endpoints': 3.540.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/region-config-resolver@3.535.0': dependencies: @@ -12061,7 +12101,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/token-providers@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': dependencies: @@ -12078,14 +12118,14 @@ snapshots: '@aws-sdk/types@3.535.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-endpoints@3.540.0': dependencies: '@aws-sdk/types': 3.535.0 '@smithy/types': 2.12.0 '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-locate-window@3.535.0': dependencies: @@ -12096,14 +12136,14 @@ snapshots: '@aws-sdk/types': 3.535.0 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-user-agent-node@3.535.0': dependencies: '@aws-sdk/types': 3.535.0 '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@aws-sdk/util-utf8-browser@3.259.0': dependencies: @@ -12385,7 +12425,7 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 '@babel/parser@7.21.4': dependencies: @@ -14370,6 +14410,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@monaco-editor/loader@1.4.0(monaco-editor@0.52.0)': + dependencies: + monaco-editor: 0.52.0 + state-local: 1.0.7 + + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) + monaco-editor: 0.52.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + '@motionone/animation@10.18.0': dependencies: '@motionone/easing': 10.18.0 @@ -15882,7 +15934,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/core@1.4.2': dependencies: @@ -15893,7 +15945,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/credential-provider-imds@2.3.0': dependencies: @@ -15909,19 +15961,19 @@ snapshots: '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/hash-node@2.2.0': dependencies: '@smithy/types': 2.12.0 '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/invalid-dependency@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/is-array-buffer@2.2.0': dependencies: @@ -15931,7 +15983,7 @@ snapshots: dependencies: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-endpoint@2.5.1': dependencies: @@ -15941,7 +15993,7 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/url-parser': 2.2.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-retry@2.3.1': dependencies: @@ -15952,25 +16004,25 @@ snapshots: '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 uuid: 9.0.1 '@smithy/middleware-serde@2.3.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/middleware-stack@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-config-provider@2.3.0': dependencies: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/node-http-handler@2.5.0': dependencies: @@ -15978,7 +16030,7 @@ snapshots: '@smithy/protocol-http': 3.3.0 '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/property-provider@2.2.0': dependencies: @@ -15988,7 +16040,7 @@ snapshots: '@smithy/protocol-http@3.3.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/querystring-builder@2.2.0': dependencies: @@ -16018,7 +16070,7 @@ snapshots: '@smithy/util-middleware': 2.2.0 '@smithy/util-uri-escape': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/smithy-client@2.5.1': dependencies: @@ -16027,36 +16079,36 @@ snapshots: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/types@2.12.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/url-parser@2.2.0': dependencies: '@smithy/querystring-parser': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-base64@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-browser@2.2.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-body-length-node@2.3.0': dependencies: - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-config-provider@2.3.0': dependencies: @@ -16068,7 +16120,7 @@ snapshots: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-defaults-mode-node@2.3.1': dependencies: @@ -16078,13 +16130,13 @@ snapshots: '@smithy/property-provider': 2.2.0 '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-endpoints@1.2.0': dependencies: '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-hex-encoding@2.2.0': dependencies: @@ -16093,13 +16145,13 @@ snapshots: '@smithy/util-middleware@2.2.0': dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-retry@2.2.0': dependencies: '@smithy/service-error-classification': 2.1.5 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.7.0 '@smithy/util-stream@2.2.0': dependencies: @@ -16119,7 +16171,7 @@ snapshots: '@smithy/util-utf8@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 + tslib: 2.7.0 '@snyk/github-codeowners@1.1.0': dependencies: @@ -16477,6 +16529,8 @@ snapshots: dependencies: '@types/node': 18.15.11 + '@types/pegjs@0.10.6': {} + '@types/prettier@2.7.2': {} '@types/prop-types@15.7.5': {} @@ -17273,8 +17327,16 @@ snapshots: ansi-styles@6.2.1: {} + antlr4-c3@1.1.16: + dependencies: + antlr4ts: 0.5.0-alpha.4 + antlr4@4.7.1: {} + antlr4ts-sql@1.1.0: + dependencies: + antlr4ts: 0.5.0-alpha.4 + antlr4ts@0.5.0-alpha.4: {} any-promise@1.3.0: {} @@ -17635,6 +17697,8 @@ snapshots: bindings: 1.5.0 prebuild-install: 7.1.1 + big-integer@1.6.52: {} + binary-extensions@2.2.0: {} bindings@1.5.0: @@ -18851,7 +18915,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 @@ -18863,7 +18927,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -18884,7 +18948,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.1.1(eslint@8.57.0)(typescript@5.4.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -21466,6 +21530,8 @@ snapshots: modern-ahocorasick@1.0.1: {} + monaco-editor@0.52.0: {} + motion@10.16.2: dependencies: '@motionone/animation': 10.18.0 @@ -21600,6 +21666,11 @@ snapshots: node-releases@2.0.18: {} + node-sql-parser@5.3.3: + dependencies: + '@types/pegjs': 0.10.6 + big-integer: 1.6.52 + node-stream-zip@1.15.0: {} nopt@6.0.0: @@ -23079,6 +23150,11 @@ snapshots: sprintf-js@1.0.3: {} + sql-autocomplete@1.1.1: + dependencies: + antlr4-c3: 1.1.16 + antlr4ts-sql: 1.1.0 + sql.js@1.8.0: {} ssri@9.0.1: @@ -23097,6 +23173,8 @@ snapshots: dependencies: type-fest: 0.7.1 + state-local@1.0.7: {} + statuses@1.5.0: {} statuses@2.0.1: {} @@ -23822,13 +23900,13 @@ snapshots: dependencies: browserslist: 4.23.0 escalade: 3.1.2 - picocolors: 1.0.0 + picocolors: 1.1.0 update-browserslist-db@1.1.0(browserslist@4.23.3): dependencies: browserslist: 4.23.3 escalade: 3.1.2 - picocolors: 1.0.1 + picocolors: 1.1.0 uqr@0.1.2: {}