Skip to content

Commit b5255e9

Browse files
committed
feat(script): add support for 'mavenId()' in 'class'
1 parent 5fddde4 commit b5255e9

File tree

6 files changed

+315
-2
lines changed

6 files changed

+315
-2
lines changed

.github/workflows/co.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
./gradlew check --stacktrace
3434
./gradlew codeCoverageReport
3535
- name: Upload coverage to Codecov
36-
uses: codecov/codecov-action@v1
36+
uses: codecov/codecov-action@v4
3737
with:
3838
token: ${{ secrets.CODECOV_TOKEN }}
3939
file: build/reports/jacoco/report.xml

idea-plugin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ intellij {
108108
type.set("IC")
109109
pluginName.set("easy-yapi")
110110
sandboxDir.set("idea-sandbox")
111-
plugins.set(listOf("java"))
111+
plugins.set(listOf("java", "maven", "gradle"))
112112
}
113113

114114
tasks {

idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/rule/ScriptRuleParser.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import com.itangcent.common.utils.mapToTypedArray
1212
import com.itangcent.http.RequestUtils
1313
import com.itangcent.idea.plugin.api.MethodInferHelper
1414
import com.itangcent.idea.plugin.format.Json5Formatter
15+
import com.itangcent.idea.utils.MavenHelper
16+
import com.itangcent.idea.utils.MavenIdData
1517
import com.itangcent.intellij.config.rule.*
1618
import com.itangcent.intellij.context.ActionContext
1719
import com.itangcent.intellij.extend.notReentrant
@@ -470,6 +472,10 @@ abstract class ScriptRuleParser : AbstractRuleParser() {
470472
}
471473
}
472474

475+
override fun mavenId(): MavenIdData? {
476+
return actionContext.callInReadUI { MavenHelper.getMavenId(psiClass) }
477+
}
478+
473479
override fun toString(): String {
474480
return name()
475481
}
@@ -1069,6 +1075,7 @@ abstract class ScriptRuleParser : AbstractRuleParser() {
10691075
*/
10701076
abstract fun implements(): Array<ScriptClassContext>?
10711077

1078+
abstract fun mavenId(): MavenIdData?
10721079
}
10731080

