Skip to content

Commit bacdd41

Browse files
authored
feat(configuration): support npm scripts run configuration (#43)
* feat(configuration): support npm scripts run configuration * chore: upgrade version to 1.5.0 * fix(ci): gradlew check failed
1 parent 8c17acf commit bacdd41

File tree

7 files changed

+164
-27
lines changed

7 files changed

+164
-27
lines changed

build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ plugins {
1919
id("org.jlleitschuh.gradle.ktlint") version "10.0.0"
2020
}
2121

22+
ktlint {
23+
// See https://github.com/pinterest/ktlint/issues/527
24+
disabledRules.add("import-ordering")
25+
}
26+
2227
group = properties("pluginGroup")
2328
version = properties("pluginVersion")
2429

detekt-config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ formatting:
55
Indentation:
66
continuationIndentSize: 8
77
ParameterListWrapping:
8-
indentSize: 8
8+
indentSize: 4
99
style:
1010
ReturnCount:
1111
max: 42

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
pluginGroup = no.eirikb.avatest
55
pluginName = AvaJavaScriptTestRunnerRunConfigurationGenerator
6-
pluginVersion = 1.4.1
6+
pluginVersion = 1.5.0
77
pluginSinceBuild = 202
88
pluginUntilBuild = 999.*
99
# Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl

src/main/kotlin/no/eirikb/avatest/actions/AvaJavaScriptTestRunnerRunConfigurationGenerator.kt

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import com.intellij.execution.RunnerAndConfigurationSettings
66
import com.intellij.execution.configurations.ConfigurationFactory
77
import com.intellij.execution.executors.DefaultRunExecutor
88
import com.intellij.execution.runners.ExecutionUtil
9+
import com.intellij.lang.javascript.buildTools.npm.PackageJsonUtil
10+
import com.intellij.lang.javascript.buildTools.npm.rc.NpmConfigurationType
11+
import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunConfiguration
12+
import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunSettings
913
import com.intellij.lang.javascript.psi.JSCallExpression
1014
import com.intellij.lang.javascript.psi.JSExpression
1115
import com.intellij.lang.javascript.psi.JSLiteralExpression
@@ -17,6 +21,8 @@ import com.intellij.openapi.actionSystem.AnActionEvent
1721
import com.intellij.openapi.actionSystem.CommonDataKeys
1822
import com.intellij.openapi.actionSystem.PlatformDataKeys
1923
import com.intellij.openapi.fileEditor.FileDocumentManager
24+
import com.intellij.openapi.project.Project
25+
import com.intellij.openapi.vfs.VirtualFile
2026
import com.intellij.openapi.wm.ToolWindowId
2127
import com.intellij.psi.PsiElement
2228
import com.jetbrains.nodejs.run.NodeJsRunConfiguration
@@ -34,6 +40,22 @@ fun JSCallExpression.isTest(): Boolean {
3440
return false
3541
}
3642

43+
fun getConfigurationName(fileName: String, testName: String?): String {
44+
return if (testName != null) {
45+
"ava $fileName $testName"
46+
} else {
47+
"ava $fileName"
48+
}
49+
}
50+
51+
fun getRunArguments(relPath: String, testName: String?): String {
52+
return if (testName != null) {
53+
"-m \"$testName\" -v $relPath"
54+
} else {
55+
"-v $relPath"
56+
}
57+
}
58+
3759
class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() {
3860
companion object {
3961
fun performAction(e: AnActionEvent, debug: Boolean = false, offset: Int? = null) {
@@ -58,30 +80,16 @@ class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() {
5880
val fileName = Paths.get(filePath).fileName.toString()
5981
val basePath = project.basePath
6082
val relPath = if (basePath == null) fileName else currentFile.path.substring(basePath.length + 1)
61-
val node: NodeJsRunConfiguration? =
62-
NodeJsRunConfiguration.getDefaultRunConfiguration(project)?.clone() as NodeJsRunConfiguration?
63-
if (node == null) {
64-
writeError("NodeJS run configuration type not found")
65-
return
83+
84+
val configuration = if (AppSettingsState.selectedCommand) {
85+
this.createNodeJsRunConfiguration(project, fileName, relPath, testName)
86+
} else {
87+
this.createNPMRunConfiguration(project, currentFile, fileName, relPath, testName)
6688
}
67-
val factory: ConfigurationFactory? = node.factory
68-
if (factory == null) {
69-
writeError("Factory not found")
89+
90+
if (configuration == null) {
7091
return
7192
}
72-
node.workingDirectory = basePath
73-
node.inputPath = AppSettingsState.inputPath
74-
if (testName != null) {
75-
node.name = "ava $fileName $testName"
76-
node.applicationParameters = "-m \"$testName\" -v $relPath"
77-
} else {
78-
node.name = "ava $fileName"
79-
node.applicationParameters = "-v $relPath"
80-
}
81-
val runManager = RunManager.getInstance(project)
82-
val configuration: RunnerAndConfigurationSettings = runManager.createConfiguration(node, factory)
83-
runManager.addConfiguration(configuration)
84-
runManager.selectedConfiguration = configuration
8593

8694
if (debug) {
8795
val executor = ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG)
@@ -125,6 +133,70 @@ class AvaJavaScriptTestRunnerRunConfigurationGenerator : AnAction() {
125133
}
126134
return getTestName(element.parent)
127135
}
136+
137+
private fun createNodeJsRunConfiguration(
138+
project: Project,
139+
fileName: String,
140+
relPath: String,
141+
testName: String?,
142+
): RunnerAndConfigurationSettings? {
143+
val node: NodeJsRunConfiguration? =
144+
NodeJsRunConfiguration.getDefaultRunConfiguration(project)?.clone() as NodeJsRunConfiguration?
145+
if (node == null) {
146+
writeError("NodeJS run configuration type not found")
147+
return null
148+
}
149+
val factory: ConfigurationFactory? = node.factory
150+
if (factory == null) {
151+
writeError("Factory not found")
152+
return null
153+
}
154+
node.workingDirectory = project.basePath
155+
node.inputPath = AppSettingsState.inputPath
156+
node.name = getConfigurationName(fileName, testName)
157+
node.applicationParameters = getRunArguments(relPath, testName)
158+
159+
val runManager = RunManager.getInstance(project)
160+
val configuration: RunnerAndConfigurationSettings = runManager.createConfiguration(node, factory)
161+
runManager.addConfiguration(configuration)
162+
runManager.selectedConfiguration = configuration
163+
164+
return configuration
165+
}
166+
167+
private fun createNPMRunConfiguration(
168+
project: Project,
169+
currentFile: VirtualFile,
170+
fileName: String,
171+
relPath: String,
172+
testName: String?,
173+
): RunnerAndConfigurationSettings? {
174+
val npmRunSettingsBuilder = NpmRunSettings.builder()
175+
val packageJsonPath = PackageJsonUtil.findUpPackageJson(currentFile)?.path
176+
177+
if (packageJsonPath == null) {
178+
return null
179+
}
180+
181+
npmRunSettingsBuilder.setPackageJsonPath(packageJsonPath)
182+
183+
npmRunSettingsBuilder.setArguments(getRunArguments(relPath, testName))
184+
npmRunSettingsBuilder.setScriptNames(listOf(AppSettingsState.npmScriptsText))
185+
186+
val npmRunConfiguration = NpmRunConfiguration(
187+
project,
188+
NpmConfigurationType.getInstance(),
189+
getConfigurationName(fileName, testName)
190+
)
191+
npmRunConfiguration.runSettings = npmRunSettingsBuilder.build()
192+
193+
val runManager = RunManager.getInstance(project)
194+
val configuration = runManager.createConfiguration(npmRunConfiguration, NpmConfigurationType.getInstance())
195+
runManager.addConfiguration(configuration)
196+
runManager.selectedConfiguration = configuration
197+
198+
return configuration
199+
}
128200
}
129201

130202
override fun actionPerformed(e: AnActionEvent) {

src/main/kotlin/no/eirikb/avatest/settings/AppSettingsComponent.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package no.eirikb.avatest.settings
22

3-
import com.intellij.ui.components.JBLabel
3+
import com.intellij.openapi.ui.ComboBox
4+
import com.intellij.ui.components.JBRadioButton
45
import com.intellij.ui.components.JBTextField
6+
import com.intellij.ui.components.JBLabel
57
import com.intellij.util.ui.FormBuilder
8+
import javax.swing.ButtonGroup
69
import javax.swing.JPanel
710

11+
const val MARGIN_TOP = 10
12+
const val MARGIN_BOTTOM = 8
13+
814
class AppSettingsComponent {
915
val panel: JPanel
1016
val myInputPathText = JBTextField()
@@ -14,9 +20,48 @@ class AppSettingsComponent {
1420
myInputPathText.text = newText
1521
}
1622

23+
private val npmPackageJSONPathInput = ComboBox<String>().apply {
24+
isEditable = false
25+
selectedItem = ""
26+
}
27+
28+
private val npmScriptsInput = JBTextField()
29+
var npmScriptsText: String
30+
get() = npmScriptsInput.text
31+
set(text) {
32+
npmScriptsInput.text = text
33+
}
34+
35+
private val commandModelRadioButton = JBRadioButton("Command Model")
36+
private val npmModelRadioButton = JBRadioButton("NPM Model")
37+
var selectedCommand: Boolean
38+
get() = commandModelRadioButton.isSelected
39+
set(isCommand) {
40+
commandModelRadioButton.isSelected = isCommand
41+
npmModelRadioButton.isSelected = !isCommand
42+
43+
myInputPathText.isEnabled = isCommand
44+
npmPackageJSONPathInput.isEnabled = !isCommand
45+
npmScriptsInput.isEnabled = !isCommand
46+
}
47+
1748
init {
49+
commandModelRadioButton.addChangeListener {
50+
selectedCommand = commandModelRadioButton.isSelected
51+
}
52+
53+
ButtonGroup().apply {
54+
add(commandModelRadioButton)
55+
add(npmModelRadioButton)
56+
}
57+
1858
panel = FormBuilder.createFormBuilder()
59+
.addComponent(commandModelRadioButton)
1960
.addLabeledComponent(JBLabel("Enter path to AVA: "), myInputPathText, 1, false)
61+
.addSeparator(MARGIN_TOP)
62+
.addVerticalGap(MARGIN_BOTTOM)
63+
.addComponent(npmModelRadioButton)
64+
.addLabeledComponent(JBLabel("npm Scripts: "), npmScriptsInput, 1, false)
2065
.addComponentFillVertically(JPanel(), 0)
2166
.panel
2267
}

src/main/kotlin/no/eirikb/avatest/settings/AppSettingsConfigurable.kt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,30 @@ class AppSettingsConfigurable : Configurable {
1818
}
1919

2020
override fun isModified(): Boolean {
21-
var modified = mySettingsComponent!!.inputPathText != AppSettingsState.inputPath
22-
modified = modified or (mySettingsComponent!!.inputPathText != AppSettingsState.inputPath)
23-
return modified
21+
var modifiedInputPath = mySettingsComponent!!.inputPathText != AppSettingsState.inputPath
22+
modifiedInputPath = modifiedInputPath or (mySettingsComponent!!.inputPathText != AppSettingsState.inputPath)
23+
24+
var modifiedSelectedModel = mySettingsComponent!!.selectedCommand != AppSettingsState.selectedCommand
25+
modifiedSelectedModel =
26+
modifiedSelectedModel or (mySettingsComponent!!.selectedCommand != AppSettingsState.selectedCommand)
27+
28+
var modifiedNPMScriptsText = mySettingsComponent!!.npmScriptsText != AppSettingsState.npmScriptsText
29+
modifiedNPMScriptsText =
30+
modifiedNPMScriptsText or (mySettingsComponent!!.npmScriptsText != AppSettingsState.npmScriptsText)
31+
32+
return modifiedInputPath || modifiedSelectedModel || modifiedNPMScriptsText
2433
}
2534

2635
override fun apply() {
2736
AppSettingsState.inputPath = mySettingsComponent!!.inputPathText
37+
AppSettingsState.selectedCommand = mySettingsComponent!!.selectedCommand
38+
AppSettingsState.npmScriptsText = mySettingsComponent!!.npmScriptsText
2839
}
2940

3041
override fun reset() {
3142
mySettingsComponent!!.inputPathText = AppSettingsState.inputPath
43+
mySettingsComponent!!.selectedCommand = AppSettingsState.selectedCommand
44+
mySettingsComponent!!.npmScriptsText = AppSettingsState.npmScriptsText
3245
}
3346

3447
override fun disposeUIResources() {

src/main/kotlin/no/eirikb/avatest/settings/AppSettingsState.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.intellij.util.xmlb.XmlSerializerUtil
88
@State(name = "no.eirikb.avatest.settings.AppSettingsState", storages = [Storage("SdkSettingsPlugin.xml")])
99
object AppSettingsState : PersistentStateComponent<AppSettingsState?> {
1010
var inputPath = "node_modules/ava/cli.js"
11+
var selectedCommand = true
12+
var npmScriptsText = ""
1113

1214
override fun getState(): AppSettingsState {
1315
return this

0 commit comments

Comments
 (0)