Browse Source

feat:优化SQL编辑器

microrain 5 months ago
parent
commit
5bf3068d8f
5 changed files with 675 additions and 144 deletions
  1. 1 0
      package.json
  2. 1 1
      src/utils/setIconfont.ts
  3. 370 0
      src/views/apihub/component/SqlEditor.vue
  4. 54 13
      src/views/apihub/component/edit.vue
  5. 249 130
      yarn.lock

+ 1 - 0
package.json

@@ -57,6 +57,7 @@
     "semver": "7.6.2",
     "sortablejs": "1.14.0",
     "splitpanes": "3.1.1",
+    "sql-formatter": "^15.6.1",
     "uuid": "9.0.0",
     "vform3-builds": "3.0.8",
     "vue": "3.2.37",

+ 1 - 1
src/utils/setIconfont.ts

@@ -1,6 +1,6 @@
 // 字体图标 url
 const cssCdnUrlList: Array<string> = [
-	'https://at.alicdn.com/t/font_2298093_y6u00apwst.css',
+	'//at.alicdn.com/t/font_2298093_y6u00apwst.css',
 ];
 // 第三方 js url
 const jsCdnUrlList: Array<string> = [];

+ 370 - 0
src/views/apihub/component/SqlEditor.vue

@@ -0,0 +1,370 @@
+<template>
+  <div class="sql-editor-wrapper" :style="{ height: height + 'px' }">
+    <div class="editor-container">
+      <div class="editor-toolbar">
+        <el-tooltip content="格式化SQL" placement="top">
+          <el-button type="primary" link @click="formatSql">
+            <el-icon><Operation /></el-icon>
+          </el-button>
+        </el-tooltip>
+
+        <el-dropdown @command="handleSnippetSelect" trigger="click">
+          <el-button type="primary" link>
+            <el-icon><Document /></el-icon>
+            <span>插入SQL片段</span>
+          </el-button>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item v-for="(snippet, index) in sqlSnippets"
+                              :key="index"
+                              :command="snippet.code">
+                {{ snippet.name }}
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+      </div>
+
+      <!-- Monaco编辑器容器 -->
+      <div ref="editorContainer" class="monaco-editor-container"></div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, onMounted, onBeforeUnmount, nextTick, markRaw } from 'vue';
+import { ElMessage } from 'element-plus';
+import { Operation, Document } from '@element-plus/icons-vue';
+import * as monaco from 'monaco-editor';
+import { format } from 'sql-formatter'; // Ensure this library is installed and imported correctly
+
+const props = defineProps({
+  modelValue: {
+    type: String,
+    default: ''
+  },
+  height: {
+    type: Number,
+    default: 300
+  }
+});
+
+const emit = defineEmits(['update:modelValue']);
+
+// 编辑器相关引用
+const sqlValue = ref(props.modelValue);
+const editorContainer = ref(null);
+const editorInstance = ref(null);
+const isFormatting = ref(false); // 格式化状态标记
+const isInserting = ref(false); // 插入片段状态标记
+
+// SQL代码片段
+const sqlSnippets = [
+  {
+    name: '基本查询',
+    code: 'SELECT * FROM table_name WHERE condition;'
+  },
+  {
+    name: '分组查询',
+    code: 'SELECT column1, COUNT(*) FROM table_name GROUP BY column1 HAVING COUNT(*) > 1;'
+  },
+  {
+    name: '联表查询',
+    code: 'SELECT a.*, b.* FROM table1 a JOIN table2 b ON a.id = b.table1_id;'
+  },
+  {
+    name: '分页查询',
+    code: 'SELECT * FROM table_name LIMIT 10 OFFSET 0;'
+  },
+  {
+    name: '插入数据',
+    code: 'INSERT INTO table_name (column1, column2) VALUES (value1, value2);'
+  },
+  {
+    name: '更新数据',
+    code: 'UPDATE table_name SET column1 = value1 WHERE condition;'
+  },
+  {
+    name: '删除数据',
+    code: 'DELETE FROM table_name WHERE condition;'
+  }
+];
+
+// SQL关键字
+const sqlKeywords = [
+  "SELECT", "FROM", "WHERE", "GROUP BY", "ORDER BY", "HAVING",
+  "JOIN", "LEFT JOIN", "RIGHT JOIN", "INNER JOIN", "LIMIT", "OFFSET",
+  "INSERT", "UPDATE", "DELETE", "CREATE", "ALTER", "DROP", "TABLE",
+  "INTO", "VALUES", "SET", "AND", "OR", "NOT", "NULL", "IS", "AS",
+  "DISTINCT", "COUNT", "SUM", "AVG", "MAX", "MIN", "BETWEEN", "LIKE",
+  "IN", "EXISTS", "ALL", "ANY", "UNION", "CASE", "WHEN", "THEN", "ELSE", "END"
+];
+
+// 监听值变化
+watch(() => props.modelValue, (newValue) => {
+  if (newValue !== sqlValue.value) {
+    sqlValue.value = newValue;
+    if (editorInstance.value) {
+      // 使用安全的方式更新编辑器内容
+      const model = editorInstance.value.getModel();
+      if (model) {
+        model.setValue(newValue);
+      }
+    }
+  }
+});
+
+// 初始化Monaco编辑器
+const initMonacoEditor = () => {
+  if (!editorContainer.value) return;
+
+  try {
+    // 清理现有实例
+    if (editorInstance.value) {
+      editorInstance.value.dispose();
+      editorInstance.value = null;
+    }
+
+    // 确保容器是空的
+    if (editorContainer.value.childNodes.length > 0) {
+      editorContainer.value.innerHTML = '';
+    }
+
+    // 创建编辑器实例
+    const editor = monaco.editor.create(editorContainer.value, {
+      value: sqlValue.value || '',
+      language: 'sql',
+      theme: 'vs',
+      automaticLayout: true,
+      scrollBeyondLastLine: false,
+      minimap: { enabled: false },
+      fontSize: 14,
+      tabSize: 2,
+      lineNumbers: 'on',
+      scrollbar: {
+        useShadows: false,
+        verticalScrollbarSize: 10,
+        horizontalScrollbarSize: 10,
+        alwaysConsumeMouseWheel: false
+      },
+      // 禁用所有可能导致性能问题的功能
+      folding: false,
+      contextmenu: false,
+      quickSuggestions: false,
+      parameterHints: false,
+      autoClosingBrackets: false,
+      suggestOnTriggerCharacters: false,
+      wordBasedSuggestions: false,
+      links: false,
+      hover: false,
+      find: false,
+      colorDecorators: false,
+      lightbulb: { enabled: false },
+      formatOnType: false,
+      formatOnPaste: false,
+      selectionHighlight: false,
+      occurrencesHighlight: false,
+      codeLens: false,
+      renderControlCharacters: false,
+      renderIndentGuides: false,
+      renderLineHighlight: 'none',
+      renderWhitespace: 'none'
+    });
+
+    console.log('[DEBUG] initMonacoEditor: Creating Monaco editor instance.');
+    editorInstance.value = markRaw(editor);
+    console.log('[DEBUG] initMonacoEditor: Monaco editor instance assigned to ref after markRaw.');
+
+    // 使用节流处理内容变化
+    const handleContentChange = () => {
+      const currentEditor = editorInstance.value;
+      if (!currentEditor) return;
+      const value = currentEditor.getValue();
+      sqlValue.value = value;
+      emit('update:modelValue', value);
+    };
+    const changeModelDisposable = editorInstance.value.onDidChangeModelContent(handleContentChange);
+
+    // 在组件销毁时清理事件监听器
+    onBeforeUnmount(() => {
+      if (changeModelDisposable) {
+        try {
+          changeModelDisposable.dispose();
+        } catch (e) {
+          // Error handling if needed
+        }
+      }
+      
+      // 确保也清理 editorInstance
+      if (editorInstance.value) {
+        try {
+          editorInstance.value.dispose();
+          editorInstance.value = null;
+        } catch (e) {
+          // Error handling if needed
+        }
+      }
+    });
+  } catch (error) {
+    // 静默处理错误或进行适当的错误上报
+  }
+};
+
+// 格式化SQL
+const formatSql = () => {
+  console.log('[DEBUG] formatSql START');
+  if (!editorInstance.value) {
+    console.error('[DEBUG] formatSql: Editor instance is NOT available.');
+    // ElMessage.error('编辑器实例未准备好,请稍后再试。');
+    return;
+  }
+  console.log('[DEBUG] formatSql: Editor instance is available.');
+
+  const currentContent = editorInstance.value.getValue();
+  console.log('[DEBUG] formatSql: Current content length:', currentContent.length);
+
+  if (!currentContent.trim()) {
+    console.log('[DEBUG] formatSql: Content is empty or whitespace, skipping format.');
+    // ElMessage.info('SQL内容为空,无需格式化。');
+    return;
+  }
+
+  // loading.value = true; // 假设有加载状态
+  // isFormatting.value = true;
+  console.log('[DEBUG] formatSql: Attempting to format SQL...');
+  try {
+    const formattedSql = format(currentContent, {
+      language: 'mysql', // 根据需要选择 'mysql', 'sql', 'n1ql', 'plsql', 'spark', 'tsql' 等
+      indent: '  ', // 两个空格缩进
+      uppercase: true, // 关键字大写
+      linesBetweenQueries: 1
+    });
+    console.log('[DEBUG] formatSql: SQL formatted successfully.');
+
+    editorInstance.value.setValue(formattedSql);
+    console.log('[DEBUG] formatSql: Formatted SQL set to editor.');
+    // ElMessage.success('SQL格式化成功!');
+  } catch (error) {
+    console.error('[DEBUG] formatSql: Error during formatting:', error);
+    // ElMessage.error('SQL格式化失败,请检查SQL语法或格式化库配置。详情请查看控制台。');
+  } finally {
+    // loading.value = false;
+    // isFormatting.value = false;
+    console.log('[DEBUG] formatSql END');
+  }
+};
+
+// 处理SQL片段选择 - 使用防抖动处理
+const handleSnippetSelect = (snippet: string) => {
+  console.log('[DEBUG] handleSnippetSelect START. Snippet:', snippet);
+  if (!editorInstance.value) {
+    console.error('[DEBUG] Editor instance is NOT available.');
+    return;
+  }
+  console.log('[DEBUG] Editor instance is available.');
+
+  try {
+    const model = editorInstance.value.getModel();
+    if (!model) {
+      console.error('[DEBUG] Editor model is NOT available.');
+      return;
+    }
+    console.log('[DEBUG] Editor model obtained.');
+
+    const currentPosition = editorInstance.value.getPosition();
+    console.log('[DEBUG] Current position:', currentPosition);
+
+    if (currentPosition) {
+      const range = new monaco.Range(
+        currentPosition.lineNumber,
+        currentPosition.column,
+        currentPosition.lineNumber,
+        currentPosition.column
+      );
+      const op = { range: range, text: snippet, forceMoveMarkers: true };
+      console.log('[DEBUG] Preparing to executeEdits. Op:', op);
+      editorInstance.value.executeEdits('snippet-inserter', [op]); // Monaco API call
+      console.log('[DEBUG] executeEdits completed.');
+    } else {
+      console.warn('[DEBUG] Cannot get current position. Appending to end.');
+      const currentValue = model.getValue();
+      const newContent = currentValue + (currentValue ? '\n' : '') + snippet;
+      model.setValue(newContent); // Monaco API call
+      console.log('[DEBUG] Appended to end using setValue.');
+    }
+  } catch (error) {
+    console.error('[DEBUG] CRITICAL ERROR in handleSnippetSelect:', error);
+  }
+  console.log('[DEBUG] handleSnippetSelect END.');
+};
+
+// 组件挂载后的生命周期钩子
+onMounted(() => {
+  // 延迟初始化编辑器,确保 DOM 已完全渲染
+  setTimeout(() => {
+    initMonacoEditor();
+  }, 300);
+});
+
+// 组件销毁前
+onBeforeUnmount(() => {
+  // 清理编辑器实例
+  if (editorInstance.value) {
+    try {
+      editorInstance.value.dispose();
+      editorInstance.value = null;
+    } catch (e) {
+      // Error handling if needed
+    }
+  }
+});
+</script>
+
+<style scoped>
+.sql-editor-wrapper {
+  display: flex;
+  height: 300px;
+  min-height: 200px;
+  width: 100%;
+  position: relative;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.editor-container {
+  flex: 1;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  width: 100%;
+}
+
+.editor-toolbar {
+  display: flex;
+  align-items: center;
+  padding: 5px 10px;
+  border-bottom: 1px solid #dcdfe6;
+  background-color: #f5f7fa;
+  z-index: 10;
+}
+
+.monaco-editor-container {
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+  min-height: 200px;
+  width: 100%;
+}
+
+/* 深色模式样式 */
+.dark .sql-editor-wrapper {
+  border-color: #4c4d4f;
+}
+
+.dark .editor-toolbar {
+  background-color: #252526;
+  border-color: #4c4d4f;
+}
+</style>

+ 54 - 13
src/views/apihub/component/edit.vue

@@ -141,9 +141,10 @@
               </el-radio-group>
             </el-form-item>
             <el-form-item label="SQL内容" prop="sqlContent" class="sql-content-item">
-              <SqlEditor
-                v-model="formData.sqlContent"
-                :dataSourceKey="formData.dataSourceKey"
+              <SqlEditor 
+                v-model="formData.sqlContent" 
+                :height="300"
+                @update:modelValue="onSqlContentChange"
               />
             </el-form-item>
             <el-form-item label="返回格式" prop="returnFormat">
@@ -217,6 +218,7 @@
 
 <script lang="ts" setup>
 import { ref, reactive, nextTick } from "vue";
+import SqlEditor from "./SqlEditor.vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import { ruleRequired } from "/@/utils/validator";
 import api from "/@/api/modules/apiHub";
@@ -227,7 +229,7 @@ import {
   FullScreen as EleFullScreen,
   ScaleToOriginal as EleScaleToOriginal
 } from '@element-plus/icons-vue';
-import SqlEditor from "./SqlEditor.vue";
+// 使用自定义的 SqlEditor 组件替代 MonacoEditor
 
 const emit = defineEmits(["getList"]);
 
@@ -235,18 +237,19 @@ const showDialog = ref(false);
 const formRef = ref();
 const dataSources = ref<any[]>([]);
 const activeTab = ref('basic'); // 当前激活的Tab
-const isFullscreen = ref(false); // 是否全屏显示
-// SQL编辑器相关变量已移至SqlEditor.vue组件
 const pluginParamsPlaceholder = '插件参数 (JSON格式,例如:{"key": "value"})';
 const originUrl: string = getOrigin("");
 
-// Monaco Editor 配置项已移至SqlEditor.vue组件
-
-// SQL内容变化回调已移至SqlEditor.vue组件
+// SQL编辑器已经在组件内部处理了关键字和自动完成功能
 
-// 编辑器将要加载时的回调已移至SqlEditor.vue组件
+// SQL内容变化回调
+const onSqlContentChange = (value: string) => {
+  // 这里可以添加其他需要的处理逻辑
+  formData.sqlContent = value;
+};
 
-// 编辑器挂载完成回调已移至SqlEditor.vue组件
+// 全屏显示控制
+const isFullscreen = ref(false);
 
 // 检查哪个标签页有验证错误并切换到该标签页
 const checkTabWithErrors = () => {
@@ -779,9 +782,47 @@ defineExpose({ open });
   color: #909399;
 }
 
-/* Monaco Editor相关样式已移至SqlEditor.vue组件 */
+/* Monaco Editor 样式 */
+.sql-content-item {
+  width: 100%;
+}
+
+.monaco-editor-wrapper {
+  display: flex;
+  align-items: stretch;
+  width: 100%;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  overflow: hidden;
+  min-width: 500px;
+}
+
+.line-number-container {
+  background-color: #f5f7fa;
+  border-right: 1px solid #dcdfe6;
+  min-width: 40px;
+  width: 40px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding-top: 8px;
+}
 
-/* Monaco Editor相关样式已移至SqlEditor.vue组件 */
+.line-number {
+  color: #909399;
+  font-family: monospace;
+  font-size: 12px;
+  line-height: 1.5;
+  text-align: center;
+  width: 100%;
+}
+
+.monaco-editor-container {
+  height: 350px; /* 增加编辑器高度,使其更好地利用空间 */
+  flex-grow: 1;
+  overflow: hidden;
+  border: none;
+}
 
 /* API路径输入框样式 */
 .path-input-container {

+ 249 - 130
yarn.lock

@@ -239,7 +239,7 @@
   resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz"
   integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
 
-"@element-plus/icons-vue@^2.0.6", "@element-plus/icons-vue@2.0.9":
+"@element-plus/icons-vue@2.0.9", "@element-plus/icons-vue@^2.0.6":
   version "2.0.9"
   resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.0.9.tgz"
   integrity sha512-okdrwiVeKBmW41Hkl0eMrXDjzJwhQMuKiBOu17rOszqM+LS/yBYpNQNV5Jvoh06Wc+89fMmb/uhzf8NZuDuUaQ==
@@ -249,6 +249,16 @@
   resolved "https://registry.npmmirror.com/@element-plus/icons/-/icons-0.0.11.tgz"
   integrity sha512-iKQXSxXu131Ai+I9Ymtcof9WId7kaXvB1+WRfAfpQCW7UiAMYgdNDqb/u0hgTo2Yq3MwC4MWJnNuTBEpG8r7+A==
 
+"@esbuild/android-arm@0.15.18":
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz#266d40b8fdcf87962df8af05b76219bc786b4f80"
+  integrity sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==
+
+"@esbuild/linux-loong64@0.15.18":
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz#128b76ecb9be48b60cf5cfc1c63a4f00691a3239"
+  integrity sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==
+
 "@eslint/eslintrc@^1.2.0":
   version "1.4.1"
   resolved "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz"
@@ -306,7 +316,7 @@
   resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
   integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
 
-"@interactjs/actions@^1.10.2", "@interactjs/actions@1.10.27":
+"@interactjs/actions@1.10.27", "@interactjs/actions@^1.10.2":
   version "1.10.27"
   resolved "https://registry.npmmirror.com/@interactjs/actions/-/actions-1.10.27.tgz"
   integrity sha512-FCRg5KwB+stkPcAMx/Cn0fgGP6p4LyMX9S/Upcn/W+hpYme31bPi54PCqmOebzz6myTthN6zFf9jMyLOqtI/gg==
@@ -320,7 +330,7 @@
   optionalDependencies:
     "@interactjs/interact" "1.10.27"
 
-"@interactjs/auto-start@^1.10.2", "@interactjs/auto-start@1.10.27":
+"@interactjs/auto-start@1.10.27", "@interactjs/auto-start@^1.10.2":
   version "1.10.27"
   resolved "https://registry.npmmirror.com/@interactjs/auto-start/-/auto-start-1.10.27.tgz"
   integrity sha512-ECLBO/nxmaF1knncJKIE5F7la3KKRgEkn0Cu2JTPOYj9xy/LpfYElo3wkRHsodgOqF651nR70GK2/IzPR2lO9A==
@@ -332,7 +342,7 @@
   resolved "https://registry.npmmirror.com/@interactjs/core/-/core-1.10.27.tgz"
   integrity sha512-SliUr/3ZbLAdED8LokzYzWHWMdCB5Cq+UnpXuRy+BIod1j97m4IUFf/D1iIKUBBjBcucgXbz28z96WnenVCB7Q==
 
-"@interactjs/dev-tools@^1.10.2", "@interactjs/dev-tools@1.10.27":
+"@interactjs/dev-tools@1.10.27", "@interactjs/dev-tools@^1.10.2":
   version "1.10.27"
   resolved "https://registry.npmmirror.com/@interactjs/dev-tools/-/dev-tools-1.10.27.tgz"
   integrity sha512-YolmBwRaKH1gWbvyLeV3m5QSwtD38lOZnCBA87PCAlcd9PQAC2gb03fEPeEyD336bE20oLB8f0WZt4Wre+afiw==
@@ -375,7 +385,7 @@
     "@interactjs/reflow" "1.10.27"
     "@interactjs/utils" "1.10.27"
 
-"@interactjs/modifiers@^1.10.2", "@interactjs/modifiers@1.10.27":
+"@interactjs/modifiers@1.10.27", "@interactjs/modifiers@^1.10.2":
   version "1.10.27"
   resolved "https://registry.npmmirror.com/@interactjs/modifiers/-/modifiers-1.10.27.tgz"
   integrity sha512-ei/qfoQ+9/8k6WzNzdNqHI6cWkIV576N4Ap16r5CoqOWwhA6Xzj3OMHf1g0t1O4eSq2HdJsVJn3eLNfw9HsbeQ==
@@ -507,7 +517,7 @@
     "@nodelib/fs.stat" "2.0.5"
     run-parallel "^1.1.9"
 
-"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
   version "2.0.5"
   resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
   integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -657,7 +667,7 @@
     "@typescript-eslint/types" "5.13.0"
     eslint-visitor-keys "^3.0.0"
 
-"@unocss/core@^0.58.9", "@unocss/core@0.58.9":
+"@unocss/core@0.58.9", "@unocss/core@^0.58.9":
   version "0.58.9"
   resolved "https://registry.npmmirror.com/@unocss/core/-/core-0.58.9.tgz"
   integrity sha512-wYpPIPPsOIbIoMIDuH8ihehJk5pAZmyFKXIYO/Kro98GEOFhz6lJoLsy6/PZuitlgp2/TSlubUuWGjHWvp5osw==
@@ -997,6 +1007,11 @@
     ua-parser-js "^1.0.38"
     vue "^3.4.31"
 
+JSV@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.npmmirror.com/JSV/-/JSV-4.0.2.tgz"
+  integrity sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==
+
 acorn-jsx@^5.3.2:
   version "5.3.2"
   resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
@@ -1257,7 +1272,7 @@ claygl@^1.2.1:
   resolved "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz"
   integrity sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==
 
-clipboard@^2.0.10, clipboard@^2.0.6, clipboard@2.0.11:
+clipboard@2.0.11, clipboard@^2.0.10, clipboard@^2.0.6:
   version "2.0.11"
   resolved "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz"
   integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==
@@ -1286,7 +1301,7 @@ codemirror-editor-vue3@2.5.8:
     diff-match-patch "^1.0.5"
     jsonlint-mod "^1.7.6"
 
-codemirror@^5, codemirror@5.65.16:
+codemirror@5.65.16, codemirror@^5:
   version "5.65.16"
   resolved "https://registry.npmmirror.com/codemirror/-/codemirror-5.65.16.tgz"
   integrity sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==
@@ -1313,15 +1328,20 @@ color-convert@^2.0.1:
   dependencies:
     color-name "~1.1.4"
 
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz"
+  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
 color-name@~1.1.4:
   version "1.1.4"
   resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-color-name@1.1.3:
-  version "1.1.3"
-  resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz"
-  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+commander@^2.19.0:
+  version "2.20.3"
+  resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
 
 commander@~2.14.1:
   version "2.14.1"
@@ -1468,7 +1488,7 @@ data-view-byte-offset@^1.0.0:
     es-errors "^1.3.0"
     is-data-view "^1.0.1"
 
-dayjs@^1.11.3, dayjs@1.11.8, dayjs@1.x:
+dayjs@1.11.8, dayjs@1.x, dayjs@^1.11.3:
   version "1.11.8"
   resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.8.tgz"
   integrity sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ==
@@ -1547,6 +1567,11 @@ dir-glob@^3.0.1:
   dependencies:
     path-type "^4.0.0"
 
+discontinuous-range@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
+  integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==
+
 doctrine@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz"
@@ -1592,20 +1617,6 @@ echarts@5.5.0:
     tslib "2.3.0"
     zrender "5.5.0"
 
-element-plus@^1.0.2-beta.28:
-  version "1.0.2-beta.71"
-  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-1.0.2-beta.71.tgz"
-  integrity sha512-tlfbRORIav8gJcIpjZI5F6aJIVHIaDuGO6/vKu43lgYq4JS2JPNRTjvrSE2p4f5xLfaFNfOWjCS3sybXLfMg8g==
-  dependencies:
-    "@element-plus/icons" "^0.0.11"
-    "@popperjs/core" "^2.4.4"
-    async-validator "^3.4.0"
-    dayjs "1.x"
-    lodash "^4.17.20"
-    mitt "^2.1.0"
-    normalize-wheel "^1.0.1"
-    resize-observer-polyfill "^1.5.1"
-
 element-plus@2.2.28:
   version "2.2.28"
   resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.2.28.tgz"
@@ -1627,6 +1638,20 @@ element-plus@2.2.28:
     memoize-one "^6.0.0"
     normalize-wheel-es "^1.2.0"
 
+element-plus@^1.0.2-beta.28:
+  version "1.0.2-beta.71"
+  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-1.0.2-beta.71.tgz"
+  integrity sha512-tlfbRORIav8gJcIpjZI5F6aJIVHIaDuGO6/vKu43lgYq4JS2JPNRTjvrSE2p4f5xLfaFNfOWjCS3sybXLfMg8g==
+  dependencies:
+    "@element-plus/icons" "^0.0.11"
+    "@popperjs/core" "^2.4.4"
+    async-validator "^3.4.0"
+    dayjs "1.x"
+    lodash "^4.17.20"
+    mitt "^2.1.0"
+    normalize-wheel "^1.0.1"
+    resize-observer-polyfill "^1.5.1"
+
 element-resize-detector@^1.2.1:
   version "1.2.4"
   resolved "https://registry.npmmirror.com/element-resize-detector/-/element-resize-detector-1.2.4.tgz"
@@ -1728,11 +1753,106 @@ es-to-primitive@^1.2.1:
     is-date-object "^1.0.1"
     is-symbol "^1.0.2"
 
+esbuild-android-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz#20a7ae1416c8eaade917fb2453c1259302c637a5"
+  integrity sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==
+
+esbuild-android-arm64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz#9cc0ec60581d6ad267568f29cf4895ffdd9f2f04"
+  integrity sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==
+
+esbuild-darwin-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz#428e1730ea819d500808f220fbc5207aea6d4410"
+  integrity sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==
+
 esbuild-darwin-arm64@0.15.18:
   version "0.15.18"
   resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz"
   integrity sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==
 
+esbuild-freebsd-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz#4e190d9c2d1e67164619ae30a438be87d5eedaf2"
+  integrity sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==
+
+esbuild-freebsd-arm64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz#18a4c0344ee23bd5a6d06d18c76e2fd6d3f91635"
+  integrity sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==
+
+esbuild-linux-32@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz#9a329731ee079b12262b793fb84eea762e82e0ce"
+  integrity sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==
+
+esbuild-linux-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz#532738075397b994467b514e524aeb520c191b6c"
+  integrity sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==
+
+esbuild-linux-arm64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz#5372e7993ac2da8f06b2ba313710d722b7a86e5d"
+  integrity sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==
+
+esbuild-linux-arm@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz#e734aaf259a2e3d109d4886c9e81ec0f2fd9a9cc"
+  integrity sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==
+
+esbuild-linux-mips64le@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz#c0487c14a9371a84eb08fab0e1d7b045a77105eb"
+  integrity sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==
+
+esbuild-linux-ppc64le@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz#af048ad94eed0ce32f6d5a873f7abe9115012507"
+  integrity sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==
+
+esbuild-linux-riscv64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz#423ed4e5927bd77f842bd566972178f424d455e6"
+  integrity sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==
+
+esbuild-linux-s390x@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz#21d21eaa962a183bfb76312e5a01cc5ae48ce8eb"
+  integrity sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==
+
+esbuild-netbsd-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz#ae75682f60d08560b1fe9482bfe0173e5110b998"
+  integrity sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==
+
+esbuild-openbsd-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz#79591a90aa3b03e4863f93beec0d2bab2853d0a8"
+  integrity sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==
+
+esbuild-sunos-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz#fd528aa5da5374b7e1e93d36ef9b07c3dfed2971"
+  integrity sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==
+
+esbuild-windows-32@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz#0e92b66ecdf5435a76813c4bc5ccda0696f4efc3"
+  integrity sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==
+
+esbuild-windows-64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz#0fc761d785414284fc408e7914226d33f82420d0"
+  integrity sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==
+
+esbuild-windows-arm64@0.15.18:
+  version "0.15.18"
+  resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz#5b5bdc56d341d0922ee94965c89ee120a6a86eb7"
+  integrity sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==
+
 esbuild@^0.15.9:
   version "0.15.18"
   resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz"
@@ -1766,12 +1886,7 @@ escape-html@^1.0.3:
   resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz"
   integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
 
-escape-string-regexp@^1.0.2:
-  version "1.0.5"
-  resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
-  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
-
-escape-string-regexp@^1.0.5:
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
   integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
@@ -1799,15 +1914,7 @@ eslint-scope@^5.1.1:
     esrecurse "^4.3.0"
     estraverse "^4.1.1"
 
-eslint-scope@^7.0.0:
-  version "7.2.2"
-  resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz"
-  integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
-  dependencies:
-    esrecurse "^4.3.0"
-    estraverse "^5.2.0"
-
-eslint-scope@^7.1.1:
+eslint-scope@^7.0.0, eslint-scope@^7.1.1:
   version "7.2.2"
   resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz"
   integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
@@ -1901,12 +2008,7 @@ estraverse@^4.1.1:
   resolved "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz"
   integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
 
-estraverse@^5.1.0:
-  version "5.3.0"
-  resolved "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz"
-  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
-
-estraverse@^5.2.0:
+estraverse@^5.1.0, estraverse@^5.2.0:
   version "5.3.0"
   resolved "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz"
   integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
@@ -2099,7 +2201,7 @@ gl-matrix@^3.0.0, gl-matrix@^3.3.0, gl-matrix@^3.4.3:
   resolved "https://registry.npmmirror.com/gl-matrix/-/gl-matrix-3.4.3.tgz"
   integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==
 
-glob-parent@^5.1.2:
+glob-parent@^5.1.2, glob-parent@~5.1.2:
   version "5.1.2"
   resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz"
   integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -2113,13 +2215,6 @@ glob-parent@^6.0.1:
   dependencies:
     is-glob "^4.0.3"
 
-glob-parent@~5.1.2:
-  version "5.1.2"
-  resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz"
-  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
-  dependencies:
-    is-glob "^4.0.1"
-
 glob@^7.1.3, glob@~7.2.3:
   version "7.2.3"
   resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz"
@@ -2280,7 +2375,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@~2.0.4, inherits@2:
+inherits@2, inherits@~2.0.4:
   version "2.0.4"
   resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -2493,8 +2588,8 @@ jsonlint-mod@^1.7.6:
   resolved "https://registry.npmmirror.com/jsonlint-mod/-/jsonlint-mod-1.7.6.tgz"
   integrity sha512-oGuk6E1ehmIpw0w9ttgb2KsDQQgGXBzZczREW8OfxEm9eCQYL9/LCexSnh++0z3AiYGcXpBgqDSx9AAgzl/Bvg==
   dependencies:
-    chalk "^2.4.2"
     JSV "^4.0.2"
+    chalk "^2.4.2"
     underscore "^1.9.1"
 
 jsplumb@2.15.6:
@@ -2507,11 +2602,6 @@ jsrsasign@10.8.6:
   resolved "https://registry.npmmirror.com/jsrsasign/-/jsrsasign-10.8.6.tgz"
   integrity sha512-bQmbVtsfbgaKBTWCKiDCPlUPbdlRIK/FzSwT3BzIgZl/cU6TqXu6pZJsCI/dJVrZ9Gir5GC4woqw9shH/v7MBw==
 
-JSV@^4.0.2:
-  version "4.0.2"
-  resolved "https://registry.npmmirror.com/JSV/-/JSV-4.0.2.tgz"
-  integrity sha512-ZJ6wx9xaKJ3yFUhq5/sk82PJMuUyLk277I8mQeyDgCTjGdjWJIvPfaU5LIXaMuaN2UO1X3kZH4+lgphublZUHw==
-
 keyv@^4.5.3:
   version "4.5.4"
   resolved "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz"
@@ -2576,14 +2666,7 @@ magic-string@^0.25.7:
   dependencies:
     sourcemap-codec "^1.4.8"
 
-magic-string@^0.30.11:
-  version "0.30.11"
-  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.11.tgz"
-  integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==
-  dependencies:
-    "@jridgewell/sourcemap-codec" "^1.5.0"
-
-magic-string@^0.30.8:
+magic-string@^0.30.11, magic-string@^0.30.8:
   version "0.30.11"
   resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.11.tgz"
   integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==
@@ -2625,16 +2708,16 @@ minimist@^1.2.0, minimist@~1.2.8:
   resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz"
   integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
 
-mitt@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.npmmirror.com/mitt/-/mitt-2.1.0.tgz"
-  integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
-
 mitt@3.0.0:
   version "3.0.0"
   resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.0.tgz"
   integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
 
+mitt@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/mitt/-/mitt-2.1.0.tgz"
+  integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
+
 mock-property@~1.0.0:
   version "1.0.3"
   resolved "https://registry.npmmirror.com/mock-property/-/mock-property-1.0.3.tgz"
@@ -2652,6 +2735,11 @@ monaco-editor@^0.52.2:
   resolved "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz"
   integrity sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==
 
+moo@^0.5.0:
+  version "0.5.2"
+  resolved "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
+  integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
+
 ms@^2.1.3:
   version "2.1.3"
   resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz"
@@ -2667,6 +2755,16 @@ natural-compare@^1.4.0:
   resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz"
   integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
 
+nearley@^2.20.1:
+  version "2.20.1"
+  resolved "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474"
+  integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==
+  dependencies:
+    commander "^2.19.0"
+    moo "^0.5.0"
+    railroad-diagrams "^1.0.0"
+    randexp "0.4.6"
+
 neo-async@^2.6.2:
   version "2.6.2"
   resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz"
@@ -2852,6 +2950,19 @@ queue-microtask@^1.2.2:
   resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz"
   integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
 
+railroad-diagrams@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+  integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==
+
+randexp@0.4.6:
+  version "0.4.6"
+  resolved "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+  integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
+  dependencies:
+    discontinuous-range "1.0.0"
+    ret "~0.1.10"
+
 readdirp@~3.6.0:
   version "3.6.0"
   resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz"
@@ -2903,6 +3014,11 @@ resolve@^1.22.1, resolve@~1.22.6:
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
+ret@~0.1.10:
+  version "0.1.15"
+  resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+  integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
 reusify@^1.0.4:
   version "1.0.4"
   resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz"
@@ -2995,7 +3111,7 @@ select@^1.1.2:
   resolved "https://registry.npmmirror.com/select/-/select-1.1.2.tgz"
   integrity sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==
 
-semver@^7.3.5, semver@7.6.2:
+semver@7.6.2, semver@^7.3.5:
   version "7.6.2"
   resolved "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz"
   integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
@@ -3059,7 +3175,7 @@ sortablejs@1.14.0:
   resolved "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz"
   integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
 
-source-map-js@^1.0.1, source-map-js@^1.2.0, "source-map-js@>=0.6.2 <2.0.0":
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.0:
   version "1.2.0"
   resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz"
   integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
@@ -3071,7 +3187,14 @@ source-map-support@^0.3.2:
   dependencies:
     source-map "0.1.32"
 
-source-map@^0.6.1, source-map@0.6.1:
+source-map@0.1.32:
+  version "0.1.32"
+  resolved "https://registry.npmmirror.com/source-map/-/source-map-0.1.32.tgz"
+  integrity sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@0.6.1, source-map@^0.6.1:
   version "0.6.1"
   resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz"
   integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -3081,13 +3204,6 @@ source-map@~0.5.1:
   resolved "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz"
   integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
 
-source-map@0.1.32:
-  version "0.1.32"
-  resolved "https://registry.npmmirror.com/source-map/-/source-map-0.1.32.tgz"
-  integrity sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==
-  dependencies:
-    amdefine ">=0.0.4"
-
 sourcemap-codec@^1.4.8:
   version "1.4.8"
   resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz"
@@ -3098,6 +3214,14 @@ splitpanes@3.1.1:
   resolved "https://registry.npmmirror.com/splitpanes/-/splitpanes-3.1.1.tgz"
   integrity sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA==
 
+sql-formatter@^15.6.1:
+  version "15.6.1"
+  resolved "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.1.tgz#79fcc3fe80884bf90e2abc92573e56403580a5ec"
+  integrity sha512-uoKbRLVbjzwa8ouY4lI9YM387zRxDv9Gg5kZBzu2iNls2wVBlDLshhudCstczddRvj7J+xOpHTTWX6Z0lRgYGA==
+  dependencies:
+    argparse "^2.0.1"
+    nearley "^2.20.1"
+
 ssf@~0.11.2:
   version "0.11.2"
   resolved "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz"
@@ -3232,12 +3356,12 @@ to-regex-range@^5.0.1:
   dependencies:
     is-number "^7.0.0"
 
-tslib@^1.10.0:
-  version "1.14.1"
-  resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz"
-  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
 
-tslib@^1.8.1:
+tslib@^1.10.0, tslib@^1.8.1:
   version "1.14.1"
   resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -3247,11 +3371,6 @@ tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1:
   resolved "https://registry.npmmirror.com/tslib/-/tslib-2.7.0.tgz"
   integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
 
-tslib@2.3.0:
-  version "2.3.0"
-  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz"
-  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
-
 tsutils@^3.21.0:
   version "3.21.0"
   resolved "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz"
@@ -3427,7 +3546,7 @@ vue-demi@*, vue-demi@latest:
   resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz"
   integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
 
-vue-eslint-parser@^8.0.1, vue-eslint-parser@8.3.0:
+vue-eslint-parser@8.3.0, vue-eslint-parser@^8.0.1:
   version "8.3.0"
   resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz"
   integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==
@@ -3470,37 +3589,6 @@ vue-router@4.0.13:
   dependencies:
     "@vue/devtools-api" "^6.0.0"
 
-vue@^3.0.0:
-  version "3.1.5"
-  resolved "https://registry.npmmirror.com/vue/-/vue-3.1.5.tgz"
-  integrity sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==
-  dependencies:
-    "@vue/compiler-dom" "3.1.5"
-    "@vue/runtime-dom" "3.1.5"
-    "@vue/shared" "3.1.5"
-
-vue@^3.4.31:
-  version "3.5.3"
-  resolved "https://registry.npmmirror.com/vue/-/vue-3.5.3.tgz"
-  integrity sha512-xvRbd0HpuLovYbOHXRHlSBsSvmUJbo0pzbkKTApWnQGf3/cu5Z39mQeA5cZdLRVIoNf3zI6MSoOgHUT5i2jO+Q==
-  dependencies:
-    "@vue/compiler-dom" "3.5.3"
-    "@vue/compiler-sfc" "3.5.3"
-    "@vue/runtime-dom" "3.5.3"
-    "@vue/server-renderer" "3.5.3"
-    "@vue/shared" "3.5.3"
-
-vue@3, vue@3.2.37:
-  version "3.2.37"
-  resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz"
-  integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
-  dependencies:
-    "@vue/compiler-dom" "3.2.37"
-    "@vue/compiler-sfc" "3.2.37"
-    "@vue/runtime-dom" "3.2.37"
-    "@vue/server-renderer" "3.2.37"
-    "@vue/shared" "3.2.37"
-
 vue3-clipboard@1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/vue3-clipboard/-/vue3-clipboard-1.0.0.tgz"
@@ -3524,6 +3612,37 @@ vue3-json-viewer@2.2.2:
   dependencies:
     clipboard "^2.0.10"
 
+vue@3, vue@3.2.37:
+  version "3.2.37"
+  resolved "https://registry.npmmirror.com/vue/-/vue-3.2.37.tgz"
+  integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
+  dependencies:
+    "@vue/compiler-dom" "3.2.37"
+    "@vue/compiler-sfc" "3.2.37"
+    "@vue/runtime-dom" "3.2.37"
+    "@vue/server-renderer" "3.2.37"
+    "@vue/shared" "3.2.37"
+
+vue@^3.0.0:
+  version "3.1.5"
+  resolved "https://registry.npmmirror.com/vue/-/vue-3.1.5.tgz"
+  integrity sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==
+  dependencies:
+    "@vue/compiler-dom" "3.1.5"
+    "@vue/runtime-dom" "3.1.5"
+    "@vue/shared" "3.1.5"
+
+vue@^3.4.31:
+  version "3.5.3"
+  resolved "https://registry.npmmirror.com/vue/-/vue-3.5.3.tgz"
+  integrity sha512-xvRbd0HpuLovYbOHXRHlSBsSvmUJbo0pzbkKTApWnQGf3/cu5Z39mQeA5cZdLRVIoNf3zI6MSoOgHUT5i2jO+Q==
+  dependencies:
+    "@vue/compiler-dom" "3.5.3"
+    "@vue/compiler-sfc" "3.5.3"
+    "@vue/runtime-dom" "3.5.3"
+    "@vue/server-renderer" "3.5.3"
+    "@vue/shared" "3.5.3"
+
 vuex@4.0.2:
   version "4.0.2"
   resolved "https://registry.npmmirror.com/vuex/-/vuex-4.0.2.tgz"
@@ -3625,7 +3744,7 @@ yargs@~3.10.0:
     decamelize "^1.0.0"
     window-size "0.1.0"
 
-zrender@^5.1.1, zrender@5.5.0:
+zrender@5.5.0, zrender@^5.1.1:
   version "5.5.0"
   resolved "https://registry.npmmirror.com/zrender/-/zrender-5.5.0.tgz"
   integrity sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==