10741081
/**
@@ -1231,6 +1238,11 @@ abstract class ScriptRuleParser : AbstractRuleParser() {
12311238
}
12321239
}
12331240

1241+
override fun mavenId(): MavenIdData? {
1242+
val psiClass = getResource() as? PsiClass ?: return null
1243+
return actionContext.callInReadUI { MavenHelper.getMavenId(psiClass) }
1244+
}
1245+
12341246
override fun toString(): String {
12351247
return name()
12361248
}
@@ -1439,6 +1451,11 @@ abstract class ScriptRuleParser : AbstractRuleParser() {
14391451
}
14401452
}
14411453

1454+
override fun mavenId(): MavenIdData? {
1455+
val psiClass = getResource() as? PsiClass ?: return null
1456+
return actionContext.callInReadUI { MavenHelper.getMavenId(psiClass) }
1457+
}
1458+
14421459
override fun equals(other: Any?): Boolean {
14431460
if (this === other) return true
14441461
if (other !is ScriptClassContext) return false
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package com.itangcent.idea.utils
2+
3+
import com.intellij.openapi.module.ModuleUtilCore
4+
import com.intellij.psi.PsiClass
5+
import com.itangcent.annotation.script.ScriptTypeName
6+
import com.itangcent.common.utils.safe
7+
import org.jetbrains.idea.maven.project.MavenProjectsManager
8+
import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataCache
9+
10+
11+
/**
12+
* Utility object for obtaining Maven identifiers of a given PsiClass through Maven or Gradle.
13+
*
14+
* @author tangcent
15+
* @date 2024/08/11
16+
*/
17+
object MavenHelper {
18+
19+
/**
20+
* Attempts to retrieve the Maven ID of a PsiClass using Maven or Gradle.
21+
*
22+
* @param psiClass the PsiClass for which the Maven ID is to be retrieved.
23+
* @return MavenIdData if found, null otherwise.
24+
*/
25+
fun getMavenId(psiClass: PsiClass): MavenIdData? {
26+
return safe {
27+
getMavenIdByMaven(psiClass)
28+
} ?: safe {
29+
getMavenIdByGradle(psiClass)
30+
}
31+
}
32+
33+
/**
34+
* Retrieves the Maven ID of a PsiClass using Maven.
35+
*
36+
* @param psiClass the PsiClass for which the Maven ID is to be retrieved.
37+
* @return MavenIdData if found, null otherwise.
38+
*/
39+
private fun getMavenIdByMaven(psiClass: PsiClass): MavenIdData? {
40+
val project = psiClass.project
41+
val module = ModuleUtilCore.findModuleForPsiElement(psiClass)
42+
?: return null
43+
44+
val mavenProjectsManager = MavenProjectsManager.getInstance(project)
45+
val mavenProject = mavenProjectsManager.findProject(module) ?: return null
46+
val mavenId = mavenProject.mavenId
47+
return MavenIdData(
48+
groupId = mavenId.groupId!!,
49+
artifactId = mavenId.artifactId!!,
50+
version = mavenId.version!!
51+
)
52+
}
53+
54+
/**
55+
* Retrieves the Maven ID of a PsiClass using Gradle.
56+
*
57+
* @param psiClass the PsiClass for which the Maven ID is to be retrieved.
58+
* @return MavenIdData if found, null otherwise.
59+
*/
60+
private fun getMavenIdByGradle(psiClass: PsiClass): MavenIdData? {
61+
val project = psiClass.project
62+
val projectPath = project.basePath ?: return null
63+
val externalProject = ExternalProjectDataCache.getInstance(project).getRootExternalProject(projectPath)
64+
?: return null
65+
66+
return MavenIdData(
67+
groupId = externalProject.group,
68+
artifactId = externalProject.name,
69+
version = externalProject.version
70+
)
71+
}
72+
}
73+
74+
/**
75+
* Data class representing Maven ID information.
76+
*/
77+
@ScriptTypeName("MavenId")
78+
class MavenIdData(
79+
val groupId: String,
80+
val artifactId: String,
81+
val version: String
82+
) {
83+
84+
/**
85+
* Generates a Maven dependency snippet
86+
*/
87+
fun maven(): String {
88+
return """
89+
<dependency>
90+
<groupId>$groupId</groupId>
91+
<artifactId>$artifactId</artifactId>
92+
<version>$version</version>
93+
</dependency>
94+
""".trimIndent()
95+
}
96+
97+
/**
98+
* Generates a Gradle implementation dependency snippet
99+
*/
100+
fun gradle(): String {
101+
return """
102+
implementation group: '$groupId', name: '$artifactId', version: '$version'
103+
""".trimIndent()
104+
}
105+
106+
/**
107+
* Generates a Gradle implementation dependency snippet in short form.
108+
*/
109+
fun gradleShort(): String {
110+
return """
111+
implementation '$groupId:$artifactId:$version'
112+
""".trimIndent()
113+
}
114+
115+
/**
116+
* Generates a Gradle implementation dependency snippet in Kotlin DSL.
117+
*/
118+
fun gradleKotlin(): String {
119+
return """
120+
implementation("$groupId:$artifactId:$version")
121+
""".trimIndent()
122+
}
123+
124+
/**
125+
* Generates an SBT dependency snippet.
126+
*/
127+
fun sbt(): String {
128+
return """
129+
libraryDependencies += "$groupId" % "$artifactId" % "$version"
130+
""".trimIndent()
131+
}
132+
133+
/**
134+
* Generates an Ivy dependency snippet.
135+
*/
136+
fun ivy(): String {
137+
return """
138+
<dependency org="$groupId" name="$artifactId" rev="$version" />
139+
""".trimIndent()
140+
}
141+
142+
override fun toString(): String {
143+
return "$groupId:$artifactId:$version"
144+
}
145+
146+
override fun equals(other: Any?): Boolean {
147+
if (this === other) return true
148+
if (other !is MavenIdData) return false
149+
150+
if (groupId != other.groupId) return false
151+
if (artifactId != other.artifactId) return false
152+
if (version != other.version) return false
153+
154+
return true
155+
}
156+
157+
override fun hashCode(): Int {
158+
var result = groupId.hashCode()
159+
result = 31 * result + artifactId.hashCode()
160+
result = 31 * result + version.hashCode()
161+
return result
162+
}
163+
}

idea-plugin/src/test/kotlin/com/itangcent/idea/plugin/rule/ScriptClassContextBaseTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,10 @@ abstract class ScriptClassContextBaseTest : PluginContextLightCodeInsightFixture
11861186
assertTrue(modelPsiClass.asClassContext().implements()!!.isEmpty())
11871187
}
11881188

1189+
fun testMavenId() {
1190+
assertNull(objectPsiClass.asClassContext().mavenId())
1191+
}
1192+
11891193
//endregion
11901194

