diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/RLSCodeEditor.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/RLSCodeEditor.tsx index fdaec522c6b..b36d37dead4 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/RLSCodeEditor.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/RLSCodeEditor.tsx @@ -1,12 +1,12 @@ import Editor, { Monaco, OnChange, OnMount, useMonaco } from '@monaco-editor/react' +import { noop } from 'lodash' import type { editor } from 'monaco-editor' import { MutableRefObject, useEffect, useRef } from 'react' import { cn } from 'ui' import { Markdown } from 'components/interfaces/Markdown' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import { formatQuery } from 'data/sql/format-sql-query' -import { noop } from 'lodash' +import { formatSql } from 'lib/formatSql' // [Joshen] Is there a way we can just have one single MonacoEditor component that's shared across the dashboard? // Feels like we're creating multiple copies of Editor. I'm keen to make this one the defacto as well so lets make sure @@ -125,31 +125,17 @@ export const RLSCodeEditor = ({ onChange() }, [value]) - async function formatPgsql(value: any) { - try { - const formatted = await formatQuery({ - projectRef: project?.ref!, - connectionString: project?.connectionString, - sql: value, - }) - return formatted - } catch (error) { - console.error('formatPgsql error:', error) - return value - } - } - useEffect(() => { if (monaco) { // Enable pgsql format const formatprovider = monaco.languages.registerDocumentFormattingEditProvider('pgsql', { async provideDocumentFormattingEdits(model: any) { const value = model.getValue() - const formatted = await formatPgsql(value) + const formatted = formatSql(value) return [ { range: model.getFullModelRange(), - text: formatted.result.trim(), + text: formatted.trim(), }, ] }, diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx index f4236a5491d..2daa81f7149 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx @@ -1,3 +1,7 @@ +import { Lightbulb } from 'lucide-react' +import { useEffect, useState } from 'react' + +import { formatSql } from 'lib/formatSql' import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, @@ -6,14 +10,11 @@ import { CodeBlock, cn, } from 'ui' +import { QueryPanelContainer, QueryPanelSection } from './QueryPanel' import { QUERY_PERFORMANCE_REPORTS, QUERY_PERFORMANCE_REPORT_TYPES, } from './QueryPerformance.constants' -import { format } from 'sql-formatter' -import { useEffect, useState } from 'react' -import { QueryPanelContainer, QueryPanelSection } from './QueryPanel' -import { Lightbulb } from 'lucide-react' interface QueryDetailProps { reportType: QUERY_PERFORMANCE_REPORT_TYPES @@ -33,15 +34,8 @@ export const QueryDetail = ({ useEffect(() => { if (selectedRow !== undefined) { - try { - const formattedQuery = format(selectedRow['query'], { - language: 'postgresql', - keywordCase: 'lower', - }) - setQuery(formattedQuery) - } catch (err) { - setQuery(selectedRow['query']) - } + const formattedQuery = formatSql(selectedRow['query']) + setQuery(formattedQuery) } }, [selectedRow]) diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx index 90b707d9efc..e4c876bcfeb 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx @@ -1,5 +1,6 @@ import type { Monaco } from '@monaco-editor/react' import { useQueryClient } from '@tanstack/react-query' +import { useCompletion } from 'ai/react' import { AnimatePresence, motion } from 'framer-motion' import { ChevronUp, Command, Loader2 } from 'lucide-react' import dynamic from 'next/dynamic' @@ -7,7 +8,6 @@ import { useRouter } from 'next/router' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { toast } from 'sonner' -import { useCompletion } from 'ai/react' import { useParams } from 'common' import { TelemetryActions } from 'common/telemetry-constants' import { GridFooter } from 'components/ui/GridFooter' @@ -17,7 +17,6 @@ import { constructHeaders } from 'data/fetchers' import { lintKeys } from 'data/lint/keys' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation' -import { useFormatQueryMutation } from 'data/sql/format-sql-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { isError } from 'data/utils/error-check' @@ -26,10 +25,10 @@ import { useSchemasForAi } from 'hooks/misc/useSchemasForAi' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { BASE_PATH, IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants' +import { formatSql } from 'lib/formatSql' import { detectOS, uuidv4 } from 'lib/helpers' import { useProfile } from 'lib/profile' import { wrapWithRoleImpersonation } from 'lib/role-impersonation' -import { format } from 'sql-formatter' import { useAppStateSnapshot } from 'state/app-state' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { isRoleImpersonationEnabled, useGetImpersonatedRole } from 'state/role-impersonation-state' @@ -151,7 +150,6 @@ export const SQLEditor = () => { const entityDefinitions = includeSchemaMetadata ? data?.map((def) => def.sql.trim()) : undefined /* React query mutations */ - const { mutate: formatQuery } = useFormatQueryMutation() const { mutateAsync: generateSqlTitle } = useSqlTitleGenerateMutation() const { mutate: sendEvent } = useSendEventMutation() const { mutate: execute, isLoading: isExecuting } = useExecuteSqlMutation({ @@ -228,29 +226,20 @@ export const SQLEditor = () => { const sql = snippet ? (selectedValue || editorRef.current?.getValue()) ?? snippet.snippet.content?.sql : selectedValue || editorRef.current?.getValue() - formatQuery( - { - projectRef: project.ref, - connectionString: project.connectionString, - sql, - }, - { - onSuccess: (res) => { - const editorModel = editorRef?.current?.getModel() - if (editorRef.current && editorModel) { - editorRef.current.executeEdits('apply-prettify-edit', [ - { - text: res.result, - range: editorModel.getFullModelRange(), - }, - ]) - snapV2.setSql(id, res.result) - } + const formattedSql = formatSql(sql) + + const editorModel = editorRef?.current?.getModel() + if (editorRef.current && editorModel) { + editorRef.current.executeEdits('apply-prettify-edit', [ + { + text: formattedSql, + range: editorModel.getFullModelRange(), }, - } - ) + ]) + snapV2.setSql(id, formattedSql) + } } - }, [formatQuery, id, isDiffOpen, project, snapV2]) + }, [id, isDiffOpen, project, snapV2]) const executeQuery = useCallback( async (force: boolean = false) => { @@ -599,18 +588,8 @@ export const SQLEditor = () => { const modified = promptState.beforeSelection + completion + promptState.afterSelection if (isCompletionLoading) { - let formattedModified = modified - // Attempt to format the modified SQL in case the LLM left out indentation, etc - try { - formattedModified = format( - promptState.beforeSelection + completion + promptState.afterSelection, - { - language: 'postgresql', - keywordCase: 'lower', - } - ) - } catch (error) {} + let formattedModified = formatSql(modified) setSourceSqlDiff({ original, diff --git a/apps/studio/components/interfaces/SqlGenerator/SqlGeneratorImpl.tsx b/apps/studio/components/interfaces/SqlGenerator/SqlGeneratorImpl.tsx index 64b524cdb39..2090607d0b8 100644 --- a/apps/studio/components/interfaces/SqlGenerator/SqlGeneratorImpl.tsx +++ b/apps/studio/components/interfaces/SqlGenerator/SqlGeneratorImpl.tsx @@ -1,13 +1,13 @@ import { AlertTriangle, User } from 'lucide-react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useEffectOnce } from 'react-use' -import { format } from 'sql-formatter' import { IS_PLATFORM } from 'common' import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query' import { useOrgOptedIntoAi } from 'hooks/misc/useOrgOptedIntoAi' import { useSchemasForAi } from 'hooks/misc/useSchemasForAi' import { useSelectedProject } from 'hooks/misc/useSelectedProject' +import { formatSql } from 'lib/formatSql' import { useAppStateSnapshot } from 'state/app-state' import { AiIconAnimation, @@ -231,17 +231,6 @@ function Messages({ messages: ReturnType['messages'] handleReset: () => void }) { - function formatAnswer(answer: string) { - try { - return format(answer, { - language: 'postgresql', - keywordCase: 'lower', - }) - } catch { - return answer - } - } - const X_PADDING = 'px-4' const UserAvatar = useCallback(() => { @@ -279,7 +268,7 @@ function Messages({ const answer = message.status === MessageStatus.Complete - ? formatAnswer(unformattedAnswer) + ? formatSql(unformattedAnswer) : unformattedAnswer const cantHelp = answer.replace(/^-- /, '') === "Sorry, I don't know how to help with that." diff --git a/apps/studio/components/interfaces/TableGridEditor/TableDefinition.tsx b/apps/studio/components/interfaces/TableGridEditor/TableDefinition.tsx index 8250fc7528a..34ce0d22e39 100644 --- a/apps/studio/components/interfaces/TableGridEditor/TableDefinition.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/TableDefinition.tsx @@ -2,7 +2,6 @@ import Editor from '@monaco-editor/react' import { useTheme } from 'next-themes' import Link from 'next/link' import { useMemo, useRef } from 'react' -import { format } from 'sql-formatter' import { useParams } from 'common' import Footer from 'components/grid/components/footer/Footer' @@ -17,6 +16,7 @@ import { isView, isViewLike, } from 'data/table-editor/table-editor-types' +import { formatSql } from 'lib/formatSql' import { timeout } from 'lib/helpers' import { Button } from 'ui' @@ -61,19 +61,8 @@ const TableDefinition = ({ entity }: TableDefinitionProps) => { ? `create materialized view ${entity.schema}.${entity.name} as\n` : '' - const formatDefinition = (value: string) => { - try { - return format(value, { - language: 'postgresql', - keywordCase: 'lower', - }) - } catch (err) { - return value - } - } - const formattedDefinition = useMemo( - () => (definition ? formatDefinition(prepend + definition) : undefined), + () => (definition ? formatSql(prepend + definition) : undefined), [definition] ) diff --git a/apps/studio/components/ui/CodeEditor/CodeEditor.tsx b/apps/studio/components/ui/CodeEditor/CodeEditor.tsx index 44237bae589..97420bf87c2 100644 --- a/apps/studio/components/ui/CodeEditor/CodeEditor.tsx +++ b/apps/studio/components/ui/CodeEditor/CodeEditor.tsx @@ -4,8 +4,8 @@ import { editor } from 'monaco-editor' import { MutableRefObject, useEffect, useRef, useState } from 'react' import { Markdown } from 'components/interfaces/Markdown' -import { formatQuery } from 'data/sql/format-sql-query' import { useSelectedProject } from 'hooks/misc/useSelectedProject' +import { formatSql } from 'lib/formatSql' import { timeout } from 'lib/helpers' import { cn } from 'ui' import { Loading } from '../Loading' @@ -94,21 +94,6 @@ const CodeEditor = ({ options ) - const formatPgsql = async (value: string) => { - try { - if (!project) throw new Error('No project') - const formatted = await formatQuery({ - projectRef: project.ref, - connectionString: project.connectionString, - sql: value, - }) - return formatted.result - } catch (error) { - console.error('formatPgsql error:', error) - return value - } - } - const onMount: OnMount = async (editor, monaco) => { editorRef.current = editor monacoRef.current = monaco @@ -234,7 +219,7 @@ const CodeEditor = ({ const formatProvider = monaco.languages.registerDocumentFormattingEditProvider('pgsql', { async provideDocumentFormattingEdits(model: any) { const value = model.getValue() - const formatted = await formatPgsql(value) + const formatted = formatSql(value) formatDocument.callback(formatted) return [{ range: model.getFullModelRange(), text: formatted }] }, diff --git a/apps/studio/components/ui/SqlEditor.tsx b/apps/studio/components/ui/SqlEditor.tsx index ad982e4ebbc..1a85ebb2939 100644 --- a/apps/studio/components/ui/SqlEditor.tsx +++ b/apps/studio/components/ui/SqlEditor.tsx @@ -3,7 +3,7 @@ import { noop } from 'lodash' import { useEffect, useRef } from 'react' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import { formatQuery } from 'data/sql/format-sql-query' +import { formatSql } from 'lib/formatSql' // [Joshen] We should deprecate this and use CodeEditor instead @@ -37,7 +37,7 @@ const SqlEditor = ({ const formatprovider = monaco.languages.registerDocumentFormattingEditProvider('pgsql', { async provideDocumentFormattingEdits(model: any) { const value = model.getValue() - const formatted = await formatPgsql(value) + const formatted = formatSql(value) return [ { range: model.getFullModelRange(), @@ -66,20 +66,6 @@ const SqlEditor = ({ } }, [queryId]) - async function formatPgsql(value: any) { - try { - const formatted = await formatQuery({ - projectRef: project?.ref!, - connectionString: project?.connectionString, - sql: value, - }) - return formatted - } catch (error) { - console.error('formatPgsql error:', error) - return value - } - } - const onMount = (editor: any, monaco: any) => { editorRef.current = editor diff --git a/apps/studio/data/sql/format-sql-query.ts b/apps/studio/data/sql/format-sql-query.ts deleted file mode 100644 index 21fb9de81d4..00000000000 --- a/apps/studio/data/sql/format-sql-query.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { useMutation, UseMutationOptions } from '@tanstack/react-query' -import { post } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' - -export type FormatQueryVariables = { - projectRef: string - sql: string - connectionString?: string -} - -export async function formatQuery( - { projectRef, connectionString, sql }: FormatQueryVariables, - signal?: AbortSignal -) { - let headers = new Headers() - - if (connectionString) headers.set('x-connection-encrypted', connectionString) - - const response = await post( - `${API_URL}/pg-meta/${projectRef}/query/format`, - { query: sql }, - { headers: Object.fromEntries(headers), signal } - ) - if (response.error) throw response.error - return { result: response } -} - -type FormatQueryData = Awaited> - -export const useFormatQueryMutation = ({ - onSuccess, - ...options -}: Omit, 'mutationFn'> = {}) => { - return useMutation((args) => formatQuery(args), { - async onSuccess(data, variables, context) { - await onSuccess?.(data, variables, context) - }, - ...options, - }) -} diff --git a/apps/studio/lib/formatSql.ts b/apps/studio/lib/formatSql.ts new file mode 100644 index 00000000000..75663004a63 --- /dev/null +++ b/apps/studio/lib/formatSql.ts @@ -0,0 +1,17 @@ +import { format } from 'sql-formatter' + +/** + * Util function for formatting SQL. It wraps the `sql-formatter` library with a preset format options so that the + * formatting is consistent across the app. It also has a try/catch block which returns the original SQL in case of + * an error. + */ +export const formatSql = (sql: string) => { + try { + return format(sql, { + language: 'postgresql', + keywordCase: 'lower', + }) + } catch { + return sql + } +} diff --git a/apps/studio/package.json b/apps/studio/package.json index d084e14ed34..2e24924ba7f 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -115,7 +115,7 @@ "semver": "^6.3.1", "shared-data": "workspace:*", "sonner": "^1.5.0", - "sql-formatter": "^13.1.0", + "sql-formatter": "^15.0.0", "sqlstring": "^2.3.2", "tus-js-client": "^4.1.0", "ui": "workspace:*", diff --git a/apps/studio/pages/project/[ref]/sql/[id].tsx b/apps/studio/pages/project/[ref]/sql/[id].tsx index 4b5c691cd92..688f48035aa 100644 --- a/apps/studio/pages/project/[ref]/sql/[id].tsx +++ b/apps/studio/pages/project/[ref]/sql/[id].tsx @@ -13,9 +13,9 @@ import { useDatabaseFunctionsQuery } from 'data/database-functions/database-func import { useKeywordsQuery } from 'data/database/keywords-query' import { useSchemasQuery } from 'data/database/schemas-query' import { useTableColumnsQuery } from 'data/database/table-columns-query' -import { useFormatQueryMutation } from 'data/sql/format-sql-query' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { LOCAL_STORAGE_KEYS } from 'lib/constants' +import { formatSql } from 'lib/formatSql' import { useAppStateSnapshot } from 'state/app-state' import { SnippetWithContent, useSnippets, useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import type { NextPageWithLayout } from 'types' @@ -30,7 +30,6 @@ const SqlEditor: NextPageWithLayout = () => { const snapV2 = useSqlEditorV2StateSnapshot() const allSnippets = useSnippets(ref!) - const { mutateAsync: formatQuery } = useFormatQueryMutation() const [intellisenseEnabled] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.SQL_EDITOR_INTELLISENSE, @@ -55,21 +54,6 @@ const SqlEditor: NextPageWithLayout = () => { } }, [ref, data]) - async function formatPgsql(value: string) { - try { - if (!project) throw new Error('No project') - const formatted = await formatQuery({ - projectRef: project.ref, - connectionString: project.connectionString, - sql: value, - }) - return formatted.result - } catch (error) { - console.error('formatPgsql error:', error) - return value - } - } - const { data: keywords, isSuccess: isKeywordsSuccess } = useKeywordsQuery( { projectRef: project?.ref, @@ -100,8 +84,6 @@ const SqlEditor: NextPageWithLayout = () => { ) const pgInfoRef = useRef(null) - const formatPgsqlRef = useRef(formatPgsql) - formatPgsqlRef.current = formatPgsql const isPgInfoReady = intellisenseEnabled && @@ -140,7 +122,7 @@ const SqlEditor: NextPageWithLayout = () => { const formatProvider = monaco.languages.registerDocumentFormattingEditProvider('pgsql', { async provideDocumentFormattingEdits(model: any) { const value = model.getValue() - const formatted = await formatPgsqlRef.current(value) + const formatted = formatSql(value) if (id) snapV2.setSql(id, formatted) return [{ range: model.getFullModelRange(), text: formatted }] }, diff --git a/packages/ai-commands/package.json b/packages/ai-commands/package.json index c1a4f0f84ff..e4d649e4733 100644 --- a/packages/ai-commands/package.json +++ b/packages/ai-commands/package.json @@ -30,7 +30,7 @@ "dotenv": "^16.3.1", "libpg-query": "15.2.0", "mdast-util-from-markdown": "^2.0.0", - "sql-formatter": "^15.0.2", + "sql-formatter": "^15.0.0", "tsconfig": "workspace:*", "typescript": "~5.5.0", "vitest": "^3.0.0" diff --git a/packages/ui-patterns/package.json b/packages/ui-patterns/package.json index b6419ec8d36..0536bfa8856 100644 --- a/packages/ui-patterns/package.json +++ b/packages/ui-patterns/package.json @@ -37,7 +37,7 @@ "recharts": "^2.8.0", "remark-gfm": "^4.0.0", "sonner": "^1.5.0", - "sql-formatter": "^15.3.1", + "sql-formatter": "^15.0.0", "sse.js": "^2.2.0", "tsconfig": "workspace:*", "ui": "workspace:*", diff --git a/packages/ui/package.json b/packages/ui/package.json index f854d6057a5..c20eafc37a1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -110,7 +110,6 @@ "config": "workspace:*", "copyfiles": "^2.4.1", "glob": "^8.1.0", - "sql-formatter": "^12.2.0", "style-dictionary": "^3.7.1", "tsconfig": "workspace:*", "tsconfig-paths-webpack-plugin": "^4.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a5a3b77e594..bc3000998f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -803,8 +803,8 @@ importers: specifier: ^1.5.0 version: 1.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) sql-formatter: - specifier: ^13.1.0 - version: 13.1.0 + specifier: ^15.0.0 + version: 15.4.9 sqlstring: specifier: ^2.3.2 version: 2.3.3 @@ -1286,8 +1286,8 @@ importers: specifier: ^2.0.0 version: 2.0.0(supports-color@8.1.1) sql-formatter: - specifier: ^15.0.2 - version: 15.3.1 + specifier: ^15.0.0 + version: 15.4.9 tsconfig: specifier: workspace:* version: link:../tsconfig @@ -1762,9 +1762,6 @@ importers: glob: specifier: ^8.1.0 version: 8.1.0 - sql-formatter: - specifier: ^12.2.0 - version: 12.2.0 style-dictionary: specifier: ^3.7.1 version: 3.8.0 @@ -1871,8 +1868,8 @@ importers: specifier: ^1.5.0 version: 1.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) sql-formatter: - specifier: ^15.3.1 - version: 15.3.1 + specifier: ^15.0.0 + version: 15.4.9 sse.js: specifier: ^2.2.0 version: 2.2.0 @@ -11509,20 +11506,12 @@ packages: resolution: {integrity: sha512-6QumAdGHEnI5dXEq1d0aBRP876AyA9Wp/UE7wopKNA2Mp9sKGRKVqGgoWHk4dr0J0nceesC85Y0p36qmGoNqhw==} hasBin: true - sql-formatter@12.2.0: - resolution: {integrity: sha512-wNsPUdOD6nnN9RUgHlNprQtm+iLW5LTOy/T0/2DDr2UeWSP8mvlQHrx6TY+IG1nfu5Kipq9GaOtS9SVq8s0Vig==} - hasBin: true - - sql-formatter@13.1.0: - resolution: {integrity: sha512-/nZQXuN7KzipFNM20ko+dHY4kOr9rymSfZLUDED8rhx3m8OK5y74jcyN+y1L51ZqHqiB0kp40VdpZP99uWvQdA==} - hasBin: true - sql-formatter@14.0.0: resolution: {integrity: sha512-VcHYMRvZqg3RNjjxNB/puT9O1hR5QLXTvgTaBtxXcvmRQwSnH9M+oW2Ti+uFuVVU8HoNlOjU2uKHv8c0FQNsdQ==} hasBin: true - sql-formatter@15.3.1: - resolution: {integrity: sha512-L/dqan+Hrt0PpPdCbHcI9bdfOvqaQZR7v5c5SWMJ3bUGQSezK09Mm9q2I3B4iObjaq7FyoldIM+fDSmfzGRXCA==} + sql-formatter@15.4.9: + resolution: {integrity: sha512-5vmt2HlCAVozxsBZuXWkAki/KGawaK+b5GG5x+BtXOFVpN/8cqppblFUxHl4jxdA0cvo14lABhM+KBnrUapOlw==} hasBin: true sql-parser-cst@0.24.0: @@ -25293,24 +25282,13 @@ snapshots: argparse: 2.0.1 nearley: 2.20.1 - sql-formatter@12.2.0: - dependencies: - argparse: 2.0.1 - nearley: 2.20.1 - - sql-formatter@13.1.0: - dependencies: - argparse: 2.0.1 - get-stdin: 8.0.0 - nearley: 2.20.1 - sql-formatter@14.0.0: dependencies: argparse: 2.0.1 get-stdin: 8.0.0 nearley: 2.20.1 - sql-formatter@15.3.1: + sql-formatter@15.4.9: dependencies: argparse: 2.0.1 get-stdin: 8.0.0