├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── AUTHORS.md ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── detekt-config.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── us │ │ └── jimschubert │ │ └── intellij │ │ └── openapitools │ │ └── ui │ │ ├── GeneratorInfoPanel.form │ │ └── GeneratorInfoPanel.java ├── kotlin │ └── us │ │ └── jimschubert │ │ └── intellij │ │ └── openapitools │ │ ├── Message.kt │ │ ├── actions │ │ ├── CodegenGenerateAction.kt │ │ └── CodegenVersion.kt │ │ ├── events │ │ └── GenerationNotificationManager.kt │ │ └── ui │ │ ├── ActionButtonGroup.kt │ │ ├── CliConstrainedOption.kt │ │ ├── CodegenConfigOptions.kt │ │ ├── ConstrainedOptionsPanel.kt │ │ ├── GenerateDialog.kt │ │ ├── GeneratorGeneralSettingsPanel.kt │ │ ├── GeneratorsTreeNode.kt │ │ ├── GeneratorsTreePanel.kt │ │ ├── GeneratorsTreeRootNode.kt │ │ ├── GeneratorsTreeSelectionListener.kt │ │ ├── JTrueFalseRadioPanel.kt │ │ ├── KeyValuePropertiesPanel.kt │ │ ├── LanguageOptionsPanel.kt │ │ ├── LogoLabel.kt │ │ ├── PlainTextCellEditor.kt │ │ ├── PropertiesPanelExtensions.kt │ │ ├── SimpleKeyValueItem.kt │ │ ├── SimpleValueItem.kt │ │ ├── UserOptionInput.kt │ │ ├── Validatable.kt │ │ ├── ValidatingKeyColumnInfo.kt │ │ ├── ValidatingValueColumnInfo.kt │ │ └── ValuePropertiesPanel.kt └── resources │ ├── META-INF │ ├── plugin.xml │ ├── pluginIcon.svg │ └── pluginIcon_dark.svg │ ├── images │ ├── openapi-generator-outline.png │ ├── openapi-generator.png │ └── openapi-generator_dark.png │ └── messages │ └── GeneratorBundle.properties └── test └── resources └── sample.yaml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: jimschubert 2 | patreon: jimschubert 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for testing and preparing the plugin release in following steps: 2 | # - validate Gradle Wrapper, 3 | # - run test and verifyPlugin tasks, 4 | # - run buildPlugin task and prepare artifact for the further tests, 5 | # - run IntelliJ Plugin Verifier, 6 | # - create a draft release. 7 | # 8 | # Workflow is triggered on push and pull_request events. 9 | # 10 | # Docs: 11 | # - GitHub Actions: https://help.github.com/en/actions 12 | # - IntelliJ Plugin Verifier GitHub Action: https://github.com/ChrisCarini/intellij-platform-plugin-verifier-action 13 | # 14 | ## JBIJPPTPL 15 | 16 | name: Build 17 | on: [push, pull_request] 18 | 19 | jobs: 20 | 21 | # Run Gradle Wrapper Validation Action to verify the wrapper's checksum 22 | gradleValidation: 23 | name: Gradle Wrapper 24 | runs-on: ubuntu-latest 25 | steps: 26 | 27 | # Check out current repository 28 | - name: Fetch Sources 29 | uses: actions/checkout@v2 30 | 31 | # Validate wrapper 32 | - name: Gradle Wrapper Validation 33 | uses: gradle/wrapper-validation-action@v1 34 | 35 | # Run verifyPlugin and test Gradle tasks 36 | test: 37 | name: Test 38 | needs: gradleValidation 39 | runs-on: ubuntu-latest 40 | steps: 41 | 42 | # Check out current repository 43 | - name: Fetch Sources 44 | uses: actions/checkout@v2 45 | 46 | # Setup Java 1.8 environment for the next steps 47 | - name: Setup Java 48 | uses: actions/setup-java@v1 49 | with: 50 | java-version: 1.8 51 | 52 | # Cache Gradle dependencies 53 | - name: Setup Cache 54 | uses: actions/cache@v1 55 | with: 56 | path: ~/.gradle/caches 57 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 58 | restore-keys: ${{ runner.os }}-gradle- 59 | 60 | # Run detekt 61 | - name: Run Linter 62 | run: ./gradlew detekt 63 | 64 | # Run verifyPlugin Gradle task 65 | - name: Verify Plugin 66 | run: ./gradlew verifyPlugin 67 | 68 | # Run test Gradle task 69 | - name: Run Tests 70 | run: ./gradlew test 71 | 72 | # Build plugin with buildPlugin Gradle task and provide the artifact for the next workflow jobs 73 | # Requires test job to be passed 74 | build: 75 | name: Build 76 | needs: test 77 | runs-on: ubuntu-latest 78 | outputs: 79 | name: ${{ steps.properties.outputs.name }} 80 | version: ${{ steps.properties.outputs.version }} 81 | artifact: ${{ steps.properties.outputs.name }}-${{ steps.properties.outputs.version }}.zip 82 | changelog: ${{ steps.properties.outputs.changelog }} 83 | steps: 84 | 85 | # Check out current repository 86 | - name: Fetch Sources 87 | uses: actions/checkout@v2 88 | 89 | # Setup Java 1.8 environment for the next steps 90 | - name: Setup Java 91 | uses: actions/setup-java@v1 92 | with: 93 | java-version: 1.8 94 | 95 | # Cache Gradle dependencies 96 | - name: Setup Cache 97 | uses: actions/cache@v1 98 | with: 99 | path: ~/.gradle/caches 100 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 101 | restore-keys: ${{ runner.os }}-gradle- 102 | 103 | # Set environment variables 104 | - name: Export Properties 105 | id: properties 106 | run: | 107 | echo "::set-output name=version::$(./gradlew properties --console=plain -q | grep "^version:" | cut -f2- -d ' ')" 108 | echo "::set-output name=name::$(./gradlew properties --console=plain -q | grep "^name:" | cut -f2- -d ' ')" 109 | 110 | CHANGELOG=$(./gradlew getChangelog --unreleased --no-header --console=plain -q) 111 | CHANGELOG="${CHANGELOG//'%'/'%25'}" 112 | CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" 113 | CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" 114 | echo "::set-output name=changelog::$CHANGELOG" 115 | 116 | # Build artifact using buildPlugin Gradle task 117 | - name: Build Plugin 118 | run: ./gradlew buildPlugin 119 | 120 | # Upload plugin artifact to make it available in the next jobs 121 | - name: Upload artifact 122 | uses: actions/upload-artifact@v1 123 | with: 124 | name: plugin-artifact 125 | path: ./build/distributions/${{ needs.build.outputs.artifact }} 126 | 127 | # Verify built plugin using IntelliJ Plugin Verifier tool 128 | # Requires build job to be passed 129 | verify: 130 | name: Verify 131 | needs: build 132 | runs-on: ubuntu-latest 133 | steps: 134 | 135 | # Download plugin artifact provided by the previous job 136 | - name: Download Artifact 137 | uses: actions/download-artifact@v1 138 | with: 139 | name: plugin-artifact 140 | 141 | # Run IntelliJ Plugin Verifier action using GitHub Action 142 | - name: Verify Plugin 143 | id: verify 144 | uses: ChrisCarini/intellij-platform-plugin-verifier-action@v0.0.2 145 | with: 146 | plugin-location: plugin-artifact/${{ needs.build.outputs.artifact }} 147 | ide-versions: | 148 | ideaIC:2019.3 149 | ideaIC:2020.1 150 | 151 | # Print the output of the verify step 152 | - name: Print Logs 153 | env: 154 | OUTPUT_LOG: ${{ steps.verify.outputs.verification-output-log-filename }} 155 | run: | 156 | echo "The verifier log file [$OUTPUT_LOG] contents : " ; 157 | cat $OUTPUT_LOG 158 | 159 | # Prepare a draft release for GitHub Releases page for the manual verification 160 | # If accepted and published, release workflow would be triggered 161 | releaseDraft: 162 | name: Release Draft 163 | if: github.ref == 'refs/heads/master' 164 | needs: [build, verify] 165 | runs-on: ubuntu-latest 166 | steps: 167 | 168 | # Check out current repository 169 | - name: Fetch Sources 170 | uses: actions/checkout@v2 171 | 172 | # Remove old release drafts by using the curl request for the available releases with draft flag 173 | - name: Remove Old Release Drafts 174 | env: 175 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 176 | run: | 177 | curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/repos/$GITHUB_REPOSITORY/releases \ 178 | | tr '\r\n' ' ' \ 179 | | jq '.[] | select(.draft == true) | .id' \ 180 | | xargs -I '{}' \ 181 | curl -X DELETE -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/repos/$GITHUB_REPOSITORY/releases/{} 182 | 183 | # Create new release draft - which is not publicly visible and requires manual acceptance 184 | - name: Create Release Draft 185 | id: createDraft 186 | uses: actions/create-release@v1 187 | env: 188 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 189 | with: 190 | tag_name: v${{ needs.build.outputs.version }} 191 | release_name: v${{ needs.build.outputs.version }} 192 | body: ${{ needs.build.outputs.changelog }} 193 | draft: true 194 | 195 | # Download plugin artifact provided by the previous job 196 | - name: Download Artifact 197 | uses: actions/download-artifact@v1 198 | with: 199 | name: plugin-artifact 200 | 201 | # Upload artifact as a release asset 202 | - name: Upload Release Asset 203 | id: upload-release-asset 204 | uses: actions/upload-release-asset@v1 205 | env: 206 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 207 | with: 208 | upload_url: ${{ steps.createDraft.outputs.upload_url }} 209 | asset_path: ./plugin-artifact/${{ needs.build.outputs.artifact }} 210 | asset_name: ${{ needs.build.outputs.artifact }} 211 | asset_content_type: application/zip -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for handling the release process based on the draft release prepared 2 | # with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. 3 | 4 | name: Release 5 | on: 6 | release: 7 | types: [released] 8 | 9 | jobs: 10 | 11 | # Prepare and publish the plugin to the Marketplace repository 12 | release: 13 | name: Publish Plugin 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | # Check out current repository 18 | - name: Fetch Sources 19 | uses: actions/checkout@v2 20 | with: 21 | ref: ${{ github.event.release.tag_name }} 22 | 23 | # Setup Java 1.8 environment for the next steps 24 | - name: Setup Java 25 | uses: actions/setup-java@v1 26 | with: 27 | java-version: 1.8 28 | 29 | # Publish the plugin to the Marketplace 30 | - name: Publish Plugin 31 | env: 32 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 33 | run: ./gradlew publishPlugin 34 | 35 | # Commit patched Changelog 36 | - name: Commit files 37 | run: | 38 | git config --local user.email "action@github.com" 39 | git config --local user.name "GitHub Action" 40 | git commit -m "Update changelog" -a 41 | 42 | # Push changes 43 | - name: Push changes 44 | uses: ad-m/github-push-action@master 45 | with: 46 | github_token: ${{ secrets.GITHUB_TOKEN }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sandbox 2 | *.iml 3 | 4 | # Created by .ignore support plugin (hsz.mobi) 5 | ### JetBrains template 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff: 10 | .idea/workspace.xml 11 | .idea/tasks.xml 12 | .idea/dictionaries 13 | .idea/vcs.xml 14 | .idea/jsLibraryMappings.xml 15 | 16 | # Sensitive or high-churn files: 17 | .idea/dataSources.ids 18 | .idea/dataSources.xml 19 | .idea/dataSources.local.xml 20 | .idea/sqlDataSources.xml 21 | .idea/dynamic.xml 22 | .idea/uiDesigner.xml 23 | 24 | # Gradle: 25 | .idea/gradle.xml 26 | .idea/libraries 27 | 28 | # Mongo Explorer plugin: 29 | .idea/mongoSettings.xml 30 | 31 | ## File-based project format: 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | /out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | fabric.properties 50 | ### Gradle template 51 | .gradle 52 | build/ 53 | 54 | # Ignore Gradle GUI config 55 | gradle-app.setting 56 | 57 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 58 | !gradle-wrapper.jar 59 | 60 | # Cache of project 61 | .gradletasknamecache 62 | 63 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 64 | # gradle/wrapper/gradle-wrapper.properties 65 | local.properties 66 | plugin/out/ 67 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Main Authors 2 | 3 | - Jim Schubert 4 | 5 | # Contributors 6 | 7 | - 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 5 | 6 | ## [Unreleased] 7 | 8 | ## [4.3.1-p1] 9 | 10 | -------------------------------------------------------------------------------- /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, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the 13 | copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other 16 | entities that control, are controlled by, or are under common control with 17 | that entity. For the purposes of this definition, "control" means (i) the 18 | power, direct or indirect, to cause the direction or management of such 19 | entity, whether by contract or otherwise, or (ii) ownership of 20 | fifty percent (50%) or more of the outstanding shares, or (iii) beneficial 21 | ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | 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 source, 28 | and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation 31 | or translation of a Source form, including but not limited to compiled 32 | object code, generated documentation, and conversions to 33 | other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or Object 36 | form, made available under the License, as indicated by a copyright notice 37 | that is included in or attached to the work (an example is provided in the 38 | Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object form, 41 | that is based on (or derived from) the Work and for which the editorial 42 | revisions, annotations, elaborations, or other modifications represent, 43 | as a whole, an original work of authorship. For the purposes of this 44 | License, Derivative Works shall not include works that remain separable 45 | from, or merely link (or bind by name) to the interfaces of, the Work and 46 | Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including the original 49 | version of the Work and any modifications or additions to that Work or 50 | Derivative Works thereof, that is intentionally submitted to Licensor for 51 | inclusion in the Work by the copyright owner or by an individual or 52 | Legal Entity authorized to submit on behalf of the copyright owner. 53 | For the purposes of this definition, "submitted" means any form of 54 | electronic, verbal, or written communication sent to the Licensor or its 55 | representatives, including but not limited to communication on electronic 56 | mailing lists, source code control systems, and issue tracking systems 57 | that are managed by, or on behalf of, the Licensor for the purpose of 58 | discussing and improving the Work, but excluding communication that is 59 | conspicuously marked or otherwise designated in writing by the copyright 60 | owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity on 63 | behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. 67 | 68 | Subject to the terms and conditions of this License, each Contributor 69 | hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 70 | royalty-free, irrevocable copyright license to reproduce, prepare 71 | Derivative Works of, publicly display, publicly perform, sublicense, 72 | and distribute the Work and such Derivative Works in 73 | Source or Object form. 74 | 75 | 3. Grant of Patent License. 76 | 77 | Subject to the terms and conditions of this License, each Contributor 78 | hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 79 | royalty-free, irrevocable (except as stated in this section) patent 80 | license to make, have made, use, offer to sell, sell, import, and 81 | otherwise transfer the Work, where such license applies only to those 82 | patent claims licensable by such Contributor that are necessarily 83 | infringed by their Contribution(s) alone or by combination of their 84 | Contribution(s) with the Work to which such Contribution(s) was submitted. 85 | If You institute patent litigation against any entity (including a 86 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 87 | Contribution incorporated within the Work constitutes direct or 88 | contributory patent infringement, then any patent licenses granted to 89 | You under this License for that Work shall terminate as of the date such 90 | litigation is filed. 91 | 92 | 4. Redistribution. 93 | 94 | You may reproduce and distribute copies of the Work or Derivative Works 95 | thereof in any medium, with or without modifications, and in Source or 96 | Object form, provided that You meet the following conditions: 97 | 98 | 1. You must give any other recipients of the Work or Derivative Works a 99 | copy of this License; and 100 | 101 | 2. You must cause any modified files to carry prominent notices stating 102 | that You changed the files; and 103 | 104 | 3. You must retain, in the Source form of any Derivative Works that You 105 | distribute, all copyright, patent, trademark, and attribution notices from 106 | the Source form of the Work, excluding those notices that do not pertain 107 | to any part of the Derivative Works; and 108 | 109 | 4. If the Work includes a "NOTICE" text file as part of its distribution, 110 | then any Derivative Works that You distribute must include a readable copy 111 | of the attribution notices contained within such NOTICE file, excluding 112 | those notices that do not pertain to any part of the Derivative Works, 113 | in at least one of the following places: within a NOTICE text file 114 | distributed as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, within a 116 | display generated by the Derivative Works, if and wherever such 117 | third-party notices normally appear. The contents of the NOTICE file are 118 | for informational purposes only and do not modify the License. 119 | You may add Your own attribution notices within Derivative Works that You 120 | distribute, alongside or as an addendum to the NOTICE text from the Work, 121 | provided that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and may 125 | provide additional or different license terms and conditions for use, 126 | reproduction, or distribution of Your modifications, or for any such 127 | Derivative Works as a whole, provided Your use, reproduction, and 128 | distribution of the Work otherwise complies with the conditions 129 | stated in this License. 130 | 131 | 5. Submission of Contributions. 132 | 133 | Unless You explicitly state otherwise, any Contribution intentionally 134 | submitted for inclusion in the Work by You to the Licensor shall be under 135 | the terms and conditions of this License, without any additional 136 | terms or conditions. Notwithstanding the above, nothing herein shall 137 | supersede or modify the terms of any separate license agreement you may 138 | have executed with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. 141 | 142 | This License does not grant permission to use the trade names, trademarks, 143 | service marks, or product names of the Licensor, except as required for 144 | reasonable and customary use in describing the origin of the Work and 145 | reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. 148 | 149 | Unless required by applicable law or agreed to in writing, Licensor 150 | provides the Work (and each Contributor provides its Contributions) 151 | on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 152 | either express or implied, including, without limitation, any warranties 153 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS 154 | FOR A PARTICULAR PURPOSE. You are solely responsible for determining the 155 | appropriateness of using or redistributing the Work and assume any risks 156 | associated with Your exercise of permissions under this License. 157 | 158 | 8. Limitation of Liability. 159 | 160 | In no event and under no legal theory, whether in tort 161 | (including negligence), contract, or otherwise, unless required by 162 | applicable law (such as deliberate and grossly negligent acts) or agreed 163 | to in writing, shall any Contributor be liable to You for damages, 164 | including any direct, indirect, special, incidental, or consequential 165 | damages of any character arising as a result of this License or out of 166 | the use or inability to use the Work (including but not limited to damages 167 | for loss of goodwill, work stoppage, computer failure or malfunction, 168 | or any and all other commercial damages or losses), even if such 169 | Contributor has been advised of the possibility of such damages. 170 | 171 | 9. Accepting Warranty or Additional Liability. 172 | 173 | While redistributing the Work or Derivative Works thereof, You may choose 174 | to offer, and charge a fee for, acceptance of support, warranty, 175 | indemnity, or other liability obligations and/or rights consistent with 176 | this License. However, in accepting such obligations, You may act only 177 | on Your own behalf and on Your sole responsibility, not on behalf of any 178 | other Contributor, and only if You agree to indemnify, defend, and hold 179 | each Contributor harmless for any liability incurred by, or claims 180 | asserted against, such Contributor by reason of your accepting any such 181 | warranty or additional liability. 182 | 183 | END OF TERMS AND CONDITIONS 184 | 185 | APPENDIX: How to apply the Apache License to your work 186 | 187 | To apply the Apache License to your work, attach the following boilerplate 188 | notice, with the fields enclosed by brackets "[]" replaced with your own 189 | identifying information. (Don't include the brackets!) The text should be 190 | enclosed in the appropriate comment syntax for the file format. We also 191 | recommend that a file or class name and description of purpose be included 192 | on the same "printed page" as the copyright notice for easier 193 | identification within third-party archives. 194 | 195 | Copyright 2016 Jim Schubert 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); 198 | you may not use this file except in compliance with the License. 199 | You may obtain a copy of the License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software 204 | distributed under the License is distributed on an "AS IS" BASIS, 205 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 206 | or implied. See the License for the specific language governing 207 | permissions and limitations under the License. 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator plugin for IntelliJ IDEs 2 | 3 | ![Assemble Plugin](https://github.com/jimschubert/intellij-openapi-generator/workflows/Assemble%20Plugin/badge.svg) 4 | 5 | 6 | The OpenAPI Generator plugin allows you to generate client, server, or documentation code from your OpenAPI specifications within your IDE. 7 | 8 | 9 | This plugin allows for a sort of _spec_ driven development. 10 | 11 | While designing your API, you can generate one or more clients from within the IDE to evaluate your changes. 12 | 13 | Also install [intellij-swagger](https://plugins.jetbrains.com/plugin/8347) for a seamless Swagger/OpenAPI editor experience. 14 | 15 | # Building 16 | 17 | ``` 18 | ./gradlew clean buildPlugin 19 | ``` 20 | 21 | # Running in IntelliJ 22 | 23 | First, you'll need to [setup a development environment](http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/setting_up_environment.html). 24 | 25 | Then: 26 | 27 | ``` 28 | ./gradlew runIde 29 | ``` 30 | 31 | NOTE: When running locally, if changes don't appear in the sandbox instance you may have forgotten to update the plugin version in `gradle.properties`. 32 | 33 | # Usage 34 | 35 | Open a Specification YAML or JSON file in IntelliJ. Supported specifications are: OpenAPI 2.0/OpenAPI 3.0. With the document active, navigate to Code -> OpenAPI -> Generate from Document. 36 | 37 | Choose your desired generator and fill out options. Then, choose an output directory and generate. 38 | 39 | ## License 40 | 41 | This project is licensed under the Apache 2.0 license. See [./LICENSE](LICENSE) for more details. 42 | 43 | Swagger® is a registered trademark of SmartBear Software, Inc. 44 | 45 | This project is not maintained by, or associated with, SmartBear Software, Inc. 46 | This project is not maintained by, or associated with, OpenAPI Initiative (OAI) in anyway. 47 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | import io.gitlab.arturbosch.detekt.Detekt 18 | import org.jetbrains.changelog.closure 19 | import org.jetbrains.changelog.markdownToHTML 20 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 21 | 22 | plugins { 23 | // Java support 24 | id("java") 25 | // Kotlin support 26 | id("org.jetbrains.kotlin.jvm") version "1.3.72" 27 | // gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin 28 | id("org.jetbrains.intellij") version "0.4.21" 29 | // gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin 30 | id("org.jetbrains.changelog") version "0.3.2" 31 | // detekt linter - read more: https://detekt.github.io/detekt/kotlindsl.html 32 | id("io.gitlab.arturbosch.detekt") version "1.10.0-RC1" 33 | } 34 | 35 | // Import variables from gradle.properties file 36 | val pluginGroup: String by project 37 | val pluginName: String by project 38 | val pluginVersion: String by project 39 | val pluginSinceBuild: String by project 40 | val pluginUntilBuild: String by project 41 | val openapiGeneratorVersion: String by project 42 | 43 | val platformType: String by project 44 | val platformVersion: String by project 45 | val platformDownloadSources: String by project 46 | 47 | group = pluginGroup 48 | version = "$openapiGeneratorVersion-p$pluginVersion" 49 | 50 | // Configure project's dependencies 51 | repositories { 52 | mavenCentral() 53 | jcenter() 54 | } 55 | dependencies { 56 | implementation(kotlin("stdlib-jdk8")) 57 | implementation(kotlin("reflect")) 58 | 59 | implementation("org.openapitools:openapi-generator:$openapiGeneratorVersion") { 60 | // exclude group: 'org.slf4j', module: 'slf4j-api' 61 | // exclude group: 'org.slf4j', module: 'slf4j-ext' 62 | // exclude group: 'org.slf4j', module: 'slf4j-simple' 63 | } 64 | testCompile("junit:junit:4.12") 65 | 66 | detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.10.0") 67 | } 68 | 69 | // Configure gradle-intellij-plugin plugin. 70 | // Read more: https://github.com/JetBrains/gradle-intellij-plugin 71 | intellij { 72 | pluginName = pluginName 73 | version = platformVersion 74 | type = platformType 75 | downloadSources = platformDownloadSources.toBoolean() 76 | updateSinceUntilBuild = true 77 | 78 | // Plugin Dependencies: 79 | // https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_dependencies.html 80 | // 81 | // setPlugins("java") 82 | } 83 | 84 | // Configure detekt plugin. 85 | // Read more: https://detekt.github.io/detekt/kotlindsl.html 86 | detekt { 87 | config = files("./detekt-config.yml") 88 | 89 | reports { 90 | html.enabled = false 91 | xml.enabled = false 92 | txt.enabled = false 93 | } 94 | } 95 | 96 | tasks { 97 | // Set the compatibility versions to 1.8 98 | withType { 99 | sourceCompatibility = "1.8" 100 | targetCompatibility = "1.8" 101 | } 102 | listOf("compileKotlin", "compileTestKotlin").forEach { 103 | getByName(it) { 104 | kotlinOptions.jvmTarget = "1.8" 105 | } 106 | } 107 | 108 | withType { 109 | jvmTarget = "1.8" 110 | } 111 | 112 | patchPluginXml { 113 | version("$openapiGeneratorVersion-p$pluginVersion") 114 | sinceBuild(pluginSinceBuild) 115 | untilBuild(pluginUntilBuild) 116 | 117 | // Extract the section from README.md and provide for the plugin's manifest 118 | pluginDescription(closure { 119 | File("./README.md").readText().lines().run { 120 | subList(indexOf("") + 1, indexOf("")) 121 | }.joinToString("\n").run { markdownToHTML(this) } 122 | }) 123 | 124 | // Get the latest available change notes from the changelog file 125 | changeNotes(closure { 126 | changelog.getLatest().toHTML() 127 | }) 128 | } 129 | 130 | publishPlugin { 131 | dependsOn("patchChangelog") 132 | token(System.getenv("PUBLISH_TOKEN")) 133 | } 134 | } -------------------------------------------------------------------------------- /detekt-config.yml: -------------------------------------------------------------------------------- 1 | # Default detekt configuration: 2 | # https://github.com/detekt/detekt/blob/master/detekt-core/src/main/resources/default-detekt-config.yml 3 | 4 | formatting: 5 | active: true 6 | android: false 7 | autoCorrect: true 8 | ImportOrdering: 9 | active: false 10 | autoCorrect: true 11 | layout: 'idea' 12 | NoConsecutiveBlankLines: 13 | active: true 14 | autoCorrect: true 15 | SpacingAroundComma: 16 | active: true 17 | autoCorrect: true 18 | 19 | performance: 20 | active: true 21 | ArrayPrimitive: 22 | active: true 23 | ForEachOnRange: 24 | active: true 25 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 26 | UnnecessaryTemporaryInstantiation: 27 | active: true 28 | 29 | 30 | potential-bugs: 31 | active: true 32 | Deprecation: 33 | active: false 34 | DuplicateCaseInWhenExpression: 35 | active: true 36 | EqualsAlwaysReturnsTrueOrFalse: 37 | active: true 38 | EqualsWithHashCodeExist: 39 | active: true 40 | ExplicitGarbageCollectionCall: 41 | active: true 42 | HasPlatformType: 43 | active: false 44 | IgnoredReturnValue: 45 | active: false 46 | restrictToAnnotatedMethods: true 47 | returnValueAnnotations: ['*.CheckReturnValue', '*.CheckResult'] 48 | ImplicitDefaultLocale: 49 | active: false 50 | InvalidRange: 51 | active: true 52 | IteratorHasNextCallsNextMethod: 53 | active: true 54 | IteratorNotThrowingNoSuchElementException: 55 | active: true 56 | LateinitUsage: 57 | active: false 58 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 59 | excludeAnnotatedProperties: [] 60 | ignoreOnClassesPattern: '' 61 | MapGetWithNotNullAssertionOperator: 62 | active: false 63 | MissingWhenCase: 64 | active: true 65 | RedundantElseInWhen: 66 | active: true 67 | UnconditionalJumpStatementInLoop: 68 | active: false 69 | UnnecessaryNotNullOperator: 70 | active: false 71 | UnnecessarySafeCall: 72 | active: false 73 | UnreachableCode: 74 | active: true 75 | UnsafeCallOnNullableType: 76 | active: true 77 | UnsafeCast: 78 | active: false 79 | UselessPostfixExpression: 80 | active: false 81 | WrongEqualsTypeParameter: 82 | active: true 83 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | name = "intellij-openapi-generator" 2 | 3 | openapiGeneratorVersion=4.3.1 4 | pluginVersion = 1 5 | 6 | slf4jVersion=1.7.12 7 | 8 | pluginGroup = us.jimschubert.intellij.openapitools 9 | pluginName = intellij_openapi_generator 10 | pluginSinceBuild = 193.4778.7 11 | pluginUntilBuild = 201.* 12 | 13 | platformType = IC 14 | platformVersion = 2019.3 15 | platformDownloadSources = true 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimschubert/intellij-openapi-generator/f673b545da3512eeb510a1997044314e0be6efc0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "intellij-openapi-generator" -------------------------------------------------------------------------------- /src/main/java/us/jimschubert/intellij/openapitools/ui/GeneratorInfoPanel.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /src/main/java/us/jimschubert/intellij/openapitools/ui/GeneratorInfoPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui; 18 | 19 | import javax.swing.*; 20 | 21 | public class GeneratorInfoPanel { 22 | private JPanel component; 23 | 24 | public JPanel getComponent() { 25 | return component; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools 18 | 19 | import com.intellij.CommonBundle 20 | import java.util.* 21 | 22 | internal class Message { 23 | companion object { 24 | private const val bundleName = "messages.GeneratorBundle" 25 | private val bundle: ResourceBundle = ResourceBundle.getBundle(bundleName) 26 | infix fun of(key: String): String { 27 | return CommonBundle.message(bundle, key, listOf()) 28 | } 29 | 30 | fun of(key: String, vararg params: Any): String { 31 | return CommonBundle.message(bundle, key, *params) 32 | } 33 | 34 | @Suppress("NOTHING_TO_INLINE", "unused") 35 | inline fun message(key: String, vararg params: Any) : String = Message.of(key, params) 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/actions/CodegenGenerateAction.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.actions 18 | 19 | import com.intellij.openapi.actionSystem.AnAction 20 | import com.intellij.openapi.actionSystem.AnActionEvent 21 | import com.intellij.openapi.actionSystem.PlatformDataKeys 22 | import us.jimschubert.intellij.openapitools.events.GenerationNotificationManager 23 | import us.jimschubert.intellij.openapitools.ui.GenerateDialog 24 | 25 | class CodegenGenerateAction : AnAction() { 26 | 27 | private val notificationManager: GenerationNotificationManager = GenerationNotificationManager() 28 | 29 | override fun actionPerformed(e: AnActionEvent) { 30 | val project = e.project ?: return 31 | val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) ?: return 32 | 33 | GenerateDialog(project, file, notificationManager).show() 34 | } 35 | 36 | override fun update(e: AnActionEvent) { 37 | try { 38 | val file = e.getData(PlatformDataKeys.VIRTUAL_FILE) 39 | val ext = file?.extension?.toLowerCase() ?: "" 40 | if (file != null) { 41 | // TODO: Add a better condition here, or maybe support user-defined regex 42 | e.presentation.isEnabled = validExtensions.contains(ext) 43 | } else { 44 | super.update(e) 45 | } 46 | } catch(ex: Throwable) { 47 | super.update(e) 48 | } 49 | } 50 | 51 | companion object { 52 | val validExtensions = listOf("yaml", "yml", "json") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/actions/CodegenVersion.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | package us.jimschubert.intellij.openapitools.actions 17 | 18 | import com.intellij.openapi.actionSystem.AnAction 19 | import com.intellij.openapi.actionSystem.AnActionEvent 20 | import com.intellij.openapi.ui.Messages 21 | import org.openapitools.codegen.DefaultCodegen 22 | 23 | class CodegenVersion : AnAction() { 24 | 25 | override fun actionPerformed(e: AnActionEvent) { 26 | val project = e.project ?: return 27 | val version = DefaultCodegen::class.java.`package`.implementationVersion 28 | Messages.showMessageDialog(project, "OpenAPI Generator ${version?:"unknown"}
See Official Docs", "Information", Messages.getInformationIcon()) 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/events/GenerationNotificationManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.events 18 | 19 | import com.intellij.ide.actions.RevealFileAction 20 | import com.intellij.ide.actions.ShowFilePathAction 21 | import com.intellij.notification.* 22 | import com.intellij.openapi.application.ApplicationManager 23 | import com.intellij.openapi.diagnostic.Logger 24 | import com.intellij.openapi.project.ProjectManager 25 | import java.nio.file.Paths 26 | 27 | class GenerationNotificationManager { 28 | private val logger = Logger.getInstance(this.javaClass) 29 | 30 | fun warn(message: String) { 31 | logger.warn(message) 32 | } 33 | 34 | @Suppress("MemberVisibilityCanBePrivate") 35 | fun error(message: String) { 36 | logger.error(message) 37 | } 38 | 39 | fun success(lang: String, outputDir: String) { 40 | val project = ProjectManager.getInstance().openProjects.firstOrNull() 41 | val title = us.jimschubert.intellij.openapitools.Message.of("notification.generation.success.title", GROUP) 42 | val content = us.jimschubert.intellij.openapitools.Message.of("notification.generation.success.content", lang, outputDir) 43 | 44 | // Use a NotificationAction here rather than a listener with hyperlinks. 45 | // This allows "Open" link to be functional in Event Log, and that link will "expire" once it is clicked in the Event Log. 46 | val notification = notificationGroup.createNotification(title, content, NotificationType.INFORMATION, null) 47 | val openAction = NotificationAction.create("Open") { _ -> 48 | RevealFileAction.openFile(Paths.get(outputDir).toAbsolutePath().toFile()) 49 | notification.expire() 50 | } 51 | notification.addAction(openAction) 52 | 53 | // Must invokeLater, otherwise Notification only displays after dialogs or other disposables are disposed 54 | // see https://intellij-support.jetbrains.com/hc/en-us/community/posts/206766265-Notification-Balloon-not-shown-weird-scenario 55 | ApplicationManager.getApplication().executeOnPooledThread { 56 | Notifications.Bus.notify(notification, project) 57 | } 58 | } 59 | 60 | fun failure(t: Throwable? = null) { 61 | val project = ProjectManager.getInstance().openProjects.firstOrNull() 62 | val title = us.jimschubert.intellij.openapitools.Message.of("notification.generation.failure.title", GROUP) 63 | 64 | error(t?.message ?: "Unknown error") 65 | 66 | // Must invokeLater, otherwise Notification only displays after dialogs or other disposables are disposed 67 | // see https://intellij-support.jetbrains.com/hc/en-us/community/posts/206766265-Notification-Balloon-not-shown-weird-scenario 68 | ApplicationManager.getApplication().executeOnPooledThread { 69 | Notifications.Bus.notify(notificationGroup.createNotification(title, NotificationType.WARNING), project) 70 | } 71 | 72 | } 73 | 74 | companion object { 75 | private const val GROUP = "OpenAPI" 76 | private var notificationGroup: NotificationGroup 77 | 78 | init { 79 | notificationGroup = NotificationGroup(GROUP, NotificationDisplayType.BALLOON, true) 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/ActionButtonGroup.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.openapi.application.ApplicationManager 20 | import java.awt.event.ActionEvent 21 | import java.awt.event.ActionListener 22 | import javax.swing.AbstractButton 23 | import javax.swing.ButtonGroup 24 | import javax.swing.event.EventListenerList 25 | 26 | // TODO: Is there some Kotlin magic to use here? 27 | internal class ActionButtonGroup : ButtonGroup() { 28 | private val app = ApplicationManager.getApplication() 29 | private val boundListeners = EventListenerList() 30 | private val listener = Listener(this) { e: ActionEvent? -> 31 | onChange(e) 32 | } 33 | 34 | override fun add(b: AbstractButton?) { 35 | b?.addActionListener(listener) 36 | super.add(b) 37 | } 38 | 39 | private fun addActionListener(listener: ActionListener) { 40 | boundListeners.add(listener.javaClass, listener) 41 | } 42 | 43 | fun addActionListener(anonymousListener: (ActionEvent?) -> Unit) { 44 | addActionListener(Listener(this, anonymousListener)) 45 | } 46 | 47 | @Suppress("unused") 48 | fun removeActionListener(listener: ActionListener) { 49 | boundListeners.remove(listener.javaClass, listener) 50 | } 51 | 52 | private fun onChange(e: ActionEvent?) { 53 | val command = e?.actionCommand ?: "" 54 | val evt = ActionEvent(this, ActionEvent.ACTION_PERFORMED, command) 55 | boundListeners.listenerList.forEach { 56 | app.invokeLater { 57 | (it as? ActionListener)?.actionPerformed(evt) 58 | } 59 | } 60 | } 61 | 62 | private class Listener(@Suppress("unused") val owner: ActionButtonGroup, val callback: (ActionEvent?) -> Unit) : 63 | ActionListener { 64 | override fun actionPerformed(e: ActionEvent?) { 65 | callback.invoke(e) 66 | } 67 | 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/CliConstrainedOption.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | internal data class CliConstrainedOption(val option: String, val description: String) { 20 | companion object { 21 | fun fromKvp(entry: Map.Entry): CliConstrainedOption { 22 | return CliConstrainedOption(entry.key, entry.value) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/CodegenConfigOptions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import org.openapitools.codegen.CodegenConfig 20 | 21 | data class CodegenConfigOptions(val config: CodegenConfig, val inputs: List) 22 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/ConstrainedOptionsPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import java.awt.GridBagConstraints 20 | import java.awt.GridBagLayout 21 | import javax.swing.JPanel 22 | import javax.swing.JRadioButton 23 | 24 | internal class ConstrainedOptionsPanel(options: List, private val default: String? = null) : 25 | JPanel(GridBagLayout()) { 26 | private val defaultIdentifier = "" 27 | private val group: ActionButtonGroup = ActionButtonGroup() 28 | 29 | init { 30 | // set width 31 | var x = 0 32 | var y = 0 33 | options.forEach { opt -> 34 | val gridConstraint = GridBagConstraints() 35 | gridConstraint.weightx = 0.5 36 | gridConstraint.gridx = x 37 | gridConstraint.gridy = y 38 | gridConstraint.fill = GridBagConstraints.HORIZONTAL 39 | 40 | val button = JRadioButton(opt.option) 41 | button.toolTipText = opt.description 42 | button.actionCommand = opt.option 43 | button.isSelected = opt.option == default ?: defaultIdentifier 44 | 45 | group.add(button) 46 | 47 | add(button, gridConstraint) 48 | 49 | x++ 50 | if (x == 2) { 51 | // Arbitrary column overflow, reset and move to next row 52 | x = 0 53 | y++ 54 | } 55 | } 56 | // avoid group.selection to be null when there is no default option 57 | if (group.selection == null) group.elements.nextElement().isSelected = true 58 | } 59 | 60 | val value: String 61 | get() = group.selection.actionCommand 62 | } 63 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GenerateDialog.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.ide.CommonActionsManager 20 | import com.intellij.ide.DefaultTreeExpander 21 | import com.intellij.openapi.actionSystem.ActionManager 22 | import com.intellij.openapi.actionSystem.ActionPlaces 23 | import com.intellij.openapi.actionSystem.ActionToolbar 24 | import com.intellij.openapi.actionSystem.DefaultActionGroup 25 | import com.intellij.openapi.diagnostic.Logger 26 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory 27 | import com.intellij.openapi.project.Project 28 | import com.intellij.openapi.ui.DialogWrapper 29 | import com.intellij.openapi.ui.TextFieldWithBrowseButton 30 | import com.intellij.openapi.ui.ValidationInfo 31 | import com.intellij.openapi.util.io.FileUtil 32 | import com.intellij.openapi.vfs.VirtualFile 33 | import com.intellij.ui.OnePixelSplitter 34 | import com.intellij.ui.ScrollPaneFactory 35 | import com.intellij.ui.TabbedPaneWrapper 36 | import com.intellij.ui.tabs.impl.JBTabsImpl 37 | import com.intellij.util.ui.JBUI 38 | import com.intellij.util.ui.tree.TreeUtil 39 | import io.swagger.parser.SwaggerParser 40 | import org.openapitools.codegen.CodegenConfig 41 | import org.openapitools.codegen.CodegenType 42 | import org.openapitools.codegen.DefaultGenerator 43 | import org.openapitools.codegen.config.CodegenConfigurator 44 | import us.jimschubert.intellij.openapitools.Message 45 | import us.jimschubert.intellij.openapitools.events.GenerationNotificationManager 46 | import java.awt.BorderLayout 47 | import java.io.File 48 | import java.util.* 49 | import javax.swing.* 50 | 51 | class GenerateDialog( 52 | private val project: Project, 53 | val file: VirtualFile, 54 | private val notificationManager: GenerationNotificationManager 55 | ) : DialogWrapper(project) { 56 | companion object { 57 | private var generatorTypeMap: MutableMap> = mutableMapOf() 58 | // private val app = ApplicationManager.getApplication() 59 | } 60 | 61 | private val logger = Logger.getInstance(this.javaClass) 62 | private lateinit var optionsPanel: JPanel 63 | private lateinit var settingsPanel: GeneratorGeneralSettingsPanel 64 | private lateinit var panel: JPanel 65 | private lateinit var tree: GeneratorsTreePanel 66 | private lateinit var expander: DefaultTreeExpander 67 | 68 | private lateinit var additionalPropertiesPanel: KeyValuePropertiesPanel 69 | private lateinit var instantiationTypesPanel: KeyValuePropertiesPanel 70 | private lateinit var importMappingsPanel: KeyValuePropertiesPanel 71 | private lateinit var typeMappingsPanel: KeyValuePropertiesPanel 72 | private lateinit var primitivesPanel: ValuePropertiesPanel 73 | 74 | private var currentConfigOptions: us.jimschubert.intellij.openapitools.ui.CodegenConfigOptions? = null 75 | private val langPanel = TabbedPaneWrapper(this.project) // TODO: Implement disposable on Dialog? 76 | 77 | private val emptyBorder = JBUI.Borders.empty() 78 | private val outputBrowse = TextFieldWithBrowseButton() 79 | 80 | init { 81 | outputBrowse.addBrowseFolderListener( 82 | us.jimschubert.intellij.openapitools.Message of "dialog.generate.output-browse.title", 83 | null, 84 | project, 85 | FileChooserDescriptorFactory.createSingleFolderDescriptor() 86 | ) 87 | 88 | // TODO: Prior to building anything here, read and parse file. If that fails, bail immediately with error message. 89 | if (generatorTypeMap.isEmpty()) { 90 | val extensions: List = 91 | ServiceLoader.load(CodegenConfig::class.java, CodegenConfig::class.java.classLoader).toList() 92 | for (extension in extensions) { 93 | if (!generatorTypeMap.containsKey(extension.tag)) { 94 | generatorTypeMap[extension.tag] = mutableListOf(extension) 95 | } else { 96 | generatorTypeMap[extension.tag]?.add(extension) 97 | } 98 | } 99 | } 100 | title = Message of "dialog.generate.title" 101 | setOKButtonText(Message of "dialog.generate.ok") 102 | setCancelButtonText(Message of "dialog.generate.cancel") 103 | 104 | createOptionsPanel() 105 | createTree() 106 | 107 | createAdditionalPropertiesPanel() 108 | createInstantiationTypesPanel() 109 | createImportMappingsPanel() 110 | createTypeMappingsPanel() 111 | createPrimitivesPanel() 112 | 113 | setResizable(false) 114 | init() 115 | } 116 | 117 | private fun createPrimitivesPanel() { 118 | primitivesPanel = ValuePropertiesPanel( 119 | Message of "panel.primitive-types.value-column" 120 | ) 121 | primitivesPanel.setEmptyMessage(Message of "panel.primitive-types.empty-message") 122 | } 123 | 124 | private fun createTypeMappingsPanel() { 125 | typeMappingsPanel = KeyValuePropertiesPanel( 126 | us.jimschubert.intellij.openapitools.Message of "panel.type-mappings.key-column", 127 | us.jimschubert.intellij.openapitools.Message of "panel.type-mappings.value-column" 128 | ) 129 | typeMappingsPanel.setEmptyMessage(Message of "panel.type-mappings.empty-message") 130 | } 131 | 132 | private fun createImportMappingsPanel() { 133 | importMappingsPanel = KeyValuePropertiesPanel( 134 | Message of "panel.import-mappings.key-column", 135 | Message of "panel.import-mappings.value-column" 136 | ) 137 | importMappingsPanel.setEmptyMessage(Message of "panel.import-mappings.empty-message") 138 | } 139 | 140 | private fun createAdditionalPropertiesPanel() { 141 | additionalPropertiesPanel = KeyValuePropertiesPanel( 142 | Message of "panel.additional-properties.key-column" 143 | ) 144 | additionalPropertiesPanel.setEmptyMessage(Message of "panel.additional-properties.empty-message") 145 | } 146 | 147 | private fun createInstantiationTypesPanel() { 148 | instantiationTypesPanel = KeyValuePropertiesPanel( 149 | Message of "panel.instantiation-types.key-column", 150 | Message of "panel.instantiation-types.value-column" 151 | ) 152 | instantiationTypesPanel.setEmptyMessage(Message of "panel.instantiation-types.empty-message") 153 | } 154 | 155 | private fun createOptionsPanel() { 156 | optionsPanel = JPanel(BorderLayout()) 157 | optionsPanel.border = JBUI.Borders.empty(0, 2, 0, 2) 158 | optionsPanel.preferredSize = JBUI.size(800 - 185, 400) 159 | } 160 | 161 | // TODO: Form validation 162 | override fun doValidate(): ValidationInfo? { 163 | // valid OpenAPI file 164 | SwaggerParser().readWithInfo(file.path) ?: return ValidationInfo("Specification file is invalid.", null) 165 | 166 | if (outputBrowse.text.isEmpty()) { 167 | notificationManager.warn("Output directory is empty.") 168 | return ValidationInfo("Output directory is empty.", outputBrowse) 169 | } else { 170 | val path = outputBrowse.text.replaceFirst("^~", System.getProperty("user.home")) 171 | if (outputBrowse.text != path) { 172 | outputBrowse.text = path 173 | } 174 | 175 | val output = File(FileUtil.toSystemDependentName(path)) 176 | if (output.exists() && !output.isDirectory) { 177 | notificationManager.warn("Output directory is not a valid directory.") 178 | return ValidationInfo("Output directory is not a valid directory.", outputBrowse) 179 | } 180 | if (!output.exists()) { 181 | if (FileUtil.createDirectory(output)) { 182 | notificationManager.warn("Could not create output directory.") 183 | return ValidationInfo("Could not create output directory.", outputBrowse) 184 | } 185 | } 186 | 187 | if (!output.canWrite()) { 188 | notificationManager.warn("Output directory is not writable.") 189 | return ValidationInfo("Output directory is not writable.", outputBrowse) 190 | } 191 | } 192 | 193 | // TODO: Does this need to switch to the tab on error or flash it maybe? 194 | return settingsPanel.doValidate() ?: super.doValidate() 195 | } 196 | 197 | private fun syncOptionsPanelOnChange(newPanel: JPanel) { 198 | optionsPanel.removeAll() 199 | 200 | val wrapper = JPanel(BorderLayout()) 201 | wrapper.add(newPanel, BorderLayout.NORTH) 202 | 203 | val scroller = ScrollPaneFactory.createScrollPane(wrapper, true) 204 | scroller.preferredSize = optionsPanel.preferredSize 205 | 206 | optionsPanel.add(scroller, BorderLayout.CENTER) 207 | 208 | optionsPanel.revalidate() 209 | panel.revalidate() 210 | optionsPanel.repaint() 211 | 212 | // TODO: Reset settings and other panels? 213 | } 214 | 215 | private fun createTree() { 216 | tree = GeneratorsTreePanel(generatorTypeMap) 217 | tree.addNodeChangeListener(GeneratorsTreeSelectionListener { p: JPanel, configOptions: CodegenConfigOptions? -> 218 | currentConfigOptions = configOptions 219 | val tabPane = langPanel.component.components.first() as? JBTabsImpl 220 | if (currentConfigOptions != null) { 221 | langPanel.setTitleAt(0, currentConfigOptions?.config?.name ?: "") 222 | tabPane?.tabs?.forEachIndexed { index, tabInfo -> if (index > 0) tabInfo.isHidden = false } 223 | } else { 224 | langPanel.setTitleAt(0, "OpenAPI Generator") 225 | tabPane?.tabs?.forEachIndexed { index, tabInfo -> if (index > 0) tabInfo.isHidden = true } 226 | } 227 | langPanel.selectedIndex = 0 228 | syncOptionsPanelOnChange(p) 229 | }) 230 | expander = DefaultTreeExpander(tree.genTypeTree) 231 | } 232 | 233 | override fun doOKAction() { 234 | logger.debug("Inputs:") 235 | logger.debug(currentConfigOptions?.config?.javaClass?.simpleName) 236 | currentConfigOptions?.inputs?.forEach { logger.debug("${it.cliOption.opt}: ${it.userInput.invoke()}") } 237 | 238 | val configurator = CodegenConfigurator.fromFile(settingsPanel.configurationFile) ?: CodegenConfigurator() 239 | 240 | val generatorName = currentConfigOptions?.config?.javaClass?.typeName 241 | ?: throw IllegalStateException("Configuration options is unexpectedly inaccessible") 242 | configurator.setInputSpec(file.path) 243 | configurator.setGeneratorName(generatorName) 244 | configurator.setOutputDir(outputBrowse.text) 245 | 246 | configurator.setInstantiationTypes(instantiationTypesPanel.itemsAsMap()) 247 | configurator.setImportMappings(importMappingsPanel.itemsAsMap()) 248 | configurator.setTypeMappings(typeMappingsPanel.itemsAsMap()) 249 | configurator.setLanguageSpecificPrimitives(primitivesPanel.itemsAsSet()) 250 | @Suppress("USELESS_CAST") 251 | configurator.setAdditionalProperties(additionalPropertiesPanel.itemsAsMap() as Map?) 252 | 253 | configurator.setVerbose(settingsPanel.isVerbose) 254 | configurator.setSkipOverwrite(settingsPanel.skipOverwrite) 255 | 256 | if (settingsPanel.templateDirectory != null) 257 | configurator.setTemplateDir(settingsPanel.templateDirectory) 258 | 259 | configurator.setLibrary(settingsPanel.library) 260 | configurator.setInvokerPackage(settingsPanel.invokerPackage) 261 | configurator.setGroupId(settingsPanel.groupId) 262 | configurator.setArtifactId(settingsPanel.artifactId) 263 | configurator.setArtifactVersion(settingsPanel.artifactVersion) 264 | configurator.setApiPackage(settingsPanel.apiPackage) 265 | configurator.setAuth(settingsPanel.auth) 266 | 267 | if (settingsPanel.includeSystemProperties) { 268 | System.getProperties().propertyNames().toList().forEach { prop -> 269 | when (prop) { 270 | is String -> configurator.addSystemProperty(prop, System.getProperty(prop)) 271 | } 272 | } 273 | } 274 | 275 | currentConfigOptions?.inputs?.forEach { userInput -> 276 | configurator.addAdditionalProperty(userInput.cliOption.opt, userInput.userInput()) 277 | } 278 | 279 | // Required for internal ServiceLoader calls to operate as expected. 280 | Thread.currentThread().contextClassLoader = javaClass.classLoader 281 | 282 | try { 283 | val files: MutableList = DefaultGenerator() 284 | .opts(configurator.toClientOptInput()) 285 | .generate() 286 | 287 | logger.info("Generated $generatorName output in ${outputBrowse.text}.") 288 | 289 | if (files.count() > 0) logger.debug("Generated files:") 290 | files.forEach { f -> logger.debug(f.canonicalPath) } 291 | 292 | notificationManager.success(currentConfigOptions?.config?.name ?: generatorName, outputBrowse.text) 293 | } catch (t: Throwable) { 294 | // notificationManager logs the error here, and we don't want to duplicate 295 | notificationManager.failure(t) 296 | } 297 | 298 | super.doOKAction() 299 | } 300 | 301 | override fun createCenterPanel(): JComponent? { 302 | panel = JPanel(BorderLayout()) 303 | 304 | // splitter divides the panel into two parts 305 | val splitter = OnePixelSplitter(false, .2f) 306 | splitter.border = emptyBorder 307 | splitter.setHonorComponentsMinimumSize(true) 308 | 309 | val scrollPaneLeft = ScrollPaneFactory.createScrollPane(tree, true) 310 | scrollPaneLeft.preferredSize = JBUI.size(185, 400) 311 | scrollPaneLeft.border = BorderFactory.createEmptyBorder(5, 5, 5, 5) 312 | 313 | val leftPanel = JPanel(BorderLayout()) 314 | leftPanel.add(createActionToolbar(tree).component, BorderLayout.NORTH) 315 | leftPanel.add(scrollPaneLeft, BorderLayout.CENTER) 316 | 317 | panel.add(splitter, BorderLayout.CENTER) 318 | splitter.firstComponent = leftPanel 319 | 320 | // TABS 321 | langPanel.addTab(currentConfigOptions?.config?.name ?: "Language", optionsPanel) 322 | 323 | langPanel.addTab("Additional Properties", additionalPropertiesPanel) 324 | langPanel.addTab("Instantiation Types", instantiationTypesPanel) 325 | langPanel.addTab("Imports", importMappingsPanel) 326 | langPanel.addTab("Type Mappings", typeMappingsPanel) 327 | langPanel.addTab("Primitives", primitivesPanel) 328 | 329 | settingsPanel = GeneratorGeneralSettingsPanel() 330 | 331 | langPanel.addTab("Generator Settings", settingsPanel.component) 332 | 333 | splitter.secondComponent = langPanel.component 334 | 335 | val outputPanel = JPanel(BorderLayout()) 336 | outputPanel.add(JSeparator(), BorderLayout.NORTH) 337 | outputPanel.add(JLabel("Output Directory: "), BorderLayout.WEST) 338 | outputPanel.add(outputBrowse, BorderLayout.CENTER) 339 | 340 | // https://github.com/JetBrains/intellij-plugins/blob/a37e133b767d5b407b172758bce8475515becc16/Dart/src/com/jetbrains/lang/dart/ide/runner/server/ui/DartCommandLineConfigurationEditorForm.java#L38 341 | panel.add(outputPanel, BorderLayout.SOUTH) 342 | 343 | if (currentConfigOptions == null || tree.genTypeTree.selectionPath == null) { 344 | TreeUtil.selectFirstNode(tree.genTypeTree) 345 | } 346 | 347 | return panel 348 | } 349 | 350 | private fun createActionToolbar(target: JComponent): ActionToolbar { 351 | val actionManager = CommonActionsManager.getInstance() 352 | val actions = DefaultActionGroup() 353 | 354 | actions.add(actionManager.createCollapseAllAction(expander, tree.genTypeTree)) 355 | actions.add(actionManager.createExpandAllAction(expander, tree.genTypeTree)) 356 | 357 | val toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actions, true) 358 | toolbar.setTargetComponent(target) 359 | return toolbar 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GeneratorGeneralSettingsPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.json.JsonFileType 20 | import com.intellij.openapi.application.ApplicationManager 21 | import com.intellij.openapi.fileChooser.FileChooserDescriptor 22 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory 23 | import com.intellij.openapi.ui.TextFieldWithBrowseButton 24 | import com.intellij.openapi.ui.ValidationInfo 25 | import com.intellij.ui.UIBundle 26 | import com.intellij.util.ui.FormBuilder 27 | import us.jimschubert.intellij.openapitools.Message 28 | import java.awt.AWTEvent 29 | import java.awt.event.TextEvent 30 | import java.io.File 31 | import javax.swing.JCheckBox 32 | import javax.swing.JPanel 33 | import javax.swing.JTextField 34 | import javax.swing.event.DocumentEvent 35 | import javax.swing.event.DocumentListener 36 | 37 | internal class GeneratorGeneralSettingsPanel : Validatable { 38 | 39 | private val _component: JPanel 40 | val component: JPanel 41 | get() = _component 42 | 43 | private var _isVerbose = false 44 | val isVerbose: Boolean 45 | get() = _isVerbose 46 | 47 | private var _skipOverwrite = false 48 | val skipOverwrite: Boolean 49 | get() = _skipOverwrite 50 | 51 | private var _includeSystemProperties = false 52 | val includeSystemProperties: Boolean 53 | get() = _includeSystemProperties 54 | 55 | private var _templateDirectory: String? = null 56 | val templateDirectory: String? 57 | get() = _templateDirectory 58 | 59 | private var _configurationFile: String? = null 60 | val configurationFile: String? 61 | get() = _configurationFile 62 | 63 | private var _library: String? = null 64 | val library: String? 65 | get() = _library 66 | 67 | private var _invokerPackage: String? = null 68 | val invokerPackage: String? 69 | get() = _invokerPackage 70 | 71 | private var _groupId: String? = null 72 | val groupId: String? 73 | get() = _groupId 74 | 75 | private var _artifactId: String? = null 76 | val artifactId: String? 77 | get() = _artifactId 78 | 79 | private var _artifactVersion: String? = null 80 | val artifactVersion: String? 81 | get() = _artifactVersion 82 | 83 | private var _apiPackage: String? = null 84 | val apiPackage: String? 85 | get() = _apiPackage 86 | 87 | private var _auth: String? = null 88 | val auth: String? 89 | get() = _auth 90 | 91 | init { 92 | 93 | val settingsPanelBuilder = FormBuilder.createFormBuilder() 94 | .addLabeledComponent("Verbose", checkbox { selected -> _isVerbose = selected }) 95 | .addLabeledComponent("Skip Overwrite", checkbox { selected -> _skipOverwrite = selected }) 96 | .addLabeledComponent( 97 | "Include System Properties", 98 | checkbox { selected -> _includeSystemProperties = selected }) 99 | .addLabeledComponent("Template Directory", 100 | browse( 101 | "panel.general-settings.browse.template-dir", 102 | FileChooserDescriptorFactory.createSingleFolderDescriptor() 103 | ) { e -> 104 | _templateDirectory = e.current 105 | }) 106 | .addLabeledComponent("Configuration File", 107 | browse( 108 | "panel.general-settings.browse.config-file", 109 | FileChooserDescriptorFactory.createSingleFileDescriptor(JsonFileType.INSTANCE) 110 | ) { e -> 111 | _configurationFile = e.current 112 | }) 113 | .addLabeledComponent("Library", text { e -> _library = e.current }) 114 | .addLabeledComponent("Invoker Package", text { e -> _invokerPackage = e.current }) 115 | .addLabeledComponent("Group ID", text { e -> _groupId = e.current }) 116 | .addLabeledComponent("Artifact ID", text { e -> _artifactId = e.current }) 117 | .addLabeledComponent("Artifact Version", text { e -> _artifactVersion = e.current }) 118 | .addLabeledComponent("API Package", text { e -> _apiPackage = e.current }) 119 | .addLabeledComponent("Auth", text { e -> _auth = e.current }) 120 | 121 | _component = settingsPanelBuilder.panel 122 | } 123 | 124 | private fun text(listener: (JTextFieldChangeEvent) -> Unit): JTextField { 125 | val element = JTextField() 126 | element.onChange { evt -> listener(evt) } 127 | 128 | return element 129 | } 130 | 131 | private fun checkbox(listener: (Boolean) -> Unit): JCheckBox { 132 | val element = JCheckBox() 133 | element.addChangeListener { _ -> listener(element.isSelected) } 134 | return element 135 | } 136 | 137 | private fun browse( 138 | bundleKey: String?, 139 | descriptor: FileChooserDescriptor, 140 | listener: (JTextFieldChangeEvent) -> Unit 141 | ): TextFieldWithBrowseButton { 142 | val element = TextFieldWithBrowseButton() 143 | @Suppress("InvalidBundleOrProperty") 144 | element.addBrowseFolderListener( 145 | Message of (bundleKey ?: UIBundle.message("file.chooser.default.title")), 146 | null, 147 | null, 148 | descriptor 149 | ) 150 | 151 | element.textField.onChange { evt -> listener(evt) } 152 | 153 | return element 154 | } 155 | 156 | override fun doValidate(): ValidationInfo? { 157 | if (_templateDirectory != null && _templateDirectory != "") { 158 | val tmplDir = File(_templateDirectory) 159 | if (!(tmplDir.exists() && tmplDir.isDirectory && tmplDir.canRead())) { 160 | return ValidationInfo("Invalid template directory") 161 | } 162 | } 163 | if (_configurationFile != null && _configurationFile != "") { 164 | val configFile = File(_configurationFile) 165 | if (!(configFile.exists() && configFile.isFile && configFile.canRead())) { 166 | return ValidationInfo("Invalid configuration file") 167 | } 168 | } 169 | // TODO: Validate other settings 170 | return super.doValidate() 171 | } 172 | } 173 | 174 | fun JTextField.onChange(listener: (JTextFieldChangeEvent) -> Unit) { 175 | document.addDocumentListener(TextChangeListener(this, listener)) 176 | } 177 | 178 | class TextChangeListener(private val source: JTextField, private val listener: (JTextFieldChangeEvent) -> Unit) : 179 | DocumentListener { 180 | private var prev: String? = null 181 | private val app = ApplicationManager.getApplication() 182 | 183 | override fun changedUpdate(e: DocumentEvent?) = handle() 184 | override fun insertUpdate(e: DocumentEvent?) = handle() 185 | override fun removeUpdate(e: DocumentEvent?) = handle() 186 | private fun handle() { 187 | app.invokeLater { 188 | listener(JTextFieldChangeEvent(source, prev, source.text)) 189 | } 190 | prev = source.text 191 | } 192 | } 193 | 194 | @Suppress("unused", "CanBeParameter") 195 | class JTextFieldChangeEvent(private val source: JTextField, val previous: String?, val current: String?) : 196 | AWTEvent(source, TextEvent.TEXT_VALUE_CHANGED) -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GeneratorsTreeNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.ui.SimpleColoredComponent 20 | import com.intellij.ui.SimpleTextAttributes 21 | import org.openapitools.codegen.CodegenConfig 22 | import javax.swing.JTree 23 | import javax.swing.tree.DefaultMutableTreeNode 24 | 25 | internal open class GeneratorsTreeNode( 26 | val display: String?, 27 | val value: CodegenConfig? = null, 28 | val parentNode: GeneratorsTreeNode? = null 29 | ) : DefaultMutableTreeNode(value) { 30 | fun render(component: SimpleColoredComponent, tree: JTree, selected: Boolean) { 31 | val unobtrusive = SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, tree.foreground.darker().darker()) 32 | val normal = SimpleTextAttributes(SimpleTextAttributes.STYLE_OPAQUE, tree.foreground) 33 | val brighter = SimpleTextAttributes(SimpleTextAttributes.STYLE_OPAQUE, tree.foreground.brighter()) 34 | val attrs = when { 35 | selected -> if (value != null) unobtrusive else brighter 36 | else -> normal 37 | } 38 | component.append(display ?: "", attrs, true) 39 | if (parentNode != null) { 40 | // Enforces no icons on generator items 41 | component.icon = null 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GeneratorsTreePanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.ui.ColoredTreeCellRenderer 20 | import com.intellij.ui.treeStructure.Tree 21 | import com.intellij.util.ui.UIUtil 22 | import com.intellij.util.ui.tree.TreeUtil 23 | import org.openapitools.codegen.CodegenConfig 24 | import org.openapitools.codegen.CodegenType 25 | import java.awt.BorderLayout 26 | import javax.swing.BorderFactory 27 | import javax.swing.JComponent 28 | import javax.swing.JTree 29 | import javax.swing.plaf.basic.BasicTreeUI 30 | import javax.swing.tree.DefaultMutableTreeNode 31 | import javax.swing.tree.DefaultTreeModel 32 | import javax.swing.tree.TreeSelectionModel 33 | 34 | internal class GeneratorsTreePanel(private val generators: Map>) : JComponent() { 35 | 36 | private val myTreeModel: DefaultTreeModel = buildModel() 37 | private val _genTypeTree: Tree = Tree(DefaultTreeModel(DefaultMutableTreeNode())) 38 | val genTypeTree: Tree 39 | get() = _genTypeTree 40 | 41 | init { 42 | genTypeTree.model = myTreeModel 43 | genTypeTree.cellRenderer = Renderer() 44 | 45 | TreeUtil.expandAll(genTypeTree) 46 | genTypeTree.isRootVisible = false 47 | genTypeTree.showsRootHandles = true 48 | 49 | // genTypeTree.putClientProperty(WideSelectionTreeUI.TREE_TABLE_TREE_KEY, true) 50 | genTypeTree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION 51 | 52 | genTypeTree.isOpaque = false 53 | genTypeTree.background = UIUtil.SIDE_PANEL_BACKGROUND 54 | genTypeTree.inputMap.clear() 55 | 56 | TreeUtil.installActions(genTypeTree) 57 | 58 | val basicUi = genTypeTree.ui as BasicTreeUI 59 | basicUi.leftChildIndent = 6 // Distance between left margin and where vertical dashes will be drawn. 60 | basicUi.rightChildIndent = 61 | 4 // Distance to add to leftChildIndent to determine where cell contents will be drawn. 62 | 63 | layout = BorderLayout() 64 | add(genTypeTree, BorderLayout.CENTER) 65 | } 66 | 67 | private fun buildModel(): DefaultTreeModel { 68 | val node = GeneratorsTreeRootNode(generators) 69 | return DefaultTreeModel(node) 70 | } 71 | 72 | fun addNodeChangeListener(listener: GeneratorsTreeSelectionListener) { 73 | genTypeTree.addTreeSelectionListener(listener) 74 | } 75 | 76 | private class Renderer : ColoredTreeCellRenderer() { 77 | init { 78 | border = BorderFactory.createEmptyBorder() 79 | isOpaque = false 80 | } 81 | 82 | override fun customizeCellRenderer( 83 | tree: JTree, 84 | value: Any?, 85 | selected: Boolean, 86 | expanded: Boolean, 87 | leaf: Boolean, 88 | row: Int, 89 | hasFocus: Boolean 90 | ) { 91 | val node = value as GeneratorsTreeNode? ?: return 92 | node.render(this, tree, selected) 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GeneratorsTreeRootNode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import org.openapitools.codegen.CodegenConfig 20 | import org.openapitools.codegen.CodegenType 21 | 22 | internal class GeneratorsTreeRootNode(generators: Map>) : GeneratorsTreeNode(null) { 23 | init { 24 | for (generator in generators) { 25 | val genNode = GeneratorsTreeNode(generator.key.toString()) 26 | add(genNode) 27 | for (typedGenerator in generator.value) { 28 | // TODO: Cleanup the display text 29 | val typedNode = 30 | GeneratorsTreeNode(display = typedGenerator.name, value = typedGenerator, parentNode = genNode) 31 | genNode.add(typedNode) 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/GeneratorsTreeSelectionListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import org.openapitools.codegen.CodegenConfig 20 | import javax.swing.JPanel 21 | import javax.swing.event.TreeSelectionEvent 22 | import javax.swing.event.TreeSelectionListener 23 | import javax.swing.tree.TreePath 24 | 25 | internal class GeneratorsTreeSelectionListener(private val sync: (JPanel, CodegenConfigOptions?) -> Unit) : 26 | TreeSelectionListener { 27 | 28 | override fun valueChanged(e: TreeSelectionEvent?) { 29 | sync(LanguageOptionsPanel.empty, null) 30 | 31 | if (e == null) return 32 | val paths = e.paths ?: return 33 | val valuePath: List = paths.filter { 34 | e.isAddedPath(it) 35 | } 36 | if (valuePath.isEmpty()) return 37 | val selected: TreePath = valuePath.first() 38 | 39 | val node = selected.lastPathComponent as GeneratorsTreeNode 40 | val language: CodegenConfig = node.value ?: return 41 | 42 | val panel = LanguageOptionsPanel(language) 43 | sync(panel.component, us.jimschubert.intellij.openapitools.ui.CodegenConfigOptions(language, panel.userOptions)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/JTrueFalseRadioPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import java.awt.GridBagConstraints 20 | import java.awt.GridBagLayout 21 | import javax.swing.JPanel 22 | import javax.swing.JRadioButton 23 | 24 | internal class JTrueFalseRadioPanel( 25 | defaultValue: Boolean, 26 | trueText: String = "True", 27 | falseText: String = "False" 28 | ) : JPanel(GridBagLayout()) { 29 | @Suppress("PrivatePropertyName") 30 | private val TRUE = "TRUE" 31 | 32 | @Suppress("PrivatePropertyName") 33 | private val FALSE = "FALSE" 34 | private val trueButton: JRadioButton = JRadioButton(trueText) 35 | private val falseButton: JRadioButton = JRadioButton(falseText) 36 | 37 | init { 38 | val group = us.jimschubert.intellij.openapitools.ui.ActionButtonGroup() 39 | 40 | trueButton.actionCommand = TRUE 41 | falseButton.actionCommand = FALSE 42 | 43 | trueButton.isSelected = defaultValue 44 | falseButton.isSelected = !trueButton.isSelected 45 | 46 | group.add(trueButton) 47 | group.add(falseButton) 48 | 49 | val gridConstraintTrue = GridBagConstraints() 50 | gridConstraintTrue.weightx = 0.5 51 | gridConstraintTrue.gridx = 0 52 | gridConstraintTrue.gridy = 0 53 | gridConstraintTrue.fill = GridBagConstraints.HORIZONTAL 54 | val gridConstraintFalse = gridConstraintTrue.clone() as GridBagConstraints 55 | gridConstraintFalse.gridx = 1 56 | 57 | add(trueButton, gridConstraintTrue) 58 | add(falseButton, gridConstraintFalse) 59 | 60 | group.addActionListener { e -> trueButton.isSelected = e?.actionCommand.equals(TRUE) } 61 | } 62 | 63 | val value: Boolean 64 | get() = trueButton.isSelected 65 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/KeyValuePropertiesPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.util.ui.ValidatingTableEditor 20 | import us.jimschubert.intellij.openapitools.Message 21 | import java.awt.BorderLayout 22 | import javax.swing.JPanel 23 | 24 | internal class KeyValuePropertiesPanel(key: String = "Key", val value: String = "Value") : JPanel(BorderLayout()) { 25 | private val _items: MutableList = mutableListOf() 26 | private val _editor: ValidatingTableEditor 27 | 28 | val items: List 29 | get() = _items.toList() 30 | 31 | init { 32 | _editor = object : ValidatingTableEditor() { 33 | override fun createItem(): SimpleKeyValueItem? = SimpleKeyValueItem("", "") 34 | 35 | override fun cloneOf(item: SimpleKeyValueItem?): SimpleKeyValueItem? = 36 | SimpleKeyValueItem(item?.key ?: "", item?.value ?: "") 37 | 38 | override fun validate(item: SimpleKeyValueItem?): String? { 39 | when { 40 | item == null -> { 41 | return Message of "panel.key-value-properties.invalid-empty" 42 | } 43 | item.key == "" -> { 44 | return Message of "panel.key-value-properties.invalid-key" 45 | } 46 | item.value == "" -> { 47 | return Message of "panel.key-value-properties.invalid-value" 48 | } 49 | } 50 | 51 | return null 52 | } 53 | } 54 | 55 | _editor.setModel( 56 | arrayOf( 57 | ValidatingKeyColumnInfo(key, PlainTextCellEditor()), 58 | ValidatingValueColumnInfo(value, PlainTextCellEditor()) 59 | ), 60 | _items 61 | ) 62 | 63 | add(_editor.contentPane, BorderLayout.CENTER) 64 | } 65 | 66 | fun setEmptyMessage(value: String) { 67 | _editor.emptyText.text = value 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/LanguageOptionsPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.icons.AllIcons 20 | import com.intellij.ui.components.JBLabel 21 | import com.intellij.util.ui.FormBuilder 22 | import org.openapitools.codegen.CodegenConfig 23 | import javax.swing.JComponent 24 | import javax.swing.JPanel 25 | import javax.swing.JTextField 26 | 27 | internal class LanguageOptionsPanel(val language: CodegenConfig) { 28 | companion object { 29 | private val generatorInfoPanel = us.jimschubert.intellij.openapitools.ui.GeneratorInfoPanel().component 30 | val empty: JPanel 31 | get() = generatorInfoPanel 32 | } 33 | 34 | private var _component: JPanel? = null 35 | val component: JPanel 36 | get() = _component ?: empty 37 | 38 | private var optionTrackers: MutableList = mutableListOf() 39 | val userOptions: MutableList 40 | get() = optionTrackers 41 | 42 | init { 43 | // TODO: Wrap JComponent instances to required fields 44 | 45 | var form = FormBuilder.createFormBuilder() 46 | .setAlignLabelOnRight(false) 47 | .setVerticalGap(4) 48 | 49 | language.cliOptions().forEachIndexed { _, cliOption -> 50 | val enums: Map = cliOption.enum ?: mapOf() 51 | val optionComponent: JComponent = when { 52 | // TODO: Support any other cliOption types? 53 | cliOption.type == "string" && enums.isEmpty() -> { 54 | val text = JTextField(cliOption.default) 55 | 56 | optionTrackers.add(UserOptionInput(cliOption) { text.text }) 57 | 58 | text 59 | } 60 | cliOption.type == "string" && enums.isNotEmpty() -> { 61 | val options = 62 | enums.map { us.jimschubert.intellij.openapitools.ui.CliConstrainedOption.fromKvp(it) }.toList() 63 | val panel = 64 | us.jimschubert.intellij.openapitools.ui.ConstrainedOptionsPanel(options, cliOption.default) 65 | 66 | optionTrackers.add(UserOptionInput(cliOption) { panel.value }) 67 | 68 | panel 69 | } 70 | cliOption.type == "boolean" -> { 71 | val panel = JTrueFalseRadioPanel(cliOption.default!!.toBoolean()) 72 | 73 | optionTrackers.add(UserOptionInput(cliOption) { panel.value.toString() }) 74 | 75 | panel 76 | } 77 | else -> { 78 | println("${cliOption.opt} is type ${cliOption.type}") 79 | val text = JTextField(cliOption.default) 80 | 81 | optionTrackers.add(UserOptionInput(cliOption) { text.text }) 82 | 83 | text 84 | } 85 | } 86 | 87 | val label = JBLabel(cliOption.opt) 88 | if (cliOption.description != null) { 89 | label.icon = AllIcons.Toolwindows.Documentation 90 | label.toolTipText = cliOption.description 91 | } 92 | 93 | form = form.addLabeledComponent(label, optionComponent) 94 | 95 | _component = form.panel 96 | } 97 | 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/LogoLabel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.openapi.util.IconLoader 20 | import com.intellij.ui.components.JBLabel 21 | import com.intellij.util.ui.UIUtil 22 | import javax.swing.Icon 23 | 24 | class LogoLabel : JBLabel() { 25 | 26 | /** 27 | * Returns the graphic image (glyph, icon) that the label displays. 28 | * 29 | * @return an Icon 30 | * @see .setIcon 31 | */ 32 | override fun getIcon(): Icon { 33 | return when { 34 | UIUtil.isUnderDarcula() -> dark 35 | else -> light 36 | } 37 | } 38 | 39 | companion object { 40 | private val light = IconLoader.getIcon("/images/openapi-generator.png") 41 | private val dark = IconLoader.getIcon("/images/openapi-generator_dark.png") 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/PlainTextCellEditor.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.util.ui.AbstractTableCellEditor 20 | import java.awt.Component 21 | import javax.swing.JTable 22 | import javax.swing.JTextField 23 | 24 | internal class PlainTextCellEditor : AbstractTableCellEditor() { 25 | private var component: JTextField 26 | 27 | init { 28 | component = JTextField() 29 | } 30 | 31 | override fun getTableCellEditorComponent( 32 | table: JTable?, 33 | value: Any?, 34 | isSelected: Boolean, 35 | row: Int, 36 | column: Int 37 | ): Component? { 38 | component = JTextField() 39 | component.text = value?.toString() ?: "" 40 | return component 41 | } 42 | 43 | override fun getCellEditorValue(): Any? = component.text 44 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/PropertiesPanelExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | internal fun KeyValuePropertiesPanel.itemsAsMap(): MutableMap = 20 | mutableMapOf(* items.map { it.key to it.value }.toTypedArray()) 21 | 22 | internal fun ValuePropertiesPanel.itemsAsSet(): MutableSet = 23 | mutableSetOf(* items.map { it.value }.toTypedArray()) 24 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/SimpleKeyValueItem.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | internal open class SimpleKeyValueItem(open var key: String, override var value: String) : SimpleValueItem(value) 20 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/SimpleValueItem.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | internal open class SimpleValueItem(open var value: String) -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/UserOptionInput.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import org.openapitools.codegen.CliOption 20 | 21 | data class UserOptionInput(val cliOption: CliOption, val userInput: () -> String?) 22 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/Validatable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.openapi.ui.ValidationInfo 20 | 21 | interface Validatable { 22 | fun doValidate(): ValidationInfo? { 23 | return null 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/ValidatingKeyColumnInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.util.ui.ColumnInfo 20 | import com.intellij.util.ui.ValidatingTableEditor 21 | import javax.swing.JTextField 22 | import javax.swing.table.TableCellEditor 23 | 24 | internal class ValidatingKeyColumnInfo( 25 | columnName: String, 26 | private val editor: TableCellEditor? = null 27 | ) : ColumnInfo(columnName), ValidatingTableEditor.RowHeightProvider { 28 | override fun valueOf(item: T): String? { 29 | return item.key 30 | } 31 | 32 | override fun setValue(item: T, value: Any?) { 33 | item.key = value.toString() 34 | } 35 | 36 | override fun isCellEditable(item: T): Boolean { 37 | return editor != null 38 | } 39 | 40 | override fun getEditor(item: T): TableCellEditor? { 41 | return editor 42 | } 43 | 44 | override fun getRowHeight(): Int { 45 | return JTextField().preferredSize.height + 1 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/ValidatingValueColumnInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.util.ui.ColumnInfo 20 | import com.intellij.util.ui.ValidatingTableEditor 21 | import javax.swing.JTextField 22 | import javax.swing.table.TableCellEditor 23 | 24 | internal class ValidatingValueColumnInfo( 25 | columnName: String, 26 | private val editor: TableCellEditor? = null 27 | ) : ColumnInfo(columnName), ValidatingTableEditor.RowHeightProvider { 28 | override fun valueOf(item: T): String? { 29 | return item.value 30 | } 31 | 32 | override fun setValue(item: T, value: Any?) { 33 | item.value = value.toString() 34 | } 35 | 36 | override fun isCellEditable(item: T): Boolean { 37 | return editor != null 38 | } 39 | 40 | override fun getEditor(item: T): TableCellEditor? { 41 | return editor 42 | } 43 | 44 | override fun getRowHeight(): Int { 45 | return JTextField().preferredSize.height + 1 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/us/jimschubert/intellij/openapitools/ui/ValuePropertiesPanel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Jim Schubert 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 13 | * or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | package us.jimschubert.intellij.openapitools.ui 18 | 19 | import com.intellij.util.ui.ValidatingTableEditor 20 | import us.jimschubert.intellij.openapitools.Message 21 | import java.awt.BorderLayout 22 | import javax.swing.JPanel 23 | 24 | internal class ValuePropertiesPanel(header: String = "Value") : JPanel(BorderLayout()) { 25 | private val _items: MutableList = mutableListOf() 26 | private val _editor: ValidatingTableEditor 27 | 28 | val items: List 29 | get() = _items.toList() 30 | 31 | init { 32 | _editor = object : ValidatingTableEditor() { 33 | override fun createItem(): SimpleValueItem? = SimpleValueItem("") 34 | 35 | override fun cloneOf(item: SimpleValueItem?): SimpleValueItem? = SimpleValueItem(item?.value ?: "") 36 | 37 | override fun validate(item: SimpleValueItem?): String? { 38 | when { 39 | item == null -> { 40 | return Message of "panel.value-properties.invalid-empty" 41 | } 42 | item.value == "" -> { 43 | return Message of "panel.value-properties.invalid-value" 44 | } 45 | } 46 | 47 | return null 48 | } 49 | } 50 | 51 | _editor.setModel( 52 | arrayOf( 53 | ValidatingValueColumnInfo(header, PlainTextCellEditor()) 54 | ), 55 | _items 56 | ) 57 | 58 | add(_editor.contentPane, BorderLayout.CENTER) 59 | } 60 | 61 | fun setEmptyMessage(value: String) { 62 | _editor.emptyText.text = value 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | main.kotlin.com.jimschubert.intellij.swaggercodegen 19 | OpenAPI Generator 20 | 4.3.1-p1 21 | Jim Schubert 22 | 23 | OpenAPI Generator 25 |
26 | GitHub  27 | Issues 28 |