11911195
//region tests of ScriptFieldContext
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.itangcent.idea.utils
2+
3+
import com.intellij.openapi.module.Module
4+
import com.intellij.psi.PsiClass
5+
import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase
6+
import org.jetbrains.idea.maven.model.MavenId
7+
import org.jetbrains.idea.maven.project.MavenProject
8+
import org.jetbrains.idea.maven.project.MavenProjectsManager
9+
import org.jetbrains.plugins.gradle.model.ExternalProject
10+
import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataCache
11+
import org.junit.jupiter.api.Assertions
12+
import org.mockito.Mockito.mockStatic
13+
import org.mockito.kotlin.any
14+
import org.mockito.kotlin.mock
15+
16+
/**
17+
* Test class for [MavenHelper].
18+
*
19+
* @author tangcent
20+
* @date 2024/08/11
21+
*/
22+
class MavenHelperTest : PluginContextLightCodeInsightFixtureTestCase() {
23+
24+
private lateinit var userCtrlPsiClass: PsiClass
25+
26+
override fun beforeBind() {
27+
super.beforeBind()
28+
userCtrlPsiClass = loadClass("api/UserCtrl.java")!!
29+
}
30+
31+
fun testGetMavenIdByMaven() {
32+
mockStatic(MavenProjectsManager::class.java).use { mavenProjectsManagerMock ->
33+
val mavenProject = mock<MavenProject> {
34+
on(it.mavenId)
35+
.thenReturn(MavenId("com.itangcent", "intellij-idea-test", "1.0.0"))
36+
}
37+
val mavenProjectsManager = mock<MavenProjectsManager> {
38+
on(it.findProject(any<Module>()))
39+
.thenReturn(mavenProject)
40+
}
41+
42+
mavenProjectsManagerMock.`when`<MavenProjectsManager> {
43+
MavenProjectsManager.getInstance(project)
44+
}.thenReturn(mavenProjectsManager)
45+
46+
val mavenId = MavenHelper.getMavenId(userCtrlPsiClass)
47+
48+
assertNotNull(mavenId)
49+
assertEquals("com.itangcent", mavenId!!.groupId)
50+
assertEquals("intellij-idea-test", mavenId.artifactId)
51+
assertEquals("1.0.0", mavenId.version)
52+
}
53+
}
54+
55+
fun testGetMavenIdByGradle() {
56+
mockStatic(ExternalProjectDataCache::class.java).use { externalProjectDataCacheMock ->
57+
val externalProject = mock<ExternalProject> {
58+
on(it.name)
59+
.thenReturn("intellij-idea-test")
60+
on(it.group)
61+
.thenReturn("com.itangcent")
62+
on(it.version)
63+
.thenReturn("1.0.0")
64+
}
65+
val externalProjectDataCache = mock<ExternalProjectDataCache> {
66+
on(it.getRootExternalProject(any()))
67+
.thenReturn(externalProject)
68+
}
69+
70+
externalProjectDataCacheMock.`when`<ExternalProjectDataCache> {
71+
ExternalProjectDataCache.getInstance(project)
72+
}.thenReturn(externalProjectDataCache)
73+
74+
val mavenIdData = MavenHelper.getMavenId(userCtrlPsiClass)
75+
76+
assertNotNull(mavenIdData)
77+
assertEquals("com.itangcent", mavenIdData!!.groupId)
78+
assertEquals("intellij-idea-test", mavenIdData.artifactId)
79+
assertEquals("1.0.0", mavenIdData.version)
80+
}
81+
}
82+
83+
fun testMavenIdData() {
84+
val mavenIdData = MavenIdData("com.itangcent", "intellij-idea-test", "1.0.0")
85+
Assertions.assertEquals("com.itangcent", mavenIdData.groupId)
86+
Assertions.assertEquals("intellij-idea-test", mavenIdData.artifactId)
87+
Assertions.assertEquals("1.0.0", mavenIdData.version)
88+
89+
Assertions.assertEquals(
90+
"""
91+
<dependency>
92+
<groupId>com.itangcent</groupId>
93+
<artifactId>intellij-idea-test</artifactId>
94+
<version>1.0.0</version>
95+
</dependency>
96+
""".trimIndent(), mavenIdData.maven()
97+
)
98+
99+
Assertions.assertEquals(
100+
"""
101+
implementation group: 'com.itangcent', name: 'intellij-idea-test', version: '1.0.0'
102+
""".trimIndent(), mavenIdData.gradle()
103+
)
104+
105+
Assertions.assertEquals(
106+
"""
107+
implementation 'com.itangcent:intellij-idea-test:1.0.0'
108+
""".trimIndent(), mavenIdData.gradleShort()
109+
)
110+
111+
Assertions.assertEquals(
112+
"""
113+
implementation("com.itangcent:intellij-idea-test:1.0.0")
114+
""".trimIndent(), mavenIdData.gradleKotlin()
115+
)
116+
117+
Assertions.assertEquals(
118+
"""
119+
<dependency org="com.itangcent" name="intellij-idea-test" rev="1.0.0" />
120+
""".trimIndent(), mavenIdData.ivy()
121+
)
122+
123+
Assertions.assertEquals(
124+
"""
125+
libraryDependencies += "com.itangcent" % "intellij-idea-test" % "1.0.0"
126+
""".trimIndent(), mavenIdData.sbt()
127+
)
128+
}
129+
}

0 commit comments

Comments
 (0)