├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── art.png ├── build.gradle ├── gradle.properties ├── preview.png ├── settings.gradle └── src ├── .DS_Store └── main ├── .DS_Store ├── java ├── DslListenerBuilderDialog.form └── DslListenerBuilderDialog.java ├── kotlin ├── .DS_Store ├── action │ └── DSLBuilderAction.kt ├── extensions │ └── UIExtensions.kt ├── model │ └── JModel.kt └── util │ ├── CodeUtil.kt │ └── VelocityEngineUtil.kt └── resources ├── META-INF ├── plugin.xml └── pluginIcon.svg └── template └── DSLBuilder.vm /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | /build/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dsl-api-generator: [(Download)](https://plugins.jetbrains.com/plugin/14386-dsl-api-generator) 2 | IntelliJ IDEA and Android Studio plugin to generate binary compatible and Java interoperable DSL boilerplate 3 | 4 | ![image](https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/master/preview.png) 5 | 6 | # Features 7 | * Interoperable with Java 8 | * Binary and source compatible 9 | * Generates comments 10 | 11 | # How to use? 12 | * Create an empty Kotlin file 13 | * Go to menu "Code" -> "Generate" or use respective keyboard shortcut 14 | * Choose "DSL API Generator" 15 | * Add properties and types 16 | * Add a class name 17 | * Select "Generate" 18 | -------------------------------------------------------------------------------- /art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/art.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.jetbrains.intellij' version '0.4.21' 3 | id 'org.jetbrains.kotlin.jvm' version '1.3.72' 4 | } 5 | 6 | group 'dev.harivignesh' 7 | version '1.0.3' 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" 15 | } 16 | 17 | // See https://github.com/JetBrains/gradle-intellij-plugin/ 18 | intellij { 19 | version '192.7142.36' 20 | type 'IC' 21 | plugins = ['Kotlin', 'android'] 22 | } 23 | runIde { 24 | // Absolute path to installed target 3.5 Android Studio to use as IDE Development Instance 25 | // The "Contents" directory is macOS specific. 26 | // ideDirectory '/Applications/Android Studio.app/Contents' 27 | } 28 | compileKotlin { 29 | kotlinOptions.jvmTarget = "1.8" 30 | } 31 | compileTestKotlin { 32 | kotlinOptions.jvmTarget = "1.8" 33 | } 34 | patchPluginXml { 35 | sinceBuild '192' 36 | untilBuild '203' 37 | changeNotes """ 38 | Release notes
39 | 42 | """ 43 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/preview.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'dsl-api-generator' 2 | 3 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/src/.DS_Store -------------------------------------------------------------------------------- /src/main/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/src/main/.DS_Store -------------------------------------------------------------------------------- /src/main/java/DslListenerBuilderDialog.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 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 |
200 | -------------------------------------------------------------------------------- /src/main/java/DslListenerBuilderDialog.java: -------------------------------------------------------------------------------- 1 | import extensions.UIExtensionsKt; 2 | import model.JModel; 3 | 4 | import javax.swing.*; 5 | import java.awt.*; 6 | import java.awt.event.KeyEvent; 7 | import java.awt.event.WindowAdapter; 8 | import java.awt.event.WindowEvent; 9 | import java.util.*; 10 | import java.util.List; 11 | 12 | public class DslListenerBuilderDialog extends JDialog { 13 | private static final int MAX_ITEM_COUNT = 30; 14 | private JButton mBtnOK; 15 | private JButton mBtnCancel; 16 | private JButton mBtnAdd; 17 | private JButton mBtnDelete; 18 | private JTextField mTFieldActionName; 19 | private JTextField mClassName; 20 | private JPanel contentPane; 21 | private JList mActionListView; 22 | private JComboBox mCBoxValueType; 23 | private JCheckBox pascalCase; 24 | private List mModelListenerList = new ArrayList<>(); 25 | private int[] mSelectedIndexArray; 26 | private DialogListener mDialogListener; 27 | 28 | public DslListenerBuilderDialog() { 29 | setContentPane(contentPane); 30 | setModal(true); 31 | getRootPane().setDefaultButton(mBtnOK); 32 | initView(); 33 | initEvent(); 34 | setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 35 | addWindowListener(new WindowAdapter() { 36 | public void windowClosing(WindowEvent e) { 37 | onCancel(); 38 | } 39 | }); 40 | contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 41 | 42 | } 43 | 44 | private void initView() { 45 | mActionListView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 46 | mCBoxValueType.setEditable(true); 47 | mBtnAdd.setEnabled(true); 48 | mBtnDelete.setEnabled(false); 49 | mModelListenerList.clear(); 50 | } 51 | 52 | private void initEvent() { 53 | mBtnOK.addActionListener(e -> onGenerate()); 54 | mBtnCancel.addActionListener(e -> onCancel()); 55 | mBtnAdd.addActionListener(e -> addProperty()); 56 | mBtnDelete.addActionListener(e -> { 57 | if (mSelectedIndexArray.length > 0 && mSelectedIndexArray.length <= mModelListenerList.size()) { 58 | for (int selectedIndex : mSelectedIndexArray) { 59 | if (selectedIndex >= 0 && selectedIndex <= mModelListenerList.size() - 1 && mModelListenerList.get(selectedIndex) != null) { 60 | mModelListenerList.remove(selectedIndex); 61 | } 62 | } 63 | refreshActionListView(); 64 | } 65 | }); 66 | mActionListView.addListSelectionListener(e -> { 67 | mBtnDelete.setEnabled(true); 68 | mSelectedIndexArray = mActionListView.getSelectedIndices(); 69 | }); 70 | 71 | } 72 | 73 | private void addProperty() { 74 | String actionName = mTFieldActionName.getText(); 75 | Object selectedItem = mCBoxValueType.getSelectedItem(); 76 | String returnValueType = (selectedItem != null) ? selectedItem.toString() : "Unit"; 77 | if (mModelListenerList.size() < MAX_ITEM_COUNT) { 78 | if (!actionName.equals("")) { 79 | mModelListenerList.add(mModelListenerList.size(), new JModel(actionName, returnValueType)); 80 | refreshActionListView(); 81 | } else { 82 | Toolkit.getDefaultToolkit().beep(); 83 | JOptionPane.showMessageDialog(null, "property cannot be empty", "DSL API Generator", JOptionPane.ERROR_MESSAGE); 84 | } 85 | } else { 86 | Toolkit.getDefaultToolkit().beep(); 87 | JOptionPane.showMessageDialog(null, "cannot add more than 30 items", "DSL API Generator", JOptionPane.ERROR_MESSAGE); 88 | } 89 | resetInput(); 90 | } 91 | 92 | private void resetInput() { 93 | mTFieldActionName.setText(""); 94 | } 95 | 96 | private void refreshActionListView() { 97 | mActionListView.setModel(new DefaultComboBoxModel(mModelListenerList.stream().map(it -> 98 | String.format(Locale.US, "%s: %s", it.getPropertyName(), it.getReturnValueType()) 99 | ).toArray())); 100 | mActionListView.setSelectedIndex(0); 101 | } 102 | 103 | 104 | private void onGenerate() { 105 | if (mDialogListener != null) { 106 | LinkedHashMap map = new LinkedHashMap<>(); 107 | for (int index = 0; index < mModelListenerList.size(); index++) { 108 | map.put(mModelListenerList.get(index).getPropertyName(), 109 | String.format(Locale.US, "%s", mModelListenerList.get(index).getReturnValueType())); 110 | } 111 | if (!mClassName.getText().equals("")) { 112 | mDialogListener.onGenerateClicked(map, mClassName.getText(), pascalCase.isSelected()); 113 | dispose(); 114 | } else { 115 | Toolkit.getDefaultToolkit().beep(); 116 | JOptionPane.showMessageDialog(null, "Please enter class name", "DSL API Generator", JOptionPane.ERROR_MESSAGE); 117 | } 118 | } 119 | } 120 | 121 | private void onCancel() { 122 | dispose(); 123 | } 124 | 125 | public static void main(String[] args) { 126 | DslListenerBuilderDialog dialog = new DslListenerBuilderDialog(); 127 | UIExtensionsKt.showDialog(dialog, 550, 600, true, false); 128 | System.exit(0); 129 | } 130 | 131 | public void setDialogListener(DialogListener listener) { 132 | mDialogListener = listener; 133 | } 134 | 135 | public interface DialogListener { 136 | void onGenerateClicked(LinkedHashMap map, String className, Boolean pascalCase); 137 | void onCancelBtnClicked(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/kotlin/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hariofspades/dsl-api-generator/cfd1e4a062405ea719ab9663e2941752a1be11bf/src/main/kotlin/.DS_Store -------------------------------------------------------------------------------- /src/main/kotlin/action/DSLBuilderAction.kt: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import com.intellij.openapi.actionSystem.AnAction 4 | import com.intellij.openapi.actionSystem.AnActionEvent 5 | import com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR 6 | import com.intellij.openapi.editor.Editor 7 | import DslListenerBuilderDialog 8 | import extensions.showDialog 9 | import util.CodeUtil 10 | import util.VelocityEngineUtil 11 | import java.util.LinkedHashMap 12 | 13 | class DSLBuilderAction : AnAction() { 14 | 15 | override fun actionPerformed(event: AnActionEvent) { 16 | VelocityEngineUtil.initialise() 17 | DslListenerBuilderDialog().apply { 18 | setDialogListener(object: DslListenerBuilderDialog.DialogListener { 19 | override fun onCancelBtnClicked() { 20 | // No implementation 21 | } 22 | 23 | override fun onGenerateClicked( 24 | map: LinkedHashMap?, 25 | className: String, 26 | pascalCase: Boolean 27 | ) { 28 | if (!map.isNullOrEmpty()) { 29 | generateCode(map, className, pascalCase, event) 30 | } else print("map is empty") 31 | } 32 | }) 33 | showDialog(height = 600) 34 | } 35 | } 36 | 37 | override fun update(event: AnActionEvent) { 38 | if (event.project == null) { 39 | event.presentation.isEnabled = false 40 | } 41 | val editor: Editor? = event.dataContext.getData(EDITOR) 42 | if (editor == null) { 43 | event.presentation.isEnabled = false 44 | } 45 | event.presentation.isEnabled = true 46 | } 47 | 48 | private fun generateCode( 49 | map: LinkedHashMap, 50 | className: String, 51 | pascalCase: Boolean, 52 | event: AnActionEvent 53 | ) { 54 | val generateCode: String = VelocityEngineUtil.evaluate(map, className, pascalCase) 55 | val editor: Editor? = event.dataContext.getData(EDITOR) 56 | if (editor != null) { 57 | try { 58 | CodeUtil.insert(generateCode, editor) 59 | println("generated code is succeed, generated code is :\n $generateCode") 60 | } catch (e: Exception) { 61 | e.printStackTrace() 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/kotlin/extensions/UIExtensions.kt: -------------------------------------------------------------------------------- 1 | package extensions 2 | 3 | import java.awt.Dialog 4 | import java.awt.Toolkit 5 | 6 | fun Dialog.showDialog(width: Int = 550, height: Int = 400, isInCenter: Boolean = true, isResizable: Boolean = true) { 7 | pack() 8 | this.isResizable = isResizable 9 | setSize(width, height) 10 | if (isInCenter) { 11 | setLocation( 12 | Toolkit.getDefaultToolkit().screenSize.width / 2 - width / 2, 13 | Toolkit.getDefaultToolkit().screenSize.height / 2 - height / 2 14 | ) 15 | } 16 | isVisible = true 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/model/JModel.kt: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | data class JModel(val propertyName: String, val returnValueType: String) -------------------------------------------------------------------------------- /src/main/kotlin/util/CodeUtil.kt: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import com.intellij.openapi.command.WriteCommandAction 4 | import com.intellij.openapi.editor.Editor 5 | import com.intellij.psi.PsiDocumentManager 6 | 7 | object CodeUtil { 8 | 9 | fun insert(generatedCode: String, editor: Editor) { 10 | val document = editor.document 11 | WriteCommandAction.runWriteCommandAction(editor.project) { 12 | document.replaceString(editor.selectionModel.selectionStart, editor.selectionModel.selectionEnd, generatedCode) 13 | editor.project?.let { project -> 14 | PsiDocumentManager.getInstance(project).commitDocument(document) 15 | } 16 | } 17 | editor.selectionModel.removeSelection() 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/kotlin/util/VelocityEngineUtil.kt: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import com.intellij.openapi.util.io.FileUtil 4 | import org.apache.velocity.VelocityContext 5 | import org.apache.velocity.app.VelocityEngine 6 | import org.apache.velocity.runtime.RuntimeConstants 7 | import org.apache.velocity.runtime.log.NullLogChute 8 | import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader 9 | import java.io.StringWriter 10 | import java.util.* 11 | 12 | object VelocityEngineUtil { 13 | 14 | private lateinit var engine: VelocityEngine 15 | 16 | fun initialise() { 17 | val properties = Properties().apply { 18 | setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath") 19 | setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogChute::class.java.name) 20 | setProperty("classpath.resource.loader.class", ClasspathResourceLoader::class.java.name) 21 | } 22 | engine = VelocityEngine(properties).apply { init() } 23 | } 24 | 25 | fun evaluate(map: LinkedHashMap, className: String, pascalCase: Boolean): String { 26 | val velocityTemplate: String = FileUtil.loadTextAndClose(this::class.java.getResourceAsStream("/template/DSLBuilder.vm")) 27 | println("VelocityEngineHelper: velocityTemplate is $velocityTemplate") 28 | val velocityContext = VelocityContext().apply { 29 | put("actionParamMap", map) 30 | put("className", className) 31 | put("pascalCase", pascalCase) 32 | } 33 | val sWriter = StringWriter() 34 | engine.evaluate(velocityContext, sWriter, "", velocityTemplate) 35 | return sWriter.toString() 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | dev.harivignesh.dsl 3 | DSL API Generator 4 | Hari Vignesh J 5 | 6 | 8 | Based on Jake Wharton's blog on "Public API challenges in Kotlin". 9 |
10 |
11 |

Features

12 |
    13 |
  • Interoperable with Java
  • 14 |
  • Binary and source compatible
  • 15 |
  • Generates comments 16 |
17 |

How to use?

18 |
    19 |
  • Create an empty Kotlin file
  • 20 |
  • Go to menu "Code" -> "Generate"
  • 21 |
  • Choose "DSL API Generator"
  • 22 |
  • Add propertys and types
  • 23 |
  • Add a class name
  • 24 |
  • Select "Generate"
  • 25 |
26 |

Output

27 | 28 |
29 | ]]>
30 | 31 | org.jetbrains.android 32 | org.jetbrains.kotlin 33 | 34 | 35 | 36 | 37 | 38 | 39 |
-------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 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 | 38 | 39 | 40 | 41 | { 42 | 43 | { 44 | { 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/resources/template/DSLBuilder.vm: -------------------------------------------------------------------------------- 1 | /** 2 | * Generated using DSL Builder 3 | #foreach(${action} in ${actionParamMap.keySet()}) 4 | * @param ${action} //TODO: define purpose and default value 5 | #end 6 | */ 7 | class ${className} private constructor( 8 | #foreach(${action} in ${actionParamMap.keySet()}) 9 | #if(${velocityCount} == ${actionParamMap.size()}) 10 | val ${action}: ${actionParamMap.get($action)} 11 | #else 12 | val ${action}: ${actionParamMap.get($action)}, 13 | #end 14 | #end 15 | ) { 16 | 17 | override fun equals(other: Any?): Boolean = TODO("implement") 18 | 19 | override fun hashCode(): Int = TODO("implement") 20 | 21 | override fun toString(): String = TODO("implement") 22 | 23 | /** 24 | * A builder for this configuration class 25 | * 26 | * Should be directly used by Java consumers. Kotlin consumers should use DSL function 27 | */ 28 | class Builder { 29 | #foreach(${action} in ${actionParamMap.keySet()}) 30 | @set:JvmSynthetic 31 | var ${action}: ${actionParamMap.get($action)} = TODO("provide a default value") 32 | 33 | #if(${velocityCount} == ${actionParamMap.size()}) 34 | #else 35 | #end 36 | #end 37 | #foreach(${action} in ${actionParamMap.keySet()}) 38 | fun set${action.substring(0,1).toUpperCase()}${action.substring(1)}(${action}: ${actionParamMap.get($action)}) = apply { 39 | this.${action} = ${action} 40 | } 41 | #if(${velocityCount} != ${actionParamMap.size()}) 42 | 43 | #else 44 | #end 45 | #end 46 | 47 | fun build() = ${className}( 48 | #foreach(${action} in ${actionParamMap.keySet()}) 49 | #if(${velocityCount} == ${actionParamMap.size()}) 50 | ${action} 51 | #else 52 | ${action}, 53 | #end 54 | #end 55 | ) 56 | 57 | } 58 | } 59 | 60 | /** 61 | * DSL to create [$className] 62 | */ 63 | @JvmSynthetic 64 | #if(${pascalCase}) 65 | fun ${className}(block: ${className}.Builder.() -> Unit) = ${className}.Builder().apply(block).build() 66 | #else 67 | fun ${className.substring(0,1).toLowerCase()}${className.substring(1)}(block: ${className}.Builder.() -> Unit) = ${className}.Builder().apply(block).build() 68 | #end --------------------------------------------------------------------------------