From 8c9cd079b783e75cf889668069178b9d97af74ea Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 00:03:07 +0530 Subject: [PATCH 01/73] feat: init codemirror --- components/smart/CodeMirror.vue | 85 +++++++++++++++++++++++++++++++++ package-lock.json | 11 +++++ package.json | 1 + 3 files changed, 97 insertions(+) create mode 100644 components/smart/CodeMirror.vue diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue new file mode 100644 index 000000000..f4dfc315f --- /dev/null +++ b/components/smart/CodeMirror.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/package-lock.json b/package-lock.json index 13bea05f5..bb3502c93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "ace-builds": "^1.4.12", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", + "codemirror": "^5.62.3", "core-js": "^3.16.4", "esprima": "^4.0.1", "firebase": "^9.0.0", @@ -13065,6 +13066,11 @@ "node": ">=0.10.0" } }, + "node_modules/codemirror": { + "version": "5.62.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", + "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -46032,6 +46038,11 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "codemirror": { + "version": "5.62.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", + "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", diff --git a/package.json b/package.json index 1bfe4b707..867955c4f 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "ace-builds": "^1.4.12", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", + "codemirror": "^5.62.3", "core-js": "^3.16.4", "esprima": "^4.0.1", "firebase": "^9.0.0", From 15373be63e6a73964128fd382a097aeb1e9d5b85 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 10:47:00 +0530 Subject: [PATCH 02/73] refactor: ts codemirror --- components/smart/CodeMirror.vue | 108 +++++++++++++++----------------- package-lock.json | 49 +++++++++++++++ package.json | 1 + 3 files changed, 102 insertions(+), 56 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index f4dfc315f..f29fe92a3 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -2,84 +2,80 @@
- - diff --git a/package-lock.json b/package-lock.json index bb3502c93..f309be5db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "@nuxtjs/stylelint-module": "^4.0.0", "@nuxtjs/svg": "^0.2.0", "@testing-library/jest-dom": "^5.14.1", + "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", "@types/lodash": "^4.14.172", "@types/lunr": "^2.3.4", @@ -7891,6 +7892,15 @@ "node": ">=0.10.0" } }, + "node_modules/@types/codemirror": { + "version": "5.60.2", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.2.tgz", + "integrity": "sha512-tk8YxckrdU49GaJYRKxdzzzXrTlyT2nQGnobb8rAk34jt+kYXOxPKGqNgr7SJpl5r6YGaRD4CDfqiL+6A+/z7w==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", @@ -7940,6 +7950,12 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "node_modules/@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, "node_modules/@types/etag": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@types/etag/-/etag-1.8.0.tgz", @@ -8330,6 +8346,15 @@ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, + "node_modules/@types/tern": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", + "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/terser-webpack-plugin": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-4.2.1.tgz", @@ -41813,6 +41838,15 @@ } } }, + "@types/codemirror": { + "version": "5.60.2", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.2.tgz", + "integrity": "sha512-tk8YxckrdU49GaJYRKxdzzzXrTlyT2nQGnobb8rAk34jt+kYXOxPKGqNgr7SJpl5r6YGaRD4CDfqiL+6A+/z7w==", + "dev": true, + "requires": { + "@types/tern": "*" + } + }, "@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", @@ -41862,6 +41896,12 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, "@types/etag": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@types/etag/-/etag-1.8.0.tgz", @@ -42252,6 +42292,15 @@ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, + "@types/tern": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", + "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "@types/terser-webpack-plugin": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-4.2.1.tgz", diff --git a/package.json b/package.json index 867955c4f..59182f6aa 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@nuxtjs/stylelint-module": "^4.0.0", "@nuxtjs/svg": "^0.2.0", "@testing-library/jest-dom": "^5.14.1", + "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", "@types/lodash": "^4.14.172", "@types/lunr": "^2.3.4", From e2b1c83698614e5a5a49da845c5c5f1f15b8b7e8 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 16:10:35 +0530 Subject: [PATCH 03/73] feat: line wrap, auto close brackets, placeholder on codemirror --- components/smart/CodeMirror.vue | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index f29fe92a3..292732f11 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -9,14 +9,10 @@ import "codemirror/lib/codemirror.css" import "codemirror/theme/juejin.css" -import "codemirror/addon/fold/foldgutter.css" -import "codemirror/addon/fold/foldgutter" -import "codemirror/addon/fold/brace-fold" -import "codemirror/addon/fold/comment-fold" -import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" - -import "codemirror/mode/javascript/javascript" +import "codemirror/addon/selection/active-line" +import "codemirror/addon/edit/closebrackets" +import "codemirror/addon/display/placeholder" import { onMounted, ref, watch } from "@nuxtjs/composition-api" @@ -25,6 +21,8 @@ const DEFAULT_THEME = "juejin" const props = defineProps<{ value: string mode: string + placeholder: string + wrap: boolean }>() const emit = defineEmits<{ @@ -53,14 +51,17 @@ onMounted(() => { cm.value = Codemirror(editor.value, { value: props.value, mode: props.mode, + lineWrapping: props.wrap, + placeholder: props.placeholder, autoRefresh: true, lineNumbers: true, - foldGutter: true, + styleActiveLine: true, + autoCloseBrackets: true, theme: DEFAULT_THEME, - gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + gutters: ["CodeMirror-linenumbers"], }) - cm.value?.on("change", (instance) => { - const val = instance.getValue() + cm.value?.on("change", (cm) => { + const val = cm.getValue() emit("input", val) }) }) @@ -73,6 +74,7 @@ onMounted(() => { @apply border-dividerLight; @apply w-full; @apply h-auto; + @apply font-mono; } .CodeMirror-scroll { From 86489d95c2c3dcdfc05006cb222adcf69eb6fe7a Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Tue, 31 Aug 2021 22:20:42 +0530 Subject: [PATCH 04/73] refactor: extract common codemirror logic out to composable --- components/smart/CodeMirror.vue | 49 ++++------------------- helpers/editor/codemirror.ts | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 41 deletions(-) create mode 100644 helpers/editor/codemirror.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 292732f11..6068778c8 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -3,20 +3,10 @@ diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts new file mode 100644 index 000000000..9a282979f --- /dev/null +++ b/helpers/editor/codemirror.ts @@ -0,0 +1,69 @@ +import CodeMirror from "codemirror" + +import "codemirror/theme/juejin.css" + +import "codemirror/lib/codemirror.css" + +import "codemirror/addon/fold/foldgutter.css" +import "codemirror/addon/fold/foldgutter" +import "codemirror/addon/fold/brace-fold" +import "codemirror/addon/fold/comment-fold" +import "codemirror/addon/fold/indent-fold" +import "codemirror/addon/display/autorefresh" + +import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" + +const DEFAULT_THEME = "juejin" + +const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { + theme: DEFAULT_THEME, + autoRefresh: true, + lineNumbers: true, + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], +} + +/** + * A Vue composable to mount and use Codemirror + * + * NOTE: Make sure to import all the necessary Codemirror modules, + * as this function doesn't import any other than the core + * @param el Reference to the dom node to attach to + * @param value Reference to value to read/write to + * @param options CodeMirror options to pass + */ +export function useCodemirror( + el: Ref, + value: Ref, + options: CodeMirror.EditorConfiguration +) { + const cm = ref(null) + + // Boot-up CodeMirror, set the value and listeners + onMounted(() => { + cm.value = CodeMirror(el.value!, { ...DEFAULT_EDITOR_CONFIG, ...options }) + cm.value.setValue(value.value) + + cm.value.on("change", (instance) => { + // External update propagation (via watchers) should be ignored + if (instance.getValue() !== value.value) { + value.value = instance.getValue() + } + }) + }) + + // Watch value updates + watch(value, (newVal) => { + // Check if we are mounted + if (cm.value) { + // Don't do anything on internal updates + if (cm.value.getValue() !== newVal) { + cm.value.setValue(newVal) + } + } + }) + + return { + cm, + } +} From e47ad946660c7f2c70d1994e19bd87662e4b00ae Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:34:02 +0530 Subject: [PATCH 05/73] refactor: add types for esprima --- package-lock.json | 19 +++++++++++++++++++ package.json | 1 + 2 files changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index ee7fdab33..a456b63a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "@testing-library/jest-dom": "^5.14.1", "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", + "@types/esprima": "^4.0.3", "@types/lodash": "^4.14.172", "@types/lunr": "^2.3.4", "@types/splitpanes": "^2.2.1", @@ -7951,6 +7952,15 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "node_modules/@types/esprima": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/esprima/-/esprima-4.0.3.tgz", + "integrity": "sha512-jo14dIWVVtF0iMsKkYek6++4cWJjwpvog+rchLulwgFJGTXqIeTdCOvY0B3yMLTaIwMcKCdJ6mQbSR6wYHy98A==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", @@ -41912,6 +41922,15 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "@types/esprima": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/esprima/-/esprima-4.0.3.tgz", + "integrity": "sha512-jo14dIWVVtF0iMsKkYek6++4cWJjwpvog+rchLulwgFJGTXqIeTdCOvY0B3yMLTaIwMcKCdJ6mQbSR6wYHy98A==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", diff --git a/package.json b/package.json index f1b22c2d9..45a291014 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@testing-library/jest-dom": "^5.14.1", "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", + "@types/esprima": "^4.0.3", "@types/lodash": "^4.14.172", "@types/lunr": "^2.3.4", "@types/splitpanes": "^2.2.1", From 52765568379d6c2620275ad5715cd3d9ca1c867b Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:41:14 +0530 Subject: [PATCH 06/73] feat: codemirror linting system --- components/smart/CodeMirror.vue | 24 +++++++++++++++++------- helpers/editor/codemirror.ts | 19 +++++++++++++++++-- helpers/editor/linting/linter.ts | 7 +++++++ helpers/editor/utils.ts | 23 +++++++++++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 helpers/editor/linting/linter.ts create mode 100644 helpers/editor/utils.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 6068778c8..3cf602030 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -7,13 +7,20 @@ import "codemirror/mode/javascript/javascript" import { ref, watch } from "@nuxtjs/composition-api" import { useCodemirror } from "~/helpers/editor/codemirror" +import { LinterDefinition } from "~/helpers/editor/linting/linter" -const props = defineProps<{ - value: string - mode: string - placeholder: string - wrap: boolean -}>() +const props = withDefaults( + defineProps<{ + value: string + mode: string + placeholder: string + wrap: boolean + linter: LinterDefinition | null + }>(), + { + linter: null as any, + } +) const emit = defineEmits<{ (e: "input", value: string): void @@ -30,7 +37,10 @@ watch(value, (val) => emit("input", val)) const editor = ref(null) useCodemirror(editor, value, { - mode: props.mode, + extendedEditorConfig: { + mode: props.mode, + }, + linter: props.linter, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 9a282979f..49969267f 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -3,6 +3,7 @@ import CodeMirror from "codemirror" import "codemirror/theme/juejin.css" import "codemirror/lib/codemirror.css" +import "codemirror/addon/lint/lint.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -10,11 +11,18 @@ import "codemirror/addon/fold/brace-fold" import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" +import "codemirror/addon/lint/lint" import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" +import { LinterDefinition } from "./linting/linter" const DEFAULT_THEME = "juejin" +type CodeMirrorOptions = { + extendedEditorConfig: CodeMirror.EditorConfiguration + linter: LinterDefinition | null +} + const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { theme: DEFAULT_THEME, autoRefresh: true, @@ -35,15 +43,22 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { export function useCodemirror( el: Ref, value: Ref, - options: CodeMirror.EditorConfiguration + options: CodeMirrorOptions ) { const cm = ref(null) // Boot-up CodeMirror, set the value and listeners onMounted(() => { - cm.value = CodeMirror(el.value!, { ...DEFAULT_EDITOR_CONFIG, ...options }) + cm.value = CodeMirror(el.value!, { + ...DEFAULT_EDITOR_CONFIG, + ...options.extendedEditorConfig, + }) cm.value.setValue(value.value) + if (options.linter) { + cm.value.setOption("lint", options.linter) + } + cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored if (instance.getValue() !== value.value) { diff --git a/helpers/editor/linting/linter.ts b/helpers/editor/linting/linter.ts new file mode 100644 index 000000000..704270cbe --- /dev/null +++ b/helpers/editor/linting/linter.ts @@ -0,0 +1,7 @@ +export type LinterResult = { + message: string + severity: "warning" | "error" + from: { line: number; ch: number } + to: { line: number; ch: number } +} +export type LinterDefinition = (text: string) => Promise diff --git a/helpers/editor/utils.ts b/helpers/editor/utils.ts new file mode 100644 index 000000000..18b311765 --- /dev/null +++ b/helpers/editor/utils.ts @@ -0,0 +1,23 @@ +export function convertIndexToLineCh( + text: string, + i: number +): { line: number; ch: number } { + const lines = text.split("/n") + + let line = 0 + let counter = 0 + + while (line < lines.length) { + if (i > lines[line].length + counter) { + counter += lines[line].length + 1 + line++ + } else { + return { + line: line + 1, + ch: i - counter + 1, + } + } + } + + throw new Error("Invalid input") +} From 3addfe8d4b49a79f1593f2d94e0e3ec2959a165f Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:45:49 +0530 Subject: [PATCH 07/73] feat: linter for prerequest and testscripts --- helpers/editor/linting/preRequest.ts | 69 ++++++++++++++++++++++++++++ helpers/editor/linting/testScript.ts | 69 ++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 helpers/editor/linting/preRequest.ts create mode 100644 helpers/editor/linting/testScript.ts diff --git a/helpers/editor/linting/preRequest.ts b/helpers/editor/linting/preRequest.ts new file mode 100644 index 000000000..db42d9864 --- /dev/null +++ b/helpers/editor/linting/preRequest.ts @@ -0,0 +1,69 @@ +import * as esprima from "esprima" +import { LinterDefinition, LinterResult } from "./linter" +import { performPreRequestLinting } from "~/helpers/tern" + +const linter: LinterDefinition = async (text) => { + let results: LinterResult[] = [] + + // Semantic linting + const semanticLints = await performPreRequestLinting(text) + + results = results.concat( + semanticLints.map((lint: any) => ({ + from: lint.from, + to: lint.to, + severity: "error", + message: `[semantic] ${lint.message}`, + })) + ) + + // Syntax linting + try { + const res: any = esprima.parseScript(text, { tolerant: true }) + if (res.errors && res.errors.length > 0) { + results = results.concat( + res.errors.map((err: any) => { + const fromPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column, + } + + return { + from: fromPos, + to: toPos, + message: `[syntax] ${err.description}`, + severity: "error", + } + }) + ) + } + } catch (e) { + const fromPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column, + } + + results = results.concat([ + { + from: fromPos, + to: toPos, + message: `[syntax] ${e.description}`, + severity: "error", + }, + ]) + } + + return results +} + +export default linter diff --git a/helpers/editor/linting/testScript.ts b/helpers/editor/linting/testScript.ts new file mode 100644 index 000000000..902d1778c --- /dev/null +++ b/helpers/editor/linting/testScript.ts @@ -0,0 +1,69 @@ +import * as esprima from "esprima" +import { LinterDefinition, LinterResult } from "./linter" +import { performTestLinting } from "~/helpers/tern" + +const linter: LinterDefinition = async (text) => { + let results: LinterResult[] = [] + + // Semantic linting + const semanticLints = await performTestLinting(text) + + results = results.concat( + semanticLints.map((lint: any) => ({ + from: lint.from, + to: lint.to, + severity: "error", + message: `[semantic] ${lint.message}`, + })) + ) + + // Syntax linting + try { + const res: any = esprima.parseScript(text, { tolerant: true }) + if (res.errors && res.errors.length > 0) { + results = results.concat( + res.errors.map((err: any) => { + const fromPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column, + } + + return { + from: fromPos, + to: toPos, + message: `[syntax] ${err.description}`, + severity: "error", + } + }) + ) + } + } catch (e) { + const fromPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column, + } + + results = results.concat([ + { + from: fromPos, + to: toPos, + message: `[syntax] ${e.description}`, + severity: "error", + }, + ]) + } + + return results +} + +export default linter From c938abf606a25511804c0d2bb6b1de12529fceba Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 1 Sep 2021 17:33:54 +0530 Subject: [PATCH 08/73] feat: placeholder, auto-close brackets, search, line wrap --- components/smart/CodeMirror.vue | 2 ++ helpers/editor/codemirror.ts | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 3cf602030..7298927ee 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -39,6 +39,8 @@ const editor = ref(null) useCodemirror(editor, value, { extendedEditorConfig: { mode: props.mode, + placeholder: props.placeholder, + lineWrapping: props.wrap, }, linter: props.linter, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 49969267f..c9bc7e1df 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -4,6 +4,7 @@ import "codemirror/theme/juejin.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" +import "codemirror/addon/dialog/dialog.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -12,6 +13,12 @@ import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" import "codemirror/addon/lint/lint" +import "codemirror/addon/display/placeholder" +import "codemirror/addon/edit/closebrackets" +import "codemirror/addon/search/search" +import "codemirror/addon/search/searchcursor" +import "codemirror/addon/search/jump-to-line" +import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" @@ -28,6 +35,7 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { autoRefresh: true, lineNumbers: true, foldGutter: true, + autoCloseBrackets: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], } From 8430921e4e84e7c95fe71a29a82b964b0c6b52e6 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 20:32:33 +0530 Subject: [PATCH 09/73] feat: codemirror editor options are reactive --- helpers/editor/codemirror.ts | 42 ++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index c9bc7e1df..99d665fd9 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -26,7 +26,7 @@ import { LinterDefinition } from "./linting/linter" const DEFAULT_THEME = "juejin" type CodeMirrorOptions = { - extendedEditorConfig: CodeMirror.EditorConfiguration + extendedEditorConfig: Omit linter: LinterDefinition | null } @@ -55,17 +55,34 @@ export function useCodemirror( ) { const cm = ref(null) + const updateEditorConfig = () => { + Object.keys(options.extendedEditorConfig).forEach((key) => { + // Only update options which need updating + if ( + cm.value && + cm.value?.getOption(key as any) !== + (options.extendedEditorConfig as any)[key] + ) { + cm.value?.setOption( + key as any, + (options.extendedEditorConfig as any)[key] + ) + } + }) + } + + const updateLinterConfig = () => { + if (options.linter) { + cm.value?.setOption("lint", options.linter) + } + } + // Boot-up CodeMirror, set the value and listeners onMounted(() => { - cm.value = CodeMirror(el.value!, { - ...DEFAULT_EDITOR_CONFIG, - ...options.extendedEditorConfig, - }) - cm.value.setValue(value.value) + cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) - if (options.linter) { - cm.value.setOption("lint", options.linter) - } + updateEditorConfig() + updateLinterConfig() cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored @@ -75,6 +92,13 @@ export function useCodemirror( }) }) + // If the editor properties are reactive, watch for updates + watch(() => options.extendedEditorConfig, updateEditorConfig, { + immediate: true, + deep: true, + }) + watch(() => options.linter, updateLinterConfig, { immediate: true }) + // Watch value updates watch(value, (newVal) => { // Check if we are mounted From 0c2cec46a7289b445f65cdec013bf9a31b43b94c Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Mon, 6 Sep 2021 23:30:43 +0530 Subject: [PATCH 10/73] feat: implement gql query linting in codemirror --- helpers/editor/linting/gqlQuery.ts | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 helpers/editor/linting/gqlQuery.ts diff --git a/helpers/editor/linting/gqlQuery.ts b/helpers/editor/linting/gqlQuery.ts new file mode 100644 index 000000000..648cfa732 --- /dev/null +++ b/helpers/editor/linting/gqlQuery.ts @@ -0,0 +1,58 @@ +import { Ref } from "@nuxtjs/composition-api" +import { + GraphQLError, + GraphQLSchema, + parse as gqlParse, + validate as gqlValidate, +} from "graphql" +import { LinterDefinition, LinterResult } from "./linter" + +/** + * Creates a Linter function that can lint a GQL query against a given + * schema + */ +export const createGQLQueryLinter: ( + schema: Ref +) => LinterDefinition = (schema: Ref) => (text) => { + if (text === "") return Promise.resolve([]) + if (!schema.value) return Promise.resolve([]) + + try { + const doc = gqlParse(text) + + const results = gqlValidate(schema.value, doc).map( + ({ locations, message }) => + { + from: { + line: locations![0].line - 1, + ch: locations![0].column - 1, + }, + to: { + line: locations![0].line - 1, + ch: locations![0].column, + }, + message, + severity: "error", + } + ) + + return Promise.resolve(results) + } catch (e) { + const err = e as GraphQLError + + return Promise.resolve([ + { + from: { + line: err.locations![0].line - 1, + ch: err.locations![0].column - 1, + }, + to: { + line: err.locations![0].line - 1, + ch: err.locations![0].column, + }, + message: err.message, + severity: "error", + }, + ]) + } +} From 12cd7940c6c8decd9b4e5f256bd636bc56218856 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Mon, 6 Sep 2021 23:47:26 +0530 Subject: [PATCH 11/73] feat: json linter support for codemirror --- helpers/editor/linting/json.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 helpers/editor/linting/json.ts diff --git a/helpers/editor/linting/json.ts b/helpers/editor/linting/json.ts new file mode 100644 index 000000000..46a690197 --- /dev/null +++ b/helpers/editor/linting/json.ts @@ -0,0 +1,21 @@ +import { convertIndexToLineCh } from "../utils" +import { LinterDefinition, LinterResult } from "./linter" +import jsonParse from "~/helpers/jsonParse" + +const linter: LinterDefinition = (text) => { + try { + jsonParse(text) + return Promise.resolve([]) + } catch (e: any) { + return Promise.resolve([ + { + from: convertIndexToLineCh(text, e.start), + to: convertIndexToLineCh(text, e.end), + message: e.message, + severity: "error", + }, + ]) + } +} + +export default linter From 8a5fd4f745b3acf7eb35284c049b6ae728d1e8ce Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 7 Sep 2021 12:14:13 +0530 Subject: [PATCH 12/73] feat: reactive codemirror theme --- assets/scss/styles.scss | 26 +++++++++++++++++++++----- components/smart/CodeMirror.vue | 18 ++---------------- helpers/editor/codemirror.ts | 32 +++++++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index f54c9535e..cfc1a6192 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -17,7 +17,7 @@ ::-webkit-scrollbar-thumb { @apply bg-divider bg-clip-content; @apply rounded-full; - @apply border-solid border-4 border-transparent; + @apply border-solid border-transparent border-4; @apply hover:(bg-dividerDark bg-clip-content); } @@ -116,8 +116,8 @@ a { &.link { @apply items-center; - @apply px-1 py-0.5; - @apply -mx-1 -my-0.5; + @apply py-0.5 px-1; + @apply -my-0.5 -mx-1; @apply text-accent; @apply rounded; @apply hover:text-accentDark; @@ -198,7 +198,7 @@ hr { .textarea { @apply flex; @apply w-full; - @apply px-4 py-2; + @apply py-2 px-4; @apply bg-transparent; @apply rounded; @apply text-secondaryDark; @@ -293,7 +293,7 @@ input[type="checkbox"] { @apply cursor-pointer; &::before { - @apply border-2 border-divider; + @apply border-divider border-2; @apply rounded; @apply inline-flex; @apply items-center; @@ -461,6 +461,22 @@ input[type="checkbox"] { @apply w-full; } +.CodeMirror { + @apply block; + @apply border-b; + @apply border-dividerLight; + @apply w-full; + @apply h-auto; +} + +.CodeMirror * { + font-family: "Roboto Mono", monospace; +} + +.CodeMirror-scroll { + @apply min-h-32; +} + @media (max-width: 767px) { main { margin-bottom: env(safe-area-inset-bottom); diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 7298927ee..2280af842 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -13,12 +13,13 @@ const props = withDefaults( defineProps<{ value: string mode: string - placeholder: string + placeholder?: string wrap: boolean linter: LinterDefinition | null }>(), { linter: null as any, + placeholder: "", } ) @@ -45,18 +46,3 @@ useCodemirror(editor, value, { linter: props.linter, }) - - diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 99d665fd9..fc7c1f976 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -1,6 +1,8 @@ import CodeMirror from "codemirror" -import "codemirror/theme/juejin.css" +import "codemirror/theme/base16-light.css" +import "codemirror/theme/base16-dark.css" +import "codemirror/theme/3024-night.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" @@ -20,18 +22,15 @@ import "codemirror/addon/search/searchcursor" import "codemirror/addon/search/jump-to-line" import "codemirror/addon/dialog/dialog" -import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" +import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" -const DEFAULT_THEME = "juejin" - type CodeMirrorOptions = { extendedEditorConfig: Omit linter: LinterDefinition | null } const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { - theme: DEFAULT_THEME, autoRefresh: true, lineNumbers: true, foldGutter: true, @@ -81,6 +80,7 @@ export function useCodemirror( onMounted(() => { cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) + setTheme() updateEditorConfig() updateLinterConfig() @@ -92,6 +92,28 @@ export function useCodemirror( }) }) + const setTheme = () => { + const { $colorMode } = useContext() as any + if (cm.value) { + cm.value?.setOption("theme", getThemeName($colorMode.value)) + } + } + + const getThemeName = (mode: string) => { + switch (mode) { + case "system": + return "default" + case "light": + return "base16-light" + case "dark": + return "base16-dark" + case "black": + return "3024-night" + default: + return "default" + } + } + // If the editor properties are reactive, watch for updates watch(() => options.extendedEditorConfig, updateEditorConfig, { immediate: true, From a5197ee5449461f07284ac809c861f1c8e97fe06 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 7 Sep 2021 16:26:26 +0530 Subject: [PATCH 13/73] refactor: github flavored codemirror light theme --- components/smart/CodeMirror.vue | 5 +++-- helpers/editor/codemirror.ts | 4 ++-- package-lock.json | 11 +++++++++++ package.json | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 2280af842..58d8997fd 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -14,12 +14,13 @@ const props = withDefaults( value: string mode: string placeholder?: string - wrap: boolean + wrap?: boolean linter: LinterDefinition | null }>(), { - linter: null as any, placeholder: "", + wrap: true, + linter: null as any, } ) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index fc7c1f976..6681f792a 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -1,6 +1,6 @@ import CodeMirror from "codemirror" -import "codemirror/theme/base16-light.css" +import "codemirror-github-light/lib/codemirror-github-light-theme.css" import "codemirror/theme/base16-dark.css" import "codemirror/theme/3024-night.css" @@ -104,7 +104,7 @@ export function useCodemirror( case "system": return "default" case "light": - return "base16-light" + return "github-light" case "dark": return "base16-dark" case "black": diff --git a/package-lock.json b/package-lock.json index a456b63a0..bff973671 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "codemirror": "^5.62.3", + "codemirror-github-light": "^0.4.2", "core-js": "^3.16.4", "esprima": "^4.0.1", "firebase": "^9.0.0", @@ -13107,6 +13108,11 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" }, + "node_modules/codemirror-github-light": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/codemirror-github-light/-/codemirror-github-light-0.4.2.tgz", + "integrity": "sha1-iUl8JJWEipRaLNIaqj5Wa4d7FDU=" + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -46127,6 +46133,11 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" }, + "codemirror-github-light": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/codemirror-github-light/-/codemirror-github-light-0.4.2.tgz", + "integrity": "sha1-iUl8JJWEipRaLNIaqj5Wa4d7FDU=" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", diff --git a/package.json b/package.json index 45a291014..1e684e937 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "codemirror": "^5.62.3", + "codemirror-github-light": "^0.4.2", "core-js": "^3.16.4", "esprima": "^4.0.1", "firebase": "^9.0.0", From d4d3d96bbb669b2a02454be8d311cc06b4a066cc Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Tue, 7 Sep 2021 22:12:38 +0530 Subject: [PATCH 14/73] feat: implement base autocomplete implementation for codemirror along with preRequest autocompletion --- components/smart/CodeMirror.vue | 4 +++ helpers/editor/codemirror.ts | 38 +++++++++++++++++++++++++ helpers/editor/completion/index.ts | 33 +++++++++++++++++++++ helpers/editor/completion/preRequest.ts | 30 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 helpers/editor/completion/index.ts create mode 100644 helpers/editor/completion/preRequest.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 58d8997fd..abe3845de 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -8,6 +8,7 @@ import "codemirror/mode/javascript/javascript" import { ref, watch } from "@nuxtjs/composition-api" import { useCodemirror } from "~/helpers/editor/codemirror" import { LinterDefinition } from "~/helpers/editor/linting/linter" +import { Completer } from "~/helpers/editor/completion" const props = withDefaults( defineProps<{ @@ -16,11 +17,13 @@ const props = withDefaults( placeholder?: string wrap?: boolean linter: LinterDefinition | null + completer: Completer | null }>(), { placeholder: "", wrap: true, linter: null as any, + completer: null as any, } ) @@ -45,5 +48,6 @@ useCodemirror(editor, value, { lineWrapping: props.wrap, }, linter: props.linter, + completer: props.completer, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 6681f792a..852d46598 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -7,6 +7,7 @@ import "codemirror/theme/3024-night.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" import "codemirror/addon/dialog/dialog.css" +import "codemirror/addon/hint/show-hint.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -15,6 +16,7 @@ import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" import "codemirror/addon/lint/lint" +import "codemirror/addon/hint/show-hint" import "codemirror/addon/display/placeholder" import "codemirror/addon/edit/closebrackets" import "codemirror/addon/search/search" @@ -24,10 +26,12 @@ import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" +import { Completer } from "./completion" type CodeMirrorOptions = { extendedEditorConfig: Omit linter: LinterDefinition | null + completer: Completer | null } const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { @@ -76,6 +80,31 @@ export function useCodemirror( } } + const updateCompleterConfig = () => { + if (options.completer) { + cm.value?.setOption("hintOptions", { + completeSingle: false, + hint: async (editor: CodeMirror.Editor) => { + const pos = editor.getCursor() + const text = editor.getValue() + + const result = await options.completer!(text, pos) + + console.log("complete!") + console.log(result) + + return { + from: result.start, + to: result.end, + list: result.completions + .sort((a, b) => a.score - b.score) + .map((x) => x.text), + } + }, + }) + } + } + // Boot-up CodeMirror, set the value and listeners onMounted(() => { cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) @@ -83,6 +112,7 @@ export function useCodemirror( setTheme() updateEditorConfig() updateLinterConfig() + updateCompleterConfig() cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored @@ -90,6 +120,13 @@ export function useCodemirror( value.value = instance.getValue() } }) + + /* TODO: Show autocomplete on typing (this is just for testing) */ + cm.value.on("keyup", (instance, event) => { + if (!instance.state.completionActive && event.key !== "Enter") { + instance.showHint() + } + }) }) const setTheme = () => { @@ -120,6 +157,7 @@ export function useCodemirror( deep: true, }) watch(() => options.linter, updateLinterConfig, { immediate: true }) + watch(() => options.completer, updateCompleterConfig, { immediate: true }) // Watch value updates watch(value, (newVal) => { diff --git a/helpers/editor/completion/index.ts b/helpers/editor/completion/index.ts new file mode 100644 index 000000000..f5f927b06 --- /dev/null +++ b/helpers/editor/completion/index.ts @@ -0,0 +1,33 @@ +export type CompletionEntry = { + text: string + meta: string + score: number +} + +export type CompleterResult = { + /** + * List of completions to display + */ + completions: CompletionEntry[] + /** + * Start of the completion position + * (on completion the start..end region is replaced) + */ + start: { line: number; ch: number } + /** + * End of the completion position + * (on completion the start..end region is replaced) + */ + end: { line: number; ch: number } +} + +export type Completer = ( + /** + * The contents of the editor + */ + text: string, + /** + * Position where the completer is fired + */ + completePos: { line: number; ch: number } +) => Promise diff --git a/helpers/editor/completion/preRequest.ts b/helpers/editor/completion/preRequest.ts new file mode 100644 index 000000000..1a3387cff --- /dev/null +++ b/helpers/editor/completion/preRequest.ts @@ -0,0 +1,30 @@ +import { convertIndexToLineCh } from "../utils" +import { Completer, CompletionEntry } from "." +import { getPreRequestScriptCompletions } from "~/helpers/tern" + +const completer: Completer = async (text, completePos) => { + const results = await getPreRequestScriptCompletions( + text, + completePos.line, + completePos.ch + ) + + const start = convertIndexToLineCh(text, results.start) + const end = convertIndexToLineCh(text, results.end) + + const completions = results.completions.map((completion: any, i: number) => { + return { + text: completion.name, + meta: completion.isKeyword ? "keyword" : completion.type, + score: results.completions.length - i, + } + }) + + return { + start, + end, + completions, + } +} + +export default completer From f64ff58dbc007ab806aa40f7e044dab608046ecb Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 04:58:23 +0530 Subject: [PATCH 15/73] feat: test script auto completion for codemirror --- helpers/editor/completion/testScript.ts | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 helpers/editor/completion/testScript.ts diff --git a/helpers/editor/completion/testScript.ts b/helpers/editor/completion/testScript.ts new file mode 100644 index 000000000..94ad4d53e --- /dev/null +++ b/helpers/editor/completion/testScript.ts @@ -0,0 +1,30 @@ +import { convertIndexToLineCh } from "../utils" +import { Completer, CompletionEntry } from "." +import { getTestScriptCompletions } from "~/helpers/tern" + +export const completer: Completer = async (text, completePos) => { + const results = await getTestScriptCompletions( + text, + completePos.line, + completePos.ch + ) + + const start = convertIndexToLineCh(text, results.start) + const end = convertIndexToLineCh(text, results.end) + + const completions = results.completions.map((completion: any, i: number) => { + return { + text: completion.name, + meta: completion.isKeyword ? "keyword" : completion.type, + score: results.completions.length - i, + } + }) + + return { + start, + end, + completions, + } +} + +export default completer From b016d3fd9d8220969db67fcf3165411e90e59e46 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 05:36:46 +0530 Subject: [PATCH 16/73] refactor: pass current token position to auto completers on codemirror --- helpers/editor/codemirror.ts | 11 ++++++++--- helpers/editor/completion/index.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 852d46598..3e9fe5d33 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -27,6 +27,7 @@ import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" import { Completer } from "./completion" +import { convertIndexToLineCh } from "./utils" type CodeMirrorOptions = { extendedEditorConfig: Omit @@ -88,10 +89,14 @@ export function useCodemirror( const pos = editor.getCursor() const text = editor.getValue() - const result = await options.completer!(text, pos) + const token = editor.getTokenAt(pos) - console.log("complete!") - console.log(result) + const result = await options.completer!(text, pos, { + start: convertIndexToLineCh(text, token.start), + end: convertIndexToLineCh(text, token.end), + }) + + if (!result) return null return { from: result.start, diff --git a/helpers/editor/completion/index.ts b/helpers/editor/completion/index.ts index f5f927b06..d23414446 100644 --- a/helpers/editor/completion/index.ts +++ b/helpers/editor/completion/index.ts @@ -29,5 +29,9 @@ export type Completer = ( /** * Position where the completer is fired */ - completePos: { line: number; ch: number } -) => Promise + completePos: { line: number; ch: number }, + completeTokenLocation: { + start: { line: number; ch: number } + end: { line: number; ch: number } + } +) => Promise From 162b3d61924e5a8bdfe66ce1edd6d56a16034ba9 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 05:38:03 +0530 Subject: [PATCH 17/73] feat: gql query autocompletion on codemirror --- helpers/editor/completion/gqlQuery.ts | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 helpers/editor/completion/gqlQuery.ts diff --git a/helpers/editor/completion/gqlQuery.ts b/helpers/editor/completion/gqlQuery.ts new file mode 100644 index 000000000..3ff56d135 --- /dev/null +++ b/helpers/editor/completion/gqlQuery.ts @@ -0,0 +1,29 @@ +import { Ref } from "@nuxtjs/composition-api" +import { GraphQLSchema } from "graphql" +import { getAutocompleteSuggestions } from "graphql-language-service-interface" +import { Completer, CompleterResult, CompletionEntry } from "." + +const completer: (schemaRef: Ref) => Completer = + (schemaRef: Ref) => (text, completePos, tokenPos) => { + if (!schemaRef.value) return Promise.resolve(null) + + const completions = getAutocompleteSuggestions(schemaRef.value, text, { + line: completePos.line, + character: completePos.ch, + } as any) + + return Promise.resolve({ + start: tokenPos.start, + end: tokenPos.end, + completions: completions.map( + (x, i) => + { + text: x.label!, + meta: x.detail!, + score: completions.length - i, + } + ), + }) + } + +export default completer From 28aeac45337f1c2a231a58ed1b5ef071cb1d1fec Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 06:00:23 +0530 Subject: [PATCH 18/73] fix: codemirror theme not changing when color mode is updated --- helpers/editor/codemirror.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 3e9fe5d33..bd5e8a991 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -57,6 +57,8 @@ export function useCodemirror( value: Ref, options: CodeMirrorOptions ) { + const { $colorMode } = useContext() as any + const cm = ref(null) const updateEditorConfig = () => { @@ -135,7 +137,6 @@ export function useCodemirror( }) const setTheme = () => { - const { $colorMode } = useContext() as any if (cm.value) { cm.value?.setOption("theme", getThemeName($colorMode.value)) } @@ -175,6 +176,9 @@ export function useCodemirror( } }) + // Watch color mode updates and update theme + watch(() => $colorMode.value, setTheme) + return { cm, } From 26c8f356883f9f945c2388c5aeadd05d5099f23b Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 19:51:43 +0530 Subject: [PATCH 19/73] refactor: map ctrl-space to autocomplete by default in codemirror --- helpers/editor/codemirror.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index bd5e8a991..e1e8791a3 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -41,6 +41,9 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { foldGutter: true, autoCloseBrackets: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + extraKeys: { + "Ctrl-Space": "autocomplete", + } } /** @@ -128,12 +131,12 @@ export function useCodemirror( } }) - /* TODO: Show autocomplete on typing (this is just for testing) */ - cm.value.on("keyup", (instance, event) => { - if (!instance.state.completionActive && event.key !== "Enter") { - instance.showHint() - } - }) + // /* TODO: Show autocomplete on typing (this is just for testing) */ + // cm.value.on("keyup", (instance, event) => { + // if (!instance.state.completionActive && event.key !== "Enter") { + // instance.showHint() + // } + // }) }) const setTheme = () => { From 66c489da8f48e8b172f54145f4d64b1f122bdd55 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 8 Sep 2021 20:27:36 +0530 Subject: [PATCH 20/73] fix: broken conditional rendering of codemirror Co-authored-by: Andrew Bastin --- helpers/editor/codemirror.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index e1e8791a3..487365c49 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -43,7 +43,7 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], extraKeys: { "Ctrl-Space": "autocomplete", - } + }, } /** @@ -115,8 +115,9 @@ export function useCodemirror( } } - // Boot-up CodeMirror, set the value and listeners - onMounted(() => { + const initialize = () => { + if (!el.value) return + cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) setTheme() @@ -130,15 +131,16 @@ export function useCodemirror( value.value = instance.getValue() } }) + } - // /* TODO: Show autocomplete on typing (this is just for testing) */ - // cm.value.on("keyup", (instance, event) => { - // if (!instance.state.completionActive && event.key !== "Enter") { - // instance.showHint() - // } - // }) + // Boot-up CodeMirror, set the value and listeners + onMounted(() => { + initialize() }) + // Reinitialize if the target ref updates + watch(el, initialize) + const setTheme = () => { if (cm.value) { cm.value?.setOption("theme", getThemeName($colorMode.value)) From 8de544696db7ebb6cb8ca6ab6daa4a410e0fac21 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 00:03:07 +0530 Subject: [PATCH 21/73] feat: init codemirror --- components/smart/CodeMirror.vue | 85 +++++++++++++++++++++++++++++++++ package-lock.json | 11 +++++ package.json | 1 + 3 files changed, 97 insertions(+) create mode 100644 components/smart/CodeMirror.vue diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue new file mode 100644 index 000000000..f4dfc315f --- /dev/null +++ b/components/smart/CodeMirror.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/package-lock.json b/package-lock.json index 098126f2d..83a929fb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "ace-builds": "^1.4.12", "acorn": "^8.5.0", "acorn-walk": "^8.2.0", + "codemirror": "^5.62.3", "core-js": "^3.17.2", "esprima": "^4.0.1", "firebase": "^9.0.1", @@ -13074,6 +13075,11 @@ "node": ">=0.10.0" } }, + "node_modules/codemirror": { + "version": "5.62.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", + "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -46082,6 +46088,11 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "codemirror": { + "version": "5.62.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", + "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", diff --git a/package.json b/package.json index 94374cc76..8206b6b85 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "ace-builds": "^1.4.12", "acorn": "^8.5.0", "acorn-walk": "^8.2.0", + "codemirror": "^5.62.3", "core-js": "^3.17.2", "esprima": "^4.0.1", "firebase": "^9.0.1", From 6a1d201e0ede760427d267ef2295332fa247db93 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 10:47:00 +0530 Subject: [PATCH 22/73] refactor: ts codemirror --- components/smart/CodeMirror.vue | 108 +++++++++++++++----------------- package-lock.json | 49 +++++++++++++++ package.json | 1 + 3 files changed, 102 insertions(+), 56 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index f4dfc315f..f29fe92a3 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -2,84 +2,80 @@
- - diff --git a/package-lock.json b/package-lock.json index 83a929fb8..b79dee05f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "@nuxtjs/stylelint-module": "^4.0.0", "@nuxtjs/svg": "^0.2.0", "@testing-library/jest-dom": "^5.14.1", + "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", "@types/lodash": "^4.14.172", "@types/splitpanes": "^2.2.1", @@ -7892,6 +7893,15 @@ "node": ">=0.10.0" } }, + "node_modules/@types/codemirror": { + "version": "5.60.2", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.2.tgz", + "integrity": "sha512-tk8YxckrdU49GaJYRKxdzzzXrTlyT2nQGnobb8rAk34jt+kYXOxPKGqNgr7SJpl5r6YGaRD4CDfqiL+6A+/z7w==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", @@ -7941,6 +7951,12 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "node_modules/@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, "node_modules/@types/etag": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@types/etag/-/etag-1.8.0.tgz", @@ -8325,6 +8341,15 @@ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, + "node_modules/@types/tern": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", + "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/terser-webpack-plugin": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-4.2.1.tgz", @@ -41849,6 +41874,15 @@ } } }, + "@types/codemirror": { + "version": "5.60.2", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.2.tgz", + "integrity": "sha512-tk8YxckrdU49GaJYRKxdzzzXrTlyT2nQGnobb8rAk34jt+kYXOxPKGqNgr7SJpl5r6YGaRD4CDfqiL+6A+/z7w==", + "dev": true, + "requires": { + "@types/tern": "*" + } + }, "@types/component-emitter": { "version": "1.2.10", "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", @@ -41898,6 +41932,12 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, "@types/etag": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@types/etag/-/etag-1.8.0.tgz", @@ -42282,6 +42322,15 @@ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, + "@types/tern": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", + "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "@types/terser-webpack-plugin": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-4.2.1.tgz", diff --git a/package.json b/package.json index 8206b6b85..2420d7536 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@nuxtjs/stylelint-module": "^4.0.0", "@nuxtjs/svg": "^0.2.0", "@testing-library/jest-dom": "^5.14.1", + "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", "@types/lodash": "^4.14.172", "@types/splitpanes": "^2.2.1", From 2bafae5397edf47c847b7a1f4fb886482109b35a Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 31 Aug 2021 16:10:35 +0530 Subject: [PATCH 23/73] feat: line wrap, auto close brackets, placeholder on codemirror --- components/smart/CodeMirror.vue | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index f29fe92a3..292732f11 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -9,14 +9,10 @@ import "codemirror/lib/codemirror.css" import "codemirror/theme/juejin.css" -import "codemirror/addon/fold/foldgutter.css" -import "codemirror/addon/fold/foldgutter" -import "codemirror/addon/fold/brace-fold" -import "codemirror/addon/fold/comment-fold" -import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" - -import "codemirror/mode/javascript/javascript" +import "codemirror/addon/selection/active-line" +import "codemirror/addon/edit/closebrackets" +import "codemirror/addon/display/placeholder" import { onMounted, ref, watch } from "@nuxtjs/composition-api" @@ -25,6 +21,8 @@ const DEFAULT_THEME = "juejin" const props = defineProps<{ value: string mode: string + placeholder: string + wrap: boolean }>() const emit = defineEmits<{ @@ -53,14 +51,17 @@ onMounted(() => { cm.value = Codemirror(editor.value, { value: props.value, mode: props.mode, + lineWrapping: props.wrap, + placeholder: props.placeholder, autoRefresh: true, lineNumbers: true, - foldGutter: true, + styleActiveLine: true, + autoCloseBrackets: true, theme: DEFAULT_THEME, - gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + gutters: ["CodeMirror-linenumbers"], }) - cm.value?.on("change", (instance) => { - const val = instance.getValue() + cm.value?.on("change", (cm) => { + const val = cm.getValue() emit("input", val) }) }) @@ -73,6 +74,7 @@ onMounted(() => { @apply border-dividerLight; @apply w-full; @apply h-auto; + @apply font-mono; } .CodeMirror-scroll { From c81178ae266c11cddbe4814cf3f8cc99fd3836b4 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Tue, 31 Aug 2021 22:20:42 +0530 Subject: [PATCH 24/73] refactor: extract common codemirror logic out to composable --- components/smart/CodeMirror.vue | 49 ++++------------------- helpers/editor/codemirror.ts | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 41 deletions(-) create mode 100644 helpers/editor/codemirror.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 292732f11..6068778c8 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -3,20 +3,10 @@ diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts new file mode 100644 index 000000000..9a282979f --- /dev/null +++ b/helpers/editor/codemirror.ts @@ -0,0 +1,69 @@ +import CodeMirror from "codemirror" + +import "codemirror/theme/juejin.css" + +import "codemirror/lib/codemirror.css" + +import "codemirror/addon/fold/foldgutter.css" +import "codemirror/addon/fold/foldgutter" +import "codemirror/addon/fold/brace-fold" +import "codemirror/addon/fold/comment-fold" +import "codemirror/addon/fold/indent-fold" +import "codemirror/addon/display/autorefresh" + +import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" + +const DEFAULT_THEME = "juejin" + +const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { + theme: DEFAULT_THEME, + autoRefresh: true, + lineNumbers: true, + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], +} + +/** + * A Vue composable to mount and use Codemirror + * + * NOTE: Make sure to import all the necessary Codemirror modules, + * as this function doesn't import any other than the core + * @param el Reference to the dom node to attach to + * @param value Reference to value to read/write to + * @param options CodeMirror options to pass + */ +export function useCodemirror( + el: Ref, + value: Ref, + options: CodeMirror.EditorConfiguration +) { + const cm = ref(null) + + // Boot-up CodeMirror, set the value and listeners + onMounted(() => { + cm.value = CodeMirror(el.value!, { ...DEFAULT_EDITOR_CONFIG, ...options }) + cm.value.setValue(value.value) + + cm.value.on("change", (instance) => { + // External update propagation (via watchers) should be ignored + if (instance.getValue() !== value.value) { + value.value = instance.getValue() + } + }) + }) + + // Watch value updates + watch(value, (newVal) => { + // Check if we are mounted + if (cm.value) { + // Don't do anything on internal updates + if (cm.value.getValue() !== newVal) { + cm.value.setValue(newVal) + } + } + }) + + return { + cm, + } +} From 10a11d6725a345c3c1c13300de0cb4314462d67a Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:34:02 +0530 Subject: [PATCH 25/73] refactor: add types for esprima --- package-lock.json | 19 +++++++++++++++++++ package.json | 1 + 2 files changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index b79dee05f..fa31b90ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "@testing-library/jest-dom": "^5.14.1", "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", + "@types/esprima": "^4.0.3", "@types/lodash": "^4.14.172", "@types/splitpanes": "^2.2.1", "@vue/runtime-dom": "^3.2.10", @@ -7951,6 +7952,15 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "node_modules/@types/esprima": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/esprima/-/esprima-4.0.3.tgz", + "integrity": "sha512-jo14dIWVVtF0iMsKkYek6++4cWJjwpvog+rchLulwgFJGTXqIeTdCOvY0B3yMLTaIwMcKCdJ6mQbSR6wYHy98A==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", @@ -41932,6 +41942,15 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, + "@types/esprima": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/esprima/-/esprima-4.0.3.tgz", + "integrity": "sha512-jo14dIWVVtF0iMsKkYek6++4cWJjwpvog+rchLulwgFJGTXqIeTdCOvY0B3yMLTaIwMcKCdJ6mQbSR6wYHy98A==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "@types/estree": { "version": "0.0.50", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", diff --git a/package.json b/package.json index 2420d7536..b121edec8 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@testing-library/jest-dom": "^5.14.1", "@types/codemirror": "^5.60.2", "@types/cookie": "^0.4.1", + "@types/esprima": "^4.0.3", "@types/lodash": "^4.14.172", "@types/splitpanes": "^2.2.1", "@vue/runtime-dom": "^3.2.10", From 071761a61e7b15f3d22e71766e2d9f29b14f8296 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:41:14 +0530 Subject: [PATCH 26/73] feat: codemirror linting system --- components/smart/CodeMirror.vue | 24 +++++++++++++++++------- helpers/editor/codemirror.ts | 19 +++++++++++++++++-- helpers/editor/linting/linter.ts | 7 +++++++ helpers/editor/utils.ts | 23 +++++++++++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 helpers/editor/linting/linter.ts create mode 100644 helpers/editor/utils.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 6068778c8..3cf602030 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -7,13 +7,20 @@ import "codemirror/mode/javascript/javascript" import { ref, watch } from "@nuxtjs/composition-api" import { useCodemirror } from "~/helpers/editor/codemirror" +import { LinterDefinition } from "~/helpers/editor/linting/linter" -const props = defineProps<{ - value: string - mode: string - placeholder: string - wrap: boolean -}>() +const props = withDefaults( + defineProps<{ + value: string + mode: string + placeholder: string + wrap: boolean + linter: LinterDefinition | null + }>(), + { + linter: null as any, + } +) const emit = defineEmits<{ (e: "input", value: string): void @@ -30,7 +37,10 @@ watch(value, (val) => emit("input", val)) const editor = ref(null) useCodemirror(editor, value, { - mode: props.mode, + extendedEditorConfig: { + mode: props.mode, + }, + linter: props.linter, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 9a282979f..49969267f 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -3,6 +3,7 @@ import CodeMirror from "codemirror" import "codemirror/theme/juejin.css" import "codemirror/lib/codemirror.css" +import "codemirror/addon/lint/lint.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -10,11 +11,18 @@ import "codemirror/addon/fold/brace-fold" import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" +import "codemirror/addon/lint/lint" import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" +import { LinterDefinition } from "./linting/linter" const DEFAULT_THEME = "juejin" +type CodeMirrorOptions = { + extendedEditorConfig: CodeMirror.EditorConfiguration + linter: LinterDefinition | null +} + const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { theme: DEFAULT_THEME, autoRefresh: true, @@ -35,15 +43,22 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { export function useCodemirror( el: Ref, value: Ref, - options: CodeMirror.EditorConfiguration + options: CodeMirrorOptions ) { const cm = ref(null) // Boot-up CodeMirror, set the value and listeners onMounted(() => { - cm.value = CodeMirror(el.value!, { ...DEFAULT_EDITOR_CONFIG, ...options }) + cm.value = CodeMirror(el.value!, { + ...DEFAULT_EDITOR_CONFIG, + ...options.extendedEditorConfig, + }) cm.value.setValue(value.value) + if (options.linter) { + cm.value.setOption("lint", options.linter) + } + cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored if (instance.getValue() !== value.value) { diff --git a/helpers/editor/linting/linter.ts b/helpers/editor/linting/linter.ts new file mode 100644 index 000000000..704270cbe --- /dev/null +++ b/helpers/editor/linting/linter.ts @@ -0,0 +1,7 @@ +export type LinterResult = { + message: string + severity: "warning" | "error" + from: { line: number; ch: number } + to: { line: number; ch: number } +} +export type LinterDefinition = (text: string) => Promise diff --git a/helpers/editor/utils.ts b/helpers/editor/utils.ts new file mode 100644 index 000000000..18b311765 --- /dev/null +++ b/helpers/editor/utils.ts @@ -0,0 +1,23 @@ +export function convertIndexToLineCh( + text: string, + i: number +): { line: number; ch: number } { + const lines = text.split("/n") + + let line = 0 + let counter = 0 + + while (line < lines.length) { + if (i > lines[line].length + counter) { + counter += lines[line].length + 1 + line++ + } else { + return { + line: line + 1, + ch: i - counter + 1, + } + } + } + + throw new Error("Invalid input") +} From 4e8484ee7c2eb7363944bab356d0d2867f30920f Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:45:49 +0530 Subject: [PATCH 27/73] feat: linter for prerequest and testscripts --- helpers/editor/linting/preRequest.ts | 69 ++++++++++++++++++++++++++++ helpers/editor/linting/testScript.ts | 69 ++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 helpers/editor/linting/preRequest.ts create mode 100644 helpers/editor/linting/testScript.ts diff --git a/helpers/editor/linting/preRequest.ts b/helpers/editor/linting/preRequest.ts new file mode 100644 index 000000000..db42d9864 --- /dev/null +++ b/helpers/editor/linting/preRequest.ts @@ -0,0 +1,69 @@ +import * as esprima from "esprima" +import { LinterDefinition, LinterResult } from "./linter" +import { performPreRequestLinting } from "~/helpers/tern" + +const linter: LinterDefinition = async (text) => { + let results: LinterResult[] = [] + + // Semantic linting + const semanticLints = await performPreRequestLinting(text) + + results = results.concat( + semanticLints.map((lint: any) => ({ + from: lint.from, + to: lint.to, + severity: "error", + message: `[semantic] ${lint.message}`, + })) + ) + + // Syntax linting + try { + const res: any = esprima.parseScript(text, { tolerant: true }) + if (res.errors && res.errors.length > 0) { + results = results.concat( + res.errors.map((err: any) => { + const fromPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column, + } + + return { + from: fromPos, + to: toPos, + message: `[syntax] ${err.description}`, + severity: "error", + } + }) + ) + } + } catch (e) { + const fromPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column, + } + + results = results.concat([ + { + from: fromPos, + to: toPos, + message: `[syntax] ${e.description}`, + severity: "error", + }, + ]) + } + + return results +} + +export default linter diff --git a/helpers/editor/linting/testScript.ts b/helpers/editor/linting/testScript.ts new file mode 100644 index 000000000..902d1778c --- /dev/null +++ b/helpers/editor/linting/testScript.ts @@ -0,0 +1,69 @@ +import * as esprima from "esprima" +import { LinterDefinition, LinterResult } from "./linter" +import { performTestLinting } from "~/helpers/tern" + +const linter: LinterDefinition = async (text) => { + let results: LinterResult[] = [] + + // Semantic linting + const semanticLints = await performTestLinting(text) + + results = results.concat( + semanticLints.map((lint: any) => ({ + from: lint.from, + to: lint.to, + severity: "error", + message: `[semantic] ${lint.message}`, + })) + ) + + // Syntax linting + try { + const res: any = esprima.parseScript(text, { tolerant: true }) + if (res.errors && res.errors.length > 0) { + results = results.concat( + res.errors.map((err: any) => { + const fromPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: err.lineNumber - 1, + ch: err.column, + } + + return { + from: fromPos, + to: toPos, + message: `[syntax] ${err.description}`, + severity: "error", + } + }) + ) + } + } catch (e) { + const fromPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column - 1, + } + + const toPos: { line: number; ch: number } = { + line: e.lineNumber - 1, + ch: e.column, + } + + results = results.concat([ + { + from: fromPos, + to: toPos, + message: `[syntax] ${e.description}`, + severity: "error", + }, + ]) + } + + return results +} + +export default linter From 33951482d54d2d0b55f10863150039dd5a4b1ec7 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 1 Sep 2021 17:33:54 +0530 Subject: [PATCH 28/73] feat: placeholder, auto-close brackets, search, line wrap --- components/smart/CodeMirror.vue | 2 ++ helpers/editor/codemirror.ts | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 3cf602030..7298927ee 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -39,6 +39,8 @@ const editor = ref(null) useCodemirror(editor, value, { extendedEditorConfig: { mode: props.mode, + placeholder: props.placeholder, + lineWrapping: props.wrap, }, linter: props.linter, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 49969267f..c9bc7e1df 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -4,6 +4,7 @@ import "codemirror/theme/juejin.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" +import "codemirror/addon/dialog/dialog.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -12,6 +13,12 @@ import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" import "codemirror/addon/lint/lint" +import "codemirror/addon/display/placeholder" +import "codemirror/addon/edit/closebrackets" +import "codemirror/addon/search/search" +import "codemirror/addon/search/searchcursor" +import "codemirror/addon/search/jump-to-line" +import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" @@ -28,6 +35,7 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { autoRefresh: true, lineNumbers: true, foldGutter: true, + autoCloseBrackets: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], } From 61da0733c2d5fc0628c066389c5ee156ba266c87 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 20:32:33 +0530 Subject: [PATCH 29/73] feat: codemirror editor options are reactive --- helpers/editor/codemirror.ts | 42 ++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index c9bc7e1df..99d665fd9 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -26,7 +26,7 @@ import { LinterDefinition } from "./linting/linter" const DEFAULT_THEME = "juejin" type CodeMirrorOptions = { - extendedEditorConfig: CodeMirror.EditorConfiguration + extendedEditorConfig: Omit linter: LinterDefinition | null } @@ -55,17 +55,34 @@ export function useCodemirror( ) { const cm = ref(null) + const updateEditorConfig = () => { + Object.keys(options.extendedEditorConfig).forEach((key) => { + // Only update options which need updating + if ( + cm.value && + cm.value?.getOption(key as any) !== + (options.extendedEditorConfig as any)[key] + ) { + cm.value?.setOption( + key as any, + (options.extendedEditorConfig as any)[key] + ) + } + }) + } + + const updateLinterConfig = () => { + if (options.linter) { + cm.value?.setOption("lint", options.linter) + } + } + // Boot-up CodeMirror, set the value and listeners onMounted(() => { - cm.value = CodeMirror(el.value!, { - ...DEFAULT_EDITOR_CONFIG, - ...options.extendedEditorConfig, - }) - cm.value.setValue(value.value) + cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) - if (options.linter) { - cm.value.setOption("lint", options.linter) - } + updateEditorConfig() + updateLinterConfig() cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored @@ -75,6 +92,13 @@ export function useCodemirror( }) }) + // If the editor properties are reactive, watch for updates + watch(() => options.extendedEditorConfig, updateEditorConfig, { + immediate: true, + deep: true, + }) + watch(() => options.linter, updateLinterConfig, { immediate: true }) + // Watch value updates watch(value, (newVal) => { // Check if we are mounted From 8af90432cf7601f39ad07971fad33b3cb6a6ba46 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Mon, 6 Sep 2021 23:30:43 +0530 Subject: [PATCH 30/73] feat: implement gql query linting in codemirror --- helpers/editor/linting/gqlQuery.ts | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 helpers/editor/linting/gqlQuery.ts diff --git a/helpers/editor/linting/gqlQuery.ts b/helpers/editor/linting/gqlQuery.ts new file mode 100644 index 000000000..648cfa732 --- /dev/null +++ b/helpers/editor/linting/gqlQuery.ts @@ -0,0 +1,58 @@ +import { Ref } from "@nuxtjs/composition-api" +import { + GraphQLError, + GraphQLSchema, + parse as gqlParse, + validate as gqlValidate, +} from "graphql" +import { LinterDefinition, LinterResult } from "./linter" + +/** + * Creates a Linter function that can lint a GQL query against a given + * schema + */ +export const createGQLQueryLinter: ( + schema: Ref +) => LinterDefinition = (schema: Ref) => (text) => { + if (text === "") return Promise.resolve([]) + if (!schema.value) return Promise.resolve([]) + + try { + const doc = gqlParse(text) + + const results = gqlValidate(schema.value, doc).map( + ({ locations, message }) => + { + from: { + line: locations![0].line - 1, + ch: locations![0].column - 1, + }, + to: { + line: locations![0].line - 1, + ch: locations![0].column, + }, + message, + severity: "error", + } + ) + + return Promise.resolve(results) + } catch (e) { + const err = e as GraphQLError + + return Promise.resolve([ + { + from: { + line: err.locations![0].line - 1, + ch: err.locations![0].column - 1, + }, + to: { + line: err.locations![0].line - 1, + ch: err.locations![0].column, + }, + message: err.message, + severity: "error", + }, + ]) + } +} From 2f8aa79ec1f3e84b6a342e7ce3f2c134dba84643 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Mon, 6 Sep 2021 23:47:26 +0530 Subject: [PATCH 31/73] feat: json linter support for codemirror --- helpers/editor/linting/json.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 helpers/editor/linting/json.ts diff --git a/helpers/editor/linting/json.ts b/helpers/editor/linting/json.ts new file mode 100644 index 000000000..46a690197 --- /dev/null +++ b/helpers/editor/linting/json.ts @@ -0,0 +1,21 @@ +import { convertIndexToLineCh } from "../utils" +import { LinterDefinition, LinterResult } from "./linter" +import jsonParse from "~/helpers/jsonParse" + +const linter: LinterDefinition = (text) => { + try { + jsonParse(text) + return Promise.resolve([]) + } catch (e: any) { + return Promise.resolve([ + { + from: convertIndexToLineCh(text, e.start), + to: convertIndexToLineCh(text, e.end), + message: e.message, + severity: "error", + }, + ]) + } +} + +export default linter From 602aabdeb82a52f1154d6b9b4c7dfd7a3199f78b Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 7 Sep 2021 12:14:13 +0530 Subject: [PATCH 32/73] feat: reactive codemirror theme --- assets/scss/styles.scss | 26 +++++++++++++++++++++----- components/smart/CodeMirror.vue | 18 ++---------------- helpers/editor/codemirror.ts | 32 +++++++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index f54c9535e..cfc1a6192 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -17,7 +17,7 @@ ::-webkit-scrollbar-thumb { @apply bg-divider bg-clip-content; @apply rounded-full; - @apply border-solid border-4 border-transparent; + @apply border-solid border-transparent border-4; @apply hover:(bg-dividerDark bg-clip-content); } @@ -116,8 +116,8 @@ a { &.link { @apply items-center; - @apply px-1 py-0.5; - @apply -mx-1 -my-0.5; + @apply py-0.5 px-1; + @apply -my-0.5 -mx-1; @apply text-accent; @apply rounded; @apply hover:text-accentDark; @@ -198,7 +198,7 @@ hr { .textarea { @apply flex; @apply w-full; - @apply px-4 py-2; + @apply py-2 px-4; @apply bg-transparent; @apply rounded; @apply text-secondaryDark; @@ -293,7 +293,7 @@ input[type="checkbox"] { @apply cursor-pointer; &::before { - @apply border-2 border-divider; + @apply border-divider border-2; @apply rounded; @apply inline-flex; @apply items-center; @@ -461,6 +461,22 @@ input[type="checkbox"] { @apply w-full; } +.CodeMirror { + @apply block; + @apply border-b; + @apply border-dividerLight; + @apply w-full; + @apply h-auto; +} + +.CodeMirror * { + font-family: "Roboto Mono", monospace; +} + +.CodeMirror-scroll { + @apply min-h-32; +} + @media (max-width: 767px) { main { margin-bottom: env(safe-area-inset-bottom); diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 7298927ee..2280af842 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -13,12 +13,13 @@ const props = withDefaults( defineProps<{ value: string mode: string - placeholder: string + placeholder?: string wrap: boolean linter: LinterDefinition | null }>(), { linter: null as any, + placeholder: "", } ) @@ -45,18 +46,3 @@ useCodemirror(editor, value, { linter: props.linter, }) - - diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 99d665fd9..fc7c1f976 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -1,6 +1,8 @@ import CodeMirror from "codemirror" -import "codemirror/theme/juejin.css" +import "codemirror/theme/base16-light.css" +import "codemirror/theme/base16-dark.css" +import "codemirror/theme/3024-night.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" @@ -20,18 +22,15 @@ import "codemirror/addon/search/searchcursor" import "codemirror/addon/search/jump-to-line" import "codemirror/addon/dialog/dialog" -import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" +import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" -const DEFAULT_THEME = "juejin" - type CodeMirrorOptions = { extendedEditorConfig: Omit linter: LinterDefinition | null } const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { - theme: DEFAULT_THEME, autoRefresh: true, lineNumbers: true, foldGutter: true, @@ -81,6 +80,7 @@ export function useCodemirror( onMounted(() => { cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) + setTheme() updateEditorConfig() updateLinterConfig() @@ -92,6 +92,28 @@ export function useCodemirror( }) }) + const setTheme = () => { + const { $colorMode } = useContext() as any + if (cm.value) { + cm.value?.setOption("theme", getThemeName($colorMode.value)) + } + } + + const getThemeName = (mode: string) => { + switch (mode) { + case "system": + return "default" + case "light": + return "base16-light" + case "dark": + return "base16-dark" + case "black": + return "3024-night" + default: + return "default" + } + } + // If the editor properties are reactive, watch for updates watch(() => options.extendedEditorConfig, updateEditorConfig, { immediate: true, From dc5f52cc0dbf834342115d8bf21bc4292e0cfcad Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 7 Sep 2021 16:26:26 +0530 Subject: [PATCH 33/73] refactor: github flavored codemirror light theme --- components/smart/CodeMirror.vue | 5 +++-- helpers/editor/codemirror.ts | 4 ++-- package-lock.json | 11 +++++++++++ package.json | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 2280af842..58d8997fd 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -14,12 +14,13 @@ const props = withDefaults( value: string mode: string placeholder?: string - wrap: boolean + wrap?: boolean linter: LinterDefinition | null }>(), { - linter: null as any, placeholder: "", + wrap: true, + linter: null as any, } ) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index fc7c1f976..6681f792a 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -1,6 +1,6 @@ import CodeMirror from "codemirror" -import "codemirror/theme/base16-light.css" +import "codemirror-github-light/lib/codemirror-github-light-theme.css" import "codemirror/theme/base16-dark.css" import "codemirror/theme/3024-night.css" @@ -104,7 +104,7 @@ export function useCodemirror( case "system": return "default" case "light": - return "base16-light" + return "github-light" case "dark": return "base16-dark" case "black": diff --git a/package-lock.json b/package-lock.json index fa31b90ef..6dab0aed6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "acorn": "^8.5.0", "acorn-walk": "^8.2.0", "codemirror": "^5.62.3", + "codemirror-github-light": "^0.4.2", "core-js": "^3.17.2", "esprima": "^4.0.1", "firebase": "^9.0.1", @@ -13115,6 +13116,11 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" }, + "node_modules/codemirror-github-light": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/codemirror-github-light/-/codemirror-github-light-0.4.2.tgz", + "integrity": "sha1-iUl8JJWEipRaLNIaqj5Wa4d7FDU=" + }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -46161,6 +46167,11 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.62.3.tgz", "integrity": "sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==" }, + "codemirror-github-light": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/codemirror-github-light/-/codemirror-github-light-0.4.2.tgz", + "integrity": "sha1-iUl8JJWEipRaLNIaqj5Wa4d7FDU=" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", diff --git a/package.json b/package.json index b121edec8..68477db16 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "acorn": "^8.5.0", "acorn-walk": "^8.2.0", "codemirror": "^5.62.3", + "codemirror-github-light": "^0.4.2", "core-js": "^3.17.2", "esprima": "^4.0.1", "firebase": "^9.0.1", From b9fc0175e7d9491982af6df59d0451366509476c Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Tue, 7 Sep 2021 22:12:38 +0530 Subject: [PATCH 34/73] feat: implement base autocomplete implementation for codemirror along with preRequest autocompletion --- components/smart/CodeMirror.vue | 4 +++ helpers/editor/codemirror.ts | 38 +++++++++++++++++++++++++ helpers/editor/completion/index.ts | 33 +++++++++++++++++++++ helpers/editor/completion/preRequest.ts | 30 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 helpers/editor/completion/index.ts create mode 100644 helpers/editor/completion/preRequest.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 58d8997fd..abe3845de 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -8,6 +8,7 @@ import "codemirror/mode/javascript/javascript" import { ref, watch } from "@nuxtjs/composition-api" import { useCodemirror } from "~/helpers/editor/codemirror" import { LinterDefinition } from "~/helpers/editor/linting/linter" +import { Completer } from "~/helpers/editor/completion" const props = withDefaults( defineProps<{ @@ -16,11 +17,13 @@ const props = withDefaults( placeholder?: string wrap?: boolean linter: LinterDefinition | null + completer: Completer | null }>(), { placeholder: "", wrap: true, linter: null as any, + completer: null as any, } ) @@ -45,5 +48,6 @@ useCodemirror(editor, value, { lineWrapping: props.wrap, }, linter: props.linter, + completer: props.completer, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 6681f792a..852d46598 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -7,6 +7,7 @@ import "codemirror/theme/3024-night.css" import "codemirror/lib/codemirror.css" import "codemirror/addon/lint/lint.css" import "codemirror/addon/dialog/dialog.css" +import "codemirror/addon/hint/show-hint.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -15,6 +16,7 @@ import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" import "codemirror/addon/lint/lint" +import "codemirror/addon/hint/show-hint" import "codemirror/addon/display/placeholder" import "codemirror/addon/edit/closebrackets" import "codemirror/addon/search/search" @@ -24,10 +26,12 @@ import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" +import { Completer } from "./completion" type CodeMirrorOptions = { extendedEditorConfig: Omit linter: LinterDefinition | null + completer: Completer | null } const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { @@ -76,6 +80,31 @@ export function useCodemirror( } } + const updateCompleterConfig = () => { + if (options.completer) { + cm.value?.setOption("hintOptions", { + completeSingle: false, + hint: async (editor: CodeMirror.Editor) => { + const pos = editor.getCursor() + const text = editor.getValue() + + const result = await options.completer!(text, pos) + + console.log("complete!") + console.log(result) + + return { + from: result.start, + to: result.end, + list: result.completions + .sort((a, b) => a.score - b.score) + .map((x) => x.text), + } + }, + }) + } + } + // Boot-up CodeMirror, set the value and listeners onMounted(() => { cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) @@ -83,6 +112,7 @@ export function useCodemirror( setTheme() updateEditorConfig() updateLinterConfig() + updateCompleterConfig() cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored @@ -90,6 +120,13 @@ export function useCodemirror( value.value = instance.getValue() } }) + + /* TODO: Show autocomplete on typing (this is just for testing) */ + cm.value.on("keyup", (instance, event) => { + if (!instance.state.completionActive && event.key !== "Enter") { + instance.showHint() + } + }) }) const setTheme = () => { @@ -120,6 +157,7 @@ export function useCodemirror( deep: true, }) watch(() => options.linter, updateLinterConfig, { immediate: true }) + watch(() => options.completer, updateCompleterConfig, { immediate: true }) // Watch value updates watch(value, (newVal) => { diff --git a/helpers/editor/completion/index.ts b/helpers/editor/completion/index.ts new file mode 100644 index 000000000..f5f927b06 --- /dev/null +++ b/helpers/editor/completion/index.ts @@ -0,0 +1,33 @@ +export type CompletionEntry = { + text: string + meta: string + score: number +} + +export type CompleterResult = { + /** + * List of completions to display + */ + completions: CompletionEntry[] + /** + * Start of the completion position + * (on completion the start..end region is replaced) + */ + start: { line: number; ch: number } + /** + * End of the completion position + * (on completion the start..end region is replaced) + */ + end: { line: number; ch: number } +} + +export type Completer = ( + /** + * The contents of the editor + */ + text: string, + /** + * Position where the completer is fired + */ + completePos: { line: number; ch: number } +) => Promise diff --git a/helpers/editor/completion/preRequest.ts b/helpers/editor/completion/preRequest.ts new file mode 100644 index 000000000..1a3387cff --- /dev/null +++ b/helpers/editor/completion/preRequest.ts @@ -0,0 +1,30 @@ +import { convertIndexToLineCh } from "../utils" +import { Completer, CompletionEntry } from "." +import { getPreRequestScriptCompletions } from "~/helpers/tern" + +const completer: Completer = async (text, completePos) => { + const results = await getPreRequestScriptCompletions( + text, + completePos.line, + completePos.ch + ) + + const start = convertIndexToLineCh(text, results.start) + const end = convertIndexToLineCh(text, results.end) + + const completions = results.completions.map((completion: any, i: number) => { + return { + text: completion.name, + meta: completion.isKeyword ? "keyword" : completion.type, + score: results.completions.length - i, + } + }) + + return { + start, + end, + completions, + } +} + +export default completer From 8d67a0d95f9dcb396e7fcd5a10425bc72c9532e7 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 04:58:23 +0530 Subject: [PATCH 35/73] feat: test script auto completion for codemirror --- helpers/editor/completion/testScript.ts | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 helpers/editor/completion/testScript.ts diff --git a/helpers/editor/completion/testScript.ts b/helpers/editor/completion/testScript.ts new file mode 100644 index 000000000..94ad4d53e --- /dev/null +++ b/helpers/editor/completion/testScript.ts @@ -0,0 +1,30 @@ +import { convertIndexToLineCh } from "../utils" +import { Completer, CompletionEntry } from "." +import { getTestScriptCompletions } from "~/helpers/tern" + +export const completer: Completer = async (text, completePos) => { + const results = await getTestScriptCompletions( + text, + completePos.line, + completePos.ch + ) + + const start = convertIndexToLineCh(text, results.start) + const end = convertIndexToLineCh(text, results.end) + + const completions = results.completions.map((completion: any, i: number) => { + return { + text: completion.name, + meta: completion.isKeyword ? "keyword" : completion.type, + score: results.completions.length - i, + } + }) + + return { + start, + end, + completions, + } +} + +export default completer From d6e3bd09b46c32d71c03d99c68b4557543e4b908 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 05:36:46 +0530 Subject: [PATCH 36/73] refactor: pass current token position to auto completers on codemirror --- helpers/editor/codemirror.ts | 11 ++++++++--- helpers/editor/completion/index.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 852d46598..3e9fe5d33 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -27,6 +27,7 @@ import "codemirror/addon/dialog/dialog" import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api" import { LinterDefinition } from "./linting/linter" import { Completer } from "./completion" +import { convertIndexToLineCh } from "./utils" type CodeMirrorOptions = { extendedEditorConfig: Omit @@ -88,10 +89,14 @@ export function useCodemirror( const pos = editor.getCursor() const text = editor.getValue() - const result = await options.completer!(text, pos) + const token = editor.getTokenAt(pos) - console.log("complete!") - console.log(result) + const result = await options.completer!(text, pos, { + start: convertIndexToLineCh(text, token.start), + end: convertIndexToLineCh(text, token.end), + }) + + if (!result) return null return { from: result.start, diff --git a/helpers/editor/completion/index.ts b/helpers/editor/completion/index.ts index f5f927b06..d23414446 100644 --- a/helpers/editor/completion/index.ts +++ b/helpers/editor/completion/index.ts @@ -29,5 +29,9 @@ export type Completer = ( /** * Position where the completer is fired */ - completePos: { line: number; ch: number } -) => Promise + completePos: { line: number; ch: number }, + completeTokenLocation: { + start: { line: number; ch: number } + end: { line: number; ch: number } + } +) => Promise From 639a629809f26cb1519f743742ff4509e5fb50c5 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 05:38:03 +0530 Subject: [PATCH 37/73] feat: gql query autocompletion on codemirror --- helpers/editor/completion/gqlQuery.ts | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 helpers/editor/completion/gqlQuery.ts diff --git a/helpers/editor/completion/gqlQuery.ts b/helpers/editor/completion/gqlQuery.ts new file mode 100644 index 000000000..3ff56d135 --- /dev/null +++ b/helpers/editor/completion/gqlQuery.ts @@ -0,0 +1,29 @@ +import { Ref } from "@nuxtjs/composition-api" +import { GraphQLSchema } from "graphql" +import { getAutocompleteSuggestions } from "graphql-language-service-interface" +import { Completer, CompleterResult, CompletionEntry } from "." + +const completer: (schemaRef: Ref) => Completer = + (schemaRef: Ref) => (text, completePos, tokenPos) => { + if (!schemaRef.value) return Promise.resolve(null) + + const completions = getAutocompleteSuggestions(schemaRef.value, text, { + line: completePos.line, + character: completePos.ch, + } as any) + + return Promise.resolve({ + start: tokenPos.start, + end: tokenPos.end, + completions: completions.map( + (x, i) => + { + text: x.label!, + meta: x.detail!, + score: completions.length - i, + } + ), + }) + } + +export default completer From 4c55b9c304da75c84cec78db17bb8426a1ad55c6 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 06:00:23 +0530 Subject: [PATCH 38/73] fix: codemirror theme not changing when color mode is updated --- helpers/editor/codemirror.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 3e9fe5d33..bd5e8a991 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -57,6 +57,8 @@ export function useCodemirror( value: Ref, options: CodeMirrorOptions ) { + const { $colorMode } = useContext() as any + const cm = ref(null) const updateEditorConfig = () => { @@ -135,7 +137,6 @@ export function useCodemirror( }) const setTheme = () => { - const { $colorMode } = useContext() as any if (cm.value) { cm.value?.setOption("theme", getThemeName($colorMode.value)) } @@ -175,6 +176,9 @@ export function useCodemirror( } }) + // Watch color mode updates and update theme + watch(() => $colorMode.value, setTheme) + return { cm, } From 2bb3b71a704a1790c99da15baf1b4a160c668b19 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 8 Sep 2021 19:51:43 +0530 Subject: [PATCH 39/73] refactor: map ctrl-space to autocomplete by default in codemirror --- helpers/editor/codemirror.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index bd5e8a991..e1e8791a3 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -41,6 +41,9 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { foldGutter: true, autoCloseBrackets: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + extraKeys: { + "Ctrl-Space": "autocomplete", + } } /** @@ -128,12 +131,12 @@ export function useCodemirror( } }) - /* TODO: Show autocomplete on typing (this is just for testing) */ - cm.value.on("keyup", (instance, event) => { - if (!instance.state.completionActive && event.key !== "Enter") { - instance.showHint() - } - }) + // /* TODO: Show autocomplete on typing (this is just for testing) */ + // cm.value.on("keyup", (instance, event) => { + // if (!instance.state.completionActive && event.key !== "Enter") { + // instance.showHint() + // } + // }) }) const setTheme = () => { From e1a25fa894875701f5d991ff51e5497590f8ff01 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 8 Sep 2021 20:27:36 +0530 Subject: [PATCH 40/73] fix: broken conditional rendering of codemirror Co-authored-by: Andrew Bastin --- helpers/editor/codemirror.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index e1e8791a3..487365c49 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -43,7 +43,7 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], extraKeys: { "Ctrl-Space": "autocomplete", - } + }, } /** @@ -115,8 +115,9 @@ export function useCodemirror( } } - // Boot-up CodeMirror, set the value and listeners - onMounted(() => { + const initialize = () => { + if (!el.value) return + cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) setTheme() @@ -130,15 +131,16 @@ export function useCodemirror( value.value = instance.getValue() } }) + } - // /* TODO: Show autocomplete on typing (this is just for testing) */ - // cm.value.on("keyup", (instance, event) => { - // if (!instance.state.completionActive && event.key !== "Enter") { - // instance.showHint() - // } - // }) + // Boot-up CodeMirror, set the value and listeners + onMounted(() => { + initialize() }) + // Reinitialize if the target ref updates + watch(el, initialize) + const setTheme = () => { if (cm.value) { cm.value?.setOption("theme", getThemeName($colorMode.value)) From b15fd6c75a6e540efa592b33720f517a8dd24b16 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 8 Sep 2021 21:52:26 +0530 Subject: [PATCH 41/73] feat: port bulk editor textareas to codemirror --- assets/scss/styles.scss | 3 +- components/graphql/RequestOptions.vue | 376 +++++++++++--------------- components/http/Headers.vue | 166 +++++------- components/http/Parameters.vue | 162 +++++------ 4 files changed, 303 insertions(+), 404 deletions(-) diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index cfc1a6192..a08772cd2 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -36,7 +36,8 @@ } input::placeholder, -textarea::placeholder { +textarea::placeholder, +.CodeMirror-empty { @apply text-secondaryDark; @apply opacity-25; } diff --git a/components/graphql/RequestOptions.vue b/components/graphql/RequestOptions.vue index 7113b4e4a..2c4863d36 100644 --- a/components/graphql/RequestOptions.vue +++ b/components/graphql/RequestOptions.vue @@ -42,9 +42,7 @@ /> @@ -174,25 +172,7 @@
- +
- diff --git a/components/http/Headers.vue b/components/http/Headers.vue index 3294219b8..5fff7dbf9 100644 --- a/components/http/Headers.vue +++ b/components/http/Headers.vue @@ -48,25 +48,7 @@
- +
- diff --git a/components/http/Parameters.vue b/components/http/Parameters.vue index 04a7d9ad9..1b24cb6d1 100644 --- a/components/http/Parameters.vue +++ b/components/http/Parameters.vue @@ -48,25 +48,7 @@
- +
-import { - defineComponent, - ref, - useContext, - watch, -} from "@nuxtjs/composition-api" + From f4f74e223f1162450a5f4822a31ef0786ac228e5 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Thu, 9 Sep 2021 01:03:46 +0530 Subject: [PATCH 42/73] refactor: a volar types shim generator --- .gitignore | 3 + modules/emit-volar-types.ts | 129 ++++++++++++++++++++++++++++++++++++ nuxt.config.js | 1 + 3 files changed, 133 insertions(+) create mode 100644 modules/emit-volar-types.ts diff --git a/.gitignore b/.gitignore index 9d566a677..211118bff 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,6 @@ tests/*/screenshots # Tests videos tests/*/videos + +# Andrew's crazy Volar shim generator +shims-volar.d.ts diff --git a/modules/emit-volar-types.ts b/modules/emit-volar-types.ts new file mode 100644 index 000000000..bd130d3ec --- /dev/null +++ b/modules/emit-volar-types.ts @@ -0,0 +1,129 @@ +import { resolve } from "path" +import { Module } from "@nuxt/types" +import ts from "typescript" + +const { readdir, writeFile } = require("fs").promises + +function titleCase(str: string): string { + return str[0].toUpperCase() + str.substring(1) +} + +async function* getFilesInDir(dir: string): AsyncIterable { + const dirents = await readdir(dir, { withFileTypes: true }) + for (const dirent of dirents) { + const res = resolve(dir, dirent.name) + if (dirent.isDirectory()) { + yield* getFilesInDir(res) + } else { + yield res + } + } +} + +async function getAllVueComponentPaths(): Promise { + const vueFilePaths: string[] = [] + + for await (const f of getFilesInDir("./components")) { + if (f.endsWith(".vue")) { + const componentsIndex = f.split("/").indexOf("components") + + vueFilePaths.push( + `./${f + .split("/") + .slice(componentsIndex + 1) + .join("/")}` + ) + } + } + + return vueFilePaths +} + +function resolveComponentName(filename: string): string { + const index = filename.split("/").indexOf("components") + + return filename + .split("/") + .slice(index + 1) + .map((x) => x.split(".vue")[0]) // Remove extension + .filter((x) => x.toUpperCase() !== x.toLowerCase()) + .map((x) => titleCase(x)) // titlecase it + .join("") +} + +function createTSImports(components: [string, string][]) { + return components.map(([componentName, componentPath]) => { + return ts.factory.createImportDeclaration( + undefined, + undefined, + ts.factory.createImportClause( + false, + ts.factory.createIdentifier(componentName), + undefined + ), + ts.factory.createStringLiteral(componentPath) + ) + }) +} + +function createTSProps(components: [string, string][]) { + return components.map(([componentName]) => { + return ts.factory.createPropertySignature( + undefined, + ts.factory.createIdentifier(componentName), + undefined, + ts.factory.createTypeQueryNode(ts.factory.createIdentifier(componentName)) + ) + }) +} + +function generateTypeScriptDef(components: [string, string][]) { + const statements = [ + ...createTSImports(components), + ts.factory.createModuleDeclaration( + undefined, + [ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword)], + ts.factory.createIdentifier("global"), + ts.factory.createModuleBlock([ + ts.factory.createInterfaceDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("__VLS_GlobalComponents"), + undefined, + undefined, + [...createTSProps(components)] + ), + ]), + ts.NodeFlags.ExportContext | + ts.NodeFlags.GlobalAugmentation | + ts.NodeFlags.ContextFlags + ), + ] + + const source = ts.factory.createSourceFile( + statements, + ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), + ts.NodeFlags.None + ) + + const printer = ts.createPrinter({ + newLine: ts.NewLineKind.LineFeed, + }) + + return printer.printFile(source) +} + +const module: Module<{}> = async function () { + if (!this.nuxt.options.dev) return + + const results = await getAllVueComponentPaths() + const fileComponentNameCombo: [string, string][] = results.map((x) => [ + resolveComponentName(x), + x, + ]) + const typescriptString = generateTypeScriptDef(fileComponentNameCombo) + + await writeFile(resolve("shims-volar.d.ts"), typescriptString) +} + +export default module diff --git a/nuxt.config.js b/nuxt.config.js index b77f39f75..c053be3e0 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -133,6 +133,7 @@ export default { "@nuxtjs/composition-api/module", // https://github.com/antfu/unplugin-vue2-script-setup "unplugin-vue2-script-setup/nuxt", + "~/modules/emit-volar-types.ts", ], // Modules (https://go.nuxtjs.dev/config-modules) From 4a12cc76fa485cc5ac0d0c2d106112189d18e4d9 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Thu, 9 Sep 2021 01:56:43 +0530 Subject: [PATCH 43/73] feat: improve shim generation for index components --- modules/emit-volar-types.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/emit-volar-types.ts b/modules/emit-volar-types.ts index bd130d3ec..c1ecb4f95 100644 --- a/modules/emit-volar-types.ts +++ b/modules/emit-volar-types.ts @@ -1,6 +1,7 @@ import { resolve } from "path" import { Module } from "@nuxt/types" import ts from "typescript" +import chokidar from "chokidar" const { readdir, writeFile } = require("fs").promises @@ -30,7 +31,7 @@ async function getAllVueComponentPaths(): Promise { vueFilePaths.push( `./${f .split("/") - .slice(componentsIndex + 1) + .slice(componentsIndex) .join("/")}` ) } @@ -45,8 +46,9 @@ function resolveComponentName(filename: string): string { return filename .split("/") .slice(index + 1) + .filter((x) => x !== "index.vue") // Remove index.vue .map((x) => x.split(".vue")[0]) // Remove extension - .filter((x) => x.toUpperCase() !== x.toLowerCase()) + .filter((x) => x.toUpperCase() !== x.toLowerCase()) // Remove non-word stuff .map((x) => titleCase(x)) // titlecase it .join("") } @@ -113,9 +115,7 @@ function generateTypeScriptDef(components: [string, string][]) { return printer.printFile(source) } -const module: Module<{}> = async function () { - if (!this.nuxt.options.dev) return - +async function generateShim() { const results = await getAllVueComponentPaths() const fileComponentNameCombo: [string, string][] = results.map((x) => [ resolveComponentName(x), @@ -126,4 +126,14 @@ const module: Module<{}> = async function () { await writeFile(resolve("shims-volar.d.ts"), typescriptString) } +const module: Module<{}> = async function () { + if (!this.nuxt.options.dev) return + + await generateShim() + + chokidar.watch(resolve("../components/")).on("all", async () => { + await generateShim() + }) +} + export default module From 02cf6200901f5e2c587eab364869f11e88d91499 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Thu, 9 Sep 2021 17:47:27 +0530 Subject: [PATCH 44/73] feat: port ace editor to codemirror Co-authored-by: Andrew Bastin --- assets/scss/styles.scss | 2 +- components/graphql/Request.vue | 49 ++--- components/graphql/RequestOptions.vue | 25 ++- components/graphql/Response.vue | 139 +++++--------- components/http/ResponseMeta.vue | 64 ++----- .../lenses/renderers/HTMLLensRenderer.vue | 175 ++++++++++-------- .../lenses/renderers/JSONLensRenderer.vue | 158 ++++++++-------- .../lenses/renderers/RawLensRenderer.vue | 149 ++++++++------- .../lenses/renderers/XMLLensRenderer.vue | 149 ++++++++------- helpers/editor/codemirror.ts | 12 +- 10 files changed, 437 insertions(+), 485 deletions(-) diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index a08772cd2..b253cd68d 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -467,7 +467,7 @@ input[type="checkbox"] { @apply border-b; @apply border-dividerLight; @apply w-full; - @apply h-auto; + @apply !h-full; } .CodeMirror * { diff --git a/components/graphql/Request.vue b/components/graphql/Request.vue index a84a16459..304ca6482 100644 --- a/components/graphql/Request.vue +++ b/components/graphql/Request.vue @@ -33,45 +33,32 @@
- diff --git a/components/graphql/RequestOptions.vue b/components/graphql/RequestOptions.vue index 2c4863d36..e8c7147f8 100644 --- a/components/graphql/RequestOptions.vue +++ b/components/graphql/RequestOptions.vue @@ -106,19 +106,7 @@ />
- +
@@ -323,6 +311,7 @@ import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" import { getCurrentStrategyID } from "~/helpers/network" import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest" import { useCodemirror } from "~/helpers/editor/codemirror" +import "codemirror/mode/javascript/javascript" const props = defineProps<{ conn: GQLConnection @@ -370,6 +359,16 @@ useCodemirror(bulkEditor, bulkHeaders, { completer: null, }) +const variableEditor = ref(null) + +useCodemirror(variableEditor, variableString, { + extendedEditorConfig: { + mode: "javascript", + }, + linter: null, + completer: null, +}) + const queryEditor = ref(null) const copyQueryIcon = ref("copy") diff --git a/components/graphql/Response.vue b/components/graphql/Response.vue index feca15fcd..09c6be4e1 100644 --- a/components/graphql/Response.vue +++ b/components/graphql/Response.vue @@ -59,38 +59,6 @@ justify-center " > -
-
- - {{ $t("shortcut.request.send_request") }} - - - {{ $t("shortcut.general.show_all") }} - - -
-
-
- {{ getSpecialKey() }} - G -
-
- {{ getSpecialKey() }} - K -
- -
-
- diff --git a/components/lenses/renderers/JSONLensRenderer.vue b/components/lenses/renderers/JSONLensRenderer.vue index fc6bc2f12..c1ea9347d 100644 --- a/components/lenses/renderers/JSONLensRenderer.vue +++ b/components/lenses/renderers/JSONLensRenderer.vue @@ -36,88 +36,92 @@
- +
- diff --git a/components/lenses/renderers/RawLensRenderer.vue b/components/lenses/renderers/RawLensRenderer.vue index 563f9de1f..ec5b015aa 100644 --- a/components/lenses/renderers/RawLensRenderer.vue +++ b/components/lenses/renderers/RawLensRenderer.vue @@ -36,79 +36,92 @@
- +
- diff --git a/components/lenses/renderers/XMLLensRenderer.vue b/components/lenses/renderers/XMLLensRenderer.vue index eb5340f41..11a6463a6 100644 --- a/components/lenses/renderers/XMLLensRenderer.vue +++ b/components/lenses/renderers/XMLLensRenderer.vue @@ -36,79 +36,92 @@
- +
- diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 487365c49..e7781ae7c 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -44,6 +44,7 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { extraKeys: { "Ctrl-Space": "autocomplete", }, + viewportMargin: Infinity, } /** @@ -120,6 +121,8 @@ export function useCodemirror( cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG) + cm.value.setValue(value.value) + setTheme() updateEditorConfig() updateLinterConfig() @@ -139,7 +142,14 @@ export function useCodemirror( }) // Reinitialize if the target ref updates - watch(el, initialize) + watch(el, () => { + if (cm.value) { + const parent = cm.value.getWrapperElement() + parent.remove() + cm.value = null + } + initialize() + }) const setTheme = () => { if (cm.value) { From c6c08f6c60331085cac4c0d9c0527bd3a754c468 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Thu, 9 Sep 2021 20:50:04 +0530 Subject: [PATCH 45/73] feat: reactive line wrap on codemirror Co-authored-by: Andrew Bastin --- assets/icons/corner-down-left.svg | 1 + assets/scss/styles.scss | 2 +- .../lenses/renderers/HTMLLensRenderer.vue | 32 +++++++++++++------ .../lenses/renderers/JSONLensRenderer.vue | 32 +++++++++++++------ .../lenses/renderers/RawLensRenderer.vue | 32 +++++++++++++------ .../lenses/renderers/XMLLensRenderer.vue | 32 +++++++++++++------ locales/en.json | 1 + 7 files changed, 95 insertions(+), 37 deletions(-) create mode 100644 assets/icons/corner-down-left.svg diff --git a/assets/icons/corner-down-left.svg b/assets/icons/corner-down-left.svg new file mode 100644 index 000000000..7a8b7473a --- /dev/null +++ b/assets/icons/corner-down-left.svg @@ -0,0 +1 @@ + diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index b253cd68d..8b826e2e2 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -475,7 +475,7 @@ input[type="checkbox"] { } .CodeMirror-scroll { - @apply min-h-32; + @apply min-h-64; } @media (max-width: 767px) { diff --git a/components/lenses/renderers/HTMLLensRenderer.vue b/components/lenses/renderers/HTMLLensRenderer.vue index f3a751de4..d7f1044c0 100644 --- a/components/lenses/renderers/HTMLLensRenderer.vue +++ b/components/lenses/renderers/HTMLLensRenderer.vue @@ -17,6 +17,14 @@ {{ $t("response.body") }}
+ diff --git a/helpers/editorutils.js b/helpers/editorutils.js index 0955bbf37..9dd46a4bf 100644 --- a/helpers/editorutils.js +++ b/helpers/editorutils.js @@ -1,12 +1,12 @@ const mimeToMode = { - "text/plain": "plain_text", - "text/html": "html", - "application/xml": "xml", - "application/hal+json": "json", - "application/vnd.api+json": "json", - "application/json": "json", + "text/plain": "text/x-yaml", + "text/html": "htmlmixed", + "application/xml": "application/xml", + "application/hal+json": "application/ld+json", + "application/vnd.api+json": "application/ld+json", + "application/json": "application/ld+json", } export function getEditorLangForMimeType(mimeType) { - return mimeToMode[mimeType] || "plain_text" + return mimeToMode[mimeType] || "text/x-yaml" } From 2eb0a4c754d0223442cd652f58cd4d7323294a8d Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Fri, 10 Sep 2021 10:46:58 +0530 Subject: [PATCH 48/73] feat: reactive syntax + line wrap on raw body --- components/http/RawBody.vue | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/components/http/RawBody.vue b/components/http/RawBody.vue index 6a440f464..1b31936dd 100644 --- a/components/http/RawBody.vue +++ b/components/http/RawBody.vue @@ -24,6 +24,13 @@ :title="$t('app.wiki')" svg="help-circle" /> + diff --git a/components/http/Tests.vue b/components/http/Tests.vue index a44afcc8b..2cba86490 100644 --- a/components/http/Tests.vue +++ b/components/http/Tests.vue @@ -24,6 +24,13 @@ :title="$t('app.wiki')" svg="help-circle" /> +
- +
+import { reactive, ref } from "@nuxtjs/composition-api" import { useTestScript } from "~/newstore/RESTSession" import testSnippets from "~/helpers/testSnippets" +import "codemirror/mode/javascript/javascript" +import { useCodemirror } from "~/helpers/editor/codemirror" +import linter from "~/helpers/editor/linting/testScript" +import completer from "~/helpers/editor/completion/testScript" const testScript = useTestScript() +const testScriptEditor = ref(null) +const linewrapEnabled = ref(true) + +useCodemirror( + testScriptEditor, + testScript, + reactive({ + extendedEditorConfig: { + mode: "application/javascript", + lineWrapping: linewrapEnabled, + }, + linter, + completer, + }) +) + const useSnippet = (script: string) => { testScript.value += script } From 457b6b982cfed04c9ab60824f49cb73876194cba Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Fri, 10 Sep 2021 16:12:04 +0530 Subject: [PATCH 50/73] feat: codemirror for graphql query, scheme and response --- components/graphql/RequestOptions.vue | 45 ++-- components/graphql/Response.vue | 51 ++-- components/graphql/Sidebar.vue | 356 ++++++++++++-------------- layouts/default.vue | 2 +- 4 files changed, 219 insertions(+), 235 deletions(-) diff --git a/components/graphql/RequestOptions.vue b/components/graphql/RequestOptions.vue index e8c7147f8..31da91239 100644 --- a/components/graphql/RequestOptions.vue +++ b/components/graphql/RequestOptions.vue @@ -55,20 +55,7 @@ />
- +
@@ -284,6 +271,7 @@ diff --git a/layouts/default.vue b/layouts/default.vue index 5bc5bfdcd..544568052 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -24,7 +24,7 @@ >
- +
From b4ed6fd10782d77c82e5813a84798772808dc011 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Fri, 10 Sep 2021 18:27:31 +0530 Subject: [PATCH 51/73] feat: codemirror for import curl and codegens --- assets/scss/styles.scss | 2 - components/http/CodegenModal.vue | 28 +++-- components/http/ImportCurl.vue | 209 ++++++++++++++++--------------- helpers/codegen/codegen.ts | 2 - 4 files changed, 121 insertions(+), 120 deletions(-) diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss index 8b826e2e2..16aa06884 100644 --- a/assets/scss/styles.scss +++ b/assets/scss/styles.scss @@ -464,8 +464,6 @@ input[type="checkbox"] { .CodeMirror { @apply block; - @apply border-b; - @apply border-dividerLight; @apply w-full; @apply !h-full; } diff --git a/components/http/CodegenModal.vue b/components/http/CodegenModal.vue index fe3c39cee..029b28f14 100644 --- a/components/http/CodegenModal.vue +++ b/components/http/CodegenModal.vue @@ -38,21 +38,11 @@ {{ t("request.generated_code") }}
- + class="w-full border border-dividerLight rounded block" + > diff --git a/components/http/ImportCurl.vue b/components/http/ImportCurl.vue index 422f78993..671541597 100644 --- a/components/http/ImportCurl.vue +++ b/components/http/ImportCurl.vue @@ -13,7 +13,7 @@ + + diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 58cfd114f..7319c7413 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -201,7 +201,6 @@ export function useCodemirror( watch(cursor, (value) => { if (value !== cm.value?.getCursor()) { cm.value?.focus() - console.log(value) cm.value?.setCursor(value) } }) diff --git a/package-lock.json b/package-lock.json index 298ea0f2c..ee0fc457c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "hoppscotch", "version": "2.0.0", "dependencies": { "@apollo/client": "^3.4.10", From 4a332f40e51a92e0b54e6c390d12e5cd15ede324 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 14 Sep 2021 23:28:39 +0530 Subject: [PATCH 70/73] fix: json outline line index --- components/lenses/renderers/JSONLensRenderer.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/lenses/renderers/JSONLensRenderer.vue b/components/lenses/renderers/JSONLensRenderer.vue index d4e5dc2f2..79652d54f 100644 --- a/components/lenses/renderers/JSONLensRenderer.vue +++ b/components/lenses/renderers/JSONLensRenderer.vue @@ -219,7 +219,9 @@ const { cursor } = useCodemirror( ) const jumpCursor = (ast: JSONValue | JSONObjectMember) => { - cursor.value = convertIndexToLineCh(jsonBodyText.value, ast.start) + const pos = convertIndexToLineCh(jsonBodyText.value, ast.start) + pos.line-- + cursor.value = pos } const downloadResponse = () => { From 1dfc8e2973f52f5a997244969d7b991b8aeb1809 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 14 Sep 2021 23:32:43 +0530 Subject: [PATCH 71/73] perf: remove absolute files --- helpers/outline.js | 124 --------------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 helpers/outline.js diff --git a/helpers/outline.js b/helpers/outline.js deleted file mode 100644 index 1eb3e31d5..000000000 --- a/helpers/outline.js +++ /dev/null @@ -1,124 +0,0 @@ -import jsonParse from "./jsonParse" - -export default () => { - let jsonAST = {} - let path = [] - - const init = (jsonStr) => { - jsonAST = jsonParse(jsonStr) - linkParents(jsonAST) - } - - const setNewText = (jsonStr) => { - init(jsonStr) - path = [] - } - - const linkParents = (node) => { - if (node.kind === "Object") { - if (node.members) { - node.members.forEach((m) => { - m.parent = node - linkParents(m) - }) - } - } else if (node.kind === "Array") { - if (node.values) { - node.values.forEach((v) => { - v.parent = node - linkParents(v) - }) - } - } else if (node.kind === "Member") { - if (node.value) { - node.value.parent = node - linkParents(node.value) - } - } - } - - const genPath = (index) => { - let output = {} - path = [] - let current = jsonAST - if (current.kind === "Object") { - path.push({ label: "{}", obj: "root" }) - } else if (current.kind === "Array") { - path.push({ label: "[]", obj: "root" }) - } - let over = false - - try { - while (!over) { - if (current.kind === "Object") { - let i = 0 - let found = false - while (i < current.members.length) { - const m = current.members[i] - if (m.start <= index && m.end >= index) { - path.push({ label: m.key.value, obj: m }) - current = current.members[i] - found = true - break - } - i++ - } - if (!found) over = true - } else if (current.kind === "Array") { - if (current.values) { - let i = 0 - let found = false - while (i < current.values.length) { - const m = current.values[i] - if (m.start <= index && m.end >= index) { - path.push({ label: `[${i.toString()}]`, obj: m }) - current = current.values[i] - found = true - break - } - i++ - } - if (!found) over = true - } else over = true - } else if (current.kind === "Member") { - if (current.value) { - if (current.value.start <= index && current.value.end >= index) { - current = current.value - } else over = true - } else over = true - } else if ( - current.kind === "String" || - current.kind === "Number" || - current.kind === "Boolean" || - current.kind === "Null" - ) { - if (current.start <= index && current.end >= index) { - path.push({ label: `${current.value}`, obj: current }) - } - over = true - } - } - output = { success: true, res: path.map((p) => p.label) } - } catch (e) { - output = { success: false, res: e } - } - return output - } - - const getSiblings = (index) => { - const parent = path[index]?.obj?.parent - if (!parent) return [] - else if (parent.kind === "Object") { - return parent.members - } else if (parent.kind === "Array") { - return parent.values - } else return [] - } - - return { - init, - genPath, - getSiblings, - setNewText, - } -} From 96bcbc80f82deffe627b5ca458c59e0cee643392 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Tue, 14 Sep 2021 23:43:20 +0530 Subject: [PATCH 72/73] fix(ci): bump deps + fix tests --- helpers/__tests__/editorutils.spec.js | 14 +- package-lock.json | 1096 +++++++++++++------------ package.json | 6 +- 3 files changed, 559 insertions(+), 557 deletions(-) diff --git a/helpers/__tests__/editorutils.spec.js b/helpers/__tests__/editorutils.spec.js index b0e38e429..61616cfa8 100644 --- a/helpers/__tests__/editorutils.spec.js +++ b/helpers/__tests__/editorutils.spec.js @@ -15,16 +15,16 @@ describe("getEditorLangForMimeType", () => { expect(getEditorLangForMimeType("text/html")).toMatch("html") }) - test("returns 'plain_text' for plain text mime", () => { - expect(getEditorLangForMimeType("text/plain")).toMatch("plain_text") + test("returns 'text/x-yaml' for plain text mime", () => { + expect(getEditorLangForMimeType("text/plain")).toMatch("text/x-yaml") }) - test("returns 'plain_text' for unimplemented mimes", () => { - expect(getEditorLangForMimeType("image/gif")).toMatch("plain_text") + test("returns 'text/x-yaml' for unimplemented mimes", () => { + expect(getEditorLangForMimeType("image/gif")).toMatch("text/x-yaml") }) - test("returns 'plain_text' for null/undefined mimes", () => { - expect(getEditorLangForMimeType(null)).toMatch("plain_text") - expect(getEditorLangForMimeType(undefined)).toMatch("plain_text") + test("returns 'text/x-yaml' for null/undefined mimes", () => { + expect(getEditorLangForMimeType(null)).toMatch("text/x-yaml") + expect(getEditorLangForMimeType(undefined)).toMatch("text/x-yaml") }) }) diff --git a/package-lock.json b/package-lock.json index 49ed46fdf..bfa0b27c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,21 +70,21 @@ "@vue/runtime-dom": "^3.2.11", "@vue/test-utils": "^1.2.2", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-nuxt": ">=2.0.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-vue": "^7.17.0", "husky": "^7.0.2", - "jest": "^27.1.1", + "jest": "^27.2.0", "jest-serializer-vue": "^2.0.2", "lint-staged": "^11.1.2", "nuxt-windicss": "^1.2.4", "prettier": "^2.4.0", "pretty-quick": "^3.1.1", "raw-loader": "^4.0.2", - "sass": "^1.39.2", + "sass": "^1.40.1", "sass-loader": "^10.2.0", "stylelint": "^13.12.0", "stylelint-config-prettier": "^8.0.2", @@ -4203,16 +4203,16 @@ } }, "node_modules/@jest/console": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.1.1.tgz", - "integrity": "sha512-VpQJRsWSeAem0zpBjeRtDbcD6DlbNoK11dNYt+PSQ+DDORh9q2/xyEpErfwgnLjWX0EKkSZmTGx/iH9Inzs6vQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.0.tgz", + "integrity": "sha512-35z+RqsK2CCgNxn+lWyK8X4KkaDtfL4BggT7oeZ0JffIiAiEYFYPo5B67V50ZubqDS1ehBrdCR2jduFnIrZOYw==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.1.1", - "jest-util": "^27.1.1", + "jest-message-util": "^27.2.0", + "jest-util": "^27.2.0", "slash": "^3.0.0" }, "engines": { @@ -4290,15 +4290,15 @@ } }, "node_modules/@jest/core": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.1.1.tgz", - "integrity": "sha512-oCkKeTgI0emznKcLoq5OCD0PhxCijA4l7ejDnWW3d5bgSi+zfVaLybVqa+EQOxpNejQWtTna7tmsAXjMN9N43Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.0.tgz", + "integrity": "sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw==", "dev": true, "dependencies": { - "@jest/console": "^27.1.1", - "@jest/reporters": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/reporters": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "ansi-escapes": "^4.2.1", @@ -4307,18 +4307,18 @@ "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-changed-files": "^27.1.1", - "jest-config": "^27.1.1", - "jest-haste-map": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-config": "^27.2.0", + "jest-haste-map": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-resolve-dependencies": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", - "jest-watcher": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-resolve-dependencies": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", + "jest-watcher": "^27.2.0", "micromatch": "^4.0.4", "p-each-series": "^2.1.0", "rimraf": "^3.0.0", @@ -4404,32 +4404,32 @@ } }, "node_modules/@jest/core/node_modules/jest-config": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.1.1.tgz", - "integrity": "sha512-2iSd5zoJV4MsWPcLCGwUVUY/j6pZXm4Qd3rnbCtrd9EHNTg458iHw8PZztPQXfxKBKJxLfBk7tbZqYF8MGtxJA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", + "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.1.1", + "@jest/test-sequencer": "^27.2.0", "@jest/types": "^27.1.1", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.1.1", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", + "jest-circus": "^27.2.0", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.1.1", + "jest-jasmine2": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -4502,12 +4502,12 @@ } }, "node_modules/@jest/environment": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.1.1.tgz", - "integrity": "sha512-+y882/ZdxhyqF5RzxIrNIANjHj991WH7jifdcplzMDosDUOyCACFYUyVTBGbSTocbU+s1cesroRzkwi8hZ9SHg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.0.tgz", + "integrity": "sha512-iPWmQI0wRIYSZX3wKu4FXHK4eIqkfq6n1DCDJS+v3uby7SOXrHvX4eiTBuEdSvtDRMTIH2kjrSkjHf/F9JIYyQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.1.1", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1" @@ -4517,46 +4517,46 @@ } }, "node_modules/@jest/fake-timers": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.1.1.tgz", - "integrity": "sha512-u8TJ5VlsVYTsGFatoyIae2l25pku4Bu15QCPTx2Gs5z+R//Ee3tHN85462Vc9yGVcdDvgADbqNkhOLxbEwPjMQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.0.tgz", + "integrity": "sha512-gSu3YHvQOoVaTWYGgHFB7IYFtcF2HBzX4l7s47VcjvkUgL4/FBnE20x7TNLa3W6ABERtGd5gStSwsA8bcn+c4w==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "@sinonjs/fake-timers": "^7.0.2", "@types/node": "*", - "jest-message-util": "^27.1.1", + "jest-message-util": "^27.2.0", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1" + "jest-util": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/globals": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.1.1.tgz", - "integrity": "sha512-Q3JcTPmY+DAEHnr4MpnBV3mwy50EGrTC6oSDTNnW7FNGGacTJAfpWNk02D7xv422T1OzK2A2BKx+26xJOvHkyw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.0.tgz", + "integrity": "sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg==", "dev": true, "dependencies": { - "@jest/environment": "^27.1.1", + "@jest/environment": "^27.2.0", "@jest/types": "^27.1.1", - "expect": "^27.1.1" + "expect": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.1.1.tgz", - "integrity": "sha512-cEERs62n1P4Pqox9HWyNOEkP57G95aK2mBjB6D8Ruz1Yc98fKH53b58rlVEnsY5nLmkLNZk65fxNi9C0Yds/8w==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.0.tgz", + "integrity": "sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -4568,10 +4568,10 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -4649,9 +4649,9 @@ } }, "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "dependencies": { "@types/node": "*", @@ -4722,12 +4722,12 @@ } }, "node_modules/@jest/test-result": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.1.1.tgz", - "integrity": "sha512-8vy75A0Jtfz9DqXFUkjC5Co/wRla+D7qRFdShUY8SbPqBS3GBx3tpba7sGKFos8mQrdbe39n+c1zgVKtarfy6A==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.0.tgz", + "integrity": "sha512-JPPqn8h0RGr4HyeY1Km+FivDIjTFzDROU46iAvzVjD42ooGwYoqYO/MQTilhfajdz6jpVnnphFrKZI5OYrBONA==", "dev": true, "dependencies": { - "@jest/console": "^27.1.1", + "@jest/console": "^27.2.0", "@jest/types": "^27.1.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" @@ -4737,24 +4737,24 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.1.1.tgz", - "integrity": "sha512-l8zD3EdeixvwmLNlJoMX3hhj8iIze95okj4sqmBzOq/zW8gZLElUveH4bpKEMuR+Nweazjlwc7L6g4C26M/y6Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz", + "integrity": "sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA==", "dev": true, "dependencies": { - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", - "jest-runtime": "^27.1.1" + "jest-haste-map": "^27.2.0", + "jest-runtime": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/transform": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.1.1.tgz", - "integrity": "sha512-qM19Eu75U6Jc5zosXXVnq900Nl9JDpoGaZ4Mg6wZs7oqbu3heYSMOZS19DlwjlhWdfNRjF4UeAgkrCJCK3fEXg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.0.tgz", + "integrity": "sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", @@ -4764,9 +4764,9 @@ "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", + "jest-haste-map": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -11163,16 +11163,16 @@ } }, "node_modules/babel-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.1.1.tgz", - "integrity": "sha512-JA+dzJl4n2RBvWQEnph6HJaTHrsIPiXGQYatt/D8nR4UpX9UG4GaDzykVVPQBbrdTebZREkRb6SOxyIXJRab6Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.0.tgz", + "integrity": "sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA==", "dev": true, "dependencies": { - "@jest/transform": "^27.1.1", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.6", + "babel-preset-jest": "^27.2.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" @@ -11347,9 +11347,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", - "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -11485,12 +11485,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", - "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.0.6", + "babel-plugin-jest-hoist": "^27.2.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -16482,16 +16482,16 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/expect": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.1.1.tgz", - "integrity": "sha512-JQAzp0CJoFFHF1RnOtrMUNMdsfx/Tl0+FhRzVl8q0fa23N+JyWdPXwb3T5rkHCvyo9uttnK7lVdKCBl1b/9EDw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.0.tgz", + "integrity": "sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "ansi-styles": "^5.0.0", "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-regex-util": "^27.0.6" }, "engines": { @@ -20275,14 +20275,14 @@ } }, "node_modules/jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.1.1.tgz", - "integrity": "sha512-LFTEZOhoZNR/2DQM3OCaK5xC6c55c1OWhYh0njRsoHX0qd6x4nkcgenkSH0JKjsAGMTmmJAoL7/oqYHMfwhruA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.0.tgz", + "integrity": "sha512-oUqVXyvh5YwEWl263KWdPUAqEzBFzGHdFLQ05hUnITr1tH+9SscEI9A/GH9eBClA+Nw1ct+KNuuOV6wlnmBPcg==", "dev": true, "dependencies": { - "@jest/core": "^27.1.1", + "@jest/core": "^27.2.0", "import-local": "^3.0.2", - "jest-cli": "^27.1.1" + "jest-cli": "^27.2.0" }, "bin": { "jest": "bin/jest.js" @@ -20314,27 +20314,27 @@ } }, "node_modules/jest-circus": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.1.1.tgz", - "integrity": "sha512-Xed1ApiMFu/yzqGMBToHr8sp2gkX/ARZf4nXoGrHJrXrTUdVIWiVYheayfcOaPdQvQEE/uyBLgW7I7YBLIrAXQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.0.tgz", + "integrity": "sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA==", "dev": true, "dependencies": { - "@jest/environment": "^27.1.1", - "@jest/test-result": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "is-generator-fn": "^2.0.0", - "jest-each": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1", + "jest-each": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -20414,21 +20414,21 @@ } }, "node_modules/jest-cli": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.1.1.tgz", - "integrity": "sha512-LCjfEYp9D3bcOeVUUpEol9Y1ijZYMWVqflSmtw/wX+6Fb7zP4IlO14/6s9v1pxsoM4Pn46+M2zABgKuQjyDpTw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.0.tgz", + "integrity": "sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA==", "dev": true, "dependencies": { - "@jest/core": "^27.1.1", - "@jest/test-result": "^27.1.1", + "@jest/core": "^27.2.0", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-config": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "prompts": "^2.0.1", "yargs": "^16.0.3" }, @@ -20514,32 +20514,32 @@ } }, "node_modules/jest-cli/node_modules/jest-config": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.1.1.tgz", - "integrity": "sha512-2iSd5zoJV4MsWPcLCGwUVUY/j6pZXm4Qd3rnbCtrd9EHNTg458iHw8PZztPQXfxKBKJxLfBk7tbZqYF8MGtxJA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", + "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.1.1", + "@jest/test-sequencer": "^27.2.0", "@jest/types": "^27.1.1", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.1.1", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", + "jest-circus": "^27.2.0", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.1.1", + "jest-jasmine2": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -20630,15 +20630,15 @@ } }, "node_modules/jest-diff": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.1.1.tgz", - "integrity": "sha512-m/6n5158rqEriTazqHtBpOa2B/gGgXJijX6nsEgZfbJ/3pxQcdpVXBe+FP39b1dxWHyLVVmuVXddmAwtqFO4Lg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.0.tgz", + "integrity": "sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^27.0.6", "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -20727,16 +20727,16 @@ } }, "node_modules/jest-each": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.1.1.tgz", - "integrity": "sha512-r6hOsTLavUBb1xN0uDa89jdDeBmJ+K49fWpbyxeGRA2pLY46PlC4z551/cWNQzrj+IUa5/gSRsCIV/01HdNPug==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.0.tgz", + "integrity": "sha512-biDmmUQjg+HZOB7MfY2RHSFL3j418nMoC3TK3pGAj880fQQSxvQe1y2Wy23JJJNUlk6YXiGU0yWy86Le1HBPmA==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1" + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -20813,17 +20813,17 @@ } }, "node_modules/jest-environment-jsdom": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.1.1.tgz", - "integrity": "sha512-6vOnoZ6IaExuw7FvnuJhA1qFYv1DDSnN0sQowzolNwxQp7bG1YhLxj2YU1sVXAYA3IR3MbH2mbnJUsLUWfyfzw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.0.tgz", + "integrity": "sha512-wNQJi6Rd/AkUWqTc4gWhuTIFPo7tlMK0RPZXeM6AqRHZA3D3vwvTa9ktAktyVyWYmUoXdYstOfyYMG3w4jt7eA==", "dev": true, "dependencies": { - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "jsdom": "^16.6.0" }, "engines": { @@ -20831,17 +20831,17 @@ } }, "node_modules/jest-environment-node": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.1.1.tgz", - "integrity": "sha512-OEGeZh0PwzngNIYWYgWrvTcLygopV8OJbC9HNb0j70VBKgEIsdZkYhwcFnaURX83OHACMqf1pa9Tv5Pw5jemrg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.0.tgz", + "integrity": "sha512-WbW+vdM4u88iy6Q3ftUEQOSgMPtSgjm3qixYYK2AKEuqmFO2zmACTw1vFUB0qI/QN88X6hA6ZkVKIdIWWzz+yg==", "dev": true, "dependencies": { - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1" + "jest-util": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -20857,9 +20857,9 @@ } }, "node_modules/jest-haste-map": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.1.1.tgz", - "integrity": "sha512-NGLYVAdh5C8Ezg5QBFzrNeYsfxptDBPlhvZNaicLiZX77F/rS27a9M6u9ripWAaaD54xnWdZNZpEkdjD5Eo5aQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.0.tgz", + "integrity": "sha512-laFet7QkNlWjwZtMGHCucLvF8o9PAh2cgePRck1+uadSM4E4XH9J4gnx4do+a6do8ZV5XHNEAXEkIoNg5XUH2Q==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", @@ -20870,8 +20870,8 @@ "graceful-fs": "^4.2.4", "jest-regex-util": "^27.0.6", "jest-serializer": "^27.0.6", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "micromatch": "^4.0.4", "walker": "^1.0.7" }, @@ -20892,9 +20892,9 @@ } }, "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "dependencies": { "@types/node": "*", @@ -20921,28 +20921,28 @@ } }, "node_modules/jest-jasmine2": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.1.1.tgz", - "integrity": "sha512-0LAzUmcmvQwjIdJt0cXUVX4G5qjVXE8ELt6nbMNDzv2yAs2hYCCUtQq+Eje70GwAysWCGcS64QeYj5VPHYVxPg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz", + "integrity": "sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA==", "dev": true, "dependencies": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.1.1", + "@jest/environment": "^27.2.0", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "is-generator-fn": "^2.0.0", - "jest-each": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1", + "jest-each": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0", "throat": "^6.0.1" }, "engines": { @@ -21020,28 +21020,28 @@ } }, "node_modules/jest-leak-detector": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.1.1.tgz", - "integrity": "sha512-gwSgzmqShoeEsEVpgObymQPrM9P6557jt1EsFW5aCeJ46Cme0EdjYU7xr6llQZ5GpWDl56eOstUaPXiZOfiTKw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.0.tgz", + "integrity": "sha512-e91BIEmbZw5+MHkB4Hnrq7S86coTxUMCkz4n7DLmQYvl9pEKmRx9H/JFH87bBqbIU5B2Ju1soKxRWX6/eGFGpA==", "dev": true, "dependencies": { "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.1.1.tgz", - "integrity": "sha512-Q1a10w9Y4sh0wegkdP6reQOa/Dtz7nAvDqBgrat1ItZAUvk4jzXAqyhXPu/ZuEtDaXaNKpdRPRQA8bvkOh2Eaw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz", + "integrity": "sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.1.1", + "jest-diff": "^27.2.0", "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -21118,9 +21118,9 @@ } }, "node_modules/jest-message-util": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.1.1.tgz", - "integrity": "sha512-b697BOJV93+AVGvzLRtVZ0cTVRbd59OaWnbB2D75GRaIMc4I+Z9W0wHxbfjW01JWO+TqqW4yevT0aN7Fd0XWng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.0.tgz", + "integrity": "sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", @@ -21129,7 +21129,7 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1", + "pretty-format": "^27.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -21247,19 +21247,19 @@ } }, "node_modules/jest-resolve": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.1.1.tgz", - "integrity": "sha512-M41YFmWhvDVstwe7XuV21zynOiBLJB5Sk0GrIsYYgTkjfEWNLVXDjAyq1W7PHseaYNOxIc0nOGq/r5iwcZNC1A==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.0.tgz", + "integrity": "sha512-v09p9Ib/VtpHM6Cz+i9lEAv1Z/M5NVxsyghRHRMEUOqwPQs3zwTdwp1xS3O/k5LocjKiGS0OTaJoBSpjbM2Jlw==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "chalk": "^4.0.0", "escalade": "^3.1.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", + "jest-haste-map": "^27.2.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "resolve": "^1.20.0", "slash": "^3.0.0" }, @@ -21268,14 +21268,14 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.1.1.tgz", - "integrity": "sha512-sYZR+uBjFDCo4VhYeazZf/T+ryYItvdLKu9vHatqkUqHGjDMrdEPOykiqC2iEpaCFTS+3iL/21CYiJuKdRbniw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz", + "integrity": "sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.1.1" + "jest-snapshot": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -21352,15 +21352,15 @@ } }, "node_modules/jest-runner": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.1.1.tgz", - "integrity": "sha512-lP3MBNQhg75/sQtVkC8dsAQZumvy3lHK/YIwYPfEyqGIX1qEcnYIRxP89q0ZgC5ngvi1vN2P5UFHszQxguWdng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.0.tgz", + "integrity": "sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww==", "dev": true, "dependencies": { - "@jest/console": "^27.1.1", - "@jest/environment": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/environment": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", @@ -21368,15 +21368,15 @@ "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", - "jest-haste-map": "^27.1.1", - "jest-leak-detector": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", + "jest-haste-map": "^27.2.0", + "jest-leak-detector": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -21443,9 +21443,9 @@ } }, "node_modules/jest-runner/node_modules/jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "dependencies": { "@types/node": "*", @@ -21484,18 +21484,18 @@ } }, "node_modules/jest-runtime": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.1.1.tgz", - "integrity": "sha512-FEwy+tSzmsvuKaQpyYsUyk31KG5vMmA2r2BSTHgv0yNfcooQdm2Ke91LM9Ud8D3xz8CLDHJWAI24haMFTwrsPg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.0.tgz", + "integrity": "sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ==", "dev": true, "dependencies": { - "@jest/console": "^27.1.1", - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", - "@jest/globals": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", + "@jest/globals": "^27.2.0", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", @@ -21505,14 +21505,14 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-mock": "^27.1.1", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^16.0.3" @@ -21632,9 +21632,9 @@ } }, "node_modules/jest-snapshot": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.1.1.tgz", - "integrity": "sha512-Wi3QGiuRFo3lU+EbQmZnBOks0CJyAMPHvYoG7iJk00Do10jeOyuOEO0Jfoaoun8+8TDv+Nzl7Aswir/IK9+1jg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.0.tgz", + "integrity": "sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ==", "dev": true, "dependencies": { "@babel/core": "^7.7.2", @@ -21643,23 +21643,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.1.1", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "graceful-fs": "^4.2.4", - "jest-diff": "^27.1.1", + "jest-diff": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-util": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-util": "^27.2.0", "natural-compare": "^1.4.0", - "pretty-format": "^27.1.1", + "pretty-format": "^27.2.0", "semver": "^7.3.2" }, "engines": { @@ -21770,9 +21770,9 @@ "dev": true }, "node_modules/jest-util": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.1.1.tgz", - "integrity": "sha512-zf9nEbrASWn2mC/L91nNb0K+GkhFvi4MP6XJG2HqnHzHvLYcs7ou/In68xYU1i1dSkJlrWcYfWXQE8nVR+nbOA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.0.tgz", + "integrity": "sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", @@ -21857,9 +21857,9 @@ } }, "node_modules/jest-validate": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.1.1.tgz", - "integrity": "sha512-N5Er5FKav/8m2dJwn7BGnZwnoD1BSc8jx5T+diG2OvyeugvZDhPeAt5DrNaGkkaKCrSUvuE7A5E4uHyT7Vj0Mw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.0.tgz", + "integrity": "sha512-uIEZGkFKk3+4liA81Xu0maG5aGDyPLdp+4ed244c+Ql0k3aLWQYcMbaMLXOIFcb83LPHzYzqQ8hwNnIxTqfAGQ==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", @@ -21867,7 +21867,7 @@ "chalk": "^4.0.0", "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -21956,17 +21956,17 @@ } }, "node_modules/jest-watcher": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.1.1.tgz", - "integrity": "sha512-XQzyHbxziDe+lZM6Dzs40fEt4q9akOGwitJnxQasJ9WG0bv3JGiRlsBgjw13znGapeMtFaEsyhL0Cl04IbaoWQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.0.tgz", + "integrity": "sha512-SjRWhnr+qO8aBsrcnYIyF+qRxNZk6MZH8TIDgvi+VlsyrvOyqg0d+Rm/v9KHiTtC9mGGeFi9BFqgavyWib6xLg==", "dev": true, "dependencies": { - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "string-length": "^4.0.1" }, "engines": { @@ -27589,9 +27589,9 @@ } }, "node_modules/pretty-format": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.1.1.tgz", - "integrity": "sha512-zdBi/xlstKJL42UH7goQti5Hip/B415w1Mfj+WWWYMBylAYtKESnXGUtVVcMVid9ReVjypCotUV6CEevYPHv2g==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.0.tgz", + "integrity": "sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA==", "dev": true, "dependencies": { "@jest/types": "^27.1.1", @@ -29522,9 +29522,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.39.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.39.2.tgz", - "integrity": "sha512-4/6Vn2RPc+qNwSclUSKvssh7dqK1Ih3FfHBW16I/GfH47b3scbYeOw65UIrYG7PkweFiKbpJjgkf5CV8EMmvzw==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.40.1.tgz", + "integrity": "sha512-M6WskYLzTfdZdb09W9SftIScjudL8jNkhdh9z96U+olQaKIcw2Knb6QLL9bUhnuSm4VD+1yJVaO2/ENDPMTtAQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0" @@ -30329,9 +30329,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -30517,12 +30517,13 @@ } }, "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", + "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", "dev": true, "dependencies": { - "escape-string-regexp": "^2.0.0" + "escape-string-regexp": "^2.0.0", + "source-map-support": "^0.5.20" }, "engines": { "node": ">=10" @@ -39593,16 +39594,16 @@ "dev": true }, "@jest/console": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.1.1.tgz", - "integrity": "sha512-VpQJRsWSeAem0zpBjeRtDbcD6DlbNoK11dNYt+PSQ+DDORh9q2/xyEpErfwgnLjWX0EKkSZmTGx/iH9Inzs6vQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.0.tgz", + "integrity": "sha512-35z+RqsK2CCgNxn+lWyK8X4KkaDtfL4BggT7oeZ0JffIiAiEYFYPo5B67V50ZubqDS1ehBrdCR2jduFnIrZOYw==", "dev": true, "requires": { "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.1.1", - "jest-util": "^27.1.1", + "jest-message-util": "^27.2.0", + "jest-util": "^27.2.0", "slash": "^3.0.0" }, "dependencies": { @@ -39658,15 +39659,15 @@ } }, "@jest/core": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.1.1.tgz", - "integrity": "sha512-oCkKeTgI0emznKcLoq5OCD0PhxCijA4l7ejDnWW3d5bgSi+zfVaLybVqa+EQOxpNejQWtTna7tmsAXjMN9N43Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.0.tgz", + "integrity": "sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw==", "dev": true, "requires": { - "@jest/console": "^27.1.1", - "@jest/reporters": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/reporters": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "ansi-escapes": "^4.2.1", @@ -39675,18 +39676,18 @@ "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-changed-files": "^27.1.1", - "jest-config": "^27.1.1", - "jest-haste-map": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-config": "^27.2.0", + "jest-haste-map": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-resolve-dependencies": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", - "jest-watcher": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-resolve-dependencies": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", + "jest-watcher": "^27.2.0", "micromatch": "^4.0.4", "p-each-series": "^2.1.0", "rimraf": "^3.0.0", @@ -39743,32 +39744,32 @@ "dev": true }, "jest-config": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.1.1.tgz", - "integrity": "sha512-2iSd5zoJV4MsWPcLCGwUVUY/j6pZXm4Qd3rnbCtrd9EHNTg458iHw8PZztPQXfxKBKJxLfBk7tbZqYF8MGtxJA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", + "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.1.1", + "@jest/test-sequencer": "^27.2.0", "@jest/types": "^27.1.1", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.1.1", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", + "jest-circus": "^27.2.0", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.1.1", + "jest-jasmine2": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" } }, "supports-color": { @@ -39805,52 +39806,52 @@ } }, "@jest/environment": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.1.1.tgz", - "integrity": "sha512-+y882/ZdxhyqF5RzxIrNIANjHj991WH7jifdcplzMDosDUOyCACFYUyVTBGbSTocbU+s1cesroRzkwi8hZ9SHg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.0.tgz", + "integrity": "sha512-iPWmQI0wRIYSZX3wKu4FXHK4eIqkfq6n1DCDJS+v3uby7SOXrHvX4eiTBuEdSvtDRMTIH2kjrSkjHf/F9JIYyQ==", "dev": true, "requires": { - "@jest/fake-timers": "^27.1.1", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1" } }, "@jest/fake-timers": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.1.1.tgz", - "integrity": "sha512-u8TJ5VlsVYTsGFatoyIae2l25pku4Bu15QCPTx2Gs5z+R//Ee3tHN85462Vc9yGVcdDvgADbqNkhOLxbEwPjMQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.0.tgz", + "integrity": "sha512-gSu3YHvQOoVaTWYGgHFB7IYFtcF2HBzX4l7s47VcjvkUgL4/FBnE20x7TNLa3W6ABERtGd5gStSwsA8bcn+c4w==", "dev": true, "requires": { "@jest/types": "^27.1.1", "@sinonjs/fake-timers": "^7.0.2", "@types/node": "*", - "jest-message-util": "^27.1.1", + "jest-message-util": "^27.2.0", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1" + "jest-util": "^27.2.0" } }, "@jest/globals": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.1.1.tgz", - "integrity": "sha512-Q3JcTPmY+DAEHnr4MpnBV3mwy50EGrTC6oSDTNnW7FNGGacTJAfpWNk02D7xv422T1OzK2A2BKx+26xJOvHkyw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.0.tgz", + "integrity": "sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg==", "dev": true, "requires": { - "@jest/environment": "^27.1.1", + "@jest/environment": "^27.2.0", "@jest/types": "^27.1.1", - "expect": "^27.1.1" + "expect": "^27.2.0" } }, "@jest/reporters": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.1.1.tgz", - "integrity": "sha512-cEERs62n1P4Pqox9HWyNOEkP57G95aK2mBjB6D8Ruz1Yc98fKH53b58rlVEnsY5nLmkLNZk65fxNi9C0Yds/8w==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.0.tgz", + "integrity": "sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -39862,10 +39863,10 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -39914,9 +39915,9 @@ "dev": true }, "jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "requires": { "@types/node": "*", @@ -39972,33 +39973,33 @@ } }, "@jest/test-result": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.1.1.tgz", - "integrity": "sha512-8vy75A0Jtfz9DqXFUkjC5Co/wRla+D7qRFdShUY8SbPqBS3GBx3tpba7sGKFos8mQrdbe39n+c1zgVKtarfy6A==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.0.tgz", + "integrity": "sha512-JPPqn8h0RGr4HyeY1Km+FivDIjTFzDROU46iAvzVjD42ooGwYoqYO/MQTilhfajdz6jpVnnphFrKZI5OYrBONA==", "dev": true, "requires": { - "@jest/console": "^27.1.1", + "@jest/console": "^27.2.0", "@jest/types": "^27.1.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.1.1.tgz", - "integrity": "sha512-l8zD3EdeixvwmLNlJoMX3hhj8iIze95okj4sqmBzOq/zW8gZLElUveH4bpKEMuR+Nweazjlwc7L6g4C26M/y6Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz", + "integrity": "sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA==", "dev": true, "requires": { - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", - "jest-runtime": "^27.1.1" + "jest-haste-map": "^27.2.0", + "jest-runtime": "^27.2.0" } }, "@jest/transform": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.1.1.tgz", - "integrity": "sha512-qM19Eu75U6Jc5zosXXVnq900Nl9JDpoGaZ4Mg6wZs7oqbu3heYSMOZS19DlwjlhWdfNRjF4UeAgkrCJCK3fEXg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.0.tgz", + "integrity": "sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg==", "dev": true, "requires": { "@babel/core": "^7.1.0", @@ -40008,9 +40009,9 @@ "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", + "jest-haste-map": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -45268,16 +45269,16 @@ "requires": {} }, "babel-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.1.1.tgz", - "integrity": "sha512-JA+dzJl4n2RBvWQEnph6HJaTHrsIPiXGQYatt/D8nR4UpX9UG4GaDzykVVPQBbrdTebZREkRb6SOxyIXJRab6Q==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.0.tgz", + "integrity": "sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA==", "dev": true, "requires": { - "@jest/transform": "^27.1.1", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.6", + "babel-preset-jest": "^27.2.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" @@ -45406,9 +45407,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", - "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -45526,12 +45527,12 @@ } }, "babel-preset-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", - "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.0.6", + "babel-plugin-jest-hoist": "^27.2.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -49391,16 +49392,16 @@ } }, "expect": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.1.1.tgz", - "integrity": "sha512-JQAzp0CJoFFHF1RnOtrMUNMdsfx/Tl0+FhRzVl8q0fa23N+JyWdPXwb3T5rkHCvyo9uttnK7lVdKCBl1b/9EDw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.0.tgz", + "integrity": "sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ==", "dev": true, "requires": { "@jest/types": "^27.1.1", "ansi-styles": "^5.0.0", "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-regex-util": "^27.0.6" }, "dependencies": { @@ -52254,14 +52255,14 @@ "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==" }, "jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.1.1.tgz", - "integrity": "sha512-LFTEZOhoZNR/2DQM3OCaK5xC6c55c1OWhYh0njRsoHX0qd6x4nkcgenkSH0JKjsAGMTmmJAoL7/oqYHMfwhruA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.0.tgz", + "integrity": "sha512-oUqVXyvh5YwEWl263KWdPUAqEzBFzGHdFLQ05hUnITr1tH+9SscEI9A/GH9eBClA+Nw1ct+KNuuOV6wlnmBPcg==", "dev": true, "requires": { - "@jest/core": "^27.1.1", + "@jest/core": "^27.2.0", "import-local": "^3.0.2", - "jest-cli": "^27.1.1" + "jest-cli": "^27.2.0" } }, "jest-changed-files": { @@ -52276,27 +52277,27 @@ } }, "jest-circus": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.1.1.tgz", - "integrity": "sha512-Xed1ApiMFu/yzqGMBToHr8sp2gkX/ARZf4nXoGrHJrXrTUdVIWiVYheayfcOaPdQvQEE/uyBLgW7I7YBLIrAXQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.0.tgz", + "integrity": "sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA==", "dev": true, "requires": { - "@jest/environment": "^27.1.1", - "@jest/test-result": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "is-generator-fn": "^2.0.0", - "jest-each": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1", + "jest-each": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -52354,21 +52355,21 @@ } }, "jest-cli": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.1.1.tgz", - "integrity": "sha512-LCjfEYp9D3bcOeVUUpEol9Y1ijZYMWVqflSmtw/wX+6Fb7zP4IlO14/6s9v1pxsoM4Pn46+M2zABgKuQjyDpTw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.0.tgz", + "integrity": "sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA==", "dev": true, "requires": { - "@jest/core": "^27.1.1", - "@jest/test-result": "^27.1.1", + "@jest/core": "^27.2.0", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-config": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "prompts": "^2.0.1", "yargs": "^16.0.3" }, @@ -52422,32 +52423,32 @@ "dev": true }, "jest-config": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.1.1.tgz", - "integrity": "sha512-2iSd5zoJV4MsWPcLCGwUVUY/j6pZXm4Qd3rnbCtrd9EHNTg458iHw8PZztPQXfxKBKJxLfBk7tbZqYF8MGtxJA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.0.tgz", + "integrity": "sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.1.1", + "@jest/test-sequencer": "^27.2.0", "@jest/types": "^27.1.1", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", "is-ci": "^3.0.0", - "jest-circus": "^27.1.1", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", + "jest-circus": "^27.2.0", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.1.1", + "jest-jasmine2": "^27.2.0", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-runner": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-runner": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" } }, "supports-color": { @@ -52499,15 +52500,15 @@ } }, "jest-diff": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.1.1.tgz", - "integrity": "sha512-m/6n5158rqEriTazqHtBpOa2B/gGgXJijX6nsEgZfbJ/3pxQcdpVXBe+FP39b1dxWHyLVVmuVXddmAwtqFO4Lg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.0.tgz", + "integrity": "sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw==", "dev": true, "requires": { "chalk": "^4.0.0", "diff-sequences": "^27.0.6", "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "dependencies": { "ansi-styles": { @@ -52571,16 +52572,16 @@ } }, "jest-each": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.1.1.tgz", - "integrity": "sha512-r6hOsTLavUBb1xN0uDa89jdDeBmJ+K49fWpbyxeGRA2pLY46PlC4z551/cWNQzrj+IUa5/gSRsCIV/01HdNPug==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.0.tgz", + "integrity": "sha512-biDmmUQjg+HZOB7MfY2RHSFL3j418nMoC3TK3pGAj880fQQSxvQe1y2Wy23JJJNUlk6YXiGU0yWy86Le1HBPmA==", "dev": true, "requires": { "@jest/types": "^27.1.1", "chalk": "^4.0.0", "jest-get-type": "^27.0.6", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1" + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0" }, "dependencies": { "ansi-styles": { @@ -52635,32 +52636,32 @@ } }, "jest-environment-jsdom": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.1.1.tgz", - "integrity": "sha512-6vOnoZ6IaExuw7FvnuJhA1qFYv1DDSnN0sQowzolNwxQp7bG1YhLxj2YU1sVXAYA3IR3MbH2mbnJUsLUWfyfzw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.0.tgz", + "integrity": "sha512-wNQJi6Rd/AkUWqTc4gWhuTIFPo7tlMK0RPZXeM6AqRHZA3D3vwvTa9ktAktyVyWYmUoXdYstOfyYMG3w4jt7eA==", "dev": true, "requires": { - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.1.1.tgz", - "integrity": "sha512-OEGeZh0PwzngNIYWYgWrvTcLygopV8OJbC9HNb0j70VBKgEIsdZkYhwcFnaURX83OHACMqf1pa9Tv5Pw5jemrg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.0.tgz", + "integrity": "sha512-WbW+vdM4u88iy6Q3ftUEQOSgMPtSgjm3qixYYK2AKEuqmFO2zmACTw1vFUB0qI/QN88X6hA6ZkVKIdIWWzz+yg==", "dev": true, "requires": { - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "jest-mock": "^27.1.1", - "jest-util": "^27.1.1" + "jest-util": "^27.2.0" } }, "jest-get-type": { @@ -52670,9 +52671,9 @@ "dev": true }, "jest-haste-map": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.1.1.tgz", - "integrity": "sha512-NGLYVAdh5C8Ezg5QBFzrNeYsfxptDBPlhvZNaicLiZX77F/rS27a9M6u9ripWAaaD54xnWdZNZpEkdjD5Eo5aQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.0.tgz", + "integrity": "sha512-laFet7QkNlWjwZtMGHCucLvF8o9PAh2cgePRck1+uadSM4E4XH9J4gnx4do+a6do8ZV5XHNEAXEkIoNg5XUH2Q==", "dev": true, "requires": { "@jest/types": "^27.1.1", @@ -52684,8 +52685,8 @@ "graceful-fs": "^4.2.4", "jest-regex-util": "^27.0.6", "jest-serializer": "^27.0.6", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "micromatch": "^4.0.4", "walker": "^1.0.7" }, @@ -52697,9 +52698,9 @@ "dev": true }, "jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "requires": { "@types/node": "*", @@ -52719,28 +52720,28 @@ } }, "jest-jasmine2": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.1.1.tgz", - "integrity": "sha512-0LAzUmcmvQwjIdJt0cXUVX4G5qjVXE8ELt6nbMNDzv2yAs2hYCCUtQq+Eje70GwAysWCGcS64QeYj5VPHYVxPg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz", + "integrity": "sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.1.1", + "@jest/environment": "^27.2.0", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "is-generator-fn": "^2.0.0", - "jest-each": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "pretty-format": "^27.1.1", + "jest-each": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "pretty-format": "^27.2.0", "throat": "^6.0.1" }, "dependencies": { @@ -52796,25 +52797,25 @@ } }, "jest-leak-detector": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.1.1.tgz", - "integrity": "sha512-gwSgzmqShoeEsEVpgObymQPrM9P6557jt1EsFW5aCeJ46Cme0EdjYU7xr6llQZ5GpWDl56eOstUaPXiZOfiTKw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.0.tgz", + "integrity": "sha512-e91BIEmbZw5+MHkB4Hnrq7S86coTxUMCkz4n7DLmQYvl9pEKmRx9H/JFH87bBqbIU5B2Ju1soKxRWX6/eGFGpA==", "dev": true, "requires": { "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" } }, "jest-matcher-utils": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.1.1.tgz", - "integrity": "sha512-Q1a10w9Y4sh0wegkdP6reQOa/Dtz7nAvDqBgrat1ItZAUvk4jzXAqyhXPu/ZuEtDaXaNKpdRPRQA8bvkOh2Eaw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz", + "integrity": "sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.1.1", + "jest-diff": "^27.2.0", "jest-get-type": "^27.0.6", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "dependencies": { "ansi-styles": { @@ -52869,9 +52870,9 @@ } }, "jest-message-util": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.1.1.tgz", - "integrity": "sha512-b697BOJV93+AVGvzLRtVZ0cTVRbd59OaWnbB2D75GRaIMc4I+Z9W0wHxbfjW01JWO+TqqW4yevT0aN7Fd0XWng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.0.tgz", + "integrity": "sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", @@ -52880,7 +52881,7 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.1.1", + "pretty-format": "^27.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -52960,19 +52961,19 @@ "dev": true }, "jest-resolve": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.1.1.tgz", - "integrity": "sha512-M41YFmWhvDVstwe7XuV21zynOiBLJB5Sk0GrIsYYgTkjfEWNLVXDjAyq1W7PHseaYNOxIc0nOGq/r5iwcZNC1A==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.0.tgz", + "integrity": "sha512-v09p9Ib/VtpHM6Cz+i9lEAv1Z/M5NVxsyghRHRMEUOqwPQs3zwTdwp1xS3O/k5LocjKiGS0OTaJoBSpjbM2Jlw==", "dev": true, "requires": { "@jest/types": "^27.1.1", "chalk": "^4.0.0", "escalade": "^3.1.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", + "jest-haste-map": "^27.2.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "resolve": "^1.20.0", "slash": "^3.0.0" }, @@ -53029,26 +53030,26 @@ } }, "jest-resolve-dependencies": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.1.1.tgz", - "integrity": "sha512-sYZR+uBjFDCo4VhYeazZf/T+ryYItvdLKu9vHatqkUqHGjDMrdEPOykiqC2iEpaCFTS+3iL/21CYiJuKdRbniw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz", + "integrity": "sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg==", "dev": true, "requires": { "@jest/types": "^27.1.1", "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.1.1" + "jest-snapshot": "^27.2.0" } }, "jest-runner": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.1.1.tgz", - "integrity": "sha512-lP3MBNQhg75/sQtVkC8dsAQZumvy3lHK/YIwYPfEyqGIX1qEcnYIRxP89q0ZgC5ngvi1vN2P5UFHszQxguWdng==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.0.tgz", + "integrity": "sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww==", "dev": true, "requires": { - "@jest/console": "^27.1.1", - "@jest/environment": "^27.1.1", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/environment": "^27.2.0", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "chalk": "^4.0.0", @@ -53056,15 +53057,15 @@ "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.1.1", - "jest-environment-node": "^27.1.1", - "jest-haste-map": "^27.1.1", - "jest-leak-detector": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-runtime": "^27.1.1", - "jest-util": "^27.1.1", - "jest-worker": "^27.1.1", + "jest-environment-jsdom": "^27.2.0", + "jest-environment-node": "^27.2.0", + "jest-haste-map": "^27.2.0", + "jest-leak-detector": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-runtime": "^27.2.0", + "jest-util": "^27.2.0", + "jest-worker": "^27.2.0", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -53110,9 +53111,9 @@ "dev": true }, "jest-worker": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.1.1.tgz", - "integrity": "sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", + "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", "dev": true, "requires": { "@types/node": "*", @@ -53143,18 +53144,18 @@ } }, "jest-runtime": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.1.1.tgz", - "integrity": "sha512-FEwy+tSzmsvuKaQpyYsUyk31KG5vMmA2r2BSTHgv0yNfcooQdm2Ke91LM9Ud8D3xz8CLDHJWAI24haMFTwrsPg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.0.tgz", + "integrity": "sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ==", "dev": true, "requires": { - "@jest/console": "^27.1.1", - "@jest/environment": "^27.1.1", - "@jest/fake-timers": "^27.1.1", - "@jest/globals": "^27.1.1", + "@jest/console": "^27.2.0", + "@jest/environment": "^27.2.0", + "@jest/fake-timers": "^27.2.0", + "@jest/globals": "^27.2.0", "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.1.1", - "@jest/transform": "^27.1.1", + "@jest/test-result": "^27.2.0", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", @@ -53164,14 +53165,14 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.1.1", - "jest-message-util": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-message-util": "^27.2.0", "jest-mock": "^27.1.1", "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.1.1", - "jest-snapshot": "^27.1.1", - "jest-util": "^27.1.1", - "jest-validate": "^27.1.1", + "jest-resolve": "^27.2.0", + "jest-snapshot": "^27.2.0", + "jest-util": "^27.2.0", + "jest-validate": "^27.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^16.0.3" @@ -53263,9 +53264,9 @@ } }, "jest-snapshot": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.1.1.tgz", - "integrity": "sha512-Wi3QGiuRFo3lU+EbQmZnBOks0CJyAMPHvYoG7iJk00Do10jeOyuOEO0Jfoaoun8+8TDv+Nzl7Aswir/IK9+1jg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.0.tgz", + "integrity": "sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ==", "dev": true, "requires": { "@babel/core": "^7.7.2", @@ -53274,23 +53275,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.1.1", + "@jest/transform": "^27.2.0", "@jest/types": "^27.1.1", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.1.1", + "expect": "^27.2.0", "graceful-fs": "^4.2.4", - "jest-diff": "^27.1.1", + "jest-diff": "^27.2.0", "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.1.1", - "jest-matcher-utils": "^27.1.1", - "jest-message-util": "^27.1.1", - "jest-resolve": "^27.1.1", - "jest-util": "^27.1.1", + "jest-haste-map": "^27.2.0", + "jest-matcher-utils": "^27.2.0", + "jest-message-util": "^27.2.0", + "jest-resolve": "^27.2.0", + "jest-util": "^27.2.0", "natural-compare": "^1.4.0", - "pretty-format": "^27.1.1", + "pretty-format": "^27.2.0", "semver": "^7.3.2" }, "dependencies": { @@ -53370,9 +53371,9 @@ } }, "jest-util": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.1.1.tgz", - "integrity": "sha512-zf9nEbrASWn2mC/L91nNb0K+GkhFvi4MP6XJG2HqnHzHvLYcs7ou/In68xYU1i1dSkJlrWcYfWXQE8nVR+nbOA==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.0.tgz", + "integrity": "sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A==", "dev": true, "requires": { "@jest/types": "^27.1.1", @@ -53435,9 +53436,9 @@ } }, "jest-validate": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.1.1.tgz", - "integrity": "sha512-N5Er5FKav/8m2dJwn7BGnZwnoD1BSc8jx5T+diG2OvyeugvZDhPeAt5DrNaGkkaKCrSUvuE7A5E4uHyT7Vj0Mw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.0.tgz", + "integrity": "sha512-uIEZGkFKk3+4liA81Xu0maG5aGDyPLdp+4ed244c+Ql0k3aLWQYcMbaMLXOIFcb83LPHzYzqQ8hwNnIxTqfAGQ==", "dev": true, "requires": { "@jest/types": "^27.1.1", @@ -53445,7 +53446,7 @@ "chalk": "^4.0.0", "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^27.1.1" + "pretty-format": "^27.2.0" }, "dependencies": { "ansi-styles": { @@ -53506,17 +53507,17 @@ } }, "jest-watcher": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.1.1.tgz", - "integrity": "sha512-XQzyHbxziDe+lZM6Dzs40fEt4q9akOGwitJnxQasJ9WG0bv3JGiRlsBgjw13znGapeMtFaEsyhL0Cl04IbaoWQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.0.tgz", + "integrity": "sha512-SjRWhnr+qO8aBsrcnYIyF+qRxNZk6MZH8TIDgvi+VlsyrvOyqg0d+Rm/v9KHiTtC9mGGeFi9BFqgavyWib6xLg==", "dev": true, "requires": { - "@jest/test-result": "^27.1.1", + "@jest/test-result": "^27.2.0", "@jest/types": "^27.1.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.1.1", + "jest-util": "^27.2.0", "string-length": "^4.0.1" }, "dependencies": { @@ -57962,9 +57963,9 @@ } }, "pretty-format": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.1.1.tgz", - "integrity": "sha512-zdBi/xlstKJL42UH7goQti5Hip/B415w1Mfj+WWWYMBylAYtKESnXGUtVVcMVid9ReVjypCotUV6CEevYPHv2g==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.0.tgz", + "integrity": "sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA==", "dev": true, "requires": { "@jest/types": "^27.1.1", @@ -59507,9 +59508,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.39.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.39.2.tgz", - "integrity": "sha512-4/6Vn2RPc+qNwSclUSKvssh7dqK1Ih3FfHBW16I/GfH47b3scbYeOw65UIrYG7PkweFiKbpJjgkf5CV8EMmvzw==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.40.1.tgz", + "integrity": "sha512-M6WskYLzTfdZdb09W9SftIScjudL8jNkhdh9z96U+olQaKIcw2Knb6QLL9bUhnuSm4VD+1yJVaO2/ENDPMTtAQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0" @@ -60154,9 +60155,9 @@ } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -60313,12 +60314,13 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", + "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", "dev": true, "requires": { - "escape-string-regexp": "^2.0.0" + "escape-string-regexp": "^2.0.0", + "source-map-support": "^0.5.20" }, "dependencies": { "escape-string-regexp": { diff --git a/package.json b/package.json index 5a438568e..2cc63adca 100644 --- a/package.json +++ b/package.json @@ -86,21 +86,21 @@ "@vue/runtime-dom": "^3.2.11", "@vue/test-utils": "^1.2.2", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^27.1.1", + "babel-jest": "^27.2.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-nuxt": ">=2.0.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-vue": "^7.17.0", "husky": "^7.0.2", - "jest": "^27.1.1", + "jest": "^27.2.0", "jest-serializer-vue": "^2.0.2", "lint-staged": "^11.1.2", "nuxt-windicss": "^1.2.4", "prettier": "^2.4.0", "pretty-quick": "^3.1.1", "raw-loader": "^4.0.2", - "sass": "^1.39.2", + "sass": "^1.40.1", "sass-loader": "^10.2.0", "stylelint": "^13.12.0", "stylelint-config-prettier": "^8.0.2", From 4e8a4e8914c099b92606c7d52037899cba661422 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Wed, 15 Sep 2021 17:30:04 +0530 Subject: [PATCH 73/73] refactor: typescript support --- components/realtime/Log.vue | 32 ++++---------- components/realtime/Mqtt.vue | 2 +- components/realtime/Socketio.vue | 2 +- components/realtime/Sse.vue | 2 +- components/realtime/Websocket.vue | 2 +- helpers/lenses/{htmlLens.js => htmlLens.ts} | 6 ++- helpers/lenses/{imageLens.js => imageLens.ts} | 6 ++- helpers/lenses/{jsonLens.js => jsonLens.ts} | 5 ++- helpers/lenses/lenses.js | 28 ------------- helpers/lenses/lenses.ts | 42 +++++++++++++++++++ helpers/lenses/rawLens.js | 8 ---- helpers/lenses/rawLens.ts | 11 +++++ helpers/lenses/{xmlLens.js => xmlLens.ts} | 7 +++- helpers/utils/StreamUtils.ts | 6 +-- helpers/utils/__tests__/debounce.spec.js | 38 ----------------- helpers/utils/__tests__/uri.spec.js | 21 ---------- helpers/utils/{b64.js => b64.ts} | 2 +- helpers/utils/debounce.js | 15 ------- helpers/utils/string.js | 12 ------ helpers/utils/string.ts | 12 ++++++ helpers/utils/uri.js | 15 ------- 21 files changed, 98 insertions(+), 176 deletions(-) rename helpers/lenses/{htmlLens.js => htmlLens.ts} (62%) rename helpers/lenses/{imageLens.js => imageLens.ts} (67%) rename helpers/lenses/{jsonLens.js => jsonLens.ts} (62%) delete mode 100644 helpers/lenses/lenses.js create mode 100644 helpers/lenses/lenses.ts delete mode 100644 helpers/lenses/rawLens.js create mode 100644 helpers/lenses/rawLens.ts rename helpers/lenses/{xmlLens.js => xmlLens.ts} (50%) delete mode 100644 helpers/utils/__tests__/debounce.spec.js delete mode 100644 helpers/utils/__tests__/uri.spec.js rename helpers/utils/{b64.js => b64.ts} (91%) delete mode 100644 helpers/utils/debounce.js delete mode 100644 helpers/utils/string.js create mode 100644 helpers/utils/string.ts delete mode 100644 helpers/utils/uri.js diff --git a/components/realtime/Log.vue b/components/realtime/Log.vue index a09fdf7ca..ef1bf74d0 100644 --- a/components/realtime/Log.vue +++ b/components/realtime/Log.vue @@ -17,14 +17,13 @@ {{ title }} -
+
{{ entry.ts }}{{ getSourcePrefix(entry.source) - }}{{ entry.payload }}{{ entry.ts }}{{ source(entry.source) }}{{ entry.payload }} {{ $t("response.waiting_for_connection") }} @@ -32,27 +31,14 @@
- diff --git a/components/realtime/Mqtt.vue b/components/realtime/Mqtt.vue index 9f1bb3b7b..5cc5f0b7f 100644 --- a/components/realtime/Mqtt.vue +++ b/components/realtime/Mqtt.vue @@ -145,7 +145,7 @@ import { defineComponent } from "@nuxtjs/composition-api" import { Splitpanes, Pane } from "splitpanes" import "splitpanes/dist/splitpanes.css" import Paho from "paho-mqtt" -import debounce from "~/helpers/utils/debounce" +import debounce from "lodash/debounce" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" import { useSetting } from "~/newstore/settings" import useWindowSize from "~/helpers/utils/useWindowSize" diff --git a/components/realtime/Socketio.vue b/components/realtime/Socketio.vue index e9e461aee..7d933e3bf 100644 --- a/components/realtime/Socketio.vue +++ b/components/realtime/Socketio.vue @@ -165,7 +165,7 @@ import { Splitpanes, Pane } from "splitpanes" import "splitpanes/dist/splitpanes.css" import { io as Client } from "socket.io-client" import wildcard from "socketio-wildcard" -import debounce from "~/helpers/utils/debounce" +import debounce from "lodash/debounce" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" import { useSetting } from "~/newstore/settings" import useWindowSize from "~/helpers/utils/useWindowSize" diff --git a/components/realtime/Sse.vue b/components/realtime/Sse.vue index 3d230dc38..ca78d4b1a 100644 --- a/components/realtime/Sse.vue +++ b/components/realtime/Sse.vue @@ -89,8 +89,8 @@ import { defineComponent } from "@nuxtjs/composition-api" import { Splitpanes, Pane } from "splitpanes" import "splitpanes/dist/splitpanes.css" +import debounce from "lodash/debounce" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" -import debounce from "~/helpers/utils/debounce" export default defineComponent({ components: { Splitpanes, Pane }, diff --git a/components/realtime/Websocket.vue b/components/realtime/Websocket.vue index 75220c973..2bacf97e5 100644 --- a/components/realtime/Websocket.vue +++ b/components/realtime/Websocket.vue @@ -205,8 +205,8 @@ import { defineComponent } from "@nuxtjs/composition-api" import { Splitpanes, Pane } from "splitpanes" import "splitpanes/dist/splitpanes.css" +import debounce from "lodash/debounce" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" -import debounce from "~/helpers/utils/debounce" import useWindowSize from "~/helpers/utils/useWindowSize" import { useSetting } from "~/newstore/settings" diff --git a/helpers/lenses/htmlLens.js b/helpers/lenses/htmlLens.ts similarity index 62% rename from helpers/lenses/htmlLens.js rename to helpers/lenses/htmlLens.ts index 7a18570eb..8c4f9da65 100644 --- a/helpers/lenses/htmlLens.js +++ b/helpers/lenses/htmlLens.ts @@ -1,10 +1,12 @@ -const htmlLens = { +import { Lens } from "./lenses" + +const htmlLens: Lens = { lensName: "response.html", isSupportedContentType: (contentType) => /\btext\/html|application\/xhtml\+xml\b/i.test(contentType), renderer: "htmlres", rendererImport: () => - import("~/components/lenses/renderers/HTMLLensRenderer"), + import("~/components/lenses/renderers/HTMLLensRenderer.vue"), } export default htmlLens diff --git a/helpers/lenses/imageLens.js b/helpers/lenses/imageLens.ts similarity index 67% rename from helpers/lenses/imageLens.js rename to helpers/lenses/imageLens.ts index 2c49b38df..d08d204ad 100644 --- a/helpers/lenses/imageLens.js +++ b/helpers/lenses/imageLens.ts @@ -1,4 +1,6 @@ -const imageLens = { +import { Lens } from "./lenses" + +const imageLens: Lens = { lensName: "response.image", isSupportedContentType: (contentType) => /\bimage\/(?:gif|jpeg|png|bmp|svg\+xml|x-icon|vnd\.microsoft\.icon)\b/i.test( @@ -6,7 +8,7 @@ const imageLens = { ), renderer: "imageres", rendererImport: () => - import("~/components/lenses/renderers/ImageLensRenderer"), + import("~/components/lenses/renderers/ImageLensRenderer.vue"), } export default imageLens diff --git a/helpers/lenses/jsonLens.js b/helpers/lenses/jsonLens.ts similarity index 62% rename from helpers/lenses/jsonLens.js rename to helpers/lenses/jsonLens.ts index 1d9135a24..28ad97348 100644 --- a/helpers/lenses/jsonLens.js +++ b/helpers/lenses/jsonLens.ts @@ -1,11 +1,12 @@ import { isJSONContentType } from "../utils/contenttypes" +import { Lens } from "./lenses" -const jsonLens = { +const jsonLens: Lens = { lensName: "response.json", isSupportedContentType: isJSONContentType, renderer: "json", rendererImport: () => - import("~/components/lenses/renderers/JSONLensRenderer"), + import("~/components/lenses/renderers/JSONLensRenderer.vue"), } export default jsonLens diff --git a/helpers/lenses/lenses.js b/helpers/lenses/lenses.js deleted file mode 100644 index 674797fce..000000000 --- a/helpers/lenses/lenses.js +++ /dev/null @@ -1,28 +0,0 @@ -import jsonLens from "./jsonLens" -import rawLens from "./rawLens" -import imageLens from "./imageLens" -import htmlLens from "./htmlLens" -import xmlLens from "./xmlLens" - -export const lenses = [jsonLens, imageLens, htmlLens, xmlLens, rawLens] - -export function getSuitableLenses(response) { - const contentType = response.headers.find((h) => h.key === "content-type") - - if (!contentType) return [rawLens] - - const result = [] - for (const lens of lenses) { - if (lens.isSupportedContentType(contentType.value)) result.push(lens) - } - - return result -} - -export function getLensRenderers() { - const response = {} - for (const lens of lenses) { - response[lens.renderer] = lens.rendererImport - } - return response -} diff --git a/helpers/lenses/lenses.ts b/helpers/lenses/lenses.ts new file mode 100644 index 000000000..a6fe10728 --- /dev/null +++ b/helpers/lenses/lenses.ts @@ -0,0 +1,42 @@ +import { HoppRESTResponse } from "../types/HoppRESTResponse" +import jsonLens from "./jsonLens" +import rawLens from "./rawLens" +import imageLens from "./imageLens" +import htmlLens from "./htmlLens" +import xmlLens from "./xmlLens" + +export type Lens = { + lensName: string + isSupportedContentType: (contentType: string) => boolean + renderer: string + rendererImport: () => Promise +} + +export const lenses: Lens[] = [jsonLens, imageLens, htmlLens, xmlLens, rawLens] + +export function getSuitableLenses(response: HoppRESTResponse): Lens[] { + // return empty array if response is loading or error + if (response.type === "loading" || response.type === "network_fail") return [] + + const contentType = response.headers.find((h) => h.key === "content-type") + + if (!contentType) return [rawLens] + + const result = [] + for (const lens of lenses) { + if (lens.isSupportedContentType(contentType.value)) result.push(lens) + } + return result +} + +type LensRenderers = { + [key: string]: Lens["rendererImport"] +} + +export function getLensRenderers(): LensRenderers { + const response: LensRenderers = {} + for (const lens of lenses) { + response[lens.renderer] = lens.rendererImport + } + return response +} diff --git a/helpers/lenses/rawLens.js b/helpers/lenses/rawLens.js deleted file mode 100644 index f8a18e193..000000000 --- a/helpers/lenses/rawLens.js +++ /dev/null @@ -1,8 +0,0 @@ -const rawLens = { - lensName: "response.raw", - isSupportedContentType: () => true, - renderer: "raw", - rendererImport: () => import("~/components/lenses/renderers/RawLensRenderer"), -} - -export default rawLens diff --git a/helpers/lenses/rawLens.ts b/helpers/lenses/rawLens.ts new file mode 100644 index 000000000..ec3a7c64f --- /dev/null +++ b/helpers/lenses/rawLens.ts @@ -0,0 +1,11 @@ +import { Lens } from "./lenses" + +const rawLens: Lens = { + lensName: "response.raw", + isSupportedContentType: () => true, + renderer: "raw", + rendererImport: () => + import("~/components/lenses/renderers/RawLensRenderer.vue"), +} + +export default rawLens diff --git a/helpers/lenses/xmlLens.js b/helpers/lenses/xmlLens.ts similarity index 50% rename from helpers/lenses/xmlLens.js rename to helpers/lenses/xmlLens.ts index d393be5f2..2f126bbb7 100644 --- a/helpers/lenses/xmlLens.js +++ b/helpers/lenses/xmlLens.ts @@ -1,8 +1,11 @@ -const xmlLens = { +import { Lens } from "./lenses" + +const xmlLens: Lens = { lensName: "response.xml", isSupportedContentType: (contentType) => /\bxml\b/i.test(contentType), renderer: "xmlres", - rendererImport: () => import("~/components/lenses/renderers/XMLLensRenderer"), + rendererImport: () => + import("~/components/lenses/renderers/XMLLensRenderer.vue"), } export default xmlLens diff --git a/helpers/utils/StreamUtils.ts b/helpers/utils/StreamUtils.ts index fad17f58e..342e9b4b3 100644 --- a/helpers/utils/StreamUtils.ts +++ b/helpers/utils/StreamUtils.ts @@ -8,9 +8,9 @@ import { map } from "rxjs/operators" * * @returns The constructed object observable */ -export function constructFromStreams( - streamObj: { [key in keyof T]: Observable } -): Observable { +export function constructFromStreams(streamObj: { + [key in keyof T]: Observable +}): Observable { return combineLatest(Object.values>(streamObj)).pipe( map((streams) => { const keys = Object.keys(streamObj) as (keyof T)[] diff --git a/helpers/utils/__tests__/debounce.spec.js b/helpers/utils/__tests__/debounce.spec.js deleted file mode 100644 index 198c103d9..000000000 --- a/helpers/utils/__tests__/debounce.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import debounce from "../debounce" - -describe("debounce", () => { - test("doesn't call function right after calling", () => { - const fn = jest.fn() - - const debFunc = debounce(fn, 100) - debFunc() - - expect(fn).not.toHaveBeenCalled() - }) - - test("calls the function after the given timeout", () => { - const fn = jest.fn() - - jest.useFakeTimers() - - const debFunc = debounce(fn, 100) - debFunc() - - jest.runAllTimers() - - expect(fn).toHaveBeenCalled() - // expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 100) - }) - - test("calls the function only one time within the timeframe", () => { - const fn = jest.fn() - - const debFunc = debounce(fn, 1000) - - for (let i = 0; i < 100; i++) debFunc() - - jest.runAllTimers() - - expect(fn).toHaveBeenCalledTimes(1) - }) -}) diff --git a/helpers/utils/__tests__/uri.spec.js b/helpers/utils/__tests__/uri.spec.js deleted file mode 100644 index 1b1dcf5a0..000000000 --- a/helpers/utils/__tests__/uri.spec.js +++ /dev/null @@ -1,21 +0,0 @@ -import { parseUrlAndPath } from "../uri" - -describe("parseUrlAndPath", () => { - test("has url and path fields", () => { - const result = parseUrlAndPath("https://hoppscotch.io/") - - expect(result).toHaveProperty("url") - expect(result).toHaveProperty("path") - }) - - test("parses out URL correctly", () => { - const result = parseUrlAndPath("https://hoppscotch.io/test/page") - - expect(result.url).toBe("https://hoppscotch.io") - }) - test("parses out Path correctly", () => { - const result = parseUrlAndPath("https://hoppscotch.io/test/page") - - expect(result.path).toBe("/test/page") - }) -}) diff --git a/helpers/utils/b64.js b/helpers/utils/b64.ts similarity index 91% rename from helpers/utils/b64.js rename to helpers/utils/b64.ts index 942b003c4..3b364c0e9 100644 --- a/helpers/utils/b64.js +++ b/helpers/utils/b64.ts @@ -1,4 +1,4 @@ -export const decodeB64StringToArrayBuffer = (input) => { +export function decodeB64StringToArrayBuffer(input: string): ArrayBuffer { const bytes = Math.floor((input.length / 4) * 3) const ab = new ArrayBuffer(bytes) const uarray = new Uint8Array(ab) diff --git a/helpers/utils/debounce.js b/helpers/utils/debounce.js deleted file mode 100644 index 0db17993b..000000000 --- a/helpers/utils/debounce.js +++ /dev/null @@ -1,15 +0,0 @@ -// Debounce is a higher order function which makes its enclosed function be executed -// only if the function wasn't called again till 'delay' time has passed, this helps reduce impact of heavy working -// functions which might be called frequently -// NOTE : Don't use lambda functions as this doesn't get bound properly in them, use the 'function (args) {}' format -const debounce = (func, delay) => { - let inDebounce - return function () { - const context = this - const args = arguments - clearTimeout(inDebounce) - inDebounce = setTimeout(() => func.apply(context, args), delay) - } -} - -export default debounce diff --git a/helpers/utils/string.js b/helpers/utils/string.js deleted file mode 100644 index 6967e1c35..000000000 --- a/helpers/utils/string.js +++ /dev/null @@ -1,12 +0,0 @@ -export function getSourcePrefix(source) { - const sourceEmojis = { - // Source used for info messages. - info: "\tℹ️ [INFO]:\t", - // Source used for client to server messages. - client: "\t⬅️ [SENT]:\t", - // Source used for server to client messages. - server: "\t➡️ [RECEIVED]:\t", - } - if (Object.keys(sourceEmojis).includes(source)) return sourceEmojis[source] - return "" -} diff --git a/helpers/utils/string.ts b/helpers/utils/string.ts new file mode 100644 index 000000000..f23107591 --- /dev/null +++ b/helpers/utils/string.ts @@ -0,0 +1,12 @@ +const sourceEmojis = { + // Source used for info messages. + info: "\tℹ️ [INFO]:\t", + // Source used for client to server messages. + client: "\t⬅️ [SENT]:\t", + // Source used for server to client messages. + server: "\t➡️ [RECEIVED]:\t", +} + +export function getSourcePrefix(source: keyof typeof sourceEmojis) { + return sourceEmojis[source] +} diff --git a/helpers/utils/uri.js b/helpers/utils/uri.js deleted file mode 100644 index 69b57ee04..000000000 --- a/helpers/utils/uri.js +++ /dev/null @@ -1,15 +0,0 @@ -export function parseUrlAndPath(value) { - const result = {} - try { - const url = new URL(value) - result.url = url.origin - result.path = url.pathname - } catch (e) { - const uriRegex = value.match( - /^((http[s]?:\/\/)?(<<[^/]+>>)?[^/]*|)(\/?.*)$/ - ) - result.url = uriRegex[1] - result.path = uriRegex[4] - } - return result -}