diff options
Diffstat (limited to 'src/tools/rust-analyzer/editors/code')
34 files changed, 8841 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/editors/code/.eslintignore b/src/tools/rust-analyzer/editors/code/.eslintignore new file mode 100644 index 00000000000..3a1e8e186f5 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.eslintignore @@ -0,0 +1,2 @@ +node_modules +.eslintrc.js diff --git a/src/tools/rust-analyzer/editors/code/.eslintrc.js b/src/tools/rust-analyzer/editors/code/.eslintrc.js new file mode 100644 index 00000000000..297e9fa1e5c --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.eslintrc.js @@ -0,0 +1,37 @@ +module.exports = { + env: { + es6: true, + node: true, + }, + extends: ["prettier"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.eslint.json", + tsconfigRootDir: __dirname, + sourceType: "module", + }, + plugins: ["@typescript-eslint"], + rules: { + camelcase: ["error"], + eqeqeq: ["error", "always", { null: "ignore" }], + curly: ["error", "multi-line"], + "no-console": ["error", { allow: ["warn", "error"] }], + "prefer-const": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + multiline: { + delimiter: "semi", + requireLast: true, + }, + singleline: { + delimiter: "semi", + requireLast: false, + }, + }, + ], + "@typescript-eslint/semi": ["error", "always"], + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/no-floating-promises": "error", + }, +}; diff --git a/src/tools/rust-analyzer/editors/code/.gitignore b/src/tools/rust-analyzer/editors/code/.gitignore new file mode 100644 index 00000000000..2c975a947eb --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.gitignore @@ -0,0 +1,7 @@ +out +node_modules +server +.vscode-test/ +*.vsix +bundle +vscode.proposed.d.ts diff --git a/src/tools/rust-analyzer/editors/code/.prettierignore b/src/tools/rust-analyzer/editors/code/.prettierignore new file mode 100644 index 00000000000..13baf68d7cc --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.prettierignore @@ -0,0 +1,3 @@ +node_modules +.vscode-test +out diff --git a/src/tools/rust-analyzer/editors/code/.prettierrc.js b/src/tools/rust-analyzer/editors/code/.prettierrc.js new file mode 100644 index 00000000000..cafb12f0e6d --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.prettierrc.js @@ -0,0 +1,5 @@ +module.exports = { + // use 100 because it's Rustfmt's default + // https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#max_width + printWidth: 100, +}; diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore new file mode 100644 index 00000000000..09dc27056b3 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/.vscodeignore @@ -0,0 +1,14 @@ +** +!icon.png +!language-configuration.json +!LICENSE +!node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm +!node_modules/@hpcc-js/wasm/dist/index.min.js +!node_modules/d3-graphviz/build/d3-graphviz.min.js +!node_modules/d3/dist/d3.min.js +!out/main.js +!package-lock.json +!package.json +!ra_syntax_tree.tmGrammar.json +!server +!README.md diff --git a/src/tools/rust-analyzer/editors/code/LICENSE b/src/tools/rust-analyzer/editors/code/LICENSE new file mode 100644 index 00000000000..d32e7fe8c91 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/LICENSE @@ -0,0 +1,230 @@ +This software is licensed under either of the Apache License, Version +2.0, or the MIT License. See below for their text. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +MIT License + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/tools/rust-analyzer/editors/code/README.md b/src/tools/rust-analyzer/editors/code/README.md new file mode 100644 index 00000000000..36ab9818822 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/README.md @@ -0,0 +1,52 @@ +# rust-analyzer + +This extension provides support for the [Rust programming language](https://www.rust-lang.org/). +It is recommended over and replaces `rust-lang.rust`. + +## Features + +- [code completion] with [imports insertion] +- go to [definition], [implementation], [type definition] +- [find all references], [workspace symbol search], [symbol renaming] +- [types and documentation on hover] +- [inlay hints] for types and parameter names +- [semantic syntax highlighting] +- a lot of [assists (code actions)] +- apply suggestions from errors +- ... and many more, check out the [manual] to see them all + +[code completion]: https://rust-analyzer.github.io/manual.html#magic-completions +[imports insertion]: https://rust-analyzer.github.io/manual.html#completion-with-autoimport +[definition]: https://rust-analyzer.github.io/manual.html#go-to-definition +[implementation]: https://rust-analyzer.github.io/manual.html#go-to-implementation +[type definition]: https://rust-analyzer.github.io/manual.html#go-to-type-definition +[find all references]: https://rust-analyzer.github.io/manual.html#find-all-references +[workspace symbol search]: https://rust-analyzer.github.io/manual.html#workspace-symbol +[symbol renaming]: https://rust-analyzer.github.io/manual.html#rename +[types and documentation on hover]: https://rust-analyzer.github.io/manual.html#hover +[inlay hints]: https://rust-analyzer.github.io/manual.html#inlay-hints +[semantic syntax highlighting]: https://rust-analyzer.github.io/manual.html#semantic-syntax-highlighting +[assists (code actions)]: https://rust-analyzer.github.io/manual.html#assists-code-actions +[manual]: https://rust-analyzer.github.io/manual.html + +## Quick start + +1. Install [rustup]. +2. Install the [rust-analyzer extension]. + +[rustup]: https://rustup.rs +[rust-analyzer extension]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer + +## Configuration + +This extension provides configurations through VSCode's configuration settings. All configurations are under `rust-analyzer.*`. + +See [the manual](https://rust-analyzer.github.io/manual.html#vs-code-2) for more information on VSCode specific configurations. + +## Communication + +For usage and troubleshooting requests, please use the ["IDEs and Editors" category of the Rust forum](https://users.rust-lang.org/c/ide/14). + +## Documentation + +See [rust-analyzer.github.io](https://rust-analyzer.github.io/) for more information. diff --git a/src/tools/rust-analyzer/editors/code/icon.png b/src/tools/rust-analyzer/editors/code/icon.png new file mode 100644 index 00000000000..072090c6f4a --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/icon.png Binary files differdiff --git a/src/tools/rust-analyzer/editors/code/language-configuration.json b/src/tools/rust-analyzer/editors/code/language-configuration.json new file mode 100644 index 00000000000..b1ee0843e3e --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/language-configuration.json @@ -0,0 +1,42 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "colorizedBracketPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "/*", "close": " */" } + ], + "autoCloseBefore": ";:.,=}])> \n\t", + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["<", ">"], + ["\"", "\""], + ["'", "'"] + ], + "indentationRules": { + "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$", + "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]" + }, + "folding": { + "markers": { + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" + } + } +} diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json new file mode 100644 index 00000000000..0436681b1a0 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -0,0 +1,2811 @@ +{ + "name": "rust-analyzer", + "version": "0.5.0-dev", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@hpcc-js/wasm": { + "version": "1.12.8", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz", + "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==", + "requires": { + "yargs": "^17.3.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/node": { + "version": "16.11.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz", + "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==", + "dev": true + }, + "@types/vscode": { + "version": "1.66.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz", + "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz", + "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/type-utils": "5.30.5", + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz", + "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz", + "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz", + "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.30.5", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz", + "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz", + "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/visitor-keys": "5.30.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz", + "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.30.5", + "@typescript-eslint/types": "5.30.5", + "@typescript-eslint/typescript-estree": "5.30.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.30.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz", + "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.30.5", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@vscode/test-electron": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", + "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "dev": true, + "requires": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + } + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "azure-devops-node-api": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", + "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "dev": true, + "requires": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "d3": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", + "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "dependencies": { + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + } + } + }, + "d3-array": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", + "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "dependencies": { + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + } + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-contour": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz", + "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==", + "requires": { + "d3-array": "^3.2.0" + } + }, + "d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "dependencies": { + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + } + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-geo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz", + "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==", + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-graphviz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz", + "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==", + "requires": { + "@hpcc-js/wasm": "1.12.8", + "d3-dispatch": "^2.0.0", + "d3-format": "^2.0.0", + "d3-interpolate": "^2.0.1", + "d3-path": "^2.0.0", + "d3-timer": "^2.0.0", + "d3-transition": "^2.0.0", + "d3-zoom": "^2.0.0" + }, + "dependencies": { + "d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" + }, + "d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" + }, + "d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + }, + "d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "requires": { + "d3-color": "1 - 2" + } + }, + "d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + }, + "d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, + "d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "requires": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + } + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, + "d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "d3-shape": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz", + "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "requires": { + "robust-predicates": "^3.0.0" + } + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", + "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "dev": true + }, + "esbuild": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", + "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", + "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "requires": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-abi": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz", + "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "ovsx": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz", + "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==", + "dev": true, + "requires": { + "commander": "^6.1.0", + "follow-redirects": "^1.14.6", + "is-ci": "^2.0.0", + "leven": "^3.1.0", + "tmp": "^0.2.1", + "vsce": "^2.6.3" + }, + "dependencies": { + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "requires": { + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dev": true, + "requires": { + "entities": "^4.3.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-rest-client": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", + "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "dev": true, + "requires": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", + "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", + "dev": true + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vsce": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz", + "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.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 + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "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 + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "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" + } + } + } + }, + "vscode-jsonrpc": { + "version": "8.0.0-next.7", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz", + "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ==" + }, + "vscode-languageclient": { + "version": "8.0.0-next.14", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz", + "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==", + "requires": { + "minimatch": "^3.0.4", + "semver": "^7.3.5", + "vscode-languageserver-protocol": "3.17.0-next.16" + } + }, + "vscode-languageserver-protocol": { + "version": "3.17.0-next.16", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz", + "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==", + "requires": { + "vscode-jsonrpc": "8.0.0-next.7", + "vscode-languageserver-types": "3.17.0-next.9" + } + }, + "vscode-languageserver-types": { + "version": "3.17.0-next.9", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz", + "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json new file mode 100644 index 00000000000..a13798d8b36 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -0,0 +1,1613 @@ +{ + "name": "rust-analyzer", + "displayName": "rust-analyzer", + "description": "Rust language support for Visual Studio Code", + "private": true, + "icon": "icon.png", + "version": "0.5.0-dev", + "releaseTag": null, + "publisher": "rust-lang", + "repository": { + "url": "https://github.com/rust-lang/rust-analyzer.git", + "type": "git" + }, + "homepage": "https://rust-analyzer.github.io/", + "license": "MIT OR Apache-2.0", + "keywords": [ + "rust" + ], + "categories": [ + "Programming Languages" + ], + "engines": { + "vscode": "^1.66.0" + }, + "enabledApiProposals": [], + "scripts": { + "vscode:prepublish": "npm run build-base -- --minify", + "package": "vsce package -o rust-analyzer.vsix", + "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16", + "build": "npm run build-base -- --sourcemap", + "watch": "npm run build-base -- --sourcemap --watch", + "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests", + "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix", + "pretest": "tsc && npm run build", + "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js" + }, + "dependencies": { + "d3": "^7.6.1", + "d3-graphviz": "^4.1.1", + "vscode-languageclient": "^8.0.0-next.14" + }, + "devDependencies": { + "@types/node": "~16.11.7", + "@types/vscode": "~1.66.0", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "@vscode/test-electron": "^2.1.5", + "cross-env": "^7.0.3", + "esbuild": "^0.14.48", + "eslint": "^8.19.0", + "eslint-config-prettier": "^8.5.0", + "ovsx": "^0.5.1", + "prettier": "^2.7.1", + "tslib": "^2.4.0", + "typescript": "^4.7.4", + "vsce": "^2.9.2" + }, + "activationEvents": [ + "onLanguage:rust", + "onCommand:rust-analyzer.analyzerStatus", + "onCommand:rust-analyzer.memoryUsage", + "onCommand:rust-analyzer.reloadWorkspace", + "workspaceContains:*/Cargo.toml", + "workspaceContains:*/rust-project.json" + ], + "main": "./out/main", + "contributes": { + "taskDefinitions": [ + { + "type": "cargo", + "required": [ + "command" + ], + "properties": { + "label": { + "type": "string" + }, + "command": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + } + } + } + } + ], + "commands": [ + { + "command": "rust-analyzer.syntaxTree", + "title": "Show Syntax Tree", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.viewHir", + "title": "View Hir", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.viewFileText", + "title": "View File Text (as seen by the server)", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.viewItemTree", + "title": "Debug ItemTree", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.viewCrateGraph", + "title": "View Crate Graph", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.viewFullCrateGraph", + "title": "View Crate Graph (Full)", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.expandMacro", + "title": "Expand macro recursively", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.matchingBrace", + "title": "Find matching brace", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.parentModule", + "title": "Locate parent module", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.joinLines", + "title": "Join lines", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.run", + "title": "Run", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.copyRunCommandLine", + "title": "Copy Run Command Line", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.debug", + "title": "Debug", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.newDebugConfig", + "title": "Generate launch configuration", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.analyzerStatus", + "title": "Status", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.memoryUsage", + "title": "Memory Usage (Clears Database)", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.shuffleCrateGraph", + "title": "Shuffle Crate Graph", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.reloadWorkspace", + "title": "Reload workspace", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.reload", + "title": "Restart server", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.onEnter", + "title": "Enhanced enter key", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.ssr", + "title": "Structural Search Replace", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.serverVersion", + "title": "Show RA Version", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.toggleInlayHints", + "title": "Toggle inlay hints", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.openDocs", + "title": "Open docs under cursor", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.openCargoToml", + "title": "Open Cargo.toml", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.peekTests", + "title": "Peek related tests", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.moveItemUp", + "title": "Move item up", + "category": "Rust Analyzer" + }, + { + "command": "rust-analyzer.moveItemDown", + "title": "Move item down", + "category": "Rust Analyzer" + } + ], + "keybindings": [ + { + "command": "rust-analyzer.parentModule", + "key": "ctrl+shift+u", + "when": "editorTextFocus && editorLangId == rust" + }, + { + "command": "rust-analyzer.matchingBrace", + "key": "ctrl+shift+m", + "when": "editorTextFocus && editorLangId == rust" + }, + { + "command": "rust-analyzer.joinLines", + "key": "ctrl+shift+j", + "when": "editorTextFocus && editorLangId == rust" + } + ], + "configuration": { + "type": "object", + "title": "Rust Analyzer", + "properties": { + "rust-analyzer.cargoRunner": { + "type": [ + "null", + "string" + ], + "default": null, + "description": "Custom cargo runner extension ID." + }, + "rust-analyzer.runnableEnv": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "mask": { + "type": "string", + "description": "Runnable name mask" + }, + "env": { + "type": "object", + "description": "Variables in form of { \"key\": \"value\"}" + } + } + } + }, + { + "type": "object", + "description": "Variables in form of { \"key\": \"value\"}" + } + ], + "default": null, + "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command." + }, + "rust-analyzer.server.path": { + "type": [ + "null", + "string" + ], + "scope": "machine-overridable", + "default": null, + "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)." + }, + "rust-analyzer.server.extraEnv": { + "type": [ + "null", + "object" + ], + "additionalProperties": { + "type": [ + "string", + "number" + ] + }, + "default": null, + "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging." + }, + "rust-analyzer.trace.server": { + "type": "string", + "scope": "window", + "enum": [ + "off", + "messages", + "verbose" + ], + "enumDescriptions": [ + "No traces", + "Error only", + "Full log" + ], + "default": "off", + "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)." + }, + "rust-analyzer.trace.extension": { + "description": "Enable logging of VS Code extensions itself.", + "type": "boolean", + "default": false + }, + "rust-analyzer.debug.engine": { + "type": "string", + "enum": [ + "auto", + "vadimcn.vscode-lldb", + "ms-vscode.cpptools" + ], + "default": "auto", + "description": "Preferred debug engine.", + "markdownEnumDescriptions": [ + "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).", + "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)", + "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)" + ] + }, + "rust-analyzer.debug.sourceFileMap": { + "type": [ + "object", + "string" + ], + "const": "auto", + "description": "Optional source file mappings passed to the debug engine.", + "default": { + "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust" + } + }, + "rust-analyzer.debug.openDebugPane": { + "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.", + "type": "boolean", + "default": false + }, + "rust-analyzer.debug.engineSettings": { + "type": "object", + "default": {}, + "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" + }, + "rust-analyzer.restartServerOnConfigChange": { + "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", + "default": false, + "type": "boolean" + }, + "$generated-start": {}, + "rust-analyzer.assist.expressionFillDefault": { + "markdownDescription": "Placeholder expression to use for missing expressions in assists.", + "default": "todo", + "type": "string", + "enum": [ + "todo", + "default" + ], + "enumDescriptions": [ + "Fill missing expressions with the `todo` macro", + "Fill missing expressions with reasonable defaults, `new` or `default` constructors." + ] + }, + "rust-analyzer.cachePriming.enable": { + "markdownDescription": "Warm up caches on project load.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.cachePriming.numThreads": { + "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.", + "default": 0, + "type": "number", + "minimum": 0, + "maximum": 255 + }, + "rust-analyzer.cargo.autoreload": { + "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.cargo.buildScripts.enable": { + "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.cargo.buildScripts.overrideCommand": { + "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, + "rust-analyzer.cargo.buildScripts.useRustcWrapper": { + "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.cargo.features": { + "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.", + "default": [], + "anyOf": [ + { + "type": "string", + "enum": [ + "all" + ], + "enumDescriptions": [ + "Pass `--all-features` to cargo" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "rust-analyzer.cargo.noDefaultFeatures": { + "markdownDescription": "Whether to pass `--no-default-features` to cargo.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.cargo.noSysroot": { + "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.cargo.target": { + "markdownDescription": "Compilation target override (target triple).", + "default": null, + "type": [ + "null", + "string" + ] + }, + "rust-analyzer.cargo.unsetTest": { + "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", + "default": [ + "core" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.checkOnSave.allTargets": { + "markdownDescription": "Check all targets and tests (`--all-targets`).", + "default": true, + "type": "boolean" + }, + "rust-analyzer.checkOnSave.command": { + "markdownDescription": "Cargo command to use for `cargo check`.", + "default": "check", + "type": "string" + }, + "rust-analyzer.checkOnSave.enable": { + "markdownDescription": "Run specified `cargo check` command for diagnostics on save.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.checkOnSave.extraArgs": { + "markdownDescription": "Extra arguments for `cargo check`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.checkOnSave.features": { + "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", + "default": null, + "anyOf": [ + { + "type": "string", + "enum": [ + "all" + ], + "enumDescriptions": [ + "Pass `--all-features` to cargo" + ] + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ] + }, + "rust-analyzer.checkOnSave.noDefaultFeatures": { + "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", + "default": null, + "type": [ + "null", + "boolean" + ] + }, + "rust-analyzer.checkOnSave.overrideCommand": { + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, + "rust-analyzer.checkOnSave.target": { + "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.", + "default": null, + "type": [ + "null", + "string" + ] + }, + "rust-analyzer.completion.autoimport.enable": { + "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.completion.autoself.enable": { + "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.completion.callable.snippets": { + "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.", + "default": "fill_arguments", + "type": "string", + "enum": [ + "fill_arguments", + "add_parentheses", + "none" + ], + "enumDescriptions": [ + "Add call parentheses and pre-fill arguments.", + "Add call parentheses.", + "Do no snippet completions for callables." + ] + }, + "rust-analyzer.completion.postfix.enable": { + "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.completion.privateEditable.enable": { + "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.completion.snippets.custom": { + "markdownDescription": "Custom completion snippets.", + "default": { + "Arc::new": { + "postfix": "arc", + "body": "Arc::new(${receiver})", + "requires": "std::sync::Arc", + "description": "Put the expression into an `Arc`", + "scope": "expr" + }, + "Rc::new": { + "postfix": "rc", + "body": "Rc::new(${receiver})", + "requires": "std::rc::Rc", + "description": "Put the expression into an `Rc`", + "scope": "expr" + }, + "Box::pin": { + "postfix": "pinbox", + "body": "Box::pin(${receiver})", + "requires": "std::boxed::Box", + "description": "Put the expression into a pinned `Box`", + "scope": "expr" + }, + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", + "scope": "expr" + }, + "Err": { + "postfix": "err", + "body": "Err(${receiver})", + "description": "Wrap the expression in a `Result::Err`", + "scope": "expr" + }, + "Some": { + "postfix": "some", + "body": "Some(${receiver})", + "description": "Wrap the expression in an `Option::Some`", + "scope": "expr" + } + }, + "type": "object" + }, + "rust-analyzer.diagnostics.disabled": { + "markdownDescription": "List of rust-analyzer diagnostics to disable.", + "default": [], + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "rust-analyzer.diagnostics.enable": { + "markdownDescription": "Whether to show native rust-analyzer diagnostics.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.diagnostics.experimental.enable": { + "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.diagnostics.remapPrefix": { + "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.", + "default": {}, + "type": "object" + }, + "rust-analyzer.diagnostics.warningsAsHint": { + "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.diagnostics.warningsAsInfo": { + "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.files.excludeDirs": { + "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.files.watcher": { + "markdownDescription": "Controls file watching implementation.", + "default": "client", + "type": "string", + "enum": [ + "client", + "server" + ], + "enumDescriptions": [ + "Use the client (editor) to watch files for changes", + "Use server-side file watching" + ] + }, + "rust-analyzer.highlightRelated.breakPoints.enable": { + "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.highlightRelated.exitPoints.enable": { + "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).", + "default": true, + "type": "boolean" + }, + "rust-analyzer.highlightRelated.references.enable": { + "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.highlightRelated.yieldPoints.enable": { + "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.actions.debug.enable": { + "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.actions.enable": { + "markdownDescription": "Whether to show HoverActions in Rust files.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.actions.gotoTypeDef.enable": { + "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.actions.implementations.enable": { + "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.actions.references.enable": { + "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.hover.actions.run.enable": { + "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.documentation.enable": { + "markdownDescription": "Whether to show documentation on hover.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.hover.links.enable": { + "markdownDescription": "Use markdown syntax for links in hover.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.imports.granularity.enforce": { + "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.imports.granularity.group": { + "markdownDescription": "How imports should be grouped into use statements.", + "default": "crate", + "type": "string", + "enum": [ + "preserve", + "crate", + "module", + "item" + ], + "enumDescriptions": [ + "Do not change the granularity of any imports and preserve the original structure written by the developer.", + "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", + "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", + "Flatten imports so that each has its own use statement." + ] + }, + "rust-analyzer.imports.group.enable": { + "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.imports.merge.glob": { + "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.imports.prefix": { + "markdownDescription": "The path structure for newly inserted paths to use.", + "default": "plain", + "type": "string", + "enum": [ + "plain", + "self", + "crate" + ], + "enumDescriptions": [ + "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", + "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", + "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." + ] + }, + "rust-analyzer.inlayHints.bindingModeHints.enable": { + "markdownDescription": "Whether to show inlay type hints for binding modes.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.inlayHints.chainingHints.enable": { + "markdownDescription": "Whether to show inlay type hints for method chains.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.inlayHints.closingBraceHints.enable": { + "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.inlayHints.closingBraceHints.minLines": { + "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).", + "default": 25, + "type": "integer", + "minimum": 0 + }, + "rust-analyzer.inlayHints.closureReturnTypeHints.enable": { + "markdownDescription": "Whether to show inlay type hints for return types of closures.", + "default": "never", + "type": "string", + "enum": [ + "always", + "never", + "with_block" + ], + "enumDescriptions": [ + "Always show type hints for return types of closures.", + "Never show type hints for return types of closures.", + "Only show type hints for return types of closures with blocks." + ] + }, + "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { + "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", + "default": "never", + "type": "string", + "enum": [ + "always", + "never", + "skip_trivial" + ], + "enumDescriptions": [ + "Always show lifetime elision hints.", + "Never show lifetime elision hints.", + "Only show lifetime elision hints if a return type is involved." + ] + }, + "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": { + "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.inlayHints.maxLength": { + "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.", + "default": 25, + "type": [ + "null", + "integer" + ], + "minimum": 0 + }, + "rust-analyzer.inlayHints.parameterHints.enable": { + "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.inlayHints.reborrowHints.enable": { + "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.", + "default": "never", + "type": "string", + "enum": [ + "always", + "never", + "mutable" + ], + "enumDescriptions": [ + "Always show reborrow hints.", + "Never show reborrow hints.", + "Only show mutable reborrow hints." + ] + }, + "rust-analyzer.inlayHints.renderColons": { + "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.inlayHints.typeHints.enable": { + "markdownDescription": "Whether to show inlay type hints for variables.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": { + "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { + "markdownDescription": "Whether to hide inlay type hints for constructors.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.joinLines.joinAssignments": { + "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.joinLines.joinElseIf": { + "markdownDescription": "Join lines inserts else between consecutive ifs.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.joinLines.removeTrailingComma": { + "markdownDescription": "Join lines removes trailing commas.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.joinLines.unwrapTrivialBlock": { + "markdownDescription": "Join lines unwraps trivial blocks.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.lens.debug.enable": { + "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.lens.enable": { + "markdownDescription": "Whether to show CodeLens in Rust files.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.lens.forceCustomCommands": { + "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.lens.implementations.enable": { + "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.lens.references.adt.enable": { + "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.lens.references.enumVariant.enable": { + "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.lens.references.method.enable": { + "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.lens.references.trait.enable": { + "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.lens.run.enable": { + "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.linkedProjects": { + "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.", + "default": [], + "type": "array", + "items": { + "type": [ + "string", + "object" + ] + } + }, + "rust-analyzer.lru.capacity": { + "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", + "default": null, + "type": [ + "null", + "integer" + ], + "minimum": 0 + }, + "rust-analyzer.notifications.cargoTomlNotFound": { + "markdownDescription": "Whether to show `can't find Cargo.toml` error message.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.procMacro.attributes.enable": { + "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.procMacro.enable": { + "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.procMacro.ignored": { + "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.", + "default": {}, + "type": "object" + }, + "rust-analyzer.procMacro.server": { + "markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).", + "default": null, + "type": [ + "null", + "string" + ] + }, + "rust-analyzer.runnables.command": { + "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", + "default": null, + "type": [ + "null", + "string" + ] + }, + "rust-analyzer.runnables.extraArgs": { + "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.rustc.source": { + "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", + "default": null, + "type": [ + "null", + "string" + ] + }, + "rust-analyzer.rustfmt.extraArgs": { + "markdownDescription": "Additional arguments to `rustfmt`.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "rust-analyzer.rustfmt.overrideCommand": { + "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.", + "default": null, + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + }, + "rust-analyzer.rustfmt.rangeFormatting.enable": { + "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.semanticHighlighting.strings.enable": { + "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.signatureInfo.detail": { + "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.", + "default": "full", + "type": "string", + "enum": [ + "full", + "parameters" + ], + "enumDescriptions": [ + "Show the entire signature.", + "Show only the parameters." + ] + }, + "rust-analyzer.signatureInfo.documentation.enable": { + "markdownDescription": "Show documentation.", + "default": true, + "type": "boolean" + }, + "rust-analyzer.typing.autoClosingAngleBrackets.enable": { + "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", + "default": false, + "type": "boolean" + }, + "rust-analyzer.workspace.symbol.search.kind": { + "markdownDescription": "Workspace symbol search kind.", + "default": "only_types", + "type": "string", + "enum": [ + "only_types", + "all_symbols" + ], + "enumDescriptions": [ + "Search for types only.", + "Search for all symbols kinds." + ] + }, + "rust-analyzer.workspace.symbol.search.limit": { + "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.", + "default": 128, + "type": "integer", + "minimum": 0 + }, + "rust-analyzer.workspace.symbol.search.scope": { + "markdownDescription": "Workspace symbol search scope.", + "default": "workspace", + "type": "string", + "enum": [ + "workspace", + "workspace_and_dependencies" + ], + "enumDescriptions": [ + "Search in current workspace only.", + "Search in current workspace and dependencies." + ] + }, + "$generated-end": {} + } + }, + "problemPatterns": [ + { + "name": "rustc", + "patterns": [ + { + "regexp": "^(warning|warn|error)(?:\\[(.*?)\\])?: (.*)$", + "severity": 1, + "code": 2, + "message": 3 + }, + { + "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$", + "file": 1, + "line": 2, + "column": 3 + } + ] + }, + { + "name": "rustc-json", + "patterns": [ + { + "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$", + "message": 1, + "file": 2, + "line": 3, + "endLine": 4, + "column": 5, + "endColumn": 6 + } + ] + } + ], + "languages": [ + { + "id": "ra_syntax_tree", + "extensions": [ + ".rast" + ] + }, + { + "id": "rust", + "extensions": [ + ".rs" + ], + "aliases": [ + "Rust", + "rs" + ], + "configuration": "language-configuration.json" + } + ], + "grammars": [ + { + "language": "ra_syntax_tree", + "scopeName": "source.ra_syntax_tree", + "path": "ra_syntax_tree.tmGrammar.json" + } + ], + "problemMatchers": [ + { + "name": "rustc", + "owner": "rustc", + "source": "rustc", + "fileLocation": [ + "autoDetect", + "${workspaceRoot}" + ], + "pattern": "$rustc" + }, + { + "name": "rustc-json", + "owner": "rustc", + "source": "rustc", + "fileLocation": [ + "autoDetect", + "${workspaceRoot}" + ], + "pattern": "$rustc-json" + }, + { + "name": "rustc-watch", + "owner": "rustc", + "source": "rustc", + "fileLocation": [ + "autoDetect", + "${workspaceRoot}" + ], + "background": { + "beginsPattern": "^\\[Running\\b", + "endsPattern": "^\\[Finished running\\b" + }, + "pattern": "$rustc" + } + ], + "colors": [ + { + "id": "rust_analyzer.syntaxTreeBorder", + "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)", + "defaults": { + "dark": "#ffffff", + "light": "#b700ff", + "highContrast": "#b700ff" + } + } + ], + "semanticTokenTypes": [ + { + "id": "angle", + "description": "Style for < or >", + "superType": "punctuation" + }, + { + "id": "arithmetic", + "description": "Style for arithmetic operators", + "superType": "operator" + }, + { + "id": "attribute", + "description": "Style for attributes" + }, + { + "id": "attributeBracket", + "description": "Style for attribute invocation brackets, that is the `#[` and `]` tokens", + "superType": "punctuation" + }, + { + "id": "bitwise", + "description": "Style for bitwise operators", + "superType": "operator" + }, + { + "id": "boolean", + "description": "Style for boolean literals", + "superType": "keyword" + }, + { + "id": "brace", + "description": "Style for { or }", + "superType": "punctuation" + }, + { + "id": "bracket", + "description": "Style for [ or ]", + "superType": "punctuation" + }, + { + "id": "builtinAttribute", + "description": "Style for builtin attributes", + "superType": "attribute" + }, + { + "id": "builtinType", + "description": "Style for builtin types", + "superType": "type" + }, + { + "id": "character", + "description": "Style for character literals", + "superType": "string" + }, + { + "id": "colon", + "description": "Style for :", + "superType": "punctuation" + }, + { + "id": "comma", + "description": "Style for ,", + "superType": "punctuation" + }, + { + "id": "comparison", + "description": "Style for comparison operators", + "superType": "operator" + }, + { + "id": "constParameter", + "description": "Style for const generics" + }, + { + "id": "derive", + "description": "Style for derives", + "superType": "attribute" + }, + { + "id": "dot", + "description": "Style for .", + "superType": "punctuation" + }, + { + "id": "escapeSequence", + "description": "Style for char escapes in strings" + }, + { + "id": "formatSpecifier", + "description": "Style for {} placeholders in format strings" + }, + { + "id": "label", + "description": "Style for labels" + }, + { + "id": "lifetime", + "description": "Style for lifetimes" + }, + { + "id": "logical", + "description": "Style for logic operators", + "superType": "operator" + }, + { + "id": "macroBang", + "description": "Style for the ! token of macro calls", + "superType": "punctuation" + }, + { + "id": "operator", + "description": "Style for operators", + "superType": "punctuation" + }, + { + "id": "parenthesis", + "description": "Style for ( or )", + "superType": "punctuation" + }, + { + "id": "punctuation", + "description": "Style for generic punctuation" + }, + { + "id": "selfKeyword", + "description": "Style for the self keyword", + "superType": "keyword" + }, + { + "id": "selfTypeKeyword", + "description": "Style for the self type keyword", + "superType": "keyword" + }, + { + "id": "semicolon", + "description": "Style for ;", + "superType": "punctuation" + }, + { + "id": "typeAlias", + "description": "Style for type aliases", + "superType": "type" + }, + { + "id": "union", + "description": "Style for C-style untagged unions", + "superType": "type" + }, + { + "id": "unresolvedReference", + "description": "Style for names which can not be resolved due to compilation errors" + } + ], + "semanticTokenModifiers": [ + { + "id": "async", + "description": "Style for async functions and the `async` and `await` keywords" + }, + { + "id": "attribute", + "description": "Style for elements within attributes" + }, + { + "id": "callable", + "description": "Style for locals whose types implements one of the `Fn*` traits" + }, + { + "id": "constant", + "description": "Style for compile-time constants" + }, + { + "id": "consuming", + "description": "Style for locals that are being consumed when use in a function call" + }, + { + "id": "controlFlow", + "description": "Style for control-flow related tokens, this includes the `?` operator" + }, + { + "id": "crateRoot", + "description": "Style for names resolving to a crate root" + }, + { + "id": "injected", + "description": "Style for doc-string injected highlighting like rust source blocks in documentation" + }, + { + "id": "intraDocLink", + "description": "Style for intra doc links in doc-strings" + }, + { + "id": "library", + "description": "Style for items that are defined outside of the current crate" + }, + { + "id": "mutable", + "description": "Style for mutable locals and statics as well as functions taking `&mut self`" + }, + { + "id": "public", + "description": "Style for items that are from the current crate and are `pub`" + }, + { + "id": "reference", + "description": "Style for locals behind a reference and functions taking `self` by reference" + }, + { + "id": "trait", + "description": "Style for associated trait items" + }, + { + "id": "unsafe", + "description": "Style for unsafe operations, like unsafe function calls, as well as the `unsafe` token" + } + ], + "semanticTokenScopes": [ + { + "language": "rust", + "scopes": { + "attribute": [ + "meta.attribute.rust" + ], + "boolean": [ + "constant.language.boolean.rust" + ], + "builtinType": [ + "support.type.primitive.rust" + ], + "constParameter": [ + "constant.other.caps.rust" + ], + "enum": [ + "entity.name.type.enum.rust" + ], + "formatSpecifier": [ + "punctuation.section.embedded.rust" + ], + "function": [ + "entity.name.function.rust" + ], + "interface": [ + "entity.name.type.trait.rust" + ], + "keyword": [ + "keyword.other.rust" + ], + "keyword.controlFlow": [ + "keyword.control.rust" + ], + "lifetime": [ + "storage.modifier.lifetime.rust" + ], + "macroBang": [ + "entity.name.function.macro.rust" + ], + "method": [ + "entity.name.function.rust" + ], + "struct": [ + "entity.name.type.struct.rust" + ], + "typeAlias": [ + "entity.name.type.declaration.rust" + ], + "union": [ + "entity.name.type.union.rust" + ], + "variable": [ + "variable.other.rust" + ], + "variable.constant": [ + "variable.other.constant.rust" + ], + "*.mutable": [ + "markup.underline" + ] + } + } + ], + "menus": { + "commandPalette": [ + { + "command": "rust-analyzer.syntaxTree", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.viewHir", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.viewFileText", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.expandMacro", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.matchingBrace", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.parentModule", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.joinLines", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.run", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.debug", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.newDebugConfig", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.analyzerStatus", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.memoryUsage", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.reloadWorkspace", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.reload", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.onEnter", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.ssr", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.serverVersion", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.toggleInlayHints", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.openDocs", + "when": "inRustProject" + }, + { + "command": "rust-analyzer.openCargoToml", + "when": "inRustProject" + } + ], + "editor/context": [ + { + "command": "rust-analyzer.peekTests", + "when": "inRustProject", + "group": "navigation@1000" + } + ] + } + } +} diff --git a/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json b/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json new file mode 100644 index 00000000000..279e7bafa0b --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/ra_syntax_tree.tmGrammar.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + + "scopeName": "source.ra_syntax_tree", + "patterns": [ + { "include": "#node_type" }, + { "include": "#node_range_index" }, + { "include": "#token_text" } + ], + "repository": { + "node_type": { + "match": "^\\s*([A-Z_][A-Z_0-9]*?)@", + "captures": { + "1": { + "name": "entity.name.class" + } + } + }, + "node_range_index": { + "match": "\\d+", + "name": "constant.numeric" + }, + "token_text": { + "match": "\".+\"", + "name": "string" + } + }, + "fileTypes": ["rast"] +} diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts new file mode 100644 index 00000000000..e57fb20e2cf --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts @@ -0,0 +1,215 @@ +import * as vscode from "vscode"; + +import { Ctx, Disposable } from "./ctx"; +import { RustEditor, isRustEditor } from "./util"; + +// FIXME: consider implementing this via the Tree View API? +// https://code.visualstudio.com/api/extension-guides/tree-view +export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { + private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ + borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"), + borderStyle: "solid", + borderWidth: "2px", + }); + private rustEditor: undefined | RustEditor; + + // Lazy rust token range -> syntax tree file range. + private readonly rust2Ast = new Lazy(() => { + const astEditor = this.findAstTextEditor(); + if (!this.rustEditor || !astEditor) return undefined; + + const buf: [vscode.Range, vscode.Range][] = []; + for (let i = 0; i < astEditor.document.lineCount; ++i) { + const astLine = astEditor.document.lineAt(i); + + // Heuristically look for nodes with quoted text (which are token nodes) + const isTokenNode = astLine.text.lastIndexOf('"') >= 0; + if (!isTokenNode) continue; + + const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text); + if (!rustRange) continue; + + buf.push([rustRange, this.findAstNodeRange(astLine)]); + } + return buf; + }); + + constructor(ctx: Ctx) { + ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this)); + ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); + vscode.workspace.onDidCloseTextDocument( + this.onDidCloseTextDocument, + this, + ctx.subscriptions + ); + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeVisibleTextEditors( + this.onDidChangeVisibleTextEditors, + this, + ctx.subscriptions + ); + + ctx.pushCleanup(this); + } + dispose() { + this.setRustEditor(undefined); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if ( + this.rustEditor && + event.document.uri.toString() === this.rustEditor.document.uri.toString() + ) { + this.rust2Ast.reset(); + } + } + + private onDidCloseTextDocument(doc: vscode.TextDocument) { + if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) { + this.setRustEditor(undefined); + } + } + + private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) { + if (!this.findAstTextEditor()) { + this.setRustEditor(undefined); + return; + } + this.setRustEditor(editors.find(isRustEditor)); + } + + private findAstTextEditor(): undefined | vscode.TextEditor { + return vscode.window.visibleTextEditors.find( + (it) => it.document.uri.scheme === "rust-analyzer" + ); + } + + private setRustEditor(newRustEditor: undefined | RustEditor) { + if (this.rustEditor && this.rustEditor !== newRustEditor) { + this.rustEditor.setDecorations(this.astDecorationType, []); + this.rust2Ast.reset(); + } + this.rustEditor = newRustEditor; + } + + // additional positional params are omitted + provideDefinition( + doc: vscode.TextDocument, + pos: vscode.Position + ): vscode.ProviderResult<vscode.DefinitionLink[]> { + if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) { + return; + } + + const astEditor = this.findAstTextEditor(); + if (!astEditor) return; + + const rust2AstRanges = this.rust2Ast + .get() + ?.find(([rustRange, _]) => rustRange.contains(pos)); + if (!rust2AstRanges) return; + + const [rustFileRange, astFileRange] = rust2AstRanges; + + astEditor.revealRange(astFileRange); + astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end); + + return [ + { + targetRange: astFileRange, + targetUri: astEditor.document.uri, + originSelectionRange: rustFileRange, + targetSelectionRange: astFileRange, + }, + ]; + } + + // additional positional params are omitted + provideHover( + doc: vscode.TextDocument, + hoverPosition: vscode.Position + ): vscode.ProviderResult<vscode.Hover> { + if (!this.rustEditor) return; + + const astFileLine = doc.lineAt(hoverPosition.line); + + const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text); + if (!rustFileRange) return; + + this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]); + this.rustEditor.revealRange(rustFileRange); + + const rustSourceCode = this.rustEditor.document.getText(rustFileRange); + const astFileRange = this.findAstNodeRange(astFileLine); + + return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange); + } + + private findAstNodeRange(astLine: vscode.TextLine): vscode.Range { + const lineOffset = astLine.range.start; + const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex); + const end = lineOffset.translate(undefined, astLine.text.trimEnd().length); + return new vscode.Range(begin, end); + } + + private parseRustTextRange( + doc: vscode.TextDocument, + astLine: string + ): undefined | vscode.Range { + const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine); + if (!parsedRange) return; + + const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off)); + + return new vscode.Range(begin, end); + } + + // Memoize the last value, otherwise the CPU is at 100% single core + // with quadratic lookups when we build rust2Ast cache + cache?: { doc: vscode.TextDocument; offset: number; line: number }; + + positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position { + if (doc.eol === vscode.EndOfLine.LF) { + return doc.positionAt(targetOffset); + } + + // Dirty workaround for crlf line endings + // We are still in this prehistoric era of carriage returns here... + + let line = 0; + let offset = 0; + + const cache = this.cache; + if (cache?.doc === doc && cache.offset <= targetOffset) { + ({ line, offset } = cache); + } + + while (true) { + const lineLenWithLf = doc.lineAt(line).text.length + 1; + if (offset + lineLenWithLf > targetOffset) { + this.cache = { doc, offset, line }; + return doc.positionAt(targetOffset + line); + } + offset += lineLenWithLf; + line += 1; + } + } +} + +class Lazy<T> { + val: undefined | T; + + constructor(private readonly compute: () => undefined | T) {} + + get() { + return this.val ?? (this.val = this.compute()); + } + + reset() { + this.val = undefined; + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts new file mode 100644 index 00000000000..8a2dea6b35b --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -0,0 +1,299 @@ +import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; +import * as ra from "../src/lsp_ext"; +import * as Is from "vscode-languageclient/lib/common/utils/is"; +import { assert } from "./util"; +import { WorkspaceEdit } from "vscode"; +import { Workspace } from "./ctx"; +import { updateConfig } from "./config"; +import { substituteVariablesInEnv } from "./config"; +import { outputChannel, traceOutputChannel } from "./main"; +import { randomUUID } from "crypto"; + +export interface Env { + [name: string]: string; +} + +// Command URIs have a form of command:command-name?arguments, where +// arguments is a percent-encoded array of data we want to pass along to +// the command function. For "Show References" this is a list of all file +// URIs with locations of every reference, and it can get quite long. +// +// To work around it we use an intermediary linkToCommand command. When +// we render a command link, a reference to a command with all its arguments +// is stored in a map, and instead a linkToCommand link is rendered +// with the key to that map. +export const LINKED_COMMANDS = new Map<string, ra.CommandLink>(); + +// For now the map is cleaned up periodically (I've set it to every +// 10 minutes). In general case we'll probably need to introduce TTLs or +// flags to denote ephemeral links (like these in hover popups) and +// persistent links and clean those separately. But for now simply keeping +// the last few links in the map should be good enough. Likewise, we could +// add code to remove a target command from the map after the link is +// clicked, but assuming most links in hover sheets won't be clicked anyway +// this code won't change the overall memory use much. +setInterval(function cleanupOlderCommandLinks() { + // keys are returned in insertion order, we'll keep a few + // of recent keys available, and clean the rest + const keys = [...LINKED_COMMANDS.keys()]; + const keysToRemove = keys.slice(0, keys.length - 10); + for (const key of keysToRemove) { + LINKED_COMMANDS.delete(key); + } +}, 10 * 60 * 1000); + +function renderCommand(cmd: ra.CommandLink): string { + const commandId = randomUUID(); + LINKED_COMMANDS.set(commandId, cmd); + return `[${cmd.title}](command:rust-analyzer.linkToCommand?${encodeURIComponent( + JSON.stringify([commandId]) + )} '${cmd.tooltip}')`; +} + +function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString { + const text = actions + .map( + (group) => + (group.title ? group.title + " " : "") + + group.commands.map(renderCommand).join(" | ") + ) + .join("___"); + + const result = new vscode.MarkdownString(text); + result.isTrusted = true; + return result; +} + +export async function createClient( + serverPath: string, + workspace: Workspace, + extraEnv: Env +): Promise<lc.LanguageClient> { + // '.' Is the fallback if no folder is open + // TODO?: Workspace folders support Uri's (eg: file://test.txt). + // It might be a good idea to test if the uri points to a file. + + const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv)); + const run: lc.Executable = { + command: serverPath, + options: { env: newEnv }, + }; + const serverOptions: lc.ServerOptions = { + run, + debug: run, + }; + + let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer"); + + // Update outdated user configs + await updateConfig(initializationOptions).catch((err) => { + void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`); + }); + + if (workspace.kind === "Detached Files") { + initializationOptions = { + detachedFiles: workspace.files.map((file) => file.uri.fsPath), + ...initializationOptions, + }; + } + + const clientOptions: lc.LanguageClientOptions = { + documentSelector: [{ scheme: "file", language: "rust" }], + initializationOptions, + diagnosticCollectionName: "rustc", + traceOutputChannel: traceOutputChannel(), + outputChannel: outputChannel(), + middleware: { + async provideHover( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + _next: lc.ProvideHoverSignature + ) { + const editor = vscode.window.activeTextEditor; + const positionOrRange = editor?.selection?.contains(position) + ? client.code2ProtocolConverter.asRange(editor.selection) + : client.code2ProtocolConverter.asPosition(position); + return client + .sendRequest( + ra.hover, + { + textDocument: + client.code2ProtocolConverter.asTextDocumentIdentifier(document), + position: positionOrRange, + }, + token + ) + .then( + (result) => { + const hover = client.protocol2CodeConverter.asHover(result); + if (hover) { + const actions = (<any>result).actions; + if (actions) { + hover.contents.push(renderHoverActions(actions)); + } + } + return hover; + }, + (error) => { + client.handleFailedRequest(lc.HoverRequest.type, token, error, null); + return Promise.resolve(null); + } + ); + }, + // Using custom handling of CodeActions to support action groups and snippet edits. + // Note that this means we have to re-implement lazy edit resolving ourselves as well. + async provideCodeActions( + document: vscode.TextDocument, + range: vscode.Range, + context: vscode.CodeActionContext, + token: vscode.CancellationToken, + _next: lc.ProvideCodeActionsSignature + ) { + const params: lc.CodeActionParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + range: client.code2ProtocolConverter.asRange(range), + context: await client.code2ProtocolConverter.asCodeActionContext( + context, + token + ), + }; + return client.sendRequest(lc.CodeActionRequest.type, params, token).then( + async (values) => { + if (values === null) return undefined; + const result: (vscode.CodeAction | vscode.Command)[] = []; + const groups = new Map< + string, + { index: number; items: vscode.CodeAction[] } + >(); + for (const item of values) { + // In our case we expect to get code edits only from diagnostics + if (lc.CodeAction.is(item)) { + assert( + !item.command, + "We don't expect to receive commands in CodeActions" + ); + const action = await client.protocol2CodeConverter.asCodeAction( + item, + token + ); + result.push(action); + continue; + } + assert( + isCodeActionWithoutEditsAndCommands(item), + "We don't expect edits or commands here" + ); + const kind = client.protocol2CodeConverter.asCodeActionKind( + (item as any).kind + ); + const action = new vscode.CodeAction(item.title, kind); + const group = (item as any).group; + action.command = { + command: "rust-analyzer.resolveCodeAction", + title: item.title, + arguments: [item], + }; + + // Set a dummy edit, so that VS Code doesn't try to resolve this. + action.edit = new WorkspaceEdit(); + + if (group) { + let entry = groups.get(group); + if (!entry) { + entry = { index: result.length, items: [] }; + groups.set(group, entry); + result.push(action); + } + entry.items.push(action); + } else { + result.push(action); + } + } + for (const [group, { index, items }] of groups) { + if (items.length === 1) { + result[index] = items[0]; + } else { + const action = new vscode.CodeAction(group); + action.kind = items[0].kind; + action.command = { + command: "rust-analyzer.applyActionGroup", + title: "", + arguments: [ + items.map((item) => { + return { + label: item.title, + arguments: item.command!.arguments![0], + }; + }), + ], + }; + + // Set a dummy edit, so that VS Code doesn't try to resolve this. + action.edit = new WorkspaceEdit(); + + result[index] = action; + } + } + return result; + }, + (_error) => undefined + ); + }, + }, + markdown: { + supportHtml: true, + }, + }; + + const client = new lc.LanguageClient( + "rust-analyzer", + "Rust Analyzer Language Server", + serverOptions, + clientOptions + ); + + // To turn on all proposed features use: client.registerProposedFeatures(); + client.registerFeature(new ExperimentalFeatures()); + + return client; +} + +class ExperimentalFeatures implements lc.StaticFeature { + fillClientCapabilities(capabilities: lc.ClientCapabilities): void { + const caps: any = capabilities.experimental ?? {}; + caps.snippetTextEdit = true; + caps.codeActionGroup = true; + caps.hoverActions = true; + caps.serverStatusNotification = true; + caps.commands = { + commands: [ + "rust-analyzer.runSingle", + "rust-analyzer.debugSingle", + "rust-analyzer.showReferences", + "rust-analyzer.gotoLocation", + "editor.action.triggerParameterHints", + ], + }; + capabilities.experimental = caps; + } + initialize( + _capabilities: lc.ServerCapabilities<any>, + _documentSelector: lc.DocumentSelector | undefined + ): void {} + dispose(): void {} +} + +function isCodeActionWithoutEditsAndCommands(value: any): boolean { + const candidate: lc.CodeAction = value; + return ( + candidate && + Is.string(candidate.title) && + (candidate.diagnostics === void 0 || + Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && + (candidate.kind === void 0 || Is.string(candidate.kind)) && + candidate.edit === void 0 && + candidate.command === void 0 + ); +} diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts new file mode 100644 index 00000000000..bf55329ca1f --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -0,0 +1,952 @@ +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient"; +import * as ra from "./lsp_ext"; +import * as path from "path"; + +import { Ctx, Cmd } from "./ctx"; +import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; +import { spawnSync } from "child_process"; +import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; +import { AstInspector } from "./ast_inspector"; +import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util"; +import { startDebugSession, makeDebugConfig } from "./debug"; +import { LanguageClient } from "vscode-languageclient/node"; +import { LINKED_COMMANDS } from "./client"; + +export * from "./ast_inspector"; +export * from "./run"; + +export function analyzerStatus(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-status://status"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + + provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> { + if (!vscode.window.activeTextEditor) return ""; + + const params: ra.AnalyzerStatusParams = {}; + const doc = ctx.activeRustEditor?.document; + if (doc != null) { + params.textDocument = + ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc); + } + return ctx.client.sendRequest(ra.analyzerStatus, params); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp) + ); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + void (await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + })); + }; +} + +export function memoryUsage(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + + provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> { + if (!vscode.window.activeTextEditor) return ""; + + return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => { + return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"; + }); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp) + ); + + return async () => { + tdcp.eventEmitter.fire(tdcp.uri); + const document = await vscode.workspace.openTextDocument(tdcp.uri); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); + }; +} + +export function shuffleCrateGraph(ctx: Ctx): Cmd { + return async () => { + const client = ctx.client; + if (!client) return; + + await client.sendRequest(ra.shuffleCrateGraph); + }; +} + +export function matchingBrace(ctx: Ctx): Cmd { + return async () => { + const editor = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const response = await client.sendRequest(ra.matchingBrace, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + positions: editor.selections.map((s) => + client.code2ProtocolConverter.asPosition(s.active) + ), + }); + editor.selections = editor.selections.map((sel, idx) => { + const active = client.protocol2CodeConverter.asPosition(response[idx]); + const anchor = sel.isEmpty ? active : sel.anchor; + return new vscode.Selection(anchor, active); + }); + editor.revealRange(editor.selection); + }; +} + +export function joinLines(ctx: Ctx): Cmd { + return async () => { + const editor = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, { + ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + }); + const textEdits = await client.protocol2CodeConverter.asTextEdits(items); + await editor.edit((builder) => { + textEdits.forEach((edit: any) => { + builder.replace(edit.range, edit.newText); + }); + }); + }; +} + +export function moveItemUp(ctx: Ctx): Cmd { + return moveItem(ctx, ra.Direction.Up); +} + +export function moveItemDown(ctx: Ctx): Cmd { + return moveItem(ctx, ra.Direction.Down); +} + +export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd { + return async () => { + const editor = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const lcEdits = await client.sendRequest(ra.moveItem, { + range: client.code2ProtocolConverter.asRange(editor.selection), + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + direction, + }); + + if (!lcEdits) return; + + const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits); + await applySnippetTextEdits(editor, edits); + }; +} + +export function onEnter(ctx: Ctx): Cmd { + async function handleKeypress() { + const editor = ctx.activeRustEditor; + const client = ctx.client; + + if (!editor || !client) return false; + + const lcEdits = await client + .sendRequest(ra.onEnter, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }) + .catch((_error: any) => { + // client.handleFailedRequest(OnEnterRequest.type, error, null); + return null; + }); + if (!lcEdits) return false; + + const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits); + await applySnippetTextEdits(editor, edits); + return true; + } + + return async () => { + if (await handleKeypress()) return; + + await vscode.commands.executeCommand("default:type", { text: "\n" }); + }; +} + +export function parentModule(ctx: Ctx): Cmd { + return async () => { + const editor = vscode.window.activeTextEditor; + const client = ctx.client; + if (!editor || !client) return; + if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return; + + const locations = await client.sendRequest(ra.parentModule, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }); + if (!locations) return; + + if (locations.length === 1) { + const loc = locations[0]; + + const uri = client.protocol2CodeConverter.asUri(loc.targetUri); + const range = client.protocol2CodeConverter.asRange(loc.targetRange); + + const doc = await vscode.workspace.openTextDocument(uri); + const e = await vscode.window.showTextDocument(doc); + e.selection = new vscode.Selection(range.start, range.start); + e.revealRange(range, vscode.TextEditorRevealType.InCenter); + } else { + const uri = editor.document.uri.toString(); + const position = client.code2ProtocolConverter.asPosition(editor.selection.active); + await showReferencesImpl( + client, + uri, + position, + locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange)) + ); + } + }; +} + +export function openCargoToml(ctx: Ctx): Cmd { + return async () => { + const editor = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const response = await client.sendRequest(ra.openCargoToml, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + }); + if (!response) return; + + const uri = client.protocol2CodeConverter.asUri(response.uri); + const range = client.protocol2CodeConverter.asRange(response.range); + + const doc = await vscode.workspace.openTextDocument(uri); + const e = await vscode.window.showTextDocument(doc); + e.selection = new vscode.Selection(range.start, range.start); + e.revealRange(range, vscode.TextEditorRevealType.InCenter); + }; +} + +export function ssr(ctx: Ctx): Cmd { + return async () => { + const editor = vscode.window.activeTextEditor; + const client = ctx.client; + if (!editor || !client) return; + + const position = editor.selection.active; + const selections = editor.selections; + const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ); + + const options: vscode.InputBoxOptions = { + value: "() ==>> ()", + prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ", + validateInput: async (x: string) => { + try { + await client.sendRequest(ra.ssr, { + query: x, + parseOnly: true, + textDocument, + position, + selections, + }); + } catch (e) { + return e.toString(); + } + return null; + }, + }; + const request = await vscode.window.showInputBox(options); + if (!request) return; + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Structured search replace in progress...", + cancellable: false, + }, + async (_progress, token) => { + const edit = await client.sendRequest(ra.ssr, { + query: request, + parseOnly: false, + textDocument, + position, + selections, + }); + + await vscode.workspace.applyEdit( + await client.protocol2CodeConverter.asWorkspaceEdit(edit, token) + ); + } + ); + }; +} + +export function serverVersion(ctx: Ctx): Cmd { + return async () => { + const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" }); + const versionString = stdout.slice(`rust-analyzer `.length).trim(); + + void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`); + }; +} + +export function toggleInlayHints(_ctx: Ctx): Cmd { + return async () => { + const config = vscode.workspace.getConfiguration("editor.inlayHints", { + languageId: "rust", + }); + const value = !config.get("enabled"); + await config.update("enabled", value, vscode.ConfigurationTarget.Global); + }; +} + +// Opens the virtual file that will show the syntax tree +// +// The contents of the file come from the `TextDocumentContentProvider` +export function syntaxTree(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + constructor() { + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent( + uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult<string> { + const rustEditor = ctx.activeRustEditor; + if (!rustEditor) return ""; + + // When the range based query is enabled we take the range of the selection + const range = + uri.query === "range=true" && !rustEditor.selection.isEmpty + ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) + : null; + + const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range }; + return ctx.client.sendRequest(ra.syntaxTree, params, ct); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + void new AstInspector(ctx); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp) + ); + ctx.pushCleanup( + vscode.languages.setLanguageConfiguration("ra_syntax_tree", { + brackets: [["[", ")"]], + }) + ); + + return async () => { + const editor = vscode.window.activeTextEditor; + const rangeEnabled = !!editor && !editor.selection.isEmpty; + + const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri; + + const document = await vscode.workspace.openTextDocument(uri); + + tdcp.eventEmitter.fire(uri); + + void (await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + })); + }; +} + +// Opens the virtual file that will show the HIR of the function containing the cursor position +// +// The contents of the file come from the `TextDocumentContentProvider` +export function viewHir(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + constructor() { + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult<string> { + const rustEditor = ctx.activeRustEditor; + const client = ctx.client; + if (!rustEditor || !client) return ""; + + const params = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document + ), + position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active), + }; + return client.sendRequest(ra.viewHir, params, ct); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp) + ); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + void (await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + })); + }; +} + +export function viewFileText(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + constructor() { + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult<string> { + const rustEditor = ctx.activeRustEditor; + const client = ctx.client; + if (!rustEditor || !client) return ""; + + const params = client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document + ); + return client.sendRequest(ra.viewFileText, params, ct); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp) + ); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + void (await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + })); + }; +} + +export function viewItemTree(ctx: Ctx): Cmd { + const tdcp = new (class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs"); + readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + constructor() { + vscode.workspace.onDidChangeTextDocument( + this.onDidChangeTextDocument, + this, + ctx.subscriptions + ); + vscode.window.onDidChangeActiveTextEditor( + this.onDidChangeActiveTextEditor, + this, + ctx.subscriptions + ); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent( + _uri: vscode.Uri, + ct: vscode.CancellationToken + ): vscode.ProviderResult<string> { + const rustEditor = ctx.activeRustEditor; + const client = ctx.client; + if (!rustEditor || !client) return ""; + + const params = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( + rustEditor.document + ), + }; + return client.sendRequest(ra.viewItemTree, params, ct); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp) + ); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + void (await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true, + })); + }; +} + +function crateGraph(ctx: Ctx, full: boolean): Cmd { + return async () => { + const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules")); + + const panel = vscode.window.createWebviewPanel( + "rust-analyzer.crate-graph", + "rust-analyzer crate graph", + vscode.ViewColumn.Two, + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [nodeModulesPath], + } + ); + const params = { + full: full, + }; + + const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params); + const uri = panel.webview.asWebviewUri(nodeModulesPath); + + const html = ` + <!DOCTYPE html> + <meta charset="utf-8"> + <head> + <style> + /* Fill the entire view */ + html, body { margin:0; padding:0; overflow:hidden } + svg { position:fixed; top:0; left:0; height:100%; width:100% } + + /* Disable the graphviz backgroud and fill the polygons */ + .graph > polygon { display:none; } + :is(.node,.edge) polygon { fill: white; } + + /* Invert the line colours for dark themes */ + body:not(.vscode-light) .edge path { stroke: white; } + </style> + </head> + <body> + <script type="text/javascript" src="${uri}/d3/dist/d3.min.js"></script> + <script type="text/javascript" src="${uri}/@hpcc-js/wasm/dist/index.min.js"></script> + <script type="text/javascript" src="${uri}/d3-graphviz/build/d3-graphviz.min.js"></script> + <div id="graph"></div> + <script> + let graph = d3.select("#graph") + .graphviz() + .fit(true) + .zoomScaleExtent([0.1, Infinity]) + .renderDot(\`${dot}\`); + + d3.select(window).on("click", (event) => { + if (event.ctrlKey) { + graph.resetZoom(d3.transition().duration(100)); + } + }); + </script> + </body> + `; + + panel.webview.html = html; + }; +} + +export function viewCrateGraph(ctx: Ctx): Cmd { + return crateGraph(ctx, false); +} + +export function viewFullCrateGraph(ctx: Ctx): Cmd { + return crateGraph(ctx, true); +} + +// Opens the virtual file that will show the syntax tree +// +// The contents of the file come from the `TextDocumentContentProvider` +export function expandMacro(ctx: Ctx): Cmd { + function codeFormat(expanded: ra.ExpandedMacro): string { + let result = `// Recursive expansion of ${expanded.name}! macro\n`; + result += "// " + "=".repeat(result.length - 3); + result += "\n\n"; + result += expanded.expansion; + + return result; + } + + const tdcp = new (class implements vscode.TextDocumentContentProvider { + uri = vscode.Uri.parse("rust-analyzer-expand-macro://expandMacro/[EXPANSION].rs"); + eventEmitter = new vscode.EventEmitter<vscode.Uri>(); + async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> { + const editor = vscode.window.activeTextEditor; + const client = ctx.client; + if (!editor || !client) return ""; + + const position = editor.selection.active; + + const expanded = await client.sendRequest(ra.expandMacro, { + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + position, + }); + + if (expanded == null) return "Not available"; + + return codeFormat(expanded); + } + + get onDidChange(): vscode.Event<vscode.Uri> { + return this.eventEmitter.event; + } + })(); + + ctx.pushCleanup( + vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp) + ); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); + }; +} + +export function reloadWorkspace(ctx: Ctx): Cmd { + return async () => ctx.client.sendRequest(ra.reloadWorkspace); +} + +async function showReferencesImpl( + client: LanguageClient, + uri: string, + position: lc.Position, + locations: lc.Location[] +) { + if (client) { + await vscode.commands.executeCommand( + "editor.action.showReferences", + vscode.Uri.parse(uri), + client.protocol2CodeConverter.asPosition(position), + locations.map(client.protocol2CodeConverter.asLocation) + ); + } +} + +export function showReferences(ctx: Ctx): Cmd { + return async (uri: string, position: lc.Position, locations: lc.Location[]) => { + await showReferencesImpl(ctx.client, uri, position, locations); + }; +} + +export function applyActionGroup(_ctx: Ctx): Cmd { + return async (actions: { label: string; arguments: lc.CodeAction }[]) => { + const selectedAction = await vscode.window.showQuickPick(actions); + if (!selectedAction) return; + await vscode.commands.executeCommand( + "rust-analyzer.resolveCodeAction", + selectedAction.arguments + ); + }; +} + +export function gotoLocation(ctx: Ctx): Cmd { + return async (locationLink: lc.LocationLink) => { + const client = ctx.client; + if (client) { + const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri); + let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange); + // collapse the range to a cursor position + range = range.with({ end: range.start }); + + await vscode.window.showTextDocument(uri, { selection: range }); + } + }; +} + +export function openDocs(ctx: Ctx): Cmd { + return async () => { + const client = ctx.client; + const editor = vscode.window.activeTextEditor; + if (!editor || !client) { + return; + } + + const position = editor.selection.active; + const textDocument = { uri: editor.document.uri.toString() }; + + const doclink = await client.sendRequest(ra.openDocs, { position, textDocument }); + + if (doclink != null) { + await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink)); + } + }; +} + +export function resolveCodeAction(ctx: Ctx): Cmd { + const client = ctx.client; + return async (params: lc.CodeAction) => { + params.command = undefined; + const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params); + if (!item.edit) { + return; + } + const itemEdit = item.edit; + const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit); + // filter out all text edits and recreate the WorkspaceEdit without them so we can apply + // snippet edits on our own + const lcFileSystemEdit = { + ...itemEdit, + documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change), + }; + const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit( + lcFileSystemEdit + ); + await vscode.workspace.applyEdit(fileSystemEdit); + await applySnippetWorkspaceEdit(edit); + if (item.command != null) { + await vscode.commands.executeCommand(item.command.command, item.command.arguments); + } + }; +} + +export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd { + return async (edit: vscode.WorkspaceEdit) => { + await applySnippetWorkspaceEdit(edit); + }; +} + +export function run(ctx: Ctx): Cmd { + let prevRunnable: RunnableQuickPick | undefined; + + return async () => { + const item = await selectRunnable(ctx, prevRunnable); + if (!item) return; + + item.detail = "rerun"; + prevRunnable = item; + const task = await createTask(item.runnable, ctx.config); + return await vscode.tasks.executeTask(task); + }; +} + +export function peekTests(ctx: Ctx): Cmd { + const client = ctx.client; + + return async () => { + const editor = ctx.activeRustEditor; + if (!editor || !client) return; + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Looking for tests...", + cancellable: false, + }, + async (_progress, _token) => { + const uri = editor.document.uri.toString(); + const position = client.code2ProtocolConverter.asPosition(editor.selection.active); + + const tests = await client.sendRequest(ra.relatedTests, { + textDocument: { uri: uri }, + position: position, + }); + const locations: lc.Location[] = tests.map((it) => + lc.Location.create( + it.runnable.location!.targetUri, + it.runnable.location!.targetSelectionRange + ) + ); + + await showReferencesImpl(client, uri, position, locations); + } + ); + }; +} + +export function runSingle(ctx: Ctx): Cmd { + return async (runnable: ra.Runnable) => { + const editor = ctx.activeRustEditor; + if (!editor) return; + + const task = await createTask(runnable, ctx.config); + task.group = vscode.TaskGroup.Build; + task.presentationOptions = { + reveal: vscode.TaskRevealKind.Always, + panel: vscode.TaskPanelKind.Dedicated, + clear: true, + }; + + return vscode.tasks.executeTask(task); + }; +} + +export function copyRunCommandLine(ctx: Ctx) { + let prevRunnable: RunnableQuickPick | undefined; + return async () => { + const item = await selectRunnable(ctx, prevRunnable); + if (!item) return; + const args = createArgs(item.runnable); + const commandLine = ["cargo", ...args].join(" "); + await vscode.env.clipboard.writeText(commandLine); + await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard."); + }; +} + +export function debug(ctx: Ctx): Cmd { + let prevDebuggee: RunnableQuickPick | undefined; + + return async () => { + const item = await selectRunnable(ctx, prevDebuggee, true); + if (!item) return; + + item.detail = "restart"; + prevDebuggee = item; + return await startDebugSession(ctx, item.runnable); + }; +} + +export function debugSingle(ctx: Ctx): Cmd { + return async (config: ra.Runnable) => { + await startDebugSession(ctx, config); + }; +} + +export function newDebugConfig(ctx: Ctx): Cmd { + return async () => { + const item = await selectRunnable(ctx, undefined, true, false); + if (!item) return; + + await makeDebugConfig(ctx, item.runnable); + }; +} + +export function linkToCommand(ctx: Ctx): Cmd { + return async (commandId: string) => { + const link = LINKED_COMMANDS.get(commandId); + if (ctx.client && link) { + const { command, arguments: args = [] } = link; + await vscode.commands.executeCommand(command, ...args); + } + }; +} diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts new file mode 100644 index 00000000000..b04f18890b9 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -0,0 +1,394 @@ +import path = require("path"); +import * as vscode from "vscode"; +import { Env } from "./client"; +import { log } from "./util"; + +export type UpdatesChannel = "stable" | "nightly"; + +const NIGHTLY_TAG = "nightly"; + +export type RunnableEnvCfg = + | undefined + | Record<string, string> + | { mask?: string; env: Record<string, string> }[]; + +export class Config { + readonly extensionId = "rust-lang.rust-analyzer"; + + readonly rootSection = "rust-analyzer"; + private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map( + (opt) => `${this.rootSection}.${opt}` + ); + private readonly requiresReloadOpts = [ + "cargo", + "procMacro", + "files", + "lens", // works as lens.* + ] + .map((opt) => `${this.rootSection}.${opt}`) + .concat(this.requiresWorkspaceReloadOpts); + + readonly package: { + version: string; + releaseTag: string | null; + enableProposedApi: boolean | undefined; + } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; + + readonly globalStorageUri: vscode.Uri; + + constructor(ctx: vscode.ExtensionContext) { + this.globalStorageUri = ctx.globalStorageUri; + vscode.workspace.onDidChangeConfiguration( + this.onDidChangeConfiguration, + this, + ctx.subscriptions + ); + this.refreshLogging(); + } + + private refreshLogging() { + log.setEnabled(this.traceExtension); + log.info("Extension version:", this.package.version); + + const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function)); + log.info("Using configuration", Object.fromEntries(cfg)); + } + + private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { + this.refreshLogging(); + + const requiresReloadOpt = this.requiresReloadOpts.find((opt) => + event.affectsConfiguration(opt) + ); + + if (!requiresReloadOpt) return; + + const requiresWorkspaceReloadOpt = this.requiresWorkspaceReloadOpts.find((opt) => + event.affectsConfiguration(opt) + ); + + if (!requiresWorkspaceReloadOpt && this.restartServerOnConfigChange) { + await vscode.commands.executeCommand("rust-analyzer.reload"); + return; + } + + const message = requiresWorkspaceReloadOpt + ? `Changing "${requiresWorkspaceReloadOpt}" requires a window reload` + : `Changing "${requiresReloadOpt}" requires a reload`; + const userResponse = await vscode.window.showInformationMessage(message, "Reload now"); + + if (userResponse === "Reload now") { + const command = requiresWorkspaceReloadOpt + ? "workbench.action.reloadWindow" + : "rust-analyzer.reload"; + if (userResponse === "Reload now") { + await vscode.commands.executeCommand(command); + } + } + } + + // We don't do runtime config validation here for simplicity. More on stackoverflow: + // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension + + private get cfg(): vscode.WorkspaceConfiguration { + return vscode.workspace.getConfiguration(this.rootSection); + } + + /** + * Beware that postfix `!` operator erases both `null` and `undefined`. + * This is why the following doesn't work as expected: + * + * ```ts + * const nullableNum = vscode + * .workspace + * .getConfiguration + * .getConfiguration("rust-analyzer") + * .get<number | null>(path)!; + * + * // What happens is that type of `nullableNum` is `number` but not `null | number`: + * const fullFledgedNum: number = nullableNum; + * ``` + * So this getter handles this quirk by not requiring the caller to use postfix `!` + */ + private get<T>(path: string): T { + return this.cfg.get<T>(path)!; + } + + get serverPath() { + return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath"); + } + get serverExtraEnv(): Env { + const extraEnv = + this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {}; + return Object.fromEntries( + Object.entries(extraEnv).map(([k, v]) => [k, typeof v !== "string" ? v.toString() : v]) + ); + } + get traceExtension() { + return this.get<boolean>("trace.extension"); + } + + get cargoRunner() { + return this.get<string | undefined>("cargoRunner"); + } + + get runnableEnv() { + return this.get<RunnableEnvCfg>("runnableEnv"); + } + + get restartServerOnConfigChange() { + return this.get<boolean>("restartServerOnConfigChange"); + } + + get debug() { + let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap"); + if (sourceFileMap !== "auto") { + // "/rustc/<id>" used by suggestions only. + const { ["/rustc/<id>"]: _, ...trimmed } = + this.get<Record<string, string>>("debug.sourceFileMap"); + sourceFileMap = trimmed; + } + + return { + engine: this.get<string>("debug.engine"), + engineSettings: this.get<object>("debug.engineSettings"), + openDebugPane: this.get<boolean>("debug.openDebugPane"), + sourceFileMap: sourceFileMap, + }; + } + + get hoverActions() { + return { + enable: this.get<boolean>("hover.actions.enable"), + implementations: this.get<boolean>("hover.actions.implementations.enable"), + references: this.get<boolean>("hover.actions.references.enable"), + run: this.get<boolean>("hover.actions.run.enable"), + debug: this.get<boolean>("hover.actions.debug.enable"), + gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"), + }; + } + + get currentExtensionIsNightly() { + return this.package.releaseTag === NIGHTLY_TAG; + } +} + +export async function updateConfig(config: vscode.WorkspaceConfiguration) { + const renames = [ + ["assist.allowMergingIntoGlobImports", "imports.merge.glob"], + ["assist.exprFillDefault", "assist.expressionFillDefault"], + ["assist.importEnforceGranularity", "imports.granularity.enforce"], + ["assist.importGranularity", "imports.granularity.group"], + ["assist.importMergeBehavior", "imports.granularity.group"], + ["assist.importMergeBehaviour", "imports.granularity.group"], + ["assist.importGroup", "imports.group.enable"], + ["assist.importPrefix", "imports.prefix"], + ["primeCaches.enable", "cachePriming.enable"], + ["cache.warmup", "cachePriming.enable"], + ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"], + ["cargo.runBuildScripts", "cargo.buildScripts.enable"], + ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"], + ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"], + ["completion.snippets", "completion.snippets.custom"], + ["diagnostics.enableExperimental", "diagnostics.experimental.enable"], + ["experimental.procAttrMacros", "procMacro.attributes.enable"], + ["highlighting.strings", "semanticHighlighting.strings.enable"], + ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"], + ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"], + ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"], + ["highlightRelated.references", "highlightRelated.references.enable"], + ["hover.documentation", "hover.documentation.enable"], + ["hover.linksInHover", "hover.links.enable"], + ["hoverActions.linksInHover", "hover.links.enable"], + ["hoverActions.debug", "hover.actions.debug.enable"], + ["hoverActions.enable", "hover.actions.enable.enable"], + ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"], + ["hoverActions.implementations", "hover.actions.implementations.enable"], + ["hoverActions.references", "hover.actions.references.enable"], + ["hoverActions.run", "hover.actions.run.enable"], + ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"], + ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"], + ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"], + ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"], + ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"], + ["inlayHints.typeHints", "inlayHints.typeHints.enable"], + ["lruCapacity", "lru.capacity"], + ["runnables.cargoExtraArgs", "runnables.extraArgs"], + ["runnables.overrideCargo", "runnables.command"], + ["rustcSource", "rustc.source"], + ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"], + ]; + + for (const [oldKey, newKey] of renames) { + const inspect = config.inspect(oldKey); + if (inspect !== undefined) { + const valMatrix = [ + { + val: inspect.globalValue, + langVal: inspect.globalLanguageValue, + target: vscode.ConfigurationTarget.Global, + }, + { + val: inspect.workspaceFolderValue, + langVal: inspect.workspaceFolderLanguageValue, + target: vscode.ConfigurationTarget.WorkspaceFolder, + }, + { + val: inspect.workspaceValue, + langVal: inspect.workspaceLanguageValue, + target: vscode.ConfigurationTarget.Workspace, + }, + ]; + for (const { val, langVal, target } of valMatrix) { + const patch = (val: unknown) => { + // some of the updates we do only append "enable" or "custom" + // that means on the next run we would find these again, but as objects with + // these properties causing us to destroy the config + // so filter those already updated ones out + return ( + val !== undefined && + !( + typeof val === "object" && + val !== null && + (oldKey === "completion.snippets" || !val.hasOwnProperty("custom")) + ) + ); + }; + if (patch(val)) { + await config.update(newKey, val, target, false); + await config.update(oldKey, undefined, target, false); + } + if (patch(langVal)) { + await config.update(newKey, langVal, target, true); + await config.update(oldKey, undefined, target, true); + } + } + } + } +} + +export function substituteVariablesInEnv(env: Env): Env { + const missingDeps = new Set<string>(); + // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier + // to follow the same convention for our dependency tracking + const definedEnvKeys = new Set(Object.keys(env).map((key) => `env:${key}`)); + const envWithDeps = Object.fromEntries( + Object.entries(env).map(([key, value]) => { + const deps = new Set<string>(); + const depRe = new RegExp(/\${(?<depName>.+?)}/g); + let match = undefined; + while ((match = depRe.exec(value))) { + const depName = match.groups!.depName; + deps.add(depName); + // `depName` at this point can have a form of `expression` or + // `prefix:expression` + if (!definedEnvKeys.has(depName)) { + missingDeps.add(depName); + } + } + return [`env:${key}`, { deps: [...deps], value }]; + }) + ); + + const resolved = new Set<string>(); + for (const dep of missingDeps) { + const match = /(?<prefix>.*?):(?<body>.+)/.exec(dep); + if (match) { + const { prefix, body } = match.groups!; + if (prefix === "env") { + const envName = body; + envWithDeps[dep] = { + value: process.env[envName] ?? "", + deps: [], + }; + resolved.add(dep); + } else { + // we can't handle other prefixes at the moment + // leave values as is, but still mark them as resolved + envWithDeps[dep] = { + value: "${" + dep + "}", + deps: [], + }; + resolved.add(dep); + } + } else { + envWithDeps[dep] = { + value: computeVscodeVar(dep), + deps: [], + }; + } + } + const toResolve = new Set(Object.keys(envWithDeps)); + + let leftToResolveSize; + do { + leftToResolveSize = toResolve.size; + for (const key of toResolve) { + if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) { + envWithDeps[key].value = envWithDeps[key].value.replace( + /\${(?<depName>.+?)}/g, + (_wholeMatch, depName) => { + return envWithDeps[depName].value; + } + ); + resolved.add(key); + toResolve.delete(key); + } + } + } while (toResolve.size > 0 && toResolve.size < leftToResolveSize); + + const resolvedEnv: Env = {}; + for (const key of Object.keys(env)) { + resolvedEnv[key] = envWithDeps[`env:${key}`].value; + } + return resolvedEnv; +} + +function computeVscodeVar(varName: string): string { + // https://code.visualstudio.com/docs/editor/variables-reference + const supportedVariables: { [k: string]: () => string } = { + workspaceFolder: () => { + const folders = vscode.workspace.workspaceFolders ?? []; + if (folders.length === 1) { + // TODO: support for remote workspaces? + return folders[0].uri.fsPath; + } else if (folders.length > 1) { + // could use currently opened document to detect the correct + // workspace. However, that would be determined by the document + // user has opened on Editor startup. Could lead to + // unpredictable workspace selection in practice. + // It's better to pick the first one + return folders[0].uri.fsPath; + } else { + // no workspace opened + return ""; + } + }, + + workspaceFolderBasename: () => { + const workspaceFolder = computeVscodeVar("workspaceFolder"); + if (workspaceFolder) { + return path.basename(workspaceFolder); + } else { + return ""; + } + }, + + cwd: () => process.cwd(), + + // see + // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81 + // or + // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56 + execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath, + + pathSeparator: () => path.sep, + }; + + if (varName in supportedVariables) { + return supportedVariables[varName](); + } else { + // can't resolve, keep the expression as is + return "${" + varName + "}"; + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts new file mode 100644 index 00000000000..26510011d43 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -0,0 +1,122 @@ +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient/node"; +import * as ra from "./lsp_ext"; + +import { Config } from "./config"; +import { createClient } from "./client"; +import { isRustEditor, RustEditor } from "./util"; +import { ServerStatusParams } from "./lsp_ext"; + +export type Workspace = + | { + kind: "Workspace Folder"; + } + | { + kind: "Detached Files"; + files: vscode.TextDocument[]; + }; + +export class Ctx { + private constructor( + readonly config: Config, + private readonly extCtx: vscode.ExtensionContext, + readonly client: lc.LanguageClient, + readonly serverPath: string, + readonly statusBar: vscode.StatusBarItem + ) {} + + static async create( + config: Config, + extCtx: vscode.ExtensionContext, + serverPath: string, + workspace: Workspace + ): Promise<Ctx> { + const client = await createClient(serverPath, workspace, config.serverExtraEnv); + + const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + extCtx.subscriptions.push(statusBar); + statusBar.text = "rust-analyzer"; + statusBar.tooltip = "ready"; + statusBar.command = "rust-analyzer.analyzerStatus"; + statusBar.show(); + + const res = new Ctx(config, extCtx, client, serverPath, statusBar); + + res.pushCleanup(client.start()); + await client.onReady(); + client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params)); + return res; + } + + get activeRustEditor(): RustEditor | undefined { + const editor = vscode.window.activeTextEditor; + return editor && isRustEditor(editor) ? editor : undefined; + } + + get visibleRustEditors(): RustEditor[] { + return vscode.window.visibleTextEditors.filter(isRustEditor); + } + + registerCommand(name: string, factory: (ctx: Ctx) => Cmd) { + const fullName = `rust-analyzer.${name}`; + const cmd = factory(this); + const d = vscode.commands.registerCommand(fullName, cmd); + this.pushCleanup(d); + } + + get extensionPath(): string { + return this.extCtx.extensionPath; + } + + get globalState(): vscode.Memento { + return this.extCtx.globalState; + } + + get subscriptions(): Disposable[] { + return this.extCtx.subscriptions; + } + + setServerStatus(status: ServerStatusParams) { + let icon = ""; + const statusBar = this.statusBar; + switch (status.health) { + case "ok": + statusBar.tooltip = status.message ?? "Ready"; + statusBar.command = undefined; + statusBar.color = undefined; + statusBar.backgroundColor = undefined; + break; + case "warning": + statusBar.tooltip = + (status.message ? status.message + "\n" : "") + "Click to reload."; + + statusBar.command = "rust-analyzer.reloadWorkspace"; + statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground"); + statusBar.backgroundColor = new vscode.ThemeColor( + "statusBarItem.warningBackground" + ); + icon = "$(warning) "; + break; + case "error": + statusBar.tooltip = + (status.message ? status.message + "\n" : "") + "Click to reload."; + + statusBar.command = "rust-analyzer.reloadWorkspace"; + statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground"); + statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground"); + icon = "$(error) "; + break; + } + if (!status.quiescent) icon = "$(sync~spin) "; + statusBar.text = `${icon}rust-analyzer`; + } + + pushCleanup(d: Disposable) { + this.extCtx.subscriptions.push(d); + } +} + +export interface Disposable { + dispose(): void; +} +export type Cmd = (...args: any[]) => unknown; diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts new file mode 100644 index 00000000000..bd45599227e --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -0,0 +1,202 @@ +import * as os from "os"; +import * as vscode from "vscode"; +import * as path from "path"; +import * as ra from "./lsp_ext"; + +import { Cargo, getRustcId, getSysroot } from "./toolchain"; +import { Ctx } from "./ctx"; +import { prepareEnv } from "./run"; + +const debugOutput = vscode.window.createOutputChannel("Debug"); +type DebugConfigProvider = ( + config: ra.Runnable, + executable: string, + env: Record<string, string>, + sourceFileMap?: Record<string, string> +) => vscode.DebugConfiguration; + +export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { + const scope = ctx.activeRustEditor?.document.uri; + if (!scope) return; + + const debugConfig = await getDebugConfiguration(ctx, runnable); + if (!debugConfig) return; + + const wsLaunchSection = vscode.workspace.getConfiguration("launch", scope); + const configurations = wsLaunchSection.get<any[]>("configurations") || []; + + const index = configurations.findIndex((c) => c.name === debugConfig.name); + if (index !== -1) { + const answer = await vscode.window.showErrorMessage( + `Launch configuration '${debugConfig.name}' already exists!`, + "Cancel", + "Update" + ); + if (answer === "Cancel") return; + + configurations[index] = debugConfig; + } else { + configurations.push(debugConfig); + } + + await wsLaunchSection.update("configurations", configurations); +} + +export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promise<boolean> { + let debugConfig: vscode.DebugConfiguration | undefined = undefined; + let message = ""; + + const wsLaunchSection = vscode.workspace.getConfiguration("launch"); + const configurations = wsLaunchSection.get<any[]>("configurations") || []; + + const index = configurations.findIndex((c) => c.name === runnable.label); + if (-1 !== index) { + debugConfig = configurations[index]; + message = " (from launch.json)"; + debugOutput.clear(); + } else { + debugConfig = await getDebugConfiguration(ctx, runnable); + } + + if (!debugConfig) return false; + + debugOutput.appendLine(`Launching debug configuration${message}:`); + debugOutput.appendLine(JSON.stringify(debugConfig, null, 2)); + return vscode.debug.startDebugging(undefined, debugConfig); +} + +async function getDebugConfiguration( + ctx: Ctx, + runnable: ra.Runnable +): Promise<vscode.DebugConfiguration | undefined> { + const editor = ctx.activeRustEditor; + if (!editor) return; + + const knownEngines: Record<string, DebugConfigProvider> = { + "vadimcn.vscode-lldb": getLldbDebugConfig, + "ms-vscode.cpptools": getCppvsDebugConfig, + }; + const debugOptions = ctx.config.debug; + + let debugEngine = null; + if (debugOptions.engine === "auto") { + for (var engineId in knownEngines) { + debugEngine = vscode.extensions.getExtension(engineId); + if (debugEngine) break; + } + } else { + debugEngine = vscode.extensions.getExtension(debugOptions.engine); + } + + if (!debugEngine) { + await vscode.window.showErrorMessage( + `Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)` + + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.` + ); + return; + } + + debugOutput.clear(); + if (ctx.config.debug.openDebugPane) { + debugOutput.show(true); + } + // folder exists or RA is not active. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const workspaceFolders = vscode.workspace.workspaceFolders!; + const isMultiFolderWorkspace = workspaceFolders.length > 1; + const firstWorkspace = workspaceFolders[0]; + const workspace = + !isMultiFolderWorkspace || !runnable.args.workspaceRoot + ? firstWorkspace + : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) || + firstWorkspace; + + const wsFolder = path.normalize(workspace.uri.fsPath); + const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : ""; + function simplifyPath(p: string): string { + // see https://github.com/rust-lang/rust-analyzer/pull/5513#issuecomment-663458818 for why this is needed + return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}"); + } + + const executable = await getDebugExecutable(runnable); + const env = prepareEnv(runnable, ctx.config.runnableEnv); + let sourceFileMap = debugOptions.sourceFileMap; + if (sourceFileMap === "auto") { + // let's try to use the default toolchain + const commitHash = await getRustcId(wsFolder); + const sysroot = await getSysroot(wsFolder); + const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust"); + sourceFileMap = {}; + sourceFileMap[`/rustc/${commitHash}/`] = rustlib; + } + + const debugConfig = knownEngines[debugEngine.id]( + runnable, + simplifyPath(executable), + env, + sourceFileMap + ); + if (debugConfig.type in debugOptions.engineSettings) { + const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; + for (var key in settingsMap) { + debugConfig[key] = settingsMap[key]; + } + } + + if (debugConfig.name === "run binary") { + // The LSP side: crates\rust-analyzer\src\main_loop\handlers.rs, + // fn to_lsp_runnable(...) with RunnableKind::Bin + debugConfig.name = `run ${path.basename(executable)}`; + } + + if (debugConfig.cwd) { + debugConfig.cwd = simplifyPath(debugConfig.cwd); + } + + return debugConfig; +} + +async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { + const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput); + const executable = await cargo.executableFromArgs(runnable.args.cargoArgs); + + // if we are here, there were no compilation errors. + return executable; +} + +function getLldbDebugConfig( + runnable: ra.Runnable, + executable: string, + env: Record<string, string>, + sourceFileMap?: Record<string, string> +): vscode.DebugConfiguration { + return { + type: "lldb", + request: "launch", + name: runnable.label, + program: executable, + args: runnable.args.executableArgs, + cwd: runnable.args.workspaceRoot, + sourceMap: sourceFileMap, + sourceLanguages: ["rust"], + env, + }; +} + +function getCppvsDebugConfig( + runnable: ra.Runnable, + executable: string, + env: Record<string, string>, + sourceFileMap?: Record<string, string> +): vscode.DebugConfiguration { + return { + type: os.platform() === "win32" ? "cppvsdbg" : "cppdbg", + request: "launch", + name: runnable.label, + program: executable, + args: runnable.args.executableArgs, + cwd: runnable.args.workspaceRoot, + sourceFileMap, + env, + }; +} diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts new file mode 100644 index 00000000000..f80af78a74a --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts @@ -0,0 +1,180 @@ +/** + * This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations. + */ + +import * as lc from "vscode-languageclient"; + +export interface AnalyzerStatusParams { + textDocument?: lc.TextDocumentIdentifier; +} +export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>( + "rust-analyzer/analyzerStatus" +); +export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage"); +export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph"); + +export interface ServerStatusParams { + health: "ok" | "warning" | "error"; + quiescent: boolean; + message?: string; +} +export const serverStatus = new lc.NotificationType<ServerStatusParams>( + "experimental/serverStatus" +); + +export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); + +export const hover = new lc.RequestType<HoverParams, lc.Hover | null, void>("textDocument/hover"); + +export interface HoverParams extends lc.WorkDoneProgressParams { + textDocument: lc.TextDocumentIdentifier; + position: lc.Range | lc.Position; +} + +export interface SyntaxTreeParams { + textDocument: lc.TextDocumentIdentifier; + range: lc.Range | null; +} +export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>( + "rust-analyzer/syntaxTree" +); + +export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>( + "rust-analyzer/viewHir" +); + +export const viewFileText = new lc.RequestType<lc.TextDocumentIdentifier, string, void>( + "rust-analyzer/viewFileText" +); + +export interface ViewItemTreeParams { + textDocument: lc.TextDocumentIdentifier; +} + +export const viewItemTree = new lc.RequestType<ViewItemTreeParams, string, void>( + "rust-analyzer/viewItemTree" +); + +export interface ViewCrateGraphParams { + full: boolean; +} + +export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>( + "rust-analyzer/viewCrateGraph" +); + +export interface ExpandMacroParams { + textDocument: lc.TextDocumentIdentifier; + position: lc.Position; +} +export interface ExpandedMacro { + name: string; + expansion: string; +} +export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>( + "rust-analyzer/expandMacro" +); + +export interface MatchingBraceParams { + textDocument: lc.TextDocumentIdentifier; + positions: lc.Position[]; +} +export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>( + "experimental/matchingBrace" +); + +export const parentModule = new lc.RequestType< + lc.TextDocumentPositionParams, + lc.LocationLink[] | null, + void +>("experimental/parentModule"); + +export interface JoinLinesParams { + textDocument: lc.TextDocumentIdentifier; + ranges: lc.Range[]; +} +export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>( + "experimental/joinLines" +); + +export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>( + "experimental/onEnter" +); + +export interface RunnablesParams { + textDocument: lc.TextDocumentIdentifier; + position: lc.Position | null; +} + +export interface Runnable { + label: string; + location?: lc.LocationLink; + kind: "cargo"; + args: { + workspaceRoot?: string; + cargoArgs: string[]; + cargoExtraArgs: string[]; + executableArgs: string[]; + expectTest?: boolean; + overrideCargo?: string; + }; +} +export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>( + "experimental/runnables" +); + +export interface TestInfo { + runnable: Runnable; +} + +export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>( + "rust-analyzer/relatedTests" +); + +export interface SsrParams { + query: string; + parseOnly: boolean; + textDocument: lc.TextDocumentIdentifier; + position: lc.Position; + selections: readonly lc.Range[]; +} +export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr"); + +export interface CommandLink extends lc.Command { + /** + * A tooltip for the command, when represented in the UI. + */ + tooltip?: string; +} + +export interface CommandLinkGroup { + title?: string; + commands: CommandLink[]; +} + +export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>( + "experimental/externalDocs" +); + +export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>( + "experimental/openCargoToml" +); + +export interface OpenCargoTomlParams { + textDocument: lc.TextDocumentIdentifier; +} + +export const moveItem = new lc.RequestType<MoveItemParams, lc.TextEdit[], void>( + "experimental/moveItem" +); + +export interface MoveItemParams { + textDocument: lc.TextDocumentIdentifier; + range: lc.Range; + direction: Direction; +} + +export const enum Direction { + Up = "Up", + Down = "Down", +} diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts new file mode 100644 index 00000000000..9ae20ddc4ac --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -0,0 +1,403 @@ +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient/node"; +import * as os from "os"; + +import * as commands from "./commands"; +import { Ctx } from "./ctx"; +import { Config } from "./config"; +import { log, isValidExecutable, isRustDocument } from "./util"; +import { PersistentState } from "./persistent_state"; +import { activateTaskProvider } from "./tasks"; +import { setContextValue } from "./util"; +import { exec } from "child_process"; + +let ctx: Ctx | undefined; + +const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; + +let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null; +export function traceOutputChannel() { + if (!TRACE_OUTPUT_CHANNEL) { + TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel( + "Rust Analyzer Language Server Trace" + ); + } + return TRACE_OUTPUT_CHANNEL; +} +let OUTPUT_CHANNEL: vscode.OutputChannel | null = null; +export function outputChannel() { + if (!OUTPUT_CHANNEL) { + OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rust Analyzer Language Server"); + } + return OUTPUT_CHANNEL; +} + +export interface RustAnalyzerExtensionApi { + client: lc.LanguageClient; +} + +export async function activate( + context: vscode.ExtensionContext +): Promise<RustAnalyzerExtensionApi> { + // VS Code doesn't show a notification when an extension fails to activate + // so we do it ourselves. + return await tryActivate(context).catch((err) => { + void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`); + throw err; + }); +} + +async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> { + const config = new Config(context); + const state = new PersistentState(context.globalState); + const serverPath = await bootstrap(context, config, state).catch((err) => { + let message = "bootstrap error. "; + + message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). '; + message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }'; + + log.error("Bootstrap error", err); + throw new Error(message); + }); + + if ((vscode.workspace.workspaceFolders || []).length === 0) { + const rustDocuments = vscode.workspace.textDocuments.filter((document) => + isRustDocument(document) + ); + if (rustDocuments.length > 0) { + ctx = await Ctx.create(config, context, serverPath, { + kind: "Detached Files", + files: rustDocuments, + }); + } else { + throw new Error("no rust files are opened"); + } + } else { + // Note: we try to start the server before we activate type hints so that it + // registers its `onDidChangeDocument` handler before us. + // + // This a horribly, horribly wrong way to deal with this problem. + ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" }); + ctx.pushCleanup(activateTaskProvider(ctx.config)); + } + await initCommonContext(context, ctx); + + warnAboutExtensionConflicts(); + + ctx.pushCleanup(configureLanguage()); + + vscode.workspace.onDidChangeConfiguration( + (_) => + ctx?.client + ?.sendNotification("workspace/didChangeConfiguration", { settings: "" }) + .catch(log.error), + null, + ctx.subscriptions + ); + + return { + client: ctx.client, + }; +} + +async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { + // Register a "dumb" onEnter command for the case where server fails to + // start. + // + // FIXME: refactor command registration code such that commands are + // **always** registered, even if the server does not start. Use API like + // this perhaps? + // + // ```TypeScript + // registerCommand( + // factory: (Ctx) => ((Ctx) => any), + // fallback: () => any = () => vscode.window.showErrorMessage( + // "rust-analyzer is not available" + // ), + // ) + const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () => + vscode.commands.executeCommand("default:type", { text: "\n" }) + ); + context.subscriptions.push(defaultOnEnter); + + await setContextValue(RUST_PROJECT_CONTEXT_NAME, true); + + // Commands which invokes manually via command palette, shortcut, etc. + + // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 + ctx.registerCommand("reload", (_) => async () => { + void vscode.window.showInformationMessage("Reloading rust-analyzer..."); + await doDeactivate(); + while (context.subscriptions.length > 0) { + try { + context.subscriptions.pop()!.dispose(); + } catch (err) { + log.error("Dispose error:", err); + } + } + await activate(context).catch(log.error); + }); + + ctx.registerCommand("analyzerStatus", commands.analyzerStatus); + ctx.registerCommand("memoryUsage", commands.memoryUsage); + ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph); + ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace); + ctx.registerCommand("matchingBrace", commands.matchingBrace); + ctx.registerCommand("joinLines", commands.joinLines); + ctx.registerCommand("parentModule", commands.parentModule); + ctx.registerCommand("syntaxTree", commands.syntaxTree); + ctx.registerCommand("viewHir", commands.viewHir); + ctx.registerCommand("viewFileText", commands.viewFileText); + ctx.registerCommand("viewItemTree", commands.viewItemTree); + ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph); + ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph); + ctx.registerCommand("expandMacro", commands.expandMacro); + ctx.registerCommand("run", commands.run); + ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine); + ctx.registerCommand("debug", commands.debug); + ctx.registerCommand("newDebugConfig", commands.newDebugConfig); + ctx.registerCommand("openDocs", commands.openDocs); + ctx.registerCommand("openCargoToml", commands.openCargoToml); + ctx.registerCommand("peekTests", commands.peekTests); + ctx.registerCommand("moveItemUp", commands.moveItemUp); + ctx.registerCommand("moveItemDown", commands.moveItemDown); + + defaultOnEnter.dispose(); + ctx.registerCommand("onEnter", commands.onEnter); + + ctx.registerCommand("ssr", commands.ssr); + ctx.registerCommand("serverVersion", commands.serverVersion); + ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints); + + // Internal commands which are invoked by the server. + ctx.registerCommand("runSingle", commands.runSingle); + ctx.registerCommand("debugSingle", commands.debugSingle); + ctx.registerCommand("showReferences", commands.showReferences); + ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand); + ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction); + ctx.registerCommand("applyActionGroup", commands.applyActionGroup); + ctx.registerCommand("gotoLocation", commands.gotoLocation); + + ctx.registerCommand("linkToCommand", commands.linkToCommand); +} + +export async function deactivate() { + TRACE_OUTPUT_CHANNEL?.dispose(); + TRACE_OUTPUT_CHANNEL = null; + OUTPUT_CHANNEL?.dispose(); + OUTPUT_CHANNEL = null; + await doDeactivate(); +} + +async function doDeactivate() { + await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined); + await ctx?.client.stop(); + ctx = undefined; +} + +async function bootstrap( + context: vscode.ExtensionContext, + config: Config, + state: PersistentState +): Promise<string> { + const path = await getServer(context, config, state); + if (!path) { + throw new Error( + "Rust Analyzer Language Server is not available. " + + "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)." + ); + } + + log.info("Using server binary at", path); + + if (!isValidExecutable(path)) { + if (config.serverPath) { + throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\ + Consider removing this config or making a valid server binary available at that path.`); + } else { + throw new Error(`Failed to execute ${path} --version`); + } + } + + return path; +} + +async function patchelf(dest: vscode.Uri): Promise<void> { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Patching rust-analyzer for NixOS", + }, + async (progress, _) => { + const expression = ` + {srcStr, pkgs ? import <nixpkgs> {}}: + pkgs.stdenv.mkDerivation { + name = "rust-analyzer"; + src = /. + srcStr; + phases = [ "installPhase" "fixupPhase" ]; + installPhase = "cp $src $out"; + fixupPhase = '' + chmod 755 $out + patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out + ''; + } + `; + const origFile = vscode.Uri.file(dest.fsPath + "-orig"); + await vscode.workspace.fs.rename(dest, origFile, { overwrite: true }); + try { + progress.report({ message: "Patching executable", increment: 20 }); + await new Promise((resolve, reject) => { + const handle = exec( + `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`, + (err, stdout, stderr) => { + if (err != null) { + reject(Error(stderr)); + } else { + resolve(stdout); + } + } + ); + handle.stdin?.write(expression); + handle.stdin?.end(); + }); + } finally { + await vscode.workspace.fs.delete(origFile); + } + } + ); +} + +async function getServer( + context: vscode.ExtensionContext, + config: Config, + state: PersistentState +): Promise<string | undefined> { + const explicitPath = serverPath(config); + if (explicitPath) { + if (explicitPath.startsWith("~/")) { + return os.homedir() + explicitPath.slice("~".length); + } + return explicitPath; + } + if (config.package.releaseTag === null) return "rust-analyzer"; + + const ext = process.platform === "win32" ? ".exe" : ""; + const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`); + const bundledExists = await vscode.workspace.fs.stat(bundled).then( + () => true, + () => false + ); + if (bundledExists) { + let server = bundled; + if (await isNixOs()) { + await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); + const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`); + let exists = await vscode.workspace.fs.stat(dest).then( + () => true, + () => false + ); + if (exists && config.package.version !== state.serverVersion) { + await vscode.workspace.fs.delete(dest); + exists = false; + } + if (!exists) { + await vscode.workspace.fs.copy(bundled, dest); + await patchelf(dest); + } + server = dest; + } + await state.updateServerVersion(config.package.version); + return server.fsPath; + } + + await state.updateServerVersion(undefined); + await vscode.window.showErrorMessage( + "Unfortunately we don't ship binaries for your platform yet. " + + "You need to manually clone the rust-analyzer repository and " + + "run `cargo xtask install --server` to build the language server from sources. " + + "If you feel that your platform should be supported, please create an issue " + + "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " + + "will consider it." + ); + return undefined; +} + +function serverPath(config: Config): string | null { + return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; +} + +async function isNixOs(): Promise<boolean> { + try { + const contents = ( + await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release")) + ).toString(); + const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux"; + return idString.indexOf("nixos") !== -1; + } catch { + return false; + } +} + +function warnAboutExtensionConflicts() { + if (vscode.extensions.getExtension("rust-lang.rust")) { + vscode.window + .showWarningMessage( + `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + + "plugins enabled. These are known to conflict and cause various functions of " + + "both plugins to not work correctly. You should disable one of them.", + "Got it" + ) + .then(() => {}, console.error); + } +} + +/** + * Sets up additional language configuration that's impossible to do via a + * separate language-configuration.json file. See [1] for more information. + * + * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076 + */ +function configureLanguage(): vscode.Disposable { + const indentAction = vscode.IndentAction.None; + return vscode.languages.setLanguageConfiguration("rust", { + onEnterRules: [ + { + // Doc single-line comment + // e.g. ///| + beforeText: /^\s*\/{3}.*$/, + action: { indentAction, appendText: "/// " }, + }, + { + // Parent doc single-line comment + // e.g. //!| + beforeText: /^\s*\/{2}\!.*$/, + action: { indentAction, appendText: "//! " }, + }, + { + // Begins an auto-closed multi-line comment (standard or parent doc) + // e.g. /** | */ or /*! | */ + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " }, + }, + { + // Begins a multi-line comment (standard or parent doc) + // e.g. /** ...| or /*! ...| + beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction, appendText: " * " }, + }, + { + // Continues a multi-line comment + // e.g. * ...| + beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction, appendText: "* " }, + }, + { + // Dedents after closing a multi-line comment + // e.g. */| + beforeText: /^(\ \ )*\ \*\/\s*$/, + action: { indentAction, removeText: 1 }, + }, + ], + }); +} diff --git a/src/tools/rust-analyzer/editors/code/src/persistent_state.ts b/src/tools/rust-analyzer/editors/code/src/persistent_state.ts new file mode 100644 index 00000000000..8964a78dc32 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/persistent_state.ts @@ -0,0 +1,20 @@ +import * as vscode from "vscode"; +import { log } from "./util"; + +export class PersistentState { + constructor(private readonly globalState: vscode.Memento) { + const { serverVersion } = this; + log.info("PersistentState:", { serverVersion }); + } + + /** + * Version of the extension that installed the server. + * Used to check if we need to run patchelf again on NixOS. + */ + get serverVersion(): string | undefined { + return this.globalState.get("serverVersion"); + } + async updateServerVersion(value: string | undefined) { + await this.globalState.update("serverVersion", value); + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts new file mode 100644 index 00000000000..22e5eda6827 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -0,0 +1,175 @@ +import * as vscode from "vscode"; +import * as lc from "vscode-languageclient"; +import * as ra from "./lsp_ext"; +import * as tasks from "./tasks"; + +import { Ctx } from "./ctx"; +import { makeDebugConfig } from "./debug"; +import { Config, RunnableEnvCfg } from "./config"; + +const quickPickButtons = [ + { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." }, +]; + +export async function selectRunnable( + ctx: Ctx, + prevRunnable?: RunnableQuickPick, + debuggeeOnly = false, + showButtons: boolean = true +): Promise<RunnableQuickPick | undefined> { + const editor = ctx.activeRustEditor; + const client = ctx.client; + if (!editor || !client) return; + + const textDocument: lc.TextDocumentIdentifier = { + uri: editor.document.uri.toString(), + }; + + const runnables = await client.sendRequest(ra.runnables, { + textDocument, + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }); + const items: RunnableQuickPick[] = []; + if (prevRunnable) { + items.push(prevRunnable); + } + for (const r of runnables) { + if (prevRunnable && JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)) { + continue; + } + + if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) { + continue; + } + items.push(new RunnableQuickPick(r)); + } + + if (items.length === 0) { + // it is the debug case, run always has at least 'cargo check ...' + // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables + await vscode.window.showErrorMessage("There's no debug target!"); + return; + } + + return await new Promise((resolve) => { + const disposables: vscode.Disposable[] = []; + const close = (result?: RunnableQuickPick) => { + resolve(result); + disposables.forEach((d) => d.dispose()); + }; + + const quickPick = vscode.window.createQuickPick<RunnableQuickPick>(); + quickPick.items = items; + quickPick.title = "Select Runnable"; + if (showButtons) { + quickPick.buttons = quickPickButtons; + } + disposables.push( + quickPick.onDidHide(() => close()), + quickPick.onDidAccept(() => close(quickPick.selectedItems[0])), + quickPick.onDidTriggerButton(async (_button) => { + await makeDebugConfig(ctx, quickPick.activeItems[0].runnable); + close(); + }), + quickPick.onDidChangeActive((active) => { + if (showButtons && active.length > 0) { + if (active[0].label.startsWith("cargo")) { + // save button makes no sense for `cargo test` or `cargo check` + quickPick.buttons = []; + } else if (quickPick.buttons.length === 0) { + quickPick.buttons = quickPickButtons; + } + } + }), + quickPick + ); + quickPick.show(); + }); +} + +export class RunnableQuickPick implements vscode.QuickPickItem { + public label: string; + public description?: string | undefined; + public detail?: string | undefined; + public picked?: boolean | undefined; + + constructor(public runnable: ra.Runnable) { + this.label = runnable.label; + } +} + +export function prepareEnv( + runnable: ra.Runnable, + runnableEnvCfg: RunnableEnvCfg +): Record<string, string> { + const env: Record<string, string> = { RUST_BACKTRACE: "short" }; + + if (runnable.args.expectTest) { + env["UPDATE_EXPECT"] = "1"; + } + + Object.assign(env, process.env as { [key: string]: string }); + + if (runnableEnvCfg) { + if (Array.isArray(runnableEnvCfg)) { + for (const it of runnableEnvCfg) { + if (!it.mask || new RegExp(it.mask).test(runnable.label)) { + Object.assign(env, it.env); + } + } + } else { + Object.assign(env, runnableEnvCfg); + } + } + + return env; +} + +export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { + if (runnable.kind !== "cargo") { + // rust-analyzer supports only one kind, "cargo" + // do not use tasks.TASK_TYPE here, these are completely different meanings. + + throw `Unexpected runnable kind: ${runnable.kind}`; + } + + const args = createArgs(runnable); + + const definition: tasks.CargoTaskDefinition = { + type: tasks.TASK_TYPE, + command: args[0], // run, test, etc... + args: args.slice(1), + cwd: runnable.args.workspaceRoot || ".", + env: prepareEnv(runnable, config.runnableEnv), + overrideCargo: runnable.args.overrideCargo, + }; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() + const cargoTask = await tasks.buildCargoTask( + target, + definition, + runnable.label, + args, + config.cargoRunner, + true + ); + + cargoTask.presentationOptions.clear = true; + // Sadly, this doesn't prevent focus stealing if the terminal is currently + // hidden, and will become revealed due to task exucution. + cargoTask.presentationOptions.focus = false; + + return cargoTask; +} + +export function createArgs(runnable: ra.Runnable): string[] { + const args = [...runnable.args.cargoArgs]; // should be a copy! + if (runnable.args.cargoExtraArgs) { + args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options. + } + if (runnable.args.executableArgs.length > 0) { + args.push("--", ...runnable.args.executableArgs); + } + return args; +} diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts new file mode 100644 index 00000000000..299d29c27ee --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts @@ -0,0 +1,87 @@ +import * as vscode from "vscode"; + +import { assert } from "./util"; + +export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { + if (edit.entries().length === 1) { + const [uri, edits] = edit.entries()[0]; + const editor = await editorFromUri(uri); + if (editor) await applySnippetTextEdits(editor, edits); + return; + } + for (const [uri, edits] of edit.entries()) { + const editor = await editorFromUri(uri); + if (editor) { + await editor.edit((builder) => { + for (const indel of edits) { + assert( + !parseSnippet(indel.newText), + `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}` + ); + builder.replace(indel.range, indel.newText); + } + }); + } + } +} + +async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undefined> { + if (vscode.window.activeTextEditor?.document.uri !== uri) { + // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed + await vscode.window.showTextDocument(uri, {}); + } + return vscode.window.visibleTextEditors.find( + (it) => it.document.uri.toString() === uri.toString() + ); +} + +export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) { + const selections: vscode.Selection[] = []; + let lineDelta = 0; + await editor.edit((builder) => { + for (const indel of edits) { + const parsed = parseSnippet(indel.newText); + if (parsed) { + const [newText, [placeholderStart, placeholderLength]] = parsed; + const prefix = newText.substr(0, placeholderStart); + const lastNewline = prefix.lastIndexOf("\n"); + + const startLine = indel.range.start.line + lineDelta + countLines(prefix); + const startColumn = + lastNewline === -1 + ? indel.range.start.character + placeholderStart + : prefix.length - lastNewline - 1; + const endColumn = startColumn + placeholderLength; + selections.push( + new vscode.Selection( + new vscode.Position(startLine, startColumn), + new vscode.Position(startLine, endColumn) + ) + ); + builder.replace(indel.range, newText); + } else { + builder.replace(indel.range, indel.newText); + } + lineDelta += + countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); + } + }); + if (selections.length > 0) editor.selections = selections; + if (selections.length === 1) { + editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport); + } +} + +function parseSnippet(snip: string): [string, [number, number]] | undefined { + const m = snip.match(/\$(0|\{0:([^}]*)\})/); + if (!m) return undefined; + const placeholder = m[2] ?? ""; + if (m.index == null) return undefined; + const range: [number, number] = [m.index, placeholder.length]; + const insert = snip.replace(m[0], placeholder); + return [insert, range]; +} + +function countLines(text: string): number { + return (text.match(/\n/g) || []).length; +} diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts new file mode 100644 index 00000000000..e6239deeb21 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts @@ -0,0 +1,138 @@ +import * as vscode from "vscode"; +import * as toolchain from "./toolchain"; +import { Config } from "./config"; +import { log } from "./util"; + +// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and +// our configuration should be compatible with it so use the same key. +export const TASK_TYPE = "cargo"; +export const TASK_SOURCE = "rust"; + +export interface CargoTaskDefinition extends vscode.TaskDefinition { + command?: string; + args?: string[]; + cwd?: string; + env?: { [key: string]: string }; + overrideCargo?: string; +} + +class CargoTaskProvider implements vscode.TaskProvider { + private readonly config: Config; + + constructor(config: Config) { + this.config = config; + } + + async provideTasks(): Promise<vscode.Task[]> { + // Detect Rust tasks. Currently we do not do any actual detection + // of tasks (e.g. aliases in .cargo/config) and just return a fixed + // set of tasks that always exist. These tasks cannot be removed in + // tasks.json - only tweaked. + + const defs = [ + { command: "build", group: vscode.TaskGroup.Build }, + { command: "check", group: vscode.TaskGroup.Build }, + { command: "clippy", group: vscode.TaskGroup.Build }, + { command: "test", group: vscode.TaskGroup.Test }, + { command: "clean", group: vscode.TaskGroup.Clean }, + { command: "run", group: undefined }, + ]; + + const tasks: vscode.Task[] = []; + for (const workspaceTarget of vscode.workspace.workspaceFolders || []) { + for (const def of defs) { + const vscodeTask = await buildCargoTask( + workspaceTarget, + { type: TASK_TYPE, command: def.command }, + `cargo ${def.command}`, + [def.command], + this.config.cargoRunner + ); + vscodeTask.group = def.group; + tasks.push(vscodeTask); + } + } + + return tasks; + } + + async resolveTask(task: vscode.Task): Promise<vscode.Task | undefined> { + // VSCode calls this for every cargo task in the user's tasks.json, + // we need to inform VSCode how to execute that command by creating + // a ShellExecution for it. + + const definition = task.definition as CargoTaskDefinition; + + if (definition.type === TASK_TYPE && definition.command) { + const args = [definition.command].concat(definition.args ?? []); + return await buildCargoTask( + task.scope, + definition, + task.name, + args, + this.config.cargoRunner + ); + } + + return undefined; + } +} + +export async function buildCargoTask( + scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined, + definition: CargoTaskDefinition, + name: string, + args: string[], + customRunner?: string, + throwOnError: boolean = false +): Promise<vscode.Task> { + let exec: vscode.ProcessExecution | vscode.ShellExecution | undefined = undefined; + + if (customRunner) { + const runnerCommand = `${customRunner}.buildShellExecution`; + try { + const runnerArgs = { kind: TASK_TYPE, args, cwd: definition.cwd, env: definition.env }; + const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs); + if (customExec) { + if (customExec instanceof vscode.ShellExecution) { + exec = customExec; + } else { + log.debug("Invalid cargo ShellExecution", customExec); + throw "Invalid cargo ShellExecution."; + } + } + // fallback to default processing + } catch (e) { + if (throwOnError) throw `Cargo runner '${customRunner}' failed! ${e}`; + // fallback to default processing + } + } + + if (!exec) { + // Check whether we must use a user-defined substitute for cargo. + // Split on spaces to allow overrides like "wrapper cargo". + const overrideCargo = definition.overrideCargo ?? definition.overrideCargo; + const cargoPath = await toolchain.cargoPath(); + const cargoCommand = overrideCargo?.split(" ") ?? [cargoPath]; + + const fullCommand = [...cargoCommand, ...args]; + + exec = new vscode.ProcessExecution(fullCommand[0], fullCommand.slice(1), definition); + } + + return new vscode.Task( + definition, + // scope can sometimes be undefined. in these situations we default to the workspace taskscope as + // recommended by the official docs: https://code.visualstudio.com/api/extension-guides/task-provider#task-provider) + scope ?? vscode.TaskScope.Workspace, + name, + TASK_SOURCE, + exec, + ["$rustc"] + ); +} + +export function activateTaskProvider(config: Config): vscode.Disposable { + const provider = new CargoTaskProvider(config); + return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); +} diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts new file mode 100644 index 00000000000..bac163da9f3 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts @@ -0,0 +1,203 @@ +import * as cp from "child_process"; +import * as os from "os"; +import * as path from "path"; +import * as readline from "readline"; +import * as vscode from "vscode"; +import { execute, log, memoizeAsync } from "./util"; + +interface CompilationArtifact { + fileName: string; + name: string; + kind: string; + isTest: boolean; +} + +export interface ArtifactSpec { + cargoArgs: string[]; + filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[]; +} + +export class Cargo { + constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) {} + + // Made public for testing purposes + static artifactSpec(args: readonly string[]): ArtifactSpec { + const cargoArgs = [...args, "--message-format=json"]; + + // arguments for a runnable from the quick pick should be updated. + // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens + switch (cargoArgs[0]) { + case "run": + cargoArgs[0] = "build"; + break; + case "test": { + if (!cargoArgs.includes("--no-run")) { + cargoArgs.push("--no-run"); + } + break; + } + } + + const result: ArtifactSpec = { cargoArgs: cargoArgs }; + if (cargoArgs[0] === "test" || cargoArgs[0] === "bench") { + // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests + // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"} + result.filter = (artifacts) => artifacts.filter((it) => it.isTest); + } + + return result; + } + + private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> { + const artifacts: CompilationArtifact[] = []; + + try { + await this.runCargo( + spec.cargoArgs, + (message) => { + if (message.reason === "compiler-artifact" && message.executable) { + const isBinary = message.target.crate_types.includes("bin"); + const isBuildScript = message.target.kind.includes("custom-build"); + if ((isBinary && !isBuildScript) || message.profile.test) { + artifacts.push({ + fileName: message.executable, + name: message.target.name, + kind: message.target.kind[0], + isTest: message.profile.test, + }); + } + } else if (message.reason === "compiler-message") { + this.output.append(message.message.rendered); + } + }, + (stderr) => this.output.append(stderr) + ); + } catch (err) { + this.output.show(true); + throw new Error(`Cargo invocation has failed: ${err}`); + } + + return spec.filter?.(artifacts) ?? artifacts; + } + + async executableFromArgs(args: readonly string[]): Promise<string> { + const artifacts = await this.getArtifacts(Cargo.artifactSpec(args)); + + if (artifacts.length === 0) { + throw new Error("No compilation artifacts"); + } else if (artifacts.length > 1) { + throw new Error("Multiple compilation artifacts are not supported."); + } + + return artifacts[0].fileName; + } + + private async runCargo( + cargoArgs: string[], + onStdoutJson: (obj: any) => void, + onStderrString: (data: string) => void + ): Promise<number> { + const path = await cargoPath(); + return await new Promise((resolve, reject) => { + const cargo = cp.spawn(path, cargoArgs, { + stdio: ["ignore", "pipe", "pipe"], + cwd: this.rootFolder, + }); + + cargo.on("error", (err) => reject(new Error(`could not launch cargo: ${err}`))); + + cargo.stderr.on("data", (chunk) => onStderrString(chunk.toString())); + + const rl = readline.createInterface({ input: cargo.stdout }); + rl.on("line", (line) => { + const message = JSON.parse(line); + onStdoutJson(message); + }); + + cargo.on("exit", (exitCode, _) => { + if (exitCode === 0) resolve(exitCode); + else reject(new Error(`exit code: ${exitCode}.`)); + }); + }); + } +} + +/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/ +export async function getSysroot(dir: string): Promise<string> { + const rustcPath = await getPathForExecutable("rustc"); + + // do not memoize the result because the toolchain may change between runs + return await execute(`${rustcPath} --print sysroot`, { cwd: dir }); +} + +export async function getRustcId(dir: string): Promise<string> { + const rustcPath = await getPathForExecutable("rustc"); + + // do not memoize the result because the toolchain may change between runs + const data = await execute(`${rustcPath} -V -v`, { cwd: dir }); + const rx = /commit-hash:\s(.*)$/m; + + return rx.exec(data)![1]; +} + +/** Mirrors `toolchain::cargo()` implementation */ +export function cargoPath(): Promise<string> { + return getPathForExecutable("cargo"); +} + +/** Mirrors `toolchain::get_path_for_executable()` implementation */ +export const getPathForExecutable = memoizeAsync( + // We apply caching to decrease file-system interactions + async (executableName: "cargo" | "rustc" | "rustup"): Promise<string> => { + { + const envVar = process.env[executableName.toUpperCase()]; + if (envVar) return envVar; + } + + if (await lookupInPath(executableName)) return executableName; + + try { + // hmm, `os.homedir()` seems to be infallible + // it is not mentioned in docs and cannot be infered by the type signature... + const standardPath = vscode.Uri.joinPath( + vscode.Uri.file(os.homedir()), + ".cargo", + "bin", + executableName + ); + + if (await isFileAtUri(standardPath)) return standardPath.fsPath; + } catch (err) { + log.error("Failed to read the fs info", err); + } + return executableName; + } +); + +async function lookupInPath(exec: string): Promise<boolean> { + const paths = process.env.PATH ?? ""; + + const candidates = paths.split(path.delimiter).flatMap((dirInPath) => { + const candidate = path.join(dirInPath, exec); + return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate]; + }); + + for await (const isFile of candidates.map(isFileAtPath)) { + if (isFile) { + return true; + } + } + return false; +} + +async function isFileAtPath(path: string): Promise<boolean> { + return isFileAtUri(vscode.Uri.file(path)); +} + +async function isFileAtUri(uri: vscode.Uri): Promise<boolean> { + try { + return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0; + } catch { + return false; + } +} diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts new file mode 100644 index 00000000000..cd91932bb60 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/util.ts @@ -0,0 +1,168 @@ +import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; +import { strict as nativeAssert } from "assert"; +import { exec, ExecOptions, spawnSync } from "child_process"; +import { inspect } from "util"; + +export function assert(condition: boolean, explanation: string): asserts condition { + try { + nativeAssert(condition, explanation); + } catch (err) { + log.error(`Assertion failed:`, explanation); + throw err; + } +} + +export const log = new (class { + private enabled = true; + private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client"); + + setEnabled(yes: boolean): void { + log.enabled = yes; + } + + // Hint: the type [T, ...T[]] means a non-empty array + debug(...msg: [unknown, ...unknown[]]): void { + if (!log.enabled) return; + log.write("DEBUG", ...msg); + } + + info(...msg: [unknown, ...unknown[]]): void { + log.write("INFO", ...msg); + } + + warn(...msg: [unknown, ...unknown[]]): void { + debugger; + log.write("WARN", ...msg); + } + + error(...msg: [unknown, ...unknown[]]): void { + debugger; + log.write("ERROR", ...msg); + log.output.show(true); + } + + private write(label: string, ...messageParts: unknown[]): void { + const message = messageParts.map(log.stringify).join(" "); + const dateTime = new Date().toLocaleString(); + log.output.appendLine(`${label} [${dateTime}]: ${message}`); + } + + private stringify(val: unknown): string { + if (typeof val === "string") return val; + return inspect(val, { + colors: false, + depth: 6, // heuristic + }); + } +})(); + +export async function sendRequestWithRetry<TParam, TRet>( + client: lc.LanguageClient, + reqType: lc.RequestType<TParam, TRet, unknown>, + param: TParam, + token?: vscode.CancellationToken +): Promise<TRet> { + // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3... + for (const delay of [40, 160, 640, 2560, 10240, null]) { + try { + return await (token + ? client.sendRequest(reqType, param, token) + : client.sendRequest(reqType, param)); + } catch (error) { + if (delay === null) { + log.warn("LSP request timed out", { method: reqType.method, param, error }); + throw error; + } + if (error.code === lc.LSPErrorCodes.RequestCancelled) { + throw error; + } + + if (error.code !== lc.LSPErrorCodes.ContentModified) { + log.warn("LSP request failed", { method: reqType.method, param, error }); + throw error; + } + await sleep(delay); + } + } + throw "unreachable"; +} + +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export type RustDocument = vscode.TextDocument & { languageId: "rust" }; +export type RustEditor = vscode.TextEditor & { document: RustDocument }; + +export function isRustDocument(document: vscode.TextDocument): document is RustDocument { + // Prevent corrupted text (particularly via inlay hints) in diff views + // by allowing only `file` schemes + // unfortunately extensions that use diff views not always set this + // to something different than 'file' (see ongoing bug: #4608) + return document.languageId === "rust" && document.uri.scheme === "file"; +} + +export function isCargoTomlDocument(document: vscode.TextDocument): document is RustDocument { + // ideally `document.languageId` should be 'toml' but user maybe not have toml extension installed + return document.uri.scheme === "file" && document.fileName.endsWith("Cargo.toml"); +} + +export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { + return isRustDocument(editor.document); +} + +export function isValidExecutable(path: string): boolean { + log.debug("Checking availability of a binary at", path); + + const res = spawnSync(path, ["--version"], { encoding: "utf8" }); + + const printOutput = res.error && (res.error as any).code !== "ENOENT" ? log.warn : log.debug; + printOutput(path, "--version:", res); + + return res.status === 0; +} + +/** Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts) clause contexts */ +export function setContextValue(key: string, value: any): Thenable<void> { + return vscode.commands.executeCommand("setContext", key, value); +} + +/** + * Returns a higher-order function that caches the results of invoking the + * underlying async function. + */ +export function memoizeAsync<Ret, TThis, Param extends string>( + func: (this: TThis, arg: Param) => Promise<Ret> +) { + const cache = new Map<string, Ret>(); + + return async function (this: TThis, arg: Param) { + const cached = cache.get(arg); + if (cached) return cached; + + const result = await func.call(this, arg); + cache.set(arg, result); + + return result; + }; +} + +/** Awaitable wrapper around `child_process.exec` */ +export function execute(command: string, options: ExecOptions): Promise<string> { + return new Promise((resolve, reject) => { + exec(command, options, (err, stdout, stderr) => { + if (err) { + reject(err); + return; + } + + if (stderr) { + reject(new Error(stderr)); + return; + } + + resolve(stdout.trimEnd()); + }); + }); +} diff --git a/src/tools/rust-analyzer/editors/code/tests/runTests.ts b/src/tools/rust-analyzer/editors/code/tests/runTests.ts new file mode 100644 index 00000000000..08632ec3b49 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/runTests.ts @@ -0,0 +1,43 @@ +import * as path from "path"; +import * as fs from "fs"; + +import { runTests } from "@vscode/test-electron"; + +async function main() { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); + + // Minimum supported version. + const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, "package.json")); + const json = JSON.parse(jsonData.toString()); + let minimalVersion: string = json.engines.vscode; + if (minimalVersion.startsWith("^")) minimalVersion = minimalVersion.slice(1); + + const launchArgs = ["--disable-extensions", extensionDevelopmentPath]; + + // All test suites (either unit tests or integration tests) should be in subfolders. + const extensionTestsPath = path.resolve(__dirname, "./unit/index"); + + // Run tests using the minimal supported version. + await runTests({ + version: minimalVersion, + launchArgs, + extensionDevelopmentPath, + extensionTestsPath, + }); + + // and the latest one + await runTests({ + version: "stable", + launchArgs, + extensionDevelopmentPath, + extensionTestsPath, + }); +} + +main().catch((err) => { + // eslint-disable-next-line no-console + console.error("Failed to run tests", err); + process.exit(1); +}); diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/index.ts b/src/tools/rust-analyzer/editors/code/tests/unit/index.ts new file mode 100644 index 00000000000..2fa223bed4a --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/index.ts @@ -0,0 +1,84 @@ +import { readdir } from "fs/promises"; +import * as path from "path"; + +class Test { + readonly name: string; + readonly promise: Promise<void>; + + constructor(name: string, promise: Promise<void>) { + this.name = name; + this.promise = promise; + } +} + +class Suite { + tests: Test[]; + + constructor() { + this.tests = []; + } + + public addTest(name: string, f: () => Promise<void>): void { + const test = new Test(name, f()); + this.tests.push(test); + } + + public async run(): Promise<void> { + let failed = 0; + for (const test of this.tests) { + try { + await test.promise; + ok(` ✔ ${test.name}`); + } catch (e) { + error(` ✖︎ ${test.name}\n ${e.stack}`); + failed += 1; + } + } + if (failed) { + const plural = failed > 1 ? "s" : ""; + throw new Error(`${failed} failed test${plural}`); + } + } +} + +export class Context { + public async suite(name: string, f: (ctx: Suite) => void): Promise<void> { + const ctx = new Suite(); + f(ctx); + try { + ok(`⌛︎ ${name}`); + await ctx.run(); + ok(`✔ ${name}`); + } catch (e) { + error(`✖︎ ${name}\n ${e.stack}`); + throw e; + } + } +} + +export async function run(): Promise<void> { + const context = new Context(); + + const testFiles = (await readdir(path.resolve(__dirname))).filter((name) => + name.endsWith(".test.js") + ); + for (const testFile of testFiles) { + try { + const testModule = require(path.resolve(__dirname, testFile)); + await testModule.getTests(context); + } catch (e) { + error(`${e}`); + throw e; + } + } +} + +function ok(message: string): void { + // eslint-disable-next-line no-console + console.log(`\x1b[32m${message}\x1b[0m`); +} + +function error(message: string): void { + // eslint-disable-next-line no-console + console.error(`\x1b[31m${message}\x1b[0m`); +} diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts new file mode 100644 index 00000000000..0531e064d2d --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/launch_config.test.ts @@ -0,0 +1,99 @@ +import * as assert from "assert"; +import { Cargo } from "../../src/toolchain"; +import { Context } from "."; + +export async function getTests(ctx: Context) { + await ctx.suite("Launch configuration/Lens", (suite) => { + suite.addTest("A binary", async () => { + const args = Cargo.artifactSpec([ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + ]); + + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + "--message-format=json", + ]); + assert.deepStrictEqual(args.filter, undefined); + }); + + suite.addTest("One of Multiple Binaries", async () => { + const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]); + + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "bin1", + "--message-format=json", + ]); + assert.deepStrictEqual(args.filter, undefined); + }); + + suite.addTest("A test", async () => { + const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]); + + assert.deepStrictEqual(args.cargoArgs, [ + "test", + "--package", + "pkg_name", + "--lib", + "--no-run", + "--message-format=json", + ]); + assert.notDeepStrictEqual(args.filter, undefined); + }); + }); + + await ctx.suite("Launch configuration/QuickPick", (suite) => { + suite.addTest("A binary", async () => { + const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]); + + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "pkg_name", + "--message-format=json", + ]); + assert.deepStrictEqual(args.filter, undefined); + }); + + suite.addTest("One of Multiple Binaries", async () => { + const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]); + + assert.deepStrictEqual(args.cargoArgs, [ + "build", + "--package", + "pkg_name", + "--bin", + "bin2", + "--message-format=json", + ]); + assert.deepStrictEqual(args.filter, undefined); + }); + + suite.addTest("A test", async () => { + const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]); + + assert.deepStrictEqual(args.cargoArgs, [ + "test", + "--package", + "pkg_name", + "--lib", + "--message-format=json", + "--no-run", + ]); + assert.notDeepStrictEqual(args.filter, undefined); + }); + }); +} diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts new file mode 100644 index 00000000000..b7d59e399dd --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts @@ -0,0 +1,121 @@ +import * as assert from "assert"; +import { prepareEnv } from "../../src/run"; +import { RunnableEnvCfg } from "../../src/config"; +import { Context } from "."; +import * as ra from "../../src/lsp_ext"; + +function makeRunnable(label: string): ra.Runnable { + return { + label, + kind: "cargo", + args: { + cargoArgs: [], + executableArgs: [], + cargoExtraArgs: [], + }, + }; +} + +function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> { + const runnable = makeRunnable(runnableName); + return prepareEnv(runnable, config); +} + +export async function getTests(ctx: Context) { + await ctx.suite("Runnable env", (suite) => { + suite.addTest("Global config works", async () => { + const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" }); + assert.strictEqual(binEnv["GLOBAL"], "g"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" }); + assert.strictEqual(testEnv["GLOBAL"], "g"); + }); + + suite.addTest("null mask works", async () => { + const config = [ + { + env: { DATA: "data" }, + }, + ]; + const binEnv = fakePrepareEnv("run project_name", config); + assert.strictEqual(binEnv["DATA"], "data"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.strictEqual(testEnv["DATA"], "data"); + }); + + suite.addTest("order works", async () => { + const config = [ + { + env: { DATA: "data" }, + }, + { + env: { DATA: "newdata" }, + }, + ]; + const binEnv = fakePrepareEnv("run project_name", config); + assert.strictEqual(binEnv["DATA"], "newdata"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.strictEqual(testEnv["DATA"], "newdata"); + }); + + suite.addTest("mask works", async () => { + const config = [ + { + env: { DATA: "data" }, + }, + { + mask: "^run", + env: { DATA: "rundata" }, + }, + { + mask: "special_test$", + env: { DATA: "special_test" }, + }, + ]; + const binEnv = fakePrepareEnv("run project_name", config); + assert.strictEqual(binEnv["DATA"], "rundata"); + + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.strictEqual(testEnv["DATA"], "data"); + + const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); + assert.strictEqual(specialTestEnv["DATA"], "special_test"); + }); + + suite.addTest("exact test name works", async () => { + const config = [ + { + env: { DATA: "data" }, + }, + { + mask: "some::mod::test_name", + env: { DATA: "test special" }, + }, + ]; + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.strictEqual(testEnv["DATA"], "test special"); + + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.strictEqual(specialTestEnv["DATA"], "data"); + }); + + suite.addTest("test mod name works", async () => { + const config = [ + { + env: { DATA: "data" }, + }, + { + mask: "some::mod", + env: { DATA: "mod special" }, + }, + ]; + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.strictEqual(testEnv["DATA"], "mod special"); + + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.strictEqual(specialTestEnv["DATA"], "mod special"); + }); + }); +} diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts new file mode 100644 index 00000000000..224cea5a232 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts @@ -0,0 +1,61 @@ +import * as assert from "assert"; +import { Context } from "."; +import { substituteVariablesInEnv } from "../../src/config"; + +export async function getTests(ctx: Context) { + await ctx.suite("Server Env Settings", (suite) => { + suite.addTest("Replacing Env Variables", async () => { + const envJson = { + USING_MY_VAR: "${env:MY_VAR} test ${env:MY_VAR}", + MY_VAR: "test", + }; + const expectedEnv = { + USING_MY_VAR: "test test test", + MY_VAR: "test", + }; + const actualEnv = await substituteVariablesInEnv(envJson); + assert.deepStrictEqual(actualEnv, expectedEnv); + }); + + suite.addTest("Circular dependencies remain as is", async () => { + const envJson = { + A_USES_B: "${env:B_USES_A}", + B_USES_A: "${env:A_USES_B}", + C_USES_ITSELF: "${env:C_USES_ITSELF}", + D_USES_C: "${env:C_USES_ITSELF}", + E_IS_ISOLATED: "test", + F_USES_E: "${env:E_IS_ISOLATED}", + }; + const expectedEnv = { + A_USES_B: "${env:B_USES_A}", + B_USES_A: "${env:A_USES_B}", + C_USES_ITSELF: "${env:C_USES_ITSELF}", + D_USES_C: "${env:C_USES_ITSELF}", + E_IS_ISOLATED: "test", + F_USES_E: "test", + }; + const actualEnv = await substituteVariablesInEnv(envJson); + assert.deepStrictEqual(actualEnv, expectedEnv); + }); + + suite.addTest("Should support external variables", async () => { + const envJson = { + USING_EXTERNAL_VAR: "${env:TEST_VARIABLE} test ${env:TEST_VARIABLE}", + }; + const expectedEnv = { + USING_EXTERNAL_VAR: "test test test", + }; + + const actualEnv = await substituteVariablesInEnv(envJson); + assert.deepStrictEqual(actualEnv, expectedEnv); + }); + + suite.addTest("should support VSCode variables", async () => { + const envJson = { + USING_VSCODE_VAR: "${workspaceFolderBasename}", + }; + const actualEnv = await substituteVariablesInEnv(envJson); + assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, "code"); + }); + }); +} diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json b/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json new file mode 100644 index 00000000000..5e2b33ca39f --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tsconfig.eslint.json @@ -0,0 +1,11 @@ +// Special typescript project file, used by eslint only. +{ + "extends": "./tsconfig.json", + "include": [ + // repeated from base config's "include" setting + "src", + "tests", + // these are the eslint-only inclusions + ".eslintrc.js" + ] +} diff --git a/src/tools/rust-analyzer/editors/code/tsconfig.json b/src/tools/rust-analyzer/editors/code/tsconfig.json new file mode 100644 index 00000000000..42e2846858a --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2021", + "outDir": "out", + "lib": ["es2021"], + "sourceMap": true, + "rootDir": ".", + "strict": true, + "useUnknownInCatchVariables": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "newLine": "LF" + }, + "exclude": ["node_modules", ".vscode-test"], + "include": ["src", "tests"] +} |
