mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-13 15:52:11 +00:00
Kotlin Ultimate: Support Mocha run configurations for Kotlin sources
#KT-16814 In Progress
This commit is contained in:
10
ultimate/.idea/libraries/javascript_support.xml
generated
Normal file
10
ultimate/.idea/libraries/javascript_support.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="javascript-support">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/ideaSDK/plugins/JavaScriptLanguage/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/ideaSDK/plugins/JavaScriptLanguage/lib" recursive="false" />
|
||||
</library>
|
||||
</component>
|
||||
10
ultimate/.idea/libraries/nodejs_support.xml
generated
Normal file
10
ultimate/.idea/libraries/nodejs_support.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="nodejs-support">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/dependencies/nodejs_plugin/NodeJS/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/dependencies/nodejs_plugin/NodeJS/lib" recursive="false" />
|
||||
</library>
|
||||
</component>
|
||||
@@ -27,6 +27,8 @@
|
||||
<orderEntry type="library" scope="PROVIDED" name="gradle-and-groovy-plugin" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="junit-plugin" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="diagram-support" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="javascript-support" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="nodejs-support" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" name="idea-full" level="project" />
|
||||
<orderEntry type="library" name="protobuf" level="project" />
|
||||
|
||||
5
ultimate/resources/META-INF/kotlin-nodejs.xml
Normal file
5
ultimate/resources/META-INF/kotlin-nodejs.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.nodejs.KotlinMochaRunConfigurationProducer"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -6,4 +6,5 @@
|
||||
<depends optional="true">com.intellij.css</depends>
|
||||
<depends optional="true">com.intellij.jsp</depends>
|
||||
<depends optional="true">com.intellij.diagram</depends>
|
||||
<depends optional="true" config-file="kotlin-nodejs.xml">NodeJS</depends>
|
||||
</idea-plugin>
|
||||
38
ultimate/src/org/jetbrains/kotlin/idea/js/jsModuleUtils.kt
Normal file
38
ultimate/src/org/jetbrains/kotlin/idea/js/jsModuleUtils.kt
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.js
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
private fun addSingleModulePaths(target: Module, result: MutableList<String>) {
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(target) ?: return
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPath?.path)
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPathForTests?.let { "${it.path}/lib" })
|
||||
}
|
||||
|
||||
fun getJsClasspath(module: Module): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
ModuleRootManager.getInstance(module).orderEntries().recursively().forEachModule {
|
||||
addSingleModulePaths(it, result)
|
||||
true
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package org.jetbrains.kotlin.idea.nodejs
|
||||
|
||||
import com.intellij.execution.RunManager
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.execution.configuration.EnvironmentVariablesData
|
||||
import com.intellij.lang.javascript.ecmascript6.TypeScriptUtil
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.SmartHashSet
|
||||
import com.jetbrains.nodejs.mocha.MochaUtil
|
||||
import com.jetbrains.nodejs.mocha.execution.*
|
||||
import com.jetbrains.nodejs.util.NodeJsCoffeeUtil
|
||||
import org.jetbrains.kotlin.idea.js.getJsClasspath
|
||||
import org.jetbrains.kotlin.idea.js.getJsOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import java.io.File
|
||||
|
||||
class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
private data class TestElementInfo(val runSettings: MochaRunSettings, val enclosingTestElement: PsiElement)
|
||||
private data class TestElementPath(val suiteNames: List<String>, val testName: String?)
|
||||
|
||||
// Copied from MochaRunConfigurationProducer.collectMochaTestRoots()
|
||||
private fun collectMochaTestRoots(project: Project): List<VirtualFile> {
|
||||
return RunManager
|
||||
.getInstance(project)
|
||||
.getConfigurationsList(MochaConfigurationType.getInstance())
|
||||
.filterIsInstance<MochaRunConfiguration>()
|
||||
.mapNotNullTo(SmartList<VirtualFile>()) { configuration ->
|
||||
val settings = configuration.runSettings
|
||||
val path = when (settings.testKind) {
|
||||
MochaTestKind.DIRECTORY -> settings.testDirPath
|
||||
MochaTestKind.TEST_FILE,
|
||||
MochaTestKind.SUITE,
|
||||
MochaTestKind.TEST -> settings.testFilePath
|
||||
else -> null
|
||||
}
|
||||
if (path.isNullOrBlank()) return@mapNotNullTo null
|
||||
LocalFileSystem.getInstance().findFileByPath(path!!)
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from MochaRunConfigurationProducer.isActiveFor()
|
||||
private fun isActiveFor(element: PsiElement, context: ConfigurationContext): Boolean {
|
||||
val file = PsiUtilCore.getVirtualFile(element) ?: return false
|
||||
if (isTestRunnerPackageAvailableFor(element.project, file)) return true
|
||||
|
||||
if (context.getOriginalConfiguration(MochaConfigurationType.getInstance()) is MochaRunConfiguration) return true
|
||||
|
||||
val roots = collectMochaTestRoots(element.project)
|
||||
if (roots.isEmpty()) return false
|
||||
|
||||
val dirs = SmartHashSet<VirtualFile>()
|
||||
for (root in roots) {
|
||||
if (root.isDirectory) {
|
||||
dirs.add(root)
|
||||
}
|
||||
else if (root == file) return true
|
||||
}
|
||||
return VfsUtilCore.isUnder(file, dirs)
|
||||
}
|
||||
|
||||
private fun createSuiteOrTestData(element: PsiElement): TestElementPath? {
|
||||
val declaration = element.getNonStrictParentOfType<KtNamedDeclaration>() ?: return null
|
||||
val klass = when (declaration) {
|
||||
is KtClassOrObject -> declaration
|
||||
is KtNamedFunction -> declaration.containingClassOrObject ?: return null
|
||||
else -> return null
|
||||
}
|
||||
val suiteNames = klass.parentsWithSelf
|
||||
.filterIsInstance<KtClassOrObject>()
|
||||
.mapNotNull { it.name }
|
||||
.toList()
|
||||
.asReversed()
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
return TestElementPath(suiteNames, testName)
|
||||
}
|
||||
|
||||
private fun createTestElementRunInfo(element: PsiElement, originalSettings: MochaRunSettings): TestElementInfo? {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null
|
||||
if (TargetPlatformDetector.getPlatform(module) !is JsPlatform) return null
|
||||
val project = module.project
|
||||
val testFilePath = getJsOutputFilePath(module, true, false) ?: return null
|
||||
val settings = if (originalSettings.workingDir.isBlank()) {
|
||||
val workingDir = FileUtil.toSystemDependentName(project.baseDir.path)
|
||||
originalSettings.builder().setWorkingDir(workingDir).build()
|
||||
}
|
||||
else originalSettings
|
||||
val (suiteNames, testName) = createSuiteOrTestData(element) ?: return null
|
||||
val builder = settings.builder()
|
||||
builder.setTestFilePath(testFilePath)
|
||||
if (settings.ui.isEmpty()) {
|
||||
builder.setUi(MochaUtil.UI_BDD)
|
||||
}
|
||||
if (testName == null) {
|
||||
builder.setTestKind(MochaTestKind.SUITE)
|
||||
builder.setSuiteNames(suiteNames)
|
||||
}
|
||||
else {
|
||||
builder.setTestKind(MochaTestKind.TEST)
|
||||
builder.setTestNames(suiteNames + testName)
|
||||
}
|
||||
|
||||
val nodeJsClasspath = getJsClasspath(module).joinToString(File.pathSeparator) {
|
||||
val basePath = project.basePath ?: return@joinToString it
|
||||
FileUtil.getRelativePath(basePath, it, '/') ?: it
|
||||
}
|
||||
builder.setEnvData(EnvironmentVariablesData.create(mapOf("NODE_PATH" to nodeJsClasspath), true))
|
||||
|
||||
return TestElementInfo(builder.build(), element)
|
||||
}
|
||||
|
||||
override fun isConfigurationFromCompatibleContext(configuration: MochaRunConfiguration, context: ConfigurationContext): Boolean {
|
||||
val element = context.psiLocation ?: return false
|
||||
val (thisRunSettings, _) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
|
||||
val thatRunSettings = configuration.runSettings
|
||||
val thisTestKind = thisRunSettings.testKind
|
||||
if (thisTestKind != thatRunSettings.testKind) return false
|
||||
return when {
|
||||
thisTestKind == MochaTestKind.DIRECTORY -> thisRunSettings.testDirPath == thatRunSettings.testDirPath
|
||||
thisTestKind == MochaTestKind.PATTERN -> thisRunSettings.testFilePattern == thatRunSettings.testFilePattern
|
||||
thisTestKind == MochaTestKind.TEST_FILE -> thisRunSettings.testFilePath == thatRunSettings.testFilePath
|
||||
thisTestKind == MochaTestKind.SUITE -> thisRunSettings.testFilePath == thatRunSettings.testFilePath && thisRunSettings.suiteNames == thatRunSettings.suiteNames
|
||||
thisTestKind != MochaTestKind.TEST -> false
|
||||
else -> thisRunSettings.testFilePath == thatRunSettings.testFilePath && thisRunSettings.testNames == thatRunSettings.testNames
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupConfigurationFromCompatibleContext(
|
||||
configuration: MochaRunConfiguration,
|
||||
context: ConfigurationContext,
|
||||
sourceElement: Ref<PsiElement>
|
||||
): Boolean {
|
||||
val element = context.psiLocation ?: return false
|
||||
if (!isActiveFor(element, context)) return false
|
||||
val (runSettings, enclosingTestElement) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
|
||||
if (runSettings.testKind == MochaTestKind.DIRECTORY) return false
|
||||
configuration.runSettings = runSettings
|
||||
sourceElement.set(enclosingTestElement)
|
||||
configuration.setGeneratedName()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,13 @@
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="get-nodejs-intellij-plugin">
|
||||
<sequential>
|
||||
<get src="http://plugins.jetbrains.com/plugin/download?updateId=37668" dest="${download}/nodejs_plugin.zip" usetimestamp="true"/>
|
||||
<unzip src="${download}/nodejs_plugin.zip" dest="dependencies/nodejs_plugin" overwrite="true"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<target name="fetch-extras">
|
||||
<mkdir dir="${download}"/>
|
||||
|
||||
@@ -33,6 +40,8 @@
|
||||
<get-spring-library lib="spring-context" version="4.2.0.RELEASE"/>
|
||||
<get-spring-library lib="spring-tx" version="4.2.0.RELEASE"/>
|
||||
<get-spring-library lib="spring-web" version="4.2.0.RELEASE"/>
|
||||
|
||||
<get-nodejs-intellij-plugin/>
|
||||
</target>
|
||||
|
||||
<!-- Override fetch-third-party from the main buildfile -->
|
||||
|
||||
Reference in New Issue
Block a user