diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c34cc2d9d2d..26213b94342 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,9 @@ "editorconfig.editorconfig", "github.vscode-pull-request-github", "github.vscode-github-actions", - "ms-dotnettools.csdevkit" + "ms-dotnettools.csdevkit", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" ] } }, diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7292312eaaf..7dab6f53109 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,7 +101,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Setup .NET Core uses: actions/setup-dotnet@v4 @@ -161,7 +161,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Setup .NET Core uses: actions/setup-dotnet@v4 @@ -364,7 +364,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: npm ci if: matrix.runTests @@ -437,7 +437,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: npm ci run: npm ci @@ -474,7 +474,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: TextMate Grammar run: | @@ -527,7 +527,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Download Bicep CLI uses: actions/download-artifact@v4 @@ -717,7 +717,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Setup .NET Core uses: actions/setup-dotnet@v4 diff --git a/.github/workflows/run-formatter.yml b/.github/workflows/run-formatter.yml index 0af194f6457..b5ad5f8bd59 100644 --- a/.github/workflows/run-formatter.yml +++ b/.github/workflows/run-formatter.yml @@ -29,12 +29,24 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: npm ci + run: npm ci + working-directory: ./src/vscode-bicep - - name: Format - run: dotnet format - - - name: Remove unnecessary using directives (IDE0005) - run: dotnet format style --diagnostics IDE0005 --severity info + - name: Format .NET code + run: | + dotnet format + dotnet format style --diagnostics IDE0005 --severity info + + - name: Format vscode-bicep + run: npm run format + working-directory: ./src/vscode-bicep - name: Commit and push formatting updates if: (!github.ref_protected) diff --git a/.vscode/settings.json b/.vscode/settings.json index c86c576d586..7952f91b871 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,5 @@ { - "eslint.format.enable": true, "eslint.lintTask.enable": true, - "[typescript]": { - "editor.defaultFormatter": "vscode.typescript-language-features" - }, "yaml.schemas": { "https://json.schemastore.org/github-workflow.json": "/.github/workflows/*.yml" }, diff --git a/src/vscode-bicep/.eslintrc.cjs b/src/vscode-bicep/.eslintrc.cjs new file mode 100644 index 00000000000..0931112515c --- /dev/null +++ b/src/vscode-bicep/.eslintrc.cjs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +module.exports = { + root: true, + ignorePatterns: ["out/**/*", ".eslintrc.cjs", "webpack.config.ts", "jest.config.*.js"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: true, + }, + settings: { + react: { + version: "detect", + }, + }, + plugins: ["header", "@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:jest/recommended", + "plugin:jest/style", + ], + rules: { + "header/header": [ + 2, + "line", + [ + " Copyright (c) Microsoft Corporation.", + " Licensed under the MIT License.", + ], + ], + }, +}; diff --git a/src/vscode-bicep/.eslintrc.js b/src/vscode-bicep/.eslintrc.js deleted file mode 100644 index 46cb2c0ba5f..00000000000 --- a/src/vscode-bicep/.eslintrc.js +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -module.exports = { - root: true, - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - ecmaFeature: { jsx: true }, - project: './tsconfig.json', - }, - plugins: ["header"], - settings: { - react: { - version: "detect", - }, - }, - extends: ["eslint:recommended", "plugin:prettier/recommended"], - ignorePatterns: ["/out/**/*", "/enableParams.js"], - rules: { - "header/header": [ - 2, - "line", - [ - " Copyright (c) Microsoft Corporation.", - " Licensed under the MIT License.", - ], - ], - eqeqeq: "error", - }, - overrides: [ - { - files: ["*.ts", "*.tsx"], - extends: [ - "plugin:react/recommended", - "plugin:@typescript-eslint/recommended", - "plugin:jest/all", - "plugin:prettier/recommended", - ], - rules: { - "react/prop-types": "off", - "react/jsx-uses-react": "off", - "react/react-in-jsx-scope": "off", - "jest/no-conditional-in-test": "off", - "jest/no-hooks": "off", - "jest/prefer-expect-assertions": "off", - "jest/expect-expect": [ - "error", - { - assertFunctionNames: ["expect*"], - }, - ], - "jest/prefer-importing-jest-globals": "off", - "prettier/prettier": "warn", - '@typescript-eslint/no-floating-promises': ["error"], - }, - }, - { - files: ["*.js"], - env: { node: true }, - }, - ], -}; diff --git a/src/vscode-bicep/.prettierrc b/src/vscode-bicep/.prettierrc new file mode 100644 index 00000000000..78a2cb16444 --- /dev/null +++ b/src/vscode-bicep/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 120, + "plugins": ["@ianvs/prettier-plugin-sort-imports"], + "importOrder": [ + "^(node:)", + "", + "^[.]", + "", + "", + "", + "^[./]" + ] +} diff --git a/src/vscode-bicep/.vscode/tasks.json b/src/vscode-bicep/.vscode/tasks.json index 8e052cfcea3..1ba17068780 100644 --- a/src/vscode-bicep/.vscode/tasks.json +++ b/src/vscode-bicep/.vscode/tasks.json @@ -104,7 +104,7 @@ { "label": "build:e2e:dev", "type": "typescript", - "tsconfig": "tsconfig.e2e.dev.json", + "tsconfig": "tsconfig.e2e.json", "problemMatcher": "$tsc", "group": "build", "presentation": { diff --git a/src/vscode-bicep/.vscodeignore b/src/vscode-bicep/.vscodeignore index a39210623c9..4e200ef8cba 100644 --- a/src/vscode-bicep/.vscodeignore +++ b/src/vscode-bicep/.vscodeignore @@ -11,10 +11,8 @@ readme-links/ .vscodeignore webpack.config.ts tsconfig.e2e.json -tsconfig.e2e.dev.json tsconfig.json package.params.json -enableParams.js jest.config.e2e.js jest.config.unit.js jest.config.snapshot.js \ No newline at end of file diff --git a/src/vscode-bicep/README.md b/src/vscode-bicep/README.md index cf709777b04..223fabf6f4a 100644 --- a/src/vscode-bicep/README.md +++ b/src/vscode-bicep/README.md @@ -32,9 +32,9 @@ Easily explore all available resource types and api versions for a given type. Y ### Other intellisense and completions -* Keyword declarations. On an empty line you will get completions for all keywords (`param`, `var`, `resource`, etc.) -* `param` and `output` types (i.e. `param myParam `) -* target scopes (i.e. `targetScope = `) +- Keyword declarations. On an empty line you will get completions for all keywords (`param`, `var`, `resource`, etc.) +- `param` and `output` types (i.e. `param myParam `) +- target scopes (i.e. `targetScope = `) ### Snippets @@ -78,12 +78,12 @@ You can rename any symbol such as a `param` or `resource` and bicep will intelli ### Formatting -* Default keybinding is `alt` + `shift` + `f` on Windows, `option` + `shift` + `f` on macOS - * You can also format via the VS Code UI. `View` -> `Command palette...` then type `format document` +- Default keybinding is `alt` + `shift` + `f` on Windows, `option` + `shift` + `f` on macOS + - You can also format via the VS Code UI. `View` -> `Command palette...` then type `format document` ![formatting a bicep file that is disorganized](/docs/images/format.gif) -* Bicep will set the following default settings for `.bicep` files when installed: +- Bicep will set the following default settings for `.bicep` files when installed: ```json "[bicep]": { @@ -94,9 +94,9 @@ You can rename any symbol such as a `param` or `resource` and bicep will intelli You can change the default settings in the following places (sorted by precedence in ascending order): -* VSCode global user settings -* VSCode workspace settings -* `.editorconfig` files (requires EditorConfig for VSCode extension to be installed) +- VSCode global user settings +- VSCode workspace settings +- `.editorconfig` files (requires EditorConfig for VSCode extension to be installed) ### Quick fixes @@ -110,4 +110,4 @@ For small issues like misspelled symbols or incorrect casing, bicep will offer a Use the "Insert Resource" command to quickly import a resource from Azure into a Bicep file. -![Insert resource command](/src/vscode-bicep/readme-links/insertresource.gif) \ No newline at end of file +![Insert resource command](/src/vscode-bicep/readme-links/insertresource.gif) diff --git a/src/vscode-bicep/media/walkthroughs/gettingStarted/2_Type_Params.md b/src/vscode-bicep/media/walkthroughs/gettingStarted/2_Type_Params.md index 848beb84c51..92afea4d385 100644 --- a/src/vscode-bicep/media/walkthroughs/gettingStarted/2_Type_Params.md +++ b/src/vscode-bicep/media/walkthroughs/gettingStarted/2_Type_Params.md @@ -1,10 +1,13 @@ # Add parameters to your Bicep file -* First, create a parameter named location: +- First, create a parameter named location: + ```bicep param location string = resourceGroup().location ``` -* Next, create a parameter named 'appPlanName': + +- Next, create a parameter named 'appPlanName': + ```bicep param appPlanName string = '${uniqueString(resourceGroup().id)}plan' ``` @@ -12,6 +15,7 @@ param appPlanName string = '${uniqueString(resourceGroup().id)}plan' These parameters will be used to fill in attributes in your resources. + [Copy code to clipboard](command:bicep.gettingStarted.copyToClipboard?%7B%22step%22%3A%22params%22%7D) ![Typing parameters into Bicep](2_Type_Params.gif) diff --git a/src/vscode-bicep/media/walkthroughs/gettingStarted/3_Type_Resources.md b/src/vscode-bicep/media/walkthroughs/gettingStarted/3_Type_Resources.md index 67985ee42d3..b93f0288250 100644 --- a/src/vscode-bicep/media/walkthroughs/gettingStarted/3_Type_Resources.md +++ b/src/vscode-bicep/media/walkthroughs/gettingStarted/3_Type_Resources.md @@ -1,14 +1,15 @@ # Add resources to your Bicep file -* First, type `'appplan'` to view the 'Application Service Plan' resource snippet and press Tab or Enter. Press Tab to jump to the `name` attribute and replace its value with the parameter `appPlanName`. +- First, type `'appplan'` to view the 'Application Service Plan' resource snippet and press Tab or Enter. Press Tab to jump to the `name` attribute and replace its value with the parameter `appPlanName`. -* Next, type `'storage'` to view the 'Storage Account' resource snippet and press Tab or Enter. Replace the `name` attribute's value with `'${appServicePlan.name}storage'` (including the single quotes). +- Next, type `'storage'` to view the 'Storage Account' resource snippet and press Tab or Enter. Replace the `name` attribute's value with `'${appServicePlan.name}storage'` (including the single quotes). -* Save the file. +- Save the file. Feel free to search for other snippets that suit your needs. + [Copy code to clipboard](command:bicep.gettingStarted.copyToClipboard?%7B%22step%22%3A%22resources%22%7D) ![Typing resources into Bicep file](3_Type_Resources.gif) diff --git a/src/vscode-bicep/package-lock.json b/src/vscode-bicep/package-lock.json index d7e65a4561d..d878111d83b 100644 --- a/src/vscode-bicep/package-lock.json +++ b/src/vscode-bicep/package-lock.json @@ -32,6 +32,7 @@ "winston-transport": "^4.7.1" }, "devDependencies": { + "@ianvs/prettier-plugin-sort-imports": "^4.3.1", "@types/cytoscape": "^3.21.4", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", @@ -52,10 +53,8 @@ "css-loader": "^7.1.2", "esbuild-loader": "^4.2.0", "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-jest": "^28.6.0", - "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.3", "fork-ts-checker-webpack-plugin": "^9.0.2", "jest": "^29.7.0", @@ -73,7 +72,7 @@ "terser-webpack-plugin": "5.3.10", "ts-jest": "^29.1.5", "ts-node": "^10.9.2", - "typescript": "^5.4.5", + "typescript": "^5.5.3", "webpack": "^5.93.0", "webpack-cli": "^5.1.4" }, @@ -604,118 +603,50 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -736,14 +667,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.24.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", + "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -751,22 +683,20 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", - "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { @@ -774,6 +704,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -783,6 +714,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -791,65 +723,75 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -868,79 +810,87 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -951,6 +901,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -963,6 +914,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -977,6 +929,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -985,13 +938,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -1001,6 +956,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1010,6 +966,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -1018,10 +975,11 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", "dev": true, + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -1207,34 +1165,36 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -1246,18 +1206,20 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1812,6 +1774,30 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@ianvs/prettier-plugin-sort-imports": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.1.tgz", + "integrity": "sha512-ZHwbyjkANZOjaBm3ZosADD2OUYGFzQGxfy67HmGZU94mHqe7g1LCMA7YYKB1Cq+UTPCBqlAYapY0KXAjKEw8Sg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/core": "^7.24.0", + "@babel/generator": "^7.23.6", + "@babel/parser": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "semver": "^7.5.2" + }, + "peerDependencies": { + "@vue/compiler-sfc": "2.7.x || 3.x", + "prettier": "2 || 3" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -2233,12 +2219,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", @@ -2257,14 +2237,15 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2280,10 +2261,11 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -2305,10 +2287,11 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2573,18 +2556,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz", @@ -4416,9 +4387,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", "dev": true, "funding": [ { @@ -4434,11 +4405,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -4575,9 +4547,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001585", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz", - "integrity": "sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==", + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", "dev": true, "funding": [ { @@ -4592,7 +4564,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "4.1.2", @@ -4925,13 +4898,11 @@ "optional": true }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } + "license": "MIT" }, "node_modules/copy-webpack-plugin": { "version": "12.0.2", @@ -5634,10 +5605,11 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.665", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz", - "integrity": "sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw==", - "dev": true + "version": "1.4.829", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.829.tgz", + "integrity": "sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==", + "dev": true, + "license": "ISC" }, "node_modules/elkjs": { "version": "0.8.2", @@ -5949,10 +5921,11 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6041,18 +6014,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, "node_modules/eslint-plugin-header": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", @@ -6087,36 +6048,6 @@ } } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-plugin-react": { "version": "7.34.3", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", @@ -6460,12 +6391,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -10156,9 +10081,10 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -10358,18 +10284,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -11711,28 +11625,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/tabbable": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", @@ -12213,10 +12105,11 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12279,9 +12172,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -12297,9 +12190,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -12366,12 +12260,6 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -13461,99 +13349,41 @@ } }, "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" } }, "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", "dev": true }, "@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "dependencies": { @@ -13566,26 +13396,26 @@ } }, "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.24.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", + "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", "dev": true, "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", - "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", "dev": true, "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -13614,50 +13444,54 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "requires": { + "@babel/types": "^7.24.7" + } }, "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" } }, "@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" } }, "@babel/helper-plugin-utils": { @@ -13667,61 +13501,62 @@ "dev": true }, "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" } }, "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true }, "@babel/helpers": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", - "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.6", - "@babel/types": "^7.22.5" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" } }, "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "dependencies": { "ansi-styles": { @@ -13783,9 +13618,9 @@ } }, "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -13915,31 +13750,31 @@ } }, "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -13952,13 +13787,13 @@ } }, "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" } }, @@ -14267,6 +14102,20 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "@ianvs/prettier-plugin-sort-imports": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.1.tgz", + "integrity": "sha512-ZHwbyjkANZOjaBm3ZosADD2OUYGFzQGxfy67HmGZU94mHqe7g1LCMA7YYKB1Cq+UTPCBqlAYapY0KXAjKEw8Sg==", + "dev": true, + "requires": { + "@babel/core": "^7.24.0", + "@babel/generator": "^7.23.6", + "@babel/parser": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "semver": "^7.5.2" + } + }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -14586,14 +14435,6 @@ "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.2" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - } } }, "@jest/types": { @@ -14611,14 +14452,14 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { @@ -14628,9 +14469,9 @@ "dev": true }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true }, "@jridgewell/source-map": { @@ -14650,9 +14491,9 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", @@ -14881,12 +14722,6 @@ "dev": true, "optional": true }, - "@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true - }, "@selderee/plugin-htmlparser2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz", @@ -16319,15 +16154,15 @@ } }, "browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "update-browserslist-db": "^1.1.0" } }, "bs-logger": { @@ -16425,9 +16260,9 @@ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==" }, "caniuse-lite": { - "version": "1.0.30001585", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz", - "integrity": "sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==", + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", "dev": true }, "chalk": { @@ -16686,13 +16521,10 @@ "optional": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "copy-webpack-plugin": { "version": "12.0.2", @@ -17181,9 +17013,9 @@ } }, "electron-to-chromium": { - "version": "1.4.665", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz", - "integrity": "sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw==", + "version": "1.4.829", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.829.tgz", + "integrity": "sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==", "dev": true }, "elkjs": { @@ -17435,9 +17267,9 @@ } }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true }, "escape-string-regexp": { @@ -17573,13 +17405,6 @@ } } }, - "eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "requires": {} - }, "eslint-plugin-header": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", @@ -17596,16 +17421,6 @@ "@typescript-eslint/utils": "^6.0.0 || ^7.0.0" } }, - "eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - } - }, "eslint-plugin-react": { "version": "7.34.3", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", @@ -17779,12 +17594,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -20545,9 +20354,9 @@ "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "picomatch": { "version": "2.3.1", @@ -20671,15 +20480,6 @@ "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, "pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -21648,24 +21448,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "requires": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - } - } - }, "tabbable": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", @@ -21992,9 +21774,9 @@ } }, "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true }, "uc.micro": { @@ -22039,13 +21821,13 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" } }, "uri-js": { @@ -22098,14 +21880,6 @@ "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - } } }, "vscode-jsonrpc": { diff --git a/src/vscode-bicep/package.json b/src/vscode-bicep/package.json index bb7fdee1ced..02c7fbba56a 100644 --- a/src/vscode-bicep/package.json +++ b/src/vscode-bicep/package.json @@ -730,12 +730,13 @@ }, "scripts": { "vscode:prepublish": "npm run build:prod", - "build": "webpack --mode development", - "build:prod": "webpack --mode production", + "build": "tsc --noEmit && webpack --mode development", + "build:prod": "tsc --noEmit && webpack --mode production", "build:e2e": "tsc -p ./tsconfig.e2e.json", "watch": "webpack --watch --mode development --stats=minimal", - "lint": "eslint src --ext ts", - "lint:fix": "eslint src --ext ts --fix", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint:fix": "eslint . --ext ts,tsx --report-unused-disable-directives --fix", + "format": "prettier --write \"**/*.{ts,tsx,md}\"", "$test:e2e.comment": "use testlocal:e2e to run on a local Mac/Linux/Windows (not PowerShell) machine", "test:e2e": "node ./out/test/e2e/runTests.js", "test:unit": "jest --config jest.config.unit.js", @@ -747,6 +748,7 @@ "packagelocal": "rimraf ./bicepLanguageServer && cp -r ../Bicep.LangServer/bin/Debug/net8.0 ./bicepLanguageServer && npm run package" }, "devDependencies": { + "@ianvs/prettier-plugin-sort-imports": "^4.3.1", "@types/cytoscape": "^3.21.4", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", @@ -767,10 +769,8 @@ "css-loader": "^7.1.2", "esbuild-loader": "^4.2.0", "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-jest": "^28.6.0", - "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.3", "fork-ts-checker-webpack-plugin": "^9.0.2", "jest": "^29.7.0", @@ -788,7 +788,7 @@ "terser-webpack-plugin": "5.3.10", "ts-jest": "^29.1.5", "ts-node": "^10.9.2", - "typescript": "^5.4.5", + "typescript": "^5.5.3", "webpack": "^5.93.0", "webpack-cli": "^5.1.4" }, diff --git a/src/vscode-bicep/src/azure/AzureUiManager.ts b/src/vscode-bicep/src/azure/AzureUiManager.ts index dba1f11455c..e1eea3ab8b7 100644 --- a/src/vscode-bicep/src/azure/AzureUiManager.ts +++ b/src/vscode-bicep/src/azure/AzureUiManager.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { TreeManager } from "../tree/TreeManager"; +import { AccessToken } from "@azure/identity"; import { IActionContext } from "@microsoft/vscode-azext-utils"; +import { TreeManager } from "../tree/TreeManager"; import { DeploymentScope, DeploymentScopeType, IAzureUiManager } from "./types"; -import { AccessToken } from "@azure/identity"; function getSubscriptionId(scope: DeploymentScope) { switch (scope.scopeType) { @@ -28,10 +28,7 @@ export class AzureUiManager implements IAzureUiManager { const subscriptionId = getSubscriptionId(scope); const scopeId = `/subscriptions/${subscriptionId}`; - const treeItem = await this.treeManager.azLocationTree.findTreeItem( - scopeId, - this.context, - ); + const treeItem = await this.treeManager.azLocationTree.findTreeItem(scopeId, this.context); if (!treeItem) { throw `Failed to authenticate with Azure for subscription ${subscriptionId}. Are you signed in to the Azure VSCode extension under the correct account?`; @@ -40,16 +37,10 @@ export class AzureUiManager implements IAzureUiManager { return treeItem.subscription.credentials.getToken(); } - public async pickScope( - scopeType: DeploymentScopeType, - ): Promise { + public async pickScope(scopeType: DeploymentScopeType): Promise { switch (scopeType) { case "resourceGroup": { - const treeItem = - await this.treeManager.azResourceGroupTreeItem.showTreeItemPicker( - "", - this.context, - ); + const treeItem = await this.treeManager.azResourceGroupTreeItem.showTreeItemPicker("", this.context); return { scopeType, @@ -60,11 +51,7 @@ export class AzureUiManager implements IAzureUiManager { }; } case "subscription": { - const treeItem = - await this.treeManager.azLocationTree.showTreeItemPicker( - "", - this.context, - ); + const treeItem = await this.treeManager.azLocationTree.showTreeItemPicker("", this.context); return { scopeType, portalUrl: treeItem.subscription.environment.portalUrl, @@ -74,16 +61,8 @@ export class AzureUiManager implements IAzureUiManager { }; } case "managementGroup": { - const locationItem = - await this.treeManager.azLocationTree.showTreeItemPicker( - "", - this.context, - ); - const treeItem = - await this.treeManager.azManagementGroupTreeItem.showTreeItemPicker( - "", - this.context, - ); + const locationItem = await this.treeManager.azLocationTree.showTreeItemPicker("", this.context); + const treeItem = await this.treeManager.azManagementGroupTreeItem.showTreeItemPicker("", this.context); return { scopeType, @@ -95,11 +74,7 @@ export class AzureUiManager implements IAzureUiManager { }; } case "tenant": { - const locationItem = - await this.treeManager.azLocationTree.showTreeItemPicker( - "", - this.context, - ); + const locationItem = await this.treeManager.azLocationTree.showTreeItemPicker("", this.context); return { scopeType, diff --git a/src/vscode-bicep/src/azure/azureClients.ts b/src/vscode-bicep/src/azure/azureClients.ts index 99448b7c787..cc8edbaaf64 100644 --- a/src/vscode-bicep/src/azure/azureClients.ts +++ b/src/vscode-bicep/src/azure/azureClients.ts @@ -10,18 +10,11 @@ import { // Lazy-load @azure packages to improve startup performance. -export async function createResourceManagementClient( - context: AzExtClientContext, -): Promise { - return createAzureClient( - context, - (await import("@azure/arm-resources")).ResourceManagementClient, - ); +export async function createResourceManagementClient(context: AzExtClientContext): Promise { + return createAzureClient(context, (await import("@azure/arm-resources")).ResourceManagementClient); } -export async function createSubscriptionClient( - context: AzExtClientContext, -): Promise { +export async function createSubscriptionClient(context: AzExtClientContext): Promise { return createAzureSubscriptionClient( context, (await import("@azure/arm-resources-subscriptions")).SubscriptionClient, diff --git a/src/vscode-bicep/src/azure/types.ts b/src/vscode-bicep/src/azure/types.ts index b7717f87ff2..416bf69b998 100644 --- a/src/vscode-bicep/src/azure/types.ts +++ b/src/vscode-bicep/src/azure/types.ts @@ -10,11 +10,7 @@ export interface AzureAccount { readonly onStatusChanged: Event; } -export type AzureLoginStatus = - | "Initializing" - | "LoggingIn" - | "LoggedIn" - | "LoggedOut"; +export type AzureLoginStatus = "Initializing" | "LoggingIn" | "LoggedIn" | "LoggedOut"; type DeploymentScopeBase = { portalUrl: string; @@ -45,11 +41,7 @@ export type DeploymentScope = DeploymentScopeBase< } >; -export type DeploymentScopeType = - | "resourceGroup" - | "subscription" - | "managementGroup" - | "tenant"; +export type DeploymentScopeType = "resourceGroup" | "subscription" | "managementGroup" | "tenant"; export interface IAzureUiManager { getAccessToken(scope: DeploymentScope): Promise; diff --git a/src/vscode-bicep/src/commands/ShowModuleSourceFileCommand.ts b/src/vscode-bicep/src/commands/ShowModuleSourceFileCommand.ts index eed8847ca00..fa146186bed 100644 --- a/src/vscode-bicep/src/commands/ShowModuleSourceFileCommand.ts +++ b/src/vscode-bicep/src/commands/ShowModuleSourceFileCommand.ts @@ -1,28 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import vscode, { Uri } from "vscode"; +import path from "path"; import { IActionContext } from "@microsoft/vscode-azext-utils"; -import { Command } from "./types"; +import vscode, { Uri } from "vscode"; import { decodeExternalSourceUri } from "../language/decodeExternalSourceUri"; -import path from "path"; +import { Command } from "./types"; export class ShowModuleSourceFileCommand implements Command { public readonly id = "bicep.internal.showModuleSourceFile"; public disclaimerShownThisSession = false; - public async execute( - context: IActionContext, - _documentUri: Uri, - targetUri: string, - ): Promise { + public async execute(context: IActionContext, _documentUri: Uri, targetUri: string): Promise { const uri = Uri.parse(targetUri, true); const doc = await vscode.workspace.openTextDocument(uri); const { requestedSourceFile } = decodeExternalSourceUri(uri); - context.telemetry.properties.extension = requestedSourceFile - ? path.extname(requestedSourceFile) - : ".json"; + context.telemetry.properties.extension = requestedSourceFile ? path.extname(requestedSourceFile) : ".json"; context.telemetry.properties.isCompiledJson = String(!requestedSourceFile); await vscode.window.showTextDocument(doc); diff --git a/src/vscode-bicep/src/commands/SuppressedWarningsManager.ts b/src/vscode-bicep/src/commands/SuppressedWarningsManager.ts index 720a460f1f3..6d8799f6c36 100644 --- a/src/vscode-bicep/src/commands/SuppressedWarningsManager.ts +++ b/src/vscode-bicep/src/commands/SuppressedWarningsManager.ts @@ -5,8 +5,7 @@ import { ConfigurationTarget, WorkspaceConfiguration } from "vscode"; import { getBicepConfiguration } from "../language/getBicepConfiguration"; export class SuppressedWarningsManager { - public static readonly suppressedWarningsConfigurationKey = - "suppressedWarnings"; + public static readonly suppressedWarningsConfigurationKey = "suppressedWarnings"; public static readonly keys = { decompileOnPasteWarning: "Decompile on paste", diff --git a/src/vscode-bicep/src/commands/build.ts b/src/vscode-bicep/src/commands/build.ts index e914718cf3e..7c34efef03b 100644 --- a/src/vscode-bicep/src/commands/build.ts +++ b/src/vscode-bicep/src/commands/build.ts @@ -14,10 +14,7 @@ export class BuildCommand implements Command { private readonly outputChannelManager: OutputChannelManager, ) {} - public async execute( - context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri = await findOrCreateActiveBicepFile( context, documentUri, @@ -25,13 +22,10 @@ export class BuildCommand implements Command { ); try { - const buildOutput: string = await this.client.sendRequest( - "workspace/executeCommand", - { - command: "build", - arguments: [documentUri.fsPath], - }, - ); + const buildOutput: string = await this.client.sendRequest("workspace/executeCommand", { + command: "build", + arguments: [documentUri.fsPath], + }); this.outputChannelManager.appendToOutputChannel(buildOutput); } catch (err) { this.client.error("Bicep build failed", parseError(err).message, true); diff --git a/src/vscode-bicep/src/commands/buildParams.ts b/src/vscode-bicep/src/commands/buildParams.ts index c631f48a3e1..f85c1e56c2c 100644 --- a/src/vscode-bicep/src/commands/buildParams.ts +++ b/src/vscode-bicep/src/commands/buildParams.ts @@ -14,10 +14,7 @@ export class BuildParamsCommand implements Command { private readonly outputChannelManager: OutputChannelManager, ) {} - public async execute( - context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri = await findOrCreateActiveBicepParamFile( context, documentUri, @@ -25,13 +22,10 @@ export class BuildParamsCommand implements Command { ); try { - const buildOutput: string = await this.client.sendRequest( - "workspace/executeCommand", - { - command: "buildParams", - arguments: [documentUri.fsPath], - }, - ); + const buildOutput: string = await this.client.sendRequest("workspace/executeCommand", { + command: "buildParams", + arguments: [documentUri.fsPath], + }); this.outputChannelManager.appendToOutputChannel(buildOutput); } catch (err) { this.client.error("Bicep build failed", parseError(err).message, true); diff --git a/src/vscode-bicep/src/commands/commandManager.ts b/src/vscode-bicep/src/commands/commandManager.ts index 551d1cadf50..11a00016060 100644 --- a/src/vscode-bicep/src/commands/commandManager.ts +++ b/src/vscode-bicep/src/commands/commandManager.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import * as azureextensionui from "@microsoft/vscode-azext-utils"; import assert from "assert"; +import * as azureextensionui from "@microsoft/vscode-azext-utils"; import * as fse from "fs-extra"; import { ExtensionContext, Uri } from "vscode"; import { Disposable } from "../utils/disposable"; @@ -15,9 +15,7 @@ export class CommandManager extends Disposable { super(); } - public async registerCommands( - ...commands: T - ): Promise { + public async registerCommands(...commands: T): Promise { commands.map((command) => this.registerCommand(command)); } @@ -44,10 +42,7 @@ export class CommandManager extends Disposable { // If the command is coming from a [command:xxx] inside a markdown file (e.g. from // a walkthrough), and the command contains a query string, the query string values // will be in an object in the next argument. - if ( - args[0] instanceof Object && - (<{ walkthrough?: string }>args[0])["walkthrough"] === "true" - ) { + if (args[0] instanceof Object && (<{ walkthrough?: string }>args[0])["walkthrough"] === "true") { // Marked as a walkthrough via query string in markdow isFromWalkthrough = true; } @@ -70,22 +65,16 @@ export class CommandManager extends Disposable { private validateCommand(command: T): void { if (!this._packageJson) { - this._packageJson = ( - fse.readJsonSync(this.extensionContext.asAbsolutePath("package.json")) - ); + this._packageJson = fse.readJsonSync(this.extensionContext.asAbsolutePath("package.json")); } - assert( - command.id.startsWith("bicep."), - `Command ID doesn't start with 'bicep.': ${command.id}`, - ); + assert(command.id.startsWith("bicep."), `Command ID doesn't start with 'bicep.': ${command.id}`); // Walkthrough commands shouldn't be shown in the command palette if (command.id.match(/gettingStarted/i)) { - const commandPaletteWhen: string | undefined = - this._packageJson.contributes?.menus?.commandPalette?.find( - (m) => m.command === command.id, - )?.when; + const commandPaletteWhen: string | undefined = this._packageJson.contributes?.menus?.commandPalette?.find( + (m) => m.command === command.id, + )?.when; assert( commandPaletteWhen === "never", `Internal error: Add an entry for '${command.id}' to package.json's contributes/menus/commandPalette array with a 'when' value of 'never'.`, diff --git a/src/vscode-bicep/src/commands/createConfigurationFile.ts b/src/vscode-bicep/src/commands/createConfigurationFile.ts index e12fde09216..9512e58e940 100644 --- a/src/vscode-bicep/src/commands/createConfigurationFile.ts +++ b/src/vscode-bicep/src/commands/createConfigurationFile.ts @@ -1,20 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { window, Uri, workspace } from "vscode"; -import { Command } from "./types"; -import { LanguageClient } from "vscode-languageclient/node"; -import { - IActionContext, - UserCancelledError, -} from "@microsoft/vscode-azext-utils"; import path from "path"; +import { IActionContext, UserCancelledError } from "@microsoft/vscode-azext-utils"; import * as fse from "fs-extra"; +import { Uri, window, workspace } from "vscode"; +import { LanguageClient } from "vscode-languageclient/node"; import { - GetRecommendedConfigLocationResult, - getRecommendedConfigLocationRequestType, CreateBicepConfigParams, + getRecommendedConfigLocationRequestType, + GetRecommendedConfigLocationResult, } from "../language/protocol"; +import { Command } from "./types"; const bicepConfig = "bicepconfig.json"; @@ -35,27 +32,17 @@ export class CreateBicepConfigurationFile implements Command { let recommendation: GetRecommendedConfigLocationResult; try { - recommendation = await this.client.sendRequest( - getRecommendedConfigLocationRequestType, - { - bicepFilePath: documentUri?.fsPath, - }, - ); + recommendation = await this.client.sendRequest(getRecommendedConfigLocationRequestType, { + bicepFilePath: documentUri?.fsPath, + }); } catch (err) { throw new Error("Failed determining recommended configuration location"); } if (recommendation.error || !recommendation.recommendedFolder) { - throw new Error( - `Could not determine recommended configuration location: ${ - recommendation.error ?? "Unknown" - }`, - ); + throw new Error(`Could not determine recommended configuration location: ${recommendation.error ?? "Unknown"}`); } - const recommendedPath = path.join( - recommendation.recommendedFolder, - bicepConfig, - ); + const recommendedPath = path.join(recommendation.recommendedFolder, bicepConfig); let selectedPath: string = recommendedPath; if (!suppressQuery) { @@ -74,9 +61,7 @@ export class CreateBicepConfigurationFile implements Command { if (path.basename(selectedPath) !== bicepConfig) { // Don't wait - void window.showErrorMessage( - `A Bicep configuration file must be named ${bicepConfig}`, - ); + void window.showErrorMessage(`A Bicep configuration file must be named ${bicepConfig}`); selectedPath = path.join(path.dirname(selectedPath), bicepConfig); } else { break; @@ -84,9 +69,7 @@ export class CreateBicepConfigurationFile implements Command { } } - context.telemetry.properties.usingRecommendedLocation = String( - selectedPath === recommendedPath, - ); + context.telemetry.properties.usingRecommendedLocation = String(selectedPath === recommendedPath); context.telemetry.properties.sameFolderAsBicep = String( recommendation.recommendedFolder === path.dirname(selectedPath), ); @@ -105,9 +88,7 @@ export class CreateBicepConfigurationFile implements Command { await window.showTextDocument(textDocument); return selectedPath; } else { - throw new Error( - "Configuration file was not created by the language server", - ); + throw new Error("Configuration file was not created by the language server"); } } } diff --git a/src/vscode-bicep/src/commands/decompile.ts b/src/vscode-bicep/src/commands/decompile.ts index 2c3484e9986..4fcbb54b9cb 100644 --- a/src/vscode-bicep/src/commands/decompile.ts +++ b/src/vscode-bicep/src/commands/decompile.ts @@ -1,11 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - IActionContext, - UserCancelledError, -} from "@microsoft/vscode-azext-utils"; import assert from "assert"; +import { IActionContext, UserCancelledError } from "@microsoft/vscode-azext-utils"; import * as fse from "fs-extra"; import vscode, { MessageItem, Uri, window } from "vscode"; import { DocumentUri, LanguageClient } from "vscode-languageclient/node"; @@ -56,19 +53,13 @@ export class DecompileCommand implements Command { // nothing to do } - public async execute( - context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri = documentUri ?? window.activeTextEditor?.document.uri; if (!documentUri) { - throw new Error( - "Please open a JSON ARM Template file before running this command", - ); + throw new Error("Please open a JSON ARM Template file before running this command"); } - const canDecompile = - await DecompileCommand.mightBeArmTemplateNoThrow(documentUri); + const canDecompile = await DecompileCommand.mightBeArmTemplateNoThrow(documentUri); if (!canDecompile) { this.outputChannelManager.appendToOutputChannel( `Cannot decompile "${documentUri.fsPath}" into Bicep because it does not appear to be an ARM template.`, @@ -79,24 +70,15 @@ export class DecompileCommand implements Command { const decompileParams: DecompileCommandParams = { jsonUri: documentUri.toString(), }; - const decompileResult: BicepDecompileCommandResult = - await this.client.sendRequest("workspace/executeCommand", { - command: "decompile", - arguments: [decompileParams], - }); - - this.outputChannelManager.appendToOutputChannel( - decompileResult.output.trimEnd(), - ); - context.telemetry.properties.decompileStatus = decompileResult.errorMessage - ? "failed" - : "success"; - context.telemetry.properties.countOutputFiles = String( - decompileResult.outputFiles.length, - ); - context.telemetry.properties.countConflictFiles = String( - decompileResult.conflictingOutputPaths.length, - ); + const decompileResult: BicepDecompileCommandResult = await this.client.sendRequest("workspace/executeCommand", { + command: "decompile", + arguments: [decompileParams], + }); + + this.outputChannelManager.appendToOutputChannel(decompileResult.output.trimEnd()); + context.telemetry.properties.decompileStatus = decompileResult.errorMessage ? "failed" : "success"; + context.telemetry.properties.countOutputFiles = String(decompileResult.outputFiles.length); + context.telemetry.properties.countConflictFiles = String(decompileResult.conflictingOutputPaths.length); if (decompileResult.errorMessage) { // Language server will have already shown the message @@ -117,27 +99,18 @@ export class DecompileCommand implements Command { outputFiles: decompileResult.outputFiles, overwrite, }; - const saveResult: BicepDecompileSaveCommandResult = - await this.client.sendRequest("workspace/executeCommand", { - command: "decompileSave", - arguments: [saveParams], - }); - context.telemetry.properties.saveStatus = decompileResult.errorMessage - ? "failed" - : "success"; - - this.outputChannelManager.appendToOutputChannel( - saveResult.output.trimEnd(), - ); + const saveResult: BicepDecompileSaveCommandResult = await this.client.sendRequest("workspace/executeCommand", { + command: "decompileSave", + arguments: [saveParams], + }); + context.telemetry.properties.saveStatus = decompileResult.errorMessage ? "failed" : "success"; + + this.outputChannelManager.appendToOutputChannel(saveResult.output.trimEnd()); } - public static async mightBeArmTemplateNoThrow( - documentUri: Uri, - ): Promise { + public static async mightBeArmTemplateNoThrow(documentUri: Uri): Promise { try { - const contents = await ( - await fse.readFile(documentUri.fsPath) - ).toString(); + const contents = await (await fse.readFile(documentUri.fsPath)).toString(); return /\$schema.*deploymenttemplate\.json/i.test(contents); } catch (err) { // ignore @@ -169,20 +142,13 @@ export class DecompileCommand implements Command { isCloseAffordance: true, }; - const conflictFilesWithQuotes = conflictingOutputPaths - .map((f) => `"${f}"`) - .join(", "); + const conflictFilesWithQuotes = conflictingOutputPaths.map((f) => `"${f}"`).join(", "); const message = isSingleFileDecompilation ? `Decompile output file already exists: ${conflictFilesWithQuotes}` : `There are multiple decompilation output files and the following already exist: ${conflictFilesWithQuotes}`; this.outputChannelManager.appendToOutputChannel(message.trimEnd()); - const result = await context.ui.showWarningMessage( - message, - overwriteAction, - createCopyAction, - cancelAction, - ); + const result = await context.ui.showWarningMessage(message, overwriteAction, createCopyAction, cancelAction); if (result === cancelAction) { this.outputChannelManager.appendToOutputChannel("Canceled."); throw new UserCancelledError("queryOverwrite"); @@ -190,12 +156,8 @@ export class DecompileCommand implements Command { assert(result === overwriteAction || result === createCopyAction); overwrite = result === overwriteAction; - this.outputChannelManager.appendToOutputChannel( - `Response: ${result.title}`, - ); - context.telemetry.properties.conflictResolution = overwrite - ? "overwrite" - : "copy"; + this.outputChannelManager.appendToOutputChannel(`Response: ${result.title}`); + context.telemetry.properties.conflictResolution = overwrite ? "overwrite" : "copy"; } return overwrite; diff --git a/src/vscode-bicep/src/commands/decompileParams.ts b/src/vscode-bicep/src/commands/decompileParams.ts index 9604bd664a9..9c827718372 100644 --- a/src/vscode-bicep/src/commands/decompileParams.ts +++ b/src/vscode-bicep/src/commands/decompileParams.ts @@ -1,17 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - IActionContext, - IAzureQuickPickItem, -} from "@microsoft/vscode-azext-utils"; +import assert from "assert"; +import * as path from "path"; +import { IActionContext, IAzureQuickPickItem, UserCancelledError } from "@microsoft/vscode-azext-utils"; +import * as fse from "fs-extra"; import vscode, { MessageItem, Uri, window } from "vscode"; import { DocumentUri, LanguageClient } from "vscode-languageclient/node"; import { OutputChannelManager } from "../utils/OutputChannelManager"; import { Command } from "./types"; -import * as fse from "fs-extra"; -import * as path from "path"; -import { UserCancelledError } from "@microsoft/vscode-azext-utils"; -import assert from "assert"; interface DecompileParamsCommandParams { jsonUri: DocumentUri; @@ -35,46 +31,36 @@ export class DecompileParamsCommand implements Command { private readonly outputChannelManager: OutputChannelManager, ) {} - public async execute( - context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri = documentUri ?? window.activeTextEditor?.document.uri; if (!documentUri) { - throw new Error( - "Please open a JSON Parameter file before running this command", - ); + throw new Error("Please open a JSON Parameter file before running this command"); } - const canDecompile = - await DecompileParamsCommand.mightBeArmParametersNoThrow(documentUri); + const canDecompile = await DecompileParamsCommand.mightBeArmParametersNoThrow(documentUri); if (!canDecompile) { this.outputChannelManager.appendToOutputChannel( `Cannot decompile "${documentUri.fsPath}" into Bicep because it does not appear to be an ARM template parameter file.`, ); - throw new UserCancelledError( - "Cannot decompile input because file provided is not a parameter file", - ); + throw new UserCancelledError("Cannot decompile input because file provided is not a parameter file"); } const bicepFileUri = await DecompileParamsCommand.selectBicepFile(context); const decompileParamsCommandParams: DecompileParamsCommandParams = { jsonUri: documentUri.path, - bicepUri: bicepFileUri - ? this.client.code2ProtocolConverter.asUri(bicepFileUri) - : undefined, + bicepUri: bicepFileUri ? this.client.code2ProtocolConverter.asUri(bicepFileUri) : undefined, }; - this.outputChannelManager.appendToOutputChannel( - `Decompiling file: ${documentUri.fsPath}`, - ); + this.outputChannelManager.appendToOutputChannel(`Decompiling file: ${documentUri.fsPath}`); - const decompileParamsResult: DecompileParamsCommandResult = - await this.client.sendRequest("workspace/executeCommand", { + const decompileParamsResult: DecompileParamsCommandResult = await this.client.sendRequest( + "workspace/executeCommand", + { command: "decompileParams", arguments: [decompileParamsCommandParams], - }); + }, + ); if (decompileParamsResult.errorMessage) { throw new Error(decompileParamsResult.errorMessage); @@ -86,41 +72,26 @@ export class DecompileParamsCommand implements Command { ).fsPath; if (await fse.pathExists(bicepparamPath)) { - const fileSaveOption = - await DecompileParamsCommand.getFileSaveOption(context); + const fileSaveOption = await DecompileParamsCommand.getFileSaveOption(context); if (fileSaveOption === "Copy") { - bicepparamPath = - await DecompileParamsCommand.getUniquePath(bicepparamPath); - this.outputChannelManager.appendToOutputChannel( - `Saving Decompiled file (copy): ${bicepparamPath}`, - ); + bicepparamPath = await DecompileParamsCommand.getUniquePath(bicepparamPath); + this.outputChannelManager.appendToOutputChannel(`Saving Decompiled file (copy): ${bicepparamPath}`); } if (fileSaveOption === "Overwrite") { - this.outputChannelManager.appendToOutputChannel( - `Overwriting Decompiled file: ${bicepparamPath}`, - ); + this.outputChannelManager.appendToOutputChannel(`Overwriting Decompiled file: ${bicepparamPath}`); } } else { - this.outputChannelManager.appendToOutputChannel( - `Saving Decompiled file: ${bicepparamPath}`, - ); + this.outputChannelManager.appendToOutputChannel(`Saving Decompiled file: ${bicepparamPath}`); } - await fse.writeFile( - bicepparamPath, - decompileParamsResult.decompiledBicepparamFile.contents, - ); + await fse.writeFile(bicepparamPath, decompileParamsResult.decompiledBicepparamFile.contents); } - public static async mightBeArmParametersNoThrow( - documentUri: Uri, - ): Promise { + public static async mightBeArmParametersNoThrow(documentUri: Uri): Promise { try { - const contents = await ( - await fse.readFile(documentUri.fsPath) - ).toString(); + const contents = await (await fse.readFile(documentUri.fsPath)).toString(); return /\$schema.*deploymentParameters\.json/i.test(contents); } catch (err) { // ignore @@ -129,9 +100,7 @@ export class DecompileParamsCommand implements Command { return false; } - private static async selectBicepFile( - context: IActionContext, - ): Promise { + private static async selectBicepFile(context: IActionContext): Promise { // eslint-disable-next-line no-constant-condition while (true) { const quickPickItems: IAzureQuickPickItem[] = [ @@ -145,25 +114,23 @@ export class DecompileParamsCommand implements Command { }, ]; - const result: IAzureQuickPickItem = - await context.ui.showQuickPick(quickPickItems, { - canPickMany: false, - placeHolder: `Link to a Bicep file?`, - }); + const result: IAzureQuickPickItem = await context.ui.showQuickPick(quickPickItems, { + canPickMany: false, + placeHolder: `Link to a Bicep file?`, + }); if (result.label === "None") { return undefined; } if (result.label === "Browse") { - const bicepPaths: Uri[] | undefined = - await vscode.window.showOpenDialog({ - canSelectMany: false, - openLabel: "Select Bicep File", - filters: { - "Bicep Files": ["bicep"], - }, - }); + const bicepPaths: Uri[] | undefined = await vscode.window.showOpenDialog({ + canSelectMany: false, + openLabel: "Select Bicep File", + filters: { + "Bicep Files": ["bicep"], + }, + }); if (bicepPaths) { assert(bicepPaths.length === 1, "Expected bicepPaths.length === 1"); return bicepPaths[0]; @@ -172,9 +139,7 @@ export class DecompileParamsCommand implements Command { } } - private static async getFileSaveOption( - context: IActionContext, - ): Promise<"Overwrite" | "Copy"> { + private static async getFileSaveOption(context: IActionContext): Promise<"Overwrite" | "Copy"> { const overwriteAction: MessageItem = { title: "Overwrite", }; @@ -204,17 +169,12 @@ export class DecompileParamsCommand implements Command { return optionPicked === overwriteAction ? "Overwrite" : "Copy"; } - private static async getUniquePath( - bicepparamPath: DocumentUri, - ): Promise { + private static async getUniquePath(bicepparamPath: DocumentUri): Promise { const parsedPath = path.parse(bicepparamPath); let appendNumber = 2; // eslint-disable-next-line no-constant-condition while (true) { - const uniquePath = path.join( - parsedPath.dir, - `${parsedPath.name}${appendNumber}${parsedPath.ext}`, - ); + const uniquePath = path.join(parsedPath.dir, `${parsedPath.name}${appendNumber}${parsedPath.ext}`); if (!(await fse.pathExists(uniquePath))) { return uniquePath; } diff --git a/src/vscode-bicep/src/commands/deploy.ts b/src/vscode-bicep/src/commands/deploy.ts index dec10aa7336..ecacc951c38 100644 --- a/src/vscode-bicep/src/commands/deploy.ts +++ b/src/vscode-bicep/src/commands/deploy.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import assert from "assert"; +import * as path from "path"; import { AccessToken } from "@azure/identity"; import { AzExtTreeDataProvider, @@ -9,15 +11,10 @@ import { ISubscriptionContext, parseError, } from "@microsoft/vscode-azext-utils"; -import assert from "assert"; -import moment from "moment"; import * as fse from "fs-extra"; -import * as path from "path"; +import moment from "moment"; import vscode, { commands, Uri } from "vscode"; -import { - LanguageClient, - TextDocumentIdentifier, -} from "vscode-languageclient/node"; +import { LanguageClient, TextDocumentIdentifier } from "vscode-languageclient/node"; import { BicepDeploymentParametersResponse, BicepDeploymentScopeParams, @@ -62,29 +59,18 @@ export class DeployCommand implements Command { private readonly treeManager: TreeManager, ) {} - public async execute( - context: IActionContext, - documentUri: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri: vscode.Uri | undefined): Promise { const deployId = Math.random().toString(); context.telemetry.properties.deployId = deployId; setOutputChannelManagerAtTheStartOfDeployment(this.outputChannelManager); - documentUri = await findOrCreateActiveBicepFile( - context, - documentUri, - "Choose which Bicep file to deploy", - ); + documentUri = await findOrCreateActiveBicepFile(context, documentUri, "Choose which Bicep file to deploy"); const documentPath = documentUri.fsPath; // Handle spaces/special characters in folder names. - const textDocument = TextDocumentIdentifier.create( - encodeURIComponent(documentUri.path), - ); - this.outputChannelManager.appendToOutputChannel( - `Preparing for deployment of ${documentPath}`, - ); + const textDocument = TextDocumentIdentifier.create(encodeURIComponent(documentUri.path)); + this.outputChannelManager.appendToOutputChannel(`Preparing for deployment of ${documentPath}`); context.errorHandling.suppressDisplay = true; @@ -92,39 +78,32 @@ export class DeployCommand implements Command { const bicepDeploymentScopeParams: BicepDeploymentScopeParams = { textDocument, }; - const deploymentScopeResponse: BicepDeploymentScopeResponse = - await this.client.sendRequest("workspace/executeCommand", { + const deploymentScopeResponse: BicepDeploymentScopeResponse = await this.client.sendRequest( + "workspace/executeCommand", + { command: "getDeploymentScope", arguments: [bicepDeploymentScopeParams], - }); + }, + ); const deploymentScope = deploymentScopeResponse?.scope; const template = deploymentScopeResponse?.template; if (!template) { this.outputChannelManager.appendToOutputChannel( - "Unable to deploy. Please fix below errors:\n " + - deploymentScopeResponse?.errorMessage, + "Unable to deploy. Please fix below errors:\n " + deploymentScopeResponse?.errorMessage, ); return; } context.telemetry.properties.targetScope = deploymentScope; this.outputChannelManager.appendToOutputChannel( - `Scope specified in ${path.basename( - documentPath, - )} -> ${deploymentScope}`, + `Scope specified in ${path.basename(documentPath)} -> ${deploymentScope}`, ); // Shows a treeView that allows user to log in to Azure. If the user is already logged in, then does nothing. const azLoginTreeItem: AzLoginTreeItem = new AzLoginTreeItem(); - const azExtTreeDataProvider = new AzExtTreeDataProvider( - azLoginTreeItem, - "", - ); - await azExtTreeDataProvider.showTreeItemPicker( - "", - context, - ); + const azExtTreeDataProvider = new AzExtTreeDataProvider(azLoginTreeItem, ""); + await azExtTreeDataProvider.showTreeItemPicker("", context); const fileName = path.basename(documentPath, ".bicep"); const options = { @@ -133,9 +112,7 @@ export class DeployCommand implements Command { }; let deploymentName = await context.ui.showInputBox(options); // Replace special characters with '_' - deploymentName = deploymentName - .replace(/[^a-z0-9\-_.!~*'()]/gi, "_") - .substring(0, 64); + deploymentName = deploymentName.replace(/[^a-z0-9\-_.!~*'()]/gi, "_").substring(0, 64); let deploymentStartResponse: BicepDeploymentStartResponse | undefined; @@ -171,23 +148,14 @@ export class DeployCommand implements Command { ); break; case "tenant": { - throw new Error( - "Tenant scope deployment is not currently supported.", - ); + throw new Error("Tenant scope deployment is not currently supported."); } default: { - throw new Error( - deploymentScopeResponse?.errorMessage ?? - "Unknown error determining target scope", - ); + throw new Error(deploymentScopeResponse?.errorMessage ?? "Unknown error determining target scope"); } } - this.sendDeployWaitForCompletionCommand( - deployId, - deploymentStartResponse, - documentPath, - ); + this.sendDeployWaitForCompletionCommand(deployId, deploymentStartResponse, documentPath); } catch (err) { let errorMessage: string; @@ -208,9 +176,7 @@ export class DeployCommand implements Command { }, ]; } else { - errorMessage = `Deployment failed for ${documentPath}. ${ - parseError(err).message - }`; + errorMessage = `Deployment failed for ${documentPath}. ${parseError(err).message}`; } this.outputChannelManager.appendToOutputChannel(errorMessage); throw err; @@ -226,10 +192,7 @@ export class DeployCommand implements Command { deploymentName: string, ): Promise { const managementGroupTreeItem = - await this.treeManager.azManagementGroupTreeItem.showTreeItemPicker( - "", - context, - ); + await this.treeManager.azManagementGroupTreeItem.showTreeItemPicker("", context); const managementGroupId = managementGroupTreeItem?.id; if (managementGroupId) { @@ -238,10 +201,7 @@ export class DeployCommand implements Command { }); if (location) { - const parameterFilePath = await this.selectParameterFile( - context, - documentUri, - ); + const parameterFilePath = await this.selectParameterFile(context, documentUri); return await this.sendDeployStartCommand( context, @@ -270,17 +230,11 @@ export class DeployCommand implements Command { deploymentName: string, ): Promise { const resourceGroupTreeItem = - await this.treeManager.azResourceGroupTreeItem.showTreeItemPicker( - "", - context, - ); + await this.treeManager.azResourceGroupTreeItem.showTreeItemPicker("", context); const resourceGroupId = resourceGroupTreeItem.id; if (resourceGroupId) { - const parameterFilePath = await this.selectParameterFile( - context, - documentUri, - ); + const parameterFilePath = await this.selectParameterFile(context, documentUri); return await this.sendDeployStartCommand( context, @@ -307,19 +261,12 @@ export class DeployCommand implements Command { deployId: string, deploymentName: string, ): Promise { - const locationTreeItem = - await this.treeManager.azLocationTree.showTreeItemPicker( - "", - context, - ); + const locationTreeItem = await this.treeManager.azLocationTree.showTreeItemPicker("", context); const location = locationTreeItem.label; const subscription = locationTreeItem.subscription; const subscriptionId = subscription.subscriptionPath; - const parameterFilePath = await this.selectParameterFile( - context, - documentUri, - ); + const parameterFilePath = await this.selectParameterFile(context, documentUri); return await this.sendDeployStartCommand( context, @@ -349,16 +296,12 @@ export class DeployCommand implements Command { ): Promise { if (!parametersFilePath) { context.telemetry.properties.parameterFileProvided = "false"; - this.outputChannelManager.appendToOutputChannel( - `No parameter file was provided`, - ); + this.outputChannelManager.appendToOutputChannel(`No parameter file was provided`); } else { context.telemetry.properties.parameterFileProvided = "true"; } - const accessToken: AccessToken = await subscription.credentials.getToken( - [], - ); + const accessToken: AccessToken = await subscription.credentials.getToken([]); if (accessToken) { const token = accessToken.token; @@ -375,19 +318,15 @@ export class DeployCommand implements Command { parametersFileName = undefined; updatedDeploymentParameters = []; } else { - [parametersFileName, updatedDeploymentParameters] = - await this.handleMissingAndDefaultParams( - context, - documentPath, - parametersFilePath, - template, - ); + [parametersFileName, updatedDeploymentParameters] = await this.handleMissingAndDefaultParams( + context, + documentPath, + parametersFilePath, + template, + ); // If all the parameters are of type secure, we will not show an option to create or update parameters file - if ( - updatedDeploymentParameters.length > 0 && - !updatedDeploymentParameters.every((x) => x.isSecure) - ) { + if (updatedDeploymentParameters.length > 0 && !updatedDeploymentParameters.every((x) => x.isSecure)) { parametersFileUpdateOption = await this.askToUpdateParametersFile( context, documentPath, @@ -419,30 +358,24 @@ export class DeployCommand implements Command { resourceManagerEndpointUrl, audience, }; - const deploymentStartResponse: BicepDeploymentStartResponse = - await this.client.sendRequest("workspace/executeCommand", { + const deploymentStartResponse: BicepDeploymentStartResponse = await this.client.sendRequest( + "workspace/executeCommand", + { command: "deploy/start", arguments: [deploymentStartParams], - }); + }, + ); // If user chose to create/update/overwrite a parameters file at the end of deployment flow, we'll // open it in vscode. - if ( - parametersFileUpdateOption !== ParametersFileUpdateOption.None && - parametersFileName && - parametersFilePath - ) { + if (parametersFileUpdateOption !== ParametersFileUpdateOption.None && parametersFileName && parametersFilePath) { if ( parametersFileUpdateOption === ParametersFileUpdateOption.Create || parametersFileUpdateOption === ParametersFileUpdateOption.Overwrite ) { - parametersFilePath = path.join( - path.dirname(documentPath), - parametersFileName, - ); + parametersFilePath = path.join(path.dirname(documentPath), parametersFileName); } - const parametersFileTextDocument = - await vscode.workspace.openTextDocument(parametersFilePath); + const parametersFileTextDocument = await vscode.workspace.openTextDocument(parametersFilePath); await vscode.window.showTextDocument(parametersFileTextDocument); } return deploymentStartResponse; @@ -456,24 +389,18 @@ export class DeployCommand implements Command { documentPath: string, ): void { if (deploymentStartResponse) { - this.outputChannelManager.appendToOutputChannel( - deploymentStartResponse.outputMessage, - ); + this.outputChannelManager.appendToOutputChannel(deploymentStartResponse.outputMessage); if (deploymentStartResponse.isSuccess) { - const viewDeploymentInPortalMessage = - deploymentStartResponse.viewDeploymentInPortalMessage; + const viewDeploymentInPortalMessage = deploymentStartResponse.viewDeploymentInPortalMessage; if (viewDeploymentInPortalMessage) { - this.outputChannelManager.appendToOutputChannel( - viewDeploymentInPortalMessage, - ); + this.outputChannelManager.appendToOutputChannel(viewDeploymentInPortalMessage); } - const bicepDeploymentWaitForCompletionParams: BicepDeploymentWaitForCompletionParams = - { - deployId, - documentPath, - }; + const bicepDeploymentWaitForCompletionParams: BicepDeploymentWaitForCompletionParams = { + deployId, + documentPath, + }; // Intentionally not waiting for completion to avoid blocking language server void this.client.sendRequest("workspace/executeCommand", { @@ -484,37 +411,31 @@ export class DeployCommand implements Command { } } - private async selectParameterFile( - context: IActionContext, - sourceUri: Uri, - ): Promise { + private async selectParameterFile(context: IActionContext, sourceUri: Uri): Promise { // eslint-disable-next-line no-constant-condition while (true) { let parameterFilePath: string; - const quickPickItems: IAzureQuickPickItem[] = - await this.createParameterFileQuickPickList( - path.dirname(sourceUri.fsPath), - ); - const result: IAzureQuickPickItem = - await context.ui.showQuickPick(quickPickItems, { - canPickMany: false, - placeHolder: `Select a parameter file`, - id: sourceUri.toString(), - }); + const quickPickItems: IAzureQuickPickItem[] = await this.createParameterFileQuickPickList( + path.dirname(sourceUri.fsPath), + ); + const result: IAzureQuickPickItem = await context.ui.showQuickPick(quickPickItems, { + canPickMany: false, + placeHolder: `Select a parameter file`, + id: sourceUri.toString(), + }); if (result.label === this._browse) { - const paramsPaths: Uri[] | undefined = - await vscode.window.showOpenDialog({ - canSelectMany: false, - defaultUri: sourceUri, - openLabel: "Select Parameter File", - filters: { - "All Parameter Files": ["json", "jsonc", "bicepparam"], - "JSON Files": ["json", "jsonc"], - "Bicepparam Files": ["bicepparam"], - }, - }); + const paramsPaths: Uri[] | undefined = await vscode.window.showOpenDialog({ + canSelectMany: false, + defaultUri: sourceUri, + openLabel: "Select Parameter File", + filters: { + "All Parameter Files": ["json", "jsonc", "bicepparam"], + "JSON Files": ["json", "jsonc"], + "Bicepparam Files": ["bicepparam"], + }, + }); if (paramsPaths) { assert(paramsPaths.length === 1, "Expected paramsPaths.length === 1"); parameterFilePath = paramsPaths[0].fsPath; @@ -533,16 +454,12 @@ export class DeployCommand implements Command { } } - private async validateIsValidParameterFile( - path: string, - showErrorMessage: boolean, - ): Promise { + private async validateIsValidParameterFile(path: string, showErrorMessage: boolean): Promise { if (path.endsWith(".bicepparam")) { return true; } - const expectedSchema = - "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"; + const expectedSchema = "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"; let message: string | undefined; let json: { $schema?: unknown } | undefined; @@ -563,10 +480,9 @@ export class DeployCommand implements Command { if (message) { if (showErrorMessage) { - await vscode.window.showErrorMessage( - `The selected file is not a valid parameters file. ${message}`, - { modal: true }, - ); + await vscode.window.showErrorMessage(`The selected file is not a valid parameters file. ${message}`, { + modal: true, + }); } return false; @@ -581,11 +497,13 @@ export class DeployCommand implements Command { parameterFilePath: string | undefined, template: string | undefined, ): Promise<[string, BicepUpdatedDeploymentParameter[]]> { - const bicepDeploymentParametersResponse: BicepDeploymentParametersResponse = - await this.client.sendRequest("workspace/executeCommand", { + const bicepDeploymentParametersResponse: BicepDeploymentParametersResponse = await this.client.sendRequest( + "workspace/executeCommand", + { command: "getDeploymentParameters", arguments: [documentPath, parameterFilePath, template], - }); + }, + ); if (bicepDeploymentParametersResponse.errorMessage) { throw new Error(bicepDeploymentParametersResponse.errorMessage); @@ -630,10 +548,7 @@ export class DeployCommand implements Command { } } - return [ - bicepDeploymentParametersResponse.parametersFileName, - updatedDeploymentParameters, - ]; + return [bicepDeploymentParametersResponse.parametersFileName, updatedDeploymentParameters]; } private async askToUpdateParametersFile( @@ -651,10 +566,7 @@ export class DeployCommand implements Command { placeholder = `Update ${parametersFileName} with values used in this deployment?`; } else { const folderContainingSourceFile = path.dirname(documentPath); - const parametersFilePath = path.join( - folderContainingSourceFile, - parametersFileName, - ); + const parametersFilePath = path.join(folderContainingSourceFile, parametersFileName); if (fse.existsSync(parametersFilePath)) { parametersFileUpdateOptionString = "Overwrite"; parametersFileUpdateOption = ParametersFileUpdateOption.Overwrite; @@ -666,17 +578,13 @@ export class DeployCommand implements Command { } } - const result: IAzureQuickPickItem = await _context.ui.showQuickPick( - this._yesNoQuickPickItems, - { - canPickMany: false, - placeHolder: placeholder, - suppressPersistence: true, - }, - ); + const result: IAzureQuickPickItem = await _context.ui.showQuickPick(this._yesNoQuickPickItems, { + canPickMany: false, + placeHolder: placeholder, + suppressPersistence: true, + }); - _context.telemetry.properties.parametersFileUpdateOption = - parametersFileUpdateOptionString; + _context.telemetry.properties.parametersFileUpdateOption = parametersFileUpdateOptionString; if (result === this._yes) { return parametersFileUpdateOption; } else { @@ -698,22 +606,16 @@ export class DeployCommand implements Command { quickPickItems.push(useExpressionValue); } const enterNewValue: IAzureQuickPickItem = { - label: localize( - "enterNewValueForParameter", - `Enter value for "${paramName}"`, - ), + label: localize("enterNewValueForParameter", `Enter value for "${paramName}"`), data: undefined, }; quickPickItems.push(enterNewValue); - const result: IAzureQuickPickItem = await _context.ui.showQuickPick( - quickPickItems, - { - canPickMany: false, - placeHolder: `Select value for parameter "${paramName}"`, - suppressPersistence: true, - }, - ); + const result: IAzureQuickPickItem = await _context.ui.showQuickPick(quickPickItems, { + canPickMany: false, + placeHolder: `Select value for parameter "${paramName}"`, + suppressPersistence: true, + }); if (result === enterNewValue) { const paramValue = await _context.ui.showInputBox({ @@ -726,9 +628,7 @@ export class DeployCommand implements Command { return undefined; } - private async createParameterFileQuickPickList( - bicepFolder: string, - ): Promise[]> { + private async createParameterFileQuickPickList(bicepFolder: string): Promise[]> { const noneQuickPickItem: IAzureQuickPickItem = { label: this._none, data: "", @@ -737,27 +637,18 @@ export class DeployCommand implements Command { label: this._browse, data: "", }; - let parameterFilesQuickPickList = [noneQuickPickItem].concat([ - browseQuickPickItem, - ]); + let parameterFilesQuickPickList = [noneQuickPickItem].concat([browseQuickPickItem]); - const jsonFilesInWorkspace = - await this.getParameterFilesInWorkspace(bicepFolder); - parameterFilesQuickPickList = - parameterFilesQuickPickList.concat(jsonFilesInWorkspace); + const jsonFilesInWorkspace = await this.getParameterFilesInWorkspace(bicepFolder); + parameterFilesQuickPickList = parameterFilesQuickPickList.concat(jsonFilesInWorkspace); return parameterFilesQuickPickList; } - private async getParameterFilesInWorkspace( - bicepFolder: string, - ): Promise[]> { + private async getParameterFilesInWorkspace(bicepFolder: string): Promise[]> { const quickPickItems: IAzureQuickPickItem[] = []; const workspaceParametersFiles = ( - await vscode.workspace.findFiles( - "**/*.{json,jsonc,bicepparam}", - undefined, - ) + await vscode.workspace.findFiles("**/*.{json,jsonc,bicepparam}", undefined) ).filter((f) => !!f.fsPath); workspaceParametersFiles.sort((a, b) => { @@ -775,22 +666,14 @@ export class DeployCommand implements Command { }); for (const uri of workspaceParametersFiles) { - if ( - !uri.fsPath.endsWith("biceppparam") && - !(await this.validateIsValidParameterFile(uri.fsPath, false)) - ) { + if (!uri.fsPath.endsWith("biceppparam") && !(await this.validateIsValidParameterFile(uri.fsPath, false))) { continue; } - const workspaceRoot: string | undefined = - vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath; - const relativePath = workspaceRoot - ? path.relative(workspaceRoot, uri.fsPath) - : path.basename(uri.fsPath); + const workspaceRoot: string | undefined = vscode.workspace.getWorkspaceFolder(uri)?.uri.fsPath; + const relativePath = workspaceRoot ? path.relative(workspaceRoot, uri.fsPath) : path.basename(uri.fsPath); const quickPickItem: IAzureQuickPickItem = { - label: `${ - uri.fsPath.endsWith("biceppparam") ? "$(bicepparam)" : "$(json)" - } ${relativePath}`, + label: `${uri.fsPath.endsWith("biceppparam") ? "$(bicepparam)" : "$(json)"} ${relativePath}`, data: uri.fsPath, id: uri.toString(), }; diff --git a/src/vscode-bicep/src/commands/deployHelper.ts b/src/vscode-bicep/src/commands/deployHelper.ts index 78386afdfdb..177001060f0 100644 --- a/src/vscode-bicep/src/commands/deployHelper.ts +++ b/src/vscode-bicep/src/commands/deployHelper.ts @@ -5,16 +5,12 @@ import { OutputChannelManager } from "../utils/OutputChannelManager"; let _outputChannelManager: OutputChannelManager; -export async function writeDeploymentOutputMessageToBicepOperationsOutputChannel( - outputMessage: string, -) { +export async function writeDeploymentOutputMessageToBicepOperationsOutputChannel(outputMessage: string) { if (_outputChannelManager) { _outputChannelManager.appendToOutputChannel(outputMessage); } } -export function setOutputChannelManagerAtTheStartOfDeployment( - outputChannelManager: OutputChannelManager, -) { +export function setOutputChannelManagerAtTheStartOfDeployment(outputChannelManager: OutputChannelManager) { _outputChannelManager = outputChannelManager; } diff --git a/src/vscode-bicep/src/commands/findOrCreateActiveBicepFile.ts b/src/vscode-bicep/src/commands/findOrCreateActiveBicepFile.ts index eaf04a761e4..18f3402210d 100644 --- a/src/vscode-bicep/src/commands/findOrCreateActiveBicepFile.ts +++ b/src/vscode-bicep/src/commands/findOrCreateActiveBicepFile.ts @@ -1,24 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import * as os from "os"; +import * as path from "path"; import { + DialogResponses, IActionContext, IAzureQuickPickItem, IAzureUserInput, TelemetryProperties, - DialogResponses, UserCancelledError, } from "@microsoft/vscode-azext-utils"; -import * as path from "path"; -import * as os from "os"; import * as fse from "fs-extra"; -import { compareStringsOrdinal } from "../utils/compareStringsOrdinal"; import { TextDocument, TextEditor, Uri, window, workspace } from "vscode"; -import { - bicepFileExtension, - bicepLanguageId, - bicepParamLanguageId, -} from "../language/constants"; +import { bicepFileExtension, bicepLanguageId, bicepParamLanguageId } from "../language/constants"; +import { compareStringsOrdinal } from "../utils/compareStringsOrdinal"; type TargetFile = | "rightClickOrMenu" @@ -52,10 +48,7 @@ export async function findOrCreateActiveBicepFile( const matchesLanguageId = (editor: TextEditor) => { const languageId = editor.document.languageId; - return ( - languageId === bicepLanguageId || - (includeBicepParam && languageId === bicepParamLanguageId) - ); + return languageId === bicepLanguageId || (includeBicepParam && languageId === bicepParamLanguageId); }; if (documentUri) { @@ -72,31 +65,22 @@ export async function findOrCreateActiveBicepFile( return activeEditor.document.uri; } - const globPattern = includeBicepParam - ? "**/*.{bicep, bicepparam}" - : "**/*.bicep"; + const globPattern = includeBicepParam ? "**/*.{bicep, bicepparam}" : "**/*.bicep"; - const workspaceBicepFiles = ( - await workspace.findFiles(globPattern, undefined) - ).filter((f) => !!f.fsPath); + const workspaceBicepFiles = (await workspace.findFiles(globPattern, undefined)).filter((f) => !!f.fsPath); const visibleBicepFiles = window.visibleTextEditors // List of the active editor in each editor tab group .filter(matchesLanguageId) .map((e) => e.document.uri); // Create deduped, sorted array of all available Bicep files (in workspace and visible editors) const map = new Map(); - workspaceBicepFiles - .concat(visibleBicepFiles) - .forEach((bf) => map.set(bf.fsPath, bf)); + workspaceBicepFiles.concat(visibleBicepFiles).forEach((bf) => map.set(bf.fsPath, bf)); const bicepFilesSorted = Array.from(map.values()); bicepFilesSorted.sort((a, b) => compareStringsOrdinal(a.path, b.path)); if (bicepFilesSorted.length === 1) { // Only a single Bicep file in the workspace/visible editors - choose it - properties.targetFile = - workspaceBicepFiles.length === 1 - ? "singleInWorkspace" - : "singleInVisibleEditors"; + properties.targetFile = workspaceBicepFiles.length === 1 ? "singleInWorkspace" : "singleInVisibleEditors"; return bicepFilesSorted[0]; } @@ -140,27 +124,20 @@ export async function findOrCreateActiveBicepParamFile( return activeEditor.document.uri; } - const workspaceBicepFiles = ( - await workspace.findFiles("**/*.bicepparam", undefined) - ).filter((f) => !!f.fsPath); + const workspaceBicepFiles = (await workspace.findFiles("**/*.bicepparam", undefined)).filter((f) => !!f.fsPath); const visibleBicepFiles = window.visibleTextEditors // List of the active editor in each editor tab group .filter((e) => e.document.languageId === bicepParamLanguageId) .map((e) => e.document.uri); // Create deduped, sorted array of all available Bicep files (in workspace and visible editors) const map = new Map(); - workspaceBicepFiles - .concat(visibleBicepFiles) - .forEach((bf) => map.set(bf.fsPath, bf)); + workspaceBicepFiles.concat(visibleBicepFiles).forEach((bf) => map.set(bf.fsPath, bf)); const bicepFilesSorted = Array.from(map.values()); bicepFilesSorted.sort((a, b) => compareStringsOrdinal(a.path, b.path)); if (bicepFilesSorted.length === 1) { // Only a single Bicep file in the workspace/visible editors - choose it - properties.targetFile = - workspaceBicepFiles.length === 1 - ? "singleInWorkspace" - : "singleInVisibleEditors"; + properties.targetFile = workspaceBicepFiles.length === 1 ? "singleInWorkspace" : "singleInVisibleEditors"; return bicepFilesSorted[0]; } @@ -187,11 +164,8 @@ function addFileQuickPick(items: IAzureQuickPickItem[], uri: Uri): void { return; } - const workspaceRoot: string | undefined = - workspace.getWorkspaceFolder(uri)?.uri.fsPath; - const relativePath = workspaceRoot - ? path.relative(workspaceRoot, uri.fsPath) - : path.basename(uri.fsPath); + const workspaceRoot: string | undefined = workspace.getWorkspaceFolder(uri)?.uri.fsPath; + const relativePath = workspaceRoot ? path.relative(workspaceRoot, uri.fsPath) : path.basename(uri.fsPath); items.push({ label: relativePath, @@ -201,10 +175,7 @@ function addFileQuickPick(items: IAzureQuickPickItem[], uri: Uri): void { }); } -async function queryCreateBicepFile( - ui: IAzureUserInput, - properties: Properties, -): Promise { +async function queryCreateBicepFile(ui: IAzureUserInput, properties: Properties): Promise { properties.targetFile = "new"; await ui.showWarningMessage( @@ -215,9 +186,7 @@ async function queryCreateBicepFile( // User said yes (otherwise would have thrown user cancel error) const startingFolder: Uri = - (workspace.workspaceFolders - ? workspace.workspaceFolders[0].uri - : undefined) ?? Uri.file(os.homedir()); + (workspace.workspaceFolders ? workspace.workspaceFolders[0].uri : undefined) ?? Uri.file(os.homedir()); const uri: Uri | undefined = await window.showSaveDialog({ title: "Save new Bicep file", defaultUri: Uri.joinPath(startingFolder, "main"), diff --git a/src/vscode-bicep/src/commands/forceModulesRestore.ts b/src/vscode-bicep/src/commands/forceModulesRestore.ts index d1db77b0090..09dce085cf6 100644 --- a/src/vscode-bicep/src/commands/forceModulesRestore.ts +++ b/src/vscode-bicep/src/commands/forceModulesRestore.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import vscode from "vscode"; -import { Command } from "./types"; import { LanguageClient } from "vscode-languageclient/node"; -import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import { OutputChannelManager } from "../utils/OutputChannelManager"; +import { Command } from "./types"; export class ForceModulesRestoreCommand implements Command { public readonly id = "bicep.forceModulesRestore"; @@ -13,10 +13,7 @@ export class ForceModulesRestoreCommand implements Command { private readonly outputChannelManager: OutputChannelManager, ) {} - public async execute( - _context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(_context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri ??= vscode.window.activeTextEditor?.document.uri; if (!documentUri) { @@ -38,27 +35,16 @@ export class ForceModulesRestoreCommand implements Command { try { this.outputChannelManager.appendToOutputChannel( - `Force restoring modules in ${ - documentUri.fsPath ?? documentUri.toString() - }...`, + `Force restoring modules in ${documentUri.fsPath ?? documentUri.toString()}...`, ); - const forceModulesRestoreOutput: string = await this.client.sendRequest( - "workspace/executeCommand", - { - command: "forceModulesRestore", - arguments: [documentUri.fsPath], - }, - ); - this.outputChannelManager.appendToOutputChannel( - forceModulesRestoreOutput, - ); + const forceModulesRestoreOutput: string = await this.client.sendRequest("workspace/executeCommand", { + command: "forceModulesRestore", + arguments: [documentUri.fsPath], + }); + this.outputChannelManager.appendToOutputChannel(forceModulesRestoreOutput); } catch (err) { - this.client.error( - "Restore (force) failed", - parseError(err).message, - true, - ); + this.client.error("Restore (force) failed", parseError(err).message, true); } } } diff --git a/src/vscode-bicep/src/commands/generateParams.ts b/src/vscode-bicep/src/commands/generateParams.ts index 7f9d459bea6..bdbb3bc9419 100644 --- a/src/vscode-bicep/src/commands/generateParams.ts +++ b/src/vscode-bicep/src/commands/generateParams.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import path from "path"; +import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import vscode, { Uri } from "vscode"; -import { Command } from "./types"; import { LanguageClient } from "vscode-languageclient/node"; -import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import { OutputChannelManager } from "../utils/OutputChannelManager"; import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; -import path from "path"; +import { Command } from "./types"; export class GenerateParamsCommand implements Command { public readonly id = "bicep.generateParams"; @@ -15,10 +15,7 @@ export class GenerateParamsCommand implements Command { private readonly outputChannelManager: OutputChannelManager, ) {} - public async execute( - context: IActionContext, - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext, documentUri?: vscode.Uri | undefined): Promise { documentUri = await findOrCreateActiveBicepFile( context, documentUri, @@ -28,55 +25,41 @@ export class GenerateParamsCommand implements Command { try { console.log(`Generating parameters file for ${documentUri.fsPath}...`); - const outputFormat = await vscode.window.showQuickPick( - ["json", "bicepparam"], - { title: "Please select the output format" }, - ); - const includeParams = await vscode.window.showQuickPick( - ["requiredonly", "all"], - { title: "Please select which parameters to include" }, - ); + const outputFormat = await vscode.window.showQuickPick(["json", "bicepparam"], { + title: "Please select the output format", + }); + const includeParams = await vscode.window.showQuickPick(["requiredonly", "all"], { + title: "Please select which parameters to include", + }); if (outputFormat === undefined || includeParams === undefined) { - throw new Error( - "Please select the output format and which parameters to include", - ); + throw new Error("Please select the output format and which parameters to include"); } context.telemetry.properties.format = outputFormat; context.telemetry.properties.includeParams = includeParams; - const generateParamsOutput: string = await this.client.sendRequest( - "workspace/executeCommand", - { - command: "generateParams", - arguments: [ - { - BicepFilePath: documentUri.fsPath, - OutputFormat: outputFormat, - IncludeParams: includeParams, - }, - ], - }, - ); + const generateParamsOutput: string = await this.client.sendRequest("workspace/executeCommand", { + command: "generateParams", + arguments: [ + { + BicepFilePath: documentUri.fsPath, + OutputFormat: outputFormat, + IncludeParams: includeParams, + }, + ], + }); this.outputChannelManager.appendToOutputChannel(generateParamsOutput); const filePath = path.parse(documentUri.fsPath); const openPath = Uri.file( - path.join( - filePath.dir, - `${filePath.name}.${ - outputFormat === "json" ? "parameters.json" : "bicepparam" - }`, - ), + path.join(filePath.dir, `${filePath.name}.${outputFormat === "json" ? "parameters.json" : "bicepparam"}`), ); const doc = await vscode.workspace.openTextDocument(openPath); await vscode.window.showTextDocument(doc); } catch (err) { - throw new Error( - `Generating parameters failed: ${parseError(err).message}`, - ); + throw new Error(`Generating parameters failed: ${parseError(err).message}`); } } } diff --git a/src/vscode-bicep/src/commands/gettingStarted/WalkthroughCreateBicepFileCommand.ts b/src/vscode-bicep/src/commands/gettingStarted/WalkthroughCreateBicepFileCommand.ts index 8e4553c39b5..e6f61e72d80 100644 --- a/src/vscode-bicep/src/commands/gettingStarted/WalkthroughCreateBicepFileCommand.ts +++ b/src/vscode-bicep/src/commands/gettingStarted/WalkthroughCreateBicepFileCommand.ts @@ -2,18 +2,11 @@ // Licensed under the MIT License. import * as os from "os"; -import * as fse from "fs-extra"; -import vscode, { - TextDocument, - TextEditor, - Uri, - window, - workspace, -} from "vscode"; import { UserCancelledError } from "@microsoft/vscode-azext-utils"; - -import { Command } from "../types"; +import * as fse from "fs-extra"; +import vscode, { TextDocument, TextEditor, Uri, window, workspace } from "vscode"; import { bicepFileExtension } from "../../language/constants"; +import { Command } from "../types"; export class WalkthroughCreateBicepFileCommand implements Command { public static id = "bicep.gettingStarted.createBicepFile"; @@ -24,13 +17,9 @@ export class WalkthroughCreateBicepFileCommand implements Command { } } -async function createAndOpenBicepFile( - fileContents: string, -): Promise { +async function createAndOpenBicepFile(fileContents: string): Promise { const folder: Uri = - (workspace.workspaceFolders - ? workspace.workspaceFolders[0].uri - : undefined) ?? Uri.file(os.homedir()); + (workspace.workspaceFolders ? workspace.workspaceFolders[0].uri : undefined) ?? Uri.file(os.homedir()); const uri: Uri | undefined = await window.showSaveDialog({ title: "Save new Bicep file", defaultUri: Uri.joinPath(folder, "main"), @@ -48,8 +37,5 @@ async function createAndOpenBicepFile( await fse.writeFile(path, fileContents, { encoding: "utf-8" }); const document: TextDocument = await workspace.openTextDocument(uri); - return await vscode.window.showTextDocument( - document, - vscode.ViewColumn.Beside, - ); + return await vscode.window.showTextDocument(document, vscode.ViewColumn.Beside); } diff --git a/src/vscode-bicep/src/commands/gettingStarted/WalkthroughOpenBicepFileCommand.ts b/src/vscode-bicep/src/commands/gettingStarted/WalkthroughOpenBicepFileCommand.ts index 917ab2f7f6c..8de07324ec1 100644 --- a/src/vscode-bicep/src/commands/gettingStarted/WalkthroughOpenBicepFileCommand.ts +++ b/src/vscode-bicep/src/commands/gettingStarted/WalkthroughOpenBicepFileCommand.ts @@ -2,21 +2,10 @@ // Licensed under the MIT License. import path from "path"; -import { - TextDocument, - Uri, - workspace, - window, - ViewColumn, - TextEditor, -} from "vscode"; -import { - IActionContext, - IAzureQuickPickItem, -} from "@microsoft/vscode-azext-utils"; - -import { Command } from "../types"; +import { IActionContext, IAzureQuickPickItem } from "@microsoft/vscode-azext-utils"; +import { TextDocument, TextEditor, Uri, ViewColumn, window, workspace } from "vscode"; import { bicepFileExtension } from "../../language/constants"; +import { Command } from "../types"; export class WalkthroughOpenBicepFileCommand implements Command { public static id = "bicep.gettingStarted.openBicepFile"; @@ -27,37 +16,28 @@ export class WalkthroughOpenBicepFileCommand implements Command { } } -async function queryAndOpenBicepFile( - context: IActionContext, -): Promise { +async function queryAndOpenBicepFile(context: IActionContext): Promise { const uri: Uri = await queryUserForBicepFile(context); const document: TextDocument = await workspace.openTextDocument(uri); return await window.showTextDocument(document, ViewColumn.Beside); } async function queryUserForBicepFile(context: IActionContext): Promise { - const foundBicepFiles = ( - await workspace.findFiles("**/*.bicep", undefined) - ).filter((f) => !!f.fsPath); + const foundBicepFiles = (await workspace.findFiles("**/*.bicep", undefined)).filter((f) => !!f.fsPath); if (foundBicepFiles.length === 0) { return await browseForFile(context); } - const entries: IAzureQuickPickItem[] = foundBicepFiles.map( - (u) => { - const workspaceRoot: string | undefined = - workspace.getWorkspaceFolder(u)?.uri.fsPath; - const relativePath = workspaceRoot - ? path.relative(workspaceRoot, u.fsPath) - : path.basename(u.fsPath); + const entries: IAzureQuickPickItem[] = foundBicepFiles.map((u) => { + const workspaceRoot: string | undefined = workspace.getWorkspaceFolder(u)?.uri.fsPath; + const relativePath = workspaceRoot ? path.relative(workspaceRoot, u.fsPath) : path.basename(u.fsPath); - return >{ - label: relativePath, - data: u, - }; - }, - ); + return >{ + label: relativePath, + data: u, + }; + }); const browse: IAzureQuickPickItem = { label: "Browse...", data: undefined, @@ -74,9 +54,7 @@ async function queryUserForBicepFile(context: IActionContext): Promise { if (response.data) { return response.data; } else { - throw new Error( - "Internal error: queryUserForBicepFile: response.data should be truthy", - ); + throw new Error("Internal error: queryUserForBicepFile: response.data should be truthy"); } } } diff --git a/src/vscode-bicep/src/commands/importKubernetesManifest.ts b/src/vscode-bicep/src/commands/importKubernetesManifest.ts index aedbb10b8a7..8ac9f2a8c45 100644 --- a/src/vscode-bicep/src/commands/importKubernetesManifest.ts +++ b/src/vscode-bicep/src/commands/importKubernetesManifest.ts @@ -1,20 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import vscode, { ViewColumn } from "vscode"; +import { LanguageClient } from "vscode-languageclient/node"; import { importKubernetesManifestRequestType } from "../language/protocol"; import { Command } from "./types"; -import { IActionContext, parseError } from "@microsoft/vscode-azext-utils"; -import { LanguageClient } from "vscode-languageclient/node"; export class ImportKubernetesManifestCommand implements Command { public readonly id = "bicep.importKubernetesManifest"; public constructor(private readonly client: LanguageClient) {} - public async execute( - context: IActionContext, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - documentUri?: vscode.Uri | undefined, - ): Promise { + public async execute(context: IActionContext): Promise { const manifestPath = await context.ui.showOpenDialog({ canSelectMany: false, openLabel: "Select Kubernetes Manifest File", @@ -22,16 +18,11 @@ export class ImportKubernetesManifestCommand implements Command { }); try { - const response = await this.client.sendRequest( - importKubernetesManifestRequestType, - { - manifestFilePath: manifestPath[0].fsPath, - }, - ); + const response = await this.client.sendRequest(importKubernetesManifestRequestType, { + manifestFilePath: manifestPath[0].fsPath, + }); - const document = await vscode.workspace.openTextDocument( - response.bicepFilePath, - ); + const document = await vscode.workspace.openTextDocument(response.bicepFilePath); await vscode.window.showTextDocument(document, ViewColumn.Active); } catch (err) { diff --git a/src/vscode-bicep/src/commands/insertResource.ts b/src/vscode-bicep/src/commands/insertResource.ts index 399cf6da091..33de046e8c4 100644 --- a/src/vscode-bicep/src/commands/insertResource.ts +++ b/src/vscode-bicep/src/commands/insertResource.ts @@ -1,21 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { IActionContext } from "@microsoft/vscode-azext-utils"; import vscode, { Uri, window, workspace } from "vscode"; -import { Command } from "./types"; import { LanguageClient } from "vscode-languageclient/node"; import { insertResourceRequestType } from "../language"; import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; -import { IActionContext } from "@microsoft/vscode-azext-utils"; +import { Command } from "./types"; export class InsertResourceCommand implements Command { public readonly id = "bicep.insertResource"; public constructor(private readonly client: LanguageClient) {} - public async execute( - context: IActionContext, - documentUri?: Uri, - ): Promise { + public async execute(context: IActionContext, documentUri?: Uri): Promise { documentUri = await findOrCreateActiveBicepFile( context, documentUri, @@ -34,11 +31,8 @@ export class InsertResourceCommand implements Command { } await this.client.sendNotification(insertResourceRequestType, { - textDocument: - this.client.code2ProtocolConverter.asTextDocumentIdentifier(document), - position: this.client.code2ProtocolConverter.asPosition( - editor.selection.start, - ), + textDocument: this.client.code2ProtocolConverter.asTextDocumentIdentifier(document), + position: this.client.code2ProtocolConverter.asPosition(editor.selection.start), resourceId: resourceId, }); } diff --git a/src/vscode-bicep/src/commands/pasteAsBicep.ts b/src/vscode-bicep/src/commands/pasteAsBicep.ts index 28857b22e57..114568c0ecb 100644 --- a/src/vscode-bicep/src/commands/pasteAsBicep.ts +++ b/src/vscode-bicep/src/commands/pasteAsBicep.ts @@ -1,43 +1,36 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import { + ConfigurationTarget, env, + MessageItem, + Position, + ProgressLocation, + Range, TextDocumentChangeEvent, TextDocumentChangeReason, Uri, window, workspace, WorkspaceEdit, - Range, - MessageItem, - ConfigurationTarget, - ProgressLocation, - Position, } from "vscode"; -import { Command } from "./types"; import { LanguageClient } from "vscode-languageclient/node"; -import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; -import { - callWithTelemetryAndErrorHandling, - IActionContext, - parseError, -} from "@microsoft/vscode-azext-utils"; -import { areEqualIgnoringWhitespace } from "../utils/areEqualIgnoringWhitespace"; -import { getTextAfterFormattingChanges } from "../utils/getTextAfterFormattingChanges"; +import { BicepDecompileForPasteCommandParams, BicepDecompileForPasteCommandResult } from "../language"; import { bicepConfigurationKeys, bicepLanguageId } from "../language/constants"; -import { - BicepDecompileForPasteCommandParams, - BicepDecompileForPasteCommandResult, -} from "../language"; -import { OutputChannelManager } from "../utils/OutputChannelManager"; import { getBicepConfiguration } from "../language/getBicepConfiguration"; -import { SuppressedWarningsManager } from "./SuppressedWarningsManager"; +import { areEqualIgnoringWhitespace } from "../utils/areEqualIgnoringWhitespace"; import { Disposable } from "../utils/disposable"; +import { getTextAfterFormattingChanges } from "../utils/getTextAfterFormattingChanges"; import { isEmptyOrWhitespace } from "../utils/isEmptyOrWhitespace"; -import { withProgressAfterDelay } from "../utils/withProgressAfterDelay"; import { getLogger } from "../utils/logger"; +import { OutputChannelManager } from "../utils/OutputChannelManager"; import { callWithTelemetryAndErrorHandlingOnlyOnErrors } from "../utils/telemetry"; +import { withProgressAfterDelay } from "../utils/withProgressAfterDelay"; +import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; +import { SuppressedWarningsManager } from "./SuppressedWarningsManager"; +import { Command } from "./types"; export class PasteAsBicepCommand implements Command { public readonly id = "bicep.pasteAsBicep"; @@ -51,28 +44,19 @@ export class PasteAsBicepCommand implements Command { // Nothing to do } - public async execute( - context: IActionContext, - documentUri?: Uri, - ): Promise { + public async execute(context: IActionContext, documentUri?: Uri): Promise { const logPrefix = "PasteAsBicep (command)"; let clipboardText: string | undefined; let finalPastedBicep: string | undefined; try { - documentUri = await findOrCreateActiveBicepFile( - context, - documentUri, - "Choose which Bicep file to paste into", - ); + documentUri = await findOrCreateActiveBicepFile(context, documentUri, "Choose which Bicep file to paste into"); const document = await workspace.openTextDocument(documentUri); const editor = await window.showTextDocument(document); if (editor?.document.languageId !== bicepLanguageId) { - throw new Error( - "Cannot paste as Bicep: Editor is not editing a Bicep document.", - ); + throw new Error("Cannot paste as Bicep: Editor is not editing a Bicep document."); } clipboardText = await env.clipboard.readText(); @@ -80,15 +64,11 @@ export class PasteAsBicepCommand implements Command { let rangeStart = documentUri.toString() === editor.document.uri.toString() ? editor.document.offsetAt(editor.selection.active) - : editor.document.offsetAt( - new Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), - ); + : editor.document.offsetAt(new Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)); let rangeEnd = documentUri.toString() === editor.document.uri.toString() ? editor.document.offsetAt(editor.selection.anchor) - : editor.document.offsetAt( - new Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER), - ); + : editor.document.offsetAt(new Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)); if (rangeEnd < rangeStart) { [rangeStart, rangeEnd] = [rangeEnd, rangeStart]; } @@ -119,9 +99,7 @@ export class PasteAsBicepCommand implements Command { if (result.errorMessage) { context.errorHandling.issueProperties.clipboardText = clipboardText; - throw new Error( - `Could not paste clipboard text as Bicep: ${result.errorMessage}`, - ); + throw new Error(`Could not paste clipboard text as Bicep: ${result.errorMessage}`); } // Note that unlike the copy/paste case, we *do* want to paste the Bicep even if the original @@ -133,9 +111,7 @@ export class PasteAsBicepCommand implements Command { builder.replace(editor.selection, finalPastedBicep ?? ""); }); } catch (err) { - getLogger().debug( - `${logPrefix}: Exception occurred: ${parseError(err).message}"`, - ); + getLogger().debug(`${logPrefix}: Exception occurred: ${parseError(err).message}"`); throw err; } finally { this.logPasteCompletion(logPrefix, clipboardText, finalPastedBicep); @@ -143,11 +119,7 @@ export class PasteAsBicepCommand implements Command { } public registerForPasteEvents(extension: Disposable) { - extension.register( - workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument.bind(this), - ), - ); + extension.register(workspace.onDidChangeTextDocument(this.onDidChangeTextDocument.bind(this))); } private async callDecompileForPaste( @@ -162,8 +134,7 @@ export class PasteAsBicepCommand implements Command { return await withProgressAfterDelay( { location: ProgressLocation.Notification, - title: - "Decompiling clipboard text into Bicep is taking longer than expected...", + title: "Decompiling clipboard text into Bicep is taking longer than expected...", }, async () => { const decompileParams: BicepDecompileForPasteCommandParams = { @@ -174,15 +145,16 @@ export class PasteAsBicepCommand implements Command { jsonContent, queryCanPaste, }; - const decompileResult: BicepDecompileForPasteCommandResult = - await this.client.sendRequest("workspace/executeCommand", { + const decompileResult: BicepDecompileForPasteCommandResult = await this.client.sendRequest( + "workspace/executeCommand", + { command: "decompileForPaste", arguments: [decompileParams], - }); + }, + ); context.telemetry.properties.pasteType = decompileResult.pasteType; - context.telemetry.properties.pasteContext = - decompileResult.pasteContext; + context.telemetry.properties.pasteContext = decompileResult.pasteContext; context.telemetry.properties.decompileId = decompileResult.decompileId; context.telemetry.properties.jsonSize = String(jsonContent.length); context.telemetry.properties.queryCanPaste = String(queryCanPaste); @@ -193,206 +165,153 @@ export class PasteAsBicepCommand implements Command { } private isAutoConvertOnPasteEnabled(): boolean { - return ( - getBicepConfiguration().get( - bicepConfigurationKeys.decompileOnPaste, - ) ?? true - ); + return getBicepConfiguration().get(bicepConfigurationKeys.decompileOnPaste) ?? true; } // Handle automatically converting to Bicep on paste // TODO: refactor - private async onDidChangeTextDocument( - e: TextDocumentChangeEvent, - ): Promise { + private async onDidChangeTextDocument(e: TextDocumentChangeEvent): Promise { const logPrefix = "PasteAsBicep (copy/paste)"; - await callWithTelemetryAndErrorHandlingOnlyOnErrors( - "copyPasteInBicepFile", - async () => { - if (!this.isAutoConvertOnPasteEnabled()) { + await callWithTelemetryAndErrorHandlingOnlyOnErrors("copyPasteInBicepFile", async () => { + if (!this.isAutoConvertOnPasteEnabled()) { + return; + } + + const editor = window.activeTextEditor; + if ( + e.reason !== TextDocumentChangeReason.Redo && + e.reason !== TextDocumentChangeReason.Undo && + e.document === editor?.document && + e.document.languageId === bicepLanguageId && + e.contentChanges.length === 1 + ) { + const contentChange = e.contentChanges[0]; + + // Ignore deletions and trivial changes + if (contentChange.text.length < 2 || isEmptyOrWhitespace(contentChange.text)) { return; } - const editor = window.activeTextEditor; + const clipboardText = await env.clipboard.readText(); + + // This edit was a paste if the clipboard text matches the inserted text (ignoring formatting) if ( - e.reason !== TextDocumentChangeReason.Redo && - e.reason !== TextDocumentChangeReason.Undo && - e.document === editor?.document && - e.document.languageId === bicepLanguageId && - e.contentChanges.length === 1 + clipboardText.length > 1 && + !isEmptyOrWhitespace(clipboardText) && // ... non-trivial changes only + areEqualIgnoringWhitespace(clipboardText, contentChange.text) ) { - const contentChange = e.contentChanges[0]; - - // Ignore deletions and trivial changes - if ( - contentChange.text.length < 2 || - isEmptyOrWhitespace(contentChange.text) - ) { - return; - } - - const clipboardText = await env.clipboard.readText(); - - // This edit was a paste if the clipboard text matches the inserted text (ignoring formatting) - if ( - clipboardText.length > 1 && - !isEmptyOrWhitespace(clipboardText) && // ... non-trivial changes only - areEqualIgnoringWhitespace(clipboardText, contentChange.text) - ) { - let finalPastedBicep: string | undefined; - - await callWithTelemetryAndErrorHandling( - "checkAutoPasteAsBicep", - async (contextCheckAutoPaste: IActionContext) => { - try { - contextCheckAutoPaste.telemetry.properties.autoPasteAsBicep = - "false"; - - // While we were awaiting async calls, the pasted text may have been formatted in the editor, get the new version - let formattedPastedText = getTextAfterFormattingChanges( + let finalPastedBicep: string | undefined; + + await callWithTelemetryAndErrorHandling( + "checkAutoPasteAsBicep", + async (contextCheckAutoPaste: IActionContext) => { + try { + contextCheckAutoPaste.telemetry.properties.autoPasteAsBicep = "false"; + + // While we were awaiting async calls, the pasted text may have been formatted in the editor, get the new version + let formattedPastedText = getTextAfterFormattingChanges( + contentChange.text, + e.document.getText(), + contentChange.rangeOffset, + ); + if (!formattedPastedText) { + getLogger().debug(`${logPrefix}: Couldn't get pasted text after editor format`); + return; + } + + // See if we can paste this text as Bicep + // (this call will log telemetry about the result) + const canPasteResult = await this.callDecompileForPaste( + contextCheckAutoPaste, + editor.document.uri, + editor.document.getText(), + contentChange.rangeOffset, + formattedPastedText.length, + clipboardText, + true, // queryCanPaste + ); + if (!canPasteResult.pasteType) { + // Nothing we know how to convert, or pasting is not allowed in this context + getLogger().debug(`${logPrefix}: pasteType empty`); + return; + } + + if (canPasteResult.pasteType === "bicepValue") { + // If the input was already a valid Bicep expression (i.e., the conversion looks the same as the original, once formatting + // changes are ignored), then skip the conversion, otherwise the user will see formatting changes when copying Bicep values + // to Bicep (e.g. [1] would get changed to a multi-line array). + // This will mainly happen with single-line arrays and objects, especially since the Newtonsoft parser accepts input that is + // JavaScript but not technically JSON, such as '{ abc: 1, def: 'def' }, but which also happens to be valid Bicep. + getLogger().debug(`${logPrefix}: Already bicep`); + return; + } + + // The clipboard contains JSON which we can convert into Bicep + // Start a new telemetry event to make tracking paste as Bicep more straightforward + contextCheckAutoPaste.telemetry.properties.autoPasteAsBicep = "true"; + await callWithTelemetryAndErrorHandling("autoPasteAsBicep", async (contextAutoPaste) => { + if (canPasteResult.errorMessage || !canPasteResult.bicep) { + // If we should be able to convert but there were errors in the JSON, show a message to the output window + this.outputChannelManager.appendToOutputChannel(canPasteResult.output); + const msg = `Could not convert pasted text into Bicep: ${canPasteResult.errorMessage}`; + this.outputChannelManager.appendToOutputChannel(msg); + getLogger().debug(`${logPrefix}: ${msg}`); + + // ... and register telemetry for the failure (don't show the error to the user again) + contextAutoPaste.telemetry.maskEntireErrorMessage = true; + contextAutoPaste.errorHandling.suppressDisplay = true; + throw new Error("Decompile error"); + } + + contextCheckAutoPaste.telemetry.properties.bicepSize = String(canPasteResult.bicep.length); + + formattedPastedText = getTextAfterFormattingChanges( contentChange.text, e.document.getText(), contentChange.rangeOffset, ); if (!formattedPastedText) { - getLogger().debug( - `${logPrefix}: Couldn't get pasted text after editor format`, - ); - return; - } - - // See if we can paste this text as Bicep - // (this call will log telemetry about the result) - const canPasteResult = await this.callDecompileForPaste( - contextCheckAutoPaste, - editor.document.uri, - editor.document.getText(), - contentChange.rangeOffset, - formattedPastedText.length, - clipboardText, - true, // queryCanPaste - ); - if (!canPasteResult.pasteType) { - // Nothing we know how to convert, or pasting is not allowed in this context - getLogger().debug(`${logPrefix}: pasteType empty`); + getLogger().debug(`${logPrefix}: Couldn't get pasted text after editor formatted it`); return; } - - if (canPasteResult.pasteType === "bicepValue") { - // If the input was already a valid Bicep expression (i.e., the conversion looks the same as the original, once formatting - // changes are ignored), then skip the conversion, otherwise the user will see formatting changes when copying Bicep values - // to Bicep (e.g. [1] would get changed to a multi-line array). - // This will mainly happen with single-line arrays and objects, especially since the Newtonsoft parser accepts input that is - // JavaScript but not technically JSON, such as '{ abc: 1, def: 'def' }, but which also happens to be valid Bicep. - getLogger().debug(`${logPrefix}: Already bicep`); - return; + if (!areEqualIgnoringWhitespace(formattedPastedText, clipboardText)) { + // Some other editor change must have happened, abort the conversion to Bicep + contextAutoPaste.errorHandling.suppressDisplay = true; + throw new Error("Editor changed"); } - // The clipboard contains JSON which we can convert into Bicep - // Start a new telemetry event to make tracking paste as Bicep more straightforward - contextCheckAutoPaste.telemetry.properties.autoPasteAsBicep = - "true"; - await callWithTelemetryAndErrorHandling( - "autoPasteAsBicep", - async (contextAutoPaste) => { - if ( - canPasteResult.errorMessage || - !canPasteResult.bicep - ) { - // If we should be able to convert but there were errors in the JSON, show a message to the output window - this.outputChannelManager.appendToOutputChannel( - canPasteResult.output, - ); - const msg = `Could not convert pasted text into Bicep: ${canPasteResult.errorMessage}`; - this.outputChannelManager.appendToOutputChannel(msg); - getLogger().debug(`${logPrefix}: ${msg}`); - - // ... and register telemetry for the failure (don't show the error to the user again) - contextAutoPaste.telemetry.maskEntireErrorMessage = - true; - contextAutoPaste.errorHandling.suppressDisplay = true; - throw new Error("Decompile error"); - } - - contextCheckAutoPaste.telemetry.properties.bicepSize = - String(canPasteResult.bicep.length); - - formattedPastedText = getTextAfterFormattingChanges( - contentChange.text, - e.document.getText(), - contentChange.rangeOffset, - ); - if (!formattedPastedText) { - getLogger().debug( - `${logPrefix}: Couldn't get pasted text after editor formatted it`, - ); - return; - } - if ( - !areEqualIgnoringWhitespace( - formattedPastedText, - clipboardText, - ) - ) { - // Some other editor change must have happened, abort the conversion to Bicep - contextAutoPaste.errorHandling.suppressDisplay = true; - throw new Error("Editor changed"); - } - - // All systems go - replace pasted JSON with Bicep - const edit = new WorkspaceEdit(); - const rangeOfFormattedPastedText = new Range( - e.document.positionAt(contentChange.rangeOffset), - e.document.positionAt( - contentChange.rangeOffset + - formattedPastedText.length, - ), - ); - edit.replace( - e.document.uri, - rangeOfFormattedPastedText, - canPasteResult.bicep, - ); - const success = await workspace.applyEdit(edit); - if (!success) { - throw new Error( - "Applying edit failed while converting pasted JSON to Bicep", - ); - } - - // Don't wait for disclaimer/warning to be dismissed because our telemetry won't fire until we return - void this.showWarning(contextAutoPaste, canPasteResult); - }, + // All systems go - replace pasted JSON with Bicep + const edit = new WorkspaceEdit(); + const rangeOfFormattedPastedText = new Range( + e.document.positionAt(contentChange.rangeOffset), + e.document.positionAt(contentChange.rangeOffset + formattedPastedText.length), ); + edit.replace(e.document.uri, rangeOfFormattedPastedText, canPasteResult.bicep); + const success = await workspace.applyEdit(edit); + if (!success) { + throw new Error("Applying edit failed while converting pasted JSON to Bicep"); + } - finalPastedBicep = canPasteResult.bicep; - } catch (err) { - getLogger().debug( - `${logPrefix}: Exception occurred: ${ - parseError(err).message - }"`, - ); - throw err; - } finally { - this.logPasteCompletion( - logPrefix, - clipboardText, - finalPastedBicep, - ); - } - }, - ); - } + // Don't wait for disclaimer/warning to be dismissed because our telemetry won't fire until we return + void this.showWarning(contextAutoPaste, canPasteResult); + }); + + finalPastedBicep = canPasteResult.bicep; + } catch (err) { + getLogger().debug(`${logPrefix}: Exception occurred: ${parseError(err).message}"`); + throw err; + } finally { + this.logPasteCompletion(logPrefix, clipboardText, finalPastedBicep); + } + }, + ); } - }, - ); + } + }); } - private async showWarning( - context: IActionContext, - pasteResult: BicepDecompileForPasteCommandResult, - ): Promise { + private async showWarning(context: IActionContext, pasteResult: BicepDecompileForPasteCommandResult): Promise { // Always show this message this.outputChannelManager.appendToOutputChannel( "The JSON pasted into the editor was automatically decompiled to Bicep. Use undo to revert.", @@ -409,17 +328,10 @@ export class PasteAsBicepCommand implements Command { } // Always show disclaimer in output window - this.outputChannelManager.appendToOutputChannel( - pasteResult.disclaimer, - true /*noFocus*/, - ); + this.outputChannelManager.appendToOutputChannel(pasteResult.disclaimer, true /*noFocus*/); // Show disclaimer in a dialog until disabled - if ( - this.suppressedWarningsManager.isWarningSuppressed( - SuppressedWarningsManager.keys.decompileOnPasteWarning, - ) - ) { + if (this.suppressedWarningsManager.isWarningSuppressed(SuppressedWarningsManager.keys.decompileOnPasteWarning)) { return; } @@ -431,21 +343,11 @@ export class PasteAsBicepCommand implements Command { }; this.disclaimerShownThisSession = true; - const result = await context.ui.showWarningMessage( - pasteResult.disclaimer, - dontShowAgain, - disable, - ); + const result = await context.ui.showWarningMessage(pasteResult.disclaimer, dontShowAgain, disable); if (result === dontShowAgain) { - await this.suppressedWarningsManager.suppressWarning( - SuppressedWarningsManager.keys.decompileOnPasteWarning, - ); + await this.suppressedWarningsManager.suppressWarning(SuppressedWarningsManager.keys.decompileOnPasteWarning); } else if (result === disable) { - await getBicepConfiguration().update( - bicepConfigurationKeys.decompileOnPaste, - false, - ConfigurationTarget.Global, - ); + await getBicepConfiguration().update(bicepConfigurationKeys.decompileOnPaste, false, ConfigurationTarget.Global); // Don't wait for this to finish void window.showWarningMessage( @@ -455,17 +357,11 @@ export class PasteAsBicepCommand implements Command { } // This allows our test code to know when a paste operation has been completed (in the case of handling CTRL+C/V) - private logPasteCompletion( - prefix: string, - clipboardText: string | undefined, - bicepText: string | undefined, - ): void { + private logPasteCompletion(prefix: string, clipboardText: string | undefined, bicepText: string | undefined): void { function format(s: string | undefined): string { return typeof s === "string" ? `"${s}"` : "undefined"; } - getLogger().debug( - `${prefix}: Result: ${format(clipboardText)} -> ${format(bicepText)}`, - ); + getLogger().debug(`${prefix}: Result: ${format(clipboardText)} -> ${format(bicepText)}`); } } diff --git a/src/vscode-bicep/src/commands/showDeployPane.ts b/src/vscode-bicep/src/commands/showDeployPane.ts index 0fa29d8010b..1f2f64d5ddb 100644 --- a/src/vscode-bicep/src/commands/showDeployPane.ts +++ b/src/vscode-bicep/src/commands/showDeployPane.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import vscode from "vscode"; import { IActionContext } from "@microsoft/vscode-azext-utils"; - +import vscode from "vscode"; import { DeployPaneViewManager } from "../panes/deploy"; -import { Command } from "./types"; import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; +import { Command } from "./types"; async function showDeployPane( context: IActionContext, diff --git a/src/vscode-bicep/src/commands/showSourceFromVisualizer.ts b/src/vscode-bicep/src/commands/showSourceFromVisualizer.ts index fd7fd57e440..f81f7513a5a 100644 --- a/src/vscode-bicep/src/commands/showSourceFromVisualizer.ts +++ b/src/vscode-bicep/src/commands/showSourceFromVisualizer.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import vscode from "vscode"; - import { BicepVisualizerViewManager } from "../visualizer"; import { Command } from "./types"; @@ -9,20 +8,13 @@ export class ShowSourceFromVisualizerCommand implements Command { public static readonly CommandId = "bicep.showSourceFromVisualizer"; public readonly id = ShowSourceFromVisualizerCommand.CommandId; - public constructor( - private readonly viewManager: BicepVisualizerViewManager, - ) {} + public constructor(private readonly viewManager: BicepVisualizerViewManager) {} public async execute(): Promise { if (this.viewManager.activeDocumentUri) { - const document = await vscode.workspace.openTextDocument( - this.viewManager.activeDocumentUri, - ); + const document = await vscode.workspace.openTextDocument(this.viewManager.activeDocumentUri); - return await vscode.window.showTextDocument( - document, - vscode.ViewColumn.One, - ); + return await vscode.window.showTextDocument(document, vscode.ViewColumn.One); } return undefined; diff --git a/src/vscode-bicep/src/commands/showVisualizer.ts b/src/vscode-bicep/src/commands/showVisualizer.ts index 09e07324510..39a7328aa70 100644 --- a/src/vscode-bicep/src/commands/showVisualizer.ts +++ b/src/vscode-bicep/src/commands/showVisualizer.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import vscode from "vscode"; import { IActionContext } from "@microsoft/vscode-azext-utils"; - +import vscode from "vscode"; import { BicepVisualizerViewManager } from "../visualizer"; -import { Command } from "./types"; import { findOrCreateActiveBicepFile } from "./findOrCreateActiveBicepFile"; +import { Command } from "./types"; async function showVisualizer( context: IActionContext, @@ -13,11 +12,7 @@ async function showVisualizer( documentUri: vscode.Uri | undefined, sideBySide = false, ) { - documentUri = await findOrCreateActiveBicepFile( - context, - documentUri, - "Choose which Bicep file to visualize", - ); + documentUri = await findOrCreateActiveBicepFile(context, documentUri, "Choose which Bicep file to visualize"); const viewColumn = sideBySide ? vscode.ViewColumn.Beside @@ -31,9 +26,7 @@ async function showVisualizer( export class ShowVisualizerCommand implements Command { public readonly id = "bicep.showVisualizer"; - public constructor( - private readonly viewManager: BicepVisualizerViewManager, - ) {} + public constructor(private readonly viewManager: BicepVisualizerViewManager) {} public async execute( context: IActionContext, @@ -46,9 +39,7 @@ export class ShowVisualizerCommand implements Command { export class ShowVisualizerToSideCommand implements Command { public readonly id = "bicep.showVisualizerToSide"; - public constructor( - private readonly viewManager: BicepVisualizerViewManager, - ) {} + public constructor(private readonly viewManager: BicepVisualizerViewManager) {} public async execute( context: IActionContext, diff --git a/src/vscode-bicep/src/commands/types.ts b/src/vscode-bicep/src/commands/types.ts index b43788abf22..58cfd303e88 100644 --- a/src/vscode-bicep/src/commands/types.ts +++ b/src/vscode-bicep/src/commands/types.ts @@ -12,9 +12,5 @@ export interface Command { * @param context Optionally used to control telemetry and error-handling behavior * @param args Optional arguments that are being passed to the command */ - execute( - context: IActionContext, - documentUri: Uri | undefined, - ...args: unknown[] - ): unknown | Promise; + execute(context: IActionContext, documentUri: Uri | undefined, ...args: unknown[]): unknown | Promise; } diff --git a/src/vscode-bicep/src/extension.ts b/src/vscode-bicep/src/extension.ts index 95f831bd8bb..43b67371ac8 100644 --- a/src/vscode-bicep/src/extension.ts +++ b/src/vscode-bicep/src/extension.ts @@ -3,64 +3,43 @@ import { registerAzureUtilsExtensionVariables } from "@microsoft/vscode-azext-azureutils"; import { registerUIExtensionVariables } from "@microsoft/vscode-azext-utils"; -import { - ExtensionContext, - ProgressLocation, - TextDocument, - TextEditor, - Uri, - window, - workspace, -} from "vscode"; +import { ExtensionContext, ProgressLocation, TextDocument, TextEditor, Uri, window, workspace } from "vscode"; import * as lsp from "vscode-languageclient/node"; +import { AzureUiManager } from "./azure/AzureUiManager"; +import { BuildCommand } from "./commands/build"; +import { BuildParamsCommand } from "./commands/buildParams"; +import { CommandManager } from "./commands/commandManager"; import { CreateBicepConfigurationFile } from "./commands/createConfigurationFile"; import { DecompileCommand } from "./commands/decompile"; +import { DecompileParamsCommand } from "./commands/decompileParams"; +import { DeployCommand } from "./commands/deploy"; +import { ForceModulesRestoreCommand } from "./commands/forceModulesRestore"; +import { GenerateParamsCommand } from "./commands/generateParams"; +import { WalkthroughCopyToClipboardCommand } from "./commands/gettingStarted/WalkthroughCopyToClipboardCommand"; +import { WalkthroughCreateBicepFileCommand } from "./commands/gettingStarted/WalkthroughCreateBicepFileCommand"; +import { WalkthroughOpenBicepFileCommand } from "./commands/gettingStarted/WalkthroughOpenBicepFileCommand"; import { ImportKubernetesManifestCommand } from "./commands/importKubernetesManifest"; +import { InsertResourceCommand } from "./commands/insertResource"; import { PasteAsBicepCommand } from "./commands/pasteAsBicep"; -import { - BicepExternalSourceContentProvider, - createLanguageService, - ensureDotnetRuntimeInstalled, -} from "./language"; -import { - ShowDeployPaneCommand, - ShowDeployPaneToSideCommand, -} from "./commands/showDeployPane"; +import { ShowDeployPaneCommand, ShowDeployPaneToSideCommand } from "./commands/showDeployPane"; +import { ShowModuleSourceFileCommand } from "./commands/ShowModuleSourceFileCommand"; +import { ShowSourceFromVisualizerCommand } from "./commands/showSourceFromVisualizer"; +import { ShowVisualizerCommand, ShowVisualizerToSideCommand } from "./commands/showVisualizer"; +import { SuppressedWarningsManager } from "./commands/SuppressedWarningsManager"; +import * as surveys from "./feedback/surveys"; +import { setGlobalStateKeysToSyncBetweenMachines } from "./globalState"; +import { BicepExternalSourceContentProvider, createLanguageService, ensureDotnetRuntimeInstalled } from "./language"; +import { bicepConfigurationPrefix, bicepLanguageId } from "./language/constants"; +import { BicepExternalSourceScheme } from "./language/decodeExternalSourceUri"; +import { DeployPaneViewManager } from "./panes/deploy"; import { TreeManager } from "./tree/TreeManager"; import { updateUiContext } from "./updateUiContext"; import { createAzExtOutputChannel } from "./utils/AzExtOutputChannel"; -import { OutputChannelManager } from "./utils/OutputChannelManager"; -import { BicepVisualizerViewManager } from "./visualizer"; -import { - bicepConfigurationPrefix, - bicepLanguageId, -} from "./language/constants"; -import { SuppressedWarningsManager } from "./commands/SuppressedWarningsManager"; import { Disposable } from "./utils/disposable"; -import { activateWithTelemetryAndErrorHandling } from "./utils/telemetry"; import { createLogger, getLogger, resetLogger } from "./utils/logger"; -import { - ShowVisualizerCommand, - ShowVisualizerToSideCommand, -} from "./commands/showVisualizer"; -import { ShowSourceFromVisualizerCommand } from "./commands/showSourceFromVisualizer"; -import { WalkthroughCopyToClipboardCommand } from "./commands/gettingStarted/WalkthroughCopyToClipboardCommand"; -import { WalkthroughCreateBicepFileCommand } from "./commands/gettingStarted/WalkthroughCreateBicepFileCommand"; -import { WalkthroughOpenBicepFileCommand } from "./commands/gettingStarted/WalkthroughOpenBicepFileCommand"; -import { ForceModulesRestoreCommand } from "./commands/forceModulesRestore"; -import { InsertResourceCommand } from "./commands/insertResource"; -import { DeployCommand } from "./commands/deploy"; -import { GenerateParamsCommand } from "./commands/generateParams"; -import { BuildParamsCommand } from "./commands/buildParams"; -import { BuildCommand } from "./commands/build"; -import { CommandManager } from "./commands/commandManager"; -import { setGlobalStateKeysToSyncBetweenMachines } from "./globalState"; -import * as surveys from "./feedback/surveys"; -import { DecompileParamsCommand } from "./commands/decompileParams"; -import { DeployPaneViewManager } from "./panes/deploy"; -import { AzureUiManager } from "./azure/AzureUiManager"; -import { BicepExternalSourceScheme } from "./language/decodeExternalSourceUri"; -import { ShowModuleSourceFileCommand } from "./commands/ShowModuleSourceFileCommand"; +import { OutputChannelManager } from "./utils/OutputChannelManager"; +import { activateWithTelemetryAndErrorHandling } from "./utils/telemetry"; +import { BicepVisualizerViewManager } from "./visualizer"; let languageClient: lsp.LanguageClient | null = null; @@ -77,14 +56,9 @@ class BicepExtension extends Disposable { } } -export async function activate( - extensionContext: ExtensionContext, -): Promise { +export async function activate(extensionContext: ExtensionContext): Promise { const extension = BicepExtension.create(extensionContext); - const outputChannel = createAzExtOutputChannel( - "Bicep", - bicepConfigurationPrefix, - ); + const outputChannel = createAzExtOutputChannel("Bicep", bicepConfigurationPrefix); extension.register(outputChannel); extension.register(createLogger(extensionContext, outputChannel)); @@ -104,16 +78,10 @@ export async function activate( }, async (progress) => { progress.report({ message: "Acquiring dotnet runtime" }); - const dotnetCommandPath = - await ensureDotnetRuntimeInstalled(actionContext); + const dotnetCommandPath = await ensureDotnetRuntimeInstalled(actionContext); progress.report({ message: "Launching language service" }); - languageClient = await createLanguageService( - actionContext, - extensionContext, - outputChannel, - dotnetCommandPath, - ); + languageClient = await createLanguageService(extensionContext, outputChannel, dotnetCommandPath); progress.report({ message: "Registering commands" }); // go2def links that point to the bicep cache will have the bicep-extsrc scheme in their document URIs @@ -131,23 +99,13 @@ export async function activate( // Show appropriate surveys surveys.showSurveys(extensionContext.globalState); - const viewManager = extension.register( - new BicepVisualizerViewManager( - extension.extensionUri, - languageClient, - ), - ); + const viewManager = extension.register(new BicepVisualizerViewManager(extension.extensionUri, languageClient)); const outputChannelManager = extension.register( - new OutputChannelManager( - "Bicep Operations", - bicepConfigurationPrefix, - ), + new OutputChannelManager("Bicep Operations", bicepConfigurationPrefix), ); - const treeManager = extension.register( - new TreeManager(outputChannelManager), - ); + const treeManager = extension.register(new TreeManager(outputChannelManager)); const deployPaneViewManager = extension.register( new DeployPaneViewManager( @@ -174,17 +132,10 @@ export async function activate( new GenerateParamsCommand(languageClient, outputChannelManager), new BuildParamsCommand(languageClient, outputChannelManager), new CreateBicepConfigurationFile(languageClient), - new DeployCommand( - languageClient, - outputChannelManager, - treeManager, - ), + new DeployCommand(languageClient, outputChannelManager, treeManager), new DecompileCommand(languageClient, outputChannelManager), new DecompileParamsCommand(languageClient, outputChannelManager), - new ForceModulesRestoreCommand( - languageClient, - outputChannelManager, - ), + new ForceModulesRestoreCommand(languageClient, outputChannelManager), new InsertResourceCommand(languageClient), pasteAsBicepCommand, new ShowDeployPaneCommand(deployPaneViewManager), @@ -203,12 +154,9 @@ export async function activate( pasteAsBicepCommand.registerForPasteEvents(extension); extension.register( - window.onDidChangeActiveTextEditor( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - async (editor: TextEditor | undefined) => { - await updateUiContext(editor?.document); - }, - ), + window.onDidChangeActiveTextEditor(async (editor: TextEditor | undefined) => { + await updateUiContext(editor?.document); + }), ); extension.register( diff --git a/src/vscode-bicep/src/feedback/surveys.ts b/src/vscode-bicep/src/feedback/surveys.ts index 6b6e5d7bd78..cb9eb9076b5 100644 --- a/src/vscode-bicep/src/feedback/surveys.ts +++ b/src/vscode-bicep/src/feedback/surveys.ts @@ -1,22 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - commands, - ConfigurationTarget, - MessageItem, - Uri, - window, -} from "vscode"; -import { parseError } from "@microsoft/vscode-azext-utils"; -import { IActionContext } from "@microsoft/vscode-azext-utils"; -import { callWithTelemetryAndErrorHandling } from "@microsoft/vscode-azext-utils"; import assert from "assert"; -import { GlobalState, GlobalStateKeys } from "../globalState"; import https from "https"; -import { daysToMs, monthsToDays } from "../utils/time"; -import { getBicepConfiguration } from "../language/getBicepConfiguration"; +import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from "@microsoft/vscode-azext-utils"; +import { commands, ConfigurationTarget, MessageItem, Uri, window } from "vscode"; +import { GlobalState, GlobalStateKeys } from "../globalState"; import { bicepConfigurationKeys } from "../language/constants"; +import { getBicepConfiguration } from "../language/getBicepConfiguration"; +import { daysToMs, monthsToDays } from "../utils/time"; // ====================================================== // DEBUGGING @@ -39,8 +31,7 @@ const hatsAnnualSurveyInfo: ISurveyInfo = { // Enough to be sure we don't ask again before the next survey, but still have flexibility about sending out the next // survey earlier than a year if we want to. postponeAfterTakenInDays: monthsToDays(6), - surveyPrompt: - "Do you have a few minutes to tell us about your experience with Bicep?", + surveyPrompt: "Do you have a few minutes to tell us about your experience with Bicep?", postponeForLaterInDays: 2 * 7, surveyStateKey: GlobalStateKeys.annualSurveyStateKey, }; @@ -55,50 +46,35 @@ export function showSurveys(globalState: GlobalState): void { checkShowSurvey(globalState, hatsAnnualSurveyInfo); } -export function checkShowSurvey( - globalState: GlobalState, - surveyInfo: ISurveyInfo, -): void { +export function checkShowSurvey(globalState: GlobalState, surveyInfo: ISurveyInfo): void { // Don't wait, run asynchronously - void callWithTelemetryAndErrorHandling( - "survey", - async (context: IActionContext) => { - let now = new Date(); - - // Check debugging settings - const debugNowDate = getBicepConfiguration().get(debugNowDateKey); - if (debugNowDate) { - now = new Date(debugNowDate); - assert.ok( - !isNaN(now.valueOf()), - `Invalid value for ${debugNowDateKey}`, - ); - console.warn( - `Debugging surveys: Pretending now is ${now.toLocaleString()}`, - ); - context.telemetry.properties.debugNowDate = debugNowDate; - context.telemetry.suppressAll = true; - } + void callWithTelemetryAndErrorHandling("survey", async (context: IActionContext) => { + let now = new Date(); + + // Check debugging settings + const debugNowDate = getBicepConfiguration().get(debugNowDateKey); + if (debugNowDate) { + now = new Date(debugNowDate); + assert.ok(!isNaN(now.valueOf()), `Invalid value for ${debugNowDateKey}`); + console.warn(`Debugging surveys: Pretending now is ${now.toLocaleString()}`); + context.telemetry.properties.debugNowDate = debugNowDate; + context.telemetry.suppressAll = true; + } - const debugTestLink = getBicepConfiguration().get( - debugSurveyLinkKeyPrefix + surveyInfo.akaLinkToSurvey, - ); - if (debugTestLink) { - console.warn( - `Debugging surveys: Replacing link ${surveyInfo.akaLinkToSurvey} with ${debugTestLink}`, - ); - surveyInfo.akaLinkToSurvey = debugTestLink; - } + const debugTestLink = getBicepConfiguration().get(debugSurveyLinkKeyPrefix + surveyInfo.akaLinkToSurvey); + if (debugTestLink) { + console.warn(`Debugging surveys: Replacing link ${surveyInfo.akaLinkToSurvey} with ${debugTestLink}`); + surveyInfo.akaLinkToSurvey = debugTestLink; + } - const survey = new Survey(globalState, surveyInfo); + const survey = new Survey(globalState, surveyInfo); - if (getBicepConfiguration().get(debugClearStateKey, false)) { - await survey.clearGlobalState(); - } + if (getBicepConfiguration().get(debugClearStateKey, false)) { + await survey.clearGlobalState(); + } - await survey.checkShowSurvey(context, now); - }, - ); + await survey.checkShowSurvey(context, now); + }); } export interface ISurveyInfo { @@ -141,26 +117,16 @@ export class Survey { /** * Shows the survey if it's available and timely, and the user doesn't opt out. */ - public async checkShowSurvey( - context: IActionContext, - now: Date, - ): Promise { + public async checkShowSurvey(context: IActionContext, now: Date): Promise { context.errorHandling.suppressDisplay = true; context.telemetry.properties.isActivationEvent = "true"; - context.telemetry.properties.akaLink = - this.surveyInfo.akaLinkToSurvey.replace("/", "-"); + context.telemetry.properties.akaLink = this.surveyInfo.akaLinkToSurvey.replace("/", "-"); const surveyState = this.getPersistedSurveyState(context, now); - const shouldAsk = await this.shouldAskToTakeSurvey( - context, - surveyState, - now, - ); + const shouldAsk = await this.shouldAskToTakeSurvey(context, surveyState, now); context.telemetry.properties.shouldAsk = shouldAsk; - console.info( - `Ask to take survey ${this.surveyInfo.akaLinkToSurvey}? ${shouldAsk}`, - ); + console.info(`Ask to take survey ${this.surveyInfo.akaLinkToSurvey}? ${shouldAsk}`); if (shouldAsk === "ask") { await this.askToTakeSurvey(context, surveyState, now); @@ -180,27 +146,20 @@ export class Survey { ): Promise<"ask" | "never" | "postponed" | "unavailable" | "alreadyTaken"> { { const areSurveysEnabled = this.areSurveysEnabled(); - context.telemetry.properties.areSurveysEnabled = - String(areSurveysEnabled); + context.telemetry.properties.areSurveysEnabled = String(areSurveysEnabled); if (!areSurveysEnabled) { return "never"; } context.telemetry.properties.lastTaken = state.lastTaken?.toUTCString(); - context.telemetry.properties.postonedUntil = - state.postponedUntil?.toUTCString(); + context.telemetry.properties.postonedUntil = state.postponedUntil?.toUTCString(); - if ( - state.postponedUntil && - state.postponedUntil.valueOf() > now.valueOf() - ) { + if (state.postponedUntil && state.postponedUntil.valueOf() > now.valueOf()) { return "postponed"; } if (state.lastTaken) { - const okayToAskAgainMs = - state.lastTaken.valueOf() + - daysToMs(this.surveyInfo.postponeAfterTakenInDays); + const okayToAskAgainMs = state.lastTaken.valueOf() + daysToMs(this.surveyInfo.postponeAfterTakenInDays); if (okayToAskAgainMs > now.valueOf()) { return "alreadyTaken"; } @@ -220,42 +179,28 @@ export class Survey { } } - private getPersistedSurveyState( - context: IActionContext, - now: Date, - ): ISurveyState { + private getPersistedSurveyState(context: IActionContext, now: Date): ISurveyState { let retrievedState: ISurveyState; const key = this.surveyInfo.surveyStateKey; try { - const persistedState = this.globalState.get( - key, - {}, - ); + const persistedState = this.globalState.get(key, {}); const state: ISurveyState = { - lastTaken: persistedState.lastTakenMs - ? new Date(persistedState.lastTakenMs) - : undefined, - postponedUntil: persistedState.postponedUntilMs - ? new Date(persistedState.postponedUntilMs) - : undefined, + lastTaken: persistedState.lastTakenMs ? new Date(persistedState.lastTakenMs) : undefined, + postponedUntil: persistedState.postponedUntilMs ? new Date(persistedState.postponedUntilMs) : undefined, }; if (state.lastTaken && state.lastTaken.valueOf() > now.valueOf()) { throw new Error("lastTaken is in the future"); } - if ( - isNaN(state.postponedUntil?.valueOf() ?? 0) || - isNaN(state.lastTaken?.valueOf() ?? 0) - ) { + if (isNaN(state.postponedUntil?.valueOf() ?? 0) || isNaN(state.lastTaken?.valueOf() ?? 0)) { throw new Error("Persisted survey state is invalid"); } retrievedState = state; } catch (err) { - context.telemetry.properties.depersistStateError = - parseError(err).message; + context.telemetry.properties.depersistStateError = parseError(err).message; retrievedState = {}; } @@ -293,56 +238,33 @@ export class Survey { }; const response = - (await this.inject?.showInformationMessage( - this.surveyInfo.surveyPrompt, - yes, - later, - neverAskAgain, - )) ?? dismissed; + (await this.inject?.showInformationMessage(this.surveyInfo.surveyPrompt, yes, later, neverAskAgain)) ?? dismissed; context.telemetry.properties.userResponse = String(response.id); if (response.id === neverAskAgain.id) { await this.disableSurveys(); } else if (response.id === later.id) { - await this.postponeSurvey( - state, - now, - this.surveyInfo.postponeForLaterInDays, - ); + await this.postponeSurvey(state, now, this.surveyInfo.postponeForLaterInDays); } else if (response.id === yes.id) { state.lastTaken = now; state.postponedUntil = undefined; await this.inject.launchSurvey(context, this.surveyInfo); } else { // Try again next time - assert( - response.id === dismissed.id, - `Unexpected response: ${response.id}`, - ); + assert(response.id === dismissed.id, `Unexpected response: ${response.id}`); } } - private static async launchSurvey( - this: void, - context: IActionContext, - surveyInfo: ISurveyInfo, - ): Promise { + private static async launchSurvey(this: void, context: IActionContext, surveyInfo: ISurveyInfo): Promise { context.telemetry.properties.launchSurvey = "true"; await commands.executeCommand( "vscode.open", - Uri.parse( - Survey.getFullSurveyLink(surveyInfo.akaLinkToSurvey), - true /*strict*/, - ), + Uri.parse(Survey.getFullSurveyLink(surveyInfo.akaLinkToSurvey), true /*strict*/), ); } - private async postponeSurvey( - state: ISurveyState, - now: Date, - days: number, - ): Promise { + private async postponeSurvey(state: ISurveyState, now: Date, days: number): Promise { assert(days > 0, "postponeSurvey: days must be positive"); let newDateMs = now.valueOf() + daysToMs(days); @@ -354,27 +276,21 @@ export class Survey { state.postponedUntil = newDate; } - public static async getIsSurveyAvailable( - this: void, - context: IActionContext, - fullLink: string, - ): Promise { + public static async getIsSurveyAvailable(this: void, context: IActionContext, fullLink: string): Promise { let linkStatus = "unknown"; try { - const statusCode: number | undefined = await new Promise( - (resolve, reject) => { - https - .get(fullLink, function (res) { - resolve(res.statusCode); - res.resume(); // Allow the response to be garbage collected - }) - .on("error", function (err) { - // Among other errors, we end up here if the Internet is not available - reject(err); - }); - }, - ); + const statusCode: number | undefined = await new Promise((resolve, reject) => { + https + .get(fullLink, function (res) { + resolve(res.statusCode); + res.resume(); // Allow the response to be garbage collected + }) + .on("error", function (err) { + // Among other errors, we end up here if the Internet is not available + reject(err); + }); + }); if (statusCode === 301 /* moved permanently */) { // The aka link exists and is active @@ -397,19 +313,13 @@ export class Survey { } public areSurveysEnabled(): boolean { - return this.inject - .provideBicepConfiguration() - .get(bicepConfigurationKeys.enableSurveys, true); + return this.inject.provideBicepConfiguration().get(bicepConfigurationKeys.enableSurveys, true); } private async disableSurveys(): Promise { return this.inject .provideBicepConfiguration() - .update( - bicepConfigurationKeys.enableSurveys, - false, - ConfigurationTarget.Global, - ); + .update(bicepConfigurationKeys.enableSurveys, false, ConfigurationTarget.Global); } public async clearGlobalState(): Promise { diff --git a/src/vscode-bicep/src/globalState.ts b/src/vscode-bicep/src/globalState.ts index 490aeaeae00..43d093db4c0 100644 --- a/src/vscode-bicep/src/globalState.ts +++ b/src/vscode-bicep/src/globalState.ts @@ -17,9 +17,7 @@ export type GlobalState = Memento & { /** * Call this once on activation to set the keys that should be synced between machines. */ -export function setGlobalStateKeysToSyncBetweenMachines( - globalState: GlobalState, -) { +export function setGlobalStateKeysToSyncBetweenMachines(globalState: GlobalState) { // Any keys not in this list will remain separate for each local machine. globalState.setKeysForSync([GlobalStateKeys.annualSurveyStateKey]); } diff --git a/src/vscode-bicep/src/language/bicepExternalSourceContentProvider.ts b/src/vscode-bicep/src/language/bicepExternalSourceContentProvider.ts index 83356910bcf..c64cd9d9e3f 100644 --- a/src/vscode-bicep/src/language/bicepExternalSourceContentProvider.ts +++ b/src/vscode-bicep/src/language/bicepExternalSourceContentProvider.ts @@ -1,24 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import * as path from "path"; import * as vscode from "vscode"; +import { Uri } from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; import { Disposable } from "../utils/disposable"; -import { - BicepExternalSourceParams, - bicepExternalSourceRequestType, -} from "./protocol"; -import * as path from "path"; -import { Uri } from "vscode"; -import { - BicepExternalSourceScheme, - decodeExternalSourceUri, -} from "./decodeExternalSourceUri"; +import { BicepExternalSourceScheme, decodeExternalSourceUri } from "./decodeExternalSourceUri"; +import { BicepExternalSourceParams, bicepExternalSourceRequestType } from "./protocol"; -export class BicepExternalSourceContentProvider - extends Disposable - implements vscode.TextDocumentContentProvider -{ +export class BicepExternalSourceContentProvider extends Disposable implements vscode.TextDocumentContentProvider { constructor(private readonly languageClient: LanguageClient) { super(); this.register( @@ -37,10 +28,7 @@ export class BicepExternalSourceContentProvider onDidChange?: vscode.Event | undefined; - async provideTextDocumentContent( - uri: vscode.Uri, - token: vscode.CancellationToken, - ): Promise { + async provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): Promise { // Ask the language server for the sources for the cached module const response = await this.languageClient.sendRequest( bicepExternalSourceRequestType, @@ -51,11 +39,8 @@ export class BicepExternalSourceContentProvider return response.error ? `// ${response.error}` : response.content ?? ""; } - private bicepExternalSourceRequest( - uri: vscode.Uri, - ): BicepExternalSourceParams { - const { moduleReference, requestedSourceFile } = - decodeExternalSourceUri(uri); + private bicepExternalSourceRequest(uri: vscode.Uri): BicepExternalSourceParams { + const { moduleReference, requestedSourceFile } = decodeExternalSourceUri(uri); return { target: moduleReference, requestedSourceFile, @@ -74,16 +59,11 @@ export class BicepExternalSourceContentProvider } } - throw new Error( - `The document URI '${uri.toString()}' is in an unexpected format.`, - ); + throw new Error(`The document URI '${uri.toString()}' is in an unexpected format.`); } private trySetExternalSourceLanguage(document: vscode.TextDocument): void { - if ( - document.uri.scheme === BicepExternalSourceScheme && - document.languageId === "plaintext" - ) { + if (document.uri.scheme === BicepExternalSourceScheme && document.languageId === "plaintext") { // The file is showing content from the bicep cache and the language is still set to plain text, so // we should try to correct it @@ -108,15 +88,11 @@ export class BicepExternalSourceContentProvider return "bicep"; } - const armToolsExtension = vscode.extensions.getExtension( - "msazurermtools.azurerm-vscode-tools", - ); + const armToolsExtension = vscode.extensions.getExtension("msazurermtools.azurerm-vscode-tools"); // if ARM Tools extension is installed and active, use a more specific language ID // otherwise, fall back to JSON - return armToolsExtension && armToolsExtension.isActive - ? "arm-template" - : "jsonc"; + return armToolsExtension && armToolsExtension.isActive ? "arm-template" : "jsonc"; } default: return "plaintext"; diff --git a/src/vscode-bicep/src/language/client.ts b/src/vscode-bicep/src/language/client.ts index 6bbc4f88c72..bb60cd79be4 100644 --- a/src/vscode-bicep/src/language/client.ts +++ b/src/vscode-bicep/src/language/client.ts @@ -1,17 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { existsSync } from "fs"; +import * as path from "path"; +import { callWithTelemetryAndErrorHandlingSync, IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import * as vscode from "vscode"; import * as lsp from "vscode-languageclient/node"; -import * as path from "path"; -import { existsSync } from "fs"; -import { getLogger } from "../utils/logger"; -import { - callWithTelemetryAndErrorHandlingSync, - IActionContext, - parseError, -} from "@microsoft/vscode-azext-utils"; import { Message, TransportKind } from "vscode-languageclient/node"; import { writeDeploymentOutputMessageToBicepOperationsOutputChannel } from "../commands/deployHelper"; +import { getLogger } from "../utils/logger"; import { bicepLanguageId } from "./constants"; const dotnetRuntimeVersion = "8.0"; @@ -67,7 +63,6 @@ function getServerStartupOptions( } export async function createLanguageService( - actionContext: IActionContext, context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, dotnetCommandPath: string, @@ -104,12 +99,7 @@ export async function createLanguageService( }, }; - const client = new lsp.LanguageClient( - bicepLanguageId, - "Bicep", - serverOptions, - clientOptions, - ); + const client = new lsp.LanguageClient(bicepLanguageId, "Bicep", serverOptions, clientOptions); client.registerProposedFeatures(); @@ -118,10 +108,7 @@ export async function createLanguageService( // To enable language server tracing, you MUST have a package setting named 'bicep.trace.server'; I was unable to find a way to enable it through code. // See https://github.com/microsoft/vscode-languageserver-node/blob/77c3a10a051ac619e4e3ef62a3865717702b64a3/client/src/common/client.ts#L3268 - client.onNotification( - "deploymentComplete", - writeDeploymentOutputMessageToBicepOperationsOutputChannel, - ); + client.onNotification("deploymentComplete", writeDeploymentOutputMessageToBicepOperationsOutputChannel); client.onNotification("bicep/triggerEditorCompletion", async () => { await vscode.commands.executeCommand("editor.action.triggerSuggest"); @@ -141,9 +128,7 @@ function getCustomDotnetRuntimePathConfig() { return acquireConfig.filter((x) => x.extensionId === extensionId)[0]; } -export async function ensureDotnetRuntimeInstalled( - actionContext: IActionContext, -): Promise { +export async function ensureDotnetRuntimeInstalled(actionContext: IActionContext): Promise { getLogger().info("Acquiring dotnet runtime..."); const customDotnetRuntimePathConfig = getCustomDotnetRuntimePathConfig(); @@ -156,13 +141,10 @@ export async function ensureDotnetRuntimeInstalled( ); } - const result = await vscode.commands.executeCommand<{ dotnetPath: string }>( - "dotnet.acquire", - { - version: dotnetRuntimeVersion, - requestingExtensionId: extensionId, - }, - ); + const result = await vscode.commands.executeCommand<{ dotnetPath: string }>("dotnet.acquire", { + version: dotnetRuntimeVersion, + requestingExtensionId: extensionId, + }); if (!result) { // Suppress the 'Report Issue' button - we want people to use the dialog displayed by the .NET installer extension. @@ -197,9 +179,7 @@ function ensureLanguageServerExists(context: vscode.ExtensionContext): string { context.asAbsolutePath(packagedServerPath); // Packaged server. if (!existsSync(languageServerPath)) { - throw new Error( - `Language server does not exist at '${languageServerPath}'.`, - ); + throw new Error(`Language server does not exist at '${languageServerPath}'.`); } return path.resolve(languageServerPath); @@ -209,52 +189,29 @@ function configureTelemetry(client: lsp.LanguageClient) { const startTime = Date.now(); const defaultErrorHandler = client.createDefaultErrorHandler(); - client.onTelemetry( - (telemetryData: { - eventName: string; - properties: { [key: string]: string | undefined }; - }) => { - callWithTelemetryAndErrorHandlingSync( - telemetryData.eventName, - (telemetryActionContext) => { - telemetryActionContext.errorHandling.suppressDisplay = true; - telemetryActionContext.telemetry.properties = - telemetryData.properties; - }, - ); - }, - ); + client.onTelemetry((telemetryData: { eventName: string; properties: { [key: string]: string | undefined } }) => { + callWithTelemetryAndErrorHandlingSync(telemetryData.eventName, (telemetryActionContext) => { + telemetryActionContext.errorHandling.suppressDisplay = true; + telemetryActionContext.telemetry.properties = telemetryData.properties; + }); + }); client.clientOptions.errorHandler = { - error( - error: Error, - message: Message | undefined, - count: number | undefined, - ) { - callWithTelemetryAndErrorHandlingSync( - "bicep.lsp-error", - (context: IActionContext) => { - context.telemetry.properties.jsonrpcMessage = message - ? message.jsonrpc - : ""; - context.telemetry.measurements.secondsSinceStart = - (Date.now() - startTime) / 1000; - - throw new Error(`Error: ${parseError(error).message}`); - }, - ); + error(error: Error, message: Message | undefined, count: number | undefined) { + callWithTelemetryAndErrorHandlingSync("bicep.lsp-error", (context: IActionContext) => { + context.telemetry.properties.jsonrpcMessage = message ? message.jsonrpc : ""; + context.telemetry.measurements.secondsSinceStart = (Date.now() - startTime) / 1000; + + throw new Error(`Error: ${parseError(error).message}`); + }); return defaultErrorHandler.error(error, message, count); }, closed() { - callWithTelemetryAndErrorHandlingSync( - "bicep.lsp-error", - (context: IActionContext) => { - context.telemetry.measurements.secondsSinceStart = - (Date.now() - startTime) / 1000; + callWithTelemetryAndErrorHandlingSync("bicep.lsp-error", (context: IActionContext) => { + context.telemetry.measurements.secondsSinceStart = (Date.now() - startTime) / 1000; - throw new Error(`Connection closed`); - }, - ); + throw new Error(`Connection closed`); + }); return defaultErrorHandler.closed(); }, }; diff --git a/src/vscode-bicep/src/language/decodeExternalSourceUri.ts b/src/vscode-bicep/src/language/decodeExternalSourceUri.ts index 0d52fcac39c..be830674d6e 100644 --- a/src/vscode-bicep/src/language/decodeExternalSourceUri.ts +++ b/src/vscode-bicep/src/language/decodeExternalSourceUri.ts @@ -26,9 +26,7 @@ export function decodeExternalSourceUri(uri: vscode.Uri): ExternalSource { // bicep-extsrc:{title}?{module-reference}[#{source-file-relative-path}] const title = decodeURIComponent(uri.path); const moduleReference = decodeURIComponent(uri.query); - let requestedSourceFile: string | undefined = decodeURIComponent( - uri.fragment, - ); + let requestedSourceFile: string | undefined = decodeURIComponent(uri.fragment); if (requestedSourceFile === "") { requestedSourceFile = undefined; diff --git a/src/vscode-bicep/src/language/getBicepConfiguration.ts b/src/vscode-bicep/src/language/getBicepConfiguration.ts index c49976c067c..1428489c910 100644 --- a/src/vscode-bicep/src/language/getBicepConfiguration.ts +++ b/src/vscode-bicep/src/language/getBicepConfiguration.ts @@ -4,8 +4,6 @@ import { ConfigurationScope, workspace, WorkspaceConfiguration } from "vscode"; import { bicepConfigurationPrefix } from "./constants"; -export function getBicepConfiguration( - scope?: ConfigurationScope, -): WorkspaceConfiguration { +export function getBicepConfiguration(scope?: ConfigurationScope): WorkspaceConfiguration { return workspace.getConfiguration(bicepConfigurationPrefix, scope); } diff --git a/src/vscode-bicep/src/language/protocol.ts b/src/vscode-bicep/src/language/protocol.ts index 863b9672826..93afd69cab6 100644 --- a/src/vscode-bicep/src/language/protocol.ts +++ b/src/vscode-bicep/src/language/protocol.ts @@ -202,10 +202,9 @@ export interface InsertResourceParams { resourceId: string; } -export const insertResourceRequestType = new ProtocolNotificationType< - InsertResourceParams, - void ->("textDocument/insertResource"); +export const insertResourceRequestType = new ProtocolNotificationType( + "textDocument/insertResource", +); export interface ImportKubernetesManifestRequest { manifestFilePath: string; @@ -259,13 +258,7 @@ export interface BicepDecompileForPasteCommandResult { errorMessage?: string; pasteContext?: "none" | "string"; // undefined if can't be pasted - pasteType: - | undefined - | "fullTemplate" - | "resource" - | "resourceList" - | "jsonValue" - | "bicepValue"; + pasteType: undefined | "fullTemplate" | "resource" | "resourceList" | "jsonValue" | "bicepValue"; bicep?: string; disclaimer?: string; } diff --git a/src/vscode-bicep/src/panes/deploy/app/components/App.tsx b/src/vscode-bicep/src/panes/deploy/app/components/App.tsx index ad1ffc54f0b..b2bc470dcf1 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/App.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/App.tsx @@ -1,19 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { FC, useState } from "react"; import { VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"; +import { FC, useState } from "react"; + import "./index.css"; + import { ParamData } from "../../models"; +import { useAzure } from "./hooks/useAzure"; import { useMessageHandler } from "./hooks/useMessageHandler"; -import { WhatIfChangesView } from "./sections/WhatIfChangesView"; +import { LocalDeployOperations, LocalDeployOutputs, LocalDeployResult } from "./localDeploy"; import { DeploymentOperationsView } from "./sections/DeploymentOperationsView"; import { DeploymentOutputsView } from "./sections/DeploymentOutputsView"; -import { ResultsView } from "./sections/ResultsView"; -import { ParametersInputView } from "./sections/ParametersInputView"; -import { useAzure } from "./hooks/useAzure"; import { DeploymentScopeInputView } from "./sections/DeploymentScopeInputView"; import { FormSection } from "./sections/FormSection"; -import { LocalDeployOperations, LocalDeployOutputs, LocalDeployResult } from "./localDeploy"; +import { ParametersInputView } from "./sections/ParametersInputView"; +import { ResultsView } from "./sections/ResultsView"; +import { WhatIfChangesView } from "./sections/WhatIfChangesView"; export const App: FC = () => { const [errorMessage, setErrorMessage] = useState(); @@ -24,7 +26,7 @@ export const App: FC = () => { acquireAccessToken: messages.acquireAccessToken, templateMetadata: messages.templateMetadata, parametersMetadata: messages.paramsMetadata, - setErrorMessage + setErrorMessage, }); function setParamValue(key: string, data: ParamData) { @@ -39,128 +41,154 @@ export const App: FC = () => { const azureDisabled = !messages.scope || !messages.templateMetadata || azure.running; async function handleDeployClick() { - messages.publishTelemetry('deployPane/deploy', {}); + messages.publishTelemetry("deployPane/deploy", {}); await azure.deploy(); } async function handleValidateClick() { - messages.publishTelemetry('deployPane/validate', {}); + messages.publishTelemetry("deployPane/validate", {}); await azure.validate(); } async function handleWhatIfClick() { - messages.publishTelemetry('deployPane/whatIf', {}); + messages.publishTelemetry("deployPane/whatIf", {}); await azure.whatIf(); } async function handleLocalDeployClick() { - messages.publishTelemetry('deployPane/localDeploy', {}); + messages.publishTelemetry("deployPane/localDeploy", {}); messages.startLocalDeploy(); } if (!messages.messageState.initialized) { - return ( - - ); + return ; } - const showLocalDeployControls = messages.messageState.localDeployEnabled && + const showLocalDeployControls = + messages.messageState.localDeployEnabled && // if there's an error, this'll cause sourceFilePath to be empty - we still want to show the controls to display the error - (errorMessage || messages.paramsMetadata.sourceFilePath?.endsWith('.bicepparam')); + (errorMessage || messages.paramsMetadata.sourceFilePath?.endsWith(".bicepparam")); return (
- {!messages.messageState.localDeployEnabled && <> - -
- - The Bicep Deployment Pane is an experimental feature. -
- Documentation is available here. Please raise issues or feature requests here. -
-
- - - - - - {errorMessage &&
- - {errorMessage} -
} -
- Deploy - Validate - What-If -
- {azure.running && } -
- - {messages.scope && <> - - - - - } - } - - {messages.messageState.localDeployEnabled && <> - -
- - Local Deployment is an experimental feature. -
-
- {showLocalDeployControls && <> + {!messages.messageState.localDeployEnabled && ( + <> + +
+ + The Bicep Deployment Pane is an experimental feature. +
+ Documentation is available{" "} + here. Please raise + issues or feature requests here. +
+
+ + + onPickParametersFile={messages.pickParamsFile} + /> - {errorMessage &&
- - {errorMessage} -
} + {errorMessage && ( +
+ + {errorMessage} +
+ )}
- Deploy + + Deploy + + + Validate + + + What-If +
- {localDeployRunning && } + {azure.running && }
- {!localDeployRunning && messages.localDeployResult && <> - - - - } - } - {!showLocalDeployControls && <> -
- Local Deployment is only currently supported for .bicepparam files. Relaunch this pane for a .bicepparam file. -
- } - } + {messages.scope && ( + <> + + + + + + )} + + )} + + {messages.messageState.localDeployEnabled && ( + <> + +
+ + Local Deployment is an experimental feature. +
+
+ {showLocalDeployControls && ( + <> + + + + {errorMessage && ( +
+ + {errorMessage} +
+ )} +
+ + Deploy + +
+ {localDeployRunning && } +
+ + {!localDeployRunning && messages.localDeployResult && ( + <> + + + + + )} + + )} + {!showLocalDeployControls && ( + <> +
+ Local Deployment is only currently supported for .bicepparam files. Relaunch this pane for a .bicepparam + file. +
+ + )} + + )}
); }; function createNewIssueUrl() { - const title = 'Deployment Pane: ' - const labels = ['story: deploy pane'] + const title = "Deployment Pane: "; + const labels = ["story: deploy pane"]; const body = ` `; - return `https://github.com/Azure/bicep/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${encodeURIComponent(labels.join(','))}`; -} \ No newline at end of file + return `https://github.com/Azure/bicep/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${encodeURIComponent(labels.join(","))}`; +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/ParamInputBox.tsx b/src/vscode-bicep/src/panes/deploy/app/components/ParamInputBox.tsx index d5bff29579f..ef5551cae68 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/ParamInputBox.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/ParamInputBox.tsx @@ -1,4 +1,13 @@ -import { VSCodeButton, VSCodeCheckbox, VSCodeDropdown, VSCodeOption, VSCodeTextArea, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import { + VSCodeButton, + VSCodeCheckbox, + VSCodeDropdown, + VSCodeOption, + VSCodeTextArea, + VSCodeTextField, +} from "@vscode/webview-ui-toolkit/react"; import { FC } from "react"; import { ParamData, ParamDefinition } from "../../models"; @@ -14,7 +23,7 @@ export const ParamInputBox: FC = (props) => { const { name, defaultValue, type } = definition; const { value } = data; - function handleValueChange(value: any) { + function handleValueChange(value: unknown) { onChangeData({ ...data, value }); } @@ -24,25 +33,23 @@ export const ParamInputBox: FC = (props) => { function getInputBox() { switch (type) { - case 'bool': + case "bool": return ( - handleValueChange(!value)} - disabled={disabled}> + handleValueChange(!value)} disabled={disabled}> {name} ); - case 'int': + case "int": return ( handleValueChange(parseInt((e.currentTarget as HTMLInputElement).value, 10))} - disabled={disabled}> + onChange={(e) => handleValueChange(parseInt((e.currentTarget as HTMLInputElement).value, 10))} + disabled={disabled} + > {name} ); - case 'string': + case "string": if (definition.allowedValues) { const dropdownHtmlId = `param-input-${name.toLowerCase()}`; return ( @@ -50,9 +57,10 @@ export const ParamInputBox: FC = (props) => { handleValueChange((e.currentTarget as HTMLSelectElement).value)} - disabled={disabled}> - {definition.allowedValues.map(option => ( + onChange={(e) => handleValueChange((e.currentTarget as HTMLSelectElement).value)} + disabled={disabled} + > + {definition.allowedValues.map((option) => ( {option} @@ -63,9 +71,10 @@ export const ParamInputBox: FC = (props) => { } else { return ( handleValueChange((e.currentTarget as HTMLInputElement).value)} - disabled={disabled}> + value={`${value ?? ""}`} + onChange={(e) => handleValueChange((e.currentTarget as HTMLInputElement).value)} + disabled={disabled} + > {name} ); @@ -75,9 +84,10 @@ export const ParamInputBox: FC = (props) => { handleValueChange(JSON.parse((e.currentTarget as HTMLInputElement).value))} - disabled={disabled}> + value={value ? JSON.stringify(value, null, 2) : ""} + onChange={(e) => handleValueChange(JSON.parse((e.currentTarget as HTMLInputElement).value))} + disabled={disabled} + > {name} ); @@ -87,11 +97,11 @@ export const ParamInputBox: FC = (props) => { return ( {getInputBox()} - {(defaultValue !== undefined && value !== defaultValue) && ( + {defaultValue !== undefined && value !== defaultValue && ( Reset to default )} ); -} \ No newline at end of file +}; diff --git a/src/vscode-bicep/src/panes/deploy/app/components/hooks/useAzure.ts b/src/vscode-bicep/src/panes/deploy/app/components/hooks/useAzure.ts index 8ef43b13336..6b0263b8e30 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/hooks/useAzure.ts +++ b/src/vscode-bicep/src/panes/deploy/app/components/hooks/useAzure.ts @@ -1,23 +1,23 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { useState } from "react"; +import { + CloudError, + Deployment, + DeploymentOperation, + ResourceManagementClient, + WhatIfChange, +} from "@azure/arm-resources"; import { RestError } from "@azure/core-rest-pipeline"; +import { AccessToken, TokenCredential } from "@azure/identity"; +import { useState } from "react"; import { - DeployResult, DeploymentScope, + DeployResult, ParamData, ParametersMetadata, TemplateMetadata, UntypedError, } from "../../../models"; -import { AccessToken, TokenCredential } from "@azure/identity"; -import { - CloudError, - Deployment, - DeploymentOperation, - ResourceManagementClient, - WhatIfChange, -} from "@azure/arm-resources"; export interface UseAzureProps { scope?: DeploymentScope; @@ -28,13 +28,7 @@ export interface UseAzureProps { } export function useAzure(props: UseAzureProps) { - const { - scope, - templateMetadata, - parametersMetadata, - acquireAccessToken, - setErrorMessage, - } = props; + const { scope, templateMetadata, parametersMetadata, acquireAccessToken, setErrorMessage } = props; const deploymentName = "bicep-deploy"; const [operations, setOperations] = useState(); const [whatIfChanges, setWhatIfChanges] = useState(); @@ -52,23 +46,16 @@ export function useAzure(props: UseAzureProps) { ? scope.associatedSubscriptionId : scope.subscriptionId; - return new ResourceManagementClient( - tokenProvider, - authenticatedSubscriptionId, - { - userAgentOptions: { - userAgentPrefix: "bicepdeploypane", - }, + return new ResourceManagementClient(tokenProvider, authenticatedSubscriptionId, { + userAgentOptions: { + userAgentPrefix: "bicepdeploypane", }, - ); + }); } async function doDeploymentOperation( scope: DeploymentScope, - operation: ( - armClient: ResourceManagementClient, - deployment: Deployment, - ) => Promise, + operation: (armClient: ResourceManagementClient, deployment: Deployment) => Promise, ) { if (!templateMetadata) { return; @@ -79,11 +66,7 @@ export function useAzure(props: UseAzureProps) { clearState(); setRunning(true); - const deployment = getDeploymentProperties( - scope, - templateMetadata, - parametersMetadata.parameters, - ); + const deployment = getDeploymentProperties(scope, templateMetadata, parametersMetadata.parameters); const accessToken = await acquireAccessToken(); const armClient = getArmClient(scope, accessToken); await operation(armClient, deployment); @@ -102,10 +85,7 @@ export function useAzure(props: UseAzureProps) { await doDeploymentOperation(scope, async (client, deployment) => { const updateOperations = async () => { const operations = []; - const result = client.deploymentOperations.listAtScope( - getScopeId(scope), - deploymentName, - ); + const result = client.deploymentOperations.listAtScope(getScopeId(scope), deploymentName); for await (const page of result.byPage()) { operations.push(...page); } @@ -114,11 +94,7 @@ export function useAzure(props: UseAzureProps) { let poller; try { - poller = await client.deployments.beginCreateOrUpdateAtScope( - getScopeId(scope), - deploymentName, - deployment, - ); + poller = await client.deployments.beginCreateOrUpdateAtScope(getScopeId(scope), deploymentName, deployment); while (!poller.isDone()) { await updateOperations(); @@ -176,12 +152,7 @@ export function useAzure(props: UseAzureProps) { await doDeploymentOperation(scope, async (client, deployment) => { try { - const response = await beginWhatIfAndWait( - client, - scope, - deploymentName, - deployment, - ); + const response = await beginWhatIfAndWait(client, scope, deploymentName, deployment); setResult({ success: !response.error, @@ -239,8 +210,7 @@ function getDeploymentProperties( } } - const location = - scope.scopeType !== "resourceGroup" ? scope.location : undefined; + const location = scope.scopeType !== "resourceGroup" ? scope.location : undefined; return { location, @@ -273,26 +243,21 @@ async function beginWhatIfAndWait( ) { switch (scope.scopeType) { case "resourceGroup": - return await client.deployments.beginWhatIfAndWait( - scope.resourceGroup, - deploymentName, - deployment, - ); + return await client.deployments.beginWhatIfAndWait(scope.resourceGroup, deploymentName, deployment); case "subscription": - return await client.deployments.beginWhatIfAtSubscriptionScopeAndWait( - deploymentName, - { ...deployment, location: scope.location }, - ); + return await client.deployments.beginWhatIfAtSubscriptionScopeAndWait(deploymentName, { + ...deployment, + location: scope.location, + }); case "managementGroup": - return await client.deployments.beginWhatIfAtManagementGroupScopeAndWait( - scope.managementGroup, - deploymentName, - { ...deployment, location: scope.location }, - ); + return await client.deployments.beginWhatIfAtManagementGroupScopeAndWait(scope.managementGroup, deploymentName, { + ...deployment, + location: scope.location, + }); case "tenant": - return await client.deployments.beginWhatIfAtTenantScopeAndWait( - deploymentName, - { ...deployment, location: scope.location }, - ); + return await client.deployments.beginWhatIfAtTenantScopeAndWait(deploymentName, { + ...deployment, + location: scope.location, + }); } } diff --git a/src/vscode-bicep/src/panes/deploy/app/components/hooks/useMessageHandler.ts b/src/vscode-bicep/src/panes/deploy/app/components/hooks/useMessageHandler.ts index 32467defa50..6b3cc367b12 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/hooks/useMessageHandler.ts +++ b/src/vscode-bicep/src/panes/deploy/app/components/hooks/useMessageHandler.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { AccessToken } from "@azure/identity"; +import { TelemetryProperties } from "@microsoft/vscode-azext-utils"; import { useEffect, useState } from "react"; -import { vscode } from "../../vscode"; +import { LocalDeployResponse } from "../../../../../language"; import { - VscodeMessage, createGetAccessTokenMessage, createGetDeploymentScopeMessage, createGetStateMessage, @@ -12,18 +13,11 @@ import { createPublishTelemetryMessage, createReadyMessage, createSaveStateMessage, + VscodeMessage, } from "../../../messages"; +import { DeploymentScope, DeployPaneState, ParametersMetadata, TemplateMetadata, UntypedError } from "../../../models"; +import { vscode } from "../../vscode"; import { parseParametersJson, parseTemplateJson } from "../utils"; -import { - DeployPaneState, - DeploymentScope, - ParametersMetadata, - TemplateMetadata, - UntypedError, -} from "../../../models"; -import { AccessToken } from "@azure/identity"; -import { TelemetryProperties } from "@microsoft/vscode-azext-utils"; -import { LocalDeployResponse } from "../../../../../language"; // TODO see if there's a way to use react hooks instead of this hackery let accessTokenResolver: { @@ -53,8 +47,7 @@ export function useMessageHandler(props: UseMessageHandlerProps) { localDeployEnabled: false, }); const [scope, setScope] = useState(); - const [localDeployResult, setLocalDeployResult] = - useState(); + const [localDeployResult, setLocalDeployResult] = useState(); const handleMessageEvent = (e: MessageEvent) => { const message = e.data; @@ -75,18 +68,14 @@ export function useMessageHandler(props: UseMessageHandlerProps) { if (!templateMetadata.scopeType) { setTemplateMetadata(undefined); - setErrorMessage( - "Failed to obtain the deployment scope from compiled Bicep file.", - ); + setErrorMessage("Failed to obtain the deployment scope from compiled Bicep file."); return; } setTemplateMetadata(templateMetadata); if (message.parametersJson) { setParamsMetadata({ - sourceFilePath: message.documentPath.endsWith(".bicep") - ? undefined - : message.documentPath, + sourceFilePath: message.documentPath.endsWith(".bicep") ? undefined : message.documentPath, parameters: parseParametersJson(message.parametersJson), }); } @@ -114,9 +103,7 @@ export function useMessageHandler(props: UseMessageHandlerProps) { if (message.accessToken) { accessTokenResolver.resolve(message.accessToken); } else { - accessTokenResolver.reject( - message.error ?? "Failed to authenticate with Azure", - ); + accessTokenResolver.reject(message.error ?? "Failed to authenticate with Azure"); } return; } @@ -154,22 +141,15 @@ export function useMessageHandler(props: UseMessageHandlerProps) { throw `ScopeType not set`; } - vscode.postMessage( - createGetDeploymentScopeMessage(templateMetadata.scopeType), - ); + vscode.postMessage(createGetDeploymentScopeMessage(templateMetadata.scopeType)); } - function publishTelemetry( - eventName: string, - properties: TelemetryProperties, - ) { + function publishTelemetry(eventName: string, properties: TelemetryProperties) { vscode.postMessage(createPublishTelemetryMessage(eventName, properties)); } function acquireAccessToken() { - const promise = new Promise( - (resolve, reject) => (accessTokenResolver = { resolve, reject }), - ); + const promise = new Promise((resolve, reject) => (accessTokenResolver = { resolve, reject })); vscode.postMessage(createGetAccessTokenMessage(scope!)); return promise; diff --git a/src/vscode-bicep/src/panes/deploy/app/components/index.tsx b/src/vscode-bicep/src/panes/deploy/app/components/index.tsx index 40158eb098b..b8404ba18c9 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/index.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/index.tsx @@ -1,10 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import ReactDOM from "react-dom"; - +import { createRoot } from "react-dom/client"; import { App } from "./App"; -ReactDOM.render( - , - document.getElementById("root") -); +const container = document.getElementById("root"); + +if (!container) { + throw new Error("Could not find the root element"); +} + +const root = createRoot(container); + +root.render(); diff --git a/src/vscode-bicep/src/panes/deploy/app/components/localDeploy.tsx b/src/vscode-bicep/src/panes/deploy/app/components/localDeploy.tsx index 3dc32d1cfe3..38b8103abfc 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/localDeploy.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/localDeploy.tsx @@ -1,28 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. import { VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; +import { FC } from "react"; +import { LocalDeploymentOperationContent, LocalDeployResponse } from "../../../../language"; import { FormSection } from "./sections/FormSection"; -import { LocalDeployResponse, LocalDeploymentOperationContent } from "../../../../language"; import { getPreformattedJson } from "./utils"; -import { FC } from "react"; export const LocalDeployResult: FC<{ result: LocalDeployResponse }> = ({ result }) => { const error = result.deployment.error; return (

{result.deployment.provisioningState}

- {error && + {error && ( - {error && - Code - {error.code} - } - {error.message && - Message - {error.message} - } - } + {error && ( + + Code + {error.code} + + )} + {error.message && ( + + Message + {error.message} + + )} + + )}
); -} +}; export const LocalDeployOperations: FC<{ result: LocalDeployResponse }> = ({ result }) => { if (!result.operations) { @@ -33,22 +40,32 @@ export const LocalDeployOperations: FC<{ result: LocalDeployResponse }> = ({ res - Resource Name - State - Error + + Resource Name + + + State + + + Error + - {result.operations.map(operation => ( - + {result.operations.map((operation) => ( + {operation.resourceName} {operation.provisioningState} - {operation.error ? getPreformattedJson(operation.error) : ''} + + {operation.error ? getPreformattedJson(operation.error) : ""} + ))} ); -} - +}; export const LocalDeployOutputs: FC<{ result: LocalDeployResponse }> = ({ result }) => { if (!result.deployment.outputs) { @@ -59,20 +76,26 @@ export const LocalDeployOutputs: FC<{ result: LocalDeployResponse }> = ({ result - Name - Value + + Name + + + Value + - {Object.keys(result.deployment.outputs).map(name => ( + {Object.keys(result.deployment.outputs).map((name) => ( {name} - {getPreformattedJson(result.deployment.outputs[name])} + + {getPreformattedJson(result.deployment.outputs[name])} + ))} ); -} +}; function isFailed(operation: LocalDeploymentOperationContent) { return operation.provisioningState.toLowerCase() === "failed"; -} \ No newline at end of file +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOperationsView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOperationsView.tsx index ddfbaa378e6..f4199aaf3f9 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOperationsView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOperationsView.tsx @@ -1,9 +1,17 @@ -import { VSCodeDataGrid, VSCodeDataGridRow, VSCodeDataGridCell, VSCodeProgressRing, VSCodeLink } from "@vscode/webview-ui-toolkit/react"; -import { FC } from "react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. import { DeploymentOperation } from "@azure/arm-resources"; +import { + VSCodeDataGrid, + VSCodeDataGridCell, + VSCodeDataGridRow, + VSCodeLink, + VSCodeProgressRing, +} from "@vscode/webview-ui-toolkit/react"; +import { FC } from "react"; +import { DeploymentScope } from "../../../models"; import { getPreformattedJson, isFailed, isInProgress } from "../utils"; import { FormSection } from "./FormSection"; -import { DeploymentScope } from "../../../models"; interface DeploymentOperationsViewProps { scope: DeploymentScope; @@ -15,8 +23,9 @@ export const DeploymentOperationsView: FC = ({ sc return null; } - const filteredOperations = operations - .filter(x => x.properties?.provisioningOperation !== "EvaluateDeploymentOutput") + const filteredOperations = operations.filter( + (x) => x.properties?.provisioningOperation !== "EvaluateDeploymentOutput", + ); if (filteredOperations.length == 0) { return null; @@ -26,21 +35,36 @@ export const DeploymentOperationsView: FC = ({ sc - Resource Name - Resource Type - Operation - State - Status + + Resource Name + + + Resource Type + + + Operation + + + State + + + Status + - {filteredOperations.map(operation => ( - + {filteredOperations.map((operation) => ( + {getResourceNameContents(scope, operation)} {operation.properties?.targetResource?.resourceType} {operation.properties?.provisioningOperation} {isInProgress(operation) ? : operation.properties?.provisioningState} - {getPreformattedJson(operation.properties?.statusMessage)} + + {getPreformattedJson(operation.properties?.statusMessage)} + ))} @@ -51,17 +75,18 @@ export const DeploymentOperationsView: FC = ({ sc function getResourceNameContents(scope: DeploymentScope, operation: DeploymentOperation) { const resourceId = operation.properties?.targetResource?.id; const resourceName = operation.properties?.targetResource?.resourceName; - const isPutOrGet = operation.properties?.provisioningOperation === 'Create' || - operation.properties?.provisioningOperation === 'Read'; + const isPutOrGet = + operation.properties?.provisioningOperation === "Create" || operation.properties?.provisioningOperation === "Read"; return ( <> - {resourceName} - {resourceId && isPutOrGet && - // It only makes sense to share a link to the portal if we're doing a PUT / GET on a resource (as opposed to a POST action) - - - } + {resourceName} + {resourceId && isPutOrGet && ( + // It only makes sense to share a link to the portal if we're doing a PUT / GET on a resource (as opposed to a POST action) + + + + )} ); -} \ No newline at end of file +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOutputsView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOutputsView.tsx index a3fea98da32..ae02876a6c6 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOutputsView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentOutputsView.tsx @@ -1,10 +1,12 @@ -import { VSCodeDataGrid, VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import { VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; import { FC } from "react"; import { getPreformattedJson } from "../utils"; import { FormSection } from "./FormSection"; interface DeploymentOutputsViewProps { - outputs?: Record; + outputs?: Record; } export const DeploymentOutputsView: FC = ({ outputs }) => { @@ -16,16 +18,22 @@ export const DeploymentOutputsView: FC = ({ outputs - Name - Value + + Name + + + Value + - {Object.keys(outputs).map(name => ( + {Object.keys(outputs).map((name) => ( {name} - {getPreformattedJson(outputs[name].value)} + + {getPreformattedJson((outputs[name] as { value: unknown }).value)} + ))} ); -}; \ No newline at end of file +}; diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentScopeInputView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentScopeInputView.tsx index aad84f8a018..d4204157712 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentScopeInputView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/DeploymentScopeInputView.tsx @@ -1,4 +1,12 @@ -import { VSCodeButton, VSCodeBadge, VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import { + VSCodeBadge, + VSCodeButton, + VSCodeDataGrid, + VSCodeDataGridCell, + VSCodeDataGridRow, +} from "@vscode/webview-ui-toolkit/react"; import { FC } from "react"; import { DeploymentScope } from "../../../models"; import { FormSection } from "./FormSection"; @@ -11,17 +19,24 @@ interface DeploymentScopeInputViewProps { export const DeploymentScopeInputView: FC = ({ scope, onPickScope }) => { return ( - {scope && - {(scope.scopeType === 'resourceGroup' || scope.scopeType === 'subscription') && getGridRow('Subscription Id', scope.subscriptionId)} - {(scope.scopeType === 'resourceGroup') && getGridRow('Resource Group', scope.resourceGroup)} - {(scope.scopeType === 'managementGroup' || scope.scopeType === 'tenant') && getGridRow('Tenant Id', scope.tenantId)} - {(scope.scopeType === 'managementGroup') && getGridRow('Management Group', scope.managementGroup)} - {(scope.scopeType === 'managementGroup' || scope.scopeType === 'tenant') && getGridRow('Authenticated Subscription Id', scope.associatedSubscriptionId)} - {scope.scopeType !== 'resourceGroup' && getGridRow('Location', scope.location)} - } + {scope && ( + + {(scope.scopeType === "resourceGroup" || scope.scopeType === "subscription") && + getGridRow("Subscription Id", scope.subscriptionId)} + {scope.scopeType === "resourceGroup" && getGridRow("Resource Group", scope.resourceGroup)} + {(scope.scopeType === "managementGroup" || scope.scopeType === "tenant") && + getGridRow("Tenant Id", scope.tenantId)} + {scope.scopeType === "managementGroup" && getGridRow("Management Group", scope.managementGroup)} + {(scope.scopeType === "managementGroup" || scope.scopeType === "tenant") && + getGridRow("Authenticated Subscription Id", scope.associatedSubscriptionId)} + {scope.scopeType !== "resourceGroup" && getGridRow("Location", scope.location)} + + )}
- {!scope ? "Pick Scope" : "Change Scope"} + + {!scope ? "Pick Scope" : "Change Scope"} +
); @@ -31,7 +46,9 @@ function getGridRow(label: string, value: string) { return ( {label} - {value} + + {value} + - ) -} \ No newline at end of file + ); +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/FormSection.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/FormSection.tsx index d665dd1bdab..d924e44d97c 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/FormSection.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/FormSection.tsx @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. import { VSCodeDivider } from "@vscode/webview-ui-toolkit/react"; import { FC, PropsWithChildren, useState } from "react"; @@ -5,19 +7,17 @@ type FormSectionProps = PropsWithChildren<{ title: string; }>; -export const FormSection: FC = ({ title, children, }) => { +export const FormSection: FC = ({ title, children }) => { const [open, setOpen] = useState(true); return (
setOpen(!open)}> - +

{title}

- {open &&
- {children} -
} + {open &&
{children}
}
); }; diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/ParametersInputView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/ParametersInputView.tsx index af30781e0c1..541def284d5 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/ParametersInputView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/ParametersInputView.tsx @@ -1,4 +1,6 @@ -import { VSCodeTextField, VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"; import { FC } from "react"; import { ParamData, ParamDefinition, ParametersMetadata, TemplateMetadata } from "../../../models"; import { ParamInputBox } from "../ParamInputBox"; @@ -13,7 +15,14 @@ interface ParametersInputViewProps { onPickParametersFile: () => void; } -export const ParametersInputView: FC = ({ template, parameters, disabled, onValueChange, onEnableEditing, onPickParametersFile }) => { +export const ParametersInputView: FC = ({ + template, + parameters, + disabled, + onValueChange, + onEnableEditing, + onPickParametersFile, +}) => { if (!template || !parameters) { return null; } @@ -23,24 +32,33 @@ export const ParametersInputView: FC = ({ template, pa return ( - {sourceFilePath && File Path} - {sourceFilePath && !sourceFilePath.endsWith('.bicepparam') && Edit Parameters} + {sourceFilePath && ( + + File Path + + )} + {sourceFilePath && !sourceFilePath.endsWith(".bicepparam") && ( + Edit Parameters + )} {!sourceFilePath && Pick JSON Parameters File} - {!sourceFilePath && parameterDefinitions.map(definition => ( - onValueChange(definition.name, data)} - /> - ))} + {!sourceFilePath && + parameterDefinitions.map((definition) => ( + onValueChange(definition.name, data)} + /> + ))} ); }; function getParamData(params: ParametersMetadata, definition: ParamDefinition): ParamData { - return params.parameters[definition.name] ?? { - value: definition.defaultValue, - }; -} \ No newline at end of file + return ( + params.parameters[definition.name] ?? { + value: definition.defaultValue, + } + ); +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/ResultsView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/ResultsView.tsx index e8b639f6fbe..41b99a0ff35 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/ResultsView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/ResultsView.tsx @@ -1,7 +1,14 @@ -import { VSCodeDataGrid, VSCodeDataGridRow, VSCodeDataGridCell, VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import { ErrorResponse } from "@azure/arm-resources"; +import { + VSCodeCheckbox, + VSCodeDataGrid, + VSCodeDataGridCell, + VSCodeDataGridRow, +} from "@vscode/webview-ui-toolkit/react"; import { FC, useState } from "react"; import { DeployResult } from "../../../models"; -import { ErrorResponse } from "@azure/arm-resources"; import { getPreformattedJson } from "../utils"; import { FormSection } from "./FormSection"; @@ -9,7 +16,7 @@ interface ResultsViewProps { result?: DeployResult; } -export const ResultsView: FC = ({ result, }) => { +export const ResultsView: FC = ({ result }) => { if (!result) { return null; } @@ -18,8 +25,12 @@ export const ResultsView: FC = ({ result, }) => { return ( -

{result.success ? 'Succeeded' : 'Failed'}

- {result.error && setShowJson(!showJson)} checked={showJson}>Show JSON?} +

{result.success ? "Succeeded" : "Failed"}

+ {result.error && ( + setShowJson(!showJson)} checked={showJson}> + Show JSON? + + )} {result.error && getError(result.error, showJson)}
); @@ -32,22 +43,30 @@ function getError(error: ErrorResponse, showJson: boolean) { return ( - {error.code && - Code - {error.code} - } - {error.message && - Message - {error.message} - } - {error.target && - Target - {error.target} - } - {error.details && - Details - {error.details.map(x => getError(x, showJson))} - } + {error.code && ( + + Code + {error.code} + + )} + {error.message && ( + + Message + {error.message} + + )} + {error.target && ( + + Target + {error.target} + + )} + {error.details && ( + + Details + {error.details.map((x) => getError(x, showJson))} + + )} ); -} \ No newline at end of file +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/sections/WhatIfChangesView.tsx b/src/vscode-bicep/src/panes/deploy/app/components/sections/WhatIfChangesView.tsx index 6cdad1f4c0b..c44e14c79e5 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/sections/WhatIfChangesView.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/sections/WhatIfChangesView.tsx @@ -1,6 +1,8 @@ -import { VSCodeDataGrid, VSCodeDataGridRow, VSCodeDataGridCell } from "@vscode/webview-ui-toolkit/react"; -import { FC } from "react"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. import { WhatIfChange, WhatIfPropertyChange } from "@azure/arm-resources"; +import { VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow } from "@vscode/webview-ui-toolkit/react"; +import { FC } from "react"; import { FormSection } from "./FormSection"; interface WhatIfChangesViewProps { @@ -12,16 +14,22 @@ export const WhatIfChangesView: FC = ({ changes }) => { return null; } - const filteredChanges = changes.filter(x => x.changeType !== "Ignore"); + const filteredChanges = changes.filter((x) => x.changeType !== "Ignore"); return ( - Resource Id - Change Type - Changes + + Resource Id + + + Change Type + + + Changes + - {filteredChanges.map(change => ( + {filteredChanges.map((change) => ( {change.resourceId} {change.changeType} @@ -38,14 +46,18 @@ function getWhatIfPropertyChanges(changes?: WhatIfPropertyChange[]) { return null; } - const filteredChanges = changes.filter(x => x.propertyChangeType !== "NoEffect"); + const filteredChanges = changes.filter((x) => x.propertyChangeType !== "NoEffect"); return ( - Path - Change Type + + Path + + + Change Type + - {filteredChanges.map(change => ( + {filteredChanges.map((change) => ( {change.path} {change.propertyChangeType} @@ -53,4 +65,4 @@ function getWhatIfPropertyChanges(changes?: WhatIfPropertyChange[]) { ))} ); -} \ No newline at end of file +} diff --git a/src/vscode-bicep/src/panes/deploy/app/components/utils.tsx b/src/vscode-bicep/src/panes/deploy/app/components/utils.tsx index 7d362100908..54dbdeef0d8 100644 --- a/src/vscode-bicep/src/panes/deploy/app/components/utils.tsx +++ b/src/vscode-bicep/src/panes/deploy/app/components/utils.tsx @@ -5,13 +5,13 @@ import { DeploymentScopeType, ParamData, ParamDefinition, TemplateMetadata } fro function getScopeTypeFromSchema(template: Record): DeploymentScopeType | undefined { const lookup: Record = { - 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#': 'resourceGroup', - 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#': 'subscription', - 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#': 'managementGroup', - 'https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#': 'tenant', - } + "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#": "resourceGroup", + "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#": "subscription", + "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#": "managementGroup", + "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#": "tenant", + }; - return lookup[template['$schema'] as string]; + return lookup[template["$schema"] as string]; } export function parseTemplateJson(json: string): TemplateMetadata { @@ -61,8 +61,6 @@ export function isSucceeded(operation: DeploymentOperation) { return operation.properties?.provisioningState?.toLowerCase() === "succeeded"; } -export function getPreformattedJson(input: any) { - return ( -
{JSON.stringify(input, null, 2)}
- ); -} \ No newline at end of file +export function getPreformattedJson(input: unknown) { + return
{JSON.stringify(input, null, 2)}
; +} diff --git a/src/vscode-bicep/src/panes/deploy/messages.ts b/src/vscode-bicep/src/panes/deploy/messages.ts index c3dc11846ba..e6f55a13005 100644 --- a/src/vscode-bicep/src/panes/deploy/messages.ts +++ b/src/vscode-bicep/src/panes/deploy/messages.ts @@ -1,14 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { AccessToken } from "@azure/identity"; -import { - DeployPaneState, - DeploymentScope, - DeploymentScopeType, - UntypedError, -} from "./models"; import { TelemetryProperties } from "@microsoft/vscode-azext-utils"; import { LocalDeployResponse } from "../../language"; +import { DeploymentScope, DeploymentScopeType, DeployPaneState, UntypedError } from "./models"; interface SimpleMessage { kind: T; @@ -58,9 +53,7 @@ export type GetStateResultMessage = MessageWithPayload< state: DeployPaneState; } >; -export function createGetStateResultMessage( - state: DeployPaneState, -): GetStateResultMessage { +export function createGetStateResultMessage(state: DeployPaneState): GetStateResultMessage { return createMessageWithPayload("GET_STATE_RESULT", { state, }); @@ -72,9 +65,7 @@ export type SaveStateMessage = MessageWithPayload< state: DeployPaneState; } >; -export function createSaveStateMessage( - state: DeployPaneState, -): SaveStateMessage { +export function createSaveStateMessage(state: DeployPaneState): SaveStateMessage { return createMessageWithPayload("SAVE_STATE", { state, }); @@ -86,9 +77,7 @@ export type GetAccessTokenMessage = MessageWithPayload< scope: DeploymentScope; } >; -export function createGetAccessTokenMessage( - scope: DeploymentScope, -): GetAccessTokenMessage { +export function createGetAccessTokenMessage(scope: DeploymentScope): GetAccessTokenMessage { return createMessageWithPayload("GET_ACCESS_TOKEN", { scope, }); @@ -139,9 +128,7 @@ export type GetDeploymentScopeMessage = MessageWithPayload< scopeType: DeploymentScopeType; } >; -export function createGetDeploymentScopeMessage( - scopeType: DeploymentScopeType, -): GetDeploymentScopeMessage { +export function createGetDeploymentScopeMessage(scopeType: DeploymentScopeType): GetDeploymentScopeMessage { return createMessageWithPayload("GET_DEPLOYMENT_SCOPE", { scopeType, }); @@ -153,9 +140,7 @@ export type GetDeploymentScopeResultMessage = MessageWithPayload< scope: DeploymentScope; } >; -export function createGetDeploymentScopeResultMessage( - scope: DeploymentScope, -): GetDeploymentScopeResultMessage { +export function createGetDeploymentScopeResultMessage(scope: DeploymentScope): GetDeploymentScopeResultMessage { return createMessageWithPayload("GET_DEPLOYMENT_SCOPE_RESULT", { scope, }); @@ -183,13 +168,8 @@ export function createLocalDeployMessage(): LocalDeployMessage { return createSimpleMessage("LOCAL_DEPLOY"); } -export type LocalDeployResultMessage = MessageWithPayload< - "LOCAL_DEPLOY_RESULT", - LocalDeployResponse ->; -export function createLocalDeployResultMessage( - response: LocalDeployResponse, -): LocalDeployResultMessage { +export type LocalDeployResultMessage = MessageWithPayload<"LOCAL_DEPLOY_RESULT", LocalDeployResponse>; +export function createLocalDeployResultMessage(response: LocalDeployResponse): LocalDeployResultMessage { return createMessageWithPayload("LOCAL_DEPLOY_RESULT", response); } @@ -215,10 +195,10 @@ function createSimpleMessage(kind: T): SimpleMessage { return { kind }; } -function createMessageWithPayload< - T extends string, - U = Record, ->(kind: T, payload: U): MessageWithPayload { +function createMessageWithPayload>( + kind: T, + payload: U, +): MessageWithPayload { return { kind, ...payload, diff --git a/src/vscode-bicep/src/panes/deploy/view.ts b/src/vscode-bicep/src/panes/deploy/view.ts index 2d817a68c5c..f247cbf4a17 100644 --- a/src/vscode-bicep/src/panes/deploy/view.ts +++ b/src/vscode-bicep/src/panes/deploy/view.ts @@ -1,10 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import vscode, { ExtensionContext } from "vscode"; -import fse from "fs-extra"; -import path from "path"; import crypto from "crypto"; +import path from "path"; +import { callWithTelemetryAndErrorHandlingSync, IActionContext } from "@microsoft/vscode-azext-utils"; +import fse from "fs-extra"; +import vscode, { ExtensionContext } from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; +import { IAzureUiManager } from "../../azure/types"; +import { GlobalStateKeys } from "../../globalState"; +import { getDeploymentDataRequestType, localDeployRequestType } from "../../language"; +import { Disposable } from "../../utils/disposable"; +import { getLogger } from "../../utils/logger"; +import { debounce } from "../../utils/time"; import { createDeploymentDataMessage, createGetAccessTokenResultMessage, @@ -14,20 +21,7 @@ import { createPickParamsFileResultMessage, ViewMessage, } from "./messages"; -import { - getDeploymentDataRequestType, - localDeployRequestType, -} from "../../language"; -import { Disposable } from "../../utils/disposable"; -import { debounce } from "../../utils/time"; -import { getLogger } from "../../utils/logger"; -import { - callWithTelemetryAndErrorHandlingSync, - IActionContext, -} from "@microsoft/vscode-azext-utils"; -import { GlobalStateKeys } from "../../globalState"; import { DeployPaneState } from "./models"; -import { IAzureUiManager } from "../../azure/types"; export class DeployPaneView extends Disposable { public static viewType = "bicep.deployPane"; @@ -54,24 +48,15 @@ export class DeployPaneView extends Disposable { new vscode.EventEmitter(), ); - this.register( - this.webviewPanel.webview.onDidReceiveMessage( - // eslint-disable-next-line jest/unbound-method - this.handleDidReceiveMessage, - this, - ), - ); + this.register(this.webviewPanel.webview.onDidReceiveMessage(this.handleDidReceiveMessage, this)); if (!this.isDisposed) { this.webviewPanel.webview.html = this.createWebviewHtml(); } this.registerMultiple( - // eslint-disable-next-line jest/unbound-method this.webviewPanel.onDidDispose(this.dispose, this), - this.webviewPanel.onDidChangeViewState((e) => - this.onDidChangeViewStateEmitter.fire(e), - ), + this.webviewPanel.onDidChangeViewState((e) => this.onDidChangeViewStateEmitter.fire(e)), ); } @@ -93,15 +78,10 @@ export class DeployPaneView extends Disposable { documentUri: vscode.Uri, ): DeployPaneView { const visualizerTitle = `Deploy ${path.basename(documentUri.fsPath)}`; - const webviewPanel = vscode.window.createWebviewPanel( - DeployPaneView.viewType, - visualizerTitle, - viewColumn, - { - enableScripts: true, - retainContextWhenHidden: true, - }, - ); + const webviewPanel = vscode.window.createWebviewPanel(DeployPaneView.viewType, visualizerTitle, viewColumn, { + enableScripts: true, + retainContextWhenHidden: true, + }); return new DeployPaneView( extensionContext, @@ -167,15 +147,9 @@ export class DeployPaneView extends Disposable { return; } - const deploymentData = await this.languageClient.sendRequest( - getDeploymentDataRequestType, - { - textDocument: - this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier( - this.document, - ), - }, - ); + const deploymentData = await this.languageClient.sendRequest(getDeploymentDataRequestType, { + textDocument: this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(this.document), + }); if (this.isDisposed) { return; @@ -201,36 +175,25 @@ export class DeployPaneView extends Disposable { private async handleDidReceiveMessage(message: ViewMessage) { switch (message.kind) { case "READY": { - getLogger().debug( - `Deployment Pane for ${this.documentUri.fsPath} is ready.`, - ); + getLogger().debug(`Deployment Pane for ${this.documentUri.fsPath} is ready.`); this.readyToRender = true; this.render(); return; } case "GET_STATE": { const deployPaneState: Record = - this.extensionContext.globalState.get( - GlobalStateKeys.deployPaneStateKey, - ) || {}; + this.extensionContext.globalState.get(GlobalStateKeys.deployPaneStateKey) || {}; const filteredState = deployPaneState[this.documentUri.toString()]; - await this.webviewPanel.webview.postMessage( - createGetStateResultMessage(filteredState), - ); + await this.webviewPanel.webview.postMessage(createGetStateResultMessage(filteredState)); return; } case "SAVE_STATE": { const deployPaneState: Record = - this.extensionContext.globalState.get( - GlobalStateKeys.deployPaneStateKey, - ) || {}; + this.extensionContext.globalState.get(GlobalStateKeys.deployPaneStateKey) || {}; deployPaneState[this.documentUri.toString()] = message.state; - await this.extensionContext.globalState.update( - GlobalStateKeys.deployPaneStateKey, - deployPaneState, - ); + await this.extensionContext.globalState.update(GlobalStateKeys.deployPaneStateKey, deployPaneState); return; } case "PICK_PARAMS_FILE": { @@ -239,15 +202,9 @@ export class DeployPaneView extends Disposable { openLabel: "Select Parameters file", filters: { "Parameters files": ["json"] }, }); - const parameterFile = await fse.readFile( - parametersFileUri[0].fsPath, - "utf-8", - ); + const parameterFile = await fse.readFile(parametersFileUri[0].fsPath, "utf-8"); await this.webviewPanel.webview.postMessage( - createPickParamsFileResultMessage( - parametersFileUri[0].fsPath, - parameterFile, - ), + createPickParamsFileResultMessage(parametersFileUri[0].fsPath, parameterFile), ); return; } @@ -255,47 +212,30 @@ export class DeployPaneView extends Disposable { try { const accessToken = await this.azureMgr.getAccessToken(message.scope); - await this.webviewPanel.webview.postMessage( - createGetAccessTokenResultMessage(accessToken), - ); + await this.webviewPanel.webview.postMessage(createGetAccessTokenResultMessage(accessToken)); } catch (error) { - await this.webviewPanel.webview.postMessage( - createGetAccessTokenResultMessage(undefined, error), - ); + await this.webviewPanel.webview.postMessage(createGetAccessTokenResultMessage(undefined, error)); } return; } case "GET_DEPLOYMENT_SCOPE": { const scope = await this.azureMgr.pickScope(message.scopeType); - await this.webviewPanel.webview.postMessage( - createGetDeploymentScopeResultMessage(scope), - ); + await this.webviewPanel.webview.postMessage(createGetDeploymentScopeResultMessage(scope)); return; } case "PUBLISH_TELEMETRY": { - callWithTelemetryAndErrorHandlingSync( - message.eventName, - (telemetryActionContext) => { - telemetryActionContext.errorHandling.suppressDisplay = true; - telemetryActionContext.telemetry.properties = message.properties; - }, - ); + callWithTelemetryAndErrorHandlingSync(message.eventName, (telemetryActionContext) => { + telemetryActionContext.errorHandling.suppressDisplay = true; + telemetryActionContext.telemetry.properties = message.properties; + }); return; } case "LOCAL_DEPLOY": { - const result = await this.languageClient.sendRequest( - localDeployRequestType, - { - textDocument: - this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier( - this.document!, - ), - }, - ); + const result = await this.languageClient.sendRequest(localDeployRequestType, { + textDocument: this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(this.document!), + }); - await this.webviewPanel.webview.postMessage( - createLocalDeployResultMessage(result), - ); + await this.webviewPanel.webview.postMessage(createLocalDeployResultMessage(result)); return; } } diff --git a/src/vscode-bicep/src/panes/deploy/viewManager.ts b/src/vscode-bicep/src/panes/deploy/viewManager.ts index a97920690f5..411c4196616 100644 --- a/src/vscode-bicep/src/panes/deploy/viewManager.ts +++ b/src/vscode-bicep/src/panes/deploy/viewManager.ts @@ -1,17 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { IActionContext } from "@microsoft/vscode-azext-utils"; import vscode from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; - -import { DeployPaneView } from "./view"; -import { Disposable } from "../../utils/disposable"; -import { IActionContext } from "@microsoft/vscode-azext-utils"; import { IAzureUiManager } from "../../azure/types"; +import { Disposable } from "../../utils/disposable"; +import { DeployPaneView } from "./view"; -export class DeployPaneViewManager - extends Disposable - implements vscode.WebviewPanelSerializer -{ +export class DeployPaneViewManager extends Disposable implements vscode.WebviewPanelSerializer { private static readonly deployPaneActiveContextKey = "deployPaneFocus"; private readonly viewsByPath = new Map(); @@ -27,15 +23,9 @@ export class DeployPaneViewManager ) { super(); - this.register( - vscode.window.registerWebviewPanelSerializer( - DeployPaneView.viewType, - this, - ), - ); + this.register(vscode.window.registerWebviewPanelSerializer(DeployPaneView.viewType, this)); - const existingMiddleware = - languageClient.clientOptions.middleware?.handleDiagnostics; + const existingMiddleware = languageClient.clientOptions.middleware?.handleDiagnostics; this.languageClient.clientOptions.middleware = { ...(this.languageClient.clientOptions.middleware ?? {}), @@ -57,10 +47,7 @@ export class DeployPaneViewManager return this.activeUri; } - public async openView( - documentUri: vscode.Uri, - viewColumn: vscode.ViewColumn, - ): Promise { + public async openView(documentUri: vscode.Uri, viewColumn: vscode.ViewColumn): Promise { const existingView = this.viewsByPath.get(documentUri.fsPath); if (existingView) { @@ -85,10 +72,7 @@ export class DeployPaneViewManager this.activeUri = documentUri; } - public async deserializeWebviewPanel( - webviewPanel: vscode.WebviewPanel, - documentPath: string, - ): Promise { + public async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, documentPath: string): Promise { const documentUri = vscode.Uri.file(documentPath); this.registerView( @@ -120,10 +104,7 @@ export class DeployPaneViewManager this.viewsByPath.clear(); } - private registerView( - documentUri: vscode.Uri, - view: DeployPaneView, - ): DeployPaneView { + private registerView(documentUri: vscode.Uri, view: DeployPaneView): DeployPaneView { this.viewsByPath.set(documentUri.fsPath, view); view.onDidChangeViewState((e) => { @@ -149,10 +130,6 @@ export class DeployPaneViewManager } private async setDeployPaneActiveContext(value: boolean) { - await vscode.commands.executeCommand( - "setContext", - DeployPaneViewManager.deployPaneActiveContextKey, - value, - ); + await vscode.commands.executeCommand("setContext", DeployPaneViewManager.deployPaneActiveContextKey, value); } } diff --git a/src/vscode-bicep/src/test/e2e/bicepExternalSourceContentProvider.test.ts b/src/vscode-bicep/src/test/e2e/bicepExternalSourceContentProvider.test.ts index b6551657d3d..9544f054f69 100644 --- a/src/vscode-bicep/src/test/e2e/bicepExternalSourceContentProvider.test.ts +++ b/src/vscode-bicep/src/test/e2e/bicepExternalSourceContentProvider.test.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { describe, expect, it } from "@jest/globals"; import { Uri } from "vscode"; import { decodeExternalSourceUri } from "../../language/decodeExternalSourceUri"; @@ -10,9 +11,7 @@ describe("bicepExternalSourceContentProvider", () => { "bicep-extsrc:br%3Asaw.azurecr.io/complicated%3Av1.0-beta/my%20entrypoint.bicep%20%28very%20complicated%20for%20just%20version%20v1.0-beta%29?br%3Asaw.azurecr.io%2Fcomplicated%3Av1.0-beta#my%20entrypoint.bicep"; const decoded = decodeExternalSourceUri(Uri.parse(uri)); - expect(decoded.moduleReference).toBe( - "br:saw.azurecr.io/complicated:v1.0-beta", - ); + expect(decoded.moduleReference).toBe("br:saw.azurecr.io/complicated:v1.0-beta"); expect(decoded.requestedSourceFile).toBe("my entrypoint.bicep"); expect(decoded.title).toBe( "br:saw.azurecr.io/complicated:v1.0-beta/my entrypoint.bicep (very complicated for just version v1.0-beta)", @@ -24,12 +23,8 @@ describe("bicepExternalSourceContentProvider", () => { "bicep-extsrc:br%3Amcr.microsoft.com/bicep/ai/bing-resource%3A1.0.2/main.json%20%28bing-resource%3A1.0.2%29?br%3Amcr.microsoft.com%2Fbicep%2Fai%2Fbing-resource%3A1.0.2"; const decoded = decodeExternalSourceUri(Uri.parse(uri)); - expect(decoded.moduleReference).toBe( - "br:mcr.microsoft.com/bicep/ai/bing-resource:1.0.2", - ); + expect(decoded.moduleReference).toBe("br:mcr.microsoft.com/bicep/ai/bing-resource:1.0.2"); expect(decoded.requestedSourceFile).toBeUndefined(); - expect(decoded.title).toBe( - "br:mcr.microsoft.com/bicep/ai/bing-resource:1.0.2/main.json (bing-resource:1.0.2)", - ); + expect(decoded.title).toBe("br:mcr.microsoft.com/bicep/ai/bing-resource:1.0.2/main.json (bing-resource:1.0.2)"); }); }); diff --git a/src/vscode-bicep/src/test/e2e/build.test.ts b/src/vscode-bicep/src/test/e2e/build.test.ts index 07ba0e7cbdb..939e54a39d8 100644 --- a/src/vscode-bicep/src/test/e2e/build.test.ts +++ b/src/vscode-bicep/src/test/e2e/build.test.ts @@ -4,9 +4,9 @@ import fs from "fs"; import path from "path"; import vscode from "vscode"; import { sleep } from "../../utils/time"; - import { executeBuildCommand, executeCloseAllEditors } from "./commands"; import { resolveExamplePath } from "./examples"; + describe("build", (): void => { afterEach(async () => { await executeCloseAllEditors(); diff --git a/src/vscode-bicep/src/test/e2e/buildParams.test.ts b/src/vscode-bicep/src/test/e2e/buildParams.test.ts index faa5c267595..274c95518bf 100644 --- a/src/vscode-bicep/src/test/e2e/buildParams.test.ts +++ b/src/vscode-bicep/src/test/e2e/buildParams.test.ts @@ -4,7 +4,6 @@ import fs from "fs"; import path from "path"; import vscode from "vscode"; import { sleep } from "../../utils/time"; - import { executeBuildParamsCommand, executeCloseAllEditors } from "./commands"; import { resolveExamplePath } from "./examples"; @@ -23,10 +22,7 @@ describe("buildParams", (): void => { await executeBuildParamsCommand(textDocument.uri); const folderContainingSourceFile = path.dirname(examplePath); - const compiledFilePath = path.join( - folderContainingSourceFile, - "main.parameters.json", - ); + const compiledFilePath = path.join(folderContainingSourceFile, "main.parameters.json"); expect(fs.existsSync(compiledFilePath)).toBe(true); diff --git a/src/vscode-bicep/src/test/e2e/commands.ts b/src/vscode-bicep/src/test/e2e/commands.ts index 76b45172678..d2cdb5aa0a6 100644 --- a/src/vscode-bicep/src/test/e2e/commands.ts +++ b/src/vscode-bicep/src/test/e2e/commands.ts @@ -14,11 +14,7 @@ export async function executeHoverProvider( documentUri: vscode.Uri, position: vscode.Position, ): Promise { - return await vscode.commands.executeCommand( - "vscode.executeHoverProvider", - documentUri, - position, - ); + return await vscode.commands.executeCommand("vscode.executeHoverProvider", documentUri, position); } export async function executeCompletionItemProvider( @@ -44,71 +40,43 @@ export async function executeTypeText(text: string): Promise { return await vscode.commands.executeCommand("type", { text }); } -export async function executeShowVisualizerCommand( - documentUri: vscode.Uri, -): Promise { - return await vscode.commands.executeCommand( - "bicep.showVisualizer", - documentUri, - ); +export async function executeShowVisualizerCommand(documentUri: vscode.Uri): Promise { + return await vscode.commands.executeCommand("bicep.showVisualizer", documentUri); } export async function executeShowVisualizerToSideCommand( documentUri: vscode.Uri, ): Promise { - return await vscode.commands.executeCommand( - "bicep.showVisualizerToSide", - documentUri, - ); + return await vscode.commands.executeCommand("bicep.showVisualizerToSide", documentUri); } -export async function executeShowDeployPaneCommand( - documentUri: vscode.Uri, -): Promise { - return await vscode.commands.executeCommand( - "bicep.showDeployPane", - documentUri, - ); +export async function executeShowDeployPaneCommand(documentUri: vscode.Uri): Promise { + return await vscode.commands.executeCommand("bicep.showDeployPane", documentUri); } export async function executeShowDeployPaneToSideCommand( documentUri: vscode.Uri, ): Promise { - return await vscode.commands.executeCommand( - "bicep.showDeployPaneToSide", - documentUri, - ); + return await vscode.commands.executeCommand("bicep.showDeployPaneToSide", documentUri); } -export async function executeShowSourceCommand(): Promise< - vscode.TextEditor | undefined -> { - return await vscode.commands.executeCommand( - ShowSourceFromVisualizerCommand.CommandId, - ); +export async function executeShowSourceCommand(): Promise { + return await vscode.commands.executeCommand(ShowSourceFromVisualizerCommand.CommandId); } -export async function executeBuildCommand( - documentUri: vscode.Uri, -): Promise { +export async function executeBuildCommand(documentUri: vscode.Uri): Promise { return await vscode.commands.executeCommand("bicep.build", documentUri); } -export async function executeBuildParamsCommand( - documentUri: vscode.Uri, -): Promise { +export async function executeBuildParamsCommand(documentUri: vscode.Uri): Promise { return await vscode.commands.executeCommand("bicep.buildParams", documentUri); } -export async function executeDecompileCommand( - documentUri: vscode.Uri, -): Promise { +export async function executeDecompileCommand(documentUri: vscode.Uri): Promise { return await vscode.commands.executeCommand("bicep.decompile", documentUri); } -export async function executeCreateConfigFileCommand( - documentUri?: vscode.Uri, -): Promise { +export async function executeCreateConfigFileCommand(documentUri?: vscode.Uri): Promise { return await vscode.commands.executeCommand( "bicep.createConfigFile", documentUri, @@ -117,26 +85,14 @@ export async function executeCreateConfigFileCommand( ); } -export async function executeForceModulesRestoreCommand( - documentUri: vscode.Uri, -): Promise { - return await vscode.commands.executeCommand( - "bicep.forceModulesRestore", - documentUri, - ); +export async function executeForceModulesRestoreCommand(documentUri: vscode.Uri): Promise { + return await vscode.commands.executeCommand("bicep.forceModulesRestore", documentUri); } -export async function executePasteAsBicepCommand( - documentUri: vscode.Uri, -): Promise { - return await vscode.commands.executeCommand( - "bicep.pasteAsBicep", - documentUri, - ); +export async function executePasteAsBicepCommand(documentUri: vscode.Uri): Promise { + return await vscode.commands.executeCommand("bicep.pasteAsBicep", documentUri); } export async function executeEditorPasteCommand(): Promise { - return await vscode.commands.executeCommand( - "editor.action.clipboardPasteAction", - ); + return await vscode.commands.executeCommand("editor.action.clipboardPasteAction"); } diff --git a/src/vscode-bicep/src/test/e2e/completion.test.ts b/src/vscode-bicep/src/test/e2e/completion.test.ts index 841f0350044..e84c31a8b10 100644 --- a/src/vscode-bicep/src/test/e2e/completion.test.ts +++ b/src/vscode-bicep/src/test/e2e/completion.test.ts @@ -3,15 +3,11 @@ import * as vscode from "vscode"; import { Range } from "vscode"; import { Position } from "vscode"; - -import { readExampleFile } from "./examples"; -import { - executeCloseAllEditors, - executeCompletionItemProvider, -} from "./commands"; +import { sleep } from "../../utils/time"; import { expectDefined } from "../utils/assert"; import { retryWhile } from "../utils/time"; -import { sleep } from "../../utils/time"; +import { executeCloseAllEditors, executeCompletionItemProvider } from "./commands"; +import { readExampleFile } from "./examples"; describe("completion", (): void => { let document: vscode.TextDocument; @@ -36,26 +32,17 @@ describe("completion", (): void => { }); it("should provide completion while typing an identifier", async () => { - await editor.edit((editBuilder) => - editBuilder.insert(new Position(17, 0), "var foo = data"), - ); + await editor.edit((editBuilder) => editBuilder.insert(new Position(17, 0), "var foo = data")); const completionList = await retryWhile( - async () => - await executeCompletionItemProvider( - document.uri, - new vscode.Position(17, 14), - ), + async () => await executeCompletionItemProvider(document.uri, new vscode.Position(17, 14)), (completionList) => - completionList === undefined || - !completionList.items.map((item) => item.label).includes("dataUri"), + completionList === undefined || !completionList.items.map((item) => item.label).includes("dataUri"), ); expectDefined(completionList); expect(completionList.items.map((item) => item.label)).toContain("dataUri"); - await editor.edit((editBuilder) => - editBuilder.delete(new Range(new Position(17, 0), new Position(17, 14))), - ); + await editor.edit((editBuilder) => editBuilder.delete(new Range(new Position(17, 0), new Position(17, 14)))); }); }); diff --git a/src/vscode-bicep/src/test/e2e/createBicepConfig.test.ts b/src/vscode-bicep/src/test/e2e/createBicepConfig.test.ts index 0c4c63ffe2f..92bce47a863 100644 --- a/src/vscode-bicep/src/test/e2e/createBicepConfig.test.ts +++ b/src/vscode-bicep/src/test/e2e/createBicepConfig.test.ts @@ -7,10 +7,7 @@ import { TextEditor, Uri, window } from "vscode"; import { createUniqueTempFolder } from "../utils/createUniqueTempFolder"; import { normalizeMultilineString } from "../utils/normalizeMultilineString"; import { testScope } from "../utils/testScope"; -import { - executeCloseAllEditors, - executeCreateConfigFileCommand, -} from "./commands"; +import { executeCloseAllEditors, executeCreateConfigFileCommand } from "./commands"; import { expectedNewConfigFileContents } from "./expectedNewConfigFileContents"; describe("bicep.createConfigFile", (): void => { @@ -26,54 +23,35 @@ describe("bicep.createConfigFile", (): void => { let newConfigPath: string; await testScope("Execute Create Config command", async () => { - const newConfigPathOrUndefined = await executeCreateConfigFileCommand( - Uri.file(fakeBicepPath), - ); + const newConfigPathOrUndefined = await executeCreateConfigFileCommand(Uri.file(fakeBicepPath)); if (!newConfigPathOrUndefined) { - throw new Error( - `Language server returned ${String( - newConfigPathOrUndefined, - )} for bicep.createConfigFile`, - ); + throw new Error(`Language server returned ${String(newConfigPathOrUndefined)} for bicep.createConfigFile`); } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion newConfigPath = newConfigPathOrUndefined!; expect(path.basename(newConfigPath)).toBe("bicepconfig.json"); if (!fileExists(newConfigPath)) { - throw new Error( - `Expected file ${newConfigPath} to exist but it doesn't`, - ); + throw new Error(`Expected file ${newConfigPath} to exist but it doesn't`); } expect(fileContains(newConfigPath, "rules")).toBeTruthy(); // Since the test instance of vscode does not have any workspace folders, the new file should be opened // in the same folder as the bicep file - expect(path.dirname(newConfigPath).toLowerCase()).toBe( - path.dirname(fakeBicepPath).toLowerCase(), - ); + expect(path.dirname(newConfigPath).toLowerCase()).toBe(path.dirname(fakeBicepPath).toLowerCase()); }); let editorOrUndefined: TextEditor | undefined; - await testScope( - "Make sure the new config file has been opened in an editor", - async () => { - editorOrUndefined = window.visibleTextEditors.find( - (ed) => - ed.document.uri.fsPath.toLowerCase() === - newConfigPath?.toLowerCase(), - ); - if (!editorOrUndefined) { - throw new Error( - "New config file should be opened in a visible editor", - ); - } - }, - ); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await testScope("Make sure the new config file has been opened in an editor", async () => { + editorOrUndefined = window.visibleTextEditors.find( + (ed) => ed.document.uri.fsPath.toLowerCase() === newConfigPath?.toLowerCase(), + ); + if (!editorOrUndefined) { + throw new Error("New config file should be opened in a visible editor"); + } + }); const editor = editorOrUndefined!; await testScope("Verify text", () => { diff --git a/src/vscode-bicep/src/test/e2e/decompile.test.ts b/src/vscode-bicep/src/test/e2e/decompile.test.ts index 6a3b86c64ca..1d77d1ef25b 100644 --- a/src/vscode-bicep/src/test/e2e/decompile.test.ts +++ b/src/vscode-bicep/src/test/e2e/decompile.test.ts @@ -5,7 +5,6 @@ import fs from "fs"; import path from "path"; import vscode from "vscode"; import { createUniqueTempFolder } from "../utils/createUniqueTempFolder"; - import { executeCloseAllEditors, executeDecompileCommand } from "./commands"; const json = ` diff --git a/src/vscode-bicep/src/test/e2e/deploypane.test.ts b/src/vscode-bicep/src/test/e2e/deploypane.test.ts index 626dc2ffd55..6442624d334 100644 --- a/src/vscode-bicep/src/test/e2e/deploypane.test.ts +++ b/src/vscode-bicep/src/test/e2e/deploypane.test.ts @@ -6,14 +6,9 @@ import path from "path"; import vscode from "vscode"; import { e2eLogName } from "../../utils/logger"; import { sleep } from "../../utils/time"; - import { expectDefined } from "../utils/assert"; import { until } from "../utils/time"; -import { - executeCloseAllEditors, - executeShowDeployPaneCommand, - executeShowDeployPaneToSideCommand, -} from "./commands"; +import { executeCloseAllEditors, executeShowDeployPaneCommand, executeShowDeployPaneToSideCommand } from "./commands"; import { resolveExamplePath } from "./examples"; const extensionLogPath = path.join(__dirname, `../../../${e2eLogName}`); @@ -33,10 +28,7 @@ describe("deploypane", (): void => { expect(viewColumn).toBe(editor.viewColumn); }); - it.each([ - resolveExamplePath("201", "sql", "main.bicepparam"), - resolveExamplePath("201", "sql", "main.bicep"), - ])( + it.each([resolveExamplePath("201", "sql", "main.bicepparam"), resolveExamplePath("201", "sql", "main.bicep")])( "should open deployment pane webview to side for %s", async (examplePath) => { const { document } = await openDocument(examplePath); diff --git a/src/vscode-bicep/src/test/e2e/emptyConfigFileSnippets.test.ts b/src/vscode-bicep/src/test/e2e/emptyConfigFileSnippets.test.ts index b697813058b..4850cbab1e9 100644 --- a/src/vscode-bicep/src/test/e2e/emptyConfigFileSnippets.test.ts +++ b/src/vscode-bicep/src/test/e2e/emptyConfigFileSnippets.test.ts @@ -1,23 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -/* eslint-disable @typescript-eslint/no-non-null-assertion */ - -import vscode, { - CompletionItem, - SnippetString, - window, - workspace, -} from "vscode"; -import path from "path"; import fs from "fs"; -import { - executeCloseAllEditors, - executeCompletionItemProvider, -} from "./commands"; +import path from "path"; +import vscode, { CompletionItem, SnippetString, window, workspace } from "vscode"; import { createUniqueTempFolder } from "../utils/createUniqueTempFolder"; import { normalizeLineEndings } from "../utils/normalizeLineEndings"; import { testScope } from "../utils/testScope"; +import { executeCloseAllEditors, executeCompletionItemProvider } from "./commands"; import { expectedNewConfigFileContents } from "./expectedNewConfigFileContents"; describe("empty config file snippets", (): void => { @@ -38,10 +28,7 @@ describe("empty config file snippets", (): void => { let items: CompletionItem[]; await testScope("Find available completions", async () => { - const completions = await executeCompletionItemProvider( - doc.uri, - new vscode.Position(0, 0), - ); + const completions = await executeCompletionItemProvider(doc.uri, new vscode.Position(0, 0)); expect(true).toBe(true); expect(completions).toBeDefined(); items = completions!.items; @@ -50,9 +37,7 @@ describe("empty config file snippets", (): void => { let scaffoldSnippet: CompletionItem | undefined; await testScope("Find the snippet of interest", async () => { - scaffoldSnippet = items.find( - (i) => getCompletionLabelText(i) === "Default Bicep Configuration", - ); + scaffoldSnippet = items.find((i) => getCompletionLabelText(i) === "Default Bicep Configuration"); expect(scaffoldSnippet).toBeDefined(); }); await testScope(" ... and insert it", async () => { @@ -61,9 +46,7 @@ describe("empty config file snippets", (): void => { await testScope("Verify inserted snippet", () => { const textAfterInsertion = editor.document.getText(); - expect(normalizeLineEndings(textAfterInsertion)).toBe( - normalizeLineEndings(expectedAfterInsertion), - ); + expect(normalizeLineEndings(textAfterInsertion)).toBe(normalizeLineEndings(expectedAfterInsertion)); }); /* TODO: DISABLED (FLAKY) - see https://github.com/Azure/bicep/issues/6766 @@ -99,7 +82,5 @@ describe("empty config file snippets", (): void => { }); function getCompletionLabelText(snippet: CompletionItem): string { - return typeof snippet.label === "string" - ? snippet.label - : snippet.label.label; + return typeof snippet.label === "string" ? snippet.label : snippet.label.label; } diff --git a/src/vscode-bicep/src/test/e2e/environment.ts b/src/vscode-bicep/src/test/e2e/environment.ts index 8552817c052..b24f25bb56b 100644 --- a/src/vscode-bicep/src/test/e2e/environment.ts +++ b/src/vscode-bicep/src/test/e2e/environment.ts @@ -7,9 +7,7 @@ class VSCodeEnvironment extends NodeEnvironment { async setup(): Promise { await super.setup(); - const bicepExtension = vscode.extensions.getExtension( - "ms-azuretools.vscode-bicep", - ); + const bicepExtension = vscode.extensions.getExtension("ms-azuretools.vscode-bicep"); if (!bicepExtension) { throw Error("Extension not found."); diff --git a/src/vscode-bicep/src/test/e2e/examples/index.ts b/src/vscode-bicep/src/test/e2e/examples/index.ts index d983999800c..ce1b226a3ad 100644 --- a/src/vscode-bicep/src/test/e2e/examples/index.ts +++ b/src/vscode-bicep/src/test/e2e/examples/index.ts @@ -1,37 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import * as path from "path"; import { readFileSync } from "fs"; +import * as path from "path"; // Cannot use __dirname because the .bicep files won't be copied to /out. -const examplesRoot = path.resolve( - __dirname, - "../../../../src/test/e2e/examples", -); +const examplesRoot = path.resolve(__dirname, "../../../../src/test/e2e/examples"); -export function resolveExamplePath( - exampleCategory: string, - exampleFolder: string, - exampleFile = "main.bicep", -): string { - return path.resolve( - examplesRoot, - exampleCategory, - exampleFolder, - exampleFile, - ); +export function resolveExamplePath(exampleCategory: string, exampleFolder: string, exampleFile = "main.bicep"): string { + return path.resolve(examplesRoot, exampleCategory, exampleFolder, exampleFile); } -export function readExampleFile( - exampleCategory: string, - exampleFolder: string, - exampleFile = "main.bicep", -): string { - const exampleFilePath = resolveExamplePath( - exampleCategory, - exampleFolder, - exampleFile, - ); +export function readExampleFile(exampleCategory: string, exampleFolder: string, exampleFile = "main.bicep"): string { + const exampleFilePath = resolveExamplePath(exampleCategory, exampleFolder, exampleFile); return readFileSync(exampleFilePath, { encoding: "utf-8", flag: "r" }); } diff --git a/src/vscode-bicep/src/test/e2e/hover.test.ts b/src/vscode-bicep/src/test/e2e/hover.test.ts index aad93ddb9f6..8dfec53ee4c 100644 --- a/src/vscode-bicep/src/test/e2e/hover.test.ts +++ b/src/vscode-bicep/src/test/e2e/hover.test.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. + +/* eslint-disable jest/expect-expect */ import * as vscode from "vscode"; import { sleep } from "../../utils/time"; - import { expectDefined, expectRange } from "../utils/assert"; import { retryWhile } from "../utils/time"; import { executeCloseAllEditors, executeHoverProvider } from "./commands"; @@ -30,10 +31,7 @@ describe("hover", (): void => { }); it("should reveal type signature when hovering over a parameter name", async () => { - const hovers = await executeHoverProviderCommandWithRetry( - document.uri, - new vscode.Position(1, 7), - ); + const hovers = await executeHoverProviderCommandWithRetry(document.uri, new vscode.Position(1, 7)); expectHovers(hovers, { startLine: 1, @@ -45,10 +43,7 @@ describe("hover", (): void => { }); it("should reveal type signature when hovering over a variable name", async () => { - const hovers = await executeHoverProviderCommandWithRetry( - document.uri, - new vscode.Position(50, 10), - ); + const hovers = await executeHoverProviderCommandWithRetry(document.uri, new vscode.Position(50, 10)); expectHovers(hovers, { startLine: 50, @@ -60,10 +55,7 @@ describe("hover", (): void => { }); it("should reveal type signature when hovering over a resource symbolic name", async () => { - const hovers = await executeHoverProviderCommandWithRetry( - document.uri, - new vscode.Position(108, 10), - ); + const hovers = await executeHoverProviderCommandWithRetry(document.uri, new vscode.Position(108, 10)); expectHovers(hovers, { startLine: 108, @@ -80,10 +72,7 @@ describe("hover", (): void => { }); it("should reveal type signature when hovering over an output name", async () => { - const hovers = await executeHoverProviderCommandWithRetry( - document.uri, - new vscode.Position(183, 14), - ); + const hovers = await executeHoverProviderCommandWithRetry(document.uri, new vscode.Position(183, 14)); expectHovers(hovers, { startLine: 183, @@ -95,10 +84,7 @@ describe("hover", (): void => { }); it("should reveal type signature when hovering over a function name", async () => { - const hovers = await executeHoverProviderCommandWithRetry( - document.uri, - new vscode.Position(18, 60), - ); + const hovers = await executeHoverProviderCommandWithRetry(document.uri, new vscode.Position(18, 60)); expectHovers(hovers, { startLine: 18, @@ -114,10 +100,7 @@ describe("hover", (): void => { }); }); - function executeHoverProviderCommandWithRetry( - documentUri: vscode.Uri, - position: vscode.Position, - ) { + function executeHoverProviderCommandWithRetry(documentUri: vscode.Uri, position: vscode.Position) { return retryWhile( async () => await executeHoverProvider(documentUri, position), (hovers) => hovers === undefined || hovers.length === 0, @@ -137,17 +120,10 @@ describe("hover", (): void => { expectDefined(hovers); expect(hovers).toHaveLength(expectedHovers.length); hovers.forEach((hover, hoverIndex) => { - const { startLine, startCharacter, endLine, endCharacter, contents } = - expectedHovers[hoverIndex]; + const { startLine, startCharacter, endLine, endCharacter, contents } = expectedHovers[hoverIndex]; expectDefined(hover.range); - expectRange( - hover.range, - startLine, - startCharacter, - endLine, - endCharacter, - ); + expectRange(hover.range, startLine, startCharacter, endLine, endCharacter); expect(hover.contents).toHaveLength(contents.length); hover.contents.forEach((content, contentIndex) => { expect(normalizeMarkedString(content)).toBe(contents[contentIndex]); @@ -155,9 +131,7 @@ describe("hover", (): void => { }); } - function normalizeMarkedString( - content: vscode.MarkedString | vscode.MarkdownString, - ): string { + function normalizeMarkedString(content: vscode.MarkedString | vscode.MarkdownString): string { return typeof content === "string" ? content : content.value; } @@ -165,10 +139,7 @@ describe("hover", (): void => { return "```bicep\n" + rawString + "\n``` \n"; } - function codeblockWithDescription( - rawString: string, - description: string, - ): string { + function codeblockWithDescription(rawString: string, description: string): string { return `${codeblock(rawString)}${description} \n`; } }); diff --git a/src/vscode-bicep/src/test/e2e/pasteAsBicep.test.ts b/src/vscode-bicep/src/test/e2e/pasteAsBicep.test.ts index e7ffd1f6631..41d84a6e626 100644 --- a/src/vscode-bicep/src/test/e2e/pasteAsBicep.test.ts +++ b/src/vscode-bicep/src/test/e2e/pasteAsBicep.test.ts @@ -3,21 +3,17 @@ /* eslint-disable jest/expect-expect */ +import assert from "assert"; +import * as path from "path"; +import * as fse from "fs-extra"; import vscode, { ConfigurationTarget, Selection, TextDocument } from "vscode"; -import { - executeCloseAllEditors, - executeEditorPasteCommand, - executePasteAsBicepCommand, -} from "./commands"; -import { getBicepConfiguration } from "../../language/getBicepConfiguration"; -import { normalizeMultilineString } from "../utils/normalizeMultilineString"; import { SuppressedWarningsManager } from "../../commands/SuppressedWarningsManager"; import { bicepConfigurationKeys } from "../../language/constants"; -import assert from "assert"; -import { until } from "../utils/time"; -import * as fse from "fs-extra"; -import * as path from "path"; +import { getBicepConfiguration } from "../../language/getBicepConfiguration"; import { e2eLogName } from "../../utils/logger"; +import { normalizeMultilineString } from "../utils/normalizeMultilineString"; +import { until } from "../utils/time"; +import { executeCloseAllEditors, executeEditorPasteCommand, executePasteAsBicepCommand } from "./commands"; const extensionLogPath = path.join(__dirname, `../../../${e2eLogName}`); @@ -28,11 +24,7 @@ describe("pasteAsBicep", (): void => { async function configureSettings(): Promise { // Make sure Decompile on Paste is on - await getBicepConfiguration().update( - bicepConfigurationKeys.decompileOnPaste, - true, - ConfigurationTarget.Global, - ); + await getBicepConfiguration().update(bicepConfigurationKeys.decompileOnPaste, true, ConfigurationTarget.Global); // Make sure decompile on paste warning is on await getBicepConfiguration().update( @@ -42,9 +34,7 @@ describe("pasteAsBicep", (): void => { ); } - function getTextAndMarkers( - s: string, - ): [text: string, markerOffset: number, markerLength: number] { + function getTextAndMarkers(s: string): [text: string, markerOffset: number, markerLength: number] { const offset = s.indexOf("|"); assert(offset >= 0, "Couldn't find marker in text"); @@ -62,11 +52,7 @@ describe("pasteAsBicep", (): void => { return [s, offset, length]; } - function setSelection( - document: TextDocument, - offsetStart: number, - offsetLength: number, - ): void { + function setSelection(document: TextDocument, offsetStart: number, offsetLength: number): void { const start = document.positionAt(offsetStart); const end = document.positionAt(offsetStart + offsetLength); const activeTextEditor = vscode.window.activeTextEditor; @@ -83,15 +69,11 @@ describe("pasteAsBicep", (): void => { error?: string; }, ): Promise<{ log: string }> { - const initialLogContentsLength = fse - .readFileSync(extensionLogPath) - .toString().length; + const initialLogContentsLength = fse.readFileSync(extensionLogPath).toString().length; await configureSettings(); - const [initialBicep, offsetStart, offsetLength] = getTextAndMarkers( - initialBicepWithMarker, - ); + const [initialBicep, offsetStart, offsetLength] = getTextAndMarkers(initialBicepWithMarker); const textDocument = await vscode.workspace.openTextDocument({ language: "bicep", content: initialBicep, @@ -114,9 +96,7 @@ describe("pasteAsBicep", (): void => { await waitForPasteAsBicep(expected); } if (expected.error) { - const match = new RegExp( - `Exception occurred: .*${escapeRegexReplacement(expected.error)}`, - ); + const match = new RegExp(`Exception occurred: .*${escapeRegexReplacement(expected.error)}`); expect(getRecentLogContents()).toMatch(match); } else { expect(getRecentLogContents()).not.toMatch(`Exception occurred`); @@ -125,24 +105,17 @@ describe("pasteAsBicep", (): void => { const buffer = textDocument.getText(); if (typeof expected.bicep === "string") { - expect(normalizeMultilineString(buffer)).toBe( - normalizeMultilineString(expected.bicep), - ); + expect(normalizeMultilineString(buffer)).toBe(normalizeMultilineString(expected.bicep)); } return { log: getRecentLogContents() }; function getRecentLogContents() { - const logContents = fse - .readFileSync(extensionLogPath) - .toString() - .substring(initialLogContentsLength); + const logContents = fse.readFileSync(extensionLogPath).toString().substring(initialLogContentsLength); return logContents; } - async function waitForPasteAsBicep( - expectedSubstring: string, - ): Promise { + async function waitForPasteAsBicep(expectedSubstring: string): Promise { await until(() => isReady(), { interval: 100, timeoutMs: 4000, diff --git a/src/vscode-bicep/src/test/e2e/runTests.ts b/src/vscode-bicep/src/test/e2e/runTests.ts index 62f6a6d3480..8e4c370e2e9 100644 --- a/src/vscode-bicep/src/test/e2e/runTests.ts +++ b/src/vscode-bicep/src/test/e2e/runTests.ts @@ -1,30 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import * as path from "path"; import * as cp from "child_process"; -import * as os from "os"; import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; +import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from "@vscode/test-electron"; import { minVersion } from "semver"; -import { - runTests, - downloadAndUnzipVSCode, - resolveCliArgsFromVSCodeExecutablePath, -} from "@vscode/test-electron"; async function go() { try { // Do not import the json file directly because it's not under /src. // We also don't want it to be included in the /out folder. const packageJsonPath = path.resolve(__dirname, "../../../package.json"); - const packageJson = JSON.parse( - fs.readFileSync(packageJsonPath, { encoding: "utf-8" }), - ); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: "utf-8" })); const minSupportedVSCodeSemver = minVersion(packageJson.engines.vscode); if (!minSupportedVSCodeSemver) { - throw new Error( - "Ensure 'engines.vscode' is properly set in package.json", - ); + throw new Error("Ensure 'engines.vscode' is properly set in package.json"); } const vscodeVersionsToVerify = [minSupportedVSCodeSemver.version, "stable"]; @@ -33,8 +25,7 @@ async function go() { console.log(`Running tests against VSCode-${vscodeVersion}`); const vscodeExecutablePath = await downloadAndUnzipVSCode(vscodeVersion); - const [cliRawPath, ...cliArguments] = - resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); + const [cliRawPath, ...cliArguments] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); const cliPath = `"${cliRawPath}"`; const isRoot = os.userInfo().username === "root"; @@ -50,16 +41,10 @@ async function go() { "ms-dotnettools.vscode-dotnet-runtime", ...userDataArguments, ]; - const extensionListArguments = [ - ...cliArguments, - "--list-extensions", - ...userDataArguments, - ]; + const extensionListArguments = [...cliArguments, "--list-extensions", ...userDataArguments]; // Install .NET Install Tool extension as a dependency. - console.log( - `Installing dotnet extension: ${cliPath} ${extensionInstallArguments.join(" ")}`, - ); + console.log(`Installing dotnet extension: ${cliPath} ${extensionInstallArguments.join(" ")}`); let result = cp.spawnSync(cliPath, extensionInstallArguments, { encoding: "utf-8", stdio: "inherit", diff --git a/src/vscode-bicep/src/test/e2e/runner.ts b/src/vscode-bicep/src/test/e2e/runner.ts index 0d27aef1de9..33e00d01b39 100644 --- a/src/vscode-bicep/src/test/e2e/runner.ts +++ b/src/vscode-bicep/src/test/e2e/runner.ts @@ -11,9 +11,7 @@ export function createTestRunner(configFile: string): TestRunner { const workspaceRoot = path.resolve(__dirname, "../../.."); const config = require(path.join(workspaceRoot, configFile)); // eslint-disable-line @typescript-eslint/no-var-requires - const { results } = await runCLI({ _: [], $0: "", ...config }, [ - workspaceRoot, - ]); + const { results } = await runCLI({ _: [], $0: "", ...config }, [workspaceRoot]); if (results.numFailedTestSuites > 0 || results.numFailedTests > 0) { process.exit(1); diff --git a/src/vscode-bicep/src/test/e2e/surveys.e2e.test.ts b/src/vscode-bicep/src/test/e2e/surveys.e2e.test.ts index f9d67d9a063..92bf9af3ba8 100644 --- a/src/vscode-bicep/src/test/e2e/surveys.e2e.test.ts +++ b/src/vscode-bicep/src/test/e2e/surveys.e2e.test.ts @@ -57,28 +57,19 @@ describe("surveys-e2etests", () => { expect(context.telemetry.properties.surveyLinkStatus).toBe("ENOTFOUND"); }); - // eslint-disable-next-line jest/prefer-lowercase-title it("Other errors", async () => { const context = createActionContextMock(); - const isAvailable = await Survey.getIsSurveyAvailable( - context, - "foo://aka.ms/bicep/tests/surveytests/active", - ); + const isAvailable = await Survey.getIsSurveyAvailable(context, "foo://aka.ms/bicep/tests/surveytests/active"); expect(isAvailable).toBeFalsy(); - expect(context.telemetry.properties.surveyLinkStatus).toBe( - "ERR_INVALID_PROTOCOL", - ); + expect(context.telemetry.properties.surveyLinkStatus).toBe("ERR_INVALID_PROTOCOL"); }); it("other status code returned", async () => { const context = createActionContextMock(); - const isAvailable = await Survey.getIsSurveyAvailable( - context, - "https://github.com/Azure/bicep", - ); + const isAvailable = await Survey.getIsSurveyAvailable(context, "https://github.com/Azure/bicep"); expect(isAvailable).toBeFalsy(); expect(context.telemetry.properties.surveyLinkStatus).toBe("200"); diff --git a/src/vscode-bicep/src/test/e2e/testReporter.ts b/src/vscode-bicep/src/test/e2e/testReporter.ts index 6ef72736dbc..7e72f355bb3 100644 --- a/src/vscode-bicep/src/test/e2e/testReporter.ts +++ b/src/vscode-bicep/src/test/e2e/testReporter.ts @@ -1,12 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { TestContext, Reporter, Test } from "@jest/reporters"; +import { Reporter, Test, TestContext } from "@jest/reporters"; import { AggregatedResult, TestResult } from "@jest/test-result"; -export default class TestReporter - implements Pick -{ - onTestResult(test: Test, { testResults }: TestResult): void { +export default class TestReporter implements Pick { + onTestResult(_test: Test, { testResults }: TestResult): void { for (const testResult of testResults) { switch (testResult.status) { case "passed": @@ -30,13 +28,9 @@ export default class TestReporter } } - onRunComplete(contexts: Set, results: AggregatedResult): void { + onRunComplete(_contexts: Set, results: AggregatedResult): void { console.log(""); - console.log( - `Test Suites: ${results.numPassedTestSuites} passed, ${results.numTotalTestSuites} total`, - ); - console.log( - `Tests: ${results.numPassedTestSuites} passed, ${results.numTotalTestSuites} total`, - ); + console.log(`Test Suites: ${results.numPassedTestSuites} passed, ${results.numTotalTestSuites} total`); + console.log(`Tests: ${results.numPassedTestSuites} passed, ${results.numTotalTestSuites} total`); } } diff --git a/src/vscode-bicep/src/test/e2e/visualizer.test.ts b/src/vscode-bicep/src/test/e2e/visualizer.test.ts index 2768c363711..6eaf4b4a037 100644 --- a/src/vscode-bicep/src/test/e2e/visualizer.test.ts +++ b/src/vscode-bicep/src/test/e2e/visualizer.test.ts @@ -6,7 +6,6 @@ import path from "path"; import vscode from "vscode"; import { e2eLogName } from "../../utils/logger"; import { sleep } from "../../utils/time"; - import { expectDefined } from "../utils/assert"; import { until } from "../utils/time"; import { @@ -35,9 +34,7 @@ describe("visualizer", (): void => { interval: 100, }); if (!visualizerIsReady(document.uri)) { - throw new Error( - `Expected visualizer to be ready for ${document.uri.toString()}`, - ); + throw new Error(`Expected visualizer to be ready for ${document.uri.toString()}`); } expectDefined(viewColumn); expect(viewColumn).toBe(editor.viewColumn); @@ -55,9 +52,7 @@ describe("visualizer", (): void => { interval: 100, }); if (!visualizerIsReady(document.uri)) { - throw new Error( - `Expected visualizer to be ready for ${document.uri.toString()}`, - ); + throw new Error(`Expected visualizer to be ready for ${document.uri.toString()}`); } expectDefined(viewColumn); expect(viewColumn).toBe(vscode.ViewColumn.Beside); @@ -76,9 +71,7 @@ describe("visualizer", (): void => { }); if (!visualizerIsReady(document.uri)) { - throw new Error( - `Expected visualizer to be ready for ${document.uri.toString()}`, - ); + throw new Error(`Expected visualizer to be ready for ${document.uri.toString()}`); } const sourceEditor = await executeShowSourceCommand(); diff --git a/src/vscode-bicep/src/test/fakes/globalStateFake.ts b/src/vscode-bicep/src/test/fakes/globalStateFake.ts index cf5a54e3f48..fb993260efb 100644 --- a/src/vscode-bicep/src/test/fakes/globalStateFake.ts +++ b/src/vscode-bicep/src/test/fakes/globalStateFake.ts @@ -5,8 +5,7 @@ import { GlobalState } from "../../globalState"; import { sleep } from "../../utils/time"; export class GlobalStateFake implements GlobalState { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private dictionary = new Map(); + private dictionary = new Map(); public keys(): readonly string[] { throw new Error("Method not implemented."); @@ -14,11 +13,8 @@ export class GlobalStateFake implements GlobalState { public get(key: string): T | undefined; public get(key: string, defaultValue: T): T; - public get( - key: string, - defaultValue: T | undefined = undefined, - ): T | undefined { - return this.dictionary.get(key) || defaultValue; + public get(key: string, defaultValue: T | undefined = undefined): T | undefined { + return this.dictionary.get(key) as T || defaultValue; } public async update(key: string, value: T): Promise { @@ -27,7 +23,7 @@ export class GlobalStateFake implements GlobalState { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - public setKeysForSync(keys: string[]): void { + public setKeysForSync(_keys: string[]): void { throw new Error("Method not implemented."); } } diff --git a/src/vscode-bicep/src/test/fakes/workspaceConfigurationFake.ts b/src/vscode-bicep/src/test/fakes/workspaceConfigurationFake.ts index c7449745810..5e46a90882c 100644 --- a/src/vscode-bicep/src/test/fakes/workspaceConfigurationFake.ts +++ b/src/vscode-bicep/src/test/fakes/workspaceConfigurationFake.ts @@ -23,7 +23,7 @@ export class WorkspaceConfigurationFake implements WorkspaceConfiguration { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - public inspect(section: string): + public inspect(_section: string): | { key: string; defaultValue?: T | undefined; @@ -47,10 +47,7 @@ export class WorkspaceConfigurationFake implements WorkspaceConfiguration { configurationTarget?: boolean | ConfigurationTarget | null | undefined, overrideInLanguage?: boolean | undefined, ): Promise { - if ( - configurationTarget !== ConfigurationTarget.Global && - configurationTarget !== true - ) { + if (configurationTarget !== ConfigurationTarget.Global && configurationTarget !== true) { throw new Error( "Functionality not implemented: WorkspaceConfigurationFake currently only supports global configuration target", ); diff --git a/src/vscode-bicep/src/test/snapshot/App.test.tsx b/src/vscode-bicep/src/test/snapshot/App.test.tsx index 66116bbe828..3556f566e90 100644 --- a/src/vscode-bicep/src/test/snapshot/App.test.tsx +++ b/src/vscode-bicep/src/test/snapshot/App.test.tsx @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import renderer from "react-test-renderer"; + import "jest-styled-components"; import { App } from "../../visualizer/app/components/App"; diff --git a/src/vscode-bicep/src/test/snapshot/Graph.test.tsx b/src/vscode-bicep/src/test/snapshot/Graph.test.tsx index d7f37f49193..7590b6e2afa 100644 --- a/src/vscode-bicep/src/test/snapshot/Graph.test.tsx +++ b/src/vscode-bicep/src/test/snapshot/Graph.test.tsx @@ -2,6 +2,7 @@ // Licensed under the MIT License. import renderer from "react-test-renderer"; import { ThemeProvider } from "styled-components"; + import "jest-styled-components"; import { Graph } from "../../visualizer/app/components/Graph"; @@ -12,7 +13,7 @@ describe("component Graph", () => { const graph = renderer.create( - + , ); expect(graph.toJSON()).toMatchSnapshot(); diff --git a/src/vscode-bicep/src/test/unit/getTextAfterFormattingChanges.test.ts b/src/vscode-bicep/src/test/unit/getTextAfterFormattingChanges.test.ts index 1bfdd0ec022..f94621cc8eb 100644 --- a/src/vscode-bicep/src/test/unit/getTextAfterFormattingChanges.test.ts +++ b/src/vscode-bicep/src/test/unit/getTextAfterFormattingChanges.test.ts @@ -111,11 +111,7 @@ and `; - const result = getTextAfterFormattingChanges( - textToMatch, - editorText, - editorText.indexOf("\r\n\tThis has"), - ); + const result = getTextAfterFormattingChanges(textToMatch, editorText, editorText.indexOf("\r\n\tThis has")); expect(result).toBe(expected); }); @@ -133,11 +129,7 @@ This is text that won't match `; - const result = getTextAfterFormattingChanges( - textToMatch, - editorText, - editorText.indexOf("This is text that"), - ); + const result = getTextAfterFormattingChanges(textToMatch, editorText, editorText.indexOf("This is text that")); expect(result).toBeUndefined(); }); @@ -150,11 +142,7 @@ This is text that won't match const editorText = ` This is text`; - const result = getTextAfterFormattingChanges( - textToMatch, - editorText, - editorText.indexOf("This is text"), - ); + const result = getTextAfterFormattingChanges(textToMatch, editorText, editorText.indexOf("This is text")); expect(result).toBeUndefined(); }); }); diff --git a/src/vscode-bicep/src/test/unit/logger.test.ts b/src/vscode-bicep/src/test/unit/logger.test.ts index 23de70efc7a..a12d9750c4a 100644 --- a/src/vscode-bicep/src/test/unit/logger.test.ts +++ b/src/vscode-bicep/src/test/unit/logger.test.ts @@ -1,7 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +import * as vscode from "vscode"; +import * as winston from "winston"; +import * as loggerModule from "../../utils/logger"; +import { expectDefined } from "../utils/assert"; + // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -// eslint-disable-next-line jest/no-untyped-mock-factory jest.mock("winston", () => ({ createLogger: () => mockWinstonLogger, format: { @@ -15,12 +21,6 @@ jest.mock("winston", () => ({ }, })); -import * as vscode from "vscode"; -import * as winston from "winston"; - -import * as loggerModule from "../../utils/logger"; -import { expectDefined } from "../utils/assert"; - const mockWinstonLogger = { clear: jest.fn(), close: jest.fn(), @@ -54,10 +54,9 @@ const mockOutputChannel: vscode.OutputChannel = { replace: jest.fn(), }; -const { createLogger, getLogger, resetLogger, WinstonLogger } = - loggerModule as typeof loggerModule & { - resetLogger: () => void; - }; +const { createLogger, getLogger, resetLogger, WinstonLogger } = loggerModule as typeof loggerModule & { + resetLogger: () => void; +}; describe("createLogger()", () => { it("should add a new logger to disposibles subscription", () => { @@ -70,11 +69,10 @@ describe("createLogger()", () => { describe("getLogger()", () => { it("should throw if createLogger() is not called first", () => { resetLogger(); - expect(() => getLogger()).toThrow( - "Logger is undefined. Make sure to call createLogger() first.", - ); + expect(() => getLogger()).toThrow("Logger is undefined. Make sure to call createLogger() first."); }); + // eslint-disable-next-line jest/expect-expect it("should return a logger if createLogger() is called first", () => { resetLogger(); createLogger(mockContext, mockOutputChannel); @@ -99,18 +97,11 @@ describe("winstonLogger", () => { expect(mockWinstonLogger.close).toHaveBeenCalledTimes(1); }); - it.each(["debug", "info", "warn", "error"] as const)( - "should should log message at %s level", - (level) => { - const logger = new WinstonLogger(mockOutputChannel, "info"); + it.each(["debug", "info", "warn", "error"] as const)("should should log message at %s level", (level) => { + const logger = new WinstonLogger(mockOutputChannel, "info"); - logger[level]("something"); + logger[level]("something"); - expect(mockWinstonLogger.log).toHaveBeenNthCalledWith( - 1, - level, - "something", - ); - }, - ); + expect(mockWinstonLogger.log).toHaveBeenNthCalledWith(1, level, "something"); + }); }); diff --git a/src/vscode-bicep/src/test/unit/packageJson.test.ts b/src/vscode-bicep/src/test/unit/packageJson.test.ts index 6680d5f0e53..ec4f155902a 100644 --- a/src/vscode-bicep/src/test/unit/packageJson.test.ts +++ b/src/vscode-bicep/src/test/unit/packageJson.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import * as fse from "fs-extra"; import * as path from "path"; +import * as fse from "fs-extra"; type IPackageKeyBinding = { command: string; @@ -28,8 +28,7 @@ describe("package.json tests", () => { const packageJson = getPackageJson(); // If there are no keybindings found we're doing something wrong in the test - const bindings: IPackageKeyBinding[] = - packageJson.contributes?.keybindings ?? []; + const bindings: IPackageKeyBinding[] = packageJson.contributes?.keybindings ?? []; expect(bindings).not.toHaveLength(0); for (const binding of bindings) { diff --git a/src/vscode-bicep/src/test/unit/removePropertiesWithPossibleUserInfo.test.ts b/src/vscode-bicep/src/test/unit/removePropertiesWithPossibleUserInfo.test.ts index a0a96957bf7..9aec8bd3395 100644 --- a/src/vscode-bicep/src/test/unit/removePropertiesWithPossibleUserInfo.test.ts +++ b/src/vscode-bicep/src/test/unit/removePropertiesWithPossibleUserInfo.test.ts @@ -53,13 +53,10 @@ describe("removePropertiesWithPossibleUserInfoInDeployParams()", () => { ), ) .join(""); - const string10MB = (string10K + withToken).repeat( - Math.ceil(10000000 / (string10K.length + withToken.length)), - ); + const string10MB = (string10K + withToken).repeat(Math.ceil(10000000 / (string10K.length + withToken.length))); const start = Date.now(); - const actual = - removePropertiesWithPossibleUserInfoInDeployParams(string10MB); + const actual = removePropertiesWithPossibleUserInfoInDeployParams(string10MB); const duration = Date.now() - start; expect(actual).not.toContain("eyJ0eXAi"); diff --git a/src/vscode-bicep/src/test/unit/surveys.unit.test.ts b/src/vscode-bicep/src/test/unit/surveys.unit.test.ts index fed32af9190..094f7533eaa 100644 --- a/src/vscode-bicep/src/test/unit/surveys.unit.test.ts +++ b/src/vscode-bicep/src/test/unit/surveys.unit.test.ts @@ -1,15 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -/* eslint-disable jest/max-expects */ - import { IActionContext } from "@microsoft/vscode-azext-utils"; import { MessageItem, window } from "vscode"; -import { - IPersistedSurveyState, - ISurveyInfo, - Survey, -} from "../../feedback/surveys"; +import { IPersistedSurveyState, ISurveyInfo, Survey } from "../../feedback/surveys"; import { bicepConfigurationKeys } from "../../language/constants"; import { daysToMs, monthsToDays, weeksToDays } from "../../utils/time"; import { GlobalStateFake } from "../fakes/globalStateFake"; @@ -20,13 +14,9 @@ describe("surveys-unittests", () => { function createMocks(options: { surveyInfo?: ISurveyInfo; isSurveyAvailable: boolean; - showInformationMessageMock?: jest.Mock< - typeof window.showInformationMessage - >; + showInformationMessageMock?: jest.Mock; getIsSurveyAvailableMock?: jest.Mock<() => Promise>; - launchSurveyMock?: jest.Mock< - (context: IActionContext, surveyInfo: ISurveyInfo) => Promise - >; + launchSurveyMock?: jest.Mock<(context: IActionContext, surveyInfo: ISurveyInfo) => Promise>; }) { const globalStorageFake = new GlobalStateFake(); const surveyInfo = @@ -38,18 +28,14 @@ describe("surveys-unittests", () => { surveyPrompt: "prompt", surveyStateKey: "testSurvey", }; - const showInformationMessageMock = - options.showInformationMessageMock ?? jest.fn(); - const getIsSurveyAvailableMock = - options.getIsSurveyAvailableMock ?? jest.fn(); + const showInformationMessageMock = options.showInformationMessageMock ?? jest.fn(); + const getIsSurveyAvailableMock = options.getIsSurveyAvailableMock ?? jest.fn(); const launchSurveyMock = options.launchSurveyMock ?? jest.fn(); const workspaceConfigurationFake = new WorkspaceConfigurationFake(); const survey = new Survey(globalStorageFake, surveyInfo, { showInformationMessage: showInformationMessageMock, - getIsSurveyAvailable: jest - .fn() - .mockImplementation(async () => options.isSurveyAvailable), + getIsSurveyAvailable: jest.fn().mockImplementation(async () => options.isSurveyAvailable), launchSurvey: launchSurveyMock, provideBicepConfiguration: () => workspaceConfigurationFake, }); @@ -66,11 +52,7 @@ describe("surveys-unittests", () => { it("doesn't prompt again if user responds never", async () => { const mocks = createMocks({ isSurveyAvailable: true }); - expect( - mocks.workspaceConfigurationFake.get( - bicepConfigurationKeys.enableSurveys, - ), - ).toBeUndefined(); + expect(mocks.workspaceConfigurationFake.get(bicepConfigurationKeys.enableSurveys)).toBeUndefined(); // Show and respond with "Never" mocks.showInformationMessageMock.mockResolvedValueOnce({ @@ -80,11 +62,7 @@ describe("surveys-unittests", () => { await mocks.survey.checkShowSurvey(createActionContextMock(), new Date()); expect(mocks.showInformationMessageMock).toHaveBeenCalledTimes(1); - expect( - mocks.workspaceConfigurationFake.get( - bicepConfigurationKeys.enableSurveys, - ), - ).toBe(false); + expect(mocks.workspaceConfigurationFake.get(bicepConfigurationKeys.enableSurveys)).toBe(false); // Try again, should not show mocks.showInformationMessageMock.mockClear(); @@ -138,14 +116,8 @@ describe("surveys-unittests", () => { await mocks.survey.checkShowSurvey(context, now); expect(mocks.showInformationMessageMock).toHaveBeenCalledTimes(1); - expect( - mocks.globalStorageFake.get("testSurvey") - ?.postponedUntilMs, - ).toBeFalsy(); - expect( - mocks.globalStorageFake.get("testSurvey") - ?.lastTakenMs, - ).toBe(now.valueOf()); + expect(mocks.globalStorageFake.get("testSurvey")?.postponedUntilMs).toBeFalsy(); + expect(mocks.globalStorageFake.get("testSurvey")?.lastTakenMs).toBe(now.valueOf()); // Try again, right before the postponement date now = new Date(start.valueOf() + daysToMs(postponeAfterYes) - 1); @@ -197,10 +169,9 @@ describe("surveys-unittests", () => { await mocks.survey.checkShowSurvey(context, now); expect(mocks.showInformationMessageMock).toHaveBeenCalledTimes(1); - expect( - mocks.globalStorageFake.get("testSurvey") - ?.postponedUntilMs, - ).toBe(now.valueOf() + daysToMs(postponeLaterDays)); + expect(mocks.globalStorageFake.get("testSurvey")?.postponedUntilMs).toBe( + now.valueOf() + daysToMs(postponeLaterDays), + ); // Try again, a day before the postponement date now = new Date(start.valueOf() + daysToMs(postponeLaterDays - 1)); diff --git a/src/vscode-bicep/src/test/utils/createUniqueTempFolder.ts b/src/vscode-bicep/src/test/utils/createUniqueTempFolder.ts index baf79941177..5b43701a449 100644 --- a/src/vscode-bicep/src/test/utils/createUniqueTempFolder.ts +++ b/src/vscode-bicep/src/test/utils/createUniqueTempFolder.ts @@ -2,8 +2,8 @@ // Licensed under the MIT License. import * as os from "os"; -import * as fse from "fs-extra"; import * as path from "path"; +import * as fse from "fs-extra"; export function createUniqueTempFolder(filenamePrefix: string): string { const tempFolder = os.tmpdir(); diff --git a/src/vscode-bicep/src/test/utils/normalizeIndentation.ts b/src/vscode-bicep/src/test/utils/normalizeIndentation.ts index 429fa91bd24..426a26b1c24 100644 --- a/src/vscode-bicep/src/test/utils/normalizeIndentation.ts +++ b/src/vscode-bicep/src/test/utils/normalizeIndentation.ts @@ -5,12 +5,8 @@ export function normalizeIndentation(s: string, spacesPerTab = 2): string { const lines = s.split(/\r\n|\r|\n/); const indentations = lines.map((l) => l.length - l.trimStart().length); const uniqueTabStopValues = [...new Set(sortNumbers(indentations))]; - const lineTabStops = lines.map((l) => - uniqueTabStopValues.indexOf(l.length - l.trimStart().length), - ); - const newLines = lines.map( - (l, i) => repeat(" ", spacesPerTab * lineTabStops[i]) + l.trimStart(), - ); + const lineTabStops = lines.map((l) => uniqueTabStopValues.indexOf(l.length - l.trimStart().length)); + const newLines = lines.map((l, i) => repeat(" ", spacesPerTab * lineTabStops[i]) + l.trimStart()); return newLines.join("\n"); } diff --git a/src/vscode-bicep/src/test/utils/testScope.ts b/src/vscode-bicep/src/test/utils/testScope.ts index fad14b27518..018be1d53ee 100644 --- a/src/vscode-bicep/src/test/utils/testScope.ts +++ b/src/vscode-bicep/src/test/utils/testScope.ts @@ -3,15 +3,10 @@ import { parseError } from "@microsoft/vscode-azext-utils"; -export async function testScope( - testScopeName: string, - action: () => Promise | void, -): Promise { +export async function testScope(testScopeName: string, action: () => Promise | void): Promise { try { await action(); } catch (err) { - throw new Error( - `Test failure in scope "${testScopeName}":\n${parseError(err).message}`, - ); + throw new Error(`Test failure in scope "${testScopeName}":\n${parseError(err).message}`); } } diff --git a/src/vscode-bicep/src/test/utils/vscodeMocks.ts b/src/vscode-bicep/src/test/utils/vscodeMocks.ts index 4e5f8b2b55c..1c7ebf2e4b6 100644 --- a/src/vscode-bicep/src/test/utils/vscodeMocks.ts +++ b/src/vscode-bicep/src/test/utils/vscodeMocks.ts @@ -12,7 +12,7 @@ export function createCancellationTokenMock(): CancellationToken { } export function createWithProgressMock(): WithProgress { - return jest.fn().mockImplementation((options, task) => { + return jest.fn().mockImplementation((_options, task) => { return new Promise((resolve, reject) => { task( { diff --git a/src/vscode-bicep/src/tree/AzLocationTreeItem.ts b/src/vscode-bicep/src/tree/AzLocationTreeItem.ts index 779f75f0de1..d6b673a50f4 100644 --- a/src/vscode-bicep/src/tree/AzLocationTreeItem.ts +++ b/src/vscode-bicep/src/tree/AzLocationTreeItem.ts @@ -2,14 +2,11 @@ // Licensed under the MIT License. import { AzureAccountTreeItemBase } from "@microsoft/vscode-azext-azureutils"; import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; - import { LocationTreeItem } from "./LocationTreeItem"; // The root of treeview used in subscription scope deployment. Represents an Azure account export class AzLocationTreeItem extends AzureAccountTreeItemBase { - public createSubscriptionTreeItem( - root: ISubscriptionContext, - ): LocationTreeItem { + public createSubscriptionTreeItem(root: ISubscriptionContext): LocationTreeItem { return new LocationTreeItem(this, root); } } diff --git a/src/vscode-bicep/src/tree/AzLoginTreeItem.ts b/src/vscode-bicep/src/tree/AzLoginTreeItem.ts index eed25001789..821e482aa85 100644 --- a/src/vscode-bicep/src/tree/AzLoginTreeItem.ts +++ b/src/vscode-bicep/src/tree/AzLoginTreeItem.ts @@ -1,8 +1,5 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import * as semver from "semver"; -import { commands, Extension, extensions } from "vscode"; - import { AzExtParentTreeItem, AzExtTreeItem, @@ -10,16 +7,14 @@ import { IActionContext, registerEvent, } from "@microsoft/vscode-azext-utils"; - +import * as semver from "semver"; +import { commands, Extension, extensions } from "vscode"; import { AzureAccount, AzureLoginStatus } from "../azure/types"; import { localize } from "../utils/localize"; import { GenericAzExtTreeItem } from "./GenericAzExtTreeItem"; const signInLabel: string = localize("signInLabel", "Sign in to Azure..."); -const createAccountLabel: string = localize( - "createAccountLabel", - "Create a Free Azure Account...", -); +const createAccountLabel: string = localize("createAccountLabel", "Create a Free Azure Account..."); const signInCommandId = "azure-account.login"; const createAccountCommandId = "azure-account.createAccount"; const azureAccountExtensionId = "ms-vscode.azure-account"; @@ -107,15 +102,10 @@ export class AzLoginTreeItem extends AzExtParentTreeItem { public async getIsLoggedIn(): Promise { const azureAccount: AzureAccountResult = await this._azureAccountTask; - return ( - typeof azureAccount !== "string" && azureAccount.status === "LoggedIn" - ); + return typeof azureAccount !== "string" && azureAccount.status === "LoggedIn"; } - public compareChildrenImpl( - item1: AzExtTreeItem, - item2: AzExtTreeItem, - ): number { + public compareChildrenImpl(item1: AzExtTreeItem, item2: AzExtTreeItem): number { if (item1 instanceof GenericTreeItem && item2 instanceof GenericTreeItem) { return 0; // already sorted } else { @@ -123,16 +113,12 @@ export class AzLoginTreeItem extends AzExtParentTreeItem { } } - private async loadAzureAccount( - azureAccount: AzureAccount | undefined, - ): Promise { + private async loadAzureAccount(azureAccount: AzureAccount | undefined): Promise { if (!azureAccount) { const extension: Extension | undefined = extensions.getExtension(azureAccountExtensionId); if (extension) { - if ( - semver.lt(extension.packageJSON.version, minAccountExtensionVersion) - ) { + if (semver.lt(extension.packageJSON.version, minAccountExtensionVersion)) { return "needsUpdate"; } @@ -157,11 +143,7 @@ export class AzLoginTreeItem extends AzExtParentTreeItem { } }, ); - await commands.executeCommand( - "setContext", - "isAzureAccountInstalled", - true, - ); + await commands.executeCommand("setContext", "isAzureAccountInstalled", true); return azureAccount; } else { return "notInstalled"; diff --git a/src/vscode-bicep/src/tree/AzManagementGroupTreeItem.ts b/src/vscode-bicep/src/tree/AzManagementGroupTreeItem.ts index 1a3e24c5e8c..644699fdf73 100644 --- a/src/vscode-bicep/src/tree/AzManagementGroupTreeItem.ts +++ b/src/vscode-bicep/src/tree/AzManagementGroupTreeItem.ts @@ -6,9 +6,7 @@ import { ManagementGroupTreeItem } from "./ManagementGroupTreeItem"; // The root of treeview used in management group scope deployment. Represents an Azure account export class AzManagementGroupTreeItem extends AzureAccountTreeItemBase { - public createSubscriptionTreeItem( - root: ISubscriptionContext, - ): ManagementGroupTreeItem { + public createSubscriptionTreeItem(root: ISubscriptionContext): ManagementGroupTreeItem { return new ManagementGroupTreeItem(this, root); } } diff --git a/src/vscode-bicep/src/tree/AzResourceGroupTreeItem.ts b/src/vscode-bicep/src/tree/AzResourceGroupTreeItem.ts index 99648bb5815..baeb93da045 100644 --- a/src/vscode-bicep/src/tree/AzResourceGroupTreeItem.ts +++ b/src/vscode-bicep/src/tree/AzResourceGroupTreeItem.ts @@ -2,7 +2,6 @@ // Licensed under the MIT License. import { AzureAccountTreeItemBase } from "@microsoft/vscode-azext-azureutils"; import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; - import { OutputChannelManager } from "../utils/OutputChannelManager"; import { ResourceGroupTreeItem } from "./ResourceGroupTreeItem"; @@ -11,9 +10,7 @@ export class AzResourceGroupTreeItem extends AzureAccountTreeItemBase { constructor(private readonly outputChannelManager: OutputChannelManager) { super(); } - public createSubscriptionTreeItem( - root: ISubscriptionContext, - ): ResourceGroupTreeItem { + public createSubscriptionTreeItem(root: ISubscriptionContext): ResourceGroupTreeItem { return new ResourceGroupTreeItem(this, root, this.outputChannelManager); } } diff --git a/src/vscode-bicep/src/tree/GenericAzExtTreeItem.ts b/src/vscode-bicep/src/tree/GenericAzExtTreeItem.ts index 583aad923f1..bd7994fbfd5 100644 --- a/src/vscode-bicep/src/tree/GenericAzExtTreeItem.ts +++ b/src/vscode-bicep/src/tree/GenericAzExtTreeItem.ts @@ -1,19 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - AzExtParentTreeItem, - AzExtTreeItem, -} from "@microsoft/vscode-azext-utils"; +import { AzExtParentTreeItem, AzExtTreeItem } from "@microsoft/vscode-azext-utils"; export class GenericAzExtTreeItem extends AzExtTreeItem { private _id: string | undefined; private _label: string | undefined; - constructor( - parent: AzExtParentTreeItem, - id: string | undefined, - label: string | undefined, - ) { + constructor(parent: AzExtParentTreeItem, id: string | undefined, label: string | undefined) { super(parent); this._id = id; this._label = label; diff --git a/src/vscode-bicep/src/tree/LocationTreeItem.ts b/src/vscode-bicep/src/tree/LocationTreeItem.ts index f582fc84549..c0f8763f9bd 100644 --- a/src/vscode-bicep/src/tree/LocationTreeItem.ts +++ b/src/vscode-bicep/src/tree/LocationTreeItem.ts @@ -3,7 +3,6 @@ import { SubscriptionClient } from "@azure/arm-resources-subscriptions"; import { SubscriptionTreeItemBase } from "@microsoft/vscode-azext-azureutils"; import { AzExtTreeItem, IActionContext } from "@microsoft/vscode-azext-utils"; - import { createSubscriptionClient } from "../azure/azureClients"; import { localize } from "../utils/localize"; import { GenericAzExtTreeItem } from "./GenericAzExtTreeItem"; @@ -19,23 +18,15 @@ export class LocationTreeItem extends SubscriptionTreeItemBase { } // Loads locations - public async loadMoreChildrenImpl( - clearCache: boolean, - context: IActionContext, - ): Promise { + public async loadMoreChildrenImpl(clearCache: boolean, context: IActionContext): Promise { if (clearCache) { this._nextLink = undefined; } - const client: SubscriptionClient = await createSubscriptionClient([ - context, - this, - ]); + const client: SubscriptionClient = await createSubscriptionClient([context, this]); const subscriptionId = this.subscription.subscriptionId; const locations = []; - for await (const location of client.subscriptions.listLocations( - subscriptionId, - )) { + for await (const location of client.subscriptions.listLocations(subscriptionId)) { locations.push(location); } diff --git a/src/vscode-bicep/src/tree/ManagementGroupTreeItem.ts b/src/vscode-bicep/src/tree/ManagementGroupTreeItem.ts index 486279db4f6..53607283a26 100644 --- a/src/vscode-bicep/src/tree/ManagementGroupTreeItem.ts +++ b/src/vscode-bicep/src/tree/ManagementGroupTreeItem.ts @@ -1,25 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { AzExtTreeItem } from "@microsoft/vscode-azext-utils"; +import { ManagementGroupInfo, ManagementGroupsAPI } from "@azure/arm-managementgroups"; import { DefaultAzureCredential } from "@azure/identity"; -import { GenericAzExtTreeItem } from "./GenericAzExtTreeItem"; +import { SubscriptionTreeItemBase, uiUtils } from "@microsoft/vscode-azext-azureutils"; +import { AzExtTreeItem } from "@microsoft/vscode-azext-utils"; import { localize } from "../utils/localize"; - -import { - ManagementGroupInfo, - ManagementGroupsAPI, -} from "@azure/arm-managementgroups"; -import { - SubscriptionTreeItemBase, - uiUtils, -} from "@microsoft/vscode-azext-azureutils"; +import { GenericAzExtTreeItem } from "./GenericAzExtTreeItem"; // Represents tree item used to display management groups export class ManagementGroupTreeItem extends SubscriptionTreeItemBase { - public readonly childTypeLabel: string = localize( - "managementGroup", - "Management Group", - ); + public readonly childTypeLabel: string = localize("managementGroup", "Management Group"); private _nextLink: string | undefined; @@ -29,16 +19,12 @@ export class ManagementGroupTreeItem extends SubscriptionTreeItemBase { // Loads management groups public async loadMoreChildrenImpl(): Promise { - const managementGroupsAPI = new ManagementGroupsAPI( - new DefaultAzureCredential(), - ); + const managementGroupsAPI = new ManagementGroupsAPI(new DefaultAzureCredential()); let managementGroupInfos: ManagementGroupInfo[] = []; try { - managementGroupInfos = await uiUtils.listAllIterator( - managementGroupsAPI.managementGroups.list(), - ); + managementGroupInfos = await uiUtils.listAllIterator(managementGroupsAPI.managementGroups.list()); } catch (error) { throw new Error( "You do not have access to any management group. Please create one in the Azure portal and try to deploy again", diff --git a/src/vscode-bicep/src/tree/ResourceGroupTreeItem.ts b/src/vscode-bicep/src/tree/ResourceGroupTreeItem.ts index a7d25de0125..5858fdb5797 100644 --- a/src/vscode-bicep/src/tree/ResourceGroupTreeItem.ts +++ b/src/vscode-bicep/src/tree/ResourceGroupTreeItem.ts @@ -20,7 +20,6 @@ import { ISubscriptionContext, nonNullProp, } from "@microsoft/vscode-azext-utils"; - import { createResourceManagementClient } from "../azure/azureClients"; import { localize } from "../utils/localize"; import { OutputChannelManager } from "../utils/OutputChannelManager"; @@ -37,10 +36,7 @@ export class ResourceGroupTreeItem extends SubscriptionTreeItemBase { this._outputChannelManager = outputChannelManager; } - public readonly childTypeLabel: string = localize( - "resourceGroup", - "Resource Group", - ); + public readonly childTypeLabel: string = localize("resourceGroup", "Resource Group"); private _nextLink: string | undefined; private _outputChannelManager: OutputChannelManager; @@ -50,18 +46,12 @@ export class ResourceGroupTreeItem extends SubscriptionTreeItemBase { } // Loads resource group - public async loadMoreChildrenImpl( - clearCache: boolean, - context: IActionContext, - ): Promise { + public async loadMoreChildrenImpl(clearCache: boolean, context: IActionContext): Promise { if (clearCache) { this._nextLink = undefined; } - const client: ResourceManagementClient = - await createResourceManagementClient([context, this]); - const rgs: ResourceGroup[] = await uiUtils.listAllIterator( - client.resourceGroups.list(), - ); + const client: ResourceManagementClient = await createResourceManagementClient([context, this]); + const rgs: ResourceGroup[] = await uiUtils.listAllIterator(client.resourceGroups.list()); const resourceGroupItems = await this.createTreeItemsWithErrorHandling( rgs, "invalidResourceGroup", @@ -73,46 +63,31 @@ export class ResourceGroupTreeItem extends SubscriptionTreeItemBase { } // Adds 'create' option in the resource group tree picker - public async createChildImpl( - context: ICreateChildImplContext, - ): Promise { - const title: string = localize( - "createResourceGroup", - "Create Resource Group", - ); + public async createChildImpl(context: ICreateChildImplContext): Promise { + const title: string = localize("createResourceGroup", "Create Resource Group"); const wizardContext: IResourceGroupWizardContext = { ...context, ...this.subscription, suppress403Handling: true, }; - const promptSteps: AzureWizardPromptStep[] = [ - new ResourceGroupNameStep(), - ]; + const promptSteps: AzureWizardPromptStep[] = [new ResourceGroupNameStep()]; LocationListStep.addStep(wizardContext, promptSteps); - const executeSteps: AzureWizardExecuteStep[] = - [new ResourceGroupCreateStep()]; + const executeSteps: AzureWizardExecuteStep[] = [new ResourceGroupCreateStep()]; - const wizard: AzureWizard = new AzureWizard( - wizardContext, - { title, promptSteps, executeSteps }, - ); + const wizard: AzureWizard = new AzureWizard(wizardContext, { + title, + promptSteps, + executeSteps, + }); await wizard.prompt(); - context.showCreatingTreeItem( - nonNullProp(wizardContext, "newResourceGroupName"), - ); + context.showCreatingTreeItem(nonNullProp(wizardContext, "newResourceGroupName")); await wizard.execute(); const azTreeItem = nonNullProp(wizardContext, "resourceGroup"); const newResourceGroupItemName = azTreeItem.name; - const newResourceGroupItem = new GenericAzExtTreeItem( - this, - azTreeItem.id, - newResourceGroupItemName, - ); + const newResourceGroupItem = new GenericAzExtTreeItem(this, azTreeItem.id, newResourceGroupItemName); - this._outputChannelManager.appendToOutputChannel( - `Created resource group -> ${newResourceGroupItemName}`, - ); + this._outputChannelManager.appendToOutputChannel(`Created resource group -> ${newResourceGroupItemName}`); return newResourceGroupItem; } diff --git a/src/vscode-bicep/src/tree/TreeManager.ts b/src/vscode-bicep/src/tree/TreeManager.ts index ebfc8af9aa1..7b16ede1c9b 100644 --- a/src/vscode-bicep/src/tree/TreeManager.ts +++ b/src/vscode-bicep/src/tree/TreeManager.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { AzExtTreeDataProvider } from "@microsoft/vscode-azext-utils"; - import { Disposable } from "../utils/disposable"; import { OutputChannelManager } from "../utils/OutputChannelManager"; import { AzLocationTreeItem } from "./AzLocationTreeItem"; @@ -14,16 +13,12 @@ export class TreeManager extends Disposable { } get azLocationTree(): AzExtTreeDataProvider { - const azLocationTreeItem: AzLocationTreeItem = this.register( - new AzLocationTreeItem(), - ); + const azLocationTreeItem: AzLocationTreeItem = this.register(new AzLocationTreeItem()); return new AzExtTreeDataProvider(azLocationTreeItem, ""); } get azManagementGroupTreeItem(): AzExtTreeDataProvider { - const azManagementGroupTreeItem: AzManagementGroupTreeItem = this.register( - new AzManagementGroupTreeItem(), - ); + const azManagementGroupTreeItem: AzManagementGroupTreeItem = this.register(new AzManagementGroupTreeItem()); return new AzExtTreeDataProvider(azManagementGroupTreeItem, ""); } diff --git a/src/vscode-bicep/src/updateUiContext.ts b/src/vscode-bicep/src/updateUiContext.ts index 1a028199f1b..540644b1602 100644 --- a/src/vscode-bicep/src/updateUiContext.ts +++ b/src/vscode-bicep/src/updateUiContext.ts @@ -1,62 +1,41 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import { callWithTelemetryAndErrorHandling, IActionContext } from "@microsoft/vscode-azext-utils"; import { commands, TextDocument } from "vscode"; import { DecompileCommand } from "./commands/decompile"; -import { - callWithTelemetryAndErrorHandling, - IActionContext, -} from "@microsoft/vscode-azext-utils"; import { DecompileParamsCommand } from "./commands/decompileParams"; -export async function updateUiContext( - currentDocument: TextDocument | undefined, -): Promise { - await callWithTelemetryAndErrorHandling( - "updateUiContext", - async (context: IActionContext) => { - context.telemetry.suppressIfSuccessful = true; +export async function updateUiContext(currentDocument: TextDocument | undefined): Promise { + await callWithTelemetryAndErrorHandling("updateUiContext", async (context: IActionContext) => { + context.telemetry.suppressIfSuccessful = true; - let cannotDecompile: boolean; - switch (currentDocument?.languageId) { - case "arm-template": - case "json": - case "jsonc": - cannotDecompile = !(await DecompileCommand.mightBeArmTemplateNoThrow( - currentDocument.uri, - )); - break; - default: - // Only disable if the current editor is JSON but not an ARM template. - cannotDecompile = false; - break; - } + let cannotDecompile: boolean; + switch (currentDocument?.languageId) { + case "arm-template": + case "json": + case "jsonc": + cannotDecompile = !(await DecompileCommand.mightBeArmTemplateNoThrow(currentDocument.uri)); + break; + default: + // Only disable if the current editor is JSON but not an ARM template. + cannotDecompile = false; + break; + } - await commands.executeCommand( - "setContext", - "bicep.cannotDecompile", - cannotDecompile, - ); + await commands.executeCommand("setContext", "bicep.cannotDecompile", cannotDecompile); - let cannotDecompileParams: boolean; - switch (currentDocument?.languageId) { - case "json": - case "jsonc": - cannotDecompileParams = - !(await DecompileParamsCommand.mightBeArmParametersNoThrow( - currentDocument.uri, - )); - break; - default: - cannotDecompileParams = true; - break; - } + let cannotDecompileParams: boolean; + switch (currentDocument?.languageId) { + case "json": + case "jsonc": + cannotDecompileParams = !(await DecompileParamsCommand.mightBeArmParametersNoThrow(currentDocument.uri)); + break; + default: + cannotDecompileParams = true; + break; + } - await commands.executeCommand( - "setContext", - "bicep.cannotDecompileParams", - cannotDecompileParams, - ); - }, - ); + await commands.executeCommand("setContext", "bicep.cannotDecompileParams", cannotDecompileParams); + }); } diff --git a/src/vscode-bicep/src/utils/AzExtOutputChannel.ts b/src/vscode-bicep/src/utils/AzExtOutputChannel.ts index 64d4e890322..8955a2e5631 100644 --- a/src/vscode-bicep/src/utils/AzExtOutputChannel.ts +++ b/src/vscode-bicep/src/utils/AzExtOutputChannel.ts @@ -8,10 +8,7 @@ import { removePropertiesWithPossibleUserInfoInDeployParams } from "./removeProp // https://github.com/microsoft/vscode-azuretools/blob/main/utils/src/AzExtOutputChannel.ts // with support to remove properties with possible user info before appendLine(..) is invoked on output channel. // TODO: revisit this when https://github.com/Azure/azure-sdk-for-net/issues/27263 is resolved. -export function createAzExtOutputChannel( - name: string, - extensionConfigurationPrefix: string, -): IAzExtOutputChannel { +export function createAzExtOutputChannel(name: string, extensionConfigurationPrefix: string): IAzExtOutputChannel { return new AzExtOutputChannel(name, extensionConfigurationPrefix); } @@ -35,19 +32,13 @@ class AzExtOutputChannel implements IAzExtOutputChannel { } public appendLine(value: string): void { - const updatedValue = - removePropertiesWithPossibleUserInfoInDeployParams(value); + const updatedValue = removePropertiesWithPossibleUserInfoInDeployParams(value); this._outputChannel.appendLine(updatedValue); } - public appendLog( - value: string, - options?: { resourceName?: string; date?: Date }, - ): void { + public appendLog(value: string, options?: { resourceName?: string; date?: Date }): void { const enableOutputTimestampsSetting = "enableOutputTimestamps"; - const result: boolean | undefined = getBicepConfiguration().get( - enableOutputTimestampsSetting, - ); + const result: boolean | undefined = getBicepConfiguration().get(enableOutputTimestampsSetting); if (!result) { this.appendLine(value); @@ -55,9 +46,7 @@ class AzExtOutputChannel implements IAzExtOutputChannel { options ||= {}; const date: Date = options.date || new Date(); this.appendLine( - `${date.toLocaleTimeString()}${ - options.resourceName ? " ".concat(options.resourceName) : "" - }: ${value}`, + `${date.toLocaleTimeString()}${options.resourceName ? " ".concat(options.resourceName) : ""}: ${value}`, ); } } @@ -67,10 +56,7 @@ class AzExtOutputChannel implements IAzExtOutputChannel { } public show(preserveFocus?: boolean | undefined): void; - public show( - column?: ViewColumn | undefined, - preserveFocus?: boolean | undefined, - ): void; + public show(column?: ViewColumn | undefined, preserveFocus?: boolean | undefined): void; // eslint-disable-next-line @typescript-eslint/no-explicit-any public show(_column?: any, preserveFocus?: boolean | undefined): void { this._outputChannel.show(preserveFocus); diff --git a/src/vscode-bicep/src/utils/OutputChannelManager.ts b/src/vscode-bicep/src/utils/OutputChannelManager.ts index 71ea26c2b82..3347e6e1dc6 100644 --- a/src/vscode-bicep/src/utils/OutputChannelManager.ts +++ b/src/vscode-bicep/src/utils/OutputChannelManager.ts @@ -9,9 +9,7 @@ export class OutputChannelManager extends Disposable { constructor(name: string, extensionConfigurationPrefix: string) { super(); - this._azExtOutputChannel = this.register( - createAzExtOutputChannel(name, extensionConfigurationPrefix), - ); + this._azExtOutputChannel = this.register(createAzExtOutputChannel(name, extensionConfigurationPrefix)); } appendToOutputChannel(text: string, noFocus = false): void { diff --git a/src/vscode-bicep/src/utils/getTextAfterFormattingChanges.ts b/src/vscode-bicep/src/utils/getTextAfterFormattingChanges.ts index 0a5340e50e1..ae9c83d492e 100644 --- a/src/vscode-bicep/src/utils/getTextAfterFormattingChanges.ts +++ b/src/vscode-bicep/src/utils/getTextAfterFormattingChanges.ts @@ -39,19 +39,13 @@ export function getTextAfterFormattingChanges( if (textChar === "") { // Matched successfully to the end of textToMatchNoWhitespace - const formattedText = editorText.substring( - editorOffsetStart, - editorOffset, - ); + const formattedText = editorText.substring(editorOffsetStart, editorOffset); // Trim all whitespace at the end except for the number of newlines that were // in the original string const [, textToMatchEnding] = splitWhitespaceFromEnd(textToMatch); const newLinesAtEndOfOriginalText = countNewlines(textToMatchEnding); - const trimmedFormattedText = trimWhitespaceAtEnd( - formattedText, - newLinesAtEndOfOriginalText, - ); + const trimmedFormattedText = trimWhitespaceAtEnd(formattedText, newLinesAtEndOfOriginalText); assert(areEqualIgnoringWhitespace(trimmedFormattedText, textToMatch)); @@ -69,17 +63,12 @@ export function getTextAfterFormattingChanges( function trimWhitespaceAtEnd(s: string, maxAllowedNewlines: number): string { assert(maxAllowedNewlines >= 0); - const [firstPartOfString, endingWhitespace]: [string, string] = - splitWhitespaceFromEnd(s); + const [firstPartOfString, endingWhitespace]: [string, string] = splitWhitespaceFromEnd(s); const endingWhitespaceWithAllowedNewlines: string = - new RegExp(`^([ \t]*(\\r\\n|\\n)){0,${maxAllowedNewlines}}`).exec( - endingWhitespace, - )?.[0] ?? ""; + new RegExp(`^([ \t]*(\\r\\n|\\n)){0,${maxAllowedNewlines}}`).exec(endingWhitespace)?.[0] ?? ""; - assert( - countNewlines(endingWhitespaceWithAllowedNewlines) <= maxAllowedNewlines, - ); + assert(countNewlines(endingWhitespaceWithAllowedNewlines) <= maxAllowedNewlines); return firstPartOfString + endingWhitespaceWithAllowedNewlines; } diff --git a/src/vscode-bicep/src/utils/logger.ts b/src/vscode-bicep/src/utils/logger.ts index e4d32130cab..96244878c47 100644 --- a/src/vscode-bicep/src/utils/logger.ts +++ b/src/vscode-bicep/src/utils/logger.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import * as path from "path"; +import { MESSAGE } from "triple-beam"; import vscode from "vscode"; import * as winston from "winston"; import Transport from "winston-transport"; -import * as path from "path"; -import { MESSAGE } from "triple-beam"; /** * This logfile is written during to E2E tests. It serves as a way to watch for events from the code @@ -91,10 +91,7 @@ class outputChannelTransport extends Transport { } } -export function createLogger( - context: vscode.ExtensionContext, - outputChannel: vscode.OutputChannel, -): Logger { +export function createLogger(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel): Logger { // TODO: // - make log level configurable // - Default log level should be info @@ -110,9 +107,7 @@ export function createLogger( export function getLogger(): Logger { if (!logger) { - throw new Error( - "Logger is undefined. Make sure to call createLogger() first.", - ); + throw new Error("Logger is undefined. Make sure to call createLogger() first."); } return logger; diff --git a/src/vscode-bicep/src/utils/removePropertiesWithPossibleUserInfo.ts b/src/vscode-bicep/src/utils/removePropertiesWithPossibleUserInfo.ts index 41af1d9a5d6..9a47554ec33 100644 --- a/src/vscode-bicep/src/utils/removePropertiesWithPossibleUserInfo.ts +++ b/src/vscode-bicep/src/utils/removePropertiesWithPossibleUserInfo.ts @@ -1,13 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -const deployParamsPattern = new RegExp( - '(?"token":\\s*")(?[^"]+)"', - "g", -); +const deployParamsPattern = new RegExp('(?"token":\\s*")(?[^"]+)"', "g"); -export function removePropertiesWithPossibleUserInfoInDeployParams( - value: string, -): string { +export function removePropertiesWithPossibleUserInfoInDeployParams(value: string): string { return value.replace(deployParamsPattern, '$"'); } diff --git a/src/vscode-bicep/src/utils/telemetry.ts b/src/vscode-bicep/src/utils/telemetry.ts index 49d856a7d52..9741b02eedc 100644 --- a/src/vscode-bicep/src/utils/telemetry.ts +++ b/src/vscode-bicep/src/utils/telemetry.ts @@ -1,33 +1,24 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - callWithTelemetryAndErrorHandling, - IActionContext, - parseError, -} from "@microsoft/vscode-azext-utils"; - +import { callWithTelemetryAndErrorHandling, IActionContext, parseError } from "@microsoft/vscode-azext-utils"; import { getLogger } from "./logger"; export async function activateWithTelemetryAndErrorHandling( activateCallback: (actionContext: IActionContext) => Promise, ): Promise { - await callWithTelemetryAndErrorHandling( - "bicep.activate", - async (actionContext: IActionContext) => { - const startTime = Date.now(); - actionContext.telemetry.properties.isActivationEvent = "true"; - - try { - await activateCallback(actionContext); - } catch (e) { - getLogger().error(parseError(e).message); - throw e; - } - - actionContext.telemetry.measurements.extensionLoad = - (Date.now() - startTime) / 1000; - }, - ); + await callWithTelemetryAndErrorHandling("bicep.activate", async (actionContext: IActionContext) => { + const startTime = Date.now(); + actionContext.telemetry.properties.isActivationEvent = "true"; + + try { + await activateCallback(actionContext); + } catch (e) { + getLogger().error(parseError(e).message); + throw e; + } + + actionContext.telemetry.measurements.extensionLoad = (Date.now() - startTime) / 1000; + }); } // Creates a possible telemetry event scope. But the event is only sent if there is a cancel or an error @@ -35,20 +26,16 @@ export async function callWithTelemetryAndErrorHandlingOnlyOnErrors( callbackId: string, callback: (context: IActionContext) => T | PromiseLike, ): Promise { - return await callWithTelemetryAndErrorHandling( - callbackId, - async (context): Promise => { - context.telemetry.suppressIfSuccessful = true; + return await callWithTelemetryAndErrorHandling(callbackId, async (context): Promise => { + context.telemetry.suppressIfSuccessful = true; - return await callback(context); - }, - ); + return await callback(context); + }); } export async function raiseErrorWithoutTelemetry( callbackId: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - error: any, + error: unknown, ) { await callWithTelemetryAndErrorHandling(callbackId, (context) => { context.telemetry.suppressAll = true; diff --git a/src/vscode-bicep/src/utils/withProgressAfterDelay.ts b/src/vscode-bicep/src/utils/withProgressAfterDelay.ts index 4392153087b..6102741f747 100644 --- a/src/vscode-bicep/src/utils/withProgressAfterDelay.ts +++ b/src/vscode-bicep/src/utils/withProgressAfterDelay.ts @@ -7,10 +7,7 @@ const defaultMsBeforeShowing = 1000; export type WithProgress = ( options: ProgressOptions, - task: ( - progress: Progress<{ message?: string; increment?: number }>, - token: CancellationToken, - ) => Thenable, + task: (progress: Progress<{ message?: string; increment?: number }>, token: CancellationToken) => Thenable, ) => Thenable; /** @@ -26,8 +23,7 @@ export async function withProgressAfterDelay( task: () => Promise, ): Promise { const withProgress = options.inject?.withProgress ?? window.withProgress; - const delayBeforeShowingMs = - options.delayBeforeShowingMs ?? defaultMsBeforeShowing; + const delayBeforeShowingMs = options.delayBeforeShowingMs ?? defaultMsBeforeShowing; let taskDone = false; diff --git a/src/vscode-bicep/src/visualizer/app/assets/icons/azure/index.ts b/src/vscode-bicep/src/visualizer/app/assets/icons/azure/index.ts index 5f3ed5f162e..74592a63ff7 100644 --- a/src/vscode-bicep/src/visualizer/app/assets/icons/azure/index.ts +++ b/src/vscode-bicep/src/visualizer/app/assets/icons/azure/index.ts @@ -1,316 +1,175 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export async function importResourceIconInline( - resourceType: string, -): Promise { +export async function importResourceIconInline(resourceType: string): Promise { switch (resourceType.toLowerCase()) { // Microsoft.Compute case "microsoft.compute/availabilitysets": - return ( - await import("./compute/10025-icon-service-Availability-Sets.svg") - ).default; + return (await import("./compute/10025-icon-service-Availability-Sets.svg")).default; case "microsoft.compute/disks": return (await import("./compute/10032-icon-service-Disks.svg")).default; case "microsoft.compute/virtualmachines": - return (await import("./compute/10021-icon-service-Virtual-Machine.svg")) - .default; + return (await import("./compute/10021-icon-service-Virtual-Machine.svg")).default; case "microsoft.compute/virtualmachinescalesets": - return (await import("./compute/10034-icon-service-VM-Scale-Sets.svg")) - .default; + return (await import("./compute/10034-icon-service-VM-Scale-Sets.svg")).default; case "microsoft.compute/proximityplacementgroups": - return ( - await import( - "./compute/10365-icon-service-Proximity-Placement-Groups.svg" - ) - ).default; + return (await import("./compute/10365-icon-service-Proximity-Placement-Groups.svg")).default; case "microsoft.compute/diskencryptionsets": - return ( - await import("./compute/00398-icon-service-Disk-Encryption-Sets.svg") - ).default; + return (await import("./compute/00398-icon-service-Disk-Encryption-Sets.svg")).default; case "microsoft.containerservice/managedclusters": - return ( - await import("./compute/10023-icon-service-Kubernetes-Services.svg") - ).default; + return (await import("./compute/10023-icon-service-Kubernetes-Services.svg")).default; case "microsoft.compute/snapshots": - return (await import("./compute/10026-icon-service-Disks-Snapshots.svg")) - .default; + return (await import("./compute/10026-icon-service-Disks-Snapshots.svg")).default; case "microsoft.batch/batchaccounts": - return (await import("./compute/10031-icon-service-Batch-Accounts.svg")) - .default; + return (await import("./compute/10031-icon-service-Batch-Accounts.svg")).default; case "microsoft.compute/images": return (await import("./compute/10033-icon-service-Images.svg")).default; case "microsoft.compute/galleries": - return ( - await import("./compute/10039-icon-service-Shared-Image-Galleries.svg") - ).default; + return (await import("./compute/10039-icon-service-Shared-Image-Galleries.svg")).default; // Microsoft.SQL case "microsoft.sql/servers": - return (await import("./databases/10132-icon-service-SQL-Server.svg")) - .default; + return (await import("./databases/10132-icon-service-SQL-Server.svg")).default; case "microsoft.sql/servers/databases": - return (await import("./databases/10130-icon-service-SQL-Database.svg")) - .default; + return (await import("./databases/10130-icon-service-SQL-Database.svg")).default; case "microsoft.documentdb/databaseaccounts": - return ( - await import("./databases/10121-icon-service-Azure-Cosmos-DB.svg") - ).default; + return (await import("./databases/10121-icon-service-Azure-Cosmos-DB.svg")).default; case "microsoft.dbformysql/servers": case "microsoft.dbformysql/flexibleservers": - return ( - await import( - "./databases/10122-icon-service-Azure-Database-MySQL-Server.svg" - ) - ).default; + return (await import("./databases/10122-icon-service-Azure-Database-MySQL-Server.svg")).default; case "microsoft.dbformariadb/servers": - return ( - await import( - "./databases/10123-icon-service-Azure-Database-MariaDB-Server.svg" - ) - ).default; + return (await import("./databases/10123-icon-service-Azure-Database-MariaDB-Server.svg")).default; case "microsoft.sqlvirtualmachine/sqlvirtualmachines": - return (await import("./databases/10124-icon-service-Azure-SQL-VM.svg")) - .default; + return (await import("./databases/10124-icon-service-Azure-SQL-VM.svg")).default; case "microsoft.datafactory/factories": - return (await import("./databases/10126-icon-service-Data-Factory.svg")) - .default; + return (await import("./databases/10126-icon-service-Data-Factory.svg")).default; case "microsoft.dbforpostgressql/servers": case "microsoft.dbforpostgressql/flexibleservers": - return ( - await import( - "./databases/10131-icon-service-Azure-Database-PostgreSQL-Server.svg" - ) - ).default; + return (await import("./databases/10131-icon-service-Azure-Database-PostgreSQL-Server.svg")).default; case "microsoft.datamigration/services": - return ( - await import( - "./databases/10133-icon-service-Azure-Database-Migration-Services.svg" - ) - ).default; + return (await import("./databases/10133-icon-service-Azure-Database-Migration-Services.svg")).default; case "microsoft.sql/servers/elasticpools": - return ( - await import("./databases/10134-icon-service-SQL-Elastic-Pools.svg") - ).default; + return (await import("./databases/10134-icon-service-SQL-Elastic-Pools.svg")).default; case "microsoft.sql/managedinstances": - return ( - await import("./databases/10136-icon-service-SQL-Managed-Instance.svg") - ).default; + return (await import("./databases/10136-icon-service-SQL-Managed-Instance.svg")).default; case "microsoft.sql/managedinstances/databases": - return ( - await import("./databases/10135-icon-service-Managed-Database.svg") - ).default; + return (await import("./databases/10135-icon-service-Managed-Database.svg")).default; case "microsoft.cache/redis": - return (await import("./databases/10137-icon-service-Cache-Redis.svg")) - .default; + return (await import("./databases/10137-icon-service-Cache-Redis.svg")).default; case "microsoft.sql/instancepools": - return (await import("./databases/10139-icon-service-Instance-Pools.svg")) - .default; + return (await import("./databases/10139-icon-service-Instance-Pools.svg")).default; // microsoft.network case "microsoft.network/privatednszones": case "microsoft.network/dnszones": - return (await import("./networking/10064-icon-service-DNS-Zones.svg")) - .default; + return (await import("./networking/10064-icon-service-DNS-Zones.svg")).default; case "microsoft.network/loadbalancers": - return ( - await import("./networking/10062-icon-service-Load-Balancers.svg") - ).default; + return (await import("./networking/10062-icon-service-Load-Balancers.svg")).default; case "microsoft.network/networkinterfaces": - return ( - await import("./networking/10080-icon-service-Network-Interfaces.svg") - ).default; + return (await import("./networking/10080-icon-service-Network-Interfaces.svg")).default; case "microsoft.network/networksecuritygroups": - return ( - await import( - "./networking/10067-icon-service-Network-Security-Groups.svg" - ) - ).default; + return (await import("./networking/10067-icon-service-Network-Security-Groups.svg")).default; case "microsoft.network/publicipaddresses": - return ( - await import("./networking/10069-icon-service-Public-IP-Addresses.svg") - ).default; + return (await import("./networking/10069-icon-service-Public-IP-Addresses.svg")).default; case "microsoft.network/virtualnetworkgateways": - return ( - await import( - "./networking/10063-icon-service-Virtual-Network-Gateways.svg" - ) - ).default; + return (await import("./networking/10063-icon-service-Virtual-Network-Gateways.svg")).default; case "microsoft.network/virtualnetworks": - return ( - await import("./networking/10061-icon-service-Virtual-Networks.svg") - ).default; + return (await import("./networking/10061-icon-service-Virtual-Networks.svg")).default; case "microsoft.network/virtualnetworks/subnets": return (await import("./custom/subnets.svg")).default; case "microsoft.network/ipgroups": - return (await import("./networking/00701-icon-service-IP-Groups.svg")) - .default; + return (await import("./networking/00701-icon-service-IP-Groups.svg")).default; case "microsoft.network/privatelinkservices": - return ( - await import("./networking/01105-icon-service-Private-Link-Service.svg") - ).default; + return (await import("./networking/01105-icon-service-Private-Link-Service.svg")).default; case "microsoft.network/trafficmanagerprofiles": - return ( - await import( - "./networking/10065-icon-service-Traffic-Manager-Profiles.svg" - ) - ).default; + return (await import("./networking/10065-icon-service-Traffic-Manager-Profiles.svg")).default; case "microsoft.network/networkwatchers": - return ( - await import("./networking/10066-icon-service-Network-Watcher.svg") - ).default; + return (await import("./networking/10066-icon-service-Network-Watcher.svg")).default; case "microsoft.network/routefilters": - return (await import("./networking/10071-icon-service-Route-Filters.svg")) - .default; + return (await import("./networking/10071-icon-service-Route-Filters.svg")).default; case "microsoft.network/ddosprotectionplans": - return ( - await import( - "./networking/10072-icon-service-DDoS-Protection-Plans.svg" - ) - ).default; + return (await import("./networking/10072-icon-service-DDoS-Protection-Plans.svg")).default; case "microsoft.network/frontdoors": - return (await import("./networking/10073-icon-service-Front-Doors.svg")) - .default; + return (await import("./networking/10073-icon-service-Front-Doors.svg")).default; case "microsoft.network/applicationgateways": - return ( - await import("./networking/10076-icon-service-Application-Gateways.svg") - ).default; + return (await import("./networking/10076-icon-service-Application-Gateways.svg")).default; case "microsoft.network/localnetworkgateways": - return ( - await import( - "./networking/10077-icon-service-Local-Network-Gateways.svg" - ) - ).default; + return (await import("./networking/10077-icon-service-Local-Network-Gateways.svg")).default; case "microsoft.network/expressroutecircuits": - return ( - await import( - "./networking/10079-icon-service-ExpressRoute-Circuits.svg" - ) - ).default; + return (await import("./networking/10079-icon-service-ExpressRoute-Circuits.svg")).default; case "microsoft.network/connections": - return (await import("./networking/10081-icon-service-Connections.svg")) - .default; + return (await import("./networking/10081-icon-service-Connections.svg")).default; case "microsoft.network/routetables": - return (await import("./networking/10082-icon-service-Route-Tables.svg")) - .default; + return (await import("./networking/10082-icon-service-Route-Tables.svg")).default; case "microsoft.network/azurefirewalls": - return (await import("./networking/10084-icon-service-Firewalls.svg")) - .default; + return (await import("./networking/10084-icon-service-Firewalls.svg")).default; case "microsoft.network/serviceendpointpolicies": - return ( - await import( - "./networking/10085-icon-service-Service-Endpoint-Policies.svg" - ) - ).default; + return (await import("./networking/10085-icon-service-Service-Endpoint-Policies.svg")).default; case "microsoft.network/natgateways": return (await import("./networking/10310-icon-service-NAT.svg")).default; case "microsoft.network/virtualwans": - return (await import("./networking/10353-icon-service-Virtual-WANs.svg")) - .default; + return (await import("./networking/10353-icon-service-Virtual-WANs.svg")).default; case "microsoft.network/firewallpolicies": - return ( - await import( - "./networking/10362-icon-service-Web-Application-Firewall-Policies(WAF).svg" - ) - ).default; + return (await import("./networking/10362-icon-service-Web-Application-Firewall-Policies(WAF).svg")).default; case "microsoft.network/publicipprefixes": - return ( - await import("./networking/10372-icon-service-Public-IP-Prefixes.svg") - ).default; + return (await import("./networking/10372-icon-service-Public-IP-Prefixes.svg")).default; case "microsoft.network/applicationsecuritygroups": - return ( - await import( - "./security/10244-icon-service-Application-Security-Groups.svg" - ) - ).default; + return (await import("./security/10244-icon-service-Application-Security-Groups.svg")).default; // Microsoft.Resources case "microsoft.resources/resourcegroups": - return (await import("./general/10007-icon-service-Resource-Groups.svg")) - .default; + return (await import("./general/10007-icon-service-Resource-Groups.svg")).default; // Microsoft.Security case "microsoft.keyvault/vaults": - return (await import("./security/10245-icon-service-Key-Vaults.svg")) - .default; + return (await import("./security/10245-icon-service-Key-Vaults.svg")).default; // Microsoft.Automation case "microsoft.automation/automationaccounts": - return ( - await import("./management/00022-icon-service-Automation-Accounts.svg") - ).default; + return (await import("./management/00022-icon-service-Automation-Accounts.svg")).default; // Microsoft.Authorization case "Microsoft.Authorization/policyDefinitions": - return (await import("./management/10316-icon-service-Policy.svg")) - .default; + return (await import("./management/10316-icon-service-Policy.svg")).default; // Microsoft.Subscriptions case "microsoft.subscription/aliases": - return (await import("./general/10002-icon-service-Subscriptions.svg")) - .default; + return (await import("./general/10002-icon-service-Subscriptions.svg")).default; // Microsoft.Storage case "microsoft.storage/storageaccounts": - return (await import("./storage/10086-icon-service-Storage-Accounts.svg")) - .default; + return (await import("./storage/10086-icon-service-Storage-Accounts.svg")).default; case "microsoft.storage/storageaccounts/fileservices": - return ( - await import("./general/10838-icon-service-Storage-Azure-Files.svg") - ).default; + return (await import("./general/10838-icon-service-Storage-Azure-Files.svg")).default; case "microsoft.storage/storageaccounts/queueservices": - return (await import("./general/10840-icon-service-Storage-Queue.svg")) - .default; + return (await import("./general/10840-icon-service-Storage-Queue.svg")).default; case "microsoft.storage/storageaccounts/tableservices": return (await import("./general/10841-icon-service-Table.svg")).default; case "microsoft.recoveryservices/vaults": - return ( - await import( - "./storage/00017-icon-service-Recovery-Services-Vaults.svg" - ) - ).default; + return (await import("./storage/00017-icon-service-Recovery-Services-Vaults.svg")).default; case "microsoft.storagesync/storagesyncservices": - return ( - await import("./storage/10093-icon-service-Storage-Sync-Services.svg") - ).default; + return (await import("./storage/10093-icon-service-Storage-Sync-Services.svg")).default; case "microsoft.databox/jobs": - return (await import("./storage/10094-icon-service-Data-Box.svg")) - .default; + return (await import("./storage/10094-icon-service-Data-Box.svg")).default; case "microsoft.databoxedge/databoxedgedevices": - return (await import("./storage/10095-icon-service-Data-Box-Edge.svg")) - .default; + return (await import("./storage/10095-icon-service-Data-Box-Edge.svg")).default; case "microsoft.netapp/netappaccounts": - return ( - await import("./storage/10096-icon-service-Azure-NetApp-Files.svg") - ).default; + return (await import("./storage/10096-icon-service-Azure-NetApp-Files.svg")).default; case "microsoft.datashare/accounts": - return (await import("./storage/10098-icon-service-Data-Shares.svg")) - .default; + return (await import("./storage/10098-icon-service-Data-Shares.svg")).default; // Microsoft.Web case "microsoft.web/serverfarms": - return ( - await import("./appServices/00046-icon-service-App-Service-Plans.svg") - ).default; + return (await import("./appServices/00046-icon-service-App-Service-Plans.svg")).default; case "microsoft.web/sites": - return (await import("./appServices/10035-icon-service-App-Services.svg")) - .default; + return (await import("./appServices/10035-icon-service-App-Services.svg")).default; case "microsoft.web/certificates": - return ( - await import( - "./appServices/00049-icon-service-App-Service-Certificates.svg" - ) - ).default; + return (await import("./appServices/00049-icon-service-App-Service-Certificates.svg")).default; case "microsoft.web/hostingenvironments": - return ( - await import( - "./appServices/10047-icon-service-App-Service-Environments.svg" - ) - ).default; + return (await import("./appServices/10047-icon-service-App-Service-Environments.svg")).default; // Microsoft.NotificationHubs case "microsoft.notificationhubs/namespaces": - return (await import("./iot/10045-icon-service-Notification-Hubs.svg")) - .default; + return (await import("./iot/10045-icon-service-Notification-Hubs.svg")).default; // Microsoft.Devices case "microsoft.devices/iothubs": @@ -318,55 +177,34 @@ export async function importResourceIconInline( // Microsoft.IoTCentral case "microsoft.iotcentral/iotapps": - return ( - await import("./iot/10184-icon-service-IoT-Central-Applications.svg") - ).default; + return (await import("./iot/10184-icon-service-IoT-Central-Applications.svg")).default; // Microsoft.TimeSeriesInsights case "microsoft.timeseriesinsights/environments": - return ( - await import( - "./iot/10181-icon-service-Time-Series-Insights-Environments.svg" - ) - ).default; + return (await import("./iot/10181-icon-service-Time-Series-Insights-Environments.svg")).default; // Microsoft.OperationalInsights case "microsoft.operationalinsights/workspaces": - return ( - await import( - "./analytics/00009-icon-service-Log-Analytics-Workspaces.svg" - ) - ).default; + return (await import("./analytics/00009-icon-service-Log-Analytics-Workspaces.svg")).default; // Microsoft.EventHub case "microsoft.eventhub/namespaces": - return (await import("./analytics/00039-icon-service-Event-Hubs.svg")) - .default; + return (await import("./analytics/00039-icon-service-Event-Hubs.svg")).default; case "microsoft.eventhub/clusters": - return ( - await import("./analytics/10149-icon-service-Event-Hub-Clusters.svg") - ).default; + return (await import("./analytics/10149-icon-service-Event-Hub-Clusters.svg")).default; // Microsoft.StreamAnalytics case "microsoft.streamanalytics/streamingjobs": - return ( - await import("./analytics/00042-icon-service-Stream-Analytics-Jobs.svg") - ).default; + return (await import("./analytics/00042-icon-service-Stream-Analytics-Jobs.svg")).default; // Microsoft.Synapse case "microsoft.synapse/workspaces": - return ( - await import( - "./analytics/00606-icon-service-Azure-Synapse-Analytics.svg" - ) - ).default; + return (await import("./analytics/00606-icon-service-Azure-Synapse-Analytics.svg")).default; // Microsoft.Databricks case "microsoft.databricks/workspaces": - return ( - await import("./analytics/10787-icon-service-Azure-Databricks.svg") - ).default; + return (await import("./analytics/10787-icon-service-Azure-Databricks.svg")).default; // Microsoft.BotService case "microsoft.botservice/botservices": @@ -374,47 +212,31 @@ export async function importResourceIconInline( // Microsoft.CognitiveServices case "microsoft.cognitiveservices/accounts": - return (await import("./ai/10162-icon-service-Cognitive-Services.svg")) - .default; + return (await import("./ai/10162-icon-service-Cognitive-Services.svg")).default; // Microsoft.MachineLearning case "microsoft.machinelearning/workspaces": - return ( - await import( - "./ai/10167-icon-service-Machine-Learning-Studio-Workspaces.svg" - ) - ).default; + return (await import("./ai/10167-icon-service-Machine-Learning-Studio-Workspaces.svg")).default; // Microsoft.HDInsight case "microsoft.hdinsight/clusters": - return ( - await import("./analytics/10142-icon-service-HD-Insight-Clusters.svg") - ).default; + return (await import("./analytics/10142-icon-service-HD-Insight-Clusters.svg")).default; // Microsoft.AnalysisServices case "microsoft.analysisservices/servers": - return ( - await import("./analytics/10148-icon-service-Analysis-Services.svg") - ).default; + return (await import("./analytics/10148-icon-service-Analysis-Services.svg")).default; // microsoft.insights case "microsoft.insights/components": - return ( - await import("./devops/00012-icon-service-Application-Insights.svg") - ).default; + return (await import("./devops/00012-icon-service-Application-Insights.svg")).default; // Microsoft.DevTestLab case "microsoft.devtestlab/labs": - return (await import("./devops/10264-icon-service-DevTest-Labs.svg")) - .default; + return (await import("./devops/10264-icon-service-DevTest-Labs.svg")).default; // Microsoft.AAD case "microsoft.aad/domainservices": - return ( - await import( - "./identity/10222-icon-service-Azure-AD-Domain-Services.svg" - ) - ).default; + return (await import("./identity/10222-icon-service-Azure-AD-Domain-Services.svg")).default; // Microsoft.Logic case "microsoft.logic/workflows": @@ -422,62 +244,42 @@ export async function importResourceIconInline( // Microsoft.AzureActiveDirectory case "microsoft.azureactivedirectory/b2cdirectories": - return (await import("./identity/10228-icon-service-Azure-AD-B2C.svg")) - .default; + return (await import("./identity/10228-icon-service-Azure-AD-B2C.svg")).default; // Microsoft.ManagedIdentity case "microsoft.managedidentity/identities": - return ( - await import("./identity/10227-icon-service-Managed-Identities.svg") - ).default; + return (await import("./identity/10227-icon-service-Managed-Identities.svg")).default; // Microsoft.LabServices case "microsoft.labservices/labaccounts": - return (await import("./devops/10265-icon-service-Lab-Services.svg")) - .default; + return (await import("./devops/10265-icon-service-Lab-Services.svg")).default; // Microsoft.ApiManagement case "microsoft.apimanagement/service": - return ( - await import( - "./appServices/10042-icon-service-API-Management-Services.svg" - ) - ).default; + return (await import("./appServices/10042-icon-service-API-Management-Services.svg")).default; // Microsoft.ServiceBus case "microsoft.servicebus/namespaces": - return (await import("./general/10836-icon-service-Service-Bus.svg")) - .default; + return (await import("./general/10836-icon-service-Service-Bus.svg")).default; // Microsoft.ContainerInstance case "microsoft.containerinstance/containergroups": - return ( - await import("./containers/10104-icon-service-Container-Instances.svg") - ).default; + return (await import("./containers/10104-icon-service-Container-Instances.svg")).default; // Microsoft.ContainerRegistry case "microsoft.containerregistry/registries": - return ( - await import("./containers/10105-icon-service-Container-Registries.svg") - ).default; + return (await import("./containers/10105-icon-service-Container-Registries.svg")).default; // Microsoft.App case "microsoft.app/containerapps": - return ( - await import("./containers/02884-icon-service-Worker-Container-App.svg") - ).default; + return (await import("./containers/02884-icon-service-Worker-Container-App.svg")).default; case "microsoft.app/managedenvironments": - return ( - await import( - "./containers/02989-icon-service-Container-App-Environments.svg" - ) - ).default; + return (await import("./containers/02989-icon-service-Container-App-Environments.svg")).default; // Microsoft.Cdn case "microsoft.cdn/service": - return (await import("./appServices/00056-icon-service-CDN-Profiles.svg")) - .default; + return (await import("./appServices/00056-icon-service-CDN-Profiles.svg")).default; default: return (await import("./custom/resource.svg")).default; diff --git a/src/vscode-bicep/src/visualizer/app/components/App.tsx b/src/vscode-bicep/src/visualizer/app/components/App.tsx index 5b03d586820..3a2f8f74dd6 100644 --- a/src/vscode-bicep/src/visualizer/app/components/App.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/App.tsx @@ -1,25 +1,19 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // import cytoscape from "cytoscape"; -import { useEffect, useState, VFC } from "react"; import { ElementDefinition } from "cytoscape"; +import { useEffect, useState, VFC } from "react"; import { DefaultTheme, ThemeProvider } from "styled-components"; - -import { StatusBar } from "./StatusBar"; -import { - Graph, - createContainerNodeBackgroundUri, - createChildlessNodeBackgroundUri, -} from "./Graph"; - -import { DeploymentGraphMessage, Message, READY_MESSAGE } from "../../messages"; import { DeploymentGraph } from "../../../language"; -import { darkTheme, lightTheme, highContrastTheme } from "../themes"; +import { DeploymentGraphMessage, Message, READY_MESSAGE } from "../../messages"; +import { darkTheme, highContrastTheme, lightTheme } from "../themes"; import { vscode } from "../vscode"; +import { createChildlessNodeBackgroundUri, createContainerNodeBackgroundUri, Graph } from "./Graph"; +import { StatusBar } from "./StatusBar"; async function mapToElements( graph: DeploymentGraphMessage["deploymentGraph"], - theme: DefaultTheme + theme: DefaultTheme, ): Promise { if (!graph) { return []; @@ -40,15 +34,10 @@ async function mapToElements( range: node.range, backgroundDataUri: node.hasChildren ? createContainerNodeBackgroundUri(symbol, node.isCollection, theme) - : await createChildlessNodeBackgroundUri( - symbol, - node.type, - node.isCollection, - theme - ), + : await createChildlessNodeBackgroundUri(symbol, node.type, node.isCollection, theme), }, }; - }) + }), ); const edges = graph.edges.map(({ sourceId, targetId }) => ({ @@ -103,9 +92,7 @@ export const App: VFC = () => { applyTheme(document.body.className); const observer = new MutationObserver((mutationRecords) => - mutationRecords.forEach((mutationRecord) => - applyTheme((mutationRecord.target as HTMLElement).className) - ) + mutationRecords.forEach((mutationRecord) => applyTheme((mutationRecord.target as HTMLElement).className)), ); observer.observe(document.body, { @@ -119,10 +106,7 @@ export const App: VFC = () => { return ( - 0} - /> + 0} /> ); }; diff --git a/src/vscode-bicep/src/visualizer/app/components/Graph/CommandBar.tsx b/src/vscode-bicep/src/visualizer/app/components/Graph/CommandBar.tsx index 4130bcff2db..d24506aab8d 100644 --- a/src/vscode-bicep/src/visualizer/app/components/Graph/CommandBar.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/Graph/CommandBar.tsx @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { FC } from "react"; -import styled, { DefaultTheme, withTheme, css } from "styled-components"; -import { VscWand } from "react-icons/vsc"; import { CgMaximize, CgZoomIn, CgZoomOut } from "react-icons/cg"; +import { VscWand } from "react-icons/vsc"; +import styled, { css, DefaultTheme, withTheme } from "styled-components"; import { TooltipHost } from "../Tooltip"; interface CommandBarProps { @@ -65,40 +65,26 @@ const CommandBarComponent: FC = (props) => ( - + - + - + - + ); // Workaround for https://github.com/styled-components/styled-components/issues/4082. -export const CommandBar = withTheme(CommandBarComponent) as FC< - Omit ->; +export const CommandBar = withTheme(CommandBarComponent) as FC>; diff --git a/src/vscode-bicep/src/visualizer/app/components/Graph/Graph.tsx b/src/vscode-bicep/src/visualizer/app/components/Graph/Graph.tsx index db66df18b84..95947e8232a 100644 --- a/src/vscode-bicep/src/visualizer/app/components/Graph/Graph.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/Graph/Graph.tsx @@ -1,21 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { - useRef, - FC, - memo, - useCallback, - useMemo, - NamedExoticComponent, -} from "react"; import cytoscape from "cytoscape"; +import { FC, memo, NamedExoticComponent, useCallback, useMemo, useRef } from "react"; import styled, { DefaultTheme, withTheme } from "styled-components"; - -import { createStylesheet } from "./style"; import { createRevealFileRangeMessage } from "../../../messages"; -import { vscode } from "../../vscode"; import { useCytoscape } from "../../hooks"; +import { vscode } from "../../vscode"; import { CommandBar } from "./CommandBar"; +import { createStylesheet } from "./style"; interface GraphProps { elements: cytoscape.ElementDefinition[]; @@ -28,8 +20,7 @@ const layoutOptions = { fit: true, animate: true, animationDuration: 800, - animationEasing: - "cubic-bezier(0.33, 1, 0.68, 1)" as cytoscape.Css.TransitionTimingFunction, + animationEasing: "cubic-bezier(0.33, 1, 0.68, 1)" as cytoscape.Css.TransitionTimingFunction, elk: { algorithm: "layered", "layered.layering.strategy": "INTERACTIVE", @@ -99,19 +90,14 @@ const GraphComponent: FC = ({ elements, theme }) => { { easing: layoutOptions.animationEasing, duration: layoutOptions.animationDuration, - } + }, ); }, []); return ( <> - + ); }; @@ -137,6 +123,6 @@ export const Graph = memo( prevData.source === nextData.source && prevData.target === nextData.target ); - }) -// Workaround for https://github.com/styled-components/styled-components/issues/4082. + }), + // Workaround for https://github.com/styled-components/styled-components/issues/4082. ) as NamedExoticComponent>; diff --git a/src/vscode-bicep/src/visualizer/app/components/Graph/style.ts b/src/vscode-bicep/src/visualizer/app/components/Graph/style.ts index c80f77ddc40..535e3f495a1 100644 --- a/src/vscode-bicep/src/visualizer/app/components/Graph/style.ts +++ b/src/vscode-bicep/src/visualizer/app/components/Graph/style.ts @@ -2,7 +2,6 @@ // Licensed under the MIT License. import { Stylesheet } from "cytoscape"; import { DefaultTheme } from "styled-components"; - import { importResourceIconInline } from "../../assets/icons/azure"; import moduleIcon from "../../assets/icons/azure/general/10802-icon-service-Folder-Blank.svg"; @@ -34,9 +33,7 @@ function truncate(text: string, lengthLimit: number) { const headLength = Math.ceil(charsLength / 2); const tailLength = Math.floor(charsLength / 2); - return ( - text.substr(0, headLength) + "..." + text.substr(text.length - tailLength) - ); + return text.substr(0, headLength) + "..." + text.substr(text.length - tailLength); } function createDataUri(svg: string) { @@ -52,8 +49,7 @@ export async function createChildlessNodeBackgroundUri( isCollection: boolean, theme: DefaultTheme, ): Promise { - const icon = - type !== "" ? await importResourceIconInline(type) : moduleIcon; + const icon = type !== "" ? await importResourceIconInline(type) : moduleIcon; type = type.split("/").pop() ?? type; type += isCollection ? "[]" : ""; @@ -66,14 +62,10 @@ export async function createChildlessNodeBackgroundUri( ${icon} - + ${escapeXml(truncate(symbol, 17))} - + ${escapeXml(truncate(type, 23))} @@ -82,11 +74,7 @@ export async function createChildlessNodeBackgroundUri( return createDataUri(backgroundSvg); } -export function createContainerNodeBackgroundUri( - symbol: string, - isCollection: boolean, - theme: DefaultTheme, -): string { +export function createContainerNodeBackgroundUri(symbol: string, isCollection: boolean, theme: DefaultTheme): string { symbol += isCollection ? " " : ""; const { foregroundSecondaryColor } = theme.common; @@ -95,9 +83,7 @@ export function createContainerNodeBackgroundUri( ${moduleIcon} - + ${escapeXml(truncate(symbol, 37))} @@ -122,10 +108,7 @@ export function createStylesheet(theme: DefaultTheme): Stylesheet[] { "background-color": childlessNode.backgroundColor, "background-image": "data(backgroundDataUri)", "border-width": childlessNode.borderWidth, - "border-color": (node) => - node.data("hasError") === true - ? errorIndicatorColor - : childlessNode.borderColor, + "border-color": (node) => (node.data("hasError") === true ? errorIndicatorColor : childlessNode.borderColor), "border-opacity": childlessNode.borderOpacity, }, }, @@ -138,10 +121,7 @@ export function createStylesheet(theme: DefaultTheme): Stylesheet[] { "background-position-x": 12, "background-position-y": 8, "border-width": containerNode.borderWidth, - "border-color": (node) => - node.data("hasError") === true - ? errorIndicatorColor - : containerNode.borderColor, + "border-color": (node) => (node.data("hasError") === true ? errorIndicatorColor : containerNode.borderColor), "border-opacity": containerNode.borderOpacity, "background-opacity": containerNode.backgroundOpacity, "padding-top": "40px", diff --git a/src/vscode-bicep/src/visualizer/app/components/StatusBar.tsx b/src/vscode-bicep/src/visualizer/app/components/StatusBar.tsx index 840f2e68b27..54a85fe085e 100644 --- a/src/vscode-bicep/src/visualizer/app/components/StatusBar.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/StatusBar.tsx @@ -22,9 +22,7 @@ const StatusCircle = styled.div<{ hasErrors: boolean }>` width: 8px; height: 8px; background-color: ${({ hasErrors, theme }) => - hasErrors - ? theme.common.errorIndicatorColor - : theme.common.errorFreeIndicatorColor}; + hasErrors ? theme.common.errorIndicatorColor : theme.common.errorFreeIndicatorColor}; border-radius: 50%; color: white; margin-top: 2px; @@ -38,15 +36,10 @@ const StatusBarComponent: VFC = ({ errorCount, hasNodes }) => (
There {errorCount === 1 ? "is " : "are "} {errorCount} - {errorCount === 1 ? " error" : " errors"} in the file. The rendered - graph may not be accurate. -
- )} - {errorCount === 0 && !hasNodes && ( -
- There are no resources or modules in the file. Nothing to display. + {errorCount === 1 ? " error" : " errors"} in the file. The rendered graph may not be accurate.
)} + {errorCount === 0 && !hasNodes &&
There are no resources or modules in the file. Nothing to display.
} ); diff --git a/src/vscode-bicep/src/visualizer/app/components/Tooltip.tsx b/src/vscode-bicep/src/visualizer/app/components/Tooltip.tsx index ec006d93a6e..c51a33a6381 100644 --- a/src/vscode-bicep/src/visualizer/app/components/Tooltip.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/Tooltip.tsx @@ -43,11 +43,7 @@ export const TooltipHost: VFC = ({ content, children }) => { return ( {content} -
+
{children}
diff --git a/src/vscode-bicep/src/visualizer/app/components/index.tsx b/src/vscode-bicep/src/visualizer/app/components/index.tsx index a862ad4aab0..efc2449d469 100644 --- a/src/vscode-bicep/src/visualizer/app/components/index.tsx +++ b/src/vscode-bicep/src/visualizer/app/components/index.tsx @@ -1,8 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; import { createGlobalStyle } from "styled-components"; - import { App } from "./App"; const GlobalStyle = createGlobalStyle` @@ -20,10 +19,17 @@ const GlobalStyle = createGlobalStyle` } `; -ReactDOM.render( +const container = document.getElementById("root"); + +if (!container) { + throw new Error("Could not find the root element"); +} + +const root = createRoot(container); + +root.render( <> , - document.getElementById("root") ); diff --git a/src/vscode-bicep/src/visualizer/app/hooks/useCytoscape.ts b/src/vscode-bicep/src/visualizer/app/hooks/useCytoscape.ts index 04e596cf032..6f370027795 100644 --- a/src/vscode-bicep/src/visualizer/app/hooks/useCytoscape.ts +++ b/src/vscode-bicep/src/visualizer/app/hooks/useCytoscape.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import React, { createContext, RefObject, useEffect, useRef } from "react"; import cytoscape, { Core, LayoutOptions, Layouts, Stylesheet } from "cytoscape"; import elk from "cytoscape-elk"; +import React, { createContext, RefObject, useEffect, useRef } from "react"; export interface ZoomOptions { minLevel: number; @@ -20,16 +20,8 @@ export interface CreationOptions { export function useCytoscape( elements: cytoscape.ElementDefinition[], stylesheets: Stylesheet[], - { - containerRef, - layoutOptions, - zoomOptions, - onNodeDoubleTap, - }: CreationOptions, -): [ - React.MutableRefObject, - React.MutableRefObject, -] { + { containerRef, layoutOptions, zoomOptions, onNodeDoubleTap }: CreationOptions, +): [React.MutableRefObject, React.MutableRefObject] { const cytoscapeRef = useRef(); const layoutRef = useRef(); @@ -73,6 +65,4 @@ export function useCytoscape( return [cytoscapeRef, layoutRef]; } -export const cytoscapeContext = createContext( - undefined, -); +export const cytoscapeContext = createContext(undefined); diff --git a/src/vscode-bicep/src/visualizer/app/themes.ts b/src/vscode-bicep/src/visualizer/app/themes.ts index b8edd873505..7fabb2900bc 100644 --- a/src/vscode-bicep/src/visualizer/app/themes.ts +++ b/src/vscode-bicep/src/visualizer/app/themes.ts @@ -2,9 +2,7 @@ // Licensed under the MIT License. import { DefaultTheme } from "styled-components"; -const fontFamily = getComputedStyle(document.body) - .getPropertyValue("--vscode-font-family") - .replace(/"/g, ""); +const fontFamily = getComputedStyle(document.body).getPropertyValue("--vscode-font-family").replace(/"/g, ""); export const darkTheme: DefaultTheme = { name: "dark", @@ -17,8 +15,7 @@ export const darkTheme: DefaultTheme = { }, canvas: { backgroundColor: "#111111", - backgroundImage: - "radial-gradient(circle at 1px 1px, #3f3f3f 1px, transparent 0)", + backgroundImage: "radial-gradient(circle at 1px 1px, #3f3f3f 1px, transparent 0)", }, graph: { childlessNode: { @@ -56,8 +53,7 @@ export const lightTheme: DefaultTheme = { }, canvas: { backgroundColor: "#ffffff", - backgroundImage: - "radial-gradient(circle at 1px 1px, #a0a6af 1px, transparent 0)", + backgroundImage: "radial-gradient(circle at 1px 1px, #a0a6af 1px, transparent 0)", }, graph: { childlessNode: { diff --git a/src/vscode-bicep/src/visualizer/app/typings/cytoscape-elk/index.d.ts b/src/vscode-bicep/src/visualizer/app/typings/cytoscape-elk/index.d.ts index 7334ff3f721..2d27e9575fe 100644 --- a/src/vscode-bicep/src/visualizer/app/typings/cytoscape-elk/index.d.ts +++ b/src/vscode-bicep/src/visualizer/app/typings/cytoscape-elk/index.d.ts @@ -1,9 +1,5 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. declare module "cytoscape-elk" { - const cytoscape = import("cytoscape"); - - export default function register( - cytoscape: (options?: cytoscape.CytoscapeOptions) => cytoscape.Core, - ): void; + export default function register(cytoscape: (options?: cytoscape.CytoscapeOptions) => cytoscape.Core): void; } diff --git a/src/vscode-bicep/src/visualizer/messages.ts b/src/vscode-bicep/src/visualizer/messages.ts index 100c693eb7a..ac11e18e220 100644 --- a/src/vscode-bicep/src/visualizer/messages.ts +++ b/src/vscode-bicep/src/visualizer/messages.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import type { DeploymentGraph } from "../language/protocol"; + import vscode from "vscode"; interface SimpleMessage { @@ -27,19 +28,16 @@ export type RevealFileRangeMessage = MessageWithPayload< } >; -export type Message = - | ReadyMessage - | DeploymentGraphMessage - | RevealFileRangeMessage; +export type Message = ReadyMessage | DeploymentGraphMessage | RevealFileRangeMessage; function createSimpleMessage(kind: T): SimpleMessage { return { kind }; } -function createMessageWithPayload< - T extends string, - U = Record, ->(kind: T, payload: U): MessageWithPayload { +function createMessageWithPayload>( + kind: T, + payload: U, +): MessageWithPayload { return { kind, ...payload, @@ -58,10 +56,7 @@ export function createDeploymentGraphMessage( }); } -export function createRevealFileRangeMessage( - filePath: string, - range: vscode.Range, -): RevealFileRangeMessage { +export function createRevealFileRangeMessage(filePath: string, range: vscode.Range): RevealFileRangeMessage { return createMessageWithPayload("REVEAL_FILE_RANGE", { filePath, range, diff --git a/src/vscode-bicep/src/visualizer/view.ts b/src/vscode-bicep/src/visualizer/view.ts index 5b631d7bdc6..4e6fcd82075 100644 --- a/src/vscode-bicep/src/visualizer/view.ts +++ b/src/vscode-bicep/src/visualizer/view.ts @@ -1,16 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import vscode from "vscode"; -import path from "path"; import crypto from "crypto"; +import path from "path"; +import { parseError } from "@microsoft/vscode-azext-utils"; +import vscode from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; - -import { createDeploymentGraphMessage, Message } from "./messages"; import { deploymentGraphRequestType } from "../language"; -import { parseError } from "@microsoft/vscode-azext-utils"; import { Disposable } from "../utils/disposable"; -import { debounce } from "../utils/time"; import { getLogger } from "../utils/logger"; +import { debounce } from "../utils/time"; +import { createDeploymentGraphMessage, Message } from "./messages"; export class BicepVisualizerView extends Disposable { public static viewType = "bicep.visualizer"; @@ -33,24 +32,15 @@ export class BicepVisualizerView extends Disposable { new vscode.EventEmitter(), ); - this.register( - this.webviewPanel.webview.onDidReceiveMessage( - // eslint-disable-next-line jest/unbound-method - this.handleDidReceiveMessage, - this, - ), - ); + this.register(this.webviewPanel.webview.onDidReceiveMessage(this.handleDidReceiveMessage, this)); if (!this.isDisposed) { this.webviewPanel.webview.html = this.createWebviewHtml(); } this.registerMultiple( - // eslint-disable-next-line jest/unbound-method this.webviewPanel.onDidDispose(this.dispose, this), - this.webviewPanel.onDidChangeViewState((e) => - this.onDidChangeViewStateEmitter.fire(e), - ), + this.webviewPanel.onDidChangeViewState((e) => this.onDidChangeViewStateEmitter.fire(e)), ); } @@ -69,22 +59,12 @@ export class BicepVisualizerView extends Disposable { documentUri: vscode.Uri, ): BicepVisualizerView { const visualizerTitle = `Visualize ${path.basename(documentUri.fsPath)}`; - const webviewPanel = vscode.window.createWebviewPanel( - BicepVisualizerView.viewType, - visualizerTitle, - viewColumn, - { - enableScripts: true, - retainContextWhenHidden: true, - }, - ); + const webviewPanel = vscode.window.createWebviewPanel(BicepVisualizerView.viewType, visualizerTitle, viewColumn, { + enableScripts: true, + retainContextWhenHidden: true, + }); - return new BicepVisualizerView( - languageClient, - webviewPanel, - extensionUri, - documentUri, - ); + return new BicepVisualizerView(languageClient, webviewPanel, extensionUri, documentUri); } public static revive( @@ -93,12 +73,7 @@ export class BicepVisualizerView extends Disposable { extensionUri: vscode.Uri, documentUri: vscode.Uri, ): BicepVisualizerView { - return new BicepVisualizerView( - languageClient, - webviewPanel, - extensionUri, - documentUri, - ); + return new BicepVisualizerView(languageClient, webviewPanel, extensionUri, documentUri); } public reveal(): void { @@ -135,15 +110,9 @@ export class BicepVisualizerView extends Disposable { return; } - const deploymentGraph = await this.languageClient.sendRequest( - deploymentGraphRequestType, - { - textDocument: - this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier( - document, - ), - }, - ); + const deploymentGraph = await this.languageClient.sendRequest(deploymentGraphRequestType, { + textDocument: this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document), + }); if (this.isDisposed) { return; @@ -163,9 +132,7 @@ export class BicepVisualizerView extends Disposable { private handleDidReceiveMessage(message: Message): void { switch (message.kind) { case "READY": - getLogger().debug( - `Visualizer for ${this.documentUri.fsPath} is ready.`, - ); + getLogger().debug(`Visualizer for ${this.documentUri.fsPath} is ready.`); this.readyToRender = true; this.render(); @@ -181,17 +148,11 @@ export class BicepVisualizerView extends Disposable { private revealFileRange(filePath: string, range: vscode.Range) { for (const visibleEditor of vscode.window.visibleTextEditors) { if (visibleEditor.document.uri.fsPath === filePath) { - vscode.window - .showTextDocument(visibleEditor.document, visibleEditor.viewColumn) - .then( - (editor) => this.revealEditorRange(editor, range), - (err) => - vscode.window.showErrorMessage( - `Could not reveal file range in "${filePath}": ${ - parseError(err).message - }`, - ), - ); + vscode.window.showTextDocument(visibleEditor.document, visibleEditor.viewColumn).then( + (editor) => this.revealEditorRange(editor, range), + (err) => + vscode.window.showErrorMessage(`Could not reveal file range in "${filePath}": ${parseError(err).message}`), + ); return; } } @@ -201,19 +162,13 @@ export class BicepVisualizerView extends Disposable { .then(vscode.window.showTextDocument) .then( (editor) => this.revealEditorRange(editor, range), - (err) => - vscode.window.showErrorMessage( - `Could not open "${filePath}": ${parseError(err).message}`, - ), + (err) => vscode.window.showErrorMessage(`Could not open "${filePath}": ${parseError(err).message}`), ); } private revealEditorRange(editor: vscode.TextEditor, range: vscode.Range) { // editor.selection.active is the current cursor position which is immutable. - const cursorPosition = editor.selection.active.with( - range.start.line, - range.start.character, - ); + const cursorPosition = editor.selection.active.with(range.start.line, range.start.character); // Move cursor to the beginning of the resource/module and reveal the source code. editor.selection = new vscode.Selection(cursorPosition, cursorPosition); editor.revealRange(range, vscode.TextEditorRevealType.InCenter); diff --git a/src/vscode-bicep/src/visualizer/viewManager.ts b/src/vscode-bicep/src/visualizer/viewManager.ts index 76f56b83fb0..c97a9ddfeaf 100644 --- a/src/vscode-bicep/src/visualizer/viewManager.ts +++ b/src/vscode-bicep/src/visualizer/viewManager.ts @@ -2,14 +2,10 @@ // Licensed under the MIT License. import vscode from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; - -import { BicepVisualizerView } from "./view"; import { Disposable } from "../utils/disposable"; +import { BicepVisualizerView } from "./view"; -export class BicepVisualizerViewManager - extends Disposable - implements vscode.WebviewPanelSerializer -{ +export class BicepVisualizerViewManager extends Disposable implements vscode.WebviewPanelSerializer { private static readonly visualizerActiveContextKey = "bicepVisualizerFocus"; private readonly viewsByPath = new Map(); @@ -22,15 +18,9 @@ export class BicepVisualizerViewManager ) { super(); - this.register( - vscode.window.registerWebviewPanelSerializer( - BicepVisualizerView.viewType, - this, - ), - ); + this.register(vscode.window.registerWebviewPanelSerializer(BicepVisualizerView.viewType, this)); - const existingMiddleware = - languageClient.clientOptions.middleware?.handleDiagnostics; + const existingMiddleware = languageClient.clientOptions.middleware?.handleDiagnostics; this.languageClient.clientOptions.middleware = { ...(this.languageClient.clientOptions.middleware ?? {}), @@ -52,10 +42,7 @@ export class BicepVisualizerViewManager return this.activeUri; } - public async openView( - documentUri: vscode.Uri, - viewColumn: vscode.ViewColumn, - ): Promise { + public async openView(documentUri: vscode.Uri, viewColumn: vscode.ViewColumn): Promise { const existingView = this.viewsByPath.get(documentUri.fsPath); if (existingView) { @@ -65,32 +52,19 @@ export class BicepVisualizerViewManager this.registerView( documentUri, - BicepVisualizerView.create( - this.languageClient, - viewColumn, - this.extensionUri, - documentUri, - ), + BicepVisualizerView.create(this.languageClient, viewColumn, this.extensionUri, documentUri), ); await this.setVisualizerActiveContext(true); this.activeUri = documentUri; } - public async deserializeWebviewPanel( - webviewPanel: vscode.WebviewPanel, - documentPath: string, - ): Promise { + public async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, documentPath: string): Promise { const documentUri = vscode.Uri.file(documentPath); this.registerView( documentUri, - BicepVisualizerView.revive( - this.languageClient, - webviewPanel, - this.extensionUri, - documentUri, - ), + BicepVisualizerView.revive(this.languageClient, webviewPanel, this.extensionUri, documentUri), ); } @@ -109,10 +83,7 @@ export class BicepVisualizerViewManager this.viewsByPath.clear(); } - private registerView( - documentUri: vscode.Uri, - view: BicepVisualizerView, - ): BicepVisualizerView { + private registerView(documentUri: vscode.Uri, view: BicepVisualizerView): BicepVisualizerView { this.viewsByPath.set(documentUri.fsPath, view); view.onDidChangeViewState((e) => { @@ -138,10 +109,6 @@ export class BicepVisualizerViewManager } private async setVisualizerActiveContext(value: boolean) { - await vscode.commands.executeCommand( - "setContext", - BicepVisualizerViewManager.visualizerActiveContextKey, - value, - ); + await vscode.commands.executeCommand("setContext", BicepVisualizerViewManager.visualizerActiveContextKey, value); } } diff --git a/src/vscode-bicep/tsconfig.e2e.dev.json b/src/vscode-bicep/tsconfig.e2e.dev.json deleted file mode 100644 index 33d47354944..00000000000 --- a/src/vscode-bicep/tsconfig.e2e.dev.json +++ /dev/null @@ -1,18 +0,0 @@ -// We need to compile the e2e tests until https://github.com/microsoft/vscode-test/issues/92 is closed. -{ - "compilerOptions": { - "target": "es6", - "lib": ["es2019"], - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "outDir": "out", - "sourceMap": true, - "skipLibCheck": true, - "strict": true, - "noImplicitReturns": true, - "noUnusedLocals": true, - "jsx": "react-jsx" - }, - "include": ["src/test/e2e"] -} diff --git a/src/vscode-bicep/tsconfig.e2e.json b/src/vscode-bicep/tsconfig.e2e.json index 33d47354944..6a396a1b2f7 100644 --- a/src/vscode-bicep/tsconfig.e2e.json +++ b/src/vscode-bicep/tsconfig.e2e.json @@ -1,18 +1,5 @@ // We need to compile the e2e tests until https://github.com/microsoft/vscode-test/issues/92 is closed. { - "compilerOptions": { - "target": "es6", - "lib": ["es2019"], - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "outDir": "out", - "sourceMap": true, - "skipLibCheck": true, - "strict": true, - "noImplicitReturns": true, - "noUnusedLocals": true, - "jsx": "react-jsx" - }, + "extends": "./tsconfig.json", "include": ["src/test/e2e"] } diff --git a/src/vscode-bicep/tsconfig.json b/src/vscode-bicep/tsconfig.json index 20e00404ad8..14afab96c27 100644 --- a/src/vscode-bicep/tsconfig.json +++ b/src/vscode-bicep/tsconfig.json @@ -1,19 +1,18 @@ { "compilerOptions": { "target": "es6", - "lib": ["dom", "dom.iterable", "es2019", "ES2021.String"], + "lib": ["dom", "dom.iterable", "es2020", "ES2021.String"], "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, "outDir": "out", "sourceMap": true, "skipLibCheck": true, + "jsx": "react-jsx", "strict": true, - "alwaysStrict": true, - "strictNullChecks": true, - "noImplicitReturns": true, "noUnusedLocals": true, - "jsx": "react-jsx" + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true }, "include": ["src"] } diff --git a/src/vscode-bicep/webpack.config.ts b/src/vscode-bicep/webpack.config.ts index d9bf1289d96..2bf9e5e6e8f 100644 --- a/src/vscode-bicep/webpack.config.ts +++ b/src/vscode-bicep/webpack.config.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import path from "path"; -import webpack from "webpack"; import CopyPlugin from "copy-webpack-plugin"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; import TerserPlugin from "terser-webpack-plugin"; +import webpack from "webpack"; const outputPath = path.resolve(__dirname, "out"); @@ -22,8 +22,7 @@ const extensionConfig: webpack.Configuration = { // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ vscode: "commonjs vscode", // The following are optional dependencies of microsoft/vscode-azext-utils that cannot be resolved. - "applicationinsights-native-metrics": - "commonjs applicationinsights-native-metrics", + "applicationinsights-native-metrics": "commonjs applicationinsights-native-metrics", "@opentelemetry/tracing": "commonjs @opentelemetry/tracing", }, optimization: { @@ -57,7 +56,7 @@ const extensionConfig: webpack.Configuration = { to: path.join(__dirname, "syntaxes/bicep.tmlanguage"), }, ], - }) as { apply(...args: unknown[]): void }, + }), new CopyPlugin({ patterns: [ { @@ -65,11 +64,12 @@ const extensionConfig: webpack.Configuration = { to: path.join(__dirname, "syntaxes/language-configuration.json"), }, ], - }) as { apply(...args: unknown[]): void }, + }), new ForkTsCheckerWebpackPlugin(), ], resolve: { extensions: [".ts", ".js"], + conditionNames: ["import", "require"], }, }; @@ -145,9 +145,9 @@ const deployPaneConfig: webpack.Configuration = { { test: /\.js$/, resolve: { - fullySpecified: false - } - } + fullySpecified: false, + }, + }, ], }, resolve: { @@ -161,14 +161,14 @@ const deployPaneConfig: webpack.Configuration = { }), new CopyPlugin({ patterns: [ - { from: 'node_modules/@vscode/codicons/dist/codicon.css', to: outputPath }, - { from: 'node_modules/@vscode/codicons/dist/codicon.ttf', to: outputPath }, - ] + { from: "node_modules/@vscode/codicons/dist/codicon.css", to: outputPath }, + { from: "node_modules/@vscode/codicons/dist/codicon.ttf", to: outputPath }, + ], }), ], }; -module.exports = (env: unknown, argv: { mode: string }) => { +module.exports = (_env: unknown, argv: { mode: string }) => { if (argv.mode === "development") { // "cheap-module-source-map" is almost 2x faster than "source-map", // while it provides decent source map quality.