29 | The OpenAPI Generator plugin allows you to generate client, server, or documentation code 30 | from your OpenAPI specifications within your IDE. 31 |

32 | GitHub Sponsors: jimschubert 33 | ]]>
34 | 35 | 37 |
4.3.1-p1
38 |
39 |
    40 |
  • Sets earliest supported JetBrains products to version 193.4778.7
  • 41 |
42 |
43 |
4.3.1-p0
44 |
45 |
    46 |
  • Bump OpenAPI Generator version to 4.3.1
  • 47 |
48 |
49 |
4.3.0-p0
50 |
51 |
    52 |
  • Bump OpenAPI Generator version to 4.3.0
  • 53 |
  • Skips plugin versions 4.1.0-4.2.0 to align with OpenAPI Generator versioning, appends semantic plugin revision
  • 54 |
55 |
56 |
4.0.0
57 |
58 |
    59 |
  • Bump OpenAPI Generator version to 4.2.3
  • 60 |
61 |
62 |
3.0.0
63 |
64 |
    65 |
  • Bump OpenAPI Generator version to 4.0.0
  • 66 |
67 |
68 | 69 | ]]> 70 |
71 | 72 | 73 | 74 | 75 | 77 | com.intellij.modules.lang 78 | com.intellij.modules.platform 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 96 | 97 | 98 | 99 | 100 |
101 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/images/openapi-generator-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimschubert/intellij-openapi-generator/f673b545da3512eeb510a1997044314e0be6efc0/src/main/resources/images/openapi-generator-outline.png -------------------------------------------------------------------------------- /src/main/resources/images/openapi-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimschubert/intellij-openapi-generator/f673b545da3512eeb510a1997044314e0be6efc0/src/main/resources/images/openapi-generator.png -------------------------------------------------------------------------------- /src/main/resources/images/openapi-generator_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimschubert/intellij-openapi-generator/f673b545da3512eeb510a1997044314e0be6efc0/src/main/resources/images/openapi-generator_dark.png -------------------------------------------------------------------------------- /src/main/resources/messages/GeneratorBundle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2020 Jim Schubert 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 13 | # or implied. See the License for the specific language governing 14 | # permissions and limitations under the License. 15 | # 16 | 17 | dialog.generate.title=Generate code from OpenAPI Document 18 | dialog.generate.ok=Generate 19 | dialog.generate.cancel=Cancel 20 | 21 | dialog.generate.output-browse.title=Select output directory 22 | 23 | panel.primitive-types.value-column=Primitive Type 24 | panel.primitive-types.empty-message=No Primitives 25 | 26 | panel.type-mappings.key-column=Codegen Type 27 | panel.type-mappings.value-column=Generated Type 28 | panel.type-mappings.empty-message=No Type Mappings 29 | 30 | panel.import-mappings.key-column=Type 31 | panel.import-mappings.value-column=Import 32 | panel.import-mappings.empty-message=No Import Mappings 33 | 34 | panel.additional-properties.key-column=Name 35 | panel.additional-properties.empty-message=No Additional Properties 36 | 37 | panel.instantiation-types.key-column=Codegen Type 38 | panel.instantiation-types.value-column=Instantiated Type 39 | panel.instantiation-types.empty-message=No Instantiated Types 40 | 41 | panel.value-properties.invalid-empty=Item is empty 42 | panel.value-properties.invalid-value=Invalid value 43 | 44 | panel.key-value-properties.invalid-empty=Item is empty 45 | panel.key-value-properties.invalid-key=Invalid key 46 | panel.key-value-properties.invalid-value=Invalid value 47 | 48 | panel.general-settings.browse.template-dir=Select template directory 49 | panel.general-settings.browse.config-file=Select configuration file 50 | 51 | notification.generation.success.title=[{0}] Generation succeeded. 52 | notification.generation.success.content=Generated: {0}.
{1} 53 | 54 | notification.generation.failure.title=[{0}] Generation failed. 55 | -------------------------------------------------------------------------------- /src/test/resources/sample.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimschubert/intellij-openapi-generator/f673b545da3512eeb510a1997044314e0be6efc0/src/test/resources/sample.yaml --------------------------------------------------------------------------------