From 9195ad08e493828b2229aa9f3f38edf26b45aae0 Mon Sep 17 00:00:00 2001 From: aboyko Date: Fri, 19 Jan 2024 15:21:49 -0500 Subject: [PATCH] [vscode-spring-cli] prepare to fetch data from CLI. Polish commands: boot, project, project-catalog --- .../vscode-spring-cli/.vscodeignore | 11 + .../vscode-spring-cli/package-lock.json | 381 ++++++++++++------ .../vscode-spring-cli/package.json | 14 +- .../vscode-spring-cli/src/boot.ts | 44 +- .../vscode-spring-cli/src/cli-types.ts | 2 +- .../vscode-spring-cli/src/cli.ts | 126 +++--- .../vscode-spring-cli/src/project-catalog.ts | 46 +-- .../vscode-spring-cli/src/project.ts | 19 +- .../vscode-spring-cli/src/utils.ts | 18 +- 9 files changed, 420 insertions(+), 241 deletions(-) create mode 100644 vscode-extensions/vscode-spring-cli/.vscodeignore diff --git a/vscode-extensions/vscode-spring-cli/.vscodeignore b/vscode-extensions/vscode-spring-cli/.vscodeignore new file mode 100644 index 000000000..5344adad2 --- /dev/null +++ b/vscode-extensions/vscode-spring-cli/.vscodeignore @@ -0,0 +1,11 @@ +# IDE configs +.vscode/** +.idea/** +*.iml + +# Logs +*.log* + +# Extensions +.gitignore +**/*.map \ No newline at end of file diff --git a/vscode-extensions/vscode-spring-cli/package-lock.json b/vscode-extensions/vscode-spring-cli/package-lock.json index 936dd5282..1bdd44fbb 100644 --- a/vscode-extensions/vscode-spring-cli/package-lock.json +++ b/vscode-extensions/vscode-spring-cli/package-lock.json @@ -8,17 +8,36 @@ "name": "vscode-spring-cli", "version": "1.52.0", "license": "EPL-1.0", + "dependencies": { + "lodash.debounce": "4.0.8" + }, "devDependencies": { + "@types/lodash.debounce": "4.0.9", "@types/node": "^18.8.0", "@types/vscode": "1.75.0", - "typescript": "^4.8.0", - "vsce": "^2.15.0" + "@vscode/vsce": "^2.22.0", + "typescript": "^4.8.0" }, "engines": { "npm": ">=6.0.0", "vscode": "^1.75.0" } }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, + "node_modules/@types/lodash.debounce": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz", + "integrity": "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "18.19.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.4.tgz", @@ -34,6 +53,71 @@ "integrity": "sha512-SAr0PoOhJS6FUq5LjNr8C/StBKALZwDVm3+U4pjF/3iYkt3GioJOPV/oB1Sf1l7lROe4TgrMyL5N1yaEgTWycw==", "dev": true }, + "node_modules/@vscode/vsce": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.22.0.tgz", + "integrity": "sha512-8df4uJiM3C6GZ2Sx/KilSKVxsetrTBBIUb3c0W4B1EWHcddioVs5mkyDKtMNP0khP/xBILVSzlXxhV+nm2rC9A==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.2.1", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.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": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vscode/vsce/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -86,13 +170,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "optional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -134,6 +220,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -218,7 +305,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "dev": true, + "optional": true }, "node_modules/color-convert": { "version": "1.9.3", @@ -283,6 +371,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "optional": true, "dependencies": { "mimic-response": "^3.1.0" }, @@ -298,6 +387,7 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, + "optional": true, "engines": { "node": ">=4.0.0" } @@ -321,6 +411,7 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "dev": true, + "optional": true, "engines": { "node": ">=8" } @@ -385,6 +476,7 @@ "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, + "optional": true, "dependencies": { "once": "^1.4.0" } @@ -415,6 +507,7 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, + "optional": true, "engines": { "node": ">=6" } @@ -432,7 +525,8 @@ "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 + "dev": true, + "optional": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -468,7 +562,8 @@ "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 + "dev": true, + "optional": true }, "node_modules/glob": { "version": "7.2.3", @@ -608,7 +703,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/inflight": { "version": "1.0.6", @@ -630,6 +726,13 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "node_modules/keytar": { @@ -638,6 +741,7 @@ "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", "dev": true, "hasInstallScript": true, + "optional": true, "dependencies": { "node-addon-api": "^4.3.0", "prebuild-install": "^7.0.1" @@ -661,6 +765,11 @@ "uc.micro": "^1.0.1" } }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -721,6 +830,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, + "optional": true, "engines": { "node": ">=10" }, @@ -745,6 +855,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -753,7 +864,8 @@ "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 + "dev": true, + "optional": true }, "node_modules/mute-stream": { "version": "0.0.8", @@ -765,13 +877,15 @@ "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 + "dev": true, + "optional": true }, "node_modules/node-abi": { "version": "3.54.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", "dev": true, + "optional": true, "dependencies": { "semver": "^7.3.5" }, @@ -784,6 +898,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "optional": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -798,7 +913,8 @@ "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 + "dev": true, + "optional": true }, "node_modules/nth-check": { "version": "2.1.1", @@ -884,6 +1000,7 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", "dev": true, + "optional": true, "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -910,6 +1027,7 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "optional": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -935,6 +1053,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, + "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -962,6 +1081,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1004,7 +1124,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/sax": { "version": "1.3.0", @@ -1068,7 +1189,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/simple-get": { "version": "4.0.1", @@ -1089,6 +1211,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -1100,6 +1223,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "optional": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -1109,6 +1233,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, + "optional": true, "engines": { "node": ">=0.10.0" } @@ -1130,6 +1255,7 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, + "optional": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -1142,6 +1268,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -1179,6 +1306,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "optional": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -1238,42 +1366,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/vsce": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz", - "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==", - "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.", "dev": true, - "dependencies": { - "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" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - } + "optional": true }, "node_modules/wrappy": { "version": "1.0.2", @@ -1281,19 +1375,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/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, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", @@ -1330,6 +1411,21 @@ } }, "dependencies": { + "@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, + "@types/lodash.debounce": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz", + "integrity": "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/node": { "version": "18.19.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.4.tgz", @@ -1345,6 +1441,56 @@ "integrity": "sha512-SAr0PoOhJS6FUq5LjNr8C/StBKALZwDVm3+U4pjF/3iYkt3GioJOPV/oB1Sf1l7lROe4TgrMyL5N1yaEgTWycw==", "dev": true }, + "@vscode/vsce": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.22.0.tgz", + "integrity": "sha512-8df4uJiM3C6GZ2Sx/KilSKVxsetrTBBIUb3c0W4B1EWHcddioVs5mkyDKtMNP0khP/xBILVSzlXxhV+nm2rC9A==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.2.1", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "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": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + } + } + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -1380,13 +1526,15 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "dev": true, + "optional": true }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "optional": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -1414,6 +1562,7 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, + "optional": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -1480,7 +1629,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "dev": true, + "optional": true }, "color-convert": { "version": "1.9.3", @@ -1533,6 +1683,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "optional": true, "requires": { "mimic-response": "^3.1.0" } @@ -1541,7 +1692,8 @@ "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 + "dev": true, + "optional": true }, "define-data-property": { "version": "1.1.1", @@ -1558,7 +1710,8 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "dev": true + "dev": true, + "optional": true }, "dom-serializer": { "version": "2.0.0", @@ -1602,6 +1755,7 @@ "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, + "optional": true, "requires": { "once": "^1.4.0" } @@ -1622,7 +1776,8 @@ "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 + "dev": true, + "optional": true }, "fd-slicer": { "version": "1.1.0", @@ -1637,7 +1792,8 @@ "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 + "dev": true, + "optional": true }, "fs.realpath": { "version": "1.0.0", @@ -1667,7 +1823,8 @@ "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 + "dev": true, + "optional": true }, "glob": { "version": "7.2.3", @@ -1753,7 +1910,8 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "dev": true, + "optional": true }, "inflight": { "version": "1.0.6", @@ -1775,6 +1933,13 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "keytar": { @@ -1782,6 +1947,7 @@ "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", "dev": true, + "optional": true, "requires": { "node-addon-api": "^4.3.0", "prebuild-install": "^7.0.1" @@ -1802,6 +1968,11 @@ "uc.micro": "^1.0.1" } }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1848,7 +2019,8 @@ "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 + "dev": true, + "optional": true }, "minimatch": { "version": "3.1.2", @@ -1863,13 +2035,15 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "dev": true, + "optional": true }, "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 + "dev": true, + "optional": true }, "mute-stream": { "version": "0.0.8", @@ -1881,13 +2055,15 @@ "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 + "dev": true, + "optional": true }, "node-abi": { "version": "3.54.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", "dev": true, + "optional": true, "requires": { "semver": "^7.3.5" }, @@ -1897,6 +2073,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "optional": true, "requires": { "lru-cache": "^6.0.0" } @@ -1907,7 +2084,8 @@ "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 + "dev": true, + "optional": true }, "nth-check": { "version": "2.1.1", @@ -1978,6 +2156,7 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", "dev": true, + "optional": true, "requires": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -1998,6 +2177,7 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -2017,6 +2197,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, + "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -2038,6 +2219,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "optional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2057,7 +2239,8 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "dev": true, + "optional": true }, "sax": { "version": "1.3.0", @@ -2098,13 +2281,15 @@ "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 + "dev": true, + "optional": 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, + "optional": true, "requires": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -2116,6 +2301,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.2.0" } @@ -2124,7 +2310,8 @@ "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 + "dev": true, + "optional": true }, "supports-color": { "version": "5.5.0", @@ -2140,6 +2327,7 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, + "optional": true, "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -2152,6 +2340,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "optional": true, "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -2180,6 +2369,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -2229,35 +2419,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "vsce": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz", - "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==", "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" - } + "optional": true }, "wrappy": { "version": "1.0.2", @@ -2265,16 +2428,6 @@ "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", diff --git a/vscode-extensions/vscode-spring-cli/package.json b/vscode-extensions/vscode-spring-cli/package.json index 6373fb51a..97ac8e2c0 100644 --- a/vscode-extensions/vscode-spring-cli/package.json +++ b/vscode-extensions/vscode-spring-cli/package.json @@ -72,7 +72,17 @@ "title": "Remove Project", "category": "Spring CLI" } - ] + ], + "configuration": { + "title": "Spring CLI", + "properties": { + "spring-cli.executable": { + "type": "string", + "default": "spring", + "description": "Spring CLI executable. Either name of the executable if it's on the PATH environment variable or absolute path to the spring CLI executable (or JAR for dev purposes)" + } + } + } }, "main": "./out/extension", "scripts": { @@ -84,8 +94,10 @@ "vsce-pre-release-package": "vsce package --pre-release" }, "dependencies": { + "lodash.debounce": "^4.0.8" }, "devDependencies": { + "@types/lodash.debounce": "^4.0.9", "@types/node": "^18.8.0", "@types/vscode": "1.75.0", "typescript": "^4.8.0", diff --git a/vscode-extensions/vscode-spring-cli/src/boot.ts b/vscode-extensions/vscode-spring-cli/src/boot.ts index 0c4cf58ae..2496d576d 100644 --- a/vscode-extensions/vscode-spring-cli/src/boot.ts +++ b/vscode-extensions/vscode-spring-cli/src/boot.ts @@ -2,26 +2,29 @@ import * as path from "path"; import { BootAddMetadata, BootNewMetadata, Project } from "./cli-types"; import { CLI } from "./extension"; import { enterText, getTargetPomXml, mapProjectToQuickPick, openDialogForFolder } from "./utils"; -import vscode, { QuickPickItem, QuickPickItemKind } from 'vscode'; +import { Uri, commands, window, workspace } from 'vscode'; import fs from 'fs' const OPEN_IN_NEW_WORKSPACE = "Open"; const OPEN_IN_CURRENT_WORKSPACE = "Add to Workspace"; -export async function handleBootAdd(pom?: vscode.Uri): Promise { +export async function handleBootAdd(pom?: Uri): Promise { const metadata: BootAddMetadata = {}; pom = pom || await getTargetPomXml(); if (pom) { metadata.targetFolder = path.dirname(pom.fsPath); } if (!metadata.targetFolder) { - vscode.window.showErrorMessage("Spring-CLI Boot Add command requires a target project"); + window.showErrorMessage("Spring-CLI Boot Add command requires a target project"); return; } - if (!metadata.catalogType) { - metadata.catalogType = (await vscode.window.showQuickPick(CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)), { canPickMany: false, ignoreFocusOut: true }))?.label; + if (!metadata.catalog) { + const fetchProjects = CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)); + metadata.catalog = (await window.showQuickPick(fetchProjects, { canPickMany: false, ignoreFocusOut: true }))?.label; + } + if (metadata.catalog) { + return CLI.bootAdd(metadata); } - return CLI.bootAdd(metadata); } export async function handleBootNew(targetFolder?: string): Promise { @@ -31,7 +34,8 @@ export async function handleBootNew(targetFolder?: string): Promise { metadata.targetFolder = targetFolder || (await openDialogForFolder({title: "Select Parent Folder"})).fsPath; // Select project type from the list of available types - metadata.catalogId = (await vscode.window.showQuickPick(CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)), { canPickMany: false }))?.label; + const fetchProjects = CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)); + metadata.catalogId = (await window.showQuickPick(fetchProjects, { canPickMany: false }))?.label; if (!metadata.catalogId) { // Cancelled @@ -43,7 +47,7 @@ export async function handleBootNew(targetFolder?: string): Promise { title: "Project Name", prompt: "Enter Project Name", defaultValue: metadata.name || metadata.catalogId, - validate: value => { + validate: async value => { if (!/^[a-z_][a-z0-9_]*(-[a-z_][a-z0-9_]*)*$/.test(value)) { return "Invalid Project Name"; } @@ -57,22 +61,22 @@ export async function handleBootNew(targetFolder?: string): Promise { title: "Artifact Id", prompt: "Enter Artifact Id", defaultValue: metadata.name, - validate: value => (/^[a-z_][a-z0-9_]*(-[a-z_][a-z0-9_]*)*$/.test(value)) ? undefined : "Invalid Artifact Id" + validate: async value => (/^[a-z_][a-z0-9_]*(-[a-z_][a-z0-9_]*)*$/.test(value)) ? undefined : "Invalid Artifact Id" }); metadata.groupId = await enterText({ title: "Group Id", prompt: "Enter Group Id", defaultValue: "com.example", - validate: value => (/^[a-z_][a-z0-9_]*(\.[a-z0-9_]+)*$/.test(value)) ? undefined : "Invalid Group Id" + validate: async value => (/^[a-z_][a-z0-9_]*(\.[a-z0-9_]+)*$/.test(value)) ? undefined : "Invalid Group Id" }); // Root package name metadata.rootPackage = await enterText({ title: "Root Package Name", prompt: "Enter Root Package Name", - defaultValue: `${metadata.groupId}.${metadata.name.replace("-", ".")}`, - validate: value => (/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$/.test(value)) ? undefined : "Invalid Package Name" + defaultValue: `${metadata.groupId}.${metadata.name.toLowerCase().replace(/(-|_)+/g, ".")}`, + validate: async value => (/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$/.test(value)) ? undefined : "Invalid Package Name" }); } catch (error) { // Cancelled @@ -85,21 +89,21 @@ export async function handleBootNew(targetFolder?: string): Promise { await CLI.bootNew(metadata); // Open project either is the same workspace or new workspace - const hasOpenFolder = vscode.workspace.workspaceFolders !== undefined || vscode.workspace.rootPath !== undefined; + const hasOpenFolder = workspace.workspaceFolders !== undefined || workspace.rootPath !== undefined; const pathToOpen = path.resolve(metadata.targetFolder, metadata.name); // Don't prompt to open projectLocation if it's already a currently opened folder - if (hasOpenFolder && (vscode.workspace.workspaceFolders.some(folder => folder.uri.fsPath === pathToOpen) || vscode.workspace.rootPath === pathToOpen)) { + if (hasOpenFolder && (workspace.workspaceFolders.some(folder => folder.uri.fsPath === pathToOpen) || workspace.rootPath === pathToOpen)) { return; } - const choice = await specifyOpenMethod(hasOpenFolder, vscode.Uri.file(pathToOpen)) + const choice = await specifyOpenMethod(hasOpenFolder, Uri.file(pathToOpen)) if (choice === OPEN_IN_NEW_WORKSPACE) { - vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(pathToOpen), hasOpenFolder); + commands.executeCommand("vscode.openFolder", Uri.file(pathToOpen), hasOpenFolder); } else if (choice === OPEN_IN_CURRENT_WORKSPACE) { - if (!vscode.workspace.workspaceFolders.find((workspaceFolder) => workspaceFolder.uri && pathToOpen.startsWith(workspaceFolder.uri.fsPath))) { - vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders.length, null, { uri: vscode.Uri.file(pathToOpen) }); + if (!workspace.workspaceFolders.find((workspaceFolder) => workspaceFolder.uri && pathToOpen.startsWith(workspaceFolder.uri.fsPath))) { + workspace.updateWorkspaceFolders(workspace.workspaceFolders.length, null, { uri: Uri.file(pathToOpen) }); } } } @@ -107,10 +111,10 @@ export async function handleBootNew(targetFolder?: string): Promise { } -async function specifyOpenMethod(hasOpenFolder: boolean, projectLocation: vscode.Uri): Promise { +async function specifyOpenMethod(hasOpenFolder: boolean, projectLocation: Uri): Promise { const candidates: string[] = [ OPEN_IN_NEW_WORKSPACE, hasOpenFolder ? OPEN_IN_CURRENT_WORKSPACE : undefined, ].filter(Boolean); - return await vscode.window.showInformationMessage(`Successfully generated. Location: ${projectLocation.fsPath}`, ...candidates); + return await window.showInformationMessage(`Successfully generated. Location: ${projectLocation.fsPath}`, ...candidates); } diff --git a/vscode-extensions/vscode-spring-cli/src/cli-types.ts b/vscode-extensions/vscode-spring-cli/src/cli-types.ts index 15684385d..b50f8f557 100644 --- a/vscode-extensions/vscode-spring-cli/src/cli-types.ts +++ b/vscode-extensions/vscode-spring-cli/src/cli-types.ts @@ -17,7 +17,7 @@ export interface BootNewMetadata { export interface BootAddMetadata { targetFolder?: string; - catalogType?: string; + catalog?: string; } export interface ProjectCatalog { diff --git a/vscode-extensions/vscode-spring-cli/src/cli.ts b/vscode-extensions/vscode-spring-cli/src/cli.ts index 1b7fd28f3..9090825ec 100644 --- a/vscode-extensions/vscode-spring-cli/src/cli.ts +++ b/vscode-extensions/vscode-spring-cli/src/cli.ts @@ -1,68 +1,31 @@ import { BootAddMetadata, BootNewMetadata, Project, ProjectCatalog } from "./cli-types"; -import vscode, { TaskScope } from "vscode"; +import { ProcessExecution, ProgressLocation, Task, TaskScope, Uri, env, tasks, window, workspace } from "vscode"; +import cp from "child_process"; +import { homedir } from "os"; +import { getWorkspaceRoot } from "./utils"; const SPRING_CLI_TASK_TYPE = 'spring-cli'; export class Cli { - projectList() : Thenable { - return Promise.resolve([ - { - name: 'web', - description: 'Hello, World RESTful web service.', - url: 'https://github.com/rd-1-2022/rest-service', - catalog: 'gs', - tags: ['java-17', 'boot-3.1.x', 'rest', 'web'] - }, - { - name: 'jpa', - description: 'Learn how to work with JPA data persistence using Spring Data JPA.', - url: 'https://github.com/rd-1-2022/rpt-spring-data-jpa', - catalog: 'gs', - tags: ['java-17', 'boot-3.1.x', 'jpa', 'h2'] - }, - { - name: 'scheduling', - description: 'How to schedule tasks', - url: 'https://github.com/rd-1-2022/rpt-spring-scheduling-tasks', - catalog: 'gs', - tags: ['scheduling'] - } - ]); + private get executable(): string { + return workspace.getConfiguration("spring-cli").get("executable") || "spring"; } - projectCatalogList(): Thenable { - return Promise.resolve([ - { - name: "gs", - url: "https://github.com/rd-1-2022/spring-gs-catalog", - description: "Getting Started Catalog", - tags: ["java-17", "boot-3.1"] - }, - { - name: "ai-azure", - url: "https://github.com/rd-1-2022/ai-azure-catalog", - description: "Azure OpenAI Catalog", - tags: ["java-17", "boot-3.1.x", "ai", "azure"] - } - ]); + isBorderLine(s: string) { + return !/(\s|\S)+/.test(s); } - projectCatalogListAvailable(): Thenable { - return Promise.resolve([ - { - name: "ai-azure", - url: "https://github.com/rd-1-2022/ai-azure-catalog", - description: "Azure OpenAI Catalog", - tags: ["java-17", "boot-3.1.x", "ai", "azure"] - }, - { - name: "dapr", - url: "https://github.com/ciberkleid/spring-cli-dapr-catalog", - description: "Dapr Catalog", - tags: ["java-17", "boot-3.1.x", "dapr"] - } - ]); + projectList() : Promise { + return this.fetch("Fetching projects...", undefined, ["project", "list-json"]); + } + + projectCatalogList(): Promise { + return this.fetch("Fetching Catalogs...", undefined, ["project-catalog", "list-json"]); + } + + projectCatalogListAvailable(): Promise { + return this.fetch("Fetching Available Catalogs...", undefined, ["project-catalog", "list-available-json"]); } projectCatalogAdd(catalog: ProjectCatalog): Promise { @@ -154,15 +117,15 @@ export class Cli { "boot", "add", "--from", - metadata.catalogType + metadata.catalog ]; - return this.exec("Add to Boot Project", `'${metadata.catalogType}'`, args, metadata.targetFolder); + return this.exec("Add to Boot Project", `'${metadata.catalog}'`, args, metadata.targetFolder); } private async exec(title: string, message: string, args: string[], cwd?: string): Promise { - return vscode.window.withProgress({ - location: vscode.ProgressLocation.Window, + return window.withProgress({ + location: ProgressLocation.Window, cancellable: true, title }, (progress, cancellation) => { @@ -170,9 +133,10 @@ export class Cli { progress.report({message}); return new Promise(async (resolve, reject) => { - const process = new vscode.ProcessExecution('spring', args, { cwd }); - const task = new vscode.Task({ type: SPRING_CLI_TASK_TYPE}, cwd ? vscode.workspace.getWorkspaceFolder(vscode.Uri.file(cwd)) : TaskScope.Global, `${title}: ${message}`, SPRING_CLI_TASK_TYPE, process); - const taskExecution = await vscode.tasks.executeTask(task); + const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() }; + const process = this.executable.endsWith(".jar") ? new ProcessExecution("java", [ "-jar", this.executable, ...args], processOpts) : new ProcessExecution(this.executable, args, processOpts); + const task = new Task({ type: SPRING_CLI_TASK_TYPE}, cwd ? workspace.getWorkspaceFolder(Uri.file(cwd)) : TaskScope.Global, `${title}: ${message}`, SPRING_CLI_TASK_TYPE, process); + const taskExecution = await tasks.executeTask(task); if (cancellation.isCancellationRequested) { reject(); } @@ -180,7 +144,7 @@ export class Cli { cancelListener.dispose(); reject(); }) - const listener = vscode.tasks.onDidEndTaskProcess(e => { + const listener = tasks.onDidEndTaskProcess(e => { if (e.execution === taskExecution) { listener.dispose(); resolve(); @@ -191,5 +155,41 @@ export class Cli { }); } + private async fetch(title: string, message: string, args: string[], cwd?: string) : Promise { + + return window.withProgress({ + location: ProgressLocation.Window, + cancellable: true, + title + }, (progress, cancellation) => { + + if (message) { + progress.report({message}); + } + + return new Promise(async (resolve, reject) => { + if (cancellation.isCancellationRequested) { + reject("Cancelled"); + } + const processOpts = { cwd: cwd || getWorkspaceRoot()?.fsPath || homedir() }; + const process = this.executable.endsWith(".jar") ? await cp.exec(`java -jar ${this.executable} ${args.join(" ")}`, processOpts) : await cp.exec(`${this.executable} ${args.join(" ")}`, processOpts); + cancellation.onCancellationRequested(() => process.kill()); + const dataChunks: string[] = []; + process.stdout.on("data", s => dataChunks.push(s)); + process.on("exit", (code) => { + if (code) { + reject(`Failed to fetch data: ${dataChunks.join()}`); + } else { + try { + resolve(JSON.parse(dataChunks.join()) as T); + } catch (error) { + reject(error); + } + } + }); + }); + }); + } + } diff --git a/vscode-extensions/vscode-spring-cli/src/project-catalog.ts b/vscode-extensions/vscode-spring-cli/src/project-catalog.ts index 1132db3fd..06f6c8c83 100644 --- a/vscode-extensions/vscode-spring-cli/src/project-catalog.ts +++ b/vscode-extensions/vscode-spring-cli/src/project-catalog.ts @@ -3,7 +3,7 @@ import { CLI } from "./extension"; import { window, QuickPickItem, Uri } from "vscode"; import { enterText } from "./utils"; -interface ProjectCatalogQuickPick extends QuickPickItem { +interface ProjectCatalogQuickPickItem extends QuickPickItem { projectCatalog: ProjectCatalog; } @@ -18,18 +18,18 @@ export async function handleCatalogAdd() { let currentCatalogNames = []; // Select from available project catalog - currentle added project ctalogs - let catalog = await pickCatalog(async () => { - const [available, current] = await Promise.all([CLI.projectCatalogListAvailable(), CLI.projectCatalogList()]); + const itemsPromise = Promise.all([CLI.projectCatalogListAvailable(), CLI.projectCatalogList()]).then(([available, current]) => { const currentCatalogNames = current.map(c => c.name); - return [CUSTOM_CATALOG, ...available.filter(a => !currentCatalogNames.includes(a.name))]; + return [CUSTOM_CATALOG, ...available.filter(a => !currentCatalogNames.includes(a.name))].map(mapCatalogToQuickPickItem); }); + let catalog = (await window.showQuickPick(itemsPromise, { ignoreFocusOut: true, canPickMany: false}))?.projectCatalog; if (catalog === CUSTOM_CATALOG) { // No available catalog selected enter the catalog manually const name = await enterText({ title: "Name", prompt: "Enter Name:", - validate: v => { + validate: async v => { if (!/^\S+$/.test(v)) { return "Invalid Project Catalog Name"; } @@ -42,7 +42,7 @@ export async function handleCatalogAdd() { title: "URL", prompt: "Enter URL:", placeholder: "https://github.com/my-org/my-project-catalog", - validate: v => { + validate: async v => { try { Uri.parse(v, true); } catch (error) { @@ -68,33 +68,17 @@ export async function handleCatalogAdd() { } export async function handleCatalogRemove() { - const catalog = await pickCatalog(CLI.projectCatalogList); + const itemsPromise = CLI.projectCatalogList().then(catalogs => catalogs.map(mapCatalogToQuickPickItem)); + const catalog = (await window.showQuickPick(itemsPromise, { ignoreFocusOut: true, canPickMany: false}))?.projectCatalog; if (catalog) { return CLI.projectCatalogRemove(catalog.name); } } -async function pickCatalog(fetch: () => Thenable): Promise { - return new Promise(async (resolve, reject) => { - const quickPick = window.createQuickPick(); - quickPick.busy = true; - quickPick.title = "Loading Project Catalogs..."; - quickPick.canSelectMany = false; - quickPick.show(); - const catalogs = await fetch(); - - quickPick.items = catalogs.map(c => ({ - label: c.name, - description: c.description, - details: c.tags ? c.tags.join(", ") : undefined, - projectCatalog: c - })); - quickPick.title = "Select Project Catalog"; - quickPick.busy = false; - - quickPick.onDidAccept(() => { - resolve(quickPick.selectedItems.length ? quickPick.selectedItems[0].projectCatalog : undefined); - quickPick.hide(); - }); - }); -} \ No newline at end of file +function mapCatalogToQuickPickItem(c: ProjectCatalog): ProjectCatalogQuickPickItem { + return { + label: c.name, + description: c.description, + projectCatalog: c + }; +} diff --git a/vscode-extensions/vscode-spring-cli/src/project.ts b/vscode-extensions/vscode-spring-cli/src/project.ts index 008595859..03ba712b2 100644 --- a/vscode-extensions/vscode-spring-cli/src/project.ts +++ b/vscode-extensions/vscode-spring-cli/src/project.ts @@ -5,15 +5,15 @@ import { CLI } from "./extension"; export async function handleProjectAdd() { try { - const currentProjectNames = (await CLI.projectList()).map(p => p.name); + const currentProjectNamesPromise = CLI.projectList().then(projects => projects.map(p => p.name)); const name = await enterText({ title: "Name", prompt: "Enter Name:", - validate: v => { + validate: async v => { if (!/^\S+$/.test(v)) { return "Invalid Project Catalog Name"; } - if (currentProjectNames.includes(v)) { + if ((await currentProjectNamesPromise).includes(v)) { return "Name alreasy exists" } } @@ -22,7 +22,7 @@ export async function handleProjectAdd() { title: "URL", prompt: "Enter URL:", placeholder: "https://github.com/my-org/my-project", - validate: v => { + validate: async v => { try { Uri.parse(v, true); } catch (error) { @@ -39,6 +39,14 @@ export async function handleProjectAdd() { prompt: "Enter Tags as strings separated by spaces and/or commas", placeholder: "java, spring, eureka, config" })).split(/(,)?\s+/); + if (name && url) { + return CLI.projectAdd({ + name, + url, + description, + tags + }); + } } catch (error) { // Ignore error - must have been cancelled } @@ -46,7 +54,8 @@ export async function handleProjectAdd() { } export async function handleProjectRemove() { - const name = (await window.showQuickPick(CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)), { + const deferred = CLI.projectList().then(ps => ps.map(mapProjectToQuickPick)); + const name = (await window.showQuickPick(deferred, { canPickMany: false, ignoreFocusOut: true, }))?.label; diff --git a/vscode-extensions/vscode-spring-cli/src/utils.ts b/vscode-extensions/vscode-spring-cli/src/utils.ts index 1a65acb85..fe72e0760 100644 --- a/vscode-extensions/vscode-spring-cli/src/utils.ts +++ b/vscode-extensions/vscode-spring-cli/src/utils.ts @@ -1,6 +1,7 @@ -import { InputBox, OpenDialogOptions, QuickPickItem, QuickPickItemKind, Uri, WorkspaceFolder, window, workspace } from "vscode"; +import { InputBox, OpenDialogOptions, QuickPickItem, QuickPickItemKind, Uri, WorkspaceFolder, window, workspace} from "vscode"; import path from "path" import { Project } from "./cli-types"; +import debounce from "lodash.debounce"; export async function openDialogForFolder(customOptions: OpenDialogOptions): Promise { const options: OpenDialogOptions = { @@ -21,7 +22,7 @@ export async function openDialogForFolder(customOptions: OpenDialogOptions): Pro export function enterText(opts: { title: string, prompt: string, - validate?: (v: string) => string | undefined, + validate?: (v: string) => Promise, defaultValue?: string, placeholder?: string }): Promise { @@ -32,10 +33,9 @@ export function enterText(opts: { inputBox.prompt = opts.prompt; inputBox.value = opts.defaultValue; inputBox.ignoreFocusOut = true; - inputBox.onDidChangeValue(() => { - inputBox.validationMessage = opts.validate ? opts.validate(inputBox.value) : undefined; - }); - inputBox.onDidAccept(() => { + inputBox.onDidChangeValue(debounce(async v => inputBox.validationMessage = opts.validate ? await opts.validate(inputBox.value) : undefined, 300)); + inputBox.onDidAccept(async () => { + inputBox.validationMessage = opts.validate ? await opts.validate(inputBox.value) : undefined; if (!inputBox.validationMessage) { resolve(inputBox.value); inputBox.hide(); @@ -96,4 +96,10 @@ export function mapProjectToQuickPick(project: Project): QuickPickItem { }; } +export function getWorkspaceRoot(): Uri | undefined { + if (workspace.workspaceFolders && workspace.workspaceFolders.length) { + return workspace.workspaceFolders[0].uri + } +} +