Browse Source

feat: 模型插件

lvkun 3 years ago
parent
commit
9647cd5614

+ 5 - 0
package.json

@@ -10,10 +10,15 @@
   },
   "dependencies": {
     "@ant-design/icons-vue": "^6.1.0",
+    "@codemirror/lang-javascript": "^6.1.7",
+    "@codemirror/lang-vue": "^0.1.1",
+    "@codemirror/theme-one-dark": "^6.1.2",
+    "@codemirror/view": "^6.10.1",
     "@vueuse/core": "^9.13.0",
     "ant-design-vue": "^3.3.0-beta.4",
     "axios": "^1.3.5",
     "babel-plugin-import": "^1.13.6",
+    "codemirror": "^6.0.1",
     "core-js": "^3.8.3",
     "dayjs": "^1.11.7",
     "mitt": "^3.0.0",

+ 59 - 0
src/api/iot/model.ts

@@ -15,6 +15,11 @@ export const getModel = (params: IOT.API.MODEL.QueryPamars) => {
   })
 }
 
+/**
+ * 此函数检索具有可选过滤器和分页的模型列表。
+ * @param params - `params` 参数是一个可以包含以下可选属性的对象:
+ * @returns `getModelList` 函数返回一个 Promise,该 Promise 解析为 `IOT.API.MODEL.ModelDot[]` 类型的对象数组。
+ */
 export const getModelList = (params: {modelLabel?: string, limit?: number, lastId?: string}) => {
   return request<IOT.API.MODEL.ModelDot[]>({
     url: '/model/list',
@@ -167,3 +172,57 @@ export const delModelCmd = (id: string) => {
     method: 'DELETE'
   })
 }
+
+/**
+ * 此函数通过 POST 请求将模型插件添加到特定模型 ID。
+ * @param data - `data` 参数是一个包含三个属性的对象:
+ * @returns `addModelPlugin` 函数返回一个解析为字符串的 Promise。
+ */
+export const addModelPlugin = (data: {modelPluginType: string, modelPluginBody: string, modelId: string}) => {
+  return request<string>({
+    url: '/modelPlugin',
+    method: 'POST',
+    data
+  })
+}
+
+/**
+ * 函数 getModelPlugin 发出 GET 请求以检索具有指定 ID 的模型插件。
+ * @param params - `params` 参数是一个包含单个属性 `modelId` 的对象,它是一个表示模型 ID 的字符串。此参数在 URL 查询字符串中用于检索特定模型插件。
+ * @returns `getModelPlugin` 函数返回一个解析为字符串的 Promise。该字符串是 GET 请求对 `/modelPlugin` 端点的响应,其中提供的 `modelId`
+ * 作为查询参数。
+ */
+export const getModelPlugin = (params: {modelId: string}) => {
+  return request<IOT.API.MODEL.plugin>({
+    url: '/modelPlugin',
+    method: 'GET',
+    params
+  })
+}
+
+/**
+ * 这是一个 TypeScript 函数,它使用提供的数据更新模型插件。
+ * @param data - `data` 参数是一个包含以下属性的对象:
+ * @returns `updateModelPlugin` 函数返回一个解析为字符串的 Promise。
+ */
+export const updateModelPlugin = (data: {modelPluginType: string, modelPluginBody: string, modelId: string, id: string}) => {
+  return request<string>({
+    url: '/modelPlugin',
+    method: 'PUT',
+    data
+  })
+}
+/**
+ * 这是一个 TypeScript 函数,它向带有输入、pluginBody 和解码参数的模型插件的调试端点发送 POST 请求。
+ * @param data - `data` 参数是一个包含三个属性的对象:
+ * @returns `debugModelPlugin` 函数返回一个解析为字符串的 Promise。该字符串是对 `/modelPlugin/debug` 端点的 POST 请求的响应,其中提供的
+ * `data` 对象作为请求主体。
+ */
+
+export const debugModelPlugin = (data: {input: string, pluginBody: string, decode: boolean}) => {
+  return request<string>({
+    url: '/modelPlugin/debug',
+    method: 'POST',
+    data
+  })
+}

+ 2 - 1
src/controller/iot/device.ts

@@ -1,7 +1,8 @@
 import {
   addDevice, addSubDevice, delDevice, delDeviceMul, delDeviceTag,
   getDeviceById, getDeviceCount, getDeviceList, getDeviceMsgList, addDeviceMsg, getDeviceTag,
-  getSubDeviceList, updateDeviceLabel, addDeviceCmd, getDeviceCmdList, addDeviceTag, addDeviceGroup, listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup
+  getSubDeviceList, updateDeviceLabel, addDeviceCmd, getDeviceCmdList, addDeviceTag, addDeviceGroup,
+  listDeviceGroup, postGroupBindDevice, delGroupBindDevice, getDeviceByGroup
 } from '@/api/iot/device'
 import { DeviceMsgEnum } from '@/enum/common'
 import { message } from 'ant-design-vue'

+ 19 - 1
src/controller/iot/model.ts

@@ -1,4 +1,4 @@
-import { addModel, delModel, getModel, getModelById, getModelList } from '@/api/iot/model'
+import { addModel, addModelPlugin, debugModelPlugin, delModel, getModel, getModelById, getModelList, getModelPlugin, updateModelPlugin } from '@/api/iot/model'
 import { message } from 'ant-design-vue'
 
 export class ModelController {
@@ -34,4 +34,22 @@ export class ModelController {
       message.success('删除成功')
     }
   }
+
+  static async getPlugin (params: {modelId: string}) {
+    return await getModelPlugin(params)
+  }
+
+  static async postPlugin (data: {modelPluginType: string, modelPluginBody: string, modelId: string}) {
+    await addModelPlugin(data)
+    message.success('保存成功')
+  }
+
+  static async updatePlugin (data: {modelPluginType: string, modelPluginBody: string, modelId: string, id: string}) {
+    await updateModelPlugin(data)
+    message.success('保存成功')
+  }
+
+  static async debugPlugin (data: {input: string, pluginBody: string, decode: boolean}) {
+    return await debugModelPlugin(data)
+  }
 }

