├── .editorconfig ├── .github ├── dependabot.yaml └── workflows │ ├── release.yml │ └── tests.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── DCO ├── Jenkinsfile ├── LICENSE ├── README.md ├── USAGE_DATA.md ├── docs ├── Features.md ├── JavaFeatures.md ├── PropertiesFeatures.md └── res │ ├── MPFormatter.gif │ ├── MPJavaCodeLens.png │ ├── MPJavaCompletion.gif │ ├── MPJavaHover.gif │ ├── MPJavaNavigation.gif │ ├── MPJavaNavigationConfig.gif │ ├── MPJavaValidationAndQuickFix.gif │ ├── MPJumpToJavaDefinition.gif │ ├── MPPropertiesDetection.png │ ├── MPPropertyCompletion.gif │ ├── MPPropertyHover.gif │ ├── MPPropertyQuickFix.gif │ ├── MPPropertyValueDefinition.gif │ ├── MPShowAsTreeOutline.png │ ├── MPShowAsTreeSetting.png │ └── WorkspaceSymbolsJakartaREST.gif ├── eslint.config.mjs ├── gulpfile.js ├── icons └── logo.png ├── images ├── componentDiagram.png ├── debugConfig.png ├── debugConfigMenu.png ├── deployment.png ├── propertiesSupport.png ├── runDebugger.png ├── runDebuggerVSCodeTests.png └── runExtension.png ├── language-support └── properties-support │ ├── language-configuration.json │ ├── microprofile-properties-injections.tmLanguage.json │ └── microprofile-properties.tmLanguage.json ├── package-lock.json ├── package.json ├── schemas └── package.schema.json ├── src ├── definitions │ ├── commands.ts │ ├── lspCommandKind.ts │ └── microProfileLSRequestNames.ts ├── extension.ts ├── languageServer │ ├── javaServerStarter.ts │ ├── plugin.ts │ └── requirements.ts ├── lsp-commands.ts ├── test │ ├── resources │ │ ├── no-lsp4mp-extension-package.json │ │ └── quarkus-package.json │ ├── runTest.ts │ └── suite │ │ ├── extension.test.ts │ │ ├── index.ts │ │ └── languageServer │ │ ├── documentSelectorPlugin.test.ts │ │ ├── plugin.test.ts │ │ └── requirements.test.ts ├── util │ ├── javaServerMode.ts │ ├── telemetry.ts │ └── workspaceUtils.ts └── yaml │ ├── YamlConstants.ts │ └── YamlSchema.ts ├── tsconfig.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | 22 | [package.json] 23 | indent_style = space 24 | indent_size = 2 25 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "cron" 7 | cronjob: "0 8 * * 2,4" 8 | open-pull-requests-limit: 10 9 | groups: 10 | eslint: 11 | patterns: 12 | - "eslint" 13 | - "@eslint/js" 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build & Release VS Code MicroProfile 2 | 3 | on: 4 | schedule: 5 | - cron: "0 8 * * *" 6 | workflow_dispatch: 7 | inputs: 8 | LSP4MP_TAG: 9 | description: "branch/tag of LSP4MP to build." 10 | type: string 11 | default: master 12 | publishPreRelease: 13 | description: "Publish a pre-release ?" 14 | required: true 15 | type: choice 16 | options: 17 | - "true" 18 | - "false" 19 | default: "true" 20 | publishToMarketPlace: 21 | description: "Publish to VS Code Marketplace ?" 22 | required: true 23 | type: choice 24 | options: 25 | - "true" 26 | - "false" 27 | default: "false" 28 | publishToOVSX: 29 | description: "Publish to OpenVSX Registry ?" 30 | required: true 31 | type: choice 32 | options: 33 | - "true" 34 | - "false" 35 | default: "false" 36 | jobs: 37 | should-build-change: 38 | runs-on: ubuntu-latest 39 | outputs: 40 | repo-cache-hit: ${{ steps.cache-last-commit.outputs.cache-hit }} 41 | steps: 42 | - uses: actions/checkout@v4 43 | with: 44 | repository: "eclipse/lsp4mp" 45 | fetch-depth: 2 46 | path: lsp4mp 47 | - uses: actions/checkout@v4 48 | with: 49 | repository: "redhat-developer/vscode-microprofile" 50 | fetch-depth: 2 51 | path: vscode-microprofile 52 | - run: | 53 | pushd lsp4mp 54 | git rev-parse HEAD >> ../lastCommit 55 | popd 56 | pushd vscode-microprofile 57 | git rev-parse HEAD >> ../lastCommit 58 | - name: Check New Changes 59 | id: cache-last-commit 60 | uses: actions/cache@v4 61 | with: 62 | path: lastCommit 63 | key: lastCommit-${{ hashFiles('lastCommit') }} 64 | packaging-job: 65 | runs-on: ubuntu-latest 66 | needs: should-build-change 67 | if: ${{ needs.should-build-change.outputs.repo-cache-hit != 'true' || github.event_name != 'schedule' }} 68 | steps: 69 | - name: Checkout LSP4MP 70 | uses: actions/checkout@v4 71 | with: 72 | repository: eclipse/lsp4mp 73 | ref: ${{ inputs.LSP4MP_TAG }} 74 | path: lsp4mp 75 | - name: Cache Maven local repository 76 | uses: actions/cache@v4 77 | with: 78 | path: | 79 | ~/.m2/repository 80 | ~/.m2/wrapper 81 | !~/.m2/repository/org/eclipse/lsp4mp 82 | key: maven-local-${{ hashFiles('**/pom.xml') }} 83 | - name: Set Up Java 84 | uses: actions/setup-java@v4 85 | with: 86 | java-version: '21' 87 | distribution: 'adopt' 88 | - name: Check Out VS Code MicroProfile 89 | uses: actions/checkout@v4 90 | with: 91 | path: vscode-microprofile 92 | - name: Set Up NodeJS 93 | uses: actions/setup-node@v4 94 | with: 95 | node-version: '20' 96 | - name: Install NodeJS dependencies 97 | run: npm install -g typescript "@vscode/vsce" "ovsx" 98 | - name: Build Extension 99 | run: | 100 | pushd vscode-microprofile 101 | echo "EXT_VERSION=$(cat package.json | jq -r .version)" >> $GITHUB_ENV 102 | npm install 103 | npm run build 104 | npm run vscode:prepublish 105 | - name: Test vscode-microprofile 106 | run: | 107 | pushd vscode-microprofile 108 | xvfb-run --auto-servernum npm run test --silent 109 | continue-on-error: true 110 | - name: Prepare Pre-Release 111 | if: ${{ github.event_name == 'schedule' || inputs.publishPreRelease == 'true' }} 112 | run: | 113 | pushd vscode-microprofile 114 | npx gulp prepare_pre_release 115 | echo "publishPreReleaseFlag=--pre-release" >> $GITHUB_ENV 116 | - name: Package vscode-microprofile 117 | run: | 118 | pushd vscode-microprofile 119 | vsce package ${{ env.publishPreReleaseFlag }} -o ../vscode-microprofile-${{ env.EXT_VERSION }}-${GITHUB_RUN_NUMBER}.vsix 120 | - name: Upload VSIX Artifacts 121 | uses: actions/upload-artifact@v4 122 | with: 123 | name: vscode-microprofile 124 | path: | 125 | vscode-microprofile-${{ env.EXT_VERSION }}-${{github.run_number}}.vsix 126 | if-no-files-found: error 127 | - name: Publish to GH Release Tab 128 | if: ${{ inputs.publishToMarketPlace == 'true' && inputs.publishToOVSX == 'true' }} 129 | uses: "marvinpinto/action-automatic-releases@919008cf3f741b179569b7a6fb4d8860689ab7f0" 130 | with: 131 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 132 | automatic_release_tag: "${{ env.EXT_VERSION }}" 133 | title: "${{ env.EXT_VERSION }}" 134 | draft: true 135 | files: | 136 | vscode-microprofile-${{ env.EXT_VERSION }}-${{ github.run_number }}.vsix 137 | release-job: 138 | environment: ${{ (inputs.publishToMarketPlace == 'true' || inputs.publishToOVSX == 'true') && 'release' || 'pre-release' }} 139 | runs-on: ubuntu-latest 140 | needs: packaging-job 141 | steps: 142 | - name: Set Up NodeJS 143 | uses: actions/setup-node@v4 144 | with: 145 | node-version: '20' 146 | - name: Install dependencies 147 | run: | 148 | npm install -g typescript "@vscode/vsce" "ovsx" 149 | - name: Download VSIX 150 | uses: actions/download-artifact@v4 151 | - name: Publish to VS Code Marketplace 152 | if: ${{ github.event_name == 'schedule' || inputs.publishToMarketPlace == 'true' || inputs.publishPreRelease == 'true' }} 153 | run: | 154 | vsce publish -p ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} --packagePath vscode-microprofile/vscode-microprofile-*-${GITHUB_RUN_NUMBER}.vsix 155 | - name: Publish to OpenVSX Registry 156 | if: ${{ github.event_name == 'schedule' || inputs.publishToOVSX == 'true' || inputs.publishPreRelease == 'true' }} 157 | run: | 158 | ovsx publish -p ${{ secrets.OVSX_MARKETPLACE_TOKEN }} --packagePath vscode-microprofile/vscode-microprofile-*-${GITHUB_RUN_NUMBER}.vsix 159 | post-release-job: 160 | if: ${{ inputs.publishToMarketPlace == 'true' && inputs.publishToOVSX == 'true' }} 161 | runs-on: ubuntu-latest 162 | needs: release-job 163 | steps: 164 | - name: Check Out VS Code MicroProfile 165 | uses: actions/checkout@v4 166 | - name: Set Up NodeJS 167 | uses: actions/setup-node@v4 168 | with: 169 | node-version: '20' 170 | - name: Upversion for Development 171 | run: | 172 | tag=`npm version --no-git-tag-version patch` 173 | git config --global user.email "vscode-microprofile-bot@users.noreply.github.com" 174 | git config --global user.name "vscode-microprofile-bot" 175 | git commit -am "Upversion to ${tag#v}" 176 | git push origin 177 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | jobs: 4 | tests: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [macos-latest, ubuntu-latest, windows-latest] 9 | include: 10 | - os: macos-latest 11 | label: 'darwin' 12 | - os: ubuntu-latest 13 | label: 'linux' 14 | steps: 15 | - name: Check out repository code 16 | uses: actions/checkout@v2 17 | - uses: actions/setup-node@v2 18 | with: 19 | node-version: '18.15' 20 | - name: Install build tools 21 | run: npm i -g vsce 22 | - name: Install dependencies 23 | run: npm i 24 | - name: Compile extension 25 | run: npm run vscode:prepublish 26 | - run: vsce package 27 | - name: eslint 28 | run: npm run eslint 29 | - name: Tests 30 | run: xvfb-run --auto-servernum npm run test --silent 31 | if: runner.os == 'Linux' 32 | - name: Tests 33 | run: npm run test --slient 34 | if: runner.os != 'Linux' 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | test-resources 3 | dist 4 | server/** 5 | jars/** 6 | node_modules 7 | .vscode-test/ 8 | *.vsix 9 | .DS_Store 10 | 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "amodio.tsl-problem-matcher" 7 | ] 8 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "env": { 17 | "VSCODE_REDHAT_TELEMETRY_DEBUG": "true" 18 | }, 19 | "outFiles": [ 20 | "${workspaceFolder}/dist/**/*.js" 21 | ], 22 | "preLaunchTask": "npm: watch" 23 | }, 24 | { 25 | "name": "Run Extension & Wait for remote debugger", 26 | "type": "extensionHost", 27 | "request": "launch", 28 | "runtimeExecutable": "${execPath}", 29 | "args": [ 30 | "--extensionDevelopmentPath=${workspaceRoot}" 31 | ], 32 | "outFiles": [ 33 | "${workspaceRoot}/dist/**/*.js" 34 | ], 35 | "preLaunchTask": "npm: watch", 36 | "env": { 37 | "SUSPEND_SERVER": "true" 38 | } 39 | }, 40 | { 41 | "name": "Extension Tests", 42 | "type": "extensionHost", 43 | "request": "launch", 44 | "runtimeExecutable": "${execPath}", 45 | "args": [ 46 | "--extensionDevelopmentPath=${workspaceFolder}", 47 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 48 | ], 49 | "outFiles": [ 50 | "${workspaceFolder}/out/test/**/*.js" 51 | ], 52 | "preLaunchTask": "npm: pretest" 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true, // set this to false to include "out" folder in search results 8 | ".vscode-test": true, 9 | "dist": true, 10 | }, 11 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 12 | "typescript.tsc.autoDetect": "off" 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": [ 10 | "$ts-webpack-watch", 11 | "$eslint-stylish" 12 | ], 13 | "isBackground": true, 14 | "presentation": { 15 | "reveal": "never" 16 | }, 17 | "group": { 18 | "kind": "build", 19 | "isDefault": true 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .gitignore 3 | .travis.yml 4 | .vscode-test/ 5 | node_modules/ 6 | src/ 7 | out/ 8 | images/ 9 | tsconfig.json 10 | webpack.config.js 11 | test-resources/** 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Tools for MicroProfile Changelog 2 | 3 | ## [0.14.0](https://github.com/redhat-developer/vscode-microprofile/milestone/15?closed=1) (April 22, 2025) 4 | 5 | ### Performance 6 | * Skip making a fake project if only sources are being scanned. See [eclipse-lsp4mp/lsp4mp#494](https://github.com/eclipse-lsp4mp/lsp4mp/pull/494). 7 | 8 | ### Bug Fixes 9 | * Do not suggest method or field snippets when the cursor is outside the top level type declaration. See [eclipse-lsp4mp/lsp4mp#476](https://github.com/eclipse-lsp4mp/lsp4mp/pull/476). 10 | * Guard against annotation binding failing to resolve. See [eclipse-lsp4mp/lsp4mp#492](https://github.com/eclipse-lsp4mp/lsp4mp/pull/492). 11 | * Fix cases where the JDT component would sometimes fail to find an inner class. See [eclipse-lsp4mp/lsp4mp#479](https://github.com/eclipse-lsp4mp/lsp4mp/pull/479), [#480](https://github.com/eclipse-lsp4mp/lsp4mp/pull/480). 12 | 13 | ## [0.13.0](https://github.com/redhat-developer/vscode-microprofile/milestone/14?closed=1) (October 22, 2024) 14 | 15 | ### Bug Fixes 16 | 17 | - Cannot publish to OpenVSX due to out of date NodeJS. See [#303](https://github.com/redhat-developer/vscode-microprofile/issues/303). 18 | - Codelens for REST endpoints should resolve variable references. See [lsp4mp#467](https://github.com/eclipse/lsp4mp/pull/467). 19 | - Prevent duplicate properties when generating them. See [lsp4mp#465](https://github.com/eclipse/lsp4mp/pull/465). 20 | - Prevent error on empty name symbol. See [lsp4mp#462](https://github.com/eclipse/lsp4mp/pull/462). 21 | 22 | ### Build 23 | 24 | - Bump webpack from 5.94.0 to 5.95.0. See [#296](https://github.com/redhat-developer/vscode-microprofile/pull/296). 25 | - Update vscode-redhat-telemetry to 0.9.0. See [#293](https://github.com/redhat-developer/vscode-microprofile/pull/293). 26 | - Update NodeJS in CD pipeline to NodeJS 20. See [#304](https://github.com/redhat-developer/vscode-microprofile/pull/304). 27 | 28 | ## [0.12.0](https://github.com/redhat-developer/vscode-microprofile/milestone/13?closed=1) (August 26, 2024) 29 | 30 | ### Enhancements 31 | 32 | - Resolve system properties/environment variables while browsing the application.properties values. See [eclipse/lsp4mp#448](https://github.com/eclipse/lsp4mp/issues/448). 33 | - Add support for @Startup healthcheck diagnostic. See [eclipse/lsp4mp#443](https://github.com/eclipse/lsp4mp/issues/443). 34 | 35 | ### Bug Fixes 36 | 37 | - NPE with Workspace Symbol when LSP client return null as SymbolInformation List. See [eclipse/lsp4mp#457](https://github.com/eclipse/lsp4mp/pull/457). 38 | - Unrecognized property mp.messaging.* when Channel annotation is used along with Multi. See [eclipse/lsp4mp#451](https://github.com/eclipse/lsp4mp/pull/451). 39 | - fix: synchronized projectLabels + collect codeLens when project is loaded. See [eclipse/lsp4mp#444](https://github.com/eclipse/lsp4mp/pull/444). 40 | 41 | ### Build 42 | 43 | - Set encoding as false for gulp.src to treat content as binary.. See [#209](https://github.com/redhat-developer/vscode-microprofile/pull/209). 44 | - Update eclipse.jdt.ls to 1.39.0-SNAPSHOT. See [eclipse/lsp4mp#454](https://github.com/eclipse/lsp4mp/pull/454). 45 | - Add About files to JDT extension bundles & Maven artifacts. See [eclipse/lsp4mp#437](https://github.com/eclipse/lsp4mp/pull/437). 46 | - Fix tests for release workflow. See [#185](https://github.com/redhat-developer/vscode-microprofile/pull/185). 47 | 48 | ## [0.11.0](https://github.com/redhat-developer/vscode-microprofile/milestone/12?closed=1) (February 1, 2024) 49 | 50 | ### Bug Fixes 51 | 52 | * Fixed `textDocument/documentSymbol` request failures when properties start with `.`. See [178](https://github.com/redhat-developer/vscode-microprofile/issues/178). 53 | * Fixed quick fixes not being applied. See [#171](https://github.com/redhat-developer/vscode-microprofile/issues/171). 54 | * Fixed broken properties completion. See [eclipse/lsp4mp#432](https://github.com/eclipse/lsp4mp/pull/432). 55 | 56 | ## [0.10.0](https://github.com/redhat-developer/vscode-microprofile/milestone/11?closed=1) (October 5, 2023) 57 | 58 | ### Bug Fixes 59 | 60 | * Properly handle `StackOverflowError` in `MicroProfileDelegateCommandHandler.getMicroProfileProjectInfo`. See [eclipse/lsp4mp#418](https://github.com/eclipse/lsp4mp/issues/418). 61 | * Fix `NullPointerException` in `TestJaxRsInfoProvider.canProvideJaxRsMethodInfoForClass`. See [eclipse/lsp4mp#424](https://github.com/eclipse/lsp4mp/issues/424). 62 | * Fix `canProvideJaxRsMethodInfoForClass` for default JAX-RS. See [eclipse/lsp4mp#420](https://github.com/eclipse/lsp4mp/pull/420). 63 | 64 | ## [0.9.0](https://github.com/redhat-developer/vscode-microprofile/milestone/10?closed=1) (August 8, 2023) 65 | 66 | ### Enhancements 67 | 68 | * Improve completion performance of `microprofile-config.properties` (remove unnecessary parameters in response). See [eclipse/lsp4mp#410](https://github.com/eclipse/lsp4mp/issues/410). 69 | * YAML support activation trigger should be more selective. See [#160](https://github.com/redhat-developer/vscode-microprofile/issues/160). 70 | 71 | ### Bug Fixes 72 | 73 | * Exception on "class extends XXX" autocompletion. See [#161](https://github.com/redhat-developer/vscode-microprofile/issues/161). 74 | 75 | ### Build 76 | 77 | * Bump semver from `5.7.1` to `5.7.2`. See [#162](https://github.com/redhat-developer/vscode-microprofile/pull/162). 78 | * Bump word-wrap from `1.2.3` to `1.2.4`. See [#164](https://github.com/redhat-developer/vscode-microprofile/pull/164). 79 | 80 | ## [0.8.0](https://github.com/redhat-developer/vscode-microprofile/milestone/8?closed=1) (June 15, 2023) 81 | 82 | ### Enhancements 83 | 84 | * Improve completion performance in properties files (resolve support, and item defaults). See [eclipse/lsp4mp#389](https://github.com/eclipse/lsp4mp/issues/389). 85 | * Warning for type declarations that are incorrectly annotated while their methods are annotated with `@Query`/`@Mutation`. See [eclipse/lsp4mp#355](https://github.com/eclipse/lsp4mp/issues/355). 86 | 87 | ## [0.7.1](https://github.com/redhat-developer/vscode-microprofile/milestone/9?closed=1) (April 12, 2023) 88 | 89 | ### Bug Fixes 90 | 91 | * Fix context-aware snippets in projects that use Project Lombok. See [#155](https://github.com/redhat-developer/vscode-microprofile/issues/155). 92 | 93 | ## [0.7.0](https://github.com/redhat-developer/vscode-microprofile/milestone/7?closed=1) (April 4, 2023) 94 | 95 | ### Enhancements 96 | 97 | * Validation for GraphQL `@Query` and `@Mutation` methods with `void` return type. See [eclipse/lsp4mp#348](https://github.com/eclipse/lsp4mp/issues/348), [eclipse/lsp4mp#359](https://github.com/eclipse/lsp4mp/issues/359). 98 | * Navigate to REST endpoints using workspace symbols. See [eclipse/lsp4mp#87](https://github.com/eclipse/lsp4mp/issues/87). 99 | * Validate lists in `@ConfigProperty`'s `defaultValue`. See [#143](https://github.com/redhat-developer/vscode-microprofile/issues/143). 100 | * Show config property documentation when hovering over the key in a properties file. See [#135](https://github.com/redhat-developer/vscode-microprofile/pull/135). 101 | * Make Java file snippets context-aware. See [eclipse/lsp4mp#108](https://github.com/eclipse/lsp4mp/issues/108). 102 | * Upgrade to vscode-languageclient 8.y.z. See [#146](https://github.com/redhat-developer/vscode-microprofile/issues/146). 103 | * Migrate from `find-java-home` to `jdk-utils`. See [#140](https://github.com/redhat-developer/vscode-microprofile/issues/140). 104 | 105 | ### Bug Fixes 106 | 107 | * Hover fails in properties files when the Java language server is loading. See [eclipse/lsp4mp#375](https://github.com/eclipse/lsp4mp/issues/375). 108 | * Definition sometimes fails on property values in a properties file. See [eclipse/lsp4mp#374](https://github.com/eclipse/lsp4mp/issues/374). 109 | * Adjust go to definition range for property keys to include the offset between the property key and `=`. See [redhat-developer/quarkus-ls#323](https://github.com/redhat-developer/quarkus-ls/issues/323). 110 | * Fix `NullPointerException` during go to definition in properties files. See [eclipse/lsp4mp#372](https://github.com/eclipse/lsp4mp/issues/372). 111 | * Fix `NullPointerException` on shutdown when LSP client doesn't define extendedClientCapabilities. See [eclipse/lsp4mp#363](https://github.com/eclipse/lsp4mp/pull/363). 112 | * Completion causes Exceptions when typing in a Java file. See [eclipse/lsp4mp#347](https://github.com/eclipse/lsp4mp/issues/347). 113 | * Support the `jakarta` namespace (JakartaEE 9+). See [eclipse/lsp4mp#344](https://github.com/eclipse/lsp4mp/issues/344). 114 | * Hovering over properties file fails with `NullPointerException` when there are multiple definitions of a property. See [eclipse/lsp4mp#341](https://github.com/eclipse/lsp4mp/issues/341). 115 | * `config_ordinal` appears as a property even in non-MicroProfile projects. See [eclipse/lsp4mp#312](https://github.com/eclipse/lsp4mp/issues/312). 116 | * Quick fix to assign a value to a property now handles the prefix set by `@ConfigProperties` properly. See [eclipse/lsp4mp#303](https://github.com/eclipse/lsp4mp/issues/303). 117 | * Change wording of "Unknown property" error message to "Unrecognized property". See [eclipse/lsp4mp#290](https://github.com/eclipse/lsp4mp/issues/290). 118 | 119 | ### Build 120 | 121 | * Use `vsce` from namespace `@vscode`. See [#141](https://github.com/redhat-developer/vscode-microprofile/pull/141). 122 | 123 | ## [0.6.0](https://github.com/redhat-developer/vscode-microprofile/milestone/6?closed=1) (December 1, 2022) 124 | 125 | ### Enhancements 126 | 127 | * Display property value as inlay hint. See [#108](https://github.com/redhat-developer/vscode-microprofile/pull/108). 128 | * Property evaluation should support the environment variable default value notation. See [eclipse/lsp4mp#241](https://github.com/eclipse/lsp4mp/issues/241). 129 | * Manage static properties using a `staticProvider` extension point. See [eclipse/lsp4mp#44](https://github.com/eclipse/lsp4mp/issues/44). 130 | * Improve code action performance with `CodeAction#data` & `resolveCodeAction`. See [#124](https://github.com/redhat-developer/vscode-microprofile/pull/124), [eclipse/lsp4mp#171](https://github.com/eclipse/lsp4mp/issues/171). 131 | * Diagnostics for mp-reactive-messaging `@Incoming`/`@Outgoing` annotation. See [eclipse/lsp4mp#58](https://github.com/eclipse/lsp4mp/issues/58). 132 | * Only activate extension if Java project is present. See [#114](https://github.com/redhat-developer/vscode-microprofile/issues/114). 133 | 134 | ### Bug Fixes 135 | 136 | * Don't throw an error popup when MicroProfile LS cancels the inlay hint process. See [#123](https://github.com/redhat-developer/vscode-microprofile/pull/123). 137 | * Java source code not validated upon start. See [eclipse/lsp4mp#301](https://github.com/eclipse/lsp4mp/issues/301). 138 | * `ClassCastException` thrown (and caught) when using invalid `@ConfigProperty` default value. See [eclipse/lsp4mp#295](https://github.com/eclipse/lsp4mp/issues/295). 139 | * Improve handling of `@ConfigProperties` for validation. See [eclipse/lsp4mp#304](https://github.com/eclipse/lsp4mp/issues/304). 140 | * Support for the `config_ordinal` property in `microprofile-config.properties`. See [eclipse/lsp4mp#289](https://github.com/eclipse/lsp4mp/issues/289). 141 | * Display property value when hovering over a key that isn't defined in the application. See [eclipse/lsp4mp#285](https://github.com/eclipse/lsp4mp/issues/285). 142 | * REST client code lens only shows up for `GET` annotations. See [eclipse/lsp4mp#94](https://github.com/eclipse/lsp4mp/issues/94). 143 | * JAXRS code lens URL should always appear above method declaration. See [eclipse/lsp4mp#194](https://github.com/eclipse/lsp4mp/issues/194). 144 | * Support `microprofile-health` 3.0 and later. See [eclipse/lsp4mp#314](https://github.com/eclipse/lsp4mp/issues/314). 145 | * Make `microprofile.tools.server.vmargs` setting application scoped. See [#121](https://github.com/redhat-developer/vscode-microprofile/pull/121). 146 | * Disable JVM logging to avoid language server failure. See [#118](https://github.com/redhat-developer/vscode-microprofile/issues/118). 147 | * Fix inlay hints & definitions when project returns empty properties. See [eclipse/lsp4mp#311](https://github.com/eclipse/lsp4mp/pull/311). 148 | * Fix code lens when no configuration sources available. See [eclipse/lsp4mp#315](https://github.com/eclipse/lsp4mp/issues/315). 149 | * `@ConfigProperties` validation should check the annotation's fully qualified name. See [eclipse/lsp4mp#304](https://github.com/eclipse/lsp4mp/issues/304). 150 | * Fix typo in `mpirc` snippet. See [eclipse/lsp4mp#325](https://github.com/eclipse/lsp4mp/issues/325). 151 | 152 | ### Build 153 | 154 | * Add support for pre-releases. See [#113](https://github.com/redhat-developer/vscode-microprofile/pull/113). 155 | * Update node in CI and CD to 14. See [#106](https://github.com/redhat-developer/vscode-microprofile/pull/106). 156 | * Update Jenkinsfile to use Java 17. See [#111](https://github.com/redhat-developer/vscode-microprofile/pull/111). 157 | * Update vscode-redhat-telemetry to 0.5.2. See [#131](https://github.com/redhat-developer/vscode-microprofile/pull/131). 158 | * Update Target Platform to 1.16.0-SNAPSHOT version of JDT-LS target. See [eclipse/lsp4mp#288](https://github.com/eclipse/lsp4mp/pull/288). 159 | * JDT.LS dependency on tests should be optional. See [eclipse/lsp4mp#286](https://github.com/eclipse/lsp4mp/issues/286). 160 | * Copy over `ModelTextDocuments#computeModelAsyncCompose` from quarkus-ls into commons package. See [eclipse/lsp4mp#257](https://github.com/eclipse/lsp4mp/issues/257). 161 | * Move VS Code workspace configuration into correct folder. See [eclipse/lsp4mp#145](https://github.com/eclipse/lsp4mp/pull/145). 162 | 163 | ## [0.5.0](https://github.com/redhat-developer/vscode-microprofile/milestone/5?closed=1) (July 25, 2022) 164 | 165 | ### Enhancements 166 | 167 | * Colorize profile part in properties. See [#96](https://github.com/redhat-developer/vscode-microprofile/issues/96). 168 | * Added textmate grammar support for property expressions. See [#95](https://github.com/redhat-developer/vscode-microprofile/pull/95). 169 | * Delay revalidation and handle validation cancellation correctly. See [eclipse/lsp4mp#252](https://github.com/eclipse/lsp4mp/pull/252). 170 | * Property file with property expressions (without default value) are flagged as wrong. See [eclipse/lsp4mp#225](https://github.com/eclipse/lsp4mp/issues/225), [eclipse/lsp4mp#227](https://github.com/eclipse/lsp4mp/issues/227). 171 | * Improved MicroProfile property value expression diagnostic message. See [eclipse/lsp4mp#242](https://github.com/eclipse/lsp4mp/pull/242). 172 | 173 | ### Bug Fixes 174 | 175 | * Language Server attempts to calculate code actions for stale diagnostics. See [eclipse/lsp4mp#272](https://github.com/eclipse/lsp4mp/issues/272). 176 | * Hovering property value fails with NPE. See [eclipse/lsp4mp#265](https://github.com/eclipse/lsp4mp/issues/265). 177 | * Completing property name with existing value will replace current value with default value. See [eclipse/lsp4mp#264](https://github.com/eclipse/lsp4mp/issues/264). 178 | * Empty completion when completion is triggered before the assign `=`. See [eclipse/lsp4mp#255](https://github.com/eclipse/lsp4mp/issues/255). 179 | * Improve validation by handling some known corner cases. [eclipse/lsp4mp#249](https://github.com/eclipse/lsp4mp/issues/249), [eclipse/lsp4mp#235](https://github.com/eclipse/lsp4mp/issues/235), [eclipse/lsp4mp#233](https://github.com/eclipse/lsp4mp/issues/233), [eclipse/lsp4mp#232](https://github.com/eclipse/lsp4mp/issues/232), [eclipse/lsp4mp#228](https://github.com/eclipse/lsp4mp/issues/228). 180 | 181 | ### Build 182 | 183 | * Bump terser from 5.6.1 to 5.14.2. See [#102](https://github.com/redhat-developer/vscode-microprofile/pull/102). 184 | * Remove ejs dependency. See [#97](https://github.com/redhat-developer/vscode-microprofile/pull/97). 185 | 186 | ### Documentation 187 | 188 | * Add DCO information to `CONTRIBUTING.md`. See [#99](https://github.com/redhat-developer/vscode-microprofile/issues/99). 189 | 190 | 191 | ## [0.4.0](https://github.com/redhat-developer/vscode-microprofile/milestone/4?closed=1) (March 24, 2022) 192 | 193 | ### Enhancements 194 | 195 | * Support validation and code actions for `@ConfigProperty`. See [eclipse/lsp4mp#90](https://github.com/eclipse/lsp4mp/issues/90), [eclipse/lsp4mp#176](https://github.com/eclipse/lsp4mp/issues/176) and [eclipse/lsp4mp#147](https://github.com/eclipse/lsp4mp/issues/147). 196 | * Completion for properties defined using `@ConfigProperties`. See [eclipse/lsp4mp#80](https://github.com/eclipse/lsp4mp/issues/80). 197 | * Support validation for `@Retry` annotation and its member values. See [eclipse/lsp4mp#191](https://github.com/eclipse/lsp4mp/pull/191) and [eclipse/lsp4mp#196](https://github.com/eclipse/lsp4mp/issues/196). 198 | * Diagnostics for `@Asynchronous`, `@Bulkhead` & `@Timeout` annotations. See [eclipse/lsp4mp#74](https://github.com/eclipse/lsp4mp/issues/74), [eclipse/lsp4mp#184](https://github.com/eclipse/lsp4mp/pull/184), [eclipse/lsp4mp#185](https://github.com/eclipse/lsp4mp/pull/185). 199 | * Support the `@ApplicationPath` annotation to handle the project URL. See [eclipse/lsp4mp#179](https://github.com/eclipse/lsp4mp/issues/179). 200 | * Diagnostics for invalid annotation parameter values. See [eclipse/lsp4mp#77](https://github.com/eclipse/lsp4mp/issues/77). 201 | * Reference only property declared in properties file in property expression. See [eclipse/lsp4mp#205](https://github.com/eclipse/lsp4mp/issues/205). 202 | * Support for default value inside properties expression. See [eclipse/lsp4mp#201](https://github.com/eclipse/lsp4mp/issues/201). 203 | * Use redhat.java embedded JRE to launch the MicroProfile language server. See [#84](https://github.com/redhat-developer/vscode-microprofile/issues/84). 204 | * Add settings and code action to ignore unassigned property warnings. See [#65](https://github.com/redhat-developer/vscode-microprofile/pull/65) and [eclipse/lsp4mp#187](https://github.com/eclipse/lsp4mp/pull/187). 205 | * Binary dynamic properties should be generated after an update. See [eclipse/lsp4mp#159](https://github.com/eclipse/lsp4mp/pull/159). 206 | * Support for config profiles. See [#73](https://github.com/redhat-developer/vscode-microprofile/pull/73). 207 | 208 | ### Bug Fixes 209 | 210 | * Provide API to configure root path of JAX RS resources. See [eclipse/lsp4mp#174](https://github.com/eclipse/lsp4mp/pull/174). 211 | * Fix bug with missing definition hover for multiple annotation members. See [eclipse/lsp4mp#216](https://github.com/eclipse/lsp4mp/pull/216). 212 | * Support optional property reference hover for annotation members. See [eclipse/lsp4mp#211](https://github.com/eclipse/lsp4mp/pull/211). 213 | * Do not rebuild list of configuration properties when MicroProfile config sources are updated in the build directory. See [eclipse/lsp4mp#162](https://github.com/eclipse/lsp4mp/issues/162). 214 | * Deadlock when client is sending burst of request. See [eclipse/lsp4mp#177](https://github.com/eclipse/lsp4mp/issues/177). 215 | * Exclude the method that's being annotated when showing completion for fallback method. See [eclipse/lsp4mp#148](https://github.com/eclipse/lsp4mp/issues/148). 216 | * SingleMemberAnnotation diagnostics not supported by annotationValidator. See [eclipse/lsp4mp#188](https://github.com/eclipse/lsp4mp/issues/188). 217 | * Add 'shouldLanguageServerExitOnShutdown' to ExtendedClientCapabilities. See [eclipse/lsp4mp#172](https://github.com/eclipse/lsp4mp/pull/172). 218 | * Update find-java-home to correctly detect java binary where it is symbolically linked. See [#81](https://github.com/redhat-developer/vscode-microprofile/issues/81). 219 | 220 | ### Build 221 | 222 | * Use ovsx<0.3.0 to ensure we build with Node v12. See [#87](https://github.com/redhat-developer/vscode-microprofile/pull/87). 223 | 224 | ### Other 225 | 226 | * Add features documentation for properties/java files. See [#64](https://github.com/redhat-developer/vscode-microprofile/issues/64). 227 | * Move to vscode-languageclient 7.0.0. See [#68](https://github.com/redhat-developer/vscode-microprofile/pull/68). 228 | * Add support for `shouldServerExitOnShutdown` capability. See [#69](https://github.com/redhat-developer/vscode-microprofile/issues/69). 229 | * Update vscode-redhat-telemetry to 0.4.2. See [#74](https://github.com/redhat-developer/vscode-microprofile/pull/74). 230 | * Update follow-redirects and mocha. See [#86](https://github.com/redhat-developer/vscode-microprofile/pull/86). 231 | 232 | ## [0.3.0](https://github.com/redhat-developer/vscode-microprofile/milestone/3?closed=1) (July 22, 2021) 233 | 234 | ### Enhancements 235 | 236 | * Completion for `fallbackMethod` in `@Fallback` annotation. See [eclipse/lsp4mp#34](https://github.com/eclipse/lsp4mp/issues/34). 237 | * Remove dependency on vscode-commons. See [#55](https://github.com/redhat-developer/vscode-microprofile/issues/55). 238 | 239 | ### Build 240 | 241 | * Migrate to eslint from tslint. See [#53](https://github.com/redhat-developer/vscode-microprofile/issues/53). 242 | * Use registry.npmjs.com in `package-lock.json`. See [#50](https://github.com/redhat-developer/vscode-microprofile/pull/50). 243 | * Migrate to GitHub Actions from travis-ci.org. See [#59](https://github.com/redhat-developer/vscode-microprofile/issues/59). 244 | 245 | ## [0.2.0](https://github.com/redhat-developer/vscode-microprofile/milestone/2?closed=1) (April 7, 2021) 246 | 247 | ### Enhancements 248 | 249 | * Support arbitrary number of member values in `PropertiesHoverParticipant`. See [eclipse/lsp4mp#124](https://github.com/eclipse/lsp4mp/pull/124). 250 | * Add extension point to contribute properties to exclude from validation. See [eclipse/lsp4mp#95](https://github.com/eclipse/lsp4mp/issues/95). 251 | * Definition support from Java to properties for `ConfigProperty/name`. See [eclipse/lsp4mp#88](https://github.com/eclipse/lsp4mp/issues/88). 252 | * Automatically infer package names when inserting class snippets. See [eclipse/lsp4mp#60](https://github.com/eclipse/lsp4mp/issues/60). 253 | * Support `handle-as` for metadata properties. See [eclipse/lsp4mp#39](https://github.com/eclipse/lsp4mp/issues/39). 254 | * Display the different values for the different profiles in Java `@ConfigProperty` Hover. See [eclipse/lsp4mp#98](https://github.com/eclipse/lsp4mp/issues/98). 255 | * Add startup and shutdown telemetry. See [#46](https://github.com/redhat-developer/vscode-microprofile/issues/46) 256 | 257 | ### Bug Fixes 258 | 259 | * Wait for the language server to stop before exiting. See [#39](https://github.com/redhat-developer/vscode-microprofile/issues/39). 260 | * Trailing tab causes infinite loop in parser. See [eclipse/lsp4mp#112](https://github.com/eclipse/lsp4mp/issues/112). 261 | * Prevent NPEs when working with MP 4.0 features. See [eclipse/lsp4mp#119](https://github.com/eclipse/lsp4mp/issues/119). 262 | * Enhance the error message when out of bounds is detected. See [eclipse/lsp4mp#114](https://github.com/eclipse/lsp4mp/pull/114). 263 | * Use `kill -0` instead of `ps -p` in `ParentProcessWatcher`. See [eclipse/lsp4mp#110](https://github.com/eclipse/lsp4mp/issues/110). 264 | * Wrong/Missing Log Levels in property files. See [eclipse/lsp4mp#15](https://github.com/eclipse/lsp4mp/pull/105). 265 | * `mp.messaging` properties now work for Emitters. See [eclipse/lsp4mp#127](https://github.com/eclipse/lsp4mp/pull/127). 266 | 267 | ## [0.1.1] (September 23, 2020) 268 | * Update name to "Tools for MicroProfile". See [#23](https://github.com/redhat-developer/vscode-microprofile/issues/23) 269 | 270 | ## [0.1.0](https://github.com/redhat-developer/vscode-microprofile/milestone/1?closed=1) (September 21, 2020) 271 | 272 | ### Enhancements 273 | 274 | * Add new setting for property expression validation. See [#18](https://github.com/redhat-developer/vscode-microprofile/pull/18). 275 | * Update extension displayName to MicroProfile Tools. See [#9](https://github.com/redhat-developer/vscode-microprofile/pull/9). 276 | * Remove quarkus-properties language and collect document selectors from extensions. See [#8](https://github.com/redhat-developer/vscode-microprofile/pull/8). 277 | * Java snippets for `microprofile rest client`. See [lsp4mp#55](https://github.com/eclipse/lsp4mp/issues/55). 278 | * CDI scope diagnostics for `mp metrics @Gauge`. See [lsp4mp#46](https://github.com/eclipse/lsp4mp/issues/46). 279 | * Highlight support for property expression. See [lsp4mp#40](https://github.com/eclipse/lsp4mp/issues/40). 280 | * Diagnostics for ` mp-fault-tolerance fallbackMethod` . See [lsp4mp#33](https://github.com/eclipse/lsp4mp/issues/33). 281 | * Java `snippets for jax-rs`. See [lsp4mp#31](https://github.com/eclipse/lsp4mp/issues/31). 282 | * Snippets for new `microprofile health liveness / readiness checks`. See [lsp4mp#28](https://github.com/eclipse/lsp4mp/issues/28). 283 | * Properties support for `microprofile-graphql`. See [lsp4mp#27](https://github.com/eclipse/lsp4mp/issues/27). 284 | * Properties support for `microprofile-reactive-messaging`. See [lsp4mp#26](https://github.com/eclipse/lsp4mp/issues/26). 285 | * Hover for Property Expressions. See [lsp4mp#24](https://github.com/eclipse/lsp4mp/issues/24). 286 | * Properties support for microprofile-jwt-auth. See [lsp4mp#23](https://github.com/eclipse/lsp4mp/issues/23). 287 | * Property expression validation. See [lsp4mp#21](https://github.com/eclipse/lsp4mp/pull/21). 288 | * Property expression definition. See [lsp4mp#19](https://github.com/eclipse/lsp4mp/pull/19). 289 | * Hardcoded support for boolean converter. See [lsp4mp#17](https://github.com/eclipse/lsp4mp/pull/17). 290 | * Properties support for `microprofile-health`. See [lsp4mp#16](https://github.com/eclipse/lsp4mp/issues/16). 291 | * Model and completion for property expressions. See [lsp4mp#13](https://github.com/eclipse/lsp4mp/pull/13). 292 | 293 | ### Bug Fixes 294 | 295 | * Ensure language server is stopped when extension is deactivated. See [#16](https://github.com/redhat-developer/vscode-microprofile/pull/16). 296 | * Ensure microprofile ls process is terminated on deactivate. See [#15](https://github.com/redhat-developer/vscode-microprofile/issues/15). 297 | * Detect lightweight java language server. See [#14](https://github.com/redhat-developer/vscode-microprofile/pull/14). 298 | * NPE during completion when Java language server is started in LightWeight mode. See [#12](https://github.com/redhat-developer/vscode-microprofile/issues/12). 299 | * Allow `[`, `]`, and `#` in property keys TextMate grammar. See [#11](https://github.com/redhat-developer/vscode-microprofile/pull/11). 300 | * NullPointerException with symbols. See [lsp4mp#66](https://github.com/eclipse/lsp4mp/issues/66). 301 | * Fix duplicate of `quarkus-properties` when registering `textDocument/rangeFormatting`. See [lsp4mp#52](https://github.com/eclipse/lsp4mp/pull/52). 302 | * Rename settings prefix to microprofile. See [lsp4mp#51](https://github.com/eclipse/lsp4mp/pull/51). 303 | * Fix missing unit in Gauge metrics snippet. See [lsp4mp#47](https://github.com/eclipse/lsp4mp/pull/47). 304 | * Escape special characters within LSP snippets. See [lsp4mp#29](https://github.com/eclipse/lsp4mp/pull/29). 305 | * Completion in properties file gives enum values before `=`. See [lsp4mp#14](https://github.com/eclipse/lsp4mp/issues/14). 306 | 307 | ### Build 308 | 309 | * Setup CI. See [#4](https://github.com/redhat-developer/vscode-microprofile/issues/4). 310 | 311 | ### Other 312 | 313 | * Add gitter link to readme. See [#20](https://github.com/redhat-developer/vscode-microprofile/pull/20). 314 | * Fix missing space in switch java mode prompt. See [#17](https://github.com/redhat-developer/vscode-microprofile/pull/17). 315 | * Document external lsp4mp extensions. See [#13](https://github.com/redhat-developer/vscode-microprofile/pull/13). 316 | * Update contributing guide. See [#10](https://github.com/redhat-developer/vscode-microprofile/pull/10). 317 | * Test collecting lsp4mp extensions. See [#7](https://github.com/redhat-developer/vscode-microprofile/pull/7). 318 | * Add badges. See [#6](https://github.com/redhat-developer/vscode-microprofile/pull/6). 319 | * Apache 2.0 License. See [#5](https://github.com/redhat-developer/vscode-microprofile/pull/5). 320 | * Remove quarkus-properties language. See [#3](https://github.com/redhat-developer/vscode-microprofile/issues/3). 321 | * Update contributing guide. See [#2](https://github.com/redhat-developer/vscode-microprofile/issues/2). 322 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | Contributions are extremely welcome, no matter how big or small. 4 | If you have any questions or suggestions we are happy to hear them. 5 | 6 | # Table of Contents 7 | 1. [Project Structure](#project-structure) 8 | 2. [Implementing language features for `microprofile-config.properties`](#implementing-language-features-for-microprofile-configproperties) 9 | 3. [Implementing language features for Java files](#implementing-language-features-for-java-files) 10 | 4. [Development Setup](#development-setup) 11 | 1. [Installation Prerequisites](#installation-prerequisites) 12 | 2. [Setup](#setup) 13 | 3. [Running vscode-microprofile](#running-vscode-microprofile) 14 | 4. [Testing vscode-microprofile](#testing-vscode-microprofile) 15 | 5. [Debugging](#debugging) 16 | 1. [Debugging the MicroProfile language server](#debugging-the-microprofile-language-server) 17 | 2. [Debugging the MicroProfile jdt.ls extension](#debugging-the-microprofile-jdtls-extension) 18 | 19 | ## Project Structure 20 | For vscode-microprofile to work, it relies on the 21 | [MicroProfile language server](https://github.com/eclipse/lsp4mp/tree/master/microprofile.ls) 22 | and the 23 | [MicroProfile jdt.ls extension](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt). 24 | The MicroProfile language server is responsible for providing 25 | [LSP language features](https://microsoft.github.io/language-server-protocol/specification) 26 | to VSCode, while the MicroProfile jdt.ls extension is responsible 27 | for functionalities like listening 28 | to Java classpath changes and generating config setting metadata for 29 | the `microprofile-config.properties` file. 30 | The reason why 31 | [vscode-java](https://github.com/redhat-developer/vscode-java) 32 | is required for vscode-microprofile to work, is because vscode-java 33 | starts the [jdt.ls](https://github.com/eclipse/eclipse.jdt.ls) 34 | language server, which is required to run the MicroProfile jdt.ls extension. 35 | 36 | **Note**: The MicroProfile language server provides language features for both `microprofile-config.properties` and `*.java` files. 37 | 38 | ![](images/componentDiagram.png) 39 | The image above represents communication between the three components. 40 | As the image implies, the MicroProfile language server cannot directly 41 | communicate with the MicroProfile jdt.ls extension and vice-versa. They must 42 | communicate via vscode-microprofile. 43 | 44 | Here is an example of how the components work together for 45 | `microprofile-config.properties` completion: 46 | 47 | **Step 1.** A MicroProfile project is opened in VSCode, and completion has been 48 | invoked inside the `microprofile-config.properties` file. VSCode sends a 49 | `textDocument/completion` request to the MicroProfile language server. 50 | 51 | **Step 2.** MicroProfile language server checks its cache if completion options 52 | exist. 53 | * If the cache holds completion options, the MicroProfile language server sends them to VSCode 54 | as the response to the `textDocument/completion` request. 55 | Communication is complete, and does not proceed to Step 3 56 | and onwards. 57 | * If completion options are not cached, the MicroProfile language server sends a 58 | custom request, `microprofile/projectInfo` to vscode-microprofile. 59 | Proceed to Step 3. 60 | 61 | **Step 3.** vscode-microprofile receives the `microprofile/projectInfo` request, 62 | and delegates it to the MicroProfile jdt.ls extension. 63 | 64 | **Step 4.** The MicroProfile jdt.ls extension receives the command, determines 65 | [project information](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java) 66 | (project URI, configuration properties, hints etc.) 67 | about the currently opened MicroProfile project and returns 68 | the information to vscode-microprofile. The project information is then sent to 69 | the MicroProfile language server 70 | 71 | **Step 5.** vscode-microprofile receives the project information and sends it 72 | to the MicroProfile language server. 73 | 74 | **Step 6.** MicroProfile language server receives the information, adds it 75 | to its cache, and returns the completion options stored in the 76 | project information as the response to the `textDocument/completion` 77 | request. 78 | 79 | ## Implementing language features for `microprofile-config.properties` 80 | When a `microprofile-config.properties` file sends a request (e.g. textDocument/completion) to the 81 | MicroProfile language server, the requests are accepted in 82 | [ApplicationPropertiesTextDocumentService#completion](https://github.com/eclipse/lsp4mp/tree/master/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/ApplicationPropertiesTextDocumentService.java#L150). 83 | This class receives LSP requests for `microprofile-config.properties` files. 84 | 85 | Properties collected by the MicroProfile jdt.ls extension are cached to keep response times 86 | fast. 87 | Collecting properties will not be done unless absolutely necessary 88 | (ie, if cache doesn't exist, if project dependencies change). 89 | 90 | When the completion is triggered, 91 | the MicroProfile LS checks the properties cache for the given `microprofile-config.properties` file. 92 | If the cache does not exist, it calls the `microprofile/projectInfo` request to call the JDT LS Extension [projectInfo delegate command handler](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandler.java#L71) which 93 | uses the 94 | [properties manager](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManager.java) 95 | that collects MicroProfile properties for the given Java project. 96 | 97 | This manager is extensible by the 98 | `org.eclipse.lsp4mp.jdt.core.propertiesProviders` 99 | [extension point](https://github.com/eclipse/lsp4mp/blob/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml#L5): 100 | 101 | * [org.eclipse.lsp4mp.jdt.core](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml#L49-L52) defines properties provider for MicroProfile. 102 | 103 | Here are some providers for MicroProfile projects and the annotation(s) they scan for: 104 | 105 | | Class | Annotations | 106 | |-------|-------------| 107 | | [MicroProfileConfigPropertyProvider](https://github.com/eclipse/lsp4mp/blob/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/config/properties/MicroProfileConfigPropertyProvider.java) | org.eclipse.microprofile.config.inject.ConfigProperty | 108 | | [MicroProfileRegisterRestClientProvider](https://github.com/eclipse/lsp4mp/blob/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/restclient/properties/MicroProfileRegisterRestClientProvider.java) | org.eclipse.microprofile.rest.client.inject.RegisterRestClient | 109 | 110 | The microprofile.jdt can also be extended to provide additional property providers. 111 | 112 | * For example: [com.redhat.microprofile.jdt.quarkus](https://github.com/redhat-developer/quarkus-ls/tree/master/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml#L5-L10) defines properties providers that scan for additional annotations for Quarkus which is used by [vscode-quarkus](https://github.com/redhat-developer/vscode-quarkus) to extend vscode-microprofile. 113 | 114 | 115 | | Class | Annotations | 116 | |-------|-------------| 117 | | [QuarkusConfigPropertiesProvider](https://github.com/redhat-developer/quarkus-ls/tree/master/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigPropertiesProvider.java) | io.quarkus.arc.config.ConfigProperties | 118 | | [QuarkusConfigRootProvider](https://github.com/redhat-developer/quarkus-ls/tree/master/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigRootProvider.java) | io.quarkus.runtime.annotations.ConfigRoot | 119 | | [QuarkusKubernetesProvider](https://github.com/redhat-developer/quarkus-ls/tree/master/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusKubernetesProvider.java) | io.dekorate.kubernetes.annotation.KubernetesApplication
io.dekorate.openshift.annotation.OpenshiftApplication
io.dekorate.s2i.annotation.S2iBuild
io.dekorate.docker.annotation.DockerBuild | 120 | 121 | 122 | ### Searching for properties in JARs not in the user's project's classpath 123 | 124 | It is also possible to search for properties in JARs not on the classpath. For an example of how the quarkus extension to microprofile.jdt does this you can look at the [vscode-quarkus CONTRIBUTING.md](https://github.com/redhat-developer/vscode-quarkus/blob/master/CONTRIBUTING.md#searching-for-properties-in-jars-not-in-the-users-quarkus-projects-classpath) 125 | 126 | ## Implementing language features for Java files 127 | When a Java file sends a request (e.g. `textDocument/codeLens`) to the 128 | MicroProfile language server, the requests are accepted in 129 | [JavaTextDocumentService#completion](https://github.com/eclipse/lsp4mp/blob/master/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/JavaTextDocumentService.java#L111). 130 | This class receives LSP requests for Java files. 131 | 132 | The `textDocument/codeLens`, `textDocument/publishDiagnostics`, `textDocument/hover` requests are delegated to 133 | [`MicroProfileDelegateCommandHandlerForJava`](https://github.com/eclipse/lsp4mp/blob/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/core/ls/MicroProfileDelegateCommandHandlerForJava.java) which creates the `lsp4j.Hover`, 134 | `lsp4j.CodeLens` and `lsp4j.PublishDiagnosticsParams` instances for hover, codelens and diagnostics respectively. 135 | 136 | Just like how `microprofile-config.properties` properties are extensible via extension point, Java codeLens, diagnostics and 137 | hover are also extensible via extension point. 138 | 139 | These Java features are extensible by the 140 | `org.eclipse.lsp4mp.jdt.core.javaFeatureParticipants` 141 | [extension point](https://github.com/eclipse/lsp4mp/blob/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml#L8): 142 | 143 | * [org.eclipse.lsp4mp.jdt.core](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/plugin.xml#L54-L57) defines Java feature participants for MicroProfile. 144 | 145 | Here are some examples of the leveraging the extension point to provide Java codeLens, diagnostics and hover: 146 | | Java Feature | Participant | 147 | |-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 148 | | MicroProfile Health diagnostics | [MicroProfileHealthDiagnosticsParticipant ](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/health/java/MicroProfileHealthDiagnosticsParticipant.java ) | 149 | | MicroProfile Rest Client diagnostics | [MicroProfileRestClientDiagnosticsParticipant ](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/restclient/java/MicroProfileRestClientDiagnosticsParticipant.java ) | 150 | | MicroProfile Rest Client codeLens | [MicroProfileRestClientCodeLensParticipant](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/restclient/java/MicroProfileRestClientCodeLensParticipant.java) | 151 | | JAX-RS codelens | [JaxRsCodeLensParticipant ](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/jaxrs/java/JaxRsCodeLensParticipant.java ) | 152 | | MicroProfile `@ConfigProperty` name hover | [MicroProfileConfigHoverParticipant ](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/internal/config/java/MicroProfileConfigHoverParticipant.java ) | 153 | 154 | 155 | Similar to properties files, the microprofile.jdt Java feature participants can be extended to provide additionally functionality. For example [com.redhat.microprofile.jdt.quarkus](https://github.com/redhat-developer/quarkus-ls/blob/master/quarkus.jdt.ext/com.redhat.microprofile.jdt.quarkus/plugin.xml#L18-L21) defines Java feature participants for Quarkus. 156 | 157 | ## Development Setup 158 | 159 | ### Installation Prerequisites 160 | 161 | * [Visual Studio Code](https://code.visualstudio.com/) 162 | * [Language Support for Java](https://marketplace.visualstudio.com/items?itemName=redhat.java) 163 | * [Node.js](https://nodejs.org/en/) 164 | * [JDK 21+](https://adoptopenjdk.net/) 165 | 166 | ### Setup 167 | **Step 1.** Fork and clone this repository 168 | 169 | **Step 2.** Fork and clone the [lsp4mp repository](https://github.com/eclipse/lsp4mp), which 170 | contains the MicroProfile jdt.ls extension and MicroProfile language server 171 | 172 | **Note:** Ensure that the cloned repositories are under the same parent directory: 173 | 174 | ``` 175 | YOUR_FOLDER/ 176 | ├──── vscode-microprofile/ 177 | ├──── lsp4mp/ 178 | ``` 179 | 180 | **Step 3.** Navigate into `vscode-microprofile/` 181 | ```bash 182 | $ cd vscode-microprofile/ 183 | ``` 184 | **Step 4.** Install npm dependencies 185 | ```bash 186 | $ npm install 187 | ``` 188 | 189 | **Step 5.** Build the MicroProfile language server and MicroProfile jdt.ls extension 190 | ```bash 191 | $ npm run build 192 | ``` 193 | This script does two things. 194 | 1. Builds the MicroProfile language server and places the jar in 195 | `vscode-microprofile/server/`. 196 | 2. Builds the MicroProfile jdt.ls extension and places the jar in 197 | `vscode-microprofile/jars/`. 198 | 199 | In addition to `npm run build`, there are two more build scripts: 200 | `npm run build-server` only builds the MicroProfile language server and places the jar in `vscode-microprofile/server/`. 201 | `npm run build-ext` only builds the MicroProfile jdt.ls extension and places the jar in `vscode-microprofile/jars/`. 202 | 203 | ### Running vscode-microprofile 204 | **Step 1.** Open `vscode-microprofile/` in VSCode. 205 | 206 | **Step 2.** Open the Run tab, select and run 207 | "Run Extension" at the top left. 208 | ![](images/runExtension.png) 209 | 210 | ### Testing vscode-microprofile 211 | 212 | Run integration tests: `npm test` 213 | 214 | The tests are located in src/tests directory. 215 | 216 | ``` 217 | vscode-microprofile/ 218 | ├──── src/ 219 | ├──── test/ 220 | ``` 221 | 222 | To debug the integration tests, open the VS Code Run tab and 223 | select the "Extension Tests" at the top left: 224 | ![](images/runDebuggerVSCodeTests.png) 225 | 226 | ## Debugging 227 | ### Debugging the MicroProfile language server: 228 | In an IDE of your choice, set the debugger configuration to connect 229 | to localhost, port 1064. 230 | 231 | If using VSCode, open `lsp4mp/microprofile.ls/` in VSCode. The proper 232 | debugger configurations are already defined in `.vscode/`. 233 | There should be a "Debug (Attach) - Remote" option 234 | at the top left of the Debugging tab. 235 | ![](images/runDebugger.png) 236 | 237 | The JVM arguments used to start the MicroProfile language 238 | server are specified 239 | [here](https://github.com/redhat-developer/vscode-microprofile/blob/master/src/languageServer/javaServerStarter.ts#L25). 240 | 241 | ### Debugging the MicroProfile jdt.ls extension: 242 | Only Eclipse can be used to debug the MicroProfile jdt.ls extension. 243 | 244 | **Step 1.** Open the jdt.ls source code in a new workspace in Eclipse by 245 | following the setup 246 | steps in the jdt.ls GitHub repository 247 | [here](https://github.com/eclipse/eclipse.jdt.ls#first-time-setup). 248 | 249 | **Step 2.** In the same workspace, import the projects from 250 | `lsp4mp/microprofile.jdt/`. 251 | 252 | **Step 3.** In the Debug dropdown menu, open "Debug Configurations...". 253 | ![](images/debugConfigMenu.png) 254 | 255 | **Step 4.** Create a new "Remote Java Application" launch configuration. 256 | Set the following settings and click "Apply": 257 | ``` 258 | Project: org.eclipse.lsp4mp.jdt.core 259 | Connection Type: Standard (Socket Attach) 260 | Host: localhost 261 | Port: 1044 262 | ``` 263 | ![](images/debugConfig.png) 264 | 265 | ### Certificate of Origin 266 | 267 | By contributing to this project you agree to the Developer Certificate of 268 | Origin (DCO). This document was created by the Linux Kernel community and is a 269 | simple statement that you, as a contributor, have the legal right to make the 270 | contribution. See the [DCO](DCO) file for details. 271 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | node('rhel8'){ 4 | stage('Checkout repos') { 5 | deleteDir() 6 | def hasLsp4mpDir = fileExists 'lsp4mp' 7 | if (!hasLsp4mpDir){ 8 | sh 'mkdir lsp4mp' 9 | } 10 | dir ('lsp4mp') { 11 | echo "Checking out LSP4MP ${params.LSP4MP_TAG}" 12 | git url: 'https://github.com/eclipse/lsp4mp.git' 13 | sh "git checkout ${params.LSP4MP_TAG}" 14 | } 15 | def hasClientDir = fileExists 'vscode-microprofile' 16 | if (!hasClientDir) { 17 | sh 'mkdir vscode-microprofile' 18 | } 19 | dir ('vscode-microprofile') { 20 | git url: "https://github.com/${params.FORK}/vscode-microprofile.git" 21 | } 22 | } 23 | 24 | stage('Install requirements') { 25 | def nodeHome = tool 'nodejs-18.15.0' 26 | env.PATH="${env.PATH}:${nodeHome}/bin" 27 | sh 'npm install -g typescript' 28 | sh 'npm install -g -f "@vscode/vsce"' 29 | } 30 | 31 | stage('Build') { 32 | env.JAVA_HOME="${tool 'openjdk-17'}" 33 | env.PATH="${env.JAVA_HOME}/bin:${env.PATH}" 34 | dir ('vscode-microprofile') { 35 | sh "npm install --ignore-scripts" 36 | sh "npm install" 37 | sh "npm run build" 38 | sh "npm run vscode:prepublish" 39 | } 40 | } 41 | 42 | withEnv(['JUNIT_REPORT_PATH=report.xml']) { 43 | stage('Test') { 44 | wrap([$class: 'Xvnc']) { 45 | dir ('vscode-microprofile') { 46 | sh "npm test --silent" 47 | //junit 'report.xml' 48 | } 49 | } 50 | } 51 | } 52 | 53 | env.publishPreReleaseFlag = "" 54 | if(publishPreRelease.equals('true')){ 55 | stage("Prepare for pre-release") { 56 | dir ('vscode-microprofile') { 57 | sh "npx gulp prepare_pre_release" 58 | env.publishPreReleaseFlag = "--pre-release" 59 | } 60 | } 61 | } 62 | 63 | stage('Package') { 64 | dir ('vscode-microprofile') { 65 | def packageJson = readJSON file: 'package.json' 66 | sh "vsce package ${env.publishPreReleaseFlag} -o ../vscode-microprofile-${packageJson.version}-${env.BUILD_NUMBER}.vsix" 67 | sh "npm pack && mv vscode-microprofile-${packageJson.version}.tgz ../vscode-microprofile-${packageJson.version}-${env.BUILD_NUMBER}.tgz" 68 | } 69 | } 70 | 71 | if(params.UPLOAD_LOCATION) { 72 | stage('Snapshot') { 73 | def filesToPush = findFiles(glob: '**.vsix') 74 | sh "sftp -C ${UPLOAD_LOCATION}/snapshots/vscode-microprofile/ <<< \$'put -p ${filesToPush[0].path}'" 75 | stash name:'vsix', includes:filesToPush[0].path 76 | def tgzFilesToPush = findFiles(glob: '**.tgz') 77 | stash name:'tgz', includes:tgzFilesToPush[0].path 78 | sh "sftp -C ${UPLOAD_LOCATION}/snapshots/vscode-microprofile/ <<< \$'put -p ${tgzFilesToPush[0].path}'" 79 | } 80 | } 81 | 82 | if('true'.equals(publishToMarketPlace) || 'true'.equals(publishToOVSX) || 'true'.equals(publishPreRelease)){ 83 | if ('true'.equals(publishToMarketPlace) || 'true'.equals(publishToOVSX)) { 84 | timeout(time:5, unit:'DAYS') { 85 | input message:'Approve deployment?', submitter: 'fbricon,rgrunber,azerr,davthomp' 86 | } 87 | } 88 | 89 | stage("Publish to Marketplaces") { 90 | unstash 'vsix' 91 | unstash 'tgz' 92 | def vsix = findFiles(glob: '**.vsix') 93 | 94 | if ('true'.equals(publishToMarketPlace) || 'true'.equals(publishPreRelease)) { 95 | // VS Code Marketplace 96 | withCredentials([[$class: 'StringBinding', credentialsId: 'vscode_java_marketplace', variable: 'TOKEN']]) { 97 | sh 'vsce publish -p ${TOKEN} --packagePath' + " ${vsix[0].path}" 98 | } 99 | } 100 | 101 | if ('true'.equals(publishToOVSX)) { 102 | // open-vsx Marketplace 103 | sh 'npm install -g ovsx' 104 | withCredentials([[$class: 'StringBinding', credentialsId: 'open-vsx-access-token', variable: 'OVSX_TOKEN']]) { 105 | sh 'ovsx publish -p ${OVSX_TOKEN}' + " ${vsix[0].path}" 106 | } 107 | } 108 | 109 | archiveArtifacts artifacts:"**.vsix,**.tgz" 110 | 111 | if ('true'.equals(publishToMarketPlace)) { 112 | stage "Promote the build to stable" 113 | sh "sftp -C ${UPLOAD_LOCATION}/stable/vscode-microprofile/ <<< \$'put -p ${vsix[0].path}'" 114 | def tgz = findFiles(glob: '**.tgz') 115 | sh "sftp -C ${UPLOAD_LOCATION}/stable/vscode-microprofile/ <<< \$'put -p ${tgz[0].path}'" 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tools for MicroProfile 2 | 3 | [![Visual Studio Marketplace](https://img.shields.io/visual-studio-marketplace/v/redhat.vscode-microprofile?style=for-the-badge&label=VS%20Marketplace&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-microprofile) 4 | [![Installs](https://img.shields.io/visual-studio-marketplace/i/redhat.vscode-microprofile?style=for-the-badge)](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-microprofile) 5 | [![Chat](https://img.shields.io/gitter/room/redhat-developer/vscode-microprofile?style=for-the-badge&logo=gitter)](https://gitter.im/redhat-developer/vscode-microprofile) 6 | [![Build Status](https://img.shields.io/github/actions/workflow/status/redhat-developer/vscode-microprofile/tests.yml?branch=master&style=for-the-badge&logo=github)](https://github.com/redhat-developer/vscode-microprofile/actions?query=branch%3Amaster) 7 | [![License](https://img.shields.io/github/license/redhat-developer/vscode-microprofile?style=for-the-badge)](https://github.com/redhat-developer/vscode-microprofile/blob/master/LICENSE) 8 | 9 | ## Description 10 | 11 | This Visual Studio Code extension provides support for the development of [MicroProfile®](https://microprofile.io/)-based applications, via the [LSP4MP project](https://github.com/eclipse/lsp4mp), which consists of: 12 | 13 | * a [language server for MicroProfile](https://github.com/eclipse/lsp4mp/tree/master/microprofile.ls). 14 | * a [jdt.ls extension for MicroProfile](https://github.com/eclipse/lsp4mp/tree/master/microprofile.jdt). 15 | 16 | ![](images/propertiesSupport.png) 17 | 18 | ## MicroProfile `properties` Features 19 | 20 | In `microprofile-config.properties` files, you will benefit with: 21 | 22 | * [Completion support for MicroProfile properties](./docs/PropertiesFeatures.md#completion-support) 23 | * [Hover support for MicroProfile properties](./docs/PropertiesFeatures.md#hover-support) 24 | * [Definition support for MicroProfile properties](./docs/PropertiesFeatures.md#definition-support) 25 | * [Format support for MicroProfile properties](./docs/PropertiesFeatures.md#format-support) 26 | * [Validation and Quick Fix support for MicroProfile properties](./docs/PropertiesFeatures.md#validation-and-quick-fix-support) 27 | * [Outline support (flat or tree view)](./docs/PropertiesFeatures.md#outline-support) 28 | 29 | ## MicroProfile `Java` Features 30 | 31 | In `Java` files, you will benefit with: 32 | 33 | * [Completion support for MicroProfile](./docs/JavaFeatures.md#completion-support) 34 | * [Hover support for MicroProfile](./docs/JavaFeatures.md#hover-support) 35 | * [Validation and Quick Fix support for MicroProfile](./docs/JavaFeatures.md#validation-and-quick-fix-support) 36 | * [Code Lens support for MicroProfile](./docs/JavaFeatures.md#codelens-support) 37 | * [Workspace symbols](./docs/JavaFeatures.md#workspace-symbols-support) 38 | * [Code snippets](./docs/JavaFeatures.md#snippets-support) 39 | 40 | ## Requirements 41 | 42 | * [Language Support for Java(TM) by Red Hat](https://marketplace.visualstudio.com/items?itemName=redhat.java) 43 | * Java JDK (or JRE) 21 or more recent is required **except** on the following platforms : `win32-x64`, `linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64`. See [JDK Tooling](https://github.com/redhat-developer/vscode-java/#java-tooling-jdk) for details. 44 | 45 | ## Supported VS Code settings 46 | 47 | The following settings are supported: 48 | 49 | * `microprofile.tools.formatting.surroundEqualsWithSpaces` : Insert spaces around the equals sign when formatting the application.properties file. Default is `false`. 50 | * `microprofile.tools.trace.server` : Trace the communication between VS Code and the MicroProfile Language Server in the Output view. 51 | * `microprofile.tools.symbols.showAsTree` : Show MicroProfile properties as tree (Outline). Default is `true`. 52 | * `microprofile.tools.validation.enabled` : Enables MicroProfile validation. Default is `true`. 53 | * `microprofile.tools.validation.duplicate.severity` : Validation severity for duplicate properties for MicroProfile `*.properties` files. 54 | Default is `warning`. 55 | * `microprofile.tools.validation.syntax.severity` : Validation severity for property syntax checking for MicroProfile `*.properties` files. 56 | Default is `error`. 57 | * `microprofile.tools.validation.required.severity` : Validation severity for required properties for MicroProfile `*.properties` files. 58 | Default is `none`. 59 | * `microprofile.tools.validation.expression.severity` : Validation severity for property expressions for MicroProfile `*.properties` files. 60 | Default is `error`. 61 | * `microprofile.tools.validation.unknown.severity` : Validation severity for unknown properties for MicroProfile `*.properties` files. Default is `warning`. 62 | * `microprofile.tools.validation.unknown.excluded` : Array of properties to ignore for unknown properties validation. Patterns can be used ('\*' = any string, '?' = any character). 63 | Default is `["*/mp-rest/providers/*/priority", "mp.openapi.schema.*", "kafka-streams.*", "camel.*"]`. 64 | * `microprofile.tools.codeLens.urlCodeLensEnabled` : Enable/disable the URL code lenses for REST services. Default is`true`. 65 | * `microprofile.tools.validation.value.severity`: Validation severity for property values for MicroProfile `*.properties` files. Default is `error`. 66 | * `microprofile.tools.validation.unassigned.excluded`: Array of properties to ignore for unassigned properties validation in Java files. Patterns can be used ('\*' = any string, '?' = any character). 67 | * `microprofile.tools.inlayHint.enabled`: Enable/disable the inlay hint support. Default is `false`. 68 | 69 | ### **Note for MicroProfile Rest Client properties**: 70 | 71 | Due to [this issue](https://github.com/redhat-developer/quarkus-ls/issues/203), the MP Rest property: `/mp-rest/providers//priority` reports an unknown error. 72 | 73 | To avoid having this error, you must configure the following in `settings.json`: 74 | 75 | ```json 76 | "microprofile.tools.validation.unknown.excluded": [ 77 | "*/mp-rest/providers/*/priority" 78 | ] 79 | ``` 80 | 81 | This settings is set by default. 82 | 83 | 84 | ## Extending Tools for MicroProfile 85 | 86 | By default, Tools for MicroProfile provides: 87 | 88 | * Support for the `microprofile-config.properties` file (completion, validation, etc.) for the properties of MicroProfile specs (config, health, fault tolerance, etc.). 89 | * Support in java files (diagnostics, codelens, etc.) taking into account the API of each of the MicroProfile specs. 90 | 91 | The support for properties and java files can be extended with: 92 | 93 | * Additional language features (diagnostics, quick fixes, etc.) in Java files for modules other than MicroProfile specs. 94 | * Additional properties support for properties other than those defined by MicroProfile specs (Ex. Quarkus properties) 95 | * Additional language / document selectors to allow MicroProfile language features in files other than `microprofile-config.properties` (Ex. the `application.properties` file for Quarkus) 96 | 97 | To contribute these features, you must create a vscode-extension that declares the `microprofile` contributions in its package.json. These contributions will be picked up automatically by vscode-microprofile when it starts up the language server. 98 | 99 | ```json 100 | "contributes": { 101 | "microprofile": { 102 | "jarExtensions": [...], 103 | "documentSelector": [...], 104 | } 105 | } 106 | ``` 107 | 108 | ### Contributing to properties and Java support 109 | 110 | LSP4MP can be [extended](https://github.com/eclipse/lsp4mp#extensions) to support custom completion, hover, validation, etc by using the [Java Service Provider Interface (SPI)](https://www.baeldung.com/java-spi). vscode-microprofile provides the ability to use your custom lsp4mp extension by contributing external JARs to the classpath of lsp4mp. 111 | 112 | To contribute an external JAR you must create a vscode extension which embeds your lsp4mp extension JAR and declares the path to your JAR in the extensions package.json 113 | 114 | ```json 115 | "contributes": { 116 | "microprofile": { 117 | "jarExtensions": [ 118 | "./jar/com.demo.custom-lsp4mp-extension.jar" 119 | ] 120 | } 121 | } 122 | ``` 123 | 124 | For an example of how this can be used you can look at [vscode-quarkus](https://github.com/redhat-developer/vscode-quarkus) and the [quarkus-ls](https://github.com/redhat-developer/quarkus-ls) lsp4mp extension. vscode-quarkus [contributes an external jar](https://github.com/redhat-developer/vscode-quarkus/blob/f38f4caaf218cf9c6ce91e64a0d9cd632314a483/package.json#L59) which provides additional language support for quarkus properties and java files. 125 | 126 | ### Contributing to MicroProfile Language / Document Selector support 127 | 128 | It is also possible to contribute additional document selectors which are used to register additional file types / languages with the lsp4mp language server 129 | 130 | ```json 131 | "contributes": { 132 | "microprofile": { 133 | "documentSelector": [ 134 | { 135 | "scheme": "file", 136 | "language": "my-custom-properties" 137 | } 138 | ] 139 | } 140 | } 141 | ``` 142 | 143 | For an example of how this can be used you can look at [vscode-quarkus](https://github.com/redhat-developer/vscode-quarkus) which [contributes a document selector](https://github.com/redhat-developer/vscode-quarkus/blob/f38f4caaf218cf9c6ce91e64a0d9cd632314a483/package.json#L62) for Quarkus's `application.properties` file in order to provide MicroProfile/Quarkus properties support in this file. 144 | 145 | ## Telemetry 146 | 147 | With your approval, vscode-microprofile extension collects anonymous [usage data](USAGE_DATA.md) and sends it to Red Hat servers to help improve our products and services. 148 | Read our [privacy statement](https://developers.redhat.com/article/tool-data-collection) to learn more. 149 | This extension respects the `redhat.telemetry.enabled` setting, which you can learn more about at https://github.com/redhat-developer/vscode-redhat-telemetry#how-to-disable-telemetry-reporting 150 | Note that this extension abides by Visual Studio Code's telemetry level: if `telemetry.telemetryLevel` is set to off, then no telemetry events will be sent to Red Hat, even if `redhat.telemetry.enabled` is set to true. If `telemetry.telemetryLevel` is set to `error` or `crash`, only events containing an error or errors property will be sent to Red Hat. 151 | 152 | ## Contributing 153 | 154 | This is an open source project open to anyone. Contributions are extremely welcome! 155 | 156 | For information on getting started, refer to the [CONTRIBUTING instructions](CONTRIBUTING.md). 157 | 158 | CI builds can be installed manually by following these instructions: 159 | 160 | 1) Download the latest development VSIX archive [from here](https://download.jboss.org/jbosstools/vscode/snapshots/vscode-microprofile/?C=M;O=D). `(vscode-microprofile-XXX.vsix)` 161 | 162 | 2) Click `View/Command Palette` 163 | 164 | 3) Type 'VSIX' 165 | 166 | 4) Select 'Install from VSIX...' and choose the `.vsix` file. 167 | 168 | ## Feedback 169 | 170 | Please report bugs, issues and feature requests by creating a [GitHub Issue](https://github.com/redhat-developer/vscode-microprofile/issues). 171 | 172 | ## License 173 | 174 | Apache License 2.0. 175 | See [LICENSE](LICENSE) file. 176 | 177 | 178 | MicroProfile® and the MicroProfile logo are trademarks of the Eclipse Foundation 179 | -------------------------------------------------------------------------------- /USAGE_DATA.md: -------------------------------------------------------------------------------- 1 | # USAGE DATA 2 | 3 | vscode-microprofile has opt-in telemetry collection, provided by [vscode-redhat-telemetry](https://github.com/redhat-developer/vscode-redhat-telemetry). 4 | 5 | ## What's included in the vscode-microprofile telemetry data 6 | 7 | vscode-microprofile emits telemetry events when the extension starts and stops, 8 | which contain the common data mentioned on the [vscode-redhat-telemetry page](https://github.com/redhat-developer/vscode-redhat-telemetry/blob/HEAD/USAGE_DATA.md#common-data). 9 | 10 | vscode-microprofile emits telemetry events whenever you apply a quick fix or source action, 11 | and emits an event if applying the quick fix or source action fails. 12 | 13 | ## How to opt in or out 14 | 15 | Use the `redhat.telemetry.enabled` setting in order to enable or disable telemetry collection. 16 | Note that this extension abides by Visual Studio Code's telemetry level: if `telemetry.telemetryLevel` is set to off, then no telemetry events will be sent to Red Hat, even if `redhat.telemetry.enabled` is set to true. If `telemetry.telemetryLevel` is set to `error` or `crash`, only events containing an error or errors property will be sent to Red Hat. 17 | -------------------------------------------------------------------------------- /docs/Features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | [vscode-microprofile](https://github.com/redhat-developer/vscode-microprofile) has a number of notable features available for MicroProfile projects. 4 | 5 | - [MicroProfile Properties Features](PropertiesFeatures.md) 6 | - [MicroProfile Java Features](JavaFeatures.md) 7 | -------------------------------------------------------------------------------- /docs/JavaFeatures.md: -------------------------------------------------------------------------------- 1 | # MicroProfile Java Features 2 | 3 | A MicroProfile project provides microservice architecture for Java applications. vscode-microprofile provides a variety of support for Java files. 4 | 5 | ## Completion support 6 | 7 | As a main component of development with MicroProfile, annotations are used to expose APIs. For MicroProfile annotation, completion support is available using `Ctrl + Space`. An example of this is the `fallbackMethod` completion for the MicroProfile Fault Tolerance `@Fallback` annotation. 8 | 9 | ![MP Java Completion](./res/MPJavaCompletion.gif) 10 | 11 | ## Snippets support 12 | 13 | In Java files in a MicroProfile project, vscode-microprofile provides the following snippets: 14 | 15 | * `rest_class`: Create a new JAX-RS/Jakarta REST resource class 16 | * `rest_get`: Create a new JAX-RS/Jakarta REST GET resource method 17 | * `mpreadiness`: Create a readiness check class 18 | * `mpliveness`: Create a liveness check class 19 | * `mpnrc`: Create a new MicroProfile REST client 20 | * `mpirc`: Inject a MicroProfile REST client 21 | * Snippets to help fill out the parameters for annotations that are introduced by MicroProfile: 22 | * `@Timeout` 23 | * `@Retry` 24 | * `@Fallback` 25 | * `@CircuitBreaker` 26 | * `@Bulkhead` 27 | * `@Metric` 28 | * `@Counted` 29 | * `@Gauge` 30 | * `@ConcurrentGauge` 31 | * `@Metered` 32 | * `@Timed` 33 | * `@SimplyTimed` 34 | * `@RegistryType` 35 | * `@Operation` 36 | * `@Content` 37 | * `@Schema` 38 | * `@Parameters` 39 | * `@Parameter` 40 | * `@APIResponses` 41 | * `@APIResponse` 42 | 43 | Only snippets relevant to the context are shown. 44 | That means that if the cursor is in a place where it doesn't make sense to add the snippet content, 45 | or if the classes that the snippet references are on the classpath of the project, 46 | then the snippets won't be shown. 47 | 48 | ## Hover support 49 | 50 | Given any MicroProfile annotation, hover support is available for more info on usage, interface, etc.. 51 | 52 | An example of this is the reference to the `@ConfigProperty` annotation value defined in the project properties file. 53 | 54 | ![MP Java Hover](./res/MPJavaHover.gif) 55 | 56 | ## Navigation support 57 | 58 | For any reference to a local definition of an annotation value, `Ctrl + Click` will navigate to the value definition. 59 | 60 | ![MP Java Navigation](./res/MPJavaNavigation.gif) 61 | 62 | Similarly, there is navigation support for any `microprofile-config.properties` definition referenced in the Java project also using `Ctrl + Click`. 63 | 64 | ![MP Java Navigation](./res/MPJavaNavigationConfig.gif) 65 | 66 | ## Validation and Quick Fix support 67 | 68 | Diagnostics are supported for MicroProfile annotations which targets errors and warnings that would thrown on runtime. Most of these diagnostics also have an associated quick fix to triage the diagnostic. 69 | 70 | ![MP Java Validation and Quick Fix](./res/MPJavaValidationAndQuickFix.gif) 71 | 72 | ## CodeLens support 73 | 74 | On debug, a Quarkus application run with MicroProfile sources supports a URL CodeLens that routes to the endpoint debug path. 75 | 76 | ![MP Java Code Lens](./res/MPJavaCodeLens.png) 77 | 78 | ## Workspace Symbols support 79 | 80 | vscode-microprofile provides workspace symbols for: 81 | 82 | ### Jakarta/JAX-RS REST methods 83 | 84 | Workspace Symbols with the prefix `@` refer to Jakarta/JAX-RS REST methods. 85 | vscode-microprofile lists the URL and the HTTP method for each method. 86 | 87 | ![Workspace Symbols for Jakarta/JAX-RS REST](./res/WorkspaceSymbolsJakartaREST.gif) 88 | -------------------------------------------------------------------------------- /docs/PropertiesFeatures.md: -------------------------------------------------------------------------------- 1 | # MicroProfile Properties Features 2 | 3 | A MicroProfile project can be configured using a `microprofile-config.properties` file. vscode-microprofile provides a variety of support for `microprofile-config.properties` files. 4 | 5 | These features are made available given a "Microprofile properties" file has been detected. 6 | 7 | ![MP Properties Detection](./res/MPPropertiesDetection.png) 8 | 9 | These features are also supported for a user profile on the [config level](https://download.eclipse.org/microprofile/microprofile-config-2.0/microprofile-config-spec-2.0.html#_on_config_source_level) and the [property level](https://download.eclipse.org/microprofile/microprofile-config-2.0/microprofile-config-spec-2.0.html#_on_property_level). For example, a file such as `microprofile-config-prod.properties` will have feature support in relation to the `prod` profile. 10 | 11 | ## Completion support 12 | 13 | Depending on the extensions installed for the project, the property autocomplete feature lists suggested properties based on the text entered and extensions available. 14 | 15 | ![Property Completion](./res/MPPropertyCompletion.gif) 16 | 17 | Value completion is also supported for each property. 18 | 19 | ### Read more 20 | 21 | You can find out more on the available extensions and the completion supported for your MicroProfile project version at microprofile.io. 22 | 23 | ## Hover support 24 | 25 | For any given supported property defined in `microprofile-config.properties`, hovering the property will list details about the property, including type, associated extension and assigned value, if any. 26 | 27 | ![Property Hover](./res/MPPropertyHover.gif) 28 | 29 | ## Definition support 30 | 31 | ### Java file definition 32 | 33 | If a property value is configured in `microprofile-config.properties`, `Ctrl + Click` of the property will jump to the Java file declaration. 34 | ![Java Definition](./res/MPJumpToJavaDefinition.gif) 35 | 36 | ### Properties definition 37 | 38 | If a property value is defined using a [property expression](https://download.eclipse.org/microprofile/microprofile-config-2.0/microprofile-config-spec-2.0.html#property-expressions) (i.e. `${}`) which references another property defined in `microprofile-config.properties`, `Ctrl + Click` of the property expression value will jump to the property definition. 39 | 40 | ![Property Definition](./res/MPPropertyValueDefinition.gif) 41 | 42 | ## Format support 43 | 44 | A "Microprofile properties" file sets the default formatter to "Tools for MicroProfile", so the formatting shortcut for a `microprofile-config.properties` file is `Ctrl + Shift + I`. The formatter can also be accessed from the command palette and right-click dropdown. 45 | 46 | ![Property Formatter](./res/MPFormatter.gif) 47 | 48 | ## Validation and Quick Fix support 49 | 50 | For any supported property that can be defined in a "Microprofile properties" file, there is validation for the property name and a quick fix action to correct the diagnostic. 51 | 52 | ![Property Quick Fix](./res/MPPropertyQuickFix.gif) 53 | 54 | ## Outline support 55 | 56 | Given the following `microprofile-config.properties` file: 57 | 58 | ```properties 59 | mp.metrics.appName=foo 60 | mp.metrics.tags=bar 61 | ``` 62 | 63 | With the `microprofile.tools.symbols.showAsTree` setting enabled: 64 | 65 | ![Show As Tree Setting](./res/MPShowAsTreeSetting.png) 66 | 67 | The property hierarchy can be viewed from the "Outline" tab. 68 | 69 | ![Show As Tree Outline](./res/MPShowAsTreeOutline.png) 70 | -------------------------------------------------------------------------------- /docs/res/MPFormatter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPFormatter.gif -------------------------------------------------------------------------------- /docs/res/MPJavaCodeLens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaCodeLens.png -------------------------------------------------------------------------------- /docs/res/MPJavaCompletion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaCompletion.gif -------------------------------------------------------------------------------- /docs/res/MPJavaHover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaHover.gif -------------------------------------------------------------------------------- /docs/res/MPJavaNavigation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaNavigation.gif -------------------------------------------------------------------------------- /docs/res/MPJavaNavigationConfig.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaNavigationConfig.gif -------------------------------------------------------------------------------- /docs/res/MPJavaValidationAndQuickFix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJavaValidationAndQuickFix.gif -------------------------------------------------------------------------------- /docs/res/MPJumpToJavaDefinition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPJumpToJavaDefinition.gif -------------------------------------------------------------------------------- /docs/res/MPPropertiesDetection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPPropertiesDetection.png -------------------------------------------------------------------------------- /docs/res/MPPropertyCompletion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPPropertyCompletion.gif -------------------------------------------------------------------------------- /docs/res/MPPropertyHover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPPropertyHover.gif -------------------------------------------------------------------------------- /docs/res/MPPropertyQuickFix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPPropertyQuickFix.gif -------------------------------------------------------------------------------- /docs/res/MPPropertyValueDefinition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPPropertyValueDefinition.gif -------------------------------------------------------------------------------- /docs/res/MPShowAsTreeOutline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPShowAsTreeOutline.png -------------------------------------------------------------------------------- /docs/res/MPShowAsTreeSetting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/MPShowAsTreeSetting.png -------------------------------------------------------------------------------- /docs/res/WorkspaceSymbolsJakartaREST.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/docs/res/WorkspaceSymbolsJakartaREST.gif -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from '@eslint/js'; 4 | import tseslint from 'typescript-eslint'; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | tseslint.configs.recommended, 9 | { 10 | files: [ 11 | "*/**test.ts" 12 | ], 13 | rules: { 14 | "@typescript-eslint/no-unused-expressions": "off" 15 | } 16 | }, 17 | ); 18 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Red Hat, Inc. and others. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | const gulp = require('gulp'); 15 | const rename = require('gulp-rename'); 16 | const cp = require('child_process'); 17 | const fse = require('fs-extra'); 18 | 19 | const microprofileServerName = 'org.eclipse.lsp4mp.ls-uber.jar'; 20 | const microprofileServerDir = '../lsp4mp/microprofile.ls/org.eclipse.lsp4mp.ls'; 21 | 22 | const microprofileExtensionDir = '../lsp4mp/microprofile.jdt'; 23 | const microprofileExtension = 'org.eclipse.lsp4mp.jdt.core'; 24 | const microprofileSite = 'org.eclipse.lsp4mp.jdt.site'; 25 | 26 | gulp.task('buildServer', (done) => { 27 | cp.execSync(mvnw() + ' clean install -B -DskipTests', { cwd: microprofileServerDir , stdio: 'inherit' }); 28 | gulp.src(microprofileServerDir + '/target/' + microprofileServerName, { encoding: false }) 29 | .pipe(gulp.dest('./server')); 30 | done(); 31 | }); 32 | 33 | gulp.task('buildExtension', (done) => { 34 | cp.execSync(mvnw() + ' clean verify -B -DskipTests', { cwd: microprofileExtensionDir, stdio: 'inherit' }); 35 | gulp.src(microprofileExtensionDir + '/' + microprofileExtension + '/target/' + microprofileExtension + '-!(*sources).jar', { encoding: false }) 36 | .pipe(rename(microprofileExtension + '.jar')) 37 | .pipe(gulp.dest('./jars')); 38 | gulp.src(microprofileExtensionDir + '/' + microprofileSite + '/target/repository/plugins/wrapped*.jar', { encoding: false }) 39 | .pipe(rename(function (path, _file) { 40 | const patt = /wrapped\.([^_]+).*/; 41 | const result = path.basename.match(patt); 42 | path.basename = result[1]; 43 | })) 44 | .pipe(gulp.dest('./jars')); 45 | gulp.src(microprofileExtensionDir + '/' + microprofileSite + '/target/repository/plugins/org.jboss.logging*.jar', { encoding: false }) 46 | .pipe(rename(function (path, _file) { 47 | const patt = /([^_]+).*/; 48 | const result = path.basename.match(patt); 49 | path.basename = result[1]; 50 | })) 51 | .pipe(gulp.dest('./jars')); 52 | done(); 53 | }); 54 | 55 | gulp.task('build', gulp.series('buildServer', 'buildExtension')); 56 | 57 | gulp.task('prepare_pre_release', function (done) { 58 | const json = JSON.parse(fse.readFileSync("./package.json").toString()); 59 | const stableVersion = json.version.match(/(\d+)\.(\d+)\.(\d+)/); 60 | const major = stableVersion[1]; 61 | const minor = stableVersion[2]; 62 | const date = new Date(); 63 | const month = date.getMonth() + 1; 64 | const day = date.getDate(); 65 | const hours = date.getHours(); 66 | const patch = `${date.getFullYear()}${prependZero(month)}${prependZero(day)}${prependZero(hours)}`; 67 | const insiderPackageJson = Object.assign(json, { 68 | version: `${major}.${minor}.${patch}`, 69 | }); 70 | fse.writeFileSync("./package.json", JSON.stringify(insiderPackageJson, null, 2)); 71 | done(); 72 | }); 73 | 74 | function mvnw() { 75 | return isWin() ? 'mvnw.cmd' : './mvnw'; 76 | } 77 | 78 | function isWin() { 79 | return /^win/.test(process.platform); 80 | } 81 | 82 | function prependZero(number) { 83 | if (number > 99) { 84 | throw "Unexpected value to prepend with zero"; 85 | } 86 | return `${number < 10 ? "0" : ""}${number}`; 87 | } 88 | -------------------------------------------------------------------------------- /icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/icons/logo.png -------------------------------------------------------------------------------- /images/componentDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/componentDiagram.png -------------------------------------------------------------------------------- /images/debugConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/debugConfig.png -------------------------------------------------------------------------------- /images/debugConfigMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/debugConfigMenu.png -------------------------------------------------------------------------------- /images/deployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/deployment.png -------------------------------------------------------------------------------- /images/propertiesSupport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/propertiesSupport.png -------------------------------------------------------------------------------- /images/runDebugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/runDebugger.png -------------------------------------------------------------------------------- /images/runDebuggerVSCodeTests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/runDebuggerVSCodeTests.png -------------------------------------------------------------------------------- /images/runExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-microprofile/7e9d4d72fb6887cff89893052542671d1df61098/images/runExtension.png -------------------------------------------------------------------------------- /language-support/properties-support/language-configuration.json: -------------------------------------------------------------------------------- 1 | // Referenced from: 2 | // https://github.com/spring-projects/sts4/blob/0714b6a69309789ac85441062698153b0ac4d9c6/vscode-extensions/vscode-spring-boot/properties-support/language-configuration.json 3 | 4 | { 5 | "comments": { 6 | "lineComment": "#" 7 | }, 8 | "brackets": [ 9 | ], 10 | "autoClosingPairs": [ 11 | ["{", "}"], 12 | ["[", "]"], 13 | ["(", ")"], 14 | ["\"", "\""], 15 | ["'", "'"] 16 | ], 17 | "surroundingPairs": [ 18 | ["{", "}"], 19 | ["[", "]"], 20 | ["(", ")"], 21 | ["\"", "\""], 22 | ["'", "'"] 23 | ] 24 | } -------------------------------------------------------------------------------- /language-support/properties-support/microprofile-properties-injections.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "microprofile-value.injection", 3 | "injectionSelector": "L:string.unquoted.java-properties", 4 | "patterns": [ 5 | { 6 | "include": "#numbers" 7 | }, 8 | { 9 | "include": "#expression" 10 | } 11 | ], 12 | "repository": { 13 | "numbers": { 14 | "patterns": [ 15 | { 16 | "match": "(?x)\n\\b(?, 38 | javaRequirement: Promise, 39 | serverMode: ServerMode, 40 | onDidServerModeChange(callback: (mode: string) => void); 41 | }; 42 | 43 | export async function activate(context: ExtensionContext): Promise { 44 | if (await isJavaProject()) { 45 | await doActivate(context); 46 | } 47 | } 48 | 49 | async function doActivate(context: ExtensionContext) { 50 | const redHatService: RedHatService = await getRedHatService(context); 51 | const telemetryService: TelemetryService = await redHatService.getTelemetryService(); 52 | await telemetryService.sendStartupEvent(); 53 | 54 | const yamlSchemaCache = getYamlSchemaCache(); 55 | let yamlRegistered = false; 56 | 57 | /** 58 | * Register Yaml Schema support to manage appropriate yaml files if currently open in workspace 59 | */ 60 | if (hasOpenedYamlConfig()) { 61 | registerYamlSchemaSupport(); 62 | yamlRegistered = true; 63 | } 64 | 65 | /** 66 | * Monitor opened files to register Yaml Schema support if appropriate yaml file is opened 67 | */ 68 | workspace.onDidOpenTextDocument((e: TextDocument) => { 69 | yamlRegistered = registerYamlSchemaSupportIfNeeded(e.fileName, yamlSchemaCache, yamlRegistered); 70 | }); 71 | 72 | /** 73 | * Monitor created files to register Yaml Schema support if appropriate yaml file is created 74 | */ 75 | workspace.onDidCreateFiles((e: FileCreateEvent) => { 76 | yamlRegistered = registerYamlSchemaSupportIfNeeded(e.files[0].fsPath, yamlSchemaCache, yamlRegistered); 77 | }); 78 | 79 | /** 80 | * Waits for the java language server to launch in standard mode 81 | * Before activating Tools for MicroProfile. 82 | * If java ls was started in lightweight mode, It will prompt user to switch 83 | */ 84 | const api: JavaExtensionAPI = await getJavaExtensionAPI(); 85 | await waitForStandardMode(api); 86 | 87 | const microprofileContributions: MicroProfileContribution[] = collectMicroProfileJavaExtensions(extensions.all); 88 | const documentSelector = getDocumentSelector(microprofileContributions); 89 | connectToLS(context, api, documentSelector, microprofileContributions).then(() => { 90 | yamlSchemaCache.then(cache => { if (cache) { cache.languageClient = languageClient; } }); 91 | 92 | /** 93 | * Delegate requests from MicroProfile LS to the Java JDT LS 94 | */ 95 | bindRequest(MicroProfileLS.PROJECT_INFO_REQUEST); 96 | bindRequest(MicroProfileLS.PROPERTY_DEFINITION_REQUEST); 97 | bindRequest(MicroProfileLS.PROPERTY_DOCUMENTATION_REQUEST); 98 | bindRequest(MicroProfileLS.JAVA_CODEACTION_REQUEST); 99 | bindRequest(MicroProfileLS.JAVA_CODEACTION_RESOLVE_REQUEST); 100 | bindRequest(MicroProfileLS.JAVA_CODELENS_REQUEST); 101 | bindRequest(MicroProfileLS.JAVA_COMPLETION_REQUEST); 102 | bindRequest(MicroProfileLS.JAVA_DEFINITION_REQUEST); 103 | bindRequest(MicroProfileLS.JAVA_DIAGNOSTICS_REQUEST); 104 | bindRequest(MicroProfileLS.JAVA_HOVER_REQUEST); 105 | bindRequest(MicroProfileLS.JAVA_WORKSPACE_SYMBOLS_REQUEST); 106 | bindRequest(MicroProfileLS.JAVA_FILE_INFO_REQUEST); 107 | bindRequest(MicroProfileLS.JAVA_PROJECT_LABELS_REQUEST); 108 | bindRequest(MicroProfileLS.JAVA_WORKSPACE_LABELS_REQUEST); 109 | 110 | /** 111 | * Delegate notifications from Java JDT LS to the MicroProfile LS 112 | */ 113 | context.subscriptions.push(commands.registerCommand(MicroProfileLS.PROPERTIES_CHANGED_NOTIFICATION, (event: MicroProfilePropertiesChangeEvent) => { 114 | languageClient.sendNotification(MicroProfileLS.PROPERTIES_CHANGED_NOTIFICATION, event); 115 | yamlSchemaCache.then(cache => { 116 | if (cache) 117 | cache.evict(event); 118 | }); 119 | })); 120 | 121 | /** 122 | * Registers a command that, given an LSP code action and a cancellation token: 123 | * 124 | * 1. Resolves the code action if necessary 125 | * 2. Runs command/applies workspace edit. If a code action provides 126 | * an edit and a command, first the edit is executed and then the command, 127 | * similar to how code actions are handled in the LSP specification. 128 | * 3. Sends telemetry if telemetry is enabled and the code action succeeds or fails 129 | */ 130 | context.subscriptions.push(commands.registerCommand(APPLY_CODE_ACTION_WITH_TELEMETRY, async (lsCodeActionOrCommand: CodeAction | Command, resolvedEdit: boolean) => { 131 | let codeActionId: string | null = null; 132 | try { 133 | if (Command.is(lsCodeActionOrCommand)) { 134 | const command = lsCodeActionOrCommand as Command; 135 | codeActionId = command.command; 136 | await commands.executeCommand(command.command, ...command.arguments); 137 | } else { 138 | let lsCodeAction = lsCodeActionOrCommand as CodeAction; 139 | codeActionId = lsCodeAction.data?.id; 140 | if ((!resolvedEdit) && (!lsCodeAction.command)) { 141 | // resolve the code action 142 | lsCodeAction = await languageClient.sendRequest(CodeActionResolveRequest.type, lsCodeAction); 143 | } 144 | 145 | if (lsCodeAction.edit) { 146 | const vsCodeAction = await languageClient.protocol2CodeConverter.asCodeAction(lsCodeAction); 147 | await workspace.applyEdit(vsCodeAction.edit); 148 | } 149 | if (lsCodeAction.command) { 150 | if (!codeActionId) { 151 | codeActionId = lsCodeAction.command.command; 152 | } 153 | const vsCommand = languageClient.protocol2CodeConverter.asCommand(lsCodeAction.command); 154 | await commands.executeCommand(vsCommand.command, ...vsCommand.arguments); 155 | } 156 | } 157 | await sendCodeActionTelemetry(telemetryService, codeActionId || 'unknown', true); 158 | } catch (e) { 159 | await sendCodeActionTelemetry(telemetryService, codeActionId || 'unknown', false, e); 160 | } 161 | })); 162 | 163 | }).catch((error) => { 164 | window.showErrorMessage(error.message, error.label).then((selection) => { 165 | if (error.label && error.label === selection && error.openUrl) { 166 | commands.executeCommand('vscode.open', error.openUrl); 167 | } 168 | }); 169 | }); 170 | 171 | function bindRequest(request: string) { 172 | const requestType = new RequestType(request); 173 | languageClient.onRequest(requestType, async (params, token: CancellationToken) => { 174 | await api.serverReady(); 175 | return commands.executeCommand( 176 | "java.execute.workspaceCommand", 177 | request, 178 | params, 179 | token 180 | ); 181 | }); 182 | } 183 | 184 | registerVSCodeCommands(context); 185 | } 186 | 187 | export async function deactivate(): Promise { 188 | // language client may not have been started 189 | // if java language server was never launched in standard mode. 190 | if (languageClient) { 191 | await languageClient.stop(); 192 | } 193 | } 194 | 195 | function registerVSCodeCommands(context: ExtensionContext) { 196 | /** 197 | * Register standard LSP commands 198 | */ 199 | context.subscriptions.push(registerConfigurationUpdateCommand()); 200 | context.subscriptions.push(registerOpenURICommand()); 201 | } 202 | 203 | const REPLACE_JDT_LINKS_PATTERN = /(\[(?:[^\]])+\]\()(jdt:\/\/(?:(?:(?:\\\))|([^)]))+))\)/g; 204 | const VSCODE_JAVA_OPEN_FILE_COMMAND_ID = "java.open.file"; 205 | 206 | /** 207 | * Replace `jdt://` links in the documentation with links that execute the VS Code command required to open the referenced file. 208 | * 209 | * Adapted from vscode-java. 210 | * 211 | * @param oldDocumentation the documentation to fix the links in 212 | * @returns the documentation with fixed links 213 | */ 214 | function fixJdtLinksInDocumentation(oldDocumentation: MarkdownString): MarkdownString { 215 | const newContent: string = oldDocumentation.value.replace(REPLACE_JDT_LINKS_PATTERN, (_substring, group1, group2) => { 216 | const uri = `command:${VSCODE_JAVA_OPEN_FILE_COMMAND_ID}?${encodeURI(JSON.stringify([encodeURIComponent(group2)]))}`; 217 | return `${group1}${uri})`; 218 | }); 219 | const mdString = new MarkdownString(newContent); 220 | mdString.isTrusted = true; 221 | return mdString; 222 | } 223 | 224 | async function connectToLS(context: ExtensionContext, api: JavaExtensionAPI, documentSelector: DocumentSelector, microprofileContributions: MicroProfileContribution[]) { 225 | const requirements = await resolveRequirements(api); 226 | const clientOptions: LanguageClientOptions = { 227 | documentSelector: documentSelector, 228 | // wrap with key 'settings' so it can be handled same a DidChangeConfiguration 229 | initializationOptions: { 230 | settings: getVSCodeMicroProfileSettings(), 231 | extendedClientCapabilities: { 232 | commands: { 233 | commandsKind: { 234 | valueSet: [ 235 | CommandKind.COMMAND_CONFIGURATION_UPDATE, 236 | CommandKind.COMMAND_OPEN_URI 237 | ] 238 | } 239 | }, 240 | completion: { 241 | skipSendingJavaCompletionThroughLanguageServer: false 242 | }, 243 | shouldLanguageServerExitOnShutdown: true 244 | } 245 | }, 246 | synchronize: { 247 | // preferences starting with these will trigger didChangeConfiguration 248 | configurationSection: ['microprofile', '[microprofile]'] 249 | }, 250 | middleware: { 251 | workspace: { 252 | didChangeConfiguration: async () => { 253 | languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getVSCodeMicroProfileSettings() }); 254 | } 255 | }, 256 | provideHover: async (document, position, token, next): Promise => { 257 | const hover = await next(document, position, token); 258 | if (hover === null || hover === undefined) { 259 | return hover; 260 | } 261 | const newContents: (MarkedString | MarkdownString)[] = []; 262 | for (const content of hover.contents) { 263 | if (content instanceof MarkdownString) { 264 | newContents.push(fixJdtLinksInDocumentation(content)); 265 | } else { 266 | newContents.push(content); 267 | } 268 | } 269 | hover.contents = newContents; 270 | return hover; 271 | }, 272 | resolveCompletionItem: async (item, token, next): Promise => { 273 | const completionItem = await next(item, token); 274 | if (completionItem !== undefined && completionItem !== null && completionItem.documentation instanceof MarkdownString) { 275 | completionItem.documentation = fixJdtLinksInDocumentation(completionItem.documentation); 276 | } 277 | return completionItem; 278 | }, 279 | provideCodeActions: async (document, range, context, token, next): Promise => { 280 | // Collect the code actions from the language server, 281 | // then rewrite them to execute the command "microprofile.applyCodeAction" 282 | // instead of whatever action was specified by the language server. 283 | // "microprofile.applyCodeAction" is a command that accepts a code action, 284 | // then applies it, then sends a telemetry event indicating which 285 | // code action was applied. 286 | return (await next(document, range, context, token)) 287 | .map((vsCodeActionOrCommand) => { 288 | let kind: CodeActionKind = undefined; 289 | let diagnostics: VSDiagnostic[] = undefined; 290 | let edit = undefined; 291 | // As command arguments are JSON object, code action / command from vscode 292 | // cannot be used as "microprofile.applyCodeAction" arguments because 293 | // it cannot be serialized as JSON correctly (some information are loosen like data, range, etc) 294 | // That's why "microprofile.applyCodeAction" arguments is filled with LSP code action /command. 295 | let lsCodeActionOrCommand: CodeAction | Command = undefined; 296 | if (Command.is(vsCodeActionOrCommand)) { 297 | // Get LSP command from the vscode command 298 | const vsCodeCommand: VSCommand = vsCodeActionOrCommand; 299 | lsCodeActionOrCommand = languageClient.code2ProtocolConverter.asCommand(vsCodeCommand); 300 | } else { 301 | // Get LSP code action from the vscode code action 302 | const vsCodeAction: VSCodeAction = vsCodeActionOrCommand; 303 | kind = vsCodeAction.kind; 304 | diagnostics = vsCodeAction.diagnostics; 305 | if (vsCodeAction.edit) { 306 | // When code action defines the edit, we return a code action with this vscode edit. 307 | // The apply workspace edit will be done by vscode himself and not by the command 308 | // "microprofile.applyCodeAction". In other words "microprofile.applyCodeAction" apply the 309 | // workspace edit only if edit must be resolved by the resolve code action. 310 | edit = vsCodeAction.edit; 311 | vsCodeAction.edit = undefined; // to avoid throwing error from https://github.com/microsoft/vscode-languageserver-node/blob/277e4564193c4ed258fe4d8d405d3379665bbab9/client/src/common/codeConverter.ts#L740 312 | } 313 | lsCodeActionOrCommand = languageClient.code2ProtocolConverter.asCodeActionSync(vsCodeAction); 314 | } 315 | const title = vsCodeActionOrCommand.title; 316 | return { 317 | title: title, 318 | command: { 319 | command: APPLY_CODE_ACTION_WITH_TELEMETRY, 320 | title: title, 321 | arguments: [lsCodeActionOrCommand, edit != undefined] 322 | }, 323 | kind: kind, 324 | diagnostics: diagnostics, 325 | edit: edit 326 | } 327 | }); 328 | } 329 | } 330 | }; 331 | 332 | const serverOptions = prepareExecutable(requirements, getMicroProfileJarExtensions(microprofileContributions)); 333 | 334 | languageClient = new LanguageClient('microprofile.tools', 'Tools for MicroProfile', serverOptions, clientOptions); 335 | await languageClient.start(); 336 | 337 | if (extensions.onDidChange) {// Theia doesn't support this API yet 338 | context.subscriptions.push(extensions.onDidChange(() => { 339 | // if extensions that contribute mp java extensions change we need to reload the window 340 | handleExtensionChange(extensions.all); 341 | })); 342 | } 343 | 344 | /** 345 | * Returns a json object with key 'microprofile' and a json object value that 346 | * holds all microprofile settings. 347 | */ 348 | function getVSCodeMicroProfileSettings(): { microprofile: unknown } { 349 | const defaultMicroProfileSettings = {}; 350 | const configMicroProfile = workspace.getConfiguration().get('microprofile'); 351 | const microprofileSettings = configMicroProfile ? configMicroProfile : defaultMicroProfileSettings; 352 | 353 | return { 354 | microprofile: microprofileSettings, 355 | }; 356 | } 357 | 358 | /** 359 | * Returns an array of paths to MicroProfileLS extension jars within `microProfileContributions` 360 | * 361 | * @param microProfileContributions MicroProfile language server contributions from other VS Code extensions 362 | */ 363 | function getMicroProfileJarExtensions(microProfileContributions: MicroProfileContribution[]): string[] { 364 | let jarPaths: string[] = []; 365 | microProfileContributions.forEach((contribution: MicroProfileContribution) => { 366 | if (contribution.jarExtensions && contribution.jarExtensions.length > 0) { 367 | jarPaths = jarPaths.concat(contribution.jarExtensions); 368 | } 369 | }); 370 | return jarPaths; 371 | } 372 | } 373 | 374 | async function getJavaExtensionAPI(): Promise { 375 | const vscodeJava = extensions.getExtension(JAVA_EXTENSION_ID); 376 | if (!vscodeJava) { 377 | throw new Error("VSCode java is not installed"); 378 | } 379 | 380 | const api = await vscodeJava.activate(); 381 | if (!api) { 382 | throw new Error("VSCode java api not found"); 383 | } 384 | 385 | return Promise.resolve(api); 386 | } 387 | 388 | 389 | /** 390 | * Returns the document selector. 391 | * 392 | * The returned document selector contains the microprofile-properties and java document selectors 393 | * and all document selectors contained in `microProfileContributions`. 394 | * 395 | * @param microProfileContributions MicroProfile language server contributions from other VS Code extensions 396 | */ 397 | function getDocumentSelector(microProfileContributions: MicroProfileContribution[]): DocumentSelector { 398 | let documentSelector: DocumentSelector = [ 399 | { scheme: 'file', language: 'java' }, 400 | { scheme: 'file', language: 'microprofile-properties' } 401 | ]; 402 | microProfileContributions.forEach((contribution: MicroProfileContribution) => { 403 | documentSelector = documentSelector.concat(contribution.documentSelector); 404 | }); 405 | return documentSelector; 406 | } 407 | 408 | /** 409 | * Returns if any workspace folder contains a build.gradle, pom.xml, or .project. 410 | * 411 | * @returns true if any workspace folder contains a build.gradle, pom.xml, or .project 412 | */ 413 | async function isJavaProject(): Promise { 414 | if (!workspace.workspaceFolders) { 415 | return false; 416 | } 417 | for (const ws of workspace.workspaceFolders) { 418 | const buildFileUris = await getFilePathsFromWorkspace( 419 | ws, 420 | "**/{pom.xml,build.gradle,.project}" 421 | ); 422 | if (buildFileUris.length) { 423 | return true; 424 | } 425 | } 426 | return false; 427 | } 428 | 429 | /** 430 | * Returns if the given file name matches YAML config source file pattern. 431 | * 432 | * See https://download.eclipse.org/microprofile/microprofile-config-3.0/microprofile-config-spec-3.0.html#_on_config_source_level for an understanding of this pattern. 433 | * 434 | * @param fileName name of the file to be checked 435 | * @returns true if the file name is a match 436 | */ 437 | function isYamlConfigSource(fileName: string): boolean { 438 | return /application(-.*)?\.(yml|yaml)/.test(fileName); 439 | } 440 | 441 | /** 442 | * Returns if any of the open files in the workspace are YAML config sources 443 | * 444 | * @returns true if the above is true 445 | */ 446 | function hasOpenedYamlConfig(): boolean { 447 | return workspace.textDocuments.some(file => isYamlConfigSource(file.fileName)); 448 | } 449 | 450 | /** 451 | * Registers YAML schema support if not already registered and if fileName is a config source. 452 | * 453 | * @param fileName the recently opened or created file to be checked 454 | * @param yamlSchemaCache 455 | * @param yamlRegistered indicates whether or not YAML support has already been registered 456 | * @returns true if YAML schema support was registered 457 | */ 458 | function registerYamlSchemaSupportIfNeeded(fileName: string, yamlSchemaCache: Promise, yamlRegistered: boolean) { 459 | if (yamlRegistered == false && isYamlConfigSource(fileName)) { 460 | registerYamlSchemaSupport(); 461 | return true; 462 | } 463 | return yamlRegistered; 464 | } 465 | -------------------------------------------------------------------------------- /src/languageServer/javaServerStarter.ts: -------------------------------------------------------------------------------- 1 | import { globSync } from 'glob'; 2 | import * as os from 'os'; 3 | import * as path from 'path'; 4 | import { workspace } from 'vscode'; 5 | import { Executable, ExecutableOptions } from 'vscode-languageclient/node'; 6 | import { RequirementsData } from './requirements'; 7 | 8 | const DEBUG = startedInDebugMode(); 9 | const DEBUG_PORT = 1064; 10 | const MICROPROFILE_SERVER_NAME = 'org.eclipse.lsp4mp.ls-uber.jar'; 11 | const MICROPROFILE_SERVER_MAIN_CLASS = 'org.eclipse.lsp4mp.ls.MicroProfileServerLauncher'; 12 | 13 | export function prepareExecutable(requirements: RequirementsData, microprofileJavaExtensions: string[]): Executable { 14 | const executable: Executable = Object.create(null); 15 | const options: ExecutableOptions = Object.create(null); 16 | options.env = process.env; 17 | executable.options = options; 18 | executable.command = path.resolve(requirements.tooling_jre + '/bin/java'); 19 | executable.args = prepareParams(microprofileJavaExtensions); 20 | return executable; 21 | } 22 | 23 | function prepareParams(microprofileJavaExtensions: string[]): string[] { 24 | const params: string[] = []; 25 | if (DEBUG) { 26 | if (process.env.SUSPEND_SERVER === 'true') { 27 | params.push(`-agentlib:jdwp=transport=dt_socket,server=y,address=${DEBUG_PORT}`); 28 | } else { 29 | params.push(`-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${DEBUG_PORT},quiet=y`); 30 | } 31 | } 32 | 33 | const vmargs = workspace.getConfiguration("microprofile.tools").get("server.vmargs", ''); 34 | if (os.platform() === 'win32') { 35 | const watchParentProcess = '-DwatchParentProcess='; 36 | if (vmargs.indexOf(watchParentProcess) < 0) { 37 | params.push(watchParentProcess + 'false'); 38 | } 39 | } 40 | // Disable logging unless the user specifically sets it to a different value. 41 | // Logging can cause issues, since sometimes it writes to standard out. 42 | // See https://github.com/redhat-developer/vscode-java/issues/2577. 43 | if (vmargs.indexOf("-Xlog:") < 0) { 44 | params.push("-Xlog:disable"); 45 | } 46 | parseVMargs(params, vmargs); 47 | const serverHome: string = path.resolve(__dirname, '../server'); 48 | const microprofileServerFound: Array = globSync(`**/${MICROPROFILE_SERVER_NAME}`, { cwd: serverHome }); 49 | if (microprofileServerFound.length) { 50 | let mpJavaExtensionsClasspath = ''; 51 | if (microprofileJavaExtensions.length > 0) { 52 | const classpathSeperator = os.platform() === 'win32' ? ';' : ':'; 53 | mpJavaExtensionsClasspath = classpathSeperator + microprofileJavaExtensions.join(classpathSeperator); 54 | } 55 | 56 | params.push('-cp'); 57 | params.push(`${serverHome}/*` + mpJavaExtensionsClasspath); 58 | params.push(MICROPROFILE_SERVER_MAIN_CLASS); 59 | } else { 60 | throw new Error('Unable to find required Language Server JARs'); 61 | } 62 | return params; 63 | } 64 | 65 | function hasDebugFlag(args: string[]): boolean { 66 | if (args) { 67 | // See https://nodejs.org/en/docs/guides/debugging-getting-started/ 68 | return args.some(arg => /^--inspect/.test(arg) || /^--debug/.test(arg)); 69 | } 70 | return false; 71 | } 72 | 73 | function startedInDebugMode(): boolean { 74 | const args: string[] = process.execArgv; 75 | return hasDebugFlag(args); 76 | } 77 | 78 | // exported for tests 79 | export function parseVMargs(params: string[], vmargsLine: string): void { 80 | if (!vmargsLine) { 81 | return; 82 | } 83 | const vmargs = vmargsLine.match(/(?:[^\s"]+|"[^"]*")+/g); 84 | if (vmargs === null) { 85 | return; 86 | } 87 | vmargs.forEach(arg => { 88 | // remove all standalone double quotes 89 | arg = arg.replace(/(\\)?"/g, ($0, $1) => { return ($1 ? $0 : ''); }); 90 | // unescape all escaped double quotes 91 | arg = arg.replace(/(\\)"/g, '"'); 92 | if (params.indexOf(arg) < 0) { 93 | params.push(arg); 94 | } 95 | }); 96 | } 97 | -------------------------------------------------------------------------------- /src/languageServer/plugin.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import * as Commands from '../definitions/commands'; 4 | import { DocumentFilter, DocumentSelector } from 'vscode-languageclient'; 5 | import { isDeepStrictEqual } from 'util'; 6 | 7 | let existingExtensions: MicroProfileContribution[]; 8 | 9 | /** 10 | * MicroProfile language server contribution 11 | */ 12 | export interface MicroProfileContribution { 13 | jarExtensions: string[]; 14 | documentSelector: DocumentSelector; 15 | } 16 | 17 | /** 18 | * Returns all MicroProfile language server contributions from package.json 19 | * 20 | * @param extensions array of extensions to search contributions from 21 | */ 22 | export function collectMicroProfileJavaExtensions(extensions: readonly vscode.Extension[]): MicroProfileContribution[] { 23 | const result: MicroProfileContribution[] = []; 24 | if (extensions && extensions.length) { 25 | for (const extension of extensions) { 26 | const contributesSection = extension.packageJSON.contributes; 27 | if (contributesSection && contributesSection.microprofile) { 28 | const microprofileSection = contributesSection.microprofile; 29 | const contributes: MicroProfileContribution = {jarExtensions: [], documentSelector: []}; 30 | 31 | setJarExtensionsIfExists(contributes, microprofileSection, extension.extensionPath); 32 | setDocumentSelectorIfExists(contributes, microprofileSection); 33 | 34 | if (contributes.jarExtensions || contributes.documentSelector) { 35 | result.push(contributes); 36 | } 37 | } 38 | } 39 | } 40 | // Make a copy of extensions: 41 | existingExtensions = result.slice(); 42 | return result; 43 | } 44 | 45 | export function handleExtensionChange(extensions: readonly vscode.Extension[]): void { 46 | if (!existingExtensions) { 47 | return; 48 | } 49 | const oldExtensions = new Set(existingExtensions.slice()); 50 | const newExtensions = collectMicroProfileJavaExtensions(extensions); 51 | let hasChanged = (oldExtensions.size !== newExtensions.length); 52 | if (!hasChanged) { 53 | for (const newExtension of newExtensions) { 54 | let found = false; 55 | for (const oldExtension of oldExtensions) { 56 | if (isDeepStrictEqual(oldExtension, newExtension)) { 57 | found = true; 58 | break; 59 | } 60 | } 61 | if (found) { 62 | continue; 63 | } else { 64 | hasChanged = true; 65 | break; 66 | } 67 | } 68 | } 69 | 70 | if (hasChanged) { 71 | const msg = `Extensions to the MicroProfile Language Server changed, reloading ${vscode.env.appName} is required for the changes to take effect.`; 72 | const action = 'Reload'; 73 | vscode.window.showWarningMessage(msg, action).then((selection) => { 74 | if (action === selection) { 75 | vscode.commands.executeCommand(Commands.RELOAD_WINDOW); 76 | } 77 | }); 78 | } 79 | } 80 | 81 | function setJarExtensionsIfExists(obj: MicroProfileContribution, section: { jarExtensions: unknown }, extensionPath: string): void { 82 | if (Array.isArray(section.jarExtensions)) { 83 | for (const microprofileJavaExtensionPath of section.jarExtensions) { 84 | obj.jarExtensions.push(path.resolve(extensionPath, microprofileJavaExtensionPath)); 85 | } 86 | } 87 | } 88 | 89 | function setDocumentSelectorIfExists(obj: MicroProfileContribution, section: { documentSelector: unknown }): void { 90 | if (!Array.isArray(section.documentSelector)) { 91 | return; 92 | } 93 | const documentSelector: DocumentSelector = []; 94 | section.documentSelector.forEach((selector) => { 95 | if (typeof selector === 'string') { 96 | documentSelector.push(selector); 97 | } else if (selector) { 98 | const documentFilter: {[key: string]: string} = {}; 99 | if (typeof selector.language === 'string') { 100 | documentFilter.language = selector.language; 101 | } 102 | if (typeof selector.scheme === 'string') { 103 | documentFilter.scheme = selector.scheme; 104 | } 105 | if (typeof selector.pattern === 'string') { 106 | documentFilter.pattern = selector.pattern; 107 | } 108 | if (documentFilter.language || documentFilter.scheme || documentFilter.pattern) { 109 | documentSelector.push(documentFilter as DocumentFilter); 110 | } 111 | } 112 | }); 113 | obj.documentSelector = obj.documentSelector.concat(documentSelector); 114 | } 115 | -------------------------------------------------------------------------------- /src/languageServer/requirements.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as cp from 'child_process'; 4 | import * as fs from 'fs'; 5 | import * as path from 'path'; 6 | import { Uri, workspace } from 'vscode'; 7 | 8 | import * as expandHomeDir from 'expand-home-dir'; 9 | import { findRuntimes, IJavaRuntime, getSources } from 'jdk-utils'; 10 | import { JavaExtensionAPI } from '../extension'; 11 | const isWindows = process.platform.indexOf('win') === 0; 12 | const JAVA_FILENAME = 'java' + (isWindows ? '.exe' : ''); 13 | 14 | export interface RequirementsData { 15 | tooling_jre: string; 16 | tooling_jre_version: number; 17 | java_home: string; 18 | java_version: number; 19 | } 20 | 21 | /** 22 | * Resolves the requirements needed to run the extension. 23 | * Returns a promise that will resolve to a RequirementsData if 24 | * all requirements are resolved, it will reject with ErrorData if 25 | * if any of the requirements fails to resolve. 26 | * 27 | */ 28 | export async function resolveRequirements(api: JavaExtensionAPI): Promise { 29 | 30 | // Use the embedded JRE from 'redhat.java' if it exists 31 | const requirementsData = api.javaRequirement; 32 | if (requirementsData) { 33 | return Promise.resolve(requirementsData); 34 | } 35 | 36 | const javaHome = await checkJavaRuntime(); 37 | const javaVersion = await checkJavaVersion(javaHome); 38 | return Promise.resolve({ tooling_jre: javaHome, tooling_jre_version: javaVersion, java_home: javaHome, java_version: javaVersion }); 39 | } 40 | 41 | async function checkJavaRuntime(): Promise { 42 | let source: string; 43 | let javaHome: string | undefined = readJavaHomeConfig(); 44 | 45 | if (javaHome) { 46 | source = 'The java.home variable defined in VS Code settings'; 47 | javaHome = expandHomeDir(javaHome); 48 | if (!fs.existsSync(javaHome)) { 49 | throw openJDKDownload(source + ' points to a missing folder'); 50 | } else if (!fs.existsSync(path.resolve(javaHome as string, 'bin', JAVA_FILENAME))) { 51 | throw openJDKDownload(source + ' does not point to a Java runtime.'); 52 | } 53 | return javaHome; 54 | } 55 | // No settings, let's try to detect as last resort. 56 | const javaRuntimes = await findRuntimes({ withVersion: true, withTags: true }); 57 | if (javaRuntimes.length) { 58 | sortJdksBySource(javaRuntimes); 59 | javaHome = javaRuntimes[0].homedir; 60 | } else { 61 | throw openJDKDownload("Java runtime could not be located. Please download and install Java or use the binary server."); 62 | } 63 | return javaHome; 64 | } 65 | 66 | function sortJdksBySource(jdks: IJavaRuntime[]) { 67 | const rankedJdks = jdks as Array; 68 | const sources = ["JDK_HOME", "JAVA_HOME", "PATH"]; 69 | for (const [index, source] of sources.entries()) { 70 | for (const jdk of rankedJdks) { 71 | if (jdk.rank === undefined && getSources(jdk).includes(source)) { 72 | jdk.rank = index; 73 | } 74 | } 75 | } 76 | rankedJdks.filter(jdk => jdk.rank === undefined).forEach(jdk => jdk.rank = sources.length); 77 | rankedJdks.sort((a, b) => a.rank - b.rank); 78 | } 79 | 80 | function readJavaHomeConfig(): string | undefined { 81 | const config = workspace.getConfiguration(); 82 | return config.get('java.home'); 83 | } 84 | 85 | function checkJavaVersion(javaHome: string): Promise { 86 | return new Promise((resolve, reject) => { 87 | cp.execFile(javaHome + '/bin/java', ['-version'], {}, (error, stdout, stderr) => { 88 | const javaVersion = parseMajorVersion(stderr); 89 | if (javaVersion < 21) { 90 | reject(openJDKDownload(`Java 21 or more recent is required to run 'Tools for MicroProfile'. Please download and install a recent JDK.`)); 91 | } else { 92 | resolve(javaVersion); 93 | } 94 | }); 95 | }); 96 | } 97 | 98 | export function parseMajorVersion(content: string): number { 99 | let regexp = /version "(.*)"/g; 100 | let match = regexp.exec(content); 101 | if (!match) { 102 | return 0; 103 | } 104 | let version = match[1]; 105 | // Ignore '1.' prefix for legacy Java versions 106 | if (version.startsWith('1.')) { 107 | version = version.substring(2); 108 | } 109 | 110 | // look into the interesting bits now 111 | regexp = /\d+/g; 112 | match = regexp.exec(version); 113 | let javaVersion = 0; 114 | if (match) { 115 | javaVersion = parseInt(match[0]); 116 | } 117 | return javaVersion; 118 | } 119 | 120 | function openJDKDownload(cause: string) { 121 | let jdkUrl = 'https://developers.redhat.com/products/openjdk/download/?sc_cid=701f2000000RWTnAAO'; 122 | if (process.platform === 'darwin') { 123 | jdkUrl = 'http://www.oracle.com/technetwork/java/javase/downloads/index.html'; 124 | } 125 | return { 126 | message: cause, 127 | label: 'Get the Java Development Kit', 128 | openUrl: Uri.parse(jdkUrl), 129 | replaceClose: false 130 | }; 131 | } 132 | -------------------------------------------------------------------------------- /src/lsp-commands.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Red Hat, Inc. and others. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { commands, ConfigurationTarget, Disposable, Uri, workspace } from 'vscode'; 18 | import * as CommandKind from './definitions/lspCommandKind'; 19 | 20 | /** 21 | * Registers the `CommandKind.COMMAND_CONFIGURATION_UPDATE` command 22 | */ 23 | export function registerConfigurationUpdateCommand(): Disposable { 24 | return commands.registerCommand(CommandKind.COMMAND_CONFIGURATION_UPDATE, resolveConfigurationItemEdit); 25 | } 26 | 27 | /** 28 | * Registers the `microprofile.command.open.uri` command. 29 | * This command gives the capability to open the given uri of the command. 30 | */ 31 | export function registerOpenURICommand(): Disposable { 32 | return commands.registerCommand(CommandKind.COMMAND_OPEN_URI, (uri) => { 33 | commands.executeCommand('vscode.open', Uri.parse(uri)); 34 | }); 35 | } 36 | 37 | /** 38 | * Registers the `CommandKind.COMMAND_IMPLEMENTATIONS` command 39 | */ 40 | export function registerImplementationsCommand(): Disposable { 41 | return commands.registerCommand(CommandKind.COMMAND_IMPLEMENTATIONS, () => { 42 | // not yet implemented 43 | }); 44 | } 45 | 46 | /** 47 | * Registers the `CommandKind.COMMAND_REFERENCES` command 48 | */ 49 | export function registerReferencesCommand(): Disposable { 50 | return commands.registerCommand(CommandKind.COMMAND_REFERENCES, () => { 51 | // not yet implemented 52 | }); 53 | } 54 | 55 | function resolveConfigurationItemEdit(configItemEdit: ConfigurationItemEdit) { 56 | switch (configItemEdit.editType) { 57 | case ConfigurationItemEditType.Add: 58 | addToPreferenceArray(configItemEdit.section, configItemEdit.value); 59 | break; 60 | case ConfigurationItemEditType.Delete: { 61 | break; 62 | } 63 | case ConfigurationItemEditType.Update: { 64 | break; 65 | } 66 | } 67 | } 68 | 69 | function addToPreferenceArray(key: string, value: T): void { 70 | const configArray: T[] = workspace.getConfiguration().get(key, []); 71 | if (configArray.includes(value)) { 72 | return; 73 | } 74 | configArray.push(value); 75 | workspace.getConfiguration().update(key, configArray, ConfigurationTarget.Workspace); 76 | } 77 | 78 | interface ConfigurationItemEdit { 79 | section: string; 80 | value; 81 | editType: ConfigurationItemEditType; 82 | } 83 | 84 | enum ConfigurationItemEditType { 85 | Add = 0, 86 | Delete = 1, 87 | Update = 2 88 | } 89 | -------------------------------------------------------------------------------- /src/test/resources/no-lsp4mp-extension-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fake-extension", 3 | "displayName": "Dummy extension", 4 | "version": "1.7.0", 5 | "icon": "icons/logo.png", 6 | "author": "fake author", 7 | "publisher": "fakepublisher", 8 | "preview": true, 9 | "license": "Apache-2.0", 10 | "engines": { 11 | "vscode": "^1.37.0" 12 | }, 13 | "main": "./dist/extension", 14 | "extensionDependencies": [ 15 | "redhat.vscode-microprofile", 16 | "redhat.java", 17 | "vscjava.vscode-java-debug" 18 | ], 19 | "contributes": {} 20 | } 21 | -------------------------------------------------------------------------------- /src/test/resources/quarkus-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fake-vscode-quarkus", 3 | "displayName": "Quarkus", 4 | "description": "Quarkus Tools for Visual Studio Code", 5 | "version": "1.7.0", 6 | "icon": "icons/logo.png", 7 | "author": "Red Hat", 8 | "publisher": "redhat", 9 | "preview": true, 10 | "license": "Apache-2.0", 11 | "engines": { 12 | "vscode": "^1.37.0" 13 | }, 14 | "activationEvents": [ 15 | "onCommand:quarkusTools.createProject", 16 | "onCommand:quarkusTools.welcome", 17 | "workspaceContains:**/src/main/resources/application.properties", 18 | "workspaceContains:**src/main/resources/META-INF/microprofile-config.properties", 19 | "workspaceContains:**/src/main/resources/application.yaml", 20 | "workspaceContains:**/src/main/resources/application.yml", 21 | "onLanguage:microprofile-properties", 22 | "onLanguage:quarkus-properties", 23 | "onLanguage:java", 24 | "onLanguage:qute-html", 25 | "onLanguage:qute-json", 26 | "onLanguage:qute-yaml", 27 | "onLanguage:qute-txt" 28 | ], 29 | "main": "./dist/extension", 30 | "extensionDependencies": [ 31 | "redhat.vscode-microprofile", 32 | "redhat.java", 33 | "vscjava.vscode-java-debug" 34 | ], 35 | "contributes": { 36 | "javaExtensions": [ 37 | "./jars/com.redhat.microprofile.jdt.quarkus.jar" 38 | ], 39 | "microprofile": { 40 | "jarExtensions": [ 41 | "./server/com.redhat.quarkus.ls.jar" 42 | ], 43 | "documentSelector": [ 44 | { 45 | "scheme": "file", 46 | "language": "quarkus-properties" 47 | } 48 | ] 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath, version: '1.83.1' }); 17 | } catch { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { expect } from 'chai'; 3 | 4 | describe('VS Code extension tests', () => { 5 | 6 | it('should be present', () => { 7 | // eslint-disable-next-line @typescript-eslint/no-unused-expressions 8 | expect(vscode.extensions.getExtension('redhat.vscode-microprofile')).to.be.ok; 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import { glob } from "glob"; 2 | import * as Mocha from "mocha"; 3 | import * as path from "path"; 4 | 5 | export async function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: "bdd", 9 | color: true, 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, ".."); 13 | const files = await glob("**/**.test.js", { cwd: testsRoot }); 14 | files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); 15 | 16 | return new Promise((resolve, reject) => { 17 | try { 18 | // Run the mocha test 19 | mocha.run((failures) => { 20 | if (failures > 0) { 21 | reject(new Error(`${failures} tests failed.`)); 22 | } else { 23 | resolve(); 24 | } 25 | }); 26 | } catch (err) { 27 | reject(err); 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /src/test/suite/languageServer/documentSelectorPlugin.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Red Hat, Inc. and others. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import * as vscode from "vscode"; 17 | import * as plugin from "../../../languageServer/plugin"; 18 | import { expect } from "chai"; 19 | import { MicroProfileContribution } from "../../../languageServer/plugin"; 20 | import { TextDocumentFilter, DocumentSelector } from "vscode-languageclient"; 21 | 22 | /** 23 | * This file ensures that DocumentSelectors contributed by other VS Code extensions 24 | * (using `contributes.microprofile.documentSelector` key within package.json) are being 25 | * collected correctly. 26 | */ 27 | describe("Document selector collection from language server plugins", () => { 28 | 29 | it ('Should collect document selector when all keys exist', () => { 30 | const selector: DocumentSelector = collectDocumentSelectors([{ scheme: "file", language: "quarkus-properties", pattern: "**/*.properties" }]); 31 | expect(selector).to.have.length(1); 32 | expect(selector[0]).to.have.all.keys(["scheme", "language", "pattern"]); 33 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 34 | expect((selector[0] as TextDocumentFilter).language).to.equal("quarkus-properties"); 35 | expect((selector[0] as TextDocumentFilter).pattern).to.equal("**/*.properties"); 36 | }); 37 | 38 | it ('Should collect all document selector when two keys exist', () => { 39 | let selector: DocumentSelector = collectDocumentSelectors([{ scheme: "file", language: "quarkus-properties" }]); 40 | expect(selector).to.have.length(1); 41 | expect(selector[0]).to.have.all.keys(["scheme", "language"]); 42 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 43 | expect((selector[0] as TextDocumentFilter).language).to.equal("quarkus-properties"); 44 | 45 | selector = collectDocumentSelectors([{ language: "quarkus-properties", pattern: "**/*.properties" }]); 46 | expect(selector).to.have.length(1); 47 | expect(selector[0]).to.have.all.keys(["language", "pattern"]); 48 | expect((selector[0] as TextDocumentFilter).language).to.equal("quarkus-properties"); 49 | expect((selector[0] as TextDocumentFilter).pattern).to.equal("**/*.properties"); 50 | 51 | selector = collectDocumentSelectors([{ pattern: "**/*.properties", scheme: "file" }]); 52 | expect(selector).to.have.length(1); 53 | expect(selector[0]).to.have.all.keys(["pattern", "scheme"]); 54 | expect((selector[0] as TextDocumentFilter).pattern).to.equal("**/*.properties"); 55 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 56 | }); 57 | 58 | it ('Should collect document selector when one key exist', () => { 59 | let selector: DocumentSelector = collectDocumentSelectors([{ scheme: "file" }]); 60 | expect(selector).to.have.length(1); 61 | expect(selector[0]).to.have.all.keys(["scheme"]); 62 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 63 | 64 | selector = collectDocumentSelectors([{ language: "quarkus-properties" }]); 65 | expect(selector).to.have.length(1); 66 | expect(selector[0]).to.have.all.keys(["language"]); 67 | expect((selector[0] as TextDocumentFilter).language).to.equal("quarkus-properties"); 68 | 69 | selector = collectDocumentSelectors([{ pattern: "**/*.properties" }]); 70 | expect(selector).to.have.length(1); 71 | expect(selector[0]).to.have.all.keys(["pattern"]); 72 | expect((selector[0] as TextDocumentFilter).pattern).to.equal("**/*.properties"); 73 | }); 74 | 75 | it ('Should collect document selector when a valid key and an invalid key exists', () => { 76 | // valid, but the "invalid" key is ignored 77 | let selector: DocumentSelector = collectDocumentSelectors([{ scheme: "file", invalid: "file" }]); 78 | expect(selector).to.have.length(1); 79 | expect(selector[0]).to.have.all.keys(["scheme"]); 80 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 81 | 82 | // valid, but the "language" key is ignored since the value has the wrong type 83 | selector = collectDocumentSelectors([{ scheme: "file", language: 12 }]); 84 | expect(selector).to.have.length(1); 85 | expect(selector[0]).to.have.all.keys(["scheme"]); 86 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 87 | }); 88 | 89 | it ('Should collect document selector strings', () => { 90 | const selector: DocumentSelector = collectDocumentSelectors(["document-selector-string"]); 91 | expect(selector).to.have.length(1); 92 | expect(selector[0]).to.be.a('string'); 93 | expect(selector[0]).to.equal("document-selector-string"); 94 | }); 95 | 96 | it ('Should not collect document selector when there are no correct keys', () => { 97 | let selector: DocumentSelector = collectDocumentSelectors([{ invalid: "file" }]); 98 | expect(selector).to.have.length(0); 99 | 100 | selector = collectDocumentSelectors([{}]); 101 | expect(selector).to.have.length(0); 102 | 103 | selector = collectDocumentSelectors([]); 104 | expect(selector).to.have.length(0); 105 | }); 106 | 107 | it ('Should not collect document selector when containing invalid types', () => { 108 | let selector: DocumentSelector = collectDocumentSelectors([12]); 109 | expect(selector).to.have.length(0); 110 | 111 | selector = collectDocumentSelectors([/test/]); 112 | expect(selector).to.have.length(0); 113 | 114 | selector = collectDocumentSelectors([true]); 115 | expect(selector).to.have.length(0); 116 | }); 117 | 118 | it ('Should not collect document selector when all keys have incorrect types', () => { 119 | 120 | let selector: DocumentSelector = collectDocumentSelectors([{ scheme: 12 }]); 121 | expect(selector).to.have.length(0); 122 | 123 | selector = collectDocumentSelectors([{ scheme: { key: "value" } }]); 124 | expect(selector).to.have.length(0); 125 | 126 | selector = collectDocumentSelectors([{ language: 12 }]); 127 | expect(selector).to.have.length(0); 128 | 129 | selector = collectDocumentSelectors([{ language: { key: "value" } }]); 130 | expect(selector).to.have.length(0); 131 | 132 | selector = collectDocumentSelectors([{ pattern: 12 }]); 133 | expect(selector).to.have.length(0); 134 | 135 | selector = collectDocumentSelectors([{ pattern: { key: "value" } }]); 136 | expect(selector).to.have.length(0); 137 | }); 138 | 139 | it ('Should collect multiple document selectors', () => { 140 | const selector: DocumentSelector = collectDocumentSelectors([ 141 | { scheme: "file", language: "quarkus-properties", pattern: "**/*.properties" }, // valid 142 | { language: "my-properties" }, // valid 143 | "document-selector-string", // valid 144 | { key: "value" }, // invalid 145 | 12 // invalid 146 | ]); 147 | 148 | expect(selector).to.have.length(3); 149 | 150 | expect(selector[0]).to.have.all.keys(["scheme", "language", "pattern"]); 151 | expect((selector[0] as TextDocumentFilter).scheme).to.equal("file"); 152 | expect((selector[0] as TextDocumentFilter).language).to.equal("quarkus-properties"); 153 | expect((selector[0] as TextDocumentFilter).pattern).to.equal("**/*.properties"); 154 | 155 | expect(selector[1]).to.have.all.keys(["language"]); 156 | expect((selector[1] as TextDocumentFilter).language).to.equal("my-properties"); 157 | 158 | expect(selector[2]).to.be.a('string'); 159 | expect(selector[2]).to.equal("document-selector-string"); 160 | }); 161 | 162 | /** 163 | * Returns the DocumentSelector created from the provided `pluginDocumentSelector`. 164 | * 165 | * `pluginDocumentSelector` represents the DocumentSelector that other VS Code 166 | * extensions would contribute to vscode-microprofile. 167 | * 168 | * @param pluginDocumentSelector array of objects to create a DocumentSelector from. 169 | */ 170 | function collectDocumentSelectors(pluginDocumentSelector: unknown[]): DocumentSelector { 171 | const fakePlugin: vscode.Extension = { 172 | id: "fake-no-plugin-extension", 173 | extensionUri: vscode.Uri.parse("https://example.org"), 174 | extensionPath: "", 175 | isActive: true, 176 | packageJSON: { 177 | contributes: { 178 | microprofile: { 179 | documentSelector: pluginDocumentSelector 180 | } 181 | } 182 | }, 183 | exports: "", 184 | activate: null, 185 | extensionKind: vscode.ExtensionKind.Workspace, 186 | }; 187 | 188 | const contribution: MicroProfileContribution[] = plugin.collectMicroProfileJavaExtensions([ fakePlugin ]); 189 | expect(contribution).to.have.length(1); 190 | 191 | return contribution[0].documentSelector; 192 | } 193 | }); 194 | -------------------------------------------------------------------------------- /src/test/suite/languageServer/plugin.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import * as fs from "fs"; 3 | import * as path from "path"; 4 | import * as vscode from "vscode"; 5 | import { TextDocumentFilter } from "vscode-languageclient"; 6 | import * as plugin from "../../../languageServer/plugin"; 7 | import { MicroProfileContribution } from "../../../languageServer/plugin"; 8 | 9 | describe("Language server plugin", () => { 10 | it('Should collect lsp4mp extensions', () => { 11 | const quarkusPackageJSON = JSON.parse( 12 | fs.readFileSync( 13 | path.join(__dirname, "../../../../src/test/resources/quarkus-package.json"), 14 | "utf8" 15 | ) 16 | ); 17 | 18 | const fakeVscodeQuarkus: vscode.Extension = { 19 | id: "fake-vscode-quarkus", 20 | extensionPath: "", 21 | extensionUri: vscode.Uri.parse("https://example.org"), 22 | isActive: true, 23 | packageJSON: quarkusPackageJSON, 24 | exports: "", 25 | activate: null, 26 | extensionKind: vscode.ExtensionKind.Workspace, 27 | }; 28 | 29 | const noPluginPackageJSON = JSON.parse( 30 | fs.readFileSync( 31 | path.join(__dirname, "../../../../src/test/resources/no-lsp4mp-extension-package.json"), 32 | "utf8" 33 | ) 34 | ); 35 | 36 | const fakeNoPluginExtension: vscode.Extension = { 37 | id: "fake-no-plugin-extension", 38 | extensionUri: vscode.Uri.parse("https://example.org"), 39 | extensionPath: "", 40 | isActive: true, 41 | packageJSON: noPluginPackageJSON, 42 | exports: "", 43 | activate: null, 44 | extensionKind: vscode.ExtensionKind.Workspace, 45 | }; 46 | 47 | const extensions = [fakeVscodeQuarkus, fakeNoPluginExtension]; 48 | const result: MicroProfileContribution[] = plugin.collectMicroProfileJavaExtensions(extensions); 49 | expect(result).to.have.length(1); 50 | 51 | expect(result[0].jarExtensions).to.have.length(1); 52 | 53 | const expectedPath: string = path.join('server', 'com.redhat.quarkus.ls.jar').replace("\\", "\\\\"); 54 | expect(result[0].jarExtensions[0]).to.be.a("string").and.match(new RegExp(`${expectedPath}$`), `String should end with "${expectedPath}".`); 55 | 56 | expect(result[0].documentSelector).to.have.length(1); 57 | expect(result[0].documentSelector[0]).has.all.keys(["scheme", "language"]); 58 | 59 | const TextDocumentFilter: TextDocumentFilter = result[0].documentSelector[0] as TextDocumentFilter; 60 | expect(TextDocumentFilter.scheme).to.be.a("string").and.equal("file"); 61 | expect(TextDocumentFilter.language).to.be.a("string").and.equal("quarkus-properties"); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/test/suite/languageServer/requirements.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { parseMajorVersion } from "../../../languageServer/requirements"; 3 | 4 | describe("Language server java requirements", () => { 5 | it("Should parse the correct java version from OpenJDK 1.8", () => { 6 | const openJDK8 = `openjdk version "1.8.0_212" 7 | OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_212-b03) 8 | OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.212-b03, mixed mode)`; 9 | 10 | expect(parseMajorVersion(openJDK8)).to.equal(8); 11 | }); 12 | 13 | it("Should parse the correct java version from AdoptOpenJDK with OpenJ9", () => { 14 | const adoptOpenJ9 = `openjdk version "11.0.6" 2020-01-14 15 | OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.6+10) 16 | Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.18.1, JRE 11 Mac OS X amd64-64-Bit Compressed References 20200122_450 (JIT enabled, AOT enabled) 17 | OpenJ9 - 51a5857d2 18 | OMR - 7a1b0239a 19 | JCL - da35e0c380 based on jdk-11.0.6+10)`; 20 | 21 | expect(parseMajorVersion(adoptOpenJ9)).to.equal(11); 22 | }); 23 | 24 | it("Should parse the correct java version from Java SE 12", () => { 25 | const javaSE12 = `java version "12.0.1" 2019-04-16 26 | Java(TM) SE Runtime Environment (build 12.0.1+12) 27 | Java HotSpot(TM) 64-Bit Server VM (build 12.0.1+12, mixed mode, sharing)`; 28 | 29 | expect(parseMajorVersion(javaSE12)).to.equal(12); 30 | }); 31 | 32 | it("Should return 0 if it cannot find a java version", () => { 33 | const javaNotFound = "bash: java: command not found"; 34 | 35 | expect(parseMajorVersion(javaNotFound)).to.equal(0); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/util/javaServerMode.ts: -------------------------------------------------------------------------------- 1 | import { window, commands } from "vscode"; 2 | import { JavaExtensionAPI } from "../extension"; 3 | 4 | export const JAVA_EXTENSION_ID = "redhat.java"; 5 | 6 | export enum ServerMode { 7 | STANDARD = "Standard", 8 | LIGHTWEIGHT = "LightWeight", 9 | HYBRID = "Hybrid", 10 | } 11 | 12 | /** 13 | * Waits for the java language server to launch in standard mode 14 | * Before activating Tools for MicroProfile. 15 | * If java ls was started in lightweight mode, It will prompt user to switch 16 | */ 17 | export async function waitForStandardMode(api: JavaExtensionAPI): Promise { 18 | // If hybrid, standard mode is being launched. Wait for standard mode then resolve. 19 | if (api.serverMode === ServerMode.HYBRID) { 20 | return new Promise((resolve) => { 21 | api.onDidServerModeChange((mode: string) => { 22 | if (mode === ServerMode.STANDARD) { 23 | resolve(); 24 | } 25 | }); 26 | }); 27 | // If Lightweight. Prompt to switch then wait for Standard mode. 28 | // Even if they do not select Yes on the prompt. This still waits for standard mode 29 | // since standard mode switch can be triggered other ways. 30 | } else if (api.serverMode === ServerMode.LIGHTWEIGHT) { 31 | window.showInformationMessage( 32 | "Tools for MicroProfile requires the Java language server to run in Standard mode. " + 33 | "Do you want to switch it to Standard mode now?", 34 | "Yes", 35 | "Later" 36 | ) 37 | .then((answer) => { 38 | if (answer === "Yes") { 39 | commands.executeCommand("java.server.mode.switch", ServerMode.STANDARD, true); 40 | } 41 | }); 42 | return new Promise((resolve) => { 43 | api.onDidServerModeChange((mode: string) => { 44 | if (mode === ServerMode.STANDARD) { 45 | resolve(); 46 | } 47 | }); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/util/telemetry.ts: -------------------------------------------------------------------------------- 1 | import { TelemetryService } from "@redhat-developer/vscode-redhat-telemetry/lib"; 2 | 3 | const CODE_ACTION_TELEMETRY_EVENT = 'codeAction'; 4 | const SUCCEED_VALUE = "succeeded"; 5 | const FAIL_VALUE = "failed"; 6 | 7 | /** 8 | * Sends a telemetry event to indicate that the given code action was applied. 9 | * 10 | * @param telemetryService the telemetry service 11 | * @param codeActionId the id of the type of code action (not the name, since that might contain context such as variable names) 12 | * @param succeeded true if the code action was applied successfully, and false otherwise 13 | * @param error the error message if the code action has failed 14 | */ 15 | export async function sendCodeActionTelemetry(telemetryService: TelemetryService, codeActionId: string, succeeded: boolean, error?) { 16 | telemetryService.send({ 17 | name: CODE_ACTION_TELEMETRY_EVENT, 18 | properties: { 19 | codeActionId: codeActionId, 20 | status: succeeded ? SUCCEED_VALUE : FAIL_VALUE, 21 | error_message: error ? `${error}` : undefined 22 | } 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /src/util/workspaceUtils.ts: -------------------------------------------------------------------------------- 1 | import { RelativePattern, Uri, workspace, WorkspaceFolder } from "vscode"; 2 | 3 | /** 4 | * Returns a list of all files that match the given glob in the given workspace. 5 | * 6 | * @param workspaceFolder the workspace to search 7 | * @param glob the glob of the files to match 8 | * @returns a list of all files that match the given glob in the given workspace 9 | */ 10 | export async function getFilePathsFromWorkspace( 11 | workspaceFolder: WorkspaceFolder, 12 | glob: string 13 | ): Promise { 14 | return await getFilePathsFromFolder(workspaceFolder.uri.fsPath, glob); 15 | } 16 | 17 | /** 18 | * Returns a list of all files that match the given glob in the given folder. 19 | * 20 | * @param folderPath the folder to search 21 | * @param glob the glob of the files to match 22 | * @returns a list of all files that match the given glob in the given folder 23 | */ 24 | export async function getFilePathsFromFolder( 25 | folderPath: string, 26 | glob: string 27 | ): Promise { 28 | return await workspace.findFiles(new RelativePattern(folderPath, glob), null); 29 | } 30 | -------------------------------------------------------------------------------- /src/yaml/YamlConstants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Red Hat, Inc. and others. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import * as vscode from 'vscode'; 17 | 18 | export const MICROPROFILE_SCHEMA = 'microprofile'; 19 | export const MICROPROFILE_SCHEMA_PREFIX = MICROPROFILE_SCHEMA + '://schema/'; 20 | export const VSCODE_YAML_EXTENSION_ID = 'redhat.vscode-yaml'; 21 | export const VSCODE_YAML_DISPLAY_NAME = 'YAML Support by Red Hat'; 22 | export const VSCODE_YAML_NOT_INSTALLED_MESSAGE = `For application.yaml support, please install '${VSCODE_YAML_DISPLAY_NAME}' and reload ${vscode.env.appName}.`; 23 | export const VSCODE_YAML_LOW_VERSION_MESSAGE = `The installed version of '${VSCODE_YAML_DISPLAY_NAME}' doesn't support multiple schemas. Please install the latest version and reload ${vscode.env.appName}.`; 24 | export const VSCODE_YAML_NO_REGISTRATION_MESSAGE = `The installed version of '${VSCODE_YAML_DISPLAY_NAME}' doesn't support MicroProfile Intellisense. Please install the latest version and reload ${vscode.env.appName}.`; 25 | export const VSCODE_YAML_INSTALL_SUCCESS = `Successfully installed '${VSCODE_YAML_DISPLAY_NAME}'. Please reload ${vscode.env.appName}.`; -------------------------------------------------------------------------------- /src/yaml/YamlSchema.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 Red Hat, Inc. and others. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import * as vscode from 'vscode'; 17 | import * as path from 'path'; 18 | import * as semver from 'semver'; 19 | 20 | import { 21 | VSCODE_YAML_EXTENSION_ID, 22 | VSCODE_YAML_DISPLAY_NAME, 23 | VSCODE_YAML_NOT_INSTALLED_MESSAGE, 24 | VSCODE_YAML_LOW_VERSION_MESSAGE, 25 | VSCODE_YAML_NO_REGISTRATION_MESSAGE, 26 | VSCODE_YAML_INSTALL_SUCCESS, 27 | MICROPROFILE_SCHEMA, 28 | MICROPROFILE_SCHEMA_PREFIX 29 | } from "./YamlConstants"; 30 | 31 | import { Uri } from 'vscode'; 32 | import { LanguageClient } from 'vscode-languageclient/node'; 33 | import * as MicroProfileLS from '../definitions/microProfileLSRequestNames'; 34 | 35 | // The function signature exposed by vscode-yaml: 36 | // 1. the requestSchema api will be called by vscode-yaml extension to decide whether the schema can be handled by this 37 | // contributor, if it returns undefined, means it doesn't support this yaml file, vscode-yaml will ask other contributors 38 | // 2. the requestSchemaContent api will give the parameter uri returned by the first api, and ask for the json content(after stringify) of 39 | // the schema 40 | declare type YamlSchemaContributor = (schema: string, 41 | requestSchema: (resource: string) => string | undefined, 42 | requestSchemaContent: (uri: string) => Promise) => void; 43 | 44 | interface JsonSchemaForProjectInfo { 45 | projectURI: string; 46 | jsonSchema: string; 47 | } 48 | 49 | export interface MicroProfilePropertiesChangeEvent { 50 | projectURIs: Array; 51 | type: Array; 52 | } 53 | export enum MicroProfilePropertiesScopeEnum { 54 | sources = 1, 55 | dependencies = 2 56 | } 57 | 58 | // Yaml Schema cache which caches YAML Schema (in JSON format) for application.yaml files 59 | // which belong to a MicroProfile project. 60 | export class YamlSchemaCache { 61 | private readonly cache = new Map(); 62 | private _languageClient: LanguageClient; 63 | public set languageClient(languageClient: LanguageClient) { 64 | this._languageClient = languageClient; 65 | } 66 | 67 | /** 68 | * Returns the JSON Schema to use for the given application yaml file URI. 69 | * 70 | * @param applicationYamlUri the application yaml file URI 71 | */ 72 | public async getSchema(applicationYamlUri: string): Promise { 73 | const yamlSchema = this.cache.get(applicationYamlUri); 74 | if (yamlSchema) { 75 | return yamlSchema.jsonSchema; 76 | } 77 | if (!this._languageClient) { 78 | return undefined; 79 | } 80 | const params = { 81 | uri: applicationYamlUri, 82 | scopes: [1, 2] 83 | }; 84 | return this._languageClient.sendRequest(MicroProfileLS.JSON_SCHEMA_FOR_PROJECT_INFO_REQUEST, params) 85 | .then((result: JsonSchemaForProjectInfo) => { 86 | const jsonSchema = result.jsonSchema; 87 | this.cache.set(applicationYamlUri, result); 88 | return jsonSchema; 89 | }, (err) => { 90 | console.error(`Error while consumming '${MicroProfileLS.JSON_SCHEMA_FOR_PROJECT_INFO_REQUEST}' request: ${err.message}`); 91 | return null; 92 | }); 93 | } 94 | 95 | /** 96 | * Evict the cache according to the classpath changed of the given project URIs 97 | * 98 | * @param event the properties change event 99 | */ 100 | public evict(event: MicroProfilePropertiesChangeEvent): void { 101 | // collect all application.yaml uris which belong to the event project URIs 102 | // and evict them from the cache. 103 | this.cache.forEach((jsonSchema: JsonSchemaForProjectInfo, uri: string) => { 104 | if (event.projectURIs.includes(jsonSchema.projectURI)) { 105 | this.cache.delete(uri); 106 | } 107 | }); 108 | } 109 | } 110 | 111 | const yamlSchemaCache = new YamlSchemaCache(); 112 | let listener: vscode.Disposable|undefined = undefined; 113 | 114 | export async function registerYamlSchemaSupport(){ 115 | const yamlPlugin = await activateYamlExtension(); 116 | if (!yamlPlugin || !yamlPlugin.registerContributor) { 117 | // activateYamlExtension has already alerted users about errors. 118 | return undefined; 119 | } 120 | // register for microprofile schema provider 121 | yamlPlugin.registerContributor(MICROPROFILE_SCHEMA, requestYamlSchemaUriCallback, requestYamlSchemaContentCallback); 122 | } 123 | 124 | // find redhat.vscode-yaml extension and try to activate it to get the yaml contributor 125 | // this function should only be called once when vscode-microprofile activates 126 | async function activateYamlExtension(): Promise<{ registerContributor: YamlSchemaContributor } | undefined> { 127 | const ext = vscode.extensions.getExtension(VSCODE_YAML_EXTENSION_ID); 128 | const isApplicationYamlOpened: boolean = isEditorApplicationYaml(vscode.window.activeTextEditor); 129 | 130 | if (!ext) { 131 | if (isApplicationYamlOpened) { 132 | await askInstallVSCodeYaml(VSCODE_YAML_NOT_INSTALLED_MESSAGE); 133 | } else { 134 | listener = createInstallListener(VSCODE_YAML_NOT_INSTALLED_MESSAGE); 135 | } 136 | return undefined; 137 | } 138 | 139 | if (ext.packageJSON.version && !semver.gte(ext.packageJSON.version, '0.0.15')) { 140 | if (isApplicationYamlOpened) { 141 | await askInstallVSCodeYaml(VSCODE_YAML_LOW_VERSION_MESSAGE); 142 | } else { 143 | listener = createInstallListener(VSCODE_YAML_LOW_VERSION_MESSAGE); 144 | } 145 | return undefined; 146 | } 147 | const yamlPlugin = await ext.activate(); 148 | 149 | if (!yamlPlugin || !yamlPlugin.registerContributor) { 150 | if (isApplicationYamlOpened) { 151 | await askInstallVSCodeYaml(VSCODE_YAML_NO_REGISTRATION_MESSAGE); 152 | } else { 153 | listener = createInstallListener(VSCODE_YAML_NO_REGISTRATION_MESSAGE); 154 | } 155 | return undefined; 156 | } 157 | 158 | return yamlPlugin; 159 | } 160 | 161 | // see docs from YamlSchemaContributor 162 | function requestYamlSchemaUriCallback(resource: string): string | undefined { 163 | const textEditor = vscode.window.visibleTextEditors.find((editor) => editor.document.uri.toString() === resource); 164 | if (textEditor) { 165 | if (resource.endsWith('application.yaml') || resource.endsWith('application.yml')) { 166 | return MICROPROFILE_SCHEMA_PREFIX + resource; 167 | } 168 | } 169 | return undefined; 170 | } 171 | 172 | // see docs from YamlSchemaContributor 173 | function requestYamlSchemaContentCallback(uri: string): Promise { 174 | const parsedUri = Uri.parse(uri); 175 | if (parsedUri.scheme !== MICROPROFILE_SCHEMA) { 176 | return undefined; 177 | } 178 | if (!parsedUri.path || !parsedUri.path.startsWith('/')) { 179 | return undefined; 180 | } 181 | const applicationYamlUri = uri.substring(MICROPROFILE_SCHEMA_PREFIX.length); 182 | return yamlSchemaCache.getSchema(applicationYamlUri); 183 | } 184 | 185 | function isEditorApplicationYaml(editor: vscode.TextEditor|undefined): boolean { 186 | if (!editor) { 187 | return false; 188 | } 189 | const currentFileName: string = editor.document.fileName; 190 | if (!currentFileName) return false; 191 | return currentFileName.endsWith(path.sep + 'application.yaml') || currentFileName.endsWith(path.sep + 'application.yml'); 192 | } 193 | 194 | function createInstallListener(message: string): vscode.Disposable { 195 | return vscode.window.onDidChangeActiveTextEditor(async (change: vscode.TextEditor | undefined) => { 196 | if (!change) return; 197 | 198 | if (isEditorApplicationYaml(change)) { 199 | await askInstallVSCodeYaml(message); 200 | } 201 | }); 202 | } 203 | 204 | async function askInstallVSCodeYaml(message: string): Promise { 205 | const INSTALL = 'Install'; 206 | const RELOAD = 'Reload'; 207 | 208 | const response: string|undefined = await vscode.window.showWarningMessage(message, INSTALL); 209 | if (response === INSTALL) { 210 | await installVSCodeYaml(); 211 | if (listener) listener.dispose(); 212 | const response: string|undefined = await vscode.window.showInformationMessage(VSCODE_YAML_INSTALL_SUCCESS, RELOAD); 213 | if (response === RELOAD) { 214 | await vscode.commands.executeCommand('workbench.action.reloadWindow'); 215 | } 216 | } 217 | } 218 | 219 | async function installVSCodeYaml(): Promise { 220 | await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `Installing '${VSCODE_YAML_DISPLAY_NAME}'...`}, () => { 221 | return vscode.commands.executeCommand('workbench.extensions.installExtension', VSCODE_YAML_EXTENSION_ID); 222 | }); 223 | } 224 | 225 | export async function getYamlSchemaCache(): Promise { 226 | return yamlSchemaCache; 227 | } 228 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": [ 5 | "es6" 6 | ], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "outDir": "out", 10 | "sourceMap": true, 11 | "plugins": [] 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | "server", 16 | "test-resources", 17 | ".vscode-test" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | //@ts-check 7 | 8 | "use strict"; 9 | 10 | const path = require("path"); 11 | const ESLintWebpackPlugin = require('eslint-webpack-plugin'); 12 | 13 | /**@type {import('webpack').Configuration}*/ 14 | const config = { 15 | target: "node", // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 16 | node: { 17 | __dirname: false, 18 | __filename: false, 19 | }, 20 | entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 21 | output: { 22 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 23 | path: path.resolve(__dirname, "dist"), 24 | filename: "extension.js", 25 | libraryTarget: "commonjs2", 26 | devtoolModuleFilenameTemplate: "../[resource-path]", 27 | }, 28 | devtool: "source-map", 29 | externals: { 30 | vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 31 | }, 32 | resolve: { 33 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 34 | extensions: [".ts", ".js"], 35 | }, 36 | module: { 37 | rules: [ 38 | { 39 | test: /\.ts$/, 40 | exclude: /node_modules/, 41 | use: [ 42 | { 43 | loader: "ts-loader", 44 | }, 45 | ], 46 | }, 47 | ], 48 | }, 49 | infrastructureLogging: { 50 | level: "log", 51 | }, 52 | plugins: [ 53 | new ESLintWebpackPlugin({ 54 | extensions: [".ts", ".js"], 55 | }) 56 | ] 57 | }; 58 | 59 | module.exports = config; 60 | --------------------------------------------------------------------------------