@@ -10,12 +10,13 @@ import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunConfiguration
10
10
import com.intellij.lang.javascript.psi.*
11
11
import com.intellij.lang.javascript.psi.ecmal4.JSClass
12
12
import com.intellij.openapi.application.ReadAction
13
+ import com.intellij.openapi.application.runReadAction
13
14
import com.intellij.openapi.project.Project
14
15
import com.intellij.openapi.vfs.LocalFileSystem
15
- import com.intellij.psi.PsiElement
16
- import com.intellij.psi.PsiFile
17
- import com.intellij.psi.PsiFileFactory
16
+ import com.intellij.psi.*
18
17
import com.intellij.psi.util.PsiTreeUtil
18
+ import java.io.File
19
+ import java.nio.file.Path
19
20
import kotlin.io.path.Path
20
21
import kotlin.io.path.nameWithoutExtension
21
22
@@ -33,7 +34,7 @@ class JSWriteTestService : WriteTestService() {
33
34
val language = sourceFile.language
34
35
val targetFilePath = sourceFile.name.replace(" .ts" , " .test.ts" )
35
36
36
- val elementToTest = getElementToTest(element) ? : return null
37
+ val elementToTest = Util . getElementToTest(element) ? : return null
37
38
val elementName = JSPsiUtil .elementName(elementToTest) ? : return null
38
39
39
40
val testFile = LocalFileSystem .getInstance().findFileByPath(targetFilePath)
@@ -54,48 +55,91 @@ class JSWriteTestService : WriteTestService() {
54
55
return emptyList()
55
56
}
56
57
57
- /* *
58
- * In JavaScript/TypeScript a testable element is a function, a class or a variable.
59
- *
60
- * Function:
61
- * ```javascript
62
- * function testableFunction() {}
63
- * export testableFunction
64
- * ```
65
- *
66
- * Class:
67
- * ```javascript
68
- * export class TestableClass {}
69
- * ```
70
- *
71
- * Variable:
72
- * ```javascript
73
- * var functionA = function() {}
74
- * export functionA
75
- * ```
76
- */
77
- fun getElementToTest (psiElement : PsiElement ): PsiElement ? {
78
- val jsFunc = PsiTreeUtil .getParentOfType(psiElement, JSFunction ::class .java, false )
79
- val jsVarStatement = PsiTreeUtil .getParentOfType(psiElement, JSVarStatement ::class .java, false )
80
- val jsClazz = PsiTreeUtil .getParentOfType(psiElement, JSClass ::class .java, false )
81
-
82
- val elementForTests: PsiElement ? = when {
83
- jsFunc != null -> jsFunc
84
- jsVarStatement != null -> jsVarStatement
85
- jsClazz != null -> jsClazz
86
- else -> null
58
+ object Util {
59
+
60
+ /* *
61
+ * In JavaScript/TypeScript a testable element is a function, a class or a variable.
62
+ *
63
+ * Function:
64
+ * ```javascript
65
+ * function testableFunction() {}
66
+ * export testableFunction
67
+ * ```
68
+ *
69
+ * Class:
70
+ * ```javascript
71
+ * export class TestableClass {}
72
+ * ```
73
+ *
74
+ * Variable:
75
+ * ```javascript
76
+ * var functionA = function() {}
77
+ * export functionA
78
+ * ```
79
+ */
80
+ fun getElementToTest (psiElement : PsiElement ): PsiElement ? {
81
+ val jsFunc = PsiTreeUtil .getParentOfType(psiElement, JSFunction ::class .java, false )
82
+ val jsVarStatement = PsiTreeUtil .getParentOfType(psiElement, JSVarStatement ::class .java, false )
83
+ val jsClazz = PsiTreeUtil .getParentOfType(psiElement, JSClass ::class .java, false )
84
+
85
+ val elementForTests: PsiElement ? = when {
86
+ jsFunc != null -> jsFunc
87
+ jsVarStatement != null -> jsVarStatement
88
+ jsClazz != null -> jsClazz
89
+ else -> null
90
+ }
91
+
92
+ if (elementForTests == null ) return null
93
+
94
+ return if (JSPsiUtil .isExportedClassPublicMethod(elementForTests) ||
95
+ JSPsiUtil .isExportedFileFunction(elementForTests) ||
96
+ JSPsiUtil .isExportedClass(elementForTests)
97
+ ) {
98
+ elementForTests
99
+ } else {
100
+ null
101
+ }
102
+ }
103
+
104
+ fun getTestFilePath (element : PsiElement ): Path ? {
105
+ val testDirectory = suggestTestDirectory(element) ? : return null
106
+ val containingFile: PsiFile = element.containingFile ? : return null
107
+ val extension = containingFile.virtualFile?.extension ? : return null
108
+ val elementName = JSPsiUtil .elementName(element) ? : return null
109
+ val testFile: Path = generateUniqueTestFile(elementName, containingFile, testDirectory, extension).toPath()
110
+ return testFile
87
111
}
88
112
89
- if (elementForTests == null ) return null
113
+ private fun suggestTestDirectory (element : PsiElement ): PsiDirectory ? {
114
+ val project: Project = element.project
115
+ val elementDirectory = runReadAction {
116
+ element.containingFile
117
+ }
90
118
91
- return if (JSPsiUtil .isExportedClassPublicMethod(elementForTests) ||
92
- JSPsiUtil .isExportedFileFunction(elementForTests) ||
93
- JSPsiUtil .isExportedClass(elementForTests)
94
- ) {
95
- elementForTests
96
- } else {
97
- null
119
+ val parentDir = elementDirectory?.virtualFile?.parent ? : return null
120
+ val childDir = parentDir.createChildDirectory(this , " test" )
121
+ return PsiManager .getInstance(project).findDirectory(childDir)
98
122
}
99
- }
100
123
124
+ private fun generateUniqueTestFile (
125
+ elementName : String? ,
126
+ containingFile : PsiFile ,
127
+ testDirectory : PsiDirectory ,
128
+ extension : String
129
+ ): File {
130
+ val testPath = testDirectory.virtualFile.path
131
+ val prefix = elementName ? : containingFile.name.substringBefore(' .' , " " )
132
+ val nameCandidate = " $prefix .test.$extension "
133
+ var testFile = File (testPath, nameCandidate)
134
+
135
+ var i = 1
136
+ while (testFile.exists()) {
137
+ val nameCandidateWithIndex = " $prefix${i} .test.$extension "
138
+ i++
139
+ testFile = File (testPath, nameCandidateWithIndex)
140
+ }
141
+
142
+ return testFile
143
+ }
144
+ }
101
145
}
0 commit comments