瀏覽代碼

feature: 文档

xiongxt 1 年之前
父節點
當前提交
0f7f564e17
共有 25 個文件被更改,包括 610 次插入20 次删除
  1. 1 0
      .eslintrc.js
  2. 30 0
      lib/flexible.js
  3. 1 0
      lib/index.js
  4. 11 1
      lib/queue.js
  5. 3 0
      package.json
  6. 35 0
      sdk/flexible.ts
  7. 13 0
      sdk/http.ts
  8. 2 0
      sdk/index.ts
  9. 13 1
      sdk/queue.ts
  10. 35 6
      src/App.vue
  11. 31 0
      src/components/block.vue
  12. 35 0
      src/components/leftAside.vue
  13. 32 5
      src/components/navBar.vue
  14. 5 1
      src/main.js
  15. 52 0
      src/router/index.js
  16. 34 0
      src/views/async.vue
  17. 22 0
      src/views/flexible.vue
  18. 34 1
      src/views/queue.vue
  19. 38 0
      src/views/storage.vue
  20. 3 1
      tsconfig.json
  21. 3 0
      types/flexible.d.ts
  22. 1 0
      types/index.d.ts
  23. 3 1
      types/queue.d.ts
  24. 10 1
      vue.config.js
  25. 163 2
      yarn.lock

+ 1 - 0
.eslintrc.js

@@ -29,6 +29,7 @@ const config = {
     "@typescript-eslint/no-var-requires": "off",
     "vue/multi-word-component-names": "off",
     "@typescript-eslint/no-empty-function": "off",
+    "@typescript-eslint/no-unused-vars": "off",
   },
 };
 

+ 30 - 0
lib/flexible.js

@@ -0,0 +1,30 @@
+export function flexible(options) {
+    const docEl = document.documentElement;
+    const dpr = window.devicePixelRatio || 1;
+    function setRemUnit() {
+        let cwidth = docEl.clientWidth;
+        if (options.minWidth) {
+            cwidth = Math.max(cwidth, options.minWidth);
+        }
+        const rem = cwidth / 10;
+        docEl.style.fontSize = rem + "px";
+    }
+    setRemUnit();
+    window.addEventListener("resize", setRemUnit);
+    window.addEventListener("pageshow", function (e) {
+        if (e.persisted) {
+            setRemUnit();
+        }
+    });
+    if (dpr >= 2) {
+        const fakeBody = document.createElement("body");
+        const testElement = document.createElement("div");
+        testElement.style.border = ".5px solid transparent";
+        fakeBody.appendChild(testElement);
+        docEl.appendChild(fakeBody);
+        if (testElement.offsetHeight === 1) {
+            docEl.classList.add("hairlines");
+        }
+        docEl.removeChild(fakeBody);
+    }
+}

+ 1 - 0
lib/index.js

@@ -1,3 +1,4 @@
 export * from "./queue";
 export * from "./async";
 export * from "./storage";
+export * from "./flexible";

+ 11 - 1
lib/queue.js

