diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7cd35099200f5e2c0e63b6606e2b899d0be8ef5c..dc83a81d2b421de89432d5d80756b977f740ce29 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,6 @@ before_script: - apk add curl - export TAG=${CI_COMMIT_TAG:-latest} - build: stage: build services: diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000000000000000000000000000000000..36af219892fda8ea669cd4b6725cd7b892231967 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000000000000000000000000000000000..154871ed58add16f47f8227661d7c5d1331fa10a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +default +dind +plugins \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..236324e86690b8e32efaf624fc0d9f93bdc2a626 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "tabWidth": 2, + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 120, + "useTabs": false +} diff --git a/CHANGELOG.md b/CHANGELOG.md index e6de0c635810f0efd00cd72376139fc2da306484..0e47e974d6434faaf7c800988ec5b4de66acaedd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,26 @@ - [1.4] 24/02/2022 -* chore: remove java plugin -* feat: prefix path instead of suffix for hosts + +- chore: remove java plugin +- feat: prefix path instead of suffix for hosts [1.3] 14/02/2022 -* upgrade java plugin to 0.21.0 -* support of git for student + +- upgrade java plugin to 0.21.0 +- support of git for student [1.2] 27/11/2020 -* Image supports in briefing -* Set theia-full instead of theia-java (https://git.e-biz.fr/deadlock-public/deadlock-theia/-/issues/2) + +- Image supports in briefing +- Set theia-full instead of theia-java (https://git.e-biz.fr/deadlock-public/deadlock-theia/-/issues/2) [1.1] 27/11/2020 -* preStop hook ok -* GitLens integration -* Keep view on memory + +- preStop hook ok +- GitLens integration +- Keep view on memory [1.0] 02/10/2020 -* git integration -* recorder-command -* docs/ support +- git integration +- recorder-command +- docs/ support diff --git a/README.md b/README.md index 0efce8a5520780a55d73ec3cbdbb3ce03eeccaa3..428481eb4b0d30b949cf41d17331633ffbd087fc 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ - Deadlock Theia projet basé sur notre propre image de Theia https://git.e-biz.fr/deadlock-public/theia. Plusieurs éléments ajoutés à l'image de base : 1. Deadlock plugins (deadlock-plugins/) 2. Outil d'enregistrment, qui permet d'enregistrer le code quand un utilisateur exécute du code (deadlock(plugins/recorder)) -3. Gestion du CORS (*.deadlock.io) dans `server.js` +3. Gestion du CORS (\*.deadlock.io) dans `server.js` + +Deux images de `deadlock-theia` sont build ici, _code_ et _kube_. -Deux images de `deadlock-theia` sont build ici, *code* et *kube*. +## Setup + +Afin d'installer les éléments requis pour le développement, vous pouvez lancer le script `./setup.sh`. ## Construire les plugins : + `./build-plugins.sh` Tous les plugins qui se trouvent dans `deadlock-public` vont être construit en `.vsix` puis placés @@ -16,19 +20,23 @@ dans `plugins/` (ex: deadlock-plugins/deadlock-extension). Il est aussi possible d'ajouter directement des plugins `.vsix` en ajoutant le fichier dans `plugins/` ## Recorder : + Le recorder permet de sauvegarder régulièrement le code de l'utilisateur. Pour se faire il écoute les commandes exécutées par l'utilisateur et si une contient `java|npm|yarn` alors un snapshot du code est réalisé. ### Build + `./build-recorder.sh` ## Construire l'image Deadlock Theia avec le recorder et les plugins + `./build.sh $TAG (code|kube)` # Requirements: + 1. NodeJS > ^14.X 2. Vscode ou Vscodium 3. Docker -Ce projet contient le minimum pour construire une image Docker Theia avec Blueprint (https://theia-ide.org/docs/composing_applications/) \ No newline at end of file +Ce projet contient le minimum pour construire une image Docker Theia avec Blueprint (https://theia-ide.org/docs/composing_applications/) diff --git a/deadlock-plugins/README.md b/deadlock-plugins/README.md index 9d3f1309c92306a79c6551a4b30cd9944eadfb97..73b6ded32c1c777f9127a8b4d9099a9f034bbec4 100644 --- a/deadlock-plugins/README.md +++ b/deadlock-plugins/README.md @@ -1,7 +1,6 @@ - Contient une liste de dossier des extensions à construire pour ajouter à Theia pendant la phase de build. Chaque dossier d'extension doit contenir un fichier `install.sh` et `build.sh` qui doivent contenir respectivement la façon d'installer les dépendances et les executions pour construire le plugin, c'est à dire créer un fichier `vsix` à la fin. -Chaque fichier build.sh sera appelé avec comme premier argument le tag en cours. \ No newline at end of file +Chaque fichier build.sh sera appelé avec comme premier argument le tag en cours. diff --git a/deadlock-plugins/deadlock-extension/.eslintrc.js b/deadlock-plugins/deadlock-extension/.eslintrc.js index cd15cf93f5de58e6be674beb72643e473d6bdb8d..2cac4952287f4b6d28a6b22b9a39044d31270618 100644 --- a/deadlock-plugins/deadlock-extension/.eslintrc.js +++ b/deadlock-plugins/deadlock-extension/.eslintrc.js @@ -1,21 +1,16 @@ /**@type {import('eslint').Linter.Config} */ // eslint-disable-next-line no-undef module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - ], - rules: { - 'semi': [2, 'always'], - 'quotes': [2, 'single', 'avoid-escape'], - '@typescript-eslint/no-unused-vars': 0, - '@typescript-eslint/no-explicit-any': 0, - '@typescript-eslint/explicit-module-boundary-types': 0, - '@typescript-eslint/no-non-null-assertion': 0, - } -}; \ No newline at end of file + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + rules: { + semi: [2, 'always'], + quotes: [2, 'single' | 'backtick', 'avoid-escape'], + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-explicit-any': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/no-non-null-assertion': 0, + }, +}; diff --git a/deadlock-plugins/deadlock-extension/.vscode/extensions.json b/deadlock-plugins/deadlock-extension/.vscode/extensions.json index af515502dfd158060279cdec8c0bb7e54c09af47..326dae3cd5b9cae9464cbdc6390d11927043f728 100644 --- a/deadlock-plugins/deadlock-extension/.vscode/extensions.json +++ b/deadlock-plugins/deadlock-extension/.vscode/extensions.json @@ -1,9 +1,7 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "dbaeumer.vscode-eslint" - ] -} \ No newline at end of file + // List of extensions which should be recommended for users of this workspace. + "recommendations": ["dbaeumer.vscode-eslint"] +} diff --git a/deadlock-plugins/deadlock-extension/.vscode/launch.json b/deadlock-plugins/deadlock-extension/.vscode/launch.json index 461f3da0dba050b10029a046cd1c0a70058cc7eb..4c4a9c78b100a81bc070816bab70bbcf326ee2c1 100644 --- a/deadlock-plugins/deadlock-extension/.vscode/launch.json +++ b/deadlock-plugins/deadlock-extension/.vscode/launch.json @@ -3,16 +3,16 @@ // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 { - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}"], - "outFiles": ["${workspaceFolder}/out/**/*.js"], - "preLaunchTask": "npm: watch" - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + "preLaunchTask": "npm: watch" + } + ] } diff --git a/deadlock-plugins/deadlock-extension/.vscode/settings.json b/deadlock-plugins/deadlock-extension/.vscode/settings.json index 8d047dada4aa529a4c752ee2c0ed4f265f819426..194c9b6b6c9840561b2552671bdaa26be65366ba 100644 --- a/deadlock-plugins/deadlock-extension/.vscode/settings.json +++ b/deadlock-plugins/deadlock-extension/.vscode/settings.json @@ -1,3 +1,3 @@ { - "editor.insertSpaces": false -} \ No newline at end of file + "editor.insertSpaces": false +} diff --git a/deadlock-plugins/deadlock-extension/.vscode/tasks.json b/deadlock-plugins/deadlock-extension/.vscode/tasks.json index 3b17e53b62cc6ffaacd997adeb1915422fb6858f..078ff7e01ef583efd188933e6f5af582ec9d81bc 100644 --- a/deadlock-plugins/deadlock-extension/.vscode/tasks.json +++ b/deadlock-plugins/deadlock-extension/.vscode/tasks.json @@ -1,20 +1,20 @@ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format { - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "watch", - "problemMatcher": "$tsc-watch", - "isBackground": true, - "presentation": { - "reveal": "never" - }, - "group": { - "kind": "build", - "isDefault": true - } - } - ] + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] } diff --git a/deadlock-plugins/deadlock-extension/.vscodeignore b/deadlock-plugins/deadlock-extension/.vscodeignore index 7d2b7710829b2c915b12a84f06439e8a6af2e2a4..d626c52f3c583b1db5e9a70958ac2f34ac37a757 100644 --- a/deadlock-plugins/deadlock-extension/.vscodeignore +++ b/deadlock-plugins/deadlock-extension/.vscodeignore @@ -1,8 +1,6 @@ .vscode -node_modules out/ !out/main.js src/ dev/ -tsconfig.json -webpack.config.js \ No newline at end of file +tsconfig.json \ No newline at end of file diff --git a/deadlock-plugins/deadlock-extension/package-lock.json b/deadlock-plugins/deadlock-extension/package-lock.json index b333a7a44e20b089514ec4236f37dd0fd07631f8..b295b7667c31cb60e1d9f701b2cefc4ce3da03cb 100644 --- a/deadlock-plugins/deadlock-extension/package-lock.json +++ b/deadlock-plugins/deadlock-extension/package-lock.json @@ -8,19 +8,27 @@ "name": "deadlock-coding", "version": "0.0.2", "dependencies": { + "@vscode/webview-ui-toolkit": "^1.0.0", "async": "^3.2.2", + "crypto-js": "^4.1.1", "date-fns": "^2.27.0", + "inversify": "^6.0.1", "marked": "^4.0.6", + "node-fetch": "^3.2.3", + "reflect-metadata": "^0.1.13", "simple-git": "^2.48.0" }, "devDependencies": { + "@types/crypto-js": "^4.1.1", "@types/marked": "^4.0.1", "@types/node": "^12.20.47", + "@types/node-fetch": "^2.6.1", "@types/vscode": "^1.51.0", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", "esbuild": "^0.14.2", "eslint": "^7.32.0", + "prettier": "2.6.2", "terser-webpack-plugin": "^5.2.5", "ts-node": "^9.1.1", "typescript": "^3.9.10", @@ -29,7 +37,7 @@ "webpack-cli": "^4.9.1" }, "engines": { - "vscode": "^1.51.0" + "vscode": "^1.63.0" } }, "node_modules/@babel/code-frame": { @@ -149,6 +157,48 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, + "node_modules/@microsoft/fast-element": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.9.0.tgz", + "integrity": "sha512-VxDwoLEEQRRxXfLOB5Llzha9WWvjVJHZFHNE1mn2s1QV5IAkOhrYrhFe9vzv50eI6CqazChDyHDy1km3+rn0wg==" + }, + "node_modules/@microsoft/fast-foundation": { + "version": "2.41.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.41.1.tgz", + "integrity": "sha512-q3t43CVsYrLeBbmiY6+GvV0/uUqnz7anmagD8qMBpHIpC6XpEERGBNbyC6AxQrRoBrYBFFhBJRTPn7vCqi4iPA==", + "dependencies": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-web-utilities": "^5.2.0", + "tabbable": "^5.2.0", + "tslib": "^1.13.0" + } + }, + "node_modules/@microsoft/fast-react-wrapper": { + "version": "0.1.48", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", + "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", + "dependencies": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-foundation": "^2.41.1" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@microsoft/fast-web-utilities": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.2.0.tgz", + "integrity": "sha512-Ri5FR4MotdAPKeFLo/yhZu6/xMVo/H9OXcGaC/qiQo+U0zY8cLPCViGmHYYgxpCYviS4VpgqPL5dslTE6wg9Yg==", + "dependencies": { + "exenv-es6": "^1.1.1" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", @@ -199,6 +249,16 @@ "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==", "dev": true }, + "node_modules/@types/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "node_modules/@types/vscode": { "version": "1.62.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz", @@ -343,6 +403,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@vscode/webview-ui-toolkit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.0.0.tgz", + "integrity": "sha512-/qaHYZXqvIKkao54b7bLzyNH8BC+X4rBmTUx1MvcIiCjqRMxml0BCpqJhnDpfrCb0IOxXRO8cAy1eB5ayzQfBA==", + "dependencies": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.38.0", + "@microsoft/fast-react-wrapper": "^0.1.18" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -538,9 +611,9 @@ "dev": true }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -667,6 +740,12 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "node_modules/azure-devops-node-api": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", @@ -1010,6 +1089,18 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1054,6 +1145,11 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "node_modules/css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -1082,6 +1178,14 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "engines": { + "node": ">= 12" + } + }, "node_modules/date-fns": { "version": "2.27.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz", @@ -1137,6 +1241,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -1333,84 +1446,6 @@ "esbuild-windows-arm64": "0.14.2" } }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", - "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", - "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", - "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", - "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", - "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", - "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/esbuild-linux-64": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", @@ -1424,136 +1459,6 @@ "linux" ] }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", - "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", - "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", - "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", - "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", - "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ] - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", - "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", - "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ] - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", - "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", - "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", - "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1692,6 +1597,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1797,6 +1714,11 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -1839,6 +1761,28 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz", + "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1883,6 +1827,31 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2241,6 +2210,11 @@ "node": ">= 0.10" } }, + "node_modules/inversify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==" + }, "node_modules/is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", @@ -2369,8 +2343,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -2493,6 +2466,18 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2687,6 +2672,41 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", + "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", @@ -2971,6 +2991,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -3053,6 +3088,18 @@ "node": ">=0.10.0" } }, + "node_modules/react": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz", + "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -3098,6 +3145,11 @@ "node": ">= 0.10" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -3498,6 +3550,11 @@ "node": ">=4" } }, + "node_modules/tabbable": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz", + "integrity": "sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ==" + }, "node_modules/table": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", @@ -3702,8 +3759,7 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -3916,6 +3972,14 @@ "node": ">=10.13.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webpack": { "version": "5.65.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz", @@ -4037,18 +4101,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4250,6 +4302,45 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, + "@microsoft/fast-element": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.9.0.tgz", + "integrity": "sha512-VxDwoLEEQRRxXfLOB5Llzha9WWvjVJHZFHNE1mn2s1QV5IAkOhrYrhFe9vzv50eI6CqazChDyHDy1km3+rn0wg==" + }, + "@microsoft/fast-foundation": { + "version": "2.41.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.41.1.tgz", + "integrity": "sha512-q3t43CVsYrLeBbmiY6+GvV0/uUqnz7anmagD8qMBpHIpC6XpEERGBNbyC6AxQrRoBrYBFFhBJRTPn7vCqi4iPA==", + "requires": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-web-utilities": "^5.2.0", + "tabbable": "^5.2.0", + "tslib": "^1.13.0" + } + }, + "@microsoft/fast-react-wrapper": { + "version": "0.1.48", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", + "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", + "requires": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-foundation": "^2.41.1" + } + }, + "@microsoft/fast-web-utilities": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.2.0.tgz", + "integrity": "sha512-Ri5FR4MotdAPKeFLo/yhZu6/xMVo/H9OXcGaC/qiQo+U0zY8cLPCViGmHYYgxpCYviS4VpgqPL5dslTE6wg9Yg==", + "requires": { + "exenv-es6": "^1.1.1" + } + }, + "@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", + "dev": true + }, "@types/eslint": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", @@ -4300,6 +4391,16 @@ "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==", "dev": true }, + "@types/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, "@types/vscode": { "version": "1.62.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz", @@ -4377,6 +4478,16 @@ "eslint-visitor-keys": "^1.1.0" } }, + "@vscode/webview-ui-toolkit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.0.0.tgz", + "integrity": "sha512-/qaHYZXqvIKkao54b7bLzyNH8BC+X4rBmTUx1MvcIiCjqRMxml0BCpqJhnDpfrCb0IOxXRO8cAy1eB5ayzQfBA==", + "requires": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.38.0", + "@microsoft/fast-react-wrapper": "^0.1.18" + } + }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -4559,9 +4670,9 @@ "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true }, "acorn-import-assertions": { @@ -4660,6 +4771,12 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "azure-devops-node-api": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", @@ -4916,6 +5033,15 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -4957,6 +5083,11 @@ "which": "^2.0.1" } }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -4976,6 +5107,11 @@ "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", "dev": true }, + "data-uri-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==" + }, "date-fns": { "version": "2.27.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz", @@ -5010,6 +5146,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -5157,48 +5299,6 @@ "esbuild-windows-arm64": "0.14.2" } }, - "esbuild-android-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", - "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", - "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", - "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", - "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", - "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", - "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", - "dev": true, - "optional": true - }, "esbuild-linux-64": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", @@ -5206,76 +5306,6 @@ "dev": true, "optional": true }, - "esbuild-linux-arm": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", - "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", - "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", - "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", - "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", - "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", - "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", - "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", - "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", - "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", - "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", - "dev": true, - "optional": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -5378,6 +5408,14 @@ "acorn": "^7.4.0", "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, "esprima": { @@ -5455,6 +5493,11 @@ "strip-final-newline": "^2.0.0" } }, + "exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" + }, "expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -5494,6 +5537,15 @@ "pend": "~1.2.0" } }, + "fetch-blob": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.5.tgz", + "integrity": "sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5529,6 +5581,25 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -5793,6 +5864,11 @@ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, + "inversify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==" + }, "is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", @@ -5887,8 +5963,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -5992,6 +6067,15 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -6151,6 +6235,21 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", + "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, "node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", @@ -6374,6 +6473,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6440,6 +6545,15 @@ } } }, + "react": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz", + "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==", + "peer": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -6481,6 +6595,11 @@ "resolve": "^1.9.0" } }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -6767,6 +6886,11 @@ "has-flag": "^3.0.0" } }, + "tabbable": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.1.tgz", + "integrity": "sha512-40pEZ2mhjaZzK0BnI+QGNjJO8UYx9pP5v7BGe17SORTO0OEuuaAwQTkAp8whcZvqon44wKFOikD+Al11K3JICQ==" + }, "table": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", @@ -6908,8 +7032,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", @@ -7075,6 +7198,11 @@ "graceful-fs": "^4.1.2" } }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + }, "webpack": { "version": "5.65.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz", @@ -7105,14 +7233,6 @@ "terser-webpack-plugin": "^5.1.3", "watchpack": "^2.3.1", "webpack-sources": "^3.2.2" - }, - "dependencies": { - "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true - } } }, "webpack-cli": { diff --git a/deadlock-plugins/deadlock-extension/package.json b/deadlock-plugins/deadlock-extension/package.json index 984302eae3d6e7e54653d9265aaea3b6f79a98e6..69aa8ecd31ee4a426c3aee800ade330a3baf4327 100644 --- a/deadlock-plugins/deadlock-extension/package.json +++ b/deadlock-plugins/deadlock-extension/package.json @@ -4,7 +4,7 @@ "version": "0.0.2", "publisher": "Deadlock", "engines": { - "vscode": "^1.51.0" + "vscode": "^1.66.0" }, "categories": [ "Other" @@ -27,6 +27,21 @@ "command": "deadlock.openBriefing", "title": "Open Briefing", "category": "Deadlock Coding" + }, + { + "command": "deadlock.openQuickSetup", + "title": "Open Deadlock quick setup page", + "category": "Deadlock Coding" + }, + { + "command": "deadlock.chooseMissionWorkdir", + "title": "Choose mission workdir", + "category": "Deadlock Coding" + }, + { + "command": "deadlock.clear", + "title": "Clear cache", + "category": "Deadlock Coding" } ], "viewsContainers": { @@ -45,11 +60,27 @@ "name": "Explorer", "icon": "media/dep.svg", "contextualTitle": "Deadlock" + }, + { + "id": "help", + "name": "Help", + "visibility": "collapsed" } ] }, + "viewsWelcome": [ + { + "view": "help", + "contents": "[Quick Setup](command:deadlock.openQuickSetup)\n" + } + ], "menus": { - "view/title": [], + "view/title": [ + { + "command": "deadlock.chooseMissionWorkdir", + "when": "view == deadlockPanel" + } + ], "view/item/context": [] } }, @@ -65,19 +96,27 @@ "watch": "tsc -w -p ./" }, "dependencies": { + "@vscode/webview-ui-toolkit": "^1.0.0", "async": "^3.2.2", + "crypto-js": "^4.1.1", "date-fns": "^2.27.0", + "inversify": "^6.0.1", "marked": "^4.0.6", + "node-fetch": "^3.2.3", + "reflect-metadata": "^0.1.13", "simple-git": "^2.48.0" }, "devDependencies": { + "@types/crypto-js": "^4.1.1", "@types/marked": "^4.0.1", "@types/node": "^12.20.47", + "@types/node-fetch": "^2.6.1", "@types/vscode": "^1.51.0", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", "esbuild": "^0.14.2", "eslint": "^7.32.0", + "prettier": "2.6.2", "terser-webpack-plugin": "^5.2.5", "ts-node": "^9.1.1", "typescript": "^3.9.10", diff --git a/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js b/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js new file mode 100644 index 0000000000000000000000000000000000000000..363a55f54e7adbcc2c6d4ca27ec46a730a2e4b81 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/resources/js/gettingStartedView.js @@ -0,0 +1,14 @@ +// This file is used by gettingStarted via a <script> tag +const vscode = acquireVsCodeApi(); + +function launchChooseMissionWorkdirAction() { + vscode.postMessage({ + command: 'launchChooseMissionWorkdirAction', + }); +} + +function openAuthenticationPageAction() { + vscode.postMessage({ + command: 'openAuthenticationPageAction', + }); +} diff --git a/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css b/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css new file mode 100644 index 0000000000000000000000000000000000000000..5ae4f6fcf2fff5cd84531b5ab0e3f00fa46cf26f --- /dev/null +++ b/deadlock-plugins/deadlock-extension/resources/styles/gettingStartedView.css @@ -0,0 +1,34 @@ +/* This file is used by gettingStarted via a <style> tag */ + +.deadlock-getting-started-card-container { + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; +} +.deadlock-getting-started-card-container .deadlock-getting-started-card { + display: flex; + align-items: start; + min-height: 5em; + margin: 0.5em; + width: 50vw; + min-width: 20vw; +} + +.deadlock-getting-started-card-container .deadlock-getting-started-card .card-checkbox { + width: 15%; +} + +.deadlock-getting-started-card-container .deadlock-getting-started-card .card-body { + width: 85%; +} + +.deadlock-getting-started-card-container .deadlock-getting-started-card .card-body .card-title { + font-weight: bold; + font-size: 1.5em; + margin-bottom: 0.2em; +} + +.deadlock-getting-started-card-container .deadlock-getting-started-card .card-body .card-description { + margin-bottom: 0.5em; +} diff --git a/deadlock-plugins/deadlock-extension/src/config.prod.ts b/deadlock-plugins/deadlock-extension/src/config.prod.ts new file mode 100644 index 0000000000000000000000000000000000000000..46ee6889446bcf153f9619125c3ab2bd4d753d65 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/config.prod.ts @@ -0,0 +1,5 @@ +export const KEYCLOAK_DEVICE_AUTH_URL = + 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device'; +export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; +export const KEYCLOAK_USER_INFO_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REJECT_UNAUTHORIZED = true; diff --git a/deadlock-plugins/deadlock-extension/src/config.staging.ts b/deadlock-plugins/deadlock-extension/src/config.staging.ts new file mode 100644 index 0000000000000000000000000000000000000000..e8ddb5e90e01601adc2b4f79ee07d241551c535b --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/config.staging.ts @@ -0,0 +1,7 @@ +export const KEYCLOAK_DEVICE_AUTH_URL = + 'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device'; +export const KEYCLOAK_TOKEN_CREATE_URL = + 'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; +export const KEYCLOAK_USER_INFO_URL = + 'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REJECT_UNAUTHORIZED = true; diff --git a/deadlock-plugins/deadlock-extension/src/config.ts b/deadlock-plugins/deadlock-extension/src/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..a53b3ab5bba69c5e9d7ed0ef82f7662a8227933f --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/config.ts @@ -0,0 +1,7 @@ +export const KEYCLOAK_DEVICE_AUTH_URL = + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device'; +export const KEYCLOAK_TOKEN_CREATE_URL = + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; +export const KEYCLOAK_USER_INFO_URL = + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REJECT_UNAUTHORIZED = false; diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dcdc452f031924a31a33349fd1ce8566ffedee0 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts @@ -0,0 +1,26 @@ +import { commands } from 'vscode'; +import { Command } from '../theia/command'; +import Controller from './controller'; +import ExtensionStore from './extensionStore'; + +export class CommandHandler { + private extensionStore: ExtensionStore; + constructor(private controller: Controller) { + this.extensionStore = ExtensionStore.getInstance(); + this.initCommandHandler(); + } + + initCommandHandler() { + commands.registerCommand( + CHOOSE_MISSION_WORKDIR_COMMAND.cmd, + this.controller.chooseMissionWorkdir.bind(this.controller), + ); + commands.registerCommand(AUTHENTICATE_COMMAND.cmd, this.controller.authenticate.bind(this.controller)); + commands.registerCommand(CLEAR_COMMAND.cmd, this.controller.clear.bind(this.controller)); + } +} + +export const CHOOSE_MISSION_WORKDIR_COMMAND = new Command('Choose mission workdir', 'deadlock.chooseMissionWorkdir'); +export const AUTHENTICATE_COMMAND = new Command('Authenticate', 'deadlock.authenticate'); +export const CLEAR_COMMAND = new Command('Clear', 'deadlock.clear'); +export const OPEN_URL_IN_BROWSER_COMMAND = new Command('Open url in browser', 'vscode.open'); diff --git a/deadlock-plugins/deadlock-extension/src/core/config.ts b/deadlock-plugins/deadlock-extension/src/core/config.ts index ff72a36003b87cf4bceb70f15eb013e319a29219..629d89ddb3183a72bfab6d8bb97bd6e15fc91049 100644 --- a/deadlock-plugins/deadlock-extension/src/core/config.ts +++ b/deadlock-plugins/deadlock-extension/src/core/config.ts @@ -7,41 +7,22 @@ const onContainer = homeDir.includes('theia') || homeDir.includes('root'); const deadlockExtensionPath = path.join(homeDir, 'deadlock-extension'); -export const PROJECT_SRC_PATH = onContainer - ? '/project' - : path.join(homeDir, 'deadlock-extension', '/project'); +export const PROJECT_SRC_PATH = onContainer ? '/project' : path.join(homeDir, 'deadlock-extension', '/project'); export const PROJECT_THEIA_PATH = onContainer ? path.join('/home/project') : path.join(deadlockExtensionPath, 'project-theia'); -export const DOCS_PATH = path.join( - path.join(onContainer ? '/home/theia' : deadlockExtensionPath), - 'docs' -); +export const DOCS_PATH = path.join(path.join(onContainer ? '/home/theia' : deadlockExtensionPath), 'docs'); -export const CONFIG_PATH = onContainer - ? '/home/config/' - : path.join(deadlockExtensionPath, 'config'); +export const CONFIG_PATH = onContainer ? '/home/config/' : path.join(deadlockExtensionPath, 'config'); -export const USER_CHALLENGE_PATH = path.join( - CONFIG_PATH, - 'user-challenge.json' -); +export const USER_CHALLENGE_PATH = path.join(CONFIG_PATH, 'user-challenge.json'); export const BRIEFING_FILE_NAME = 'briefing.md'; -export const ENV_FILE_PATH = path.join( - PROJECT_THEIA_PATH, - '/.env' -); +export const ENV_FILE_PATH = path.join(PROJECT_THEIA_PATH, '/.env'); -export const BASHRC_PATH = path.join( - homeDir, - '/.bashrc' -); +export const BASHRC_PATH = path.join(homeDir, '/.bashrc'); -export const SERVICES_PATHS_PATH = path.join( - PROJECT_THEIA_PATH, - '/paths.json' -); +export const SERVICES_PATHS_PATH = path.join(PROJECT_THEIA_PATH, '/paths.json'); diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d7d3bb15fec7d1d56978bac11aa52d28b86716f --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts @@ -0,0 +1,109 @@ +import * as vscode from 'vscode'; +import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config'; +import { OPEN_QUICK_SETUP_COMMAND } from '../theia/command'; +import BriefingView from '../view/briefingView'; +import QuickSetupView from '../view/quickSetupView'; +import { CHOOSE_MISSION_WORKDIR_COMMAND, CommandHandler, OPEN_URL_IN_BROWSER_COMMAND } from './commandHandler'; +import ExtensionStore from './extensionStore'; +import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; + +export default class Controller { + public connection: KeycloakOAuth2DeviceFlowConnection; + private commandHandler: CommandHandler; + private briefingView: BriefingView; + private quickSetupView: QuickSetupView; + private extensionStore: ExtensionStore; + + constructor(private context: vscode.ExtensionContext) { + this.extensionStore = ExtensionStore.getInstance(context); + this.briefingView = new BriefingView(); + this.quickSetupView = new QuickSetupView(context.extensionUri); + this.commandHandler = new CommandHandler(this); + this.connection = new KeycloakOAuth2DeviceFlowConnection( + KEYCLOAK_DEVICE_AUTH_URL, + KEYCLOAK_TOKEN_CREATE_URL, + KEYCLOAK_USER_INFO_URL, + ); + + this.init(); + } + private async init() { + const that = this; + vscode.window.registerUriHandler({ + handleUri(uri: vscode.Uri) { + const queryParams: URLSearchParams = new URLSearchParams(uri.query); + const action: string | null = queryParams.get('action'); + + switch (action) { + case 'open-challenge': + that.launchMission(queryParams.get('missionId')); + break; + + default: + vscode.window.showInformationMessage('Aucune action trouvée!'); + } + }, + }); + + const exensionStorage = ExtensionStore.getInstance(); + this.quickSetupView.isAlreadyConnected = !!(await exensionStorage.getAccessToken()); + } + async chooseMissionWorkdir() { + const actualMissionWorkDir = this.extensionStore.getMissionWorkdir(); + + const folderUri = await vscode.window.showOpenDialog({ + defaultUri: actualMissionWorkDir ? vscode.Uri.file(actualMissionWorkDir) : undefined, + canSelectFolders: true, + canSelectFiles: false, + title: 'Choisis le dossier qui contiendra tes missions', + }); + + if (!folderUri) { + if (this.extensionStore.getMissionWorkdir()) { + return; + } + this.chooseMissionWorkdir(); + } else { + this.extensionStore.setMissionWorkdir(folderUri[0].path); + } + } + public async clear() { + const exensionStorage = ExtensionStore.getInstance(); + await exensionStorage.clear(); + this.quickSetupView.isAlreadyConnected = false; + } + + public async authenticate() { + // WARN generate a new device code every time student clicks on log in button. Should I keep it ?\ + // The answer might be 'yes' because when the student is already authenticated, the log in button should be disabled. + await this.connection.registerDevice(); + const tokens = await this.connection.getToken({ openLink: Controller.openBrowserWithUrl }); + await this.extensionStore.setAccessToken(tokens.accessToken); + await this.extensionStore.setRefreshToken(tokens.refreshToken); + this.quickSetupView.isAlreadyConnected = true; + } + public static openBrowserWithUrl(url: string) { + vscode.commands.executeCommand(OPEN_URL_IN_BROWSER_COMMAND.cmd, vscode.Uri.parse(url)); + } + + public async launchMission(missionId: string | null) { + if (missionId) { + vscode.window.showInformationMessage(`vous lancez la mission ${missionId}`); + const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined; + if (!hadMissionWorkdir) { + await vscode.commands.executeCommand(CHOOSE_MISSION_WORKDIR_COMMAND.cmd); + } + + const hadBeenConnected = (await this.extensionStore.getAccessToken()) !== undefined; + + if (!hadBeenConnected) { + this.authenticate(); + vscode.window.showInformationMessage('Nouvelle connexion validée'); + } else { + vscode.window.showInformationMessage('Déjà connecté: session récupérée'); + } + + vscode.commands.executeCommand(OPEN_QUICK_SETUP_COMMAND.cmd); + } + } +} diff --git a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d4497c98e99a9929c8e88368d2c8a445bb602cc --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts @@ -0,0 +1,82 @@ +import { ExtensionContext, Memento, SecretStorage, window } from 'vscode'; +import { log } from '../recorder/utils'; + +export type GlobalStorageType = Memento & { setKeysForSync(keys: readonly string[]): void }; + +export default class ExtensionStore { + private static instance: ExtensionStore; + + private globalStorage: GlobalStorageType; + private secretStorage: SecretStorage; + + private constructor(context: ExtensionContext) { + this.globalStorage = context.globalState; + this.secretStorage = context.secrets; + } + + public async clear() { + if (this.globalStorage.keys()) { + for (let key of this.globalStorage.keys()) { + this.globalStorage.update(key, undefined); + } + } + if (await this.secretStorage.get(StoreKey.AccessTokenKey)) this.secretStorage.delete(StoreKey.AccessTokenKey); + if (await this.secretStorage.get(StoreKey.RefreshTokenKey)) this.secretStorage.delete(StoreKey.RefreshTokenKey); + } + + public static getInstance(context?: ExtensionContext): ExtensionStore { + if (!ExtensionStore.instance) { + if (!context) throw new Error('ExtensionStore should be initiate with a storage first time'); + ExtensionStore.instance = new ExtensionStore(context); + } + + return ExtensionStore.instance; + } + + getMissionWorkdir(): string | undefined { + return this.globalStorage.get<string>(StoreKey.MissionWorkdirKey); + } + + setMissionWorkdir(path: string) { + this.globalStorage.update(StoreKey.MissionWorkdirKey, path); + window.showInformationMessage(`Nouveau dossier de stockage des missions: ${path}`); + } + + public async getAccessToken() { + return this.readSecret(StoreKey.AccessTokenKey); + } + + public async getRefreshToken() { + return this.readSecret(StoreKey.RefreshTokenKey); + } + + public async setAccessToken(accessToken: string) { + if (!accessToken) { + log('Attempt to store undefined access token'); + return; + } + return this.storeSecret(StoreKey.AccessTokenKey, accessToken); + } + + public async setRefreshToken(refreshToken: string) { + if (!refreshToken) { + log('Attempt to store undefined refresh token'); + return; + } + return this.storeSecret(StoreKey.RefreshTokenKey, refreshToken); + } + + private async storeSecret(key: StoreKey, value: string) { + this.secretStorage.store(key, value); + } + + private async readSecret(key: StoreKey) { + return this.secretStorage.get(key); + } +} + +enum StoreKey { + MissionWorkdirKey = 'mission-workdir-key', + AccessTokenKey = 'access-token-key', + RefreshTokenKey = 'refresh-token-key', +} diff --git a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts index aa0f9d2989970ae9729b4cac877d9fa4301fe4fe..9e739afc67856fa5f0f13e735acde4d5e2f4554a 100644 --- a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts +++ b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts @@ -1,4 +1,5 @@ import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git'; +import { error } from '../recorder/utils'; import { PROJECT_SRC_PATH } from './config'; import UserConfig from './userConfig'; @@ -9,103 +10,106 @@ const DEFAULT_REMOTE = 'origin'; const DEFAULT_BRANCH = 'master'; export default class GitMission { + private git: SimpleGit; - private git: SimpleGit; + constructor(private userConfig: UserConfig) { + const options: Partial<SimpleGitOptions> = { + baseDir: PROJECT_SRC_PATH, + binary: 'git', + maxConcurrentProcesses: 2, + }; - constructor(private userConfig: UserConfig) { - const options: Partial<SimpleGitOptions> = { - baseDir: PROJECT_SRC_PATH, - binary: 'git', - maxConcurrentProcesses: 2, - }; + this.git = simpleGit(options); + } - this.git = simpleGit(options); - } - - async setupSshAgent() { - const { err, stderr, stdout } = await exec(`eval "$(ssh-agent -s)" && ssh-keyscan -p ${this.userConfig.getGiteaSshPort()} -H ${this.userConfig.getGiteaHost()} >> ~/.ssh/known_hosts`); + async setupSshAgent() { + const { err, stderr, stdout } = await exec( + `eval "$(ssh-agent -s)" && ssh-keyscan -p ${this.userConfig.getGiteaSshPort()} -H ${this.userConfig.getGiteaHost()} >> ~/.ssh/known_hosts`, + ); - console.log(stdout); - - if (err) { - console.error(stderr); - throw new Error(err); - } + console.log(stdout); + if (err) { + console.error(stderr); + throw new Error(err); } - - get author() { - - return this.userConfig.getUsername(); + } + + get author() { + return this.userConfig.getUsername(); + } + + async init() { + try { + console.log('Setup ssh agent'); + await this.setupSshAgent(); + + console.log('Init Git mission..'); + + const remote = await this.readRemote(); + if (remote === DEFAULT_REMOTE) { + return Promise.resolve(this); + } + + const remotePath = this.getRemotePath(); + + await this.git.init(); + await this.git.addRemote(DEFAULT_REMOTE, remotePath); + await this.git.addConfig('user.email', this.userConfig.getCurrentUserDetails().email, false, 'system'); + await this.git.addConfig( + 'user.name', + `${this.userConfig.getCurrentUserDetails().lastName} ${this.userConfig.getCurrentUserDetails().firstName}`, + false, + 'system', + ); + + return Promise.resolve(this); + } catch (e) { + console.error(e); + return Promise.reject(e); } + } - async init() { - try { - - console.log('Setup ssh agent'); - await this.setupSshAgent(); - - console.log('Init Git mission..'); + private getRemotePath() { + return `ssh://git@${this.userConfig.getGiteaHost()}:${this.userConfig.getGiteaSshPort()}/${this.userConfig.getRemoteGitUsername()}/${this.userConfig.getMissionId()}`; + } - const remote = await this.readRemote(); - if (remote === DEFAULT_REMOTE) { - return Promise.resolve(this); - } - - const remotePath = this.getRemotePath(); - - await this.git.init(); - await this.git.addRemote(DEFAULT_REMOTE, remotePath); - await this.git.addConfig('user.email', this.userConfig.getCurrentUserDetails().email, false, "system"); - await this.git.addConfig('user.name', `${this.userConfig.getCurrentUserDetails().lastName} ${this.userConfig.getCurrentUserDetails().firstName}`, false, "system"); - - return Promise.resolve(this); - } catch (e) { - console.error(e); - return Promise.reject(e); - } + async readRemote() { + try { + return ((await this.git.remote([])) || '').replace(/(\r\n|\n|\r)/gm, ''); + } catch (e) { + error(e); } - - private getRemotePath() { - return `ssh://git@${this.userConfig.getGiteaHost()}:${this.userConfig.getGiteaSshPort()}/${this.userConfig.getRemoteGitUsername()}/${this.userConfig.getMissionId()}`; - } - - async readRemote() { - try { - return (await this.git.remote([]) || '').replace(/(\r\n|\n|\r)/gm, ''); - } catch (e) { - // ignore it, maybe the git repo does not exist - } - return ''; - } - - fetch() { - return this.git.fetch(DEFAULT_REMOTE); - } - - pull() { - return this.git.pull(DEFAULT_REMOTE, DEFAULT_BRANCH, { '--rebase': 'true' }); - } - - addAll() { - return this.git.add('.'); - } - - commit(message) { - return this.git.commit(message); - } - - push() { - return this.git.push(DEFAULT_REMOTE, DEFAULT_BRANCH); - } - - async isRemoteRepoExist() { - try { - const remotes = await this.git.listRemote(); - return remotes.length !== 0; - } catch { - // error, Gitea throws Gitea: Unauthorized when not found - return false; - } + return ''; + } + + fetch() { + return this.git.fetch(DEFAULT_REMOTE); + } + + pull() { + return this.git.pull(DEFAULT_REMOTE, DEFAULT_BRANCH, { '--rebase': 'true' }); + } + + addAll() { + return this.git.add('.'); + } + + commit(message) { + return this.git.commit(message); + } + + push() { + return this.git.push(DEFAULT_REMOTE, DEFAULT_BRANCH); + } + + async isRemoteRepoExist() { + try { + const remotes = await this.git.listRemote(); + return remotes.length !== 0; + } catch { + // error, Gitea throws Gitea: Unauthorized when not found + return false; } -} \ No newline at end of file + } +} diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..006d71388862f23244deef583bda1675242eb2e8 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.test.ts @@ -0,0 +1,56 @@ +import { error, log } from '../recorder/utils'; +import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; + +/** + * Maybe temporary file ?\ + * This class shows how to use KeycloakOAuth2DeviceFlowConnection.\ + * It is currently based on dev.deadlock instance\ + * but there are only some urls to change for further testings. + * + */ +export default class KeycloakOAuth2DeviceFlowConnectionTest { + public connection: KeycloakOAuth2DeviceFlowConnection; + constructor() { + log(' --- KeycloakOAuth2DeviceFlowConnectionTest --- '); + this.connection = new KeycloakOAuth2DeviceFlowConnection( + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device', + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token', + 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo', + ); + } + + /** + * Simple working examples + */ + public async run() { + const openLinkPlaceholder = (link: string) => { + log(`click here: ${link}`); + }; + + let tokens = await this.connection.getToken({ openLink: openLinkPlaceholder }); + log('tokens', tokens); + if (!tokens?.refreshToken) { + log("refresh token doesn't exist"); + return; + } + + let refreshedTokens = await this.connection.getToken({ + refreshToken: tokens.refreshToken, + openLink: openLinkPlaceholder, + }); + log('refreshed tokens', refreshedTokens); + + try { + log(`'12345' is a valid token ? ${await this.connection.tokenIsValid('12345')};`); + log(`'' is a valid token ? ${await this.connection.tokenIsValid('')};`); + log(`${tokens.accessToken} is a valid token ? ${await this.connection.tokenIsValid(tokens.accessToken)};`); + log( + `${refreshedTokens.accessToken} is a valid token ? ${await this.connection.tokenIsValid( + refreshedTokens.accessToken, + )};`, + ); + } catch (e) { + error(e); + } + } +} diff --git a/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0fbb38bf3c481e4ddafe1262b2d0b40c281981e --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/keycloakOAuth2DeviceFlowConnection.ts @@ -0,0 +1,266 @@ +import * as https from 'https'; +import fetch, { Response } from 'node-fetch'; +import { REJECT_UNAUTHORIZED } from '../config'; +import { HttpStatusCode } from '../customTypings/HttpStatusCode'; +import { TokenFetchErrorCode } from '../customTypings/KeycloakAPITypes'; +import { error as err, log } from '../recorder/utils'; + +process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = REJECT_UNAUTHORIZED ? '1' : '0'; + +export default class KeycloakOAuth2DeviceFlowConnection { + private waitDuration: WaitDuration; + private accessToken: string; + private refreshToken: string; + private deviceAuthorizationRequestResponse: DeviceAuthorizationRequestResponse; + + constructor(private deviceUrl: string, private tokenUrl: string, private userInfoUrl: string) { + /* + * Arbitrary durations to wait in seconds \ + * Waiting time between requests should be increasing + * if Keycloak api reponds with error code `slow_down` \ + * otherwise, it will continue to respond with this error code. \ + * The minimal waiting duration has been chosen to not be too short: \ + * Keycloak may saturate and crash due to too many requests. + */ + this.waitDuration = new WaitDuration([5_000, 5_000, 5_000, 10_000, 10_000, 10_000, 30_000, 30_000, 100_000]); + this.accessToken = ''; + this.refreshToken = ''; + this.deviceAuthorizationRequestResponse = {}; + } + + /** + * @param accessToken + * @returns Promise + */ + public async tokenIsValid(accessToken: string) { + if (!accessToken) { + return Promise.resolve(false); + } + const tokenValidationRequestResponse: Response = await fetch(this.userInfoUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Bearer ${accessToken}`, + }, + body: '', + agent: new https.Agent({ rejectUnauthorized: REJECT_UNAUTHORIZED }), + }); + const tokenValidationRequestResponseCode = tokenValidationRequestResponse.status; + switch (tokenValidationRequestResponseCode) { + case HttpStatusCode.OK: { + return Promise.resolve(true); + } + case HttpStatusCode.BAD_REQUEST: { + const badRequestResponse = (await tokenValidationRequestResponse.json()) as FailedAuthenticationResponse; + err(`${badRequestResponse.error!}: ${badRequestResponse.error_description}`); + throw new Error(`${badRequestResponse.error}: ${badRequestResponse.error_description}`); + } + case HttpStatusCode.UNAUTHORIZED: { + return Promise.resolve(false); + } + default: { + err(`Unhandled HTTP status: ${tokenValidationRequestResponseCode}`); + throw new Error(`Unhandled HTTP status: ${tokenValidationRequestResponseCode}`); + } + } + } + + public async getToken(args: { refreshToken?: string; openLink: (link: string) => void }) { + const { refreshToken, openLink } = args; + if (!!refreshToken) { + await this.createUserAuthentication({ + url: this.tokenUrl, + body: (() => { + const params = new URLSearchParams(); + params.append('response_type', 'token'); + params.append('client_id', 'deadlock-desktop'); + params.append('grant_type', 'refresh_token'); + params.append('refresh_token', refreshToken); + return params.toString(); + })(), + }); + return Promise.resolve({ accessToken: this.accessToken, refreshToken: this.refreshToken }); + } + if (!this.deviceIsRegistered()) { + await this.registerDevice(); + } + try { + openLink(this.deviceAuthorizationRequestResponse.verification_uri_complete!); + await this.createUserAuthentication({ + url: this.tokenUrl, + body: (() => { + const params = new URLSearchParams(); + params.append('response_type', 'token'); + params.append('device_code', this.deviceAuthorizationRequestResponse.device_code ?? ''); + params.append('grant_type', 'urn:ietf:params:oauth:grant-type:device_code'); + params.append('client_id', 'deadlock-desktop'); + return params.toString(); + })(), + }); + return Promise.resolve({ accessToken: this.accessToken, refreshToken: this.refreshToken }); + } catch (error) { + return Promise.reject(error); + } + } + + private deviceIsRegistered(): boolean { + return !!this.deviceAuthorizationRequestResponse.device_code; + } + + public async registerDevice() { + log('Device not registered. Registering ...'); + const deviceAuthorizationRequestResponse: Response = await this.createDeviceAuthorization({ + url: this.deviceUrl, + body: (() => { + const params = new URLSearchParams(); + params.append('client_id', 'deadlock-desktop'); + return params.toString(); + })(), + }); + this.deviceAuthorizationRequestResponse = + (await deviceAuthorizationRequestResponse.json()) as DeviceAuthorizationRequestResponse; + } + + private async createDeviceAuthorization(args: { url: string; body: string }): Promise<Response> { + const { url, body } = args; + log(`[POST] ${url} \n ${body}`); + return fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: body, + agent: new https.Agent({ rejectUnauthorized: REJECT_UNAUTHORIZED }), + }); + } + + /** + * + * @param args API URL endpoint to ask for a new token & request form parameters + * @throw Error containing Keycloak API `error_code` + */ + private async createUserAuthentication(args: { url: string; body: string }) { + const { url, body } = args; + let userAuthenticationRequestResponseCode = HttpStatusCode.I_AM_A_TEAPOT; + while (userAuthenticationRequestResponseCode !== HttpStatusCode.OK) { + log(`[POST] ${url} \n ${body}`); + const userAuthenticationRequestResponse: Response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: body, + agent: new https.Agent({ rejectUnauthorized: REJECT_UNAUTHORIZED }), + }); + userAuthenticationRequestResponseCode = userAuthenticationRequestResponse.status; + switch (userAuthenticationRequestResponseCode) { + case HttpStatusCode.BAD_REQUEST: { + await this.onUserAuthenticationBadRequest(userAuthenticationRequestResponse); + break; + } + + case HttpStatusCode.OK: { + await this.onUserAuthenticationSuccess(userAuthenticationRequestResponse); + break; + } + + default: { + err(`Unhandled HTTP status: ${userAuthenticationRequestResponseCode}`); + throw new Error(`Unhandled HTTP status: ${userAuthenticationRequestResponseCode}`); + } + } + } + } + + private async onUserAuthenticationBadRequest(userAuthenticationRequestResponse: Response) { + const badRequestResponse = (await userAuthenticationRequestResponse.json()) as FailedAuthenticationResponse; + const errorCode = TokenFetchErrorCode[badRequestResponse.error!]; + switch (errorCode) { + case TokenFetchErrorCode.invalid_client: + case TokenFetchErrorCode.invalid_grant: + case TokenFetchErrorCode.unsupported_grant_type: { + err(`${badRequestResponse.error!}: ${badRequestResponse.error_description}`); + throw new Error('createUserAuthentication: ' + errorCode); + } + case TokenFetchErrorCode.authorization_pending: { + await sleep(this.waitDuration.getCurrentDuration()); + break; + } + case TokenFetchErrorCode.slow_down: { + this.waitDuration.increase(); + await sleep(this.waitDuration.getCurrentDuration()); + break; + } + default: { + err(`${badRequestResponse.error!}: ${badRequestResponse.error_description}`); + throw new Error( + `Unhandled error code [ ${badRequestResponse.error!}: ${badRequestResponse.error_description} ]`, + ); + } + } + } + + private async onUserAuthenticationSuccess(userAuthenticationRequestResponse: Response) { + const successRequestResponse = (await userAuthenticationRequestResponse.json()) as SuccessfulAuthenticationResponse; + this.accessToken = successRequestResponse.access_token ?? ''; + this.refreshToken = successRequestResponse.refresh_token ?? ''; + } +} + +/** + * KEEP the SAME case \ + * to respect keycloak API return + */ +interface DeviceAuthorizationRequestResponse { + device_code?: string; + user_code?: string; + verification_uri?: string; + verification_uri_complete?: string; + expires_in?: number; + interval?: number; +} + +/** + * KEEP the SAME case \ + * to respect keycloak API return + */ +interface SuccessfulAuthenticationResponse { + access_token?: string; + expires_in?: number; + 'not-before-policy'?: number; + refresh_expires_in: number; + refresh_token?: string; + scope?: string; + session_state?: string; + token_type?: 'Bearer' | string; +} + +interface FailedAuthenticationResponse { + error?: string; + error_description?: string; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +class WaitDuration { + private durations: Uint16Array; + private index: number; + constructor(durations: number[]) { + this.durations = new Uint16Array(durations); + this.durations.sort(); + this.index = 0; + } + public getCurrentDuration(): number { + if (this.index >= this.durations.length - 1) { + throw new Error(`Index out of bounds. Current index: ${this.index} | Max val: ${this.durations.length - 1}`); + } + return this.durations[this.index]; + } + public increase(): void { + if (this.index < this.durations.length - 1) { + this.index += 1; + } + } +} diff --git a/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts b/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts index 22d50dda5700a4075c72853b8eaa9cc8740c037a..a598545b60abeb4628fb4f5e15949b5dcd391b18 100644 --- a/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts +++ b/deadlock-plugins/deadlock-extension/src/core/metadataProvider.ts @@ -5,65 +5,64 @@ import { error as err, log } from '../recorder/utils'; import { BASHRC_PATH, ENV_FILE_PATH } from './config'; export default class MetadataProvider { + public static loadPathsToJson(filePath: string) { + const portToPath = userConfig.getPaths(); + const serviceNameToPath = this.getServicePathFromPortPath(portToPath); + const jsonValue = Object.fromEntries(serviceNameToPath); + const fileContent = JSON.stringify(jsonValue, null, 4) + '\n'; + fs.writeFileSync(filePath, fileContent, { flag: 'w+' }); + } - public static loadPathsToJson(filePath: string) { - const portToPath = userConfig.getPaths(); - const serviceNameToPath = this.getServicePathFromPortPath(portToPath); - const jsonValue = Object.fromEntries(serviceNameToPath); - const fileContent = JSON.stringify(jsonValue, null, 4) + '\n'; - fs.writeFileSync(filePath, fileContent, { flag: 'w+'}); + public static loadPathsToEnvVariables(): void { + const portToPath = userConfig.getPaths(); + const serviceNameToPath = this.getServicePathFromPortPath(portToPath); + let fileContent = ''; + for (const [serviceName, servicePath] of serviceNameToPath.entries()) { + fileContent += `${serviceName}=${servicePath} \n`; } - - public static loadPathsToEnvVariables(): void { - const portToPath = userConfig.getPaths(); - const serviceNameToPath = this.getServicePathFromPortPath(portToPath); - let fileContent = ''; - for (const [serviceName, servicePath] of serviceNameToPath.entries()) { - fileContent += `${serviceName}=${servicePath} \n`; - } - fs.writeFileSync(ENV_FILE_PATH, fileContent, { flag: 'w+'}); - const bashrcAppendContent = ` + fs.writeFileSync(ENV_FILE_PATH, fileContent, { flag: 'w+' }); + const bashrcAppendContent = ` export $(cat ${ENV_FILE_PATH} | xargs -L 1) `; - fs.writeFileSync(BASHRC_PATH, bashrcAppendContent, { flag: 'a+'}); - exec(`. ${BASHRC_PATH}`, execCallback); - } + fs.writeFileSync(BASHRC_PATH, bashrcAppendContent, { flag: 'a+' }); + exec(`. ${BASHRC_PATH}`, execCallback); + } - /** - * two formats to handle: (key="front", value="3001") | (key="8080": value="HXW3fnKwUULrfKS1-cdb")\ - * expected result: (key="front", value="localhost:3001") | (key="cdb", value="HXW3fnKwUULrfKS1-cdb") - * - */ - private static getServicePathFromPortPath(portToPath: Map<number, string>): Map<string, string> { - const serviceToPath = new Map<string, string>(); - for (const [port, path] of Object.entries(portToPath)) { - - let key = ''; - let value = ''; - if (isNumeric(port)) { - key = path.split('-').slice(-1); - value = `${path}.${userConfig.getHost()}`; - } else { - key = port; - value = `localhost:${path}`; - } - serviceToPath.set(key, value); - } - return serviceToPath; + /** + * two formats to handle: (key="front", value="3001") | (key="8080": value="HXW3fnKwUULrfKS1-cdb")\ + * expected result: (key="front", value="localhost:3001") | (key="cdb", value="HXW3fnKwUULrfKS1-cdb") + * + */ + private static getServicePathFromPortPath(portToPath: Map<number, string>): Map<string, string> { + const serviceToPath = new Map<string, string>(); + for (const [port, path] of Object.entries(portToPath)) { + let key = ''; + let value = ''; + if (isNumeric(port)) { + key = path.split('-').slice(-1); + value = `${path}.${userConfig.getHost()}`; + } else { + key = port; + value = `localhost:${path}`; + } + serviceToPath.set(key, value); } - + return serviceToPath; + } } -function isNumeric(val: string) { return /^\d+$/.test(val); } +function isNumeric(val: string) { + return /^\d+$/.test(val); +} function execCallback(error: ExecException | null, stdout: string, stderr: string) { - if (error) { - err(`error: ${error.message}`); - return; - } - if (stderr) { - err(`stderr: ${stderr}`); - return; - } - log(stdout); + if (error) { + err(`error: ${error.message}`); + return; + } + if (stderr) { + err(`stderr: ${stderr}`); + return; + } + log(stdout); } diff --git a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts b/deadlock-plugins/deadlock-extension/src/core/userConfig.ts index 21f1d3eac3c171ec402a976e662d530222fd8c59..46295519cf5a44668fabe677467787ecbfd7276e 100644 --- a/deadlock-plugins/deadlock-extension/src/core/userConfig.ts +++ b/deadlock-plugins/deadlock-extension/src/core/userConfig.ts @@ -1,4 +1,3 @@ - /** * Example: * { @@ -19,75 +18,75 @@ import { error } from '../recorder/utils'; export interface UserDetails { - firstName: string; - lastName: string; - avatarUrl: string; - email: string; + firstName: string; + lastName: string; + avatarUrl: string; + email: string; } export default abstract class UserConfig { - private userConfigJson: any | undefined; + private userConfigJson: any | undefined; - getPaths(): Map<number, string> { - return this.userConfigJson?.paths; - } + getPaths(): Map<number, string> { + return this.userConfigJson?.paths; + } - getHost(): string { - return this.userConfigJson?.host; - } + getHost(): string { + return this.userConfigJson?.host; + } - getToken(): string { - return this.userConfigJson?.token; - } + getToken(): string { + return this.userConfigJson?.token; + } - getGiteaHost(): string { - return this.userConfigJson?.giteaHost; - } + getGiteaHost(): string { + return this.userConfigJson?.giteaHost; + } - getGiteaSshPort(): number { - return this.userConfigJson?.giteaSshPort; - } + getGiteaSshPort(): number { + return this.userConfigJson?.giteaSshPort; + } - getUsername(): string { - return this.userConfigJson?.username; - } + getUsername(): string { + return this.userConfigJson?.username; + } - getRemoteGitUsername(): string { - return this.userConfigJson?.remoteGitUsername; - } + getRemoteGitUsername(): string { + return this.userConfigJson?.remoteGitUsername; + } - getMissionId(): string { - return this.userConfigJson?.missionId; - } + getMissionId(): string { + return this.userConfigJson?.missionId; + } - getEmail(): string { - return this.userConfigJson?.email; - } + getEmail(): string { + return this.userConfigJson?.email; + } - isProfessor(): boolean { - return this.userConfigJson?.professor; - } + isProfessor(): boolean { + return this.userConfigJson?.professor; + } - getCurrentUserDetails(): UserDetails { - return this.userConfigJson?.currentUserDetails; - } + getCurrentUserDetails(): UserDetails { + return this.userConfigJson?.currentUserDetails; + } - getRemoteUserDetails(): UserDetails { - return this.userConfigJson?.remoteUserDetails; - } + getRemoteUserDetails(): UserDetails { + return this.userConfigJson?.remoteUserDetails; + } - abstract loadText(): Promise<string>; + abstract loadText(): Promise<string>; - public async init() { - try { - const userConfig = await this.loadText(); + public async init() { + try { + const userConfig = await this.loadText(); - this.userConfigJson = JSON.parse(userConfig); - return Promise.resolve(); - } catch (e) { - error('Cannot load userConfig'); - error(e); - return Promise.reject(); - } + this.userConfigJson = JSON.parse(userConfig); + return Promise.resolve(); + } catch (e) { + error('Cannot load userConfig'); + error(e); + return Promise.reject(); } -} \ No newline at end of file + } +} diff --git a/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts b/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5bb61ccb9a971188808ff21d9693ae63679e851 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/customTypings/HttpStatusCode.ts @@ -0,0 +1,379 @@ +/** + * {@link https://gist.github.com/scokmen/f813c904ef79022e84ab2409574d1b45 Source code link}\ + * Hypertext Transfer Protocol (HTTP) response status codes. + * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes} + */ +export enum HttpStatusCode { + /** + * The server has received the request headers and the client should proceed to send the request body + * (in the case of a request for which a body needs to be sent; for example, a POST request). + * Sending a large request body to a server after a request has been rejected for inappropriate headers would be inefficient. + * To have a server check the request's headers, a client must send Expect: 100-continue as a header in its initial request + * and receive a 100 Continue status code in response before sending the body. The response 417 Expectation Failed indicates the request should not be continued. + */ + CONTINUE = 100, + + /** + * The requester has asked the server to switch protocols and the server has agreed to do so. + */ + SWITCHING_PROTOCOLS = 101, + + /** + * A WebDAV request may contain many sub-requests involving file operations, requiring a long time to complete the request. + * This code indicates that the server has received and is processing the request, but no response is available yet. + * This prevents the client from timing out and assuming the request was lost. + */ + PROCESSING = 102, + + /** + * Standard response for successful HTTP requests. + * The actual response will depend on the request method used. + * In a GET request, the response will contain an entity corresponding to the requested resource. + * In a POST request, the response will contain an entity describing or containing the result of the action. + */ + OK = 200, + + /** + * The request has been fulfilled, resulting in the creation of a new resource. + */ + CREATED = 201, + + /** + * The request has been accepted for processing, but the processing has not been completed. + * The request might or might not be eventually acted upon, and may be disallowed when processing occurs. + */ + ACCEPTED = 202, + + /** + * SINCE HTTP/1.1 + * The server is a transforming proxy that received a 200 OK from its origin, + * but is returning a modified version of the origin's response. + */ + NON_AUTHORITATIVE_INFORMATION = 203, + + /** + * The server successfully processed the request and is not returning any content. + */ + NO_CONTENT = 204, + + /** + * The server successfully processed the request, but is not returning any content. + * Unlike a 204 response, this response requires that the requester reset the document view. + */ + RESET_CONTENT = 205, + + /** + * The server is delivering only part of the resource (byte serving) due to a range header sent by the client. + * The range header is used by HTTP clients to enable resuming of interrupted downloads, + * or split a download into multiple simultaneous streams. + */ + PARTIAL_CONTENT = 206, + + /** + * The message body that follows is an XML message and can contain a number of separate response codes, + * depending on how many sub-requests were made. + */ + MULTI_STATUS = 207, + + /** + * The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response, + * and are not being included again. + */ + ALREADY_REPORTED = 208, + + /** + * The server has fulfilled a request for the resource, + * and the response is a representation of the result of one or more instance-manipulations applied to the current instance. + */ + IM_USED = 226, + + /** + * Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation). + * For example, this code could be used to present multiple video format options, + * to list files with different filename extensions, or to suggest word-sense disambiguation. + */ + MULTIPLE_CHOICES = 300, + + /** + * This and all future requests should be directed to the given URI. + */ + MOVED_PERMANENTLY = 301, + + /** + * This is an example of industry practice contradicting the standard. + * The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect + * (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302 + * with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 + * to distinguish between the two behaviours. However, some Web applications and frameworks + * use the 302 status code as if it were the 303. + */ + FOUND = 302, + + /** + * SINCE HTTP/1.1 + * The response to the request can be found under another URI using a GET method. + * When received in response to a POST (or PUT/DELETE), the client should presume that + * the server has received the data and should issue a redirect with a separate GET message. + */ + SEE_OTHER = 303, + + /** + * Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match. + * In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy. + */ + NOT_MODIFIED = 304, + + /** + * SINCE HTTP/1.1 + * The requested resource is available only through a proxy, the address for which is provided in the response. + * Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons. + */ + USE_PROXY = 305, + + /** + * No longer used. Originally meant "Subsequent requests should use the specified proxy." + */ + SWITCH_PROXY = 306, + + /** + * SINCE HTTP/1.1 + * In this case, the request should be repeated with another URI; however, future requests should still use the original URI. + * In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. + * For example, a POST request should be repeated using another POST request. + */ + TEMPORARY_REDIRECT = 307, + + /** + * The request and all future requests should be repeated using another URI. + * 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. + * So, for example, submitting a form to a permanently redirected resource may continue smoothly. + */ + PERMANENT_REDIRECT = 308, + + /** + * The server cannot or will not process the request due to an apparent client error + * (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing). + */ + BAD_REQUEST = 400, + + /** + * Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet + * been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the + * requested resource. See Basic access authentication and Digest access authentication. 401 semantically means + * "unauthenticated",i.e. the user does not have the necessary credentials. + */ + UNAUTHORIZED = 401, + + /** + * Reserved for future use. The original intention was that this code might be used as part of some form of digital + * cash or micro payment scheme, but that has not happened, and this code is not usually used. + * Google Developers API uses this status if a particular developer has exceeded the daily limit on requests. + */ + PAYMENT_REQUIRED = 402, + + /** + * The request was valid, but the server is refusing action. + * The user might not have the necessary permissions for a resource. + */ + FORBIDDEN = 403, + + /** + * The requested resource could not be found but may be available in the future. + * Subsequent requests by the client are permissible. + */ + NOT_FOUND = 404, + + /** + * A request method is not supported for the requested resource; + * for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource. + */ + METHOD_NOT_ALLOWED = 405, + + /** + * The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request. + */ + NOT_ACCEPTABLE = 406, + + /** + * The client must first authenticate itself with the proxy. + */ + PROXY_AUTHENTICATION_REQUIRED = 407, + + /** + * The server timed out waiting for the request. + * According to HTTP specifications: + * "The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time." + */ + REQUEST_TIMEOUT = 408, + + /** + * Indicates that the request could not be processed because of conflict in the request, + * such as an edit conflict between multiple simultaneous updates. + */ + CONFLICT = 409, + + /** + * Indicates that the resource requested is no longer available and will not be available again. + * This should be used when a resource has been intentionally removed and the resource should be purged. + * Upon receiving a 410 status code, the client should not request the resource in the future. + * Clients such as search engines should remove the resource from their indices. + * Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead. + */ + GONE = 410, + + /** + * The request did not specify the length of its content, which is required by the requested resource. + */ + LENGTH_REQUIRED = 411, + + /** + * The server does not meet one of the preconditions that the requester put on the request. + */ + PRECONDITION_FAILED = 412, + + /** + * The request is larger than the server is willing or able to process. Previously called "Request Entity Too Large". + */ + PAYLOAD_TOO_LARGE = 413, + + /** + * The URI provided was too long for the server to process. Often the result of too much data being encoded as a query-string of a GET request, + * in which case it should be converted to a POST request. + * Called "Request-URI Too Long" previously. + */ + URI_TOO_LONG = 414, + + /** + * The request entity has a media type which the server or resource does not support. + * For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format. + */ + UNSUPPORTED_MEDIA_TYPE = 415, + + /** + * The client has asked for a portion of the file (byte serving), but the server cannot supply that portion. + * For example, if the client asked for a part of the file that lies beyond the end of the file. + * Called "Requested Range Not Satisfiable" previously. + */ + RANGE_NOT_SATISFIABLE = 416, + + /** + * The server cannot meet the requirements of the Expect request-header field. + */ + EXPECTATION_FAILED = 417, + + /** + * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol, + * and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by + * teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including Google.com. + */ + I_AM_A_TEAPOT = 418, + + /** + * The request was directed at a server that is not able to produce a response (for example because a connection reuse). + */ + MISDIRECTED_REQUEST = 421, + + /** + * The request was well-formed but was unable to be followed due to semantic errors. + */ + UNPROCESSABLE_ENTITY = 422, + + /** + * The resource that is being accessed is locked. + */ + LOCKED = 423, + + /** + * The request failed due to failure of a previous request (e.g., a PROPPATCH). + */ + FAILED_DEPENDENCY = 424, + + /** + * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field. + */ + UPGRADE_REQUIRED = 426, + + /** + * The origin server requires the request to be conditional. + * Intended to prevent "the 'lost update' problem, where a client + * GETs a resource's state, modifies it, and PUTs it back to the server, + * when meanwhile a third party has modified the state on the server, leading to a conflict." + */ + PRECONDITION_REQUIRED = 428, + + /** + * The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes. + */ + TOO_MANY_REQUESTS = 429, + + /** + * The server is unwilling to process the request because either an individual header field, + * or all the header fields collectively, are too large. + */ + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + + /** + * A server operator has received a legal demand to deny access to a resource or to a set of resources + * that includes the requested resource. The code 451 was chosen as a reference to the novel Fahrenheit 451. + */ + UNAVAILABLE_FOR_LEGAL_REASONS = 451, + + /** + * A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. + */ + INTERNAL_SERVER_ERROR = 500, + + /** + * The server either does not recognize the request method, or it lacks the ability to fulfill the request. + * Usually this implies future availability (e.g., a new feature of a web-service API). + */ + NOT_IMPLEMENTED = 501, + + /** + * The server was acting as a gateway or proxy and received an invalid response from the upstream server. + */ + BAD_GATEWAY = 502, + + /** + * The server is currently unavailable (because it is overloaded or down for maintenance). + * Generally, this is a temporary state. + */ + SERVICE_UNAVAILABLE = 503, + + /** + * The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. + */ + GATEWAY_TIMEOUT = 504, + + /** + * The server does not support the HTTP protocol version used in the request + */ + HTTP_VERSION_NOT_SUPPORTED = 505, + + /** + * Transparent content negotiation for the request results in a circular reference. + */ + VARIANT_ALSO_NEGOTIATES = 506, + + /** + * The server is unable to store the representation needed to complete the request. + */ + INSUFFICIENT_STORAGE = 507, + + /** + * The server detected an infinite loop while processing the request. + */ + LOOP_DETECTED = 508, + + /** + * Further extensions to the request are required for the server to fulfill it. + */ + NOT_EXTENDED = 510, + + /** + * The client needs to authenticate to gain network access. + * Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used + * to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot). + */ + NETWORK_AUTHENTICATION_REQUIRED = 511, +} diff --git a/deadlock-plugins/deadlock-extension/src/customTypings/KeycloakAPITypes.ts b/deadlock-plugins/deadlock-extension/src/customTypings/KeycloakAPITypes.ts new file mode 100644 index 0000000000000000000000000000000000000000..d33bc3989e1792c3a7a6a3dc5b0eea3d68cd87b1 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/customTypings/KeycloakAPITypes.ts @@ -0,0 +1,13 @@ +// +/** + * KEEP the SAME case \ + * `TokenFetchErrorCode['slow_down'] === TokenFetchErrorCode.slow_down; // === true` \ + * `TokenFetchErrorCode['slow_down'] === TokenFetchErrorCode.SLOW_DOWN; // === false` + */ +export enum TokenFetchErrorCode { + authorization_pending = 'authorization_pending', + invalid_grant = 'invalid_grant', + unsupported_grant_type = 'unsupported_grant_type', + invalid_client = 'invalid_client', + slow_down = 'slow_down', +} diff --git a/deadlock-plugins/deadlock-extension/src/extension.ts b/deadlock-plugins/deadlock-extension/src/extension.ts index aa7bc8dc7214bd709f53c830a23678059995602d..506ad15ae186c4a443ddda1651c5a02ff2cb1bce 100644 --- a/deadlock-plugins/deadlock-extension/src/extension.ts +++ b/deadlock-plugins/deadlock-extension/src/extension.ts @@ -1,38 +1,29 @@ import * as vscode from 'vscode'; import { SERVICES_PATHS_PATH } from './core/config'; +import Controller from './core/controller'; import MetadataProvider from './core/metadataProvider'; import { error } from './recorder/utils'; -import { OPEN_BRIEFING_COMMAND } from './theia/command'; import { DepNodeProvider } from './theia/deadlockPanel'; import UserConfigTheia from './theia/userConfigTheia'; -import BriefingView from './view/briefingView'; - -export function initViews() { - new BriefingView(); -} export const userConfig = new UserConfigTheia(); export async function activate(context: vscode.ExtensionContext) { vscode.window.showInformationMessage('Bienvenue sur Deadlock!'); + const controller = new Controller(context); + + const workspaceFolders = vscode.workspace.workspaceFolders?.toString() ?? ''; + if (!workspaceFolders) vscode.window.showInformationMessage('Pas de répertoires ouverts'); + const deadlockPanelProvider = new DepNodeProvider(workspaceFolders); + vscode.window.registerTreeDataProvider('deadlockPanel', deadlockPanelProvider); + try { await userConfig.init(); } catch (e) { error('Cannot init userConfig'); } - initViews(); - - await vscode.commands.executeCommand(OPEN_BRIEFING_COMMAND.cmd); - - // @ts-ignore - const deadlockPanelProvider = new DepNodeProvider(vscode.workspace.rootPath); - vscode.window.registerTreeDataProvider( - 'deadlockPanel', - deadlockPanelProvider - ); - MetadataProvider.loadPathsToEnvVariables(); MetadataProvider.loadPathsToJson(`${SERVICES_PATHS_PATH}`); } diff --git a/deadlock-plugins/deadlock-extension/src/recorder/README.md b/deadlock-plugins/deadlock-extension/src/recorder/README.md index acb5a763e59ad8b9c7b30752f4bdf3ab95ac3c27..0b5bd9b0e9b22c9486284b70f2398406bbd2a03e 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/README.md +++ b/deadlock-plugins/deadlock-extension/src/recorder/README.md @@ -2,4 +2,4 @@ ``` ts-node recorder.ts -``` \ No newline at end of file +``` diff --git a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts index ca941693d5f0ec9953d36082d96fda2fb3641beb..17865f4da95b95c0572a67cbb59456bb0fb82657 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts @@ -33,9 +33,7 @@ export default class CommandRecorder { if (!this.commandsInProgress.has(pid)) { this.commandsInProgress.set(pid, new Command(pid, command)); try { - this.queue.push( - async () => await commitAndPushCode(this.gitMission, CommitFrom.Run) - ); + this.queue.push(async () => await commitAndPushCode(this.gitMission, CommitFrom.Run)); } catch (e) { console.error('Cannot send user code to git'); console.error(e); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/index.ts b/deadlock-plugins/deadlock-extension/src/recorder/index.ts index 9a4b4f0b698f84b48d8fab62249474d77747e4bd..51f4a3a41cd3a2804c1ac81a2e2b5f5c15efbb72 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/index.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/index.ts @@ -5,64 +5,62 @@ import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config'; import { copyProjectSources, clearFilesExceptGit, log, error, renameTempToUserGitFiles } from './utils'; import UserConfig from '../core/userConfig'; - export default class Recorder { + async setupProject(userConfig: UserConfig, gitMission?: GitMission) { + log('Setup user project..'); - async setupProject(userConfig: UserConfig, gitMission?: GitMission) { - log('Setup user project..'); + if (!userConfig.isProfessor()) { + await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH, ['.git/']); - if (!userConfig.isProfessor()) { - await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH, ['.git/']); - - if (gitMission) { - renameTempToUserGitFiles(PROJECT_THEIA_PATH, gitMission.author); + if (gitMission) { + renameTempToUserGitFiles(PROJECT_THEIA_PATH, gitMission.author); - log('Starting CommandRecorder..'); - new CommandRecorder(gitMission).run(); - } else { - error('Cannot start command recorder, gitMission not found'); - } - } else { - await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH); - } + log('Starting CommandRecorder..'); + new CommandRecorder(gitMission).run(); + } else { + error('Cannot start command recorder, gitMission not found'); + } + } else { + await copyProjectSources(PROJECT_SRC_PATH, PROJECT_THEIA_PATH); } + } - async setupFromRemoteRepo(gitMission: GitMission) { - log('Check if remote repo exist'); - const isRemoteRepoExist = await gitMission.isRemoteRepoExist(); - if (isRemoteRepoExist) { - // rm all except git directory pull remote code and setup - log('Cleaning files to pull repo'); + async setupFromRemoteRepo(gitMission: GitMission) { + log('Check if remote repo exist'); + const isRemoteRepoExist = await gitMission.isRemoteRepoExist(); + if (isRemoteRepoExist) { + // rm all except git directory pull remote code and setup + log('Cleaning files to pull repo'); - await clearFilesExceptGit(PROJECT_SRC_PATH); + await clearFilesExceptGit(PROJECT_SRC_PATH); - log('Pulling user repo'); - await gitMission.pull(); - } + log('Pulling user repo'); + await gitMission.pull(); } + } - async run() { - const userConfig = new UserConfigNode(); + async run() { + const userConfig = new UserConfigNode(); - let gitMission; + let gitMission; - try { - log('Init User config'); - await userConfig.init(); - log('Init GitMission'); - gitMission = await new GitMission(userConfig).init(); - await this.setupFromRemoteRepo(gitMission); - } catch (e) { - error('Cannot setup user repo.'); - error(e); - } - try { - await this.setupProject(userConfig, gitMission); - } catch (e) { - error('Error while setup project sources'); - error(e); - } + try { + log('Init User config'); + await userConfig.init(); + log('Init GitMission'); + gitMission = await new GitMission(userConfig).init(); + await this.setupFromRemoteRepo(gitMission); + } catch (e) { + error('Cannot setup user repo.'); + error(e); + } + try { + await this.setupProject(userConfig, gitMission); + } catch (e) { + error('Error while setup project sources'); + error(e); } + } } -new Recorder().run(); \ No newline at end of file +new Recorder().run(); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts b/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts index 98b321368ba4311d3caebcb4789c1e21dfe0b555..e3154055e67b1b1a0d13521cc58a7c7891aac31e 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts @@ -1,10 +1,10 @@ import UserConfigNode from './userConfigNode'; -import GitMission from '../core/gitMission' -import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config' +import GitMission from '../core/gitMission'; +import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config'; -import { log, error, commitAndPushCode, CommitFrom } from "./utils"; -const util = require("util"); -const exec = util.promisify(require("child_process").exec); +import { log, error, commitAndPushCode, CommitFrom } from './utils'; +const util = require('util'); +const exec = util.promisify(require('child_process').exec); async function containsDiff() { try { @@ -16,10 +16,7 @@ async function containsDiff() { // when status code is > 0 if (result.code === 1) { const stdout = result.stdout; - if ( - stdout.indexOf("Files ") !== -1 || - stdout.indexOf("Only in /home/project/") !== -1 - ) { + if (stdout.indexOf('Files ') !== -1 || stdout.indexOf('Only in /home/project/') !== -1) { // if user created new file or added a directory return true; } @@ -33,20 +30,20 @@ async function containsDiff() { (async () => { try { - log("Container will die"); + log('Container will die'); const userConfig = new UserConfigNode(); await userConfig.init(); if (!userConfig.isProfessor()) { - log("Save user code.."); + log('Save user code..'); const gitMission = await new GitMission(userConfig).init(); if (await containsDiff()) { await commitAndPushCode(gitMission, CommitFrom.Auto); } } } catch (e) { - error("Cannot push user code at the end.."); + error('Cannot push user code at the end..'); error(e); } })(); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts b/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts index ce449c84d90c606a7c1551cfe2eb3e891788cc62..3b977cae4be6285c3233aa2ee74e814dd3f20c9f 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/userConfigNode.ts @@ -2,13 +2,11 @@ import UserConfig from '../core/userConfig'; import { USER_CHALLENGE_PATH } from '../core/config'; const fs = require('fs'); - export default class UserConfigNode extends UserConfig { - async loadText(): Promise<string> { - const text = fs.readFileSync(USER_CHALLENGE_PATH, 'utf8'); + async loadText(): Promise<string> { + const text = fs.readFileSync(USER_CHALLENGE_PATH, 'utf8'); - return Promise.resolve(text); - } - -} \ No newline at end of file + return Promise.resolve(text); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts index 74331fbc5a781394c296e116e28a58efa7ad56a1..cc271f3f93a3efba58d1b43ba020581c0f1f417e 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts @@ -1,7 +1,7 @@ import GitMission from '../core/gitMission'; import { PROJECT_SRC_PATH, PROJECT_THEIA_PATH } from '../core/config'; import { format } from 'date-fns'; -import { execSync } from "child_process"; +import { execSync } from 'child_process'; import { existsSync, renameSync, copyFileSync, PathLike } from 'fs'; const util = require('util'); @@ -13,136 +13,119 @@ const Path = require('path'); const PREFIX = '[DEADLOCK-RECORDER]'; -export const log = (message: any, args?: any[]) => { - if (args) { - console.log(`${PREFIX} ${message}`, args); - } else { - console.log(`${PREFIX} ${message}`); - } +export const log = (message: any, ...args: any[]) => { + if (args) { + console.log(`${PREFIX} ${message}`, ...args); + } else { + console.log(`${PREFIX} ${message}`); + } }; -export const error = (message: any, args?: any[]) => { - if (args) { - console.error(`${PREFIX} ${message}`, args); - } else { - console.error(`${PREFIX} ${message}`); - } +export const error = (message: any, ...args: any[]) => { + if (args) { + console.error(`${PREFIX} ${message}`, ...args); + } else { + console.error(`${PREFIX} ${message}`); + } }; -export async function copyProjectSources( - srcPath: string, - theiaPath: string, - excludes: Array<string> = []) -{ - const excludeCmd = excludes.map((current) => `--exclude ${current}`).join(' '); - return exec(`rsync -a ${srcPath}/ ${theiaPath} ${excludeCmd} && chown -R theia:theia /home/project`); +export async function copyProjectSources(srcPath: string, theiaPath: string, excludes: Array<string> = []) { + const excludeCmd = excludes.map((current) => `--exclude ${current}`).join(' '); + return exec(`rsync -a ${srcPath}/ ${theiaPath} ${excludeCmd} && chown -R theia:theia /home/project`); } export async function pathContainsFiles(path: string) { - return exec(`ls -1 ${path} | wc -l`); + return exec(`ls -1 ${path} | wc -l`); } export async function clearFilesExceptGit(path) { - readdirSync(path).forEach(async (file) => { - if (file !== '.git') { - const curPath = Path.join(path, file); - if (fs.lstatSync(curPath).isDirectory()) { - fs.rmdirSync(curPath, { recursive: true }); - } else { - await unlink(curPath); - } - } - }); + readdirSync(path).forEach(async (file) => { + if (file !== '.git') { + const curPath = Path.join(path, file); + if (fs.lstatSync(curPath).isDirectory()) { + fs.rmdirSync(curPath, { recursive: true }); + } else { + await unlink(curPath); + } + } + }); } function renameIfExistsSync(srcPath: PathLike, destPath: PathLike) { - - if (existsSync(srcPath)) { - renameSync(srcPath, destPath); - } else { - log(`Renaming : No ${srcPath} found`); - } + if (existsSync(srcPath)) { + renameSync(srcPath, destPath); + } else { + log(`Renaming : No ${srcPath} found`); + } } function copyFileIfExistsSync(srcPath: PathLike, destPath: PathLike) { - - if (existsSync(srcPath)) { - copyFileSync(srcPath, destPath); - } else { - log(`Copying file: No ${srcPath} found`); - } + if (existsSync(srcPath)) { + copyFileSync(srcPath, destPath); + } else { + log(`Copying file: No ${srcPath} found`); + } } function copyFolderIfExistsSync(srcPath: PathLike, destPath: PathLike) { - - if (existsSync(srcPath)) { - execSync(`rsync -r ${srcPath}/* ${destPath}`); - } else { - log(`Copying folder: No ${srcPath} found`); - } + if (existsSync(srcPath)) { + execSync(`rsync -r ${srcPath}/* ${destPath}`); + } else { + log(`Copying folder: No ${srcPath} found`); + } } - /** - * + * * Rename temporary git files back to actual git files. - * + * * @param path Path of the folder containing user's temporary git project files. * @param userId Identifier used to create the temporary files name */ export function renameTempToUserGitFiles(path: string, userId: string) { - - renameIfExistsSync( - Path.join(path,`user-git-${userId}`), - Path.join(path,'.git') - ); - renameIfExistsSync( - Path.join(path, `user-gitignore-${userId}`), - Path.join(path, '.gitignore') - ); + renameIfExistsSync(Path.join(path, `user-git-${userId}`), Path.join(path, '.git')); + renameIfExistsSync(Path.join(path, `user-gitignore-${userId}`), Path.join(path, '.gitignore')); } /** - * + * * Copy user's git project files and paste them with renamed filenames so that * they can be saved by the recorder. - * + * * @param srcPath Path of the folder containing user's git project files to be saved. * @param destPath Path where the user's git project files should be pasted. * @param userId Identifier used to create the temporary files name */ function copyGitUserFiles(srcPath: string, destPath: string, userId: string) { - - copyFolderIfExistsSync( - Path.join(srcPath,'.git'), - Path.join(destPath,`user-git-${userId}`) - ); - copyFileIfExistsSync( - Path.join(srcPath, '.gitignore'), - Path.join(destPath, `user-gitignore-${userId}`) - ); + copyFolderIfExistsSync(Path.join(srcPath, '.git'), Path.join(destPath, `user-git-${userId}`)); + copyFileIfExistsSync(Path.join(srcPath, '.gitignore'), Path.join(destPath, `user-gitignore-${userId}`)); } export enum CommitFrom { - Run = 'Run', - Auto = 'Auto' + Run = 'Run', + Auto = 'Auto', } export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom) { - try { - log('Commit & push'); - await clearFilesExceptGit(PROJECT_SRC_PATH); - - copyGitUserFiles(PROJECT_THEIA_PATH, PROJECT_SRC_PATH, gitMission.author); - execSync(`rsync -r --exclude .git --exclude npm --exclude target ${PROJECT_THEIA_PATH}/* ${PROJECT_SRC_PATH} && cp ${Path.join(__dirname, '.gitignore')} ${PROJECT_SRC_PATH} && chown -R root:root /project`); - - const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); - await gitMission.addAll(); - await gitMission.commit(currentDate); - await gitMission.push(); - log('Commit & push done.'); - } catch (e) { - error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`); - error(e.message); - } + try { + log('Commit & push'); + await clearFilesExceptGit(PROJECT_SRC_PATH); + + copyGitUserFiles(PROJECT_THEIA_PATH, PROJECT_SRC_PATH, gitMission.author); + execSync( + `rsync -r --exclude .git --exclude npm --exclude target ${PROJECT_THEIA_PATH}/* ${PROJECT_SRC_PATH} && cp ${Path.join( + __dirname, + '.gitignore', + )} ${PROJECT_SRC_PATH} && chown -R root:root /project`, + ); + + const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); + await gitMission.addAll(); + await gitMission.commit(currentDate); + await gitMission.push(); + log('Commit & push done.'); + } catch (e) { + error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`); + error(e.message); + } } diff --git a/deadlock-plugins/deadlock-extension/src/theia/command.ts b/deadlock-plugins/deadlock-extension/src/theia/command.ts index 72ec485011d6183ba5f8a86ea1d01c2bd242c603..53638bd941e7cc69623287b76f5670be8e78cb2c 100644 --- a/deadlock-plugins/deadlock-extension/src/theia/command.ts +++ b/deadlock-plugins/deadlock-extension/src/theia/command.ts @@ -1,21 +1,19 @@ - import { Command as VscodeComand } from 'vscode'; export class Command { - constructor(private _title: string, private _command: string) { - } - - get title() { - return this._title; - } + constructor(private _title: string, private command: string) {} - get cmd() { - return this._command; - } + get title() { + return this._title; + } - asVsCodeCommand(): VscodeComand { - return { title: this.title, command: this.cmd } + get cmd() { + return this.command; + } - } + asVsCodeCommand(): VscodeComand { + return { title: this.title, command: this.cmd }; + } } -export const OPEN_BRIEFING_COMMAND = new Command('Open Briefing', 'deadlock.openBriefing'); \ No newline at end of file +export const OPEN_BRIEFING_COMMAND = new Command('Open Briefing', 'deadlock.openBriefing'); +export const OPEN_QUICK_SETUP_COMMAND = new Command('Open Deadlock quick setup page', 'deadlock.openQuickSetup'); diff --git a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts b/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts index d4a5f752125a191492db1ed4d86d7dc62fbc920c..bf68f8424c822157b6e3d543d1afc09ec5702dcb 100644 --- a/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts +++ b/deadlock-plugins/deadlock-extension/src/theia/deadlockPanel.ts @@ -1,75 +1,66 @@ -import * as vscode from 'vscode'; import * as path from 'path'; +import * as vscode from 'vscode'; import { TreeItemCollapsibleState } from 'vscode'; import { OPEN_BRIEFING_COMMAND } from './command'; const DOCUMENTATION_LABEL = 'Documentation'; export class DepNodeProvider implements vscode.TreeDataProvider<Action> { - - private _onDidChangeTreeData: vscode.EventEmitter<Action | undefined | void> = new vscode.EventEmitter<Action | undefined | void>(); - // @ts-ignore - readonly onDidChangeTreeData: vscode.Event<Action | undefined | void> = this._onDidChangeTreeData.event; - - constructor(private workspaceRoot: string) { - } - - refresh(): void { - this._onDidChangeTreeData.fire(); - } - - private root(): Action[] { - return [ - new Action(DOCUMENTATION_LABEL, TreeItemCollapsibleState.Collapsed, 'folder'), - ]; - } - - getTreeItem(element: Action): vscode.TreeItem { - return element; - } - - getChildren(element?: Action): Thenable<Action[]> { - if (!element) { - return Promise.resolve(this.root()); - } else if (element.label === DOCUMENTATION_LABEL) { - return Promise.resolve([ - new Action( - 'Briefing', - TreeItemCollapsibleState.None, - 'document', - OPEN_BRIEFING_COMMAND.asVsCodeCommand()), - ]); - } - - return Promise.resolve([]); - } - + private _onDidChangeTreeData: vscode.EventEmitter<Action | undefined | void> = new vscode.EventEmitter< + Action | undefined | void + >(); + // @ts-ignore + readonly onDidChangeTreeData: vscode.Event<Action | undefined | void> = this._onDidChangeTreeData.event; + + constructor(private workspaceRoot: string) {} + + refresh(): void { + this._onDidChangeTreeData.fire(); + } + + private root(): Action[] { + return [new Action(DOCUMENTATION_LABEL, TreeItemCollapsibleState.Collapsed, 'folder')]; + } + + getTreeItem(element: Action): vscode.TreeItem { + return element; + } + + getChildren(element?: Action): Thenable<Action[]> { + if (!element) { + return Promise.resolve(this.root()); + } else if (element.label === DOCUMENTATION_LABEL) { + return Promise.resolve([ + new Action('Briefing', TreeItemCollapsibleState.None, 'document', OPEN_BRIEFING_COMMAND.asVsCodeCommand()), + ]); + } + + return Promise.resolve([]); + } } export class Action extends vscode.TreeItem { - - constructor( - public readonly label: string, - public readonly collapsibleState: vscode.TreeItemCollapsibleState, - public readonly iconName: string, - public readonly command?: vscode.Command - ) { - super(label, collapsibleState); - } - - get tooltip(): string { - return this.label; - } - - get description(): string { - return ''; - } - - iconPath = { - light: path.join(__filename, '..', '..', 'resources', 'light', `${this.iconName}.svg`), - dark: path.join(__filename, '..', '..', 'resources', 'dark', `${this.iconName}.svg`) - }; - - contextValue = 'dependency'; - -} \ No newline at end of file + constructor( + public readonly label: string, + public readonly collapsibleState: vscode.TreeItemCollapsibleState, + public readonly iconName: string, + public readonly command?: vscode.Command, + ) { + super(label, collapsibleState); + } + + get tooltip(): string { + return this.label; + } + + get description(): string { + return ''; + } + + iconPath = { + light: path.join(__filename, '..', '..', 'resources', 'light', `${this.iconName}.svg`), + dark: path.join(__filename, '..', '..', 'resources', 'dark', `${this.iconName}.svg`), + }; + + contextValue = 'dependency'; +} diff --git a/deadlock-plugins/deadlock-extension/src/theia/userConfigTheia.ts b/deadlock-plugins/deadlock-extension/src/theia/userConfigTheia.ts index d4c07f85bd14faec6ca81f7be080883663e090e3..387a808962c71036b199aac2b2e63ce5d078eeee 100644 --- a/deadlock-plugins/deadlock-extension/src/theia/userConfigTheia.ts +++ b/deadlock-plugins/deadlock-extension/src/theia/userConfigTheia.ts @@ -4,9 +4,8 @@ import * as vscode from 'vscode'; import { USER_CHALLENGE_PATH } from '../core/config'; export default class UserConfigTheia extends UserConfig { - async loadText(): Promise<string> { - const textDocument = await vscode.workspace.openTextDocument(vscode.Uri.parse(USER_CHALLENGE_PATH)); - return Promise.resolve(textDocument.getText()); - } - -} \ No newline at end of file + async loadText(): Promise<string> { + const textDocument = await vscode.workspace.openTextDocument(vscode.Uri.parse(USER_CHALLENGE_PATH)); + return Promise.resolve(textDocument.getText()); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts index 21a6ae7727d106c1595a71c3c7f6d5f8f12d2074..c041518b04192392f591fdc2b69c12ccc983fc11 100644 --- a/deadlock-plugins/deadlock-extension/src/view/briefingView.ts +++ b/deadlock-plugins/deadlock-extension/src/view/briefingView.ts @@ -28,15 +28,13 @@ export default class BriefingView extends WebviewBase { } setupImages(text: string) { - const imageRegex = /\!\[(.*?)\]\(\b(image:)(.*?\))?/g + const imageRegex = /\!\[(.*?)\]\(\b(image:)(.*?\))?/g; return text.replace(imageRegex, (match, title, imagePrefix, img) => { const fileName = img.replace(')', ''); const extension = fileName.split('.'); - return `})`; + return `})`; }); } @@ -46,25 +44,20 @@ export default class BriefingView extends WebviewBase { this.loadingBriefing = true; clearInterval(intervalId); - vscode.workspace - .openTextDocument( - vscode.Uri.parse(path.join(DOCS_PATH, BRIEFING_FILE_NAME)) - ) - .then( - (document) => { - try { - this.briefingContent = this.setupImages(document.getText()); - } catch (e) { - console.error(e); - this.briefingContent = 'Error while parsing your briefing.'; - } - this.show(); - }, - (error) => { - console.error('Cannot load briefing', error); - this.errorLoadingBriefing = true; + vscode.workspace.openTextDocument(vscode.Uri.parse(path.join(DOCS_PATH, BRIEFING_FILE_NAME))).then( + (document) => { + try { + this.briefingContent = this.setupImages(document.getText()); + } catch (e) { + console.error(e); + this.briefingContent = 'Error while parsing your briefing.'; } - ); + }, + (error) => { + console.error('Cannot load briefing', error); + this.errorLoadingBriefing = true; + }, + ); } }, 500); } @@ -77,9 +70,9 @@ export default class BriefingView extends WebviewBase { <h2>Professeur</h2> Bonjour ${userConfig.getCurrentUserDetails().lastName} ${ userConfig.getCurrentUserDetails().firstName - } vous êtes actuellement entrain de relire le code de <b>${ - userConfig.getRemoteUserDetails().lastName - } ${userConfig.getRemoteUserDetails().firstName}</b>.<br /> + } vous êtes actuellement entrain de relire le code de <b>${userConfig.getRemoteUserDetails().lastName} ${ + userConfig.getRemoteUserDetails().firstName + }</b>.<br /> Vous pouvez consulter chaque exécution de son code dans l'onglet à gauche de GitLens. Chaque commit sur <b>master</b> représente une exécution. <br /> `; diff --git a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts new file mode 100644 index 0000000000000000000000000000000000000000..daeb16529db561a4389c29535b84496c16cac449 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts @@ -0,0 +1,135 @@ +import * as vscode from 'vscode'; +import { AUTHENTICATE_COMMAND, CHOOSE_MISSION_WORKDIR_COMMAND } from '../core/commandHandler'; +import ExtensionStore from '../core/extensionStore'; +import { log } from '../recorder/utils'; +import { OPEN_QUICK_SETUP_COMMAND } from '../theia/command'; +import { WebviewBase } from './webviewBase'; + +export const QUICK_SETUP_ID = 'quickSetup'; + +export default class QuickSetupView extends WebviewBase { + private extensionUri: vscode.Uri; + private extensionStore: ExtensionStore; + private _isAlreadyConnected: boolean; + + constructor(extensionUri: vscode.Uri) { + super(QUICK_SETUP_ID, 'QuickSetup', OPEN_QUICK_SETUP_COMMAND); + this.extensionUri = extensionUri; + this.extensionStore = ExtensionStore.getInstance(); + this._isAlreadyConnected = false; + } + + set isAlreadyConnected(newVal: boolean) { + if (this._isAlreadyConnected !== newVal) { + this._isAlreadyConnected = newVal; + this.reload(); + } + } + + render(): string { + return ` + <head> + ${this.renderHeaderHtml()} + </head> + <body> + ${this.renderHtmlBody()} + </body> + `; + } + + renderHtmlBody() { + const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined; + + return ` + <h1>Quick Setup</h1> + <div class="deadlock-getting-started-card-container"> + + ${this.renderCardHtml( + 'Connexion à Deadlock', + "Tu as besoin d'être connecté à Deadlock pour continuer.", + { name: 'Se connecter', onClickFunctionName: 'openAuthenticationPageAction' }, + this._isAlreadyConnected, + this._isAlreadyConnected, + )} + ${this.renderCardHtml( + 'Dossier contenant tes exercices', + 'Choisis le dossier qui contiendra tous les exercices Deadlock.', + { + name: 'Choisir un dossier', + onClickFunctionName: 'launchChooseMissionWorkdirAction', + }, + hadMissionWorkdir, + )} + </div> + + + `; + } + + renderCardHtml( + title: string, + description: string, + button: { name: string; onClickFunctionName: string }, + isChecked: boolean, + isDisabled?: boolean, + callbackArgs?: string, + ) { + return ` + <div class="deadlock-getting-started-card"> + <vscode-checkbox ${isChecked ? 'checked' : ''} readonly> </vscode-checkbox> + <div class="card-body"> + <div class="card-title"> + ${title} + </div> + <div class="card-description"> + ${description} + </div> + <vscode-button ${isDisabled ? 'disabled' : ''} onclick="${button.onClickFunctionName}(${callbackArgs})">${ + button.name + }</vscode-button> + </div> + </div> + + `; + } + + renderHeaderHtml() { + const toolkitUri = this.getExternalRessourcePath(this.extensionUri, [ + 'node_modules', + '@vscode', + 'webview-ui-toolkit', + 'dist', + 'toolkit.js', + ]); + + const customStyle = this.getExternalRessourcePath(this.extensionUri, [ + 'resources', + 'styles', + 'gettingStartedView.css', + ]); + + const customScript = this.getExternalRessourcePath(this.extensionUri, ['resources', 'js', 'gettingStartedView.js']); + + return ` + <meta charset="UTF-8"> + <script type="module" src="${toolkitUri}"></script> + <script type="text/javascript" src="${customScript}"></script> + <link href="${customStyle}" rel="stylesheet" /> + `; + } + + onMessageReceive(message: any): void { + switch (message.command) { + case 'launchChooseMissionWorkdirAction': + vscode.commands.executeCommand(CHOOSE_MISSION_WORKDIR_COMMAND.cmd).then(() => this.reload()); + return; + case 'openAuthenticationPageAction': + vscode.commands.executeCommand(AUTHENTICATE_COMMAND.cmd); + return; + } + } + + load(): void { + log('Loading GettingStartedView'); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/view/view.ts b/deadlock-plugins/deadlock-extension/src/view/view.ts index c2387c802709dbbca6fe070b5ba3bd89096c39a5..43791cdbadd2625dd8be886001b18eb52e4aa7e6 100644 --- a/deadlock-plugins/deadlock-extension/src/view/view.ts +++ b/deadlock-plugins/deadlock-extension/src/view/view.ts @@ -1,10 +1,8 @@ -import * as path from 'path'; import * as vscode from 'vscode'; function getNonce() { let text = ''; - const possible = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < 32; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } @@ -15,7 +13,6 @@ function getNonce() { * @deprecated use #webviewBase instead of */ export default abstract class View { - private static views: Map<string, View> = new Map(); public currentWebviewPanel: vscode.WebviewPanel | undefined; @@ -26,7 +23,7 @@ export default abstract class View { id: string, private readonly context: vscode.ExtensionContext, public readonly panelName: string, - public readonly title: string + public readonly title: string, ) { this.isRegisteredOnWebviewPanelSerializer = false; @@ -51,14 +48,9 @@ export default abstract class View { } private init(currentWebviewPanel) { - // Listen for when the panel is disposed // This happens when the user closes the panel or when the panel is closed programatically - currentWebviewPanel.onDidDispose( - () => this.dispose(), - null, - this._disposables - ); + currentWebviewPanel.onDidDispose(() => this.dispose(), null, this._disposables); // Update the content based on view changes currentWebviewPanel.onDidChangeViewState( @@ -68,7 +60,7 @@ export default abstract class View { } }, null, - this._disposables + this._disposables, ); // Handle messages from the webview @@ -81,16 +73,13 @@ export default abstract class View { } }, null, - this._disposables + this._disposables, ); if (vscode.window.registerWebviewPanelSerializer && !this.isRegisteredOnWebviewPanelSerializer) { // Make sure we register a serializer in activation event vscode.window.registerWebviewPanelSerializer(this.panelName, { - async deserializeWebviewPanel( - webviewPanel: vscode.WebviewPanel, - state: any - ) { + async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) { // View.revive(webviewPanel, extensionPath); }, }); @@ -99,9 +88,7 @@ export default abstract class View { } public createOrShow() { - const column = vscode.window.activeTextEditor - ? vscode.window.activeTextEditor.viewColumn - : undefined; + const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; // If we already have a panel, show it. if (this.currentWebviewPanel) { @@ -121,9 +108,9 @@ export default abstract class View { // And restrict the webview to only loading content from our extension's `media` directory. // for now we don't need to include the media folder, because React bundle is not used // localResourceRoots: [ - // vscode.Uri.file(path.join(this.extensionPath, 'media')), + // vscode.Uri.file(path.join(this.extensionPath, 'media')), // ], - } + }, ); // update first time to force render of webviewPanel this.update(); @@ -165,16 +152,16 @@ export default abstract class View { // /!\ EXPERIMENTAL /!\ // Local path to main script run in the webview // const scriptPathOnDisk = vscode.Uri.file( - // path.join(this.extensionPath, 'media', 'static/bundle.js') + // path.join(this.extensionPath, 'media', 'static/bundle.js') // ); // const cssPathOnDisk = vscode.Uri.file( - // path.join(this.extensionPath, 'media', 'static/bundle.css') + // path.join(this.extensionPath, 'media', 'static/bundle.css') // ); // And the uri we use to load this script in the webview // const scriptUri = webview.asWebviewUri(scriptPathOnDisk); // const cssUri = webview.asWebviewUri(cssPathOnDisk); - // append in the HTML head <link href="${cssUri}" rel="stylesheet"></head> + // append in the HTML head <link href="${cssUri}" rel="stylesheet"></head> // Use a nonce to whitelist which scripts can be run // const nonce = getNonce(); @@ -186,20 +173,20 @@ export default abstract class View { content = this.render(); } catch (e) { console.error('Erreur lors du render', e); - content = 'Impossible d\'afficher le rendu, nous sommes désolés'; + content = "Impossible d'afficher le rendu, nous sommes désolés"; } return `<!DOCTYPE html><html lang="en"> - <head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Deadlock</title> - </head> - <body> - <div> - ${content} - </div> - </body></html>`; + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Deadlock</title> + </head> + <body> + <div> + ${content} + </div> + </body></html>`; } /** diff --git a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts index 14d582f41acaefef13194e2da8c2ef9a68205703..1639cb5634d43b3209661865ad8e2bb0a3dac4ee 100644 --- a/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts +++ b/deadlock-plugins/deadlock-extension/src/view/webviewBase.ts @@ -1,14 +1,15 @@ -"use strict"; +'use strict'; import { commands, Disposable, + Uri, ViewColumn, Webview, WebviewPanel, WebviewPanelOnDidChangeViewStateEvent, window, -} from "vscode"; -import { Command } from "../theia/command"; +} from 'vscode'; +import { Command } from '../theia/command'; const emptyCommands: Disposable[] = [ { @@ -18,18 +19,24 @@ const emptyCommands: Disposable[] = [ }, ]; +export function getUri(webview: Webview, extensionUri: Uri, pathList: string[]) { + return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList)); +} + export abstract class WebviewBase implements Disposable { protected disposable: Disposable; - private _disposablePanel: Disposable | undefined; - private _panel: WebviewPanel | undefined; + private disposablePanel: Disposable | undefined; + protected panel: WebviewPanel | undefined; - constructor(private id: string, private title:string, command: Command, private readonly _column?: ViewColumn) { - this.disposable = Disposable.from( - commands.registerCommand(command.cmd, this.onShowCommand, this) - ); + constructor(private id: string, private title: string, command: Command, private readonly _column?: ViewColumn) { + this.disposable = Disposable.from(commands.registerCommand(command.cmd, this.onShowCommand, this)); this.load(); } + getExternalRessourcePath(extensionUri: Uri, pathList: string[]) { + return getUri(this.panel!.webview, extensionUri, pathList); + } + registerCommands(): Disposable[] { return emptyCommands; } @@ -40,7 +47,7 @@ export abstract class WebviewBase implements Disposable { dispose() { this.disposable.dispose(); - this._disposablePanel?.dispose(); + this.disposablePanel?.dispose(); } protected onShowCommand() { @@ -48,42 +55,42 @@ export abstract class WebviewBase implements Disposable { } private onPanelDisposed() { - this._disposablePanel?.dispose(); - this._panel = undefined; + this.disposablePanel?.dispose(); + this.panel = undefined; } private onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent) { console.log( `Webview(${this.id}).onViewStateChanged`, - `active=${e.webviewPanel.active}, visible=${e.webviewPanel.visible}` + `active=${e.webviewPanel.active}, visible=${e.webviewPanel.visible}`, ); } get visible() { - return this._panel?.visible ?? false; + return this.panel?.visible ?? false; } hide() { - this._panel?.dispose(); + this.panel?.dispose(); } setTitle(title: string) { - if (this._panel == null) return; + if (this.panel == null) return; - this._panel.title = title; + this.panel.title = title; } onMessageReceive(message) { switch (message.command) { - case "alert": + case 'alert': window.showErrorMessage(message.text); return; } } async show(column: ViewColumn = ViewColumn.Beside): Promise<void> { - if (this._panel == null) { - this._panel = window.createWebviewPanel( + if (this.panel == null) { + this.panel = window.createWebviewPanel( this.id, this.title, { viewColumn: column, preserveFocus: false }, @@ -92,26 +99,36 @@ export abstract class WebviewBase implements Disposable { enableFindWidget: true, enableCommandUris: true, enableScripts: true, - } + }, ); - this._disposablePanel = Disposable.from( - this._panel, - this._panel.onDidDispose(this.onPanelDisposed, this), - this._panel.onDidChangeViewState(this.onViewStateChanged, this), - this._panel.webview.onDidReceiveMessage(this.onMessageReceive, this), - ...this.registerCommands() + this.disposablePanel = Disposable.from( + this.panel, + this.panel.onDidDispose(this.onPanelDisposed, this), + this.panel.onDidChangeViewState(this.onViewStateChanged, this), + this.panel.webview.onDidReceiveMessage(this.onMessageReceive, this), + ...this.registerCommands(), ); - this._panel.webview.html = await this.getHtml(this._panel.webview); + this.panel.webview.html = await this.getHtml(this.panel.webview); } else { - const html = await this.getHtml(this._panel.webview); + const html = await this.getHtml(this.panel.webview); // Reset the html to get the webview to reload - this._panel.webview.html = ""; - this._panel.webview.html = html; + this.panel.webview.html = ''; + this.panel.webview.html = html; - this._panel.reveal(this._panel.viewColumn ?? ViewColumn.Active, false); + this.panel.reveal(this.panel.viewColumn ?? ViewColumn.Active, false); + } + } + + async reload() { + if (this.panel) { + const html = await this.getHtml(this.panel.webview); + + // Reset the html to get the webview to reload + this.panel.webview.html = ''; + this.panel.webview.html = html; } } @@ -125,7 +142,6 @@ export abstract class WebviewBase implements Disposable { abstract load(): void; private async getHtml(webview: Webview): Promise<string> { - return this.render(); + return this.render(); } - } diff --git a/deadlock-plugins/deadlock-extension/tsconfig.json b/deadlock-plugins/deadlock-extension/tsconfig.json index 45ea4863817c56fa21e1f40ba11c6c29935fb8a0..adaa4e495b1fd3b88482adf9b1a89fb97262fbdf 100644 --- a/deadlock-plugins/deadlock-extension/tsconfig.json +++ b/deadlock-plugins/deadlock-extension/tsconfig.json @@ -1,14 +1,18 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es2019", - "lib": ["ES2019"], - "outDir": "out", - "sourceMap": false, - "strict": true, - "rootDir": "src", - "noImplicitAny": false, - "allowJs": true, - }, - "exclude": ["node_modules", ".vscode-test", "front", "out", "media"] + "compilerOptions": { + "module": "commonjs", + "target": "es2019", + "lib": ["ES2019"], + "outDir": "out", + "sourceMap": false, + "strict": true, + "rootDir": "src", + "noImplicitAny": false, + "allowJs": true, + "types": ["reflect-metadata"], + "moduleResolution": "node", + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "exclude": ["node_modules", ".vscode-test", "front", "out", "media", "resources"] } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..392bf32cda135bf2b4ca4bc13b692b889436e486 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1705 @@ +{ + "name": "deadlock-theia", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "deadlock-theia", + "version": "1.0.0", + "devDependencies": { + "husky": "^7.0.4", + "lint-staged": "^12.3.7", + "prettier": "2.6.2" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lint-staged": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.7.tgz", + "integrity": "sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ==", + "dev": true, + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.16", + "commander": "^8.3.0", + "debug": "^4.3.3", + "execa": "^5.1.1", + "lilconfig": "2.0.4", + "listr2": "^4.0.1", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.0", + "pidtree": "^0.5.0", + "string-argv": "^0.3.1", + "supports-color": "^9.2.1", + "yaml": "^1.10.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/listr2/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true + }, + "lint-staged": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.7.tgz", + "integrity": "sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ==", + "dev": true, + "requires": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.16", + "commander": "^8.3.0", + "debug": "^4.3.3", + "execa": "^5.1.1", + "lilconfig": "2.0.4", + "listr2": "^4.0.1", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.0", + "pidtree": "^0.5.0", + "string-argv": "^0.3.1", + "supports-color": "^9.2.1", + "yaml": "^1.10.2" + } + }, + "listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", + "dev": true + }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + } + }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "supports-color": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..784d63424ab0720db5c3080ad5c7da5e34770300 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "deadlock-theia", + "version": "1.0.0", + "description": "Deadlock Theia projet basé sur notre propre image de Theia https://git.e-biz.fr/deadlock-public/theia.", + "scripts": { + "prepare": "husky install" + }, + "repository": { + "type": "git", + "url": "git@git.e-biz.fr:deadlock-public/deadlock-theia.git" + }, + "author": "Takima", + "devDependencies": { + "husky": "^7.0.4", + "lint-staged": "^12.3.7", + "prettier": "2.6.2" + }, + "lint-staged": { + "*.{ts,md,js,json}": [ + "prettier --write --ignore-unknown", + "git add" + ] + } +} diff --git a/server.js b/server.js index b553783e30565b8c16184bc9dd3fe31584b0e112..00cc0611f7b3a6daf4060cd0acc11449fb63b357 100644 --- a/server.js +++ b/server.js @@ -5,13 +5,12 @@ * then you will find the content within /home/theia/src-gen/backend/server.js in the container */ - // @ts-check require('reflect-metadata'); // Patch electron version if missing, see https://github.com/eclipse-theia/theia/pull/7361#pullrequestreview-377065146 if (typeof process.versions.electron === 'undefined' && typeof process.env.THEIA_ELECTRON_VERSION === 'string') { - process.versions.electron = process.env.THEIA_ELECTRON_VERSION; + process.versions.electron = process.env.THEIA_ELECTRON_VERSION; } const path = require('path'); @@ -29,58 +28,96 @@ container.load(loggerBackendModule); //CORS middleware const allowCrossDomain = function (req, res, next) { - if (req.headers.origin && req.headers.origin.endsWith('.deadlock.io')) { - res.setHeader('Access-Control-Allow-Origin', req.headers.origin); - res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); - } - next(); + if (req.headers.origin && req.headers.origin.endsWith('.deadlock.io')) { + res.setHeader('Access-Control-Allow-Origin', req.headers.origin); + res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); + } + next(); }; function load(raw) { - return Promise.resolve(raw.default).then(module => - container.load(module) - ) + return Promise.resolve(raw.default).then((module) => container.load(module)); } function start(port, host, argv) { - if (argv === undefined) { - argv = process.argv; - } + if (argv === undefined) { + argv = process.argv; + } - const cliManager = container.get(CliManager); - return cliManager.initializeCli(argv).then(function () { - const application = container.get(BackendApplication); - application.use(allowCrossDomain); - application.use(express.static(path.join(__dirname, '../../lib'))); - application.use(express.static(path.join(__dirname, '../../lib/index.html'))); - return application.start(port, host); - }); + const cliManager = container.get(CliManager); + return cliManager.initializeCli(argv).then(function () { + const application = container.get(BackendApplication); + application.use(allowCrossDomain); + application.use(express.static(path.join(__dirname, '../../lib'))); + application.use(express.static(path.join(__dirname, '../../lib/index.html'))); + return application.start(port, host); + }); } -module.exports = (port, host, argv) => Promise.resolve() - .then(function () { return Promise.resolve(require('@theia/core/lib/node/i18n/i18n-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/core/lib/node/hosting/backend-hosting-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/filesystem/lib/node/filesystem-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/filesystem/lib/node/download/file-download-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/workspace/lib/node/workspace-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/process/lib/common/process-common-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/process/lib/node/process-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/file-search/lib/node/file-search-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/git/lib/node/git-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/git/lib/node/env/git-env-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/terminal/lib/node/terminal-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/task/lib/node/task-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/debug/lib/node/debug-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/search-in-workspace/lib/node/search-in-workspace-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/plugin-ext/lib/plugin-ext-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/plugin-ext-vscode/lib/node/plugin-vscode-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/mini-browser/lib/node/mini-browser-backend-module')).then(load) }) - .then(function () { return Promise.resolve(require('@theia/vsx-registry/lib/node/vsx-registry-backend-module')).then(load) }) - .then(() => start(port, host, argv)).catch(reason => { - console.error('Failed to start the backend application.'); - if (reason) { - console.error(reason); - } - throw reason; +module.exports = (port, host, argv) => + Promise.resolve() + .then(function () { + return Promise.resolve(require('@theia/core/lib/node/i18n/i18n-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/core/lib/node/hosting/backend-hosting-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/filesystem/lib/node/filesystem-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/filesystem/lib/node/download/file-download-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/workspace/lib/node/workspace-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/process/lib/common/process-common-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/process/lib/node/process-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/file-search/lib/node/file-search-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/git/lib/node/git-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/git/lib/node/env/git-env-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/terminal/lib/node/terminal-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/task/lib/node/task-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/debug/lib/node/debug-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/search-in-workspace/lib/node/search-in-workspace-backend-module')).then( + load, + ); + }) + .then(function () { + return Promise.resolve(require('@theia/plugin-ext/lib/plugin-ext-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/plugin-ext-vscode/lib/node/plugin-vscode-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/mini-browser/lib/node/mini-browser-backend-module')).then(load); + }) + .then(function () { + return Promise.resolve(require('@theia/vsx-registry/lib/node/vsx-registry-backend-module')).then(load); + }) + .then(() => start(port, host, argv)) + .catch((reason) => { + console.error('Failed to start the backend application.'); + if (reason) { + console.error(reason); + } + throw reason; }); diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000000000000000000000000000000000000..2ebb8e0d4157f9d08fc87605c996fc2daf1e1085 --- /dev/null +++ b/setup.sh @@ -0,0 +1,2 @@ +npm install +npm install --prefix ./deadlock-plugins/deadlock-extension \ No newline at end of file