+ 131 - 0
src/pages/Iot/model/components/plugins.vue

@@ -0,0 +1,131 @@
+<template>
+  <a-card
+    title='插件脚本'
+  >
+    <div ref="editorRef"></div>
+  </a-card>
+  <a-card
+
+  >
+    <template #title>
+      <a-space>
+        <span>模拟类型</span>
+        <a-select v-model:value="state.decode" style="width: 170px;" >
+          <a-select-option v-for="(item, index) in codeList" :key="index" :value="item.key" >
+            {{item.name}}
+          </a-select-option>
+        </a-select>
+      </a-space>
+    </template>
+    <template #extra >
+      <a-space>
+        <a-button @click="debugPlugin" >调试</a-button>
+        <a-button type="primary" @click="savePlugin" >保存</a-button>
+      </a-space>
+    </template>
+    <a-row>
+      <a-col :span="12" >
+        <a-textarea
+          v-model:value="state.input"
+          :placeholder="placeholder"
+          :auto-size="{ minRows: 8 }"
+        />
+      </a-col>
+      <a-col :span="12" >
+        <a-textarea
+          v-model:value="state.result"
+          :auto-size="{ minRows: 8 }"
+        />
+      </a-col>
+    </a-row>
+  </a-card>
+</template>
+<script lang='ts' setup >
+import { basicSetup } from 'codemirror'
+import { EditorView } from '@codemirror/view'
+import { EditorState, StateEffect } from '@codemirror/state'
+import { javascript } from '@codemirror/lang-javascript'
+import { ref, onMounted, reactive } from 'vue'
+import { ModelCmdController, ModelController } from '@/controller'
+import { useRoute } from 'vue-router'
+import { computed } from '@vue/reactivity'
+
+const placeholder = computed(() => {
+  return state.decode
+    ? "输入JSON字符串,如:{'msg_type':'commands','command_name':'SET_ALARM','service_id':'smokerdector','paras':{'value':'1'}}"
+    : '输入HEX字符,如二进制[0x00, 0x50, 0x00, 0x5a]对应的模拟输入数据为0050005a'
+})
+
+const codeList = [
+  { name: '编码', key: true },
+  { name: '解码', key: false }
+]
+
+const route = useRoute()
+
+const modelId = route.query.id as string
+
+const state = reactive({
+  decode: false,
+  input: '',
+  pluginId: '',
+  modelPluginBody: '',
+  pluginBody: 'function encode(payload) {\n  var jsonObj = {};   return JSON.stringify(jsonObj);\n }\n function decode(json) {\n var payload = [];\n return payload;\n }',
+  result: ''
+})
+
+const debugPlugin = async () => {
+  const { data } = await ModelController.debugPlugin({
+    pluginBody: state.pluginBody,
+    input: state.input,
+    decode: state.decode
+  })
+  console.log(data)
+}
+
+const savePlugin = async () => {
+  const requestFn = state.pluginId ? ModelController.updatePlugin : ModelController.postPlugin
+  await requestFn({
+    modelPluginType: 'JS',
+    modelPluginBody: state.modelPluginBody,
+    modelId,
+    id: state.pluginId
+  })
+}
+
+const getPlugin = async () => {
+  const { data } = await ModelController.getPlugin({ modelId })
+  state.modelPluginBody = data.modelPluginBody
+  state.pluginId = data.id
+  createView()
+}
+
+const editorRef = ref()
+
+onMounted(() => {
+  getPlugin()
+})
+
+const createView = () => {
+  const editorState = EditorState.create({
+    doc: state.modelPluginBody,
+    extensions: [basicSetup, javascript()]
+  })
+
+  const view = new EditorView({
+    state: editorState,
+    parent: editorRef.value
+  })
+}
+
+// codemirror.fromTextArea(
+//   document.getElementById('input'),
+//   {
+//     lineNumbers: true
+//   }
+// )
+// console.log('codemirror:')
+
+</script>
+<style lang='less' scoped >
+</style>