@@ -3,7 +3,7 @@ class Queue {
     constructor() {
         this.status = "waiting";
     }
-    append(item, autoRun = true) {
+    append(item, autoRun = false) {
         const node = new Node(item);
         if (!this.current || !this.end) {
             this.current = this.end = node;
@@ -19,7 +19,11 @@ class Queue {
     startRun() {
         if (this.status === "waiting") {
             this.run();
+            this._promise = new Promise((resolve) => {
+                this._myResolve = resolve;
+            });
         }
+        return this._promise;
     }
     run() {
         return __awaiter(this, void 0, void 0, function* () {
@@ -32,6 +36,9 @@ class Queue {
                 current.destroy();
                 if (res === false) {
                     this.status = "waiting";
+                    this._myResolve("stopped");
+                    this._promise = undefined;
+                    this._myResolve = undefined;
                 }
                 else {
                     this.run();
@@ -40,6 +47,9 @@ class Queue {
             else {
                 this.end = undefined;
                 this.status = "waiting";
+                this._myResolve("finished");
+                this._promise = undefined;
+                this._myResolve = undefined;
             }
         });
     }

+ 3 - 0
package.json

@@ -16,9 +16,12 @@
   "license": "ISC",
   "dependencies": {
     "amfe-flexible": "^2.2.1",
+    "axios": "^1.4.0",
+    "codemirror": "^6.0.1",
     "core-js": "^3.8.3",
     "reset-css": "^5.0.1",
     "vue": "^3.2.13",
+    "vue-codemirror": "^6.1.1",
     "vue-router": "^4.0.3",
     "vuex": "^4.0.0"
   },

+ 35 - 0
sdk/flexible.ts

@@ -0,0 +1,35 @@
+export function flexible(options: { minWidth?: number }) {
+  const docEl = document.documentElement;
+  const dpr = window.devicePixelRatio || 1;
+
+  function setRemUnit() {
+    let cwidth = docEl.clientWidth;
+    if (options.minWidth) {
+      cwidth = Math.max(cwidth, options.minWidth);
+    }
+    const rem = cwidth / 10;
+    docEl.style.fontSize = rem + "px";
+  }
+
+  setRemUnit();
+
+  window.addEventListener("resize", setRemUnit);
+  window.addEventListener("pageshow", function (e) {
+    if (e.persisted) {
+      setRemUnit();
+    }
+  });
+
+  // detect 0.5px supports
+  if (dpr >= 2) {
+    const fakeBody = document.createElement("body");
+    const testElement = document.createElement("div");
+    testElement.style.border = ".5px solid transparent";
+    fakeBody.appendChild(testElement);
+    docEl.appendChild(fakeBody);
+    if (testElement.offsetHeight === 1) {
+      docEl.classList.add("hairlines");
+    }
+    docEl.removeChild(fakeBody);
+  }
+}

+ 13 - 0
sdk/http.ts

@@ -0,0 +1,13 @@
+import axios from "node_modules/axios/index";
+import type { CreateAxiosDefaults } from "node_modules/axios/index";
+
+export function createHttpInstance(options: CreateAxiosDefaults) {
+  const instance = axios.create({
+    timeout: 10000,
+    ...options,
+  });
+
+  return {
+    instance,
+  };
+}

+ 2 - 0
sdk/index.ts

@@ -1,3 +1,5 @@
 export * from "./queue";
 export * from "./async";
 export * from "./storage";
+export * from "./flexible";
+export * from "./http";

+ 13 - 1
sdk/queue.ts

@@ -2,8 +2,10 @@ class Queue<T extends { run: () => Promise<any> }> {
   private current?: Node<T>;
   private end?: Node<T>;
   private status: "waiting" | "running" = "waiting";
+  private _myResolve?: (v: "finished" | "stopped") => void;
+  private _promise?: Promise<"finished" | "stopped">;
 
-  append(item: T, autoRun = true) {
+  append(item: T, autoRun = false) {
     const node = new Node(item);
     if (!this.current || !this.end) {
       this.current = this.end = node;
@@ -20,7 +22,11 @@ class Queue<T extends { run: () => Promise<any> }> {
   startRun() {
     if (this.status === "waiting") {
       this.run();
+      this._promise = new Promise<"finished" | "stopped">((resolve) => {
+        this._myResolve = resolve;
+      });
     }
+    return this._promise;
   }
 
   async run() {
@@ -33,12 +39,18 @@ class Queue<T extends { run: () => Promise<any> }> {
       current.destroy();
       if (res === false) {
         this.status = "waiting";
+        this._myResolve("stopped");
+        this._promise = undefined;
+        this._myResolve = undefined;
       } else {
         this.run();
       }
     } else {
       this.end = undefined;
       this.status = "waiting";
+      this._myResolve("finished");
+      this._promise = undefined;
+      this._myResolve = undefined;
     }
   }
 }

+ 35 - 6
src/App.vue

@@ -1,17 +1,18 @@
 <template>
   <div id="app">
     <nav-bar />
-    <div>
-      <div></div>
-      <div><router-view /></div>
+    <div class="wrap">
+      <left-aside class="menu"></left-aside>
+      <div class="right"><router-view /></div>
     </div>
   </div>
 </template>
 
 <script>
 import NavBar from "@/components/navBar.vue";
+import LeftAside from "@/components/leftAside.vue";
 export default {
-  components: { NavBar },
+  components: { NavBar, LeftAside },
   setup() {},
 };
 </script>
@@ -23,7 +24,35 @@ body {
     Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
+  color: #444;
+}
+
+body {
+  font-size: 14px !important;
+  /* prettier-ignore */
+  min-width: 700PX;
+}
+</style>
+
+<style lang="less" scoped>
+#app {
+  .wrap {
+    display: flex;
+    align-items: stretch;
+    min-height: calc(100vh - 80px);
+    .menu {
+      width: 200px;
+      border-right: 1px solid #eee;
+      padding: 20px 0 0 20px;
+      box-sizing: border-box;
+      flex-shrink: 0;
+    }
+    .right {
+      flex-grow: 1;
+      padding: 20px;
+      flex-shrink: 0;
+      box-sizing: border-box;
+    }
+  }
 }
 </style>

+ 31 - 0
src/components/block.vue

@@ -0,0 +1,31 @@
+<template>
+  <div>
+    <h3>{{ title }}</h3>
+    <p class="desc">{{ desc }}</p>
+    <div><slot /></div>
+  </div>
+</template>
+
+<script setup>
+const props = defineProps({
+  title: String,
+  desc: String,
+});
+</script>
+
+<style lang="less" scoped>
+h3 {
+  font-size: 24px;
+  padding-bottom: 20px;
+  border-bottom: 1px solid #eee;
+  margin-bottom: 20px;
+}
+
+.desc {
+  color: #666;
+}
+
+div {
+  margin: 20px 0;
+}
+</style>

+ 35 - 0
src/components/leftAside.vue

@@ -0,0 +1,35 @@
+<template>
+  <ul class="left-aside">
+    <li>
+      <RouterLink to="/sdk/queue">Queue队列</RouterLink>
+    </li>
+    <li><RouterLink to="/sdk/async">Async异步</RouterLink></li>
+    <li><RouterLink to="/sdk/storage">Storage</RouterLink></li>
+    <li><RouterLink to="/sdk/flexible">flexible</RouterLink></li>
+    <li><RouterLink to="/sdk/http">Http请求</RouterLink></li>
+  </ul>
+</template>
+
+<script>
+export default {
+  name: "LeftAside",
+  setup() {},
+};
+</script>
+
+<style lang="less" scoped>
+.left-aside {
+  > li {
+    padding: 6px 0;
+    > a {
+      font-size: 13px;
+      color: #999;
+      text-decoration: none;
+    }
+    .router-link-active {
+      color: @primary-color;
+      font-weight: bold;
+    }
+  }
+}
+</style>

+ 32 - 5
src/components/navBar.vue

@@ -2,21 +2,48 @@
   <div class="nav-bar">
     <div class="logo">
       <h1>Ludash</h1>
-      <p>一些常用的SDK</p>
     </div>
-    <div></div>
+    <div class="menu">
+      <RouterLink to="/sdk">SDK</RouterLink>
+    </div>
   </div>
 </template>
 
 <style lang="less" scoped>
 .nav-bar {
-  height: 60px;
-  border-bottom: 1px solid #ccc;
+  border-bottom: 1px solid #eee;
   display: flex;
   align-items: center;
-  padding: 0 20px;
+  padding: 20px;
+  > * {
+    flex-shrink: 0;
+  }
   .logo {
     display: flex;
+    align-items: baseline;
+    flex-grow: 1;
+    h1 {
+      font-weight: bold;
+      font-size: 24px;
+      color: @primary-color;
+    }
+    p {
+      padding-left: 10px;
+      font-size: 0.6em;
+      color: #999;
+    }
+  }
+
+  .menu {
+    > a {
+      text-decoration: none;
+      color: @font-color;
+      margin-left: 10px;
+    }
+    .router-link-active {
+      color: @primary-color;
+      font-weight: bold;
+    }
   }
 }
 </style>

+ 5 - 1
src/main.js

@@ -2,7 +2,11 @@ import { createApp } from "vue";
 import App from "./App.vue";
 import router from "./router";
 import store from "./store";
-import "amfe-flexible";
+import { flexible } from "../lib";
 import "reset-css";
 
+import "axios";
+
+flexible({ minWidth: 700 });
+
 createApp(App).use(store).use(router).mount("#app");

+ 52 - 0
src/router/index.js

@@ -1,5 +1,9 @@
 import { createRouter, createWebHistory } from "vue-router";
+import { defineComponent } from "vue";
 
+/**
+ * @type {import("vue-router").RouteRecordRaw[]}
+ */
 const routes = [
   {
     path: "/",
@@ -7,6 +11,54 @@ const routes = [
     component: () =>
       import(/* webpackChunkName: "about" */ "../views/queue.vue"),
   },
+  {
+    path: "/sdk",
+    name: "sdk",
+    component: defineComponent({
+      name: "DynamicComponent",
+      render() {
+        return <router-view></router-view>;
+      },
+    }),
+    children: [
+      {
+        path: "queue",
+        name: "queue",
+        component: () =>
+          import(/* webpackChunkName: "queue" */ "../views/queue.vue"),
+      },
+      {
+        path: "async",
+        name: "async",
+        component: () =>
+          import(/* webpackChunkName: "async" */ "../views/async.vue"),
+      },
+      {
+        path: "storage",
+        name: "storage",
+        component: () =>
+          import(/* webpackChunkName: "storage" */ "../views/storage.vue"),
+      },
+      {
+        path: "flexible",
+        name: "flexible",
+        component: () =>
+          import(/* webpackChunkName: "flexible" */ "../views/flexible.vue"),
+      },
+      {
+        path: "",
+        redirect: {
+          name: "queue",
+        },
+      },
+      {
+        path: "/:pathMatch(.*)",
+        redirect: {
+          name: "queue",
+        },
+      },
+    ],
+  },
 ];
 
 const router = createRouter({

+ 34 - 0
src/views/async.vue

@@ -0,0 +1,34 @@
+<template>
+  <div>
+    <Block
+      title="Async"
+      desc="这里主要是异步遍历的函数集合,函数会等待上一次异步结束才会开始下一个"
+    >
+      <p>DEMO</p>
+      <Codemirror v-model="code" :disabled="true" />
+    </Block>
+  </div>
+</template>
+
+<script setup>
+import Block from "@/components/block.vue";
+import { ref } from "vue";
+import { Codemirror } from "vue-codemirror";
+
+const code = ref(`import { asyncWhile, asyncForEach, nextTick } from "ludash";
+
+asyncForEach([1, 2, 3, 4, 5], async (it, index) => {
+  await nextTick(1000);
+  console.log(it, index);
+  // return false 则会中断执行
+  return true;
+});
+
+asyncWhile(
+  // checker 这是判断函数
+  async (index) => index < 10,
+  async (index) => {
+    console.log(index);
+  }
+);`);
+</script>

+ 22 - 0
src/views/flexible.vue

@@ -0,0 +1,22 @@
+<template>
+  <div>
+    <Block
+      title="flexible"
+      desc="amfe-flexible代码变种,取消了body的font-size,新增了配置最低宽度的选项"
+    >
+      <p>DEMO</p>
+      <Codemirror v-model="code" :disabled="true" />
+    </Block>
+  </div>
+</template>
+
+<script setup>
+import Block from "@/components/block.vue";
+import { ref } from "vue";
+import { Codemirror } from "vue-codemirror";
+
+const code = ref(`import { flexible } from "ludash";
+
+// 最低700px,低于700px按宽度为700计算html的fontSize
+flexible({ minWidth: 700 });`);
+</script>

+ 34 - 1
src/views/queue.vue

@@ -1,3 +1,36 @@
 <template>
-  <div>this is queue</div>
+  <div>
+    <Block
+      title="Queue"
+      desc="这个函数用于创建一个promise队列,并按加入顺序执行"
+    >
+      <p>DEMO</p>
+      <Codemirror v-model="code" :disabled="true" />
+    </Block>
+  </div>
 </template>
+
+<script setup>
+import Block from "@/components/block.vue";
+import { ref } from "vue";
+import { Codemirror } from "vue-codemirror";
+
+const code = ref(`import { Queue, nextTick } from "ludash";
+
+const q = new Queue();
+
+for (let index = 0; index < 10; index++) {
+  q.append({
+    async run() {
+      await nextTick(1000)
+      // 如果return false,队列则会暂停
+      // 直到下一次调用startRun才会重新开始
+      return true
+    },
+  });
+}
+
+// finished | stopped
+const status = await q.startRun();
+console.log(status === "finished")`);
+</script>

+ 38 - 0
src/views/storage.vue

@@ -0,0 +1,38 @@
+<template>
+  <div>
+    <Block
+      title="Storage"
+      desc="将浏览器的LocalStorage和SessionStorage重新包装了一下"
+    >
+      <p>DEMO</p>
+      <Codemirror v-model="code" :disabled="true" />
+    </Block>
+  </div>
+</template>
+
+<script setup>
+import Block from "@/components/block.vue";
+import { ref } from "vue";
+import { Codemirror } from "vue-codemirror";
+
+const code = ref(`import { StorageAdapter } from "ludash";
+
+// 根据sessionStorage
+const store = StorageAdapter.session;
+// 根据LocalStorage
+// const store = StorageAdapter.local;
+
+// 自动执行JSON.stringify()
+store.setItem("userInfo", {
+  id: 123,
+  name: "123",
+  token: "123123",
+});
+
+// 自动转为json
+const userInfo = store.getItem("userInfo");
+
+store.removeItem("userInfo");
+
+store.clear();`);
+</script>

+ 3 - 1
tsconfig.json

@@ -11,8 +11,10 @@
     "skipLibCheck": true, 
     "importHelpers": true,     
     "forceConsistentCasingInFileNames": true,
+    "noUnusedLocals": true,
     "paths": {
-      "tslib" : ["node_modules/tslib/tslib.d.ts"]
+      "tslib" : ["node_modules/tslib/tslib.d.ts"],
+      "@/*": ["src/*"]
     }
   },
   "include": ["sdk/**/*.ts"],

+ 3 - 0
types/flexible.d.ts

@@ -0,0 +1,3 @@
+export declare function flexible(options: {
+    minWidth?: number;
+}): void;

+ 1 - 0
types/index.d.ts

@@ -1,3 +1,4 @@
 export * from "./queue";
 export * from "./async";
 export * from "./storage";
+export * from "./flexible";

+ 3 - 1
types/queue.d.ts

@@ -4,8 +4,10 @@ declare class Queue<T extends {
     private current?;
     private end?;
     private status;
+    private _myResolve?;
+    private _promise?;
     append(item: T, autoRun?: boolean): void;
-    startRun(): void;
+    startRun(): Promise<"finished" | "stopped">;
     run(): Promise<void>;
 }
 export { Queue };

+ 10 - 1
vue.config.js

@@ -4,6 +4,15 @@ module.exports = defineConfig({
   transpileDependencies: true,
   css: {
     loaderOptions: {
+      less: {
+        lessOptions: {
+          javascriptEnabled: true,
+          modifyVars: {
+            "primary-color": "#42b883",
+            "font-color": "#444",
+          },
+        },
+      },
       postcss: {
         postcssOptions: {
           plugins: [
@@ -19,7 +28,7 @@ module.exports = defineConfig({
               grid: true,
             }),
             require("postcss-pxtorem")({
-              rootValue: 192, //设计稿宽度%10 比如 1920
+              rootValue: 140, //设计稿宽度%10 比如 1920
               exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module|src)/
               propList: ["*"], //是一个存储哪些将被转换的属性列表,这里设置为["*"]全部,假设需要仅对边框进行设置,可以写]['*','!border*']
               //selectorBlackList :['.box'],//,那例如fs-xl类名,里面有关px的样式将不被转换,这里也支持正则写法。

+ 163 - 2
yarn.lock

@@ -1022,6 +1022,70 @@
     "@babel/helper-validator-identifier" "^7.22.5"
     to-fast-properties "^2.0.0"
 
+"@codemirror/autocomplete@^6.0.0":
+  version "6.8.1"
+  resolved "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.8.1.tgz#3f3daa9f591186901db07f58d17256656242e841"
+  integrity sha512-HpphvDcTdOx+9R3eUw9hZK9JA77jlaBF0kOt2McbyfvY0rX9pnMoO8rkkZc0GzSbzhIY4m5xJ0uHHgjfqHNmXQ==
+  dependencies:
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.6.0"
+    "@lezer/common" "^1.0.0"
+
+"@codemirror/commands@6.x", "@codemirror/commands@^6.0.0":
+  version "6.2.4"
+  resolved "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.2.4.tgz#b8a0e5ce72448c092ba4c4b1d902e6f183948aec"
+  integrity sha512-42lmDqVH0ttfilLShReLXsDfASKLXzfyC36bzwcqzox9PlHulMcsUOfHXNo2X2aFMVNUoQ7j+d4q5bnfseYoOA==
+  dependencies:
+    "@codemirror/language" "^6.0.0"
+    "@codemirror/state" "^6.2.0"
+    "@codemirror/view" "^6.0.0"
+    "@lezer/common" "^1.0.0"
+
+"@codemirror/language@6.x", "@codemirror/language@^6.0.0":
+  version "6.8.0"
+  resolved "https://registry.npmmirror.com/@codemirror/language/-/language-6.8.0.tgz#f2d7eea6b338c25593d800f2293b062d9f9856db"
+  integrity sha512-r1paAyWOZkfY0RaYEZj3Kul+MiQTEbDvYqf8gPGaRvNneHXCmfSaAVFjwRUPlgxS8yflMxw2CTu6uCMp8R8A2g==
+  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.3.0"
+  resolved "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.3.0.tgz#bd36fb85094cf5735e5426e48f1a8e575a7b70df"
+  integrity sha512-tzxOVQNoDhhwFNfcTO2IB74wQoWarARcH6gv3YufPpiJ9yhcb7zD6JCkO5+FWARskqRFc8GFa6E+wUyOvADl5A==
+  dependencies:
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    crelt "^1.0.5"
+
+"@codemirror/search@^6.0.0":
+  version "6.5.0"
+  resolved "https://registry.npmmirror.com/@codemirror/search/-/search-6.5.0.tgz#308f9968434e0e6ed59c9ec36a0239eb1dfc5d92"
+  integrity sha512-64/M40YeJPToKvGO6p3fijo2vwUEj4nACEAXElCaYQ50HrXSvRaK+NHEhSh73WFBGdvIdhrV+lL9PdJy2RfCYA==
+  dependencies:
+    "@codemirror/state" "^6.0.0"
+    "@codemirror/view" "^6.0.0"
+    crelt "^1.0.5"
+
+"@codemirror/state@6.x", "@codemirror/state@^6.0.0", "@codemirror/state@^6.1.4", "@codemirror/state@^6.2.0":
+  version "6.2.1"
+  resolved "https://registry.npmmirror.com/@codemirror/state/-/state-6.2.1.tgz#6dc8d8e5abb26b875e3164191872d69a5e85bd73"
+  integrity sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw==
+
+"@codemirror/view@6.x", "@codemirror/view@^6.0.0", "@codemirror/view@^6.6.0":
+  version "6.14.0"
+  resolved "https://registry.npmmirror.com/@codemirror/view/-/view-6.14.0.tgz#a8ecb0216d6f81aeb20bf8b0cbbc7ed563cf0777"
+  integrity sha512-I263FPs4In42MNmrdwN2DfmYPFMVMXgT7o/mxdGp4jv5LPs8i0FOxzmxF5yeeQdYSTztb2ZhmPIu0ahveInVTg==
+  dependencies:
+    "@codemirror/state" "^6.1.4"
+    style-mod "^4.0.0"
+    w3c-keyname "^2.2.4"
+
 "@discoveryjs/json-ext@0.5.7":
   version "0.5.7"
   resolved "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
@@ -1130,6 +1194,25 @@
   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":
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/@lezer/common/-/common-1.0.3.tgz#1808f70e2b0a7b1fdcbaf5c074723d2d4ed1e4c5"
+  integrity sha512-JH4wAXCgUOcCGNekQPLhVeUtIqjH0yPBs7vvUdSjyQama9618IOKFJwkv2kcqdhF0my8hQEgCTEJU0GIgnahvA==
+
+"@lezer/highlight@^1.0.0":
+  version "1.1.6"
+  resolved "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.1.6.tgz#87e56468c0f43c2a8b3dc7f0b7c2804b34901556"
+  integrity sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==
+  dependencies:
+    "@lezer/common" "^1.0.0"
+
+"@lezer/lr@^1.0.0":
+  version "1.3.7"
+  resolved "https://registry.npmmirror.com/@lezer/lr/-/lr-1.3.7.tgz#e3012c74512a063098eb9da86d4cc689170e1f92"
+  integrity sha512-ssHKb3p0MxhJXT2i7UBmgAY1BIM3Uq/D772Qutu3EVmxWIyNMU12nQ0rL3Fhu+MiFtiTzyTmd3xGwEf3ON5PSA==
+  dependencies:
+    "@lezer/common" "^1.0.0"
+
 "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
   version "5.1.1-v1"
   resolved "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
@@ -2144,6 +2227,11 @@ async@^2.6.4:
   dependencies:
     lodash "^4.17.14"
 
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
 at-least-node@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
@@ -2161,6 +2249,15 @@ autoprefixer@^10.2.4, autoprefixer@^10.4.14:
     picocolors "^1.0.0"
     postcss-value-parser "^4.2.0"
 
+axios@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
+  integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
+  dependencies:
+    follow-redirects "^1.15.0"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
 babel-loader@^8.2.2:
   version "8.3.0"
   resolved "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8"
@@ -2493,6 +2590,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.npmmirror.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"
@@ -2527,6 +2637,13 @@ colorette@^2.0.10:
   resolved "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
   integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
 
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
 commander@^2.20.0:
   version "2.20.3"
   resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -2658,6 +2775,11 @@ cosmiconfig@^7.0.0:
     path-type "^4.0.0"
     yaml "^1.10.0"
 
+crelt@^1.0.5:
+  version "1.0.6"
+  resolved "https://registry.npmmirror.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
+  integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
+
 cross-spawn@^5.0.1:
   version "5.1.0"
   resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -2866,6 +2988,11 @@ define-properties@^1.1.4:
     has-property-descriptors "^1.0.0"
     object-keys "^1.1.1"
 
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
 depd@2.0.0:
   version "2.0.0"
   resolved "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
@@ -3465,11 +3592,20 @@ flatted@^3.1.0:
   resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
   integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
 
-follow-redirects@^1.0.0:
+follow-redirects@^1.0.0, follow-redirects@^1.15.0:
   version "1.15.2"
   resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
   integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
 
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
 forwarded@0.2.0:
   version "0.2.0"
   resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -4387,7 +4523,7 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
   resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
   integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
-mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
+mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
   version "2.1.35"
   resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
   integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@@ -5192,6 +5328,11 @@ proxy-addr@~2.0.7:
     forwarded "0.2.0"
     ipaddr.js "1.9.1"
 
+proxy-from-env@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
 prr@~1.0.1:
   version "1.0.1"
   resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -5824,6 +5965,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.npmmirror.com/style-mod/-/style-mod-4.0.3.tgz#136c4abc905f82a866a18b39df4dc08ec762b1ad"
+  integrity sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==
+
 stylehacks@^5.1.1:
   version "5.1.1"
   resolved "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9"
@@ -6113,6 +6259,16 @@ vary@~1.1.2:
   resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
   integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
 
+vue-codemirror@^6.1.1:
+  version "6.1.1"
+  resolved "https://registry.npmmirror.com/vue-codemirror/-/vue-codemirror-6.1.1.tgz#246697ef4cfa6b2448dd592ade214bb7ff86611f"
+  integrity sha512-rTAYo44owd282yVxKtJtnOi7ERAcXTeviwoPXjIc6K/IQYUsoDkzPvw/JDFtSP6T7Cz/2g3EHaEyeyaQCKoDMg==
+  dependencies:
+    "@codemirror/commands" "6.x"
+    "@codemirror/language" "6.x"
+    "@codemirror/state" "6.x"
+    "@codemirror/view" "6.x"
+
 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#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
@@ -6191,6 +6347,11 @@ vuex@^4.0.0:
   dependencies:
     "@vue/devtools-api" "^6.0.0-beta.11"
 
+w3c-keyname@^2.2.4:
+  version "2.2.8"
+  resolved "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"
+  integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
+
 watchpack@^2.4.0:
   version "2.4.0"
   resolved "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"