diff --git a/build.gradle.kts b/build.gradle.kts index 21e7d9b..670487b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,11 @@ plugins { id("org.jlleitschuh.gradle.ktlint") version "10.0.0" } +ktlint { + // See https://github.com/pinterest/ktlint/issues/527 + disabledRules.add("import-ordering") +} + group = properties("pluginGroup") version = properties("pluginVersion") diff --git a/detekt-config.yml b/detekt-config.yml index d964eb8..d870cb6 100644 --- a/detekt-config.yml +++ b/detekt-config.yml @@ -5,7 +5,7 @@ formatting: Indentation: continuationIndentSize: 8 ParameterListWrapping: - indentSize: 8 + indentSize: 4 style: ReturnCount: max: 42 diff --git a/gradle.properties b/gradle.properties index 64c1365..cb0741a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ pluginGroup = no.eirikb.avatest pluginName = AvaJavaScriptTestRunnerRunConfigurationGenerator -pluginVersion = 1.4.1 +pluginVersion = 1.5.0 pluginSinceBuild = 202 pluginUntilBuild = 999.* # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl diff --git a/src/main/kotlin/no/eirikb/avatest/actions/AvaJavaScriptTestRunnerRunConfigurationGenerator.kt b/src/main/kotlin/no/eirikb/avatest/actions/AvaJavaScriptTestRunnerRunConfigurationGenerator.kt index d69b08f..2d844b7 100644 --- a/src/main/kotlin/no/eirikb/avatest/actions/AvaJavaScriptTestRunnerRunConfigurationGenerator.kt +++ b/src/main/kotlin/no/eirikb/avatest/actions/AvaJavaScriptTestRunnerRunConfigurationGenerator.kt @@ -6,6 +6,10 @@ import com.intellij.execution.RunnerAndConfigurationSettings import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.executors.DefaultRunExecutor import com.intellij.execution.runners.ExecutionUtil +import com.intellij.lang.javascript.buildTools.npm.PackageJsonUtil +import com.intellij.lang.javascript.buildTools.npm.rc.NpmConfigurationType +import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunConfiguration +import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunSettings import com.intellij.lang.javascript.psi.JSCallExpression import com.intellij.lang.javascript.psi.JSExpression import com.intellij.lang.javascript.psi.JSLiteralExpression @@ -17,6 +21,8 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.wm.ToolWindowId import com.intellij.psi.PsiElement import com.jetbrains.nodejs.run.NodeJsRunConfiguration @@ -34,6 +40,22 @@ fun JSCallExpression.isTest(): Boolean { return false } +fun getConfigurationName(fileName: String, testName: String?): String { + return if (testName != null) { + "ava $fileName $testName" + } else { + "ava $fileName" + } +} + +fun getRunArguments(relPath: String, testName: String?): String { + return if (testName != null) { + "-m \"$testName\" -v $relPath" + } else { + "-v $relPath" + } +} + class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() { companion object { fun performAction(e: AnActionEvent, debug: Boolean = false, offset: Int? = null) { @@ -58,30 +80,16 @@ class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() { val fileName = Paths.get(filePath).fileName.toString() val basePath = project.basePath val relPath = if (basePath == null) fileName else currentFile.path.substring(basePath.length + 1) - val node: NodeJsRunConfiguration? = - NodeJsRunConfiguration.getDefaultRunConfiguration(project)?.clone() as NodeJsRunConfiguration? - if (node == null) { - writeError("NodeJS run configuration type not found") - return + + val configuration = if (AppSettingsState.selectedCommand) { + this.createNodeJsRunConfiguration(project, fileName, relPath, testName) + } else { + this.createNPMRunConfiguration(project, currentFile, fileName, relPath, testName) } - val factory: ConfigurationFactory? = node.factory - if (factory == null) { - writeError("Factory not found") + + if (configuration == null) { return } - node.workingDirectory = basePath - node.inputPath = AppSettingsState.inputPath - if (testName != null) { - node.name = "ava $fileName $testName" - node.applicationParameters = "-m \"$testName\" -v $relPath" - } else { - node.name = "ava $fileName" - node.applicationParameters = "-v $relPath" - } - val runManager = RunManager.getInstance(project) - val configuration: RunnerAndConfigurationSettings = runManager.createConfiguration(node, factory) - runManager.addConfiguration(configuration) - runManager.selectedConfiguration = configuration if (debug) { val executor = ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG) @@ -125,6 +133,70 @@ class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() { } return getTestName(element.parent) } + + private fun createNodeJsRunConfiguration( + project: Project, + fileName: String, + relPath: String, + testName: String?, + ): RunnerAndConfigurationSettings? { + val node: NodeJsRunConfiguration? = + NodeJsRunConfiguration.getDefaultRunConfiguration(project)?.clone() as NodeJsRunConfiguration? + if (node == null) { + writeError("NodeJS run configuration type not found") + return null + } + val factory: ConfigurationFactory? = node.factory + if (factory == null) { + writeError("Factory not found") + return null + } + node.workingDirectory = project.basePath + node.inputPath = AppSettingsState.inputPath + node.name = getConfigurationName(fileName, testName) + node.applicationParameters = getRunArguments(relPath, testName) + + val runManager = RunManager.getInstance(project) + val configuration: RunnerAndConfigurationSettings = runManager.createConfiguration(node, factory) + runManager.addConfiguration(configuration) + runManager.selectedConfiguration = configuration + + return configuration + } + + private fun createNPMRunConfiguration( + project: Project, + currentFile: VirtualFile, + fileName: String, + relPath: String, + testName: String?, + ): RunnerAndConfigurationSettings? { + val npmRunSettingsBuilder = NpmRunSettings.builder() + val packageJsonPath = PackageJsonUtil.findUpPackageJson(currentFile)?.path + + if (packageJsonPath == null) { + return null + } + + npmRunSettingsBuilder.setPackageJsonPath(packageJsonPath) + + npmRunSettingsBuilder.setArguments(getRunArguments(relPath, testName)) + npmRunSettingsBuilder.setScriptNames(listOf(AppSettingsState.npmScriptsText)) + + val npmRunConfiguration = NpmRunConfiguration( + project, + NpmConfigurationType.getInstance(), + getConfigurationName(fileName, testName) + ) + npmRunConfiguration.runSettings = npmRunSettingsBuilder.build() + + val runManager = RunManager.getInstance(project) + val configuration = runManager.createConfiguration(npmRunConfiguration, NpmConfigurationType.getInstance()) + runManager.addConfiguration(configuration) + runManager.selectedConfiguration = configuration + + return configuration + } } override fun actionPerformed(e: AnActionEvent) { diff --git a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsComponent.kt b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsComponent.kt index f4a311f..4778e55 100644 --- a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsComponent.kt +++ b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsComponent.kt @@ -1,10 +1,16 @@ package no.eirikb.avatest.settings -import com.intellij.ui.components.JBLabel +import com.intellij.openapi.ui.ComboBox +import com.intellij.ui.components.JBRadioButton import com.intellij.ui.components.JBTextField +import com.intellij.ui.components.JBLabel import com.intellij.util.ui.FormBuilder +import javax.swing.ButtonGroup import javax.swing.JPanel +const val MARGIN_TOP = 10 +const val MARGIN_BOTTOM = 8 + class AppSettingsComponent { val panel: JPanel val myInputPathText = JBTextField() @@ -14,9 +20,48 @@ class AppSettingsComponent { myInputPathText.text = newText } + private val npmPackageJSONPathInput = ComboBox().apply { + isEditable = false + selectedItem = "" + } + + private val npmScriptsInput = JBTextField() + var npmScriptsText: String + get() = npmScriptsInput.text + set(text) { + npmScriptsInput.text = text + } + + private val commandModelRadioButton = JBRadioButton("Command Model") + private val npmModelRadioButton = JBRadioButton("NPM Model") + var selectedCommand: Boolean + get() = commandModelRadioButton.isSelected + set(isCommand) { + commandModelRadioButton.isSelected = isCommand + npmModelRadioButton.isSelected = !isCommand + + myInputPathText.isEnabled = isCommand + npmPackageJSONPathInput.isEnabled = !isCommand + npmScriptsInput.isEnabled = !isCommand + } + init { + commandModelRadioButton.addChangeListener { + selectedCommand = commandModelRadioButton.isSelected + } + + ButtonGroup().apply { + add(commandModelRadioButton) + add(npmModelRadioButton) + } + panel = FormBuilder.createFormBuilder() + .addComponent(commandModelRadioButton) .addLabeledComponent(JBLabel("Enter path to AVA: "), myInputPathText, 1, false) + .addSeparator(MARGIN_TOP) + .addVerticalGap(MARGIN_BOTTOM) + .addComponent(npmModelRadioButton) + .addLabeledComponent(JBLabel("npm Scripts: "), npmScriptsInput, 1, false) .addComponentFillVertically(JPanel(), 0) .panel } diff --git a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsConfigurable.kt b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsConfigurable.kt index 66490ca..ce585ce 100644 --- a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsConfigurable.kt +++ b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsConfigurable.kt @@ -18,17 +18,30 @@ class AppSettingsConfigurable : Configurable { } override fun isModified(): Boolean { - var modified = mySettingsComponent!!.inputPathText != AppSettingsState.inputPath - modified = modified or (mySettingsComponent!!.inputPathText != AppSettingsState.inputPath) - return modified + var modifiedInputPath = mySettingsComponent!!.inputPathText != AppSettingsState.inputPath + modifiedInputPath = modifiedInputPath or (mySettingsComponent!!.inputPathText != AppSettingsState.inputPath) + + var modifiedSelectedModel = mySettingsComponent!!.selectedCommand != AppSettingsState.selectedCommand + modifiedSelectedModel = + modifiedSelectedModel or (mySettingsComponent!!.selectedCommand != AppSettingsState.selectedCommand) + + var modifiedNPMScriptsText = mySettingsComponent!!.npmScriptsText != AppSettingsState.npmScriptsText + modifiedNPMScriptsText = + modifiedNPMScriptsText or (mySettingsComponent!!.npmScriptsText != AppSettingsState.npmScriptsText) + + return modifiedInputPath || modifiedSelectedModel || modifiedNPMScriptsText } override fun apply() { AppSettingsState.inputPath = mySettingsComponent!!.inputPathText + AppSettingsState.selectedCommand = mySettingsComponent!!.selectedCommand + AppSettingsState.npmScriptsText = mySettingsComponent!!.npmScriptsText } override fun reset() { mySettingsComponent!!.inputPathText = AppSettingsState.inputPath + mySettingsComponent!!.selectedCommand = AppSettingsState.selectedCommand + mySettingsComponent!!.npmScriptsText = AppSettingsState.npmScriptsText } override fun disposeUIResources() { diff --git a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsState.kt b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsState.kt index 8f0aa5f..d067c57 100644 --- a/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsState.kt +++ b/src/main/kotlin/no/eirikb/avatest/settings/AppSettingsState.kt @@ -8,6 +8,8 @@ import com.intellij.util.xmlb.XmlSerializerUtil @State(name = "no.eirikb.avatest.settings.AppSettingsState", storages = [Storage("SdkSettingsPlugin.xml")]) object AppSettingsState : PersistentStateComponent { var inputPath = "node_modules/ava/cli.js" + var selectedCommand = true + var npmScriptsText = "" override fun getState(): AppSettingsState { return this