+ 3 - 1
src/pages/Iot/model/detail.vue

@@ -24,6 +24,7 @@
       <a-tab-pane  :key="item.key" :tab="item.label" v-for="item in tabsdata">
         <ModelDefine v-if="state.activeKey === 0"/>
         <OnlineTest v-else-if="state.activeKey === 2" />
+        <Plugins v-else-if="state.activeKey === 1" />
       </a-tab-pane>
     </a-tabs>
   </a-card>
@@ -35,6 +36,7 @@ import { onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'
 import ModelDefine from './components/modelDefine.vue'
 import OnlineTest from './components/onlineTest.vue'
+import Plugins from './components/plugins.vue'
 
 const queryParams = useRoute().query as {id: string}
 
@@ -43,7 +45,7 @@ const state = reactive<{
   activeKey: number
 }>({
   model: null,
-  activeKey: 0
+  activeKey: 1
 })
 
 const tabsdata = [

+ 9 - 0
src/type/iot.d.ts

@@ -25,6 +25,13 @@ declare namespace IOT {
         deleted: boolean,
         tenantId: string
       }
+
+      interface plugin {
+        id: string
+        "modelId": string,
+        "modelPluginType": "JS",
+        "modelPluginBody": string
+      }
     }
 
     namespace MODELATTR {
@@ -65,6 +72,8 @@ declare namespace IOT {
       }
     }
 
+    
+
     namespace DEVICE {
       type QueryPamars = {
         page: number

+ 198 - 6
yarn.lock

@@ -983,6 +983,131 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
+"@codemirror/autocomplete@^6.0.0":
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.6.0.tgz#9c0ea57792b405a391599bd80acae19b8c4c6ff5"
+  integrity sha512-SjbgWSwNKbyQOiVXtG8DXG2z29zTbmzpGccxMqakVo+vqK8fx3Ai0Ee7is3JqX6dxJOoK0GfP3LfeUK53Ltv7w==
+  dependencies:
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.6.0"
+    "@lezer/common" "^1.0.0"
+
+"@codemirror/commands@^6.0.0":
+  version "6.2.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.2.3.tgz#ec476fd588f7a4333f54584d4783dd3862befe3b"
+  integrity sha512-9uf0g9m2wZyrIim1SavcxMdwsu8wc/y5uSw6JRUBYIGWrN+RY4vSru/BqB+MyNWqx4C2uRhQ/Kh7Pw8lAyT3qQ==
+  dependencies:
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.2.0"
+    "@codemirror/view" "^6.0.0"
+    "@lezer/common" "^1.0.0"
+
+"@codemirror/lang-css@^6.0.0":
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-6.2.0.tgz#f84f9da392099432445c75e32fdac63ae572315f"
+  integrity sha512-oyIdJM29AyRPM3+PPq1I2oIk8NpUfEN3kAM05XWDDs6o3gSneIKaVJifT2P+fqONLou2uIgXynFyMUDQvo/szA==
+  dependencies:
+    "@codemirror/autocomplete" "^6.0.0"
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@lezer/common" "^1.0.2"
+    "@lezer/css" "^1.0.0"
+
+"@codemirror/lang-html@^6.0.0":
+  version "6.4.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-6.4.3.tgz#dec78f76d9d0261cbe9f2a3a247a1b546327f700"
+  integrity sha512-VKzQXEC8nL69Jg2hvAFPBwOdZNvL8tMFOrdFwWpU+wc6a6KEkndJ/19R5xSaglNX6v2bttm8uIEFYxdQDcIZVQ==
+  dependencies:
+    "@codemirror/autocomplete" "^6.0.0"
+    "@codemirror/lang-css" "^6.0.0"
+    "@codemirror/lang-javascript" "^6.0.0"
+    "@codemirror/language" "^6.4.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.2.2"
+    "@lezer/common" "^1.0.0"
+    "@lezer/css" "^1.1.0"
+    "@lezer/html" "^1.3.0"
+
+"@codemirror/lang-javascript@^6.0.0", "@codemirror/lang-javascript@^6.1.2", "@codemirror/lang-javascript@^6.1.7":
+  version "6.1.7"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.1.7.tgz#e39fb9757b1cf47de432e4244d18ca5284a73a58"
+  integrity sha512-KXKqxlZ4W6t5I7i2ScmITUD3f/F5Cllk3kj0De9P9mFeYVfhOVOWuDLgYiLpk357u7Xh4dhqjJAnsNPPoTLghQ==
+  dependencies:
+    "@codemirror/autocomplete" "^6.0.0"
+    "@codemirror/language" "^6.6.0"
+    "@codemirror/lint" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    "@lezer/common" "^1.0.0"
+    "@lezer/javascript" "^1.0.0"
+
+"@codemirror/lang-vue@^0.1.1":
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-vue/-/lang-vue-0.1.1.tgz#79567fb3be3f411354cd135af59d67f956cdb042"
+  integrity sha512-GIfc/MemCFKUdNSYGTFZDN8XsD2z0DUY7DgrK34on0dzdZ/CawZbi+SADYfVzWoPPdxngHzLhqlR5pSOqyPCvA==
+  dependencies:
+    "@codemirror/lang-html" "^6.0.0"
+    "@codemirror/lang-javascript" "^6.1.2"
+    "@codemirror/language" "^6.0.0"
+    "@lezer/common" "^1.0.0"
+    "@lezer/highlight" "^1.0.0"
+    "@lezer/lr" "^1.3.1"
+
+"@codemirror/language@^6.0.0", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0":
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.6.0.tgz#2204407174a38a68053715c19e28ad61f491779f"
+  integrity sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==
+  dependencies:
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    "@lezer/common" "^1.0.0"
+    "@lezer/highlight" "^1.0.0"
+    "@lezer/lr" "^1.0.0"
+    style-mod "^4.0.0"
+
+"@codemirror/lint@^6.0.0":
+  version "6.2.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.2.1.tgz#654581d8cc293c315ecfa5c9d61d78c52bbd9ccd"
+  integrity sha512-y1muai5U/uUPAGRyHMx9mHuHLypPcHWxzlZGknp/U5Mdb5Ol8Q5ZLp67UqyTbNFJJ3unVxZ8iX3g1fMN79S1JQ==
+  dependencies:
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    crelt "^1.0.5"
+
+"@codemirror/search@^6.0.0":
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.4.0.tgz#2b256a9e0eaa9317fb48e3cc81eb2735360a59b4"
+  integrity sha512-zMDgaBXah+nMLK2dHz9GdCnGbQu+oaGRXS1qviqNZkvOCv/whp5XZFyoikLp/23PM9RBcbuKUUISUmQHM1eRHw==
+  dependencies:
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    crelt "^1.0.5"
+
+"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.4", "@codemirror/state@^6.2.0":
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.2.0.tgz#a0fb08403ced8c2a68d1d0acee926bd20be922f2"
+  integrity sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==
+
+"@codemirror/theme-one-dark@^6.1.2":
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz#fcef9f9cfc17a07836cb7da17c9f6d7231064df8"
+  integrity sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==
+  dependencies:
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    "@lezer/highlight" "^1.0.0"
+
+"@codemirror/view@^6.0.0", "@codemirror/view@^6.10.1", "@codemirror/view@^6.2.2", "@codemirror/view@^6.6.0":
+  version "6.10.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.10.1.tgz#b840a04db8941084ca88af1552c4678cc2980f37"
+  integrity sha512-Q3FAmkajqcoqBUlfrlD6p58lnuffYxS/6ImIrsLd4SZOZItCBysqAXvQ/OqWxMCyVuDoh5KaNErl9/FDlWM5IA==
+  dependencies:
+    "@codemirror/state" "^6.1.4"
+    style-mod "^4.0.0"
+    w3c-keyname "^2.2.4"
+
 "@ctrl/tinycolor@^3.4.0":
   version "3.6.0"
   resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz#53fa5fe9c34faee89469e48f91d51a3766108bc8"
@@ -1099,6 +1224,50 @@
   resolved "https://registry.npmmirror.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
   integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
 
+"@lezer/common@^1.0.0", "@lezer/common@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.0.2.tgz#8fb9b86bdaa2ece57e7d59e5ffbcb37d71815087"
+  integrity sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==
+
+"@lezer/css@^1.0.0", "@lezer/css@^1.1.0":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@lezer/css/-/css-1.1.1.tgz#c36dcb0789317cb80c3740767dd3b85e071ad082"
+  integrity sha512-mSjx+unLLapEqdOYDejnGBokB5+AiJKZVclmud0MKQOKx3DLJ5b5VTCstgDDknR6iIV4gVrN6euzsCnj0A2gQA==
+  dependencies:
+    "@lezer/highlight" "^1.0.0"
+    "@lezer/lr" "^1.0.0"
+
+"@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3":
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.1.4.tgz#98ed821e89f72981b7ba590474e6ee86c8185619"
+  integrity sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ==
+  dependencies:
+    "@lezer/common" "^1.0.0"
+
+"@lezer/html@^1.3.0":
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/@lezer/html/-/html-1.3.4.tgz#7a5c5498dae6c93aee3de208bfb01aa3a0a932e3"
+  integrity sha512-HdJYMVZcT4YsMo7lW3ipL4NoyS2T67kMPuSVS5TgLGqmaCjEU/D6xv7zsa1ktvTK5lwk7zzF1e3eU6gBZIPm5g==
+  dependencies:
+    "@lezer/common" "^1.0.0"
+    "@lezer/highlight" "^1.0.0"
+    "@lezer/lr" "^1.0.0"
+
+"@lezer/javascript@^1.0.0":
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-1.4.3.tgz#f59e764a0578184c6fb86abb5279a9679777c3ba"
+  integrity sha512-k7Eo9z9B1supZ5cCD4ilQv/RZVN30eUQL+gGbr6ybrEY3avBAL5MDiYi2aa23Aj0A79ry4rJRvPAwE2TM8bd+A==
+  dependencies:
+    "@lezer/highlight" "^1.1.3"
+    "@lezer/lr" "^1.3.0"
+
+"@lezer/lr@^1.0.0", "@lezer/lr@^1.3.0", "@lezer/lr@^1.3.1":
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.3.4.tgz#8795bf2ba4f69b998e8fb4b5a7c57ea68753474c"
+  integrity sha512-7o+e4og/QoC/6btozDPJqnzBhUaD1fMfmvnEKQO1wRRiTse1WxaJ3OMEXZJnkgT6HCcTVOctSoXK9jGJw2oe9g==
+  dependencies:
+    "@lezer/common" "^1.0.0"
+
 "@node-ipc/js-queue@2.0.3":
   version "2.0.3"
   resolved "https://registry.npmmirror.com/@node-ipc/js-queue/-/js-queue-2.0.3.tgz#ac7fe33d766fa53e233ef8fedaf3443a01c5a4cd"
@@ -2647,6 +2816,19 @@ clone@^1.0.2:
   resolved "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
 
+codemirror@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29"
+  integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==
+  dependencies:
+    "@codemirror/autocomplete" "^6.0.0"
+    "@codemirror/commands" "^6.0.0"
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/lint" "^6.0.0"
+    "@codemirror/search" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+
 color-convert@^1.9.0:
   version "1.9.3"
   resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -2840,6 +3022,11 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
     path-type "^4.0.0"
     yaml "^1.10.0"
 
+crelt@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
+  integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==
+
 cross-spawn@^5.0.1:
   version "5.1.0"
   resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -2990,16 +3177,11 @@ csstype@^2.6.8:
   resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e"
   integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
 
-dayjs@^1.10.5:
+dayjs@^1.10.5, dayjs@^1.11.7:
   version "1.11.7"
   resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
   integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
 
-dayjs@^1.11.7:
-  version "1.11.7"
-  resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
-  integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
-
 debug@2.6.9:
   version "2.6.9"
   resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -6672,6 +6854,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
   resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
   integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
 
+style-mod@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.3.tgz#136c4abc905f82a866a18b39df4dc08ec762b1ad"
+  integrity sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==
+
 style-resources-loader@^1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/style-resources-loader/-/style-resources-loader-1.5.0.tgz#6e0585ca475b9dac45387c308be90d74c814f41f"
@@ -7119,6 +7306,11 @@ vue@^3.2.13:
     "@vue/server-renderer" "3.2.47"
     "@vue/shared" "3.2.47"
 
+w3c-keyname@^2.2.4:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.6.tgz#8412046116bc16c5d73d4e612053ea10a189c85f"
+  integrity sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==
+
 warning@^4.0.0:
   version "4.0.3"
   resolved "https://registry.npmmirror.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"