().scheduleConfigurationReload()
- }
- })
- }
-
- override fun dispose() {
- logd("project=${project.name}")
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighter.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighter.kt
deleted file mode 100644
index c775dee554a..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighter.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2016-2024 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
- * Copyright (c) 2018-present, Jim Kynde Meyer
- * All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-package com.apollographql.ijplugin.highlighting
-
-import com.apollographql.ijplugin.psi.ApolloGraphQLElementTypes
-import com.apollographql.ijplugin.psi.ApolloGraphQLExtendedElementTypes
-import com.apollographql.ijplugin.psi.ApolloGraphQLLexer
-import com.intellij.lexer.FlexAdapter
-import com.intellij.lexer.Lexer
-import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
-import com.intellij.openapi.editor.HighlighterColors
-import com.intellij.openapi.editor.colors.TextAttributesKey
-import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
-import com.intellij.psi.TokenType
-import com.intellij.psi.tree.IElementType
-
-class ApolloGraphQLSyntaxHighlighter : SyntaxHighlighterBase() {
- override fun getHighlightingLexer(): Lexer {
- return ApolloGraphQLLexerAdapter()
- }
-
- override fun getTokenHighlights(tokenType: IElementType): Array {
- return when {
- tokenType == ApolloGraphQLElementTypes.NAME -> {
- IDENTIFIER_KEYS
- }
-
- ApolloGraphQLExtendedElementTypes.KEYWORDS.contains(tokenType) -> {
- KEYWORD_KEYS
- }
-
- ApolloGraphQLExtendedElementTypes.NUMBER_LITERALS.contains(tokenType) -> {
- NUMBER_KEYS
- }
-
- ApolloGraphQLExtendedElementTypes.STRING_TOKENS.contains(tokenType) -> {
- STRING_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.EOL_COMMENT -> {
- COMMENT_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.BRACE_L || tokenType == ApolloGraphQLElementTypes.BRACE_R -> {
- BRACES_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.PAREN_L || tokenType == ApolloGraphQLElementTypes.PAREN_R -> {
- PARENTHESES_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.BRACKET_L || tokenType == ApolloGraphQLElementTypes.BRACKET_R -> {
- BRACKETS_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.SPREAD -> {
- SPREAD_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.COLON -> {
- COLON_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.BANG -> {
- BANG_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.PIPE -> {
- PIPE_KEYS
- }
-
- tokenType == ApolloGraphQLElementTypes.AMP -> {
- AMP_KEYS
- }
-
- tokenType == TokenType.BAD_CHARACTER -> {
- BAD_CHARACTER_KEYS
- }
-
- else -> {
- EMPTY_KEYS
- }
- }
- }
-
- companion object {
- val IDENTIFIER: TextAttributesKey =
- TextAttributesKey.createTextAttributesKey("GRAPHQL_IDENTIFIER", DefaultLanguageHighlighterColors.IDENTIFIER)
- val KEYWORD: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD)
- val NUMBER: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_NUMBER", DefaultLanguageHighlighterColors.NUMBER)
- val STRING: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_STRING", DefaultLanguageHighlighterColors.STRING)
- val COMMENT: TextAttributesKey =
- TextAttributesKey.createTextAttributesKey("GRAPHQL_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT)
- val BRACES: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_BRACES", DefaultLanguageHighlighterColors.BRACES)
- val PARENTHESES: TextAttributesKey =
- TextAttributesKey.createTextAttributesKey("GRAPHQL_PARENTHESES", DefaultLanguageHighlighterColors.PARENTHESES)
- val BRACKETS: TextAttributesKey =
- TextAttributesKey.createTextAttributesKey("GRAPHQL_BRACKETS", DefaultLanguageHighlighterColors.BRACKETS)
- val SPREAD: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_SPREAD", DefaultLanguageHighlighterColors.SEMICOLON)
- val COLON: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_COLON", DefaultLanguageHighlighterColors.SEMICOLON)
- val BANG: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_BANG", DefaultLanguageHighlighterColors.OPERATION_SIGN)
- val PIPE: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_PIPE", DefaultLanguageHighlighterColors.SEMICOLON)
- val AMP: TextAttributesKey = TextAttributesKey.createTextAttributesKey("GRAPHQL_AMP", DefaultLanguageHighlighterColors.SEMICOLON)
- val BAD_CHARACTER: TextAttributesKey =
- TextAttributesKey.createTextAttributesKey("GRAPHQL_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER)
-
- private val IDENTIFIER_KEYS = arrayOf(IDENTIFIER)
- private val KEYWORD_KEYS = arrayOf(KEYWORD)
- private val NUMBER_KEYS = arrayOf(NUMBER)
- private val STRING_KEYS = arrayOf(STRING)
- private val COMMENT_KEYS = arrayOf(COMMENT)
- private val BRACES_KEYS = arrayOf(BRACES)
- private val PARENTHESES_KEYS = arrayOf(PARENTHESES)
- private val BRACKETS_KEYS = arrayOf(BRACKETS)
- private val SPREAD_KEYS = arrayOf(SPREAD)
- private val COLON_KEYS = arrayOf(COLON)
- private val BANG_KEYS = arrayOf(BANG)
- private val PIPE_KEYS = arrayOf(PIPE)
- private val AMP_KEYS = arrayOf(AMP)
- private val BAD_CHARACTER_KEYS = arrayOf(BAD_CHARACTER)
- private val EMPTY_KEYS: Array = TextAttributesKey.EMPTY_ARRAY
- }
-}
-
-private class ApolloGraphQLLexerAdapter : FlexAdapter(ApolloGraphQLLexer(null))
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighterFactory.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighterFactory.kt
deleted file mode 100644
index 79729a77998..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/highlighting/ApolloGraphQLSyntaxHighlighterFactory.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.apollographql.ijplugin.highlighting
-
-import com.intellij.openapi.fileTypes.SyntaxHighlighter
-import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VirtualFile
-
-class ApolloGraphQLSyntaxHighlighterFactory : SyntaxHighlighterFactory() {
- override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter {
- return ApolloGraphQLSyntaxHighlighter()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/ApolloIcons.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/ApolloIcons.kt
deleted file mode 100644
index eed70713377..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/ApolloIcons.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.apollographql.ijplugin.icons
-
-import com.intellij.openapi.util.IconLoader
-import javax.swing.Icon
-
-object ApolloIcons {
- object Gutter {
- val GraphQL by lazy { load("/icons/gutter-graphql.svg") }
- }
-
- object Symbol {
- val GraphQL by lazy { load("/icons/symbol-graphql.svg") }
- val ApolloGraphQL by lazy { load("/icons/symbol-apollo-graphql.svg") }
- }
-
- object Action {
- val Apollo by lazy { load("/icons/action-apollo-monochrome.svg") }
-
- // This one cannot be lazy because it's referenced from plugin.xml
- @JvmField
- val ApolloColor = load("/icons/action-apollo-color.svg")
- }
-
- object ToolWindow {
- @JvmField
- val NormalizedCacheViewer = load("/icons/toolwindow-normalized-cache-viewer.svg")
- }
-
- object Node {
- val Package by lazy { load("/icons/node-package.svg") }
- }
-
- object StatusBar {
- val Apollo by lazy { load("/icons/status-apollo-monochrome.svg") }
- }
-
- private fun load(path: String): Icon {
- return IconLoader.getIcon(path, ApolloIcons::class.java)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/GraphQLIconProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/GraphQLIconProvider.kt
deleted file mode 100644
index 04ebca397c4..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/icons/GraphQLIconProvider.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.apollographql.ijplugin.icons
-
-import com.intellij.ide.IconProvider
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.psi.PsiElement
-import javax.swing.Icon
-
-class GraphQLIconProvider : IconProvider() {
- override fun getIcon(element: PsiElement, flags: Int): Icon? {
- if (element is GraphQLElement) {
- return ApolloIcons.Symbol.GraphQL
- }
- return null
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/Apollo4AvailableInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/Apollo4AvailableInspection.kt
deleted file mode 100644
index 6a3553c75de..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/Apollo4AvailableInspection.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.action.ApolloV3ToV4MigrationAction
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.refactoring.migration.v3tov4.ApolloV3ToV4MigrationProcessor
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.apollo3
-import com.apollographql.ijplugin.util.getMethodName
-import com.apollographql.ijplugin.util.unquoted
-import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.openapi.actionSystem.ActionManager
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiElementVisitor
-import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
-import org.jetbrains.kotlin.psi.KtBinaryExpression
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtStringTemplateExpression
-import org.toml.lang.psi.TomlLiteral
-import org.toml.lang.psi.ext.TomlLiteralKind
-import org.toml.lang.psi.ext.kind
-
-class Apollo4AvailableInspection : LocalInspectionTool() {
- // XXX kts files are not highlighted in tests
- private val buildGradleFileName = if (isUnitTestMode()) "build.gradle.kt" else "build.gradle.kts"
-
- // Do not warn until 4.0 is stable (but keep enabled always in unit tests)
- private val isEnabled = isUnitTestMode() || !ApolloV3ToV4MigrationProcessor.apollo4LatestVersion.contains('-')
-
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : PsiElementVisitor() {
- override fun visitElement(element: PsiElement) {
- if (!isEnabled) return
- if (!element.project.apolloProjectService.apolloVersion.isAtLeastV3) return
- when {
- element.containingFile.name.endsWith(".versions.toml") && element is TomlLiteral -> {
- visitVersionsToml(element, holder)
- }
-
- element.containingFile.name == buildGradleFileName && element is KtCallExpression -> {
- visitBuildGradleKts(element, holder)
- }
- }
- }
-
- private fun visitVersionsToml(element: TomlLiteral, holder: ProblemsHolder) {
- if (element.kind !is TomlLiteralKind.String) return
- val dependencyText = element.text.unquoted()
- if (dependencyText == apollo3 || dependencyText.startsWith("$apollo3:")) {
- holder.registerProblem(element.parent.parent.parent, ApolloBundle.message("inspection.apollo4Available.reportText"), Apollo4AvailableQuickFix)
- }
- }
-
- private fun visitBuildGradleKts(callExpression: KtCallExpression, holder: ProblemsHolder) {
- when (callExpression.getMethodName()) {
- "id" -> {
- // id("xxx")
- val dependencyText = callExpression.getArgumentAsString(0) ?: return
- if (dependencyText != apollo3) return
- val element = when (val parent = callExpression.parent) {
- is KtBinaryExpression, is KtDotQualifiedExpression -> {
- parent
- }
-
- else -> {
- callExpression
- }
- }
- holder.registerProblem(element, ApolloBundle.message("inspection.apollo4Available.reportText"), Apollo4AvailableQuickFix)
- }
-
- "implementation", "api", "testImplementation", "testApi" -> {
- when (callExpression.valueArguments.size) {
- // implementation("xxx:yyy:zzz")
- 1 -> {
- val dependency = callExpression.getArgumentAsString(0) ?: return
- val dependencyElements = dependency.split(":")
- val groupId = dependencyElements[0]
- if (groupId != apollo3) return
- holder.registerProblem(callExpression, ApolloBundle.message("inspection.apollo4Available.reportText"), Apollo4AvailableQuickFix)
- }
-
-
- // implementation("xxx", "yyy")
- // implementation("xxx", "yyy", "zzz")
- 2, 3 -> {
- val groupId = callExpression.getArgumentAsString(0) ?: return
- if (groupId != apollo3) return
- holder.registerProblem(callExpression, ApolloBundle.message("inspection.apollo4Available.reportText"), Apollo4AvailableQuickFix)
- }
- }
- }
- }
- }
-
- private fun KtCallExpression.getArgumentAsString(index: Int): String? =
- (valueArgumentList?.arguments?.getOrNull(index)
- ?.children?.firstOrNull() as? KtStringTemplateExpression)?.text?.unquoted()
- }
- }
-}
-
-object Apollo4AvailableQuickFix : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.apollo4Available.quickFix")
-
- override fun getFamilyName() = name
-
- override fun availableInBatchMode() = false
-
- override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjApollo4AvailableQuickFix())
- val action = ActionManager.getInstance().getAction(ApolloV3ToV4MigrationAction.ACTION_ID)
- ActionManager.getInstance().tryToExecute(action, null, null, null, false)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloEndpointNotConfiguredInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloEndpointNotConfiguredInspection.kt
deleted file mode 100644
index 0f84e6ad8f3..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloEndpointNotConfiguredInspection.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.getMethodName
-import com.apollographql.ijplugin.util.isMethodCall
-import com.apollographql.ijplugin.util.lambdaBlockExpression
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.findParentInFile
-import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.psi.KtVisitorVoid
-
-class ApolloEndpointNotConfiguredInspection : LocalInspectionTool() {
- // XXX kts files are not highlighted in tests
- private val buildGradleFileName = if (isUnitTestMode()) "build.gradle.kt" else "build.gradle.kts"
-
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : KtVisitorVoid() {
- override fun visitCallExpression(expression: KtCallExpression) {
- super.visitCallExpression(expression)
- if (!expression.project.apolloProjectService.apolloVersion.isAtLeastV3) return
- if (expression.containingFile.name != buildGradleFileName) return
- if (expression.getMethodName() == "service" && expression.findParentInFile { it.isMethodCall("apollo") } != null) {
- val serviceBlockExpression = expression.lambdaBlockExpression() ?: return
- // Don't suggest to add an introspection block if this is a submodule
- val hasDependsOn = serviceBlockExpression.statements.any { it.isMethodCall("dependsOn") }
- if (hasDependsOn) return
- if (serviceBlockExpression.statements.none { it.isMethodCall("introspection") }) {
- holder.registerProblem(expression.calleeExpression!!, ApolloBundle.message("inspection.endpointNotConfigured.reportText"), AddIntrospectionBlockQuickFix)
- }
- }
- }
- }
- }
-}
-
-object AddIntrospectionBlockQuickFix : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.endpointNotConfigured.quickFix")
- override fun getFamilyName() = name
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjEndpointNotConfiguredQuickFix())
- val callExpression = descriptor.psiElement.parent as KtCallExpression
- val serviceBlockExpression = callExpression.lambdaBlockExpression() ?: return
- val ktFactory = KtPsiFactory(project)
- val newCallExpression = ktFactory.createExpression(
- """
- introspection {
- endpointUrl.set("https://example.com/graphql")
- headers.put("api-key", "1234567890abcdef")
- schemaFile.set(file("src/main/graphql/schema.graphqls"))
- }
- """.trimIndent()
- )
- serviceBlockExpression.add(ktFactory.createNewLine())
- serviceBlockExpression.add(newCallExpression)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloGraphQLConfigFilePresentInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloGraphQLConfigFilePresentInspection.kt
deleted file mode 100644
index 93b97403835..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloGraphQLConfigFilePresentInspection.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.settings.projectSettingsState
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.annotation.AnnotationHolder
-import com.intellij.lang.annotation.Annotator
-import com.intellij.lang.annotation.HighlightSeverity
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Condition
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.PsiFile
-
-private val graphQLConfigFileNames = setOf(
- "graphql.config.json",
- "graphql.config.js",
- "graphql.config.cjs",
- "graphql.config.ts",
- "graphql.config.yaml",
- "graphql.config.yml",
- ".graphqlrc",
- ".graphqlrc.json",
- ".graphqlrc.yaml",
- ".graphqlrc.yml",
- ".graphqlrc.js",
- ".graphqlrc.ts"
-)
-
-class ApolloGraphQLConfigFilePresentInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : PsiElementVisitor() {
- override fun visitFile(file: PsiFile) {
- if (!file.project.apolloProjectService.apolloVersion.isAtLeastV4 || !file.project.projectSettingsState.contributeConfigurationToGraphqlPlugin) return
- if (file.name in graphQLConfigFileNames) {
- holder.registerProblem(file, ApolloBundle.message("inspection.graphQLConfigFilePresent.reportText"), ApolloGraphQLConfigFilePresentQuickFix(file.name))
- }
- }
- }
- }
-}
-
-private class ApolloGraphQLConfigFilePresentQuickFix(private val fileName: String) : LocalQuickFix {
- override fun getName(): String {
- return ApolloBundle.message("inspection.graphQLConfigFilePresent.quickFix", fileName)
- }
-
- override fun getFamilyName() = name
-
- override fun availableInBatchMode() = false
-
- override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjGraphQLConfigFilePresentQuickFix())
- val psiFile = descriptor.psiElement.containingFile
- psiFile.virtualFile.delete(this)
- }
-}
-
-class ApolloGraphQLConfigFilePresentAnnotator : Annotator {
- override fun annotate(element: PsiElement, holder: AnnotationHolder) {
- if (element !is PsiFile) return
- if (!element.project.apolloProjectService.apolloVersion.isAtLeastV4 || !element.project.projectSettingsState.contributeConfigurationToGraphqlPlugin) return
- if (element.containingFile.name in graphQLConfigFileNames) {
- holder.newAnnotation(HighlightSeverity.WARNING, ApolloBundle.message("inspection.graphQLConfigFilePresent.reportText"))
- .range(element)
- .create()
- }
- }
-}
-
-class GraphQLConfigFileFilter : Condition {
- override fun value(virtualFile: VirtualFile): Boolean {
- return virtualFile.name in graphQLConfigFileNames
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloInputConstructorNamedArgsInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloInputConstructorNamedArgsInspection.kt
deleted file mode 100644
index 63293e36e99..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloInputConstructorNamedArgsInspection.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.navigation.isApolloInputClassReference
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.apollo3
-import com.apollographql.ijplugin.util.apollo4
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.getParameterNames
-import com.apollographql.ijplugin.util.originalClassName
-import com.apollographql.ijplugin.util.registerProblem
-import com.intellij.codeInsight.intention.FileModifier
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElementVisitor
-import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
-import org.jetbrains.kotlin.idea.references.mainReference
-import org.jetbrains.kotlin.psi.KtCallElement
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.psi.KtValueArgument
-import org.jetbrains.kotlin.psi.KtVisitorVoid
-
-class ApolloInputConstructorNamedArgsInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : KtVisitorVoid() {
- override fun visitCallExpression(expression: KtCallExpression) {
- super.visitCallExpression(expression)
- val projectApolloVersion = expression.project.apolloProjectService.apolloVersion
- if (!projectApolloVersion.isAtLeastV3) return
- val reference = expression.calleeExpression.cast()
- if (expression.valueArguments.size < 2) return
- if (expression.valueArguments.all { it.isNamed() }) return
- if (reference?.isApolloInputClassReference() != true) return
- val quickFixes = buildList {
- val parameterNames = expression.getParameterNames() ?: return@buildList
- add(AddArgumentNamesQuickFix(parameterNames))
- if (projectApolloVersion.isAtLeastV4) add(ChangeToBuilderQuickFix(parameterNames))
- }.toTypedArray()
- holder.registerProblem(this@ApolloInputConstructorNamedArgsInspection, expression, ApolloBundle.message("inspection.inputConstructorNamedArgs.reportText"), withMoreLink = true, *quickFixes)
- }
- }
- }
-}
-
-class AddArgumentNamesQuickFix(
- @FileModifier.SafeFieldForPreview
- private val parameterNames: List,
-) : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.inputConstructorNamedArgs.quickFix.addArgumentNames")
- override fun getFamilyName() = name
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjInputConstructorNamedArgsAddArgumentNamesQuickFix())
- val callElement = descriptor.psiElement as KtCallElement
- val arguments = callElement.valueArguments
- for ((i, argument) in arguments.withIndex()) {
- val ktArgument = argument.cast() ?: continue
- ktArgument.replace(KtPsiFactory(project).createArgument("${parameterNames[i]} = ${ktArgument.getArgumentExpression()!!.text}"))
- }
- }
-}
-
-class ChangeToBuilderQuickFix(
- @FileModifier.SafeFieldForPreview
- private val parameterNames: List,
-) : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.inputConstructorNamedArgs.quickFix.changeToBuilder")
- override fun getFamilyName() = name
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjInputConstructorNamedArgsChangeToBuilderQuickFix())
- val callElement = descriptor.psiElement as KtCallElement
- applyFix(project, callElement)
- }
-
- fun applyFix(project: Project, callElement: KtCallElement) {
- val arguments = callElement.valueArguments
- val inputClassName = callElement.calleeExpression.cast()?.originalClassName() ?: return
- val replacementExpression = buildString {
- append("$inputClassName.Builder()")
- for ((i, argument) in arguments.withIndex()) {
- val ktArgument = argument.cast() ?: continue
- val name = parameterNames[i]
- val argumentText = ktArgument.unwrapOptional()
- if (argumentText != null) {
- append("\n.$name($argumentText)")
- }
- }
- append("\n.build()")
- }
- callElement.replace(KtPsiFactory(project).createExpression(replacementExpression))
- }
-
- /**
- * - Optional.present(xxx) -> `"xxx"`
- * - Optional.Present(xxx) -> `"xxx"`
- * - Optional.absent() -> `null`
- * - Optional.Absent -> `null`
- * - xxx -> `"xxx.getOrNull()"`
- */
- private fun KtValueArgument.unwrapOptional(): String? {
- val argumentExpression = getArgumentExpression() ?: return "?"
- val dotQualifiedExpression = argumentExpression.cast()
- val receiverClassName = dotQualifiedExpression?.receiverExpression?.mainReference?.resolve()?.kotlinFqName?.asString()
- val isOptional = receiverClassName == "$apollo3.api.Optional" || receiverClassName == "$apollo4.api.Optional"
- val isOptionalCompanion =
- receiverClassName == "$apollo3.api.Optional.Companion" || receiverClassName == "$apollo4.api.Optional.Companion"
- val selectorCallExpression = dotQualifiedExpression?.selectorExpression.cast()
- val selectorCallExpressionText = selectorCallExpression?.calleeExpression?.text
- val nameReferenceExpressionText = dotQualifiedExpression?.selectorExpression.cast()?.text
- val isPresent = isOptional && selectorCallExpressionText == "Present" || isOptionalCompanion && selectorCallExpressionText == "present"
- val presentArgumentText = selectorCallExpression?.valueArguments?.firstOrNull()?.text ?: "?"
- val isAbsent = isOptional && nameReferenceExpressionText == "Absent" || isOptionalCompanion && selectorCallExpressionText == "absent"
- return when {
- isPresent -> presentArgumentText
- isAbsent -> null
- else -> "${argumentExpression.text}.getOrNull()"
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloMissingGraphQLDefinitionImportInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloMissingGraphQLDefinitionImportInspection.kt
deleted file mode 100644
index 802c713714b..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloMissingGraphQLDefinitionImportInspection.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.apollo.ast.GQLDefinition
-import com.apollographql.apollo.ast.GQLDirectiveDefinition
-import com.apollographql.apollo.ast.GQLEnumTypeDefinition
-import com.apollographql.apollo.ast.GQLInputObjectTypeDefinition
-import com.apollographql.apollo.ast.GQLNamed
-import com.apollographql.apollo.ast.GQLScalarTypeDefinition
-import com.apollographql.apollo.ast.rawType
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.gradle.gradleToolingModelService
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.KOTLIN_LABS_DEFINITIONS
-import com.apollographql.ijplugin.util.KOTLIN_LABS_URL
-import com.apollographql.ijplugin.util.NULLABILITY_DEFINITIONS
-import com.apollographql.ijplugin.util.NULLABILITY_URL
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.createLinkDirective
-import com.apollographql.ijplugin.util.createLinkDirectiveSchemaExtension
-import com.apollographql.ijplugin.util.directives
-import com.apollographql.ijplugin.util.isImported
-import com.apollographql.ijplugin.util.linkDirectives
-import com.apollographql.ijplugin.util.nameForImport
-import com.apollographql.ijplugin.util.schemaFiles
-import com.apollographql.ijplugin.util.unquoted
-import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemHighlightType
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.jsgraphql.psi.GraphQLArrayValue
-import com.intellij.lang.jsgraphql.psi.GraphQLDirective
-import com.intellij.lang.jsgraphql.psi.GraphQLElementFactory
-import com.intellij.lang.jsgraphql.psi.GraphQLFile
-import com.intellij.lang.jsgraphql.psi.GraphQLVisitor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.parentOfType
-
-class ApolloMissingGraphQLDefinitionImportInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : GraphQLVisitor() {
- override fun visitDirective(o: GraphQLDirective) {
- super.visitDirective(o)
- if (!o.project.apolloProjectService.apolloVersion.isAtLeastV4) return
- visitDirective(o, holder, NULLABILITY_DEFINITIONS, NULLABILITY_URL, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL)
- visitDirective(o, holder, KOTLIN_LABS_DEFINITIONS, KOTLIN_LABS_URL, ProblemHighlightType.WEAK_WARNING)
- }
- }
- }
-
- private fun visitDirective(
- directiveElement: GraphQLDirective,
- holder: ProblemsHolder,
- definitions: List,
- definitionsUrl: String,
- highlightType: ProblemHighlightType,
- ) {
- if (directiveElement.name !in definitions.directives().map { it.name }) return
- val message =
- if (highlightType == ProblemHighlightType.WEAK_WARNING) "inspection.missingGraphQLDefinitionImport.reportText.warning" else "inspection.missingGraphQLDefinitionImport.reportText.error"
- if (!directiveElement.isImported(definitionsUrl)) {
- val typeKind = ApolloBundle.message("inspection.missingGraphQLDefinitionImport.reportText.directive")
- holder.registerProblem(
- directiveElement,
- ApolloBundle.message(message, typeKind, directiveElement.name!!),
- highlightType,
- ImportDefinitionQuickFix(typeKind = typeKind, elementName = directiveElement.name!!, definitions = definitions, definitionsUrl = definitionsUrl),
- )
- } else {
- val directiveDefinition = definitions.directives().firstOrNull { it.name == directiveElement.name } ?: return
- val knownDefinitionNames = definitions.filterIsInstance().map { it.name }
- val arguments = directiveElement.arguments?.argumentList.orEmpty()
- for (argument in arguments) {
- val argumentDefinition = directiveDefinition.arguments.firstOrNull { it.name == argument.name } ?: continue
- val argumentTypeToImport = argumentDefinition.type.rawType().name.takeIf { it in knownDefinitionNames } ?: continue
- if (!isImported(directiveElement, argumentTypeToImport, definitionsUrl)) {
- val typeKind = getTypeKind(argumentTypeToImport)
- holder.registerProblem(
- argument,
- ApolloBundle.message(message, typeKind, argumentTypeToImport),
- highlightType,
- ImportDefinitionQuickFix(typeKind = typeKind, elementName = argumentTypeToImport, definitions = definitions, definitionsUrl = definitionsUrl),
- )
- }
- }
- }
- }
-}
-
-private fun getTypeKind(typeName: String): String {
- val typeDefinition = NULLABILITY_DEFINITIONS.firstOrNull { it is GQLNamed && it.name == typeName } ?: return "unknown"
- return ApolloBundle.message(
- when (typeDefinition) {
- is GQLDirectiveDefinition -> "inspection.missingGraphQLDefinitionImport.reportText.directive"
- is GQLEnumTypeDefinition -> "inspection.missingGraphQLDefinitionImport.reportText.enum"
- is GQLInputObjectTypeDefinition -> "inspection.missingGraphQLDefinitionImport.reportText.input"
- is GQLScalarTypeDefinition -> "inspection.missingGraphQLDefinitionImport.reportText.scalar"
- else -> return "unknown"
- }
- )
-}
-
-private class ImportDefinitionQuickFix(
- val typeKind: String,
- val elementName: String,
- private val definitions: List,
- private val definitionsUrl: String,
-) : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.missingGraphQLDefinitionImport.quickFix", typeKind, "'$elementName'")
- override fun getFamilyName() = name
-
- override fun availableInBatchMode() = false
- override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjMissingGraphQLDefinitionImportQuickFix())
-
- val element = descriptor.psiElement.parentOfType(withSelf = true)!!
- val schemaFiles = element.schemaFiles()
- val linkDirective = schemaFiles.flatMap { it.linkDirectives(definitionsUrl) }.firstOrNull()
-
- if (linkDirective == null) {
- val linkDirectiveSchemaExtension =
- createLinkDirectiveSchemaExtension(project, setOf(element.nameForImport), definitions, definitionsUrl)
- val extraSchemaFile = (element.containingFile as? GraphQLFile)?.takeIf { it.name == "extra.graphqls" }
- ?: schemaFiles.firstOrNull { it.name == "extra.graphqls" }
- if (extraSchemaFile == null) {
- GraphQLElementFactory.createFile(project, linkDirectiveSchemaExtension.text).also {
- // Save the file to the project
- it.name = "extra.graphqls"
- val directory = schemaFiles.firstOrNull()?.containingDirectory ?: element.containingFile.containingDirectory ?: return
- directory.add(it)
-
- // There's a new schema file, reload the configuration
- project.gradleToolingModelService.triggerFetchToolingModels()
- }
- } else {
- val addedElement = extraSchemaFile.addBefore(linkDirectiveSchemaExtension, extraSchemaFile.firstChild)
- extraSchemaFile.addAfter(GraphQLElementFactory.createWhiteSpace(project, "\n\n"), addedElement)
- }
- } else {
- val importedNames = buildSet {
- addAll(linkDirective.arguments!!.argumentList.firstOrNull { it.name == "import" }?.value?.cast()?.valueList.orEmpty()
- .map { it.text.unquoted() })
- add(element.nameForImport)
- }
- linkDirective.replace(createLinkDirective(project, importedNames, definitions, definitionsUrl))
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfGraphQLViolationInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfGraphQLViolationInspection.kt
deleted file mode 100644
index a4d089b9fbc..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfGraphQLViolationInspection.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.navigation.findFragmentSpreads
-import com.apollographql.ijplugin.util.rawType
-import com.apollographql.ijplugin.util.resolve
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.jsgraphql.psi.GraphQLArgument
-import com.intellij.lang.jsgraphql.psi.GraphQLArrayValue
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLNonNullType
-import com.intellij.lang.jsgraphql.psi.GraphQLNullValue
-import com.intellij.lang.jsgraphql.psi.GraphQLObjectField
-import com.intellij.lang.jsgraphql.psi.GraphQLObjectValue
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLVariable
-import com.intellij.lang.jsgraphql.psi.GraphQLVariableDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLVisitor
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.parentOfType
-
-class ApolloOneOfGraphQLViolationInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : GraphQLVisitor() {
- override fun visitObjectValue(o: GraphQLObjectValue) {
- super.visitObjectValue(o)
- val parent = if (o.parent is GraphQLArrayValue) o.parent.parent else o.parent
- val inputValueDefinition: GraphQLInputValueDefinition = (parent as? GraphQLArgument ?: parent as? GraphQLObjectField)
- ?.resolve()
- ?: return
- val graphQLTypeName = inputValueDefinition.type?.rawType ?: return
- val graphQLInputObjectTypeDefinition: GraphQLInputObjectTypeDefinition = graphQLTypeName.resolve() ?: return
- val isOneOf = graphQLInputObjectTypeDefinition.directives.any { it.name == "oneOf" }
- if (!isOneOf) return
-
- if (o.objectFieldList.size != 1) {
- holder.registerProblem(o, ApolloBundle.message("inspection.oneOfGraphQLViolation.reportText.oneFieldMustBeSupplied", graphQLTypeName.name!!))
- } else {
- val field = o.objectFieldList.first()
- when (val value = field.value) {
- is GraphQLNullValue -> {
- holder.registerProblem(o, ApolloBundle.message("inspection.oneOfGraphQLViolation.reportText.fieldMustNotBeNull", field.name!!, graphQLTypeName.name!!))
- }
-
- is GraphQLVariable -> {
- // Look for the parent operation - if there isn't one, we're in a fragment: search for an operation using this fragment
- val operationDefinition = field.parentOfType()
- ?: field.parentOfType()?.let { fragmentParent ->
- findFragmentSpreads(fragmentParent.project) { it.nameIdentifier.reference?.resolve() == fragmentParent.nameIdentifier }.firstOrNull()
- ?.parentOfType()
- }
- ?: return
- val variableDefinition: GraphQLVariableDefinition = operationDefinition.variableDefinitions
- ?.variableDefinitions?.firstOrNull { it.variable.name == value.name }
- ?: return
- if (variableDefinition.type !is GraphQLNonNullType) {
- holder.registerProblem(
- o,
- ApolloBundle.message(
- "inspection.oneOfGraphQLViolation.reportText.variableMustBeNonNullType",
- value.name!!,
- variableDefinition.type?.text ?: "Unknown"
- )
- )
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfInputCreationInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfInputCreationInspection.kt
deleted file mode 100644
index d512cc125a9..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloOneOfInputCreationInspection.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.navigation.findInputTypeGraphQLDefinitions
-import com.apollographql.ijplugin.navigation.isApolloInputClass
-import com.apollographql.ijplugin.navigation.isApolloInputClassReference
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.util.apollo4
-import com.apollographql.ijplugin.util.canBeNull
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.className
-import com.apollographql.ijplugin.util.getCalleeExpressionIfAny
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.ProblemHighlightType
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.findTopmostParentOfType
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
-import org.jetbrains.kotlin.idea.references.mainReference
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtExpression
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-import org.jetbrains.kotlin.psi.KtVisitorVoid
-import org.jetbrains.kotlin.psi.psiUtil.containingClass
-
-class ApolloOneOfInputCreationInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : KtVisitorVoid() {
- private val alreadyVisitedBuildExpressions = mutableSetOf()
-
- // For constructor calls
- override fun visitCallExpression(expression: KtCallExpression) {
- super.visitCallExpression(expression)
- if (!expression.project.apolloProjectService.apolloVersion.isAtLeastV4) return
- val reference = (expression.calleeExpression.cast())
- if (reference?.isApolloInputClassReference() != true) return
- val inputTypeName = reference.text
- val inputTypeDefinition = findInputTypeGraphQLDefinitions(expression.project, inputTypeName).firstOrNull()
- ?.parentOfType()
- ?: return
- val isOneOf = inputTypeDefinition.directives.any { it.name == "oneOf" }
- if (!isOneOf) return
- if (expression.valueArguments.size != 1) {
- holder.registerProblem(expression.calleeExpression!!, ApolloBundle.message("inspection.oneOfInputCreation.reportText.constructor.wrongNumberOfArgs"))
- return
- }
- val arg = expression.valueArguments.first()
- if (arg.getArgumentExpression()?.className() == "$apollo4.api.Optional.Absent") {
- holder.registerProblem(expression.calleeExpression!!, ApolloBundle.message("inspection.oneOfInputCreation.reportText.constructor.argIsAbsent"))
- }
- }
-
- // For builder calls
- override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
- super.visitDotQualifiedExpression(expression)
- if (!expression.project.apolloProjectService.apolloVersion.isAtLeastV4) return
- val expressionClass =
- expression.selectorExpression.getCalleeExpressionIfAny()?.mainReference?.resolve()?.parentOfType(withSelf = true)
- ?: return
- if (expressionClass.name != "Builder") return
- val containingClass = expressionClass.containingClass() ?: return
- if (!containingClass.isApolloInputClass()) return
- val inputTypeName = containingClass.name ?: return
- val inputTypeDefinition = findInputTypeGraphQLDefinitions(expression.project, inputTypeName).firstOrNull()
- ?.parentOfType()
- ?: return
- val isOneOf = inputTypeDefinition.directives.any { it.name == "oneOf" }
- if (!isOneOf) return
- val arguments = expression.selectorExpression.cast()?.valueArguments ?: return
- // No arguments: we're on the MyInput.Builder() or .build() call
- if (arguments.size == 0) return
-
- val argumentExpression = arguments.first().getArgumentExpression()
- if (argumentExpression?.isNullExpression() == true) {
- // `null`
- holder.registerProblem(expression.selectorExpression!!, ApolloBundle.message("inspection.oneOfInputCreation.reportText.builder.argIsNull"))
- } else if (argumentExpression?.canBeNull() == true) {
- // a nullable type: warning only
- holder.registerProblem(expression.selectorExpression!!, ApolloBundle.message("inspection.oneOfInputCreation.reportText.builder.argIsNull"), ProblemHighlightType.WARNING)
- }
-
- val buildExpression = expression.findTopmostParentOfType() ?: return
- // If we've already visited the build expression it means several fields are being set in the same builder
- if (buildExpression in alreadyVisitedBuildExpressions) {
- holder.registerProblem(expression.selectorExpression!!, ApolloBundle.message("inspection.oneOfInputCreation.reportText.builder.wrongNumberOfArgs"))
- }
- alreadyVisitedBuildExpressions.add(buildExpression)
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloSchemaInGraphqlFileInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloSchemaInGraphqlFileInspection.kt
deleted file mode 100644
index 41b9671b795..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloSchemaInGraphqlFileInspection.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.jsgraphql.psi.GraphQLDirectiveDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLSchemaDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLVisitor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElementVisitor
-
-class ApolloSchemaInGraphqlFileInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : GraphQLVisitor() {
- override fun visitSchemaDefinition(o: GraphQLSchemaDefinition) {
- checkForInvalidFile(o)
- }
-
- override fun visitTypeDefinition(o: GraphQLTypeDefinition) {
- checkForInvalidFile(o)
- }
-
- override fun visitDirectiveDefinition(o: GraphQLDirectiveDefinition) {
- checkForInvalidFile(o)
- }
-
- private fun checkForInvalidFile(o: GraphQLElement) {
- val currentFileName = o.containingFile.name
- if (currentFileName.endsWith(".graphql")) {
- holder.registerProblem(o, ApolloBundle.message("inspection.schemaInGraphqlFile.reportText"), RenameToGraphqlsQuickFix(currentFileName))
- }
- }
- }
- }
-
- private class RenameToGraphqlsQuickFix(private val currentFileName: String) : LocalQuickFix {
- override fun getName(): String {
- val newFileName = currentFileName.replace(".graphql", ".graphqls")
- return ApolloBundle.message("inspection.schemaInGraphqlFile.quickFix", newFileName)
- }
- override fun getFamilyName() = name
-
- override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjSchemaInGraphqlFileQuickFix())
- val psiFile = descriptor.psiElement.containingFile
- val newName = psiFile.name.replace(".graphql", ".graphqls")
- psiFile.virtualFile.rename(this, newName)
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedFieldInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedFieldInspection.kt
deleted file mode 100644
index d8d32b1cbd8..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedFieldInspection.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.navigation.compat.KotlinFindUsagesHandlerFactoryCompat
-import com.apollographql.ijplugin.navigation.findKotlinFieldDefinitions
-import com.apollographql.ijplugin.navigation.findKotlinFragmentSpreadDefinitions
-import com.apollographql.ijplugin.navigation.findKotlinInlineFragmentDefinitions
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.isProcessCanceled
-import com.apollographql.ijplugin.util.matchingFieldCoordinates
-import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.codeInspection.ui.InspectionOptionsPanel
-import com.intellij.codeInspection.ui.ListEditForm
-import com.intellij.lang.jsgraphql.psi.GraphQLField
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread
-import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier
-import com.intellij.lang.jsgraphql.psi.GraphQLInlineFragment
-import com.intellij.lang.jsgraphql.psi.GraphQLSelection
-import com.intellij.lang.jsgraphql.psi.GraphQLTypeName
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLVisitor
-import com.intellij.openapi.project.Project
-import com.intellij.profile.codeInspection.ProjectInspectionProfileManager
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.findParentOfType
-import javax.swing.JComponent
-
-class ApolloUnusedFieldInspection : LocalInspectionTool() {
- @JvmField
- var fieldsToIgnore: MutableList = mutableListOf()
-
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- var isUnusedOperation = false
- return object : GraphQLVisitor() {
- override fun visitIdentifier(o: GraphQLIdentifier) {
- if (isProcessCanceled()) return
- if (!o.project.apolloProjectService.apolloVersion.isAtLeastV3) return
- if (isUnusedOperation) return
- val operation = o.findParentOfType()
- if (operation != null && isUnusedOperation(operation)) {
- // The whole operation is unused, no need to check the fields
- isUnusedOperation = true
- return
- }
-
- var isFragment = false
- val parent = o.parent
- val ktDefinitions = when (parent) {
- is GraphQLField -> findKotlinFieldDefinitions(parent)
- is GraphQLFragmentSpread -> {
- isFragment = true
- findKotlinFragmentSpreadDefinitions(parent)
- }
-
- is GraphQLTypeName -> {
- val inlineFragment = parent.parent?.parent as? GraphQLInlineFragment ?: return
- isFragment = true
- findKotlinInlineFragmentDefinitions(inlineFragment)
- }
-
- else -> return
- }.ifEmpty { return }
-
- val matchingFieldCoordinates: Collection = if (parent is GraphQLField) {
- matchingFieldCoordinates(o)
- } else {
- emptySet()
- }
- val shouldIgnoreField = fieldsToIgnore.any { fieldToIgnore ->
- matchingFieldCoordinates.any match@{ fieldCoordinates ->
- val regex = runCatching { Regex(fieldToIgnore) }.getOrNull() ?: return@match false
- fieldCoordinates.matches(regex)
- }
- }
- if (shouldIgnoreField) return
-
- val kotlinFindUsagesHandlerFactory = KotlinFindUsagesHandlerFactoryCompat(o.project)
- val hasUsageProcessor = HasUsageProcessor()
- for (kotlinDefinition in ktDefinitions) {
- if (kotlinFindUsagesHandlerFactory.canFindUsages(kotlinDefinition)) {
- val kotlinFindUsagesHandler = kotlinFindUsagesHandlerFactory.createFindUsagesHandler(kotlinDefinition, false)
- ?: return
- val findUsageOptions = kotlinFindUsagesHandlerFactory.findPropertyOptions ?: return
- kotlinFindUsagesHandler.processElementUsages(kotlinDefinition, hasUsageProcessor, findUsageOptions)
- if (hasUsageProcessor.foundUsage) return
- }
- }
- holder.registerProblem(
- if (isFragment) o.findParentOfType()!! else o,
- ApolloBundle.message("inspection.unusedField.reportText"),
- *buildList {
- add(DeleteElementQuickFix(label = "inspection.unusedField.quickFix.deleteField", telemetryEvent = { TelemetryEvent.ApolloIjUnusedFieldDeleteFieldQuickFix() }) { it.findParentOfType(strict = false)!! })
- for (matchingFieldCoordinate in matchingFieldCoordinates) {
- add(IgnoreFieldQuickFix(matchingFieldCoordinate))
- }
- }.toTypedArray()
- )
- }
- }
- }
-
- // In a future version of the platform we should use `AddToInspectionOptionListFix` instead.
- private inner class IgnoreFieldQuickFix(private val fieldCoordinates: String) : LocalQuickFix {
- override fun getName() = ApolloBundle.message("inspection.unusedField.quickFix.ignoreField", fieldCoordinates)
- override fun getFamilyName() = name
-
- override fun availableInBatchMode() = false
- override fun generatePreview(project: Project, previewDescriptor: ProblemDescriptor): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjUnusedFieldIgnoreFieldQuickFix())
- fieldsToIgnore += fieldCoordinates.replace(".", "\\.")
-
- // Save the inspection settings
- ProjectInspectionProfileManager.getInstance(project).fireProfileChanged()
- }
- }
-
- override fun createOptionsPanel(): JComponent {
- val form = ListEditForm(ApolloBundle.message("inspection.unusedField.options.fieldsToIgnore.title"), ApolloBundle.message("inspection.unusedField.options.fieldsToIgnore.label"), fieldsToIgnore)
- form.contentPanel.minimumSize = InspectionOptionsPanel.getMinimumListSize()
- return form.contentPanel
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedOperationInspection.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedOperationInspection.kt
deleted file mode 100644
index 9d1359f666d..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/ApolloUnusedOperationInspection.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.navigation.compat.KotlinFindUsagesHandlerFactoryCompat
-import com.apollographql.ijplugin.navigation.findKotlinOperationDefinitions
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.util.isProcessCanceled
-import com.intellij.codeInspection.LocalInspectionTool
-import com.intellij.codeInspection.ProblemsHolder
-import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLVisitor
-import com.intellij.psi.PsiElementVisitor
-import com.intellij.psi.util.childrenOfType
-
-class ApolloUnusedOperationInspection : LocalInspectionTool() {
- override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
- return object : GraphQLVisitor() {
- override fun visitTypedOperationDefinition(o: GraphQLTypedOperationDefinition) {
- if (isUnusedOperation(o)) {
- val nameElement = o.childrenOfType().firstOrNull() ?: return
- holder.registerProblem(
- nameElement,
- ApolloBundle.message("inspection.unusedOperation.reportText"),
- DeleteElementQuickFix(label = "inspection.unusedOperation.quickFix", telemetryEvent = { TelemetryEvent.ApolloIjUnusedOperationQuickFix() }) { it.parent }
- )
- }
- }
- }
- }
-}
-
-fun isUnusedOperation(operationDefinition: GraphQLTypedOperationDefinition): Boolean {
- if (isProcessCanceled()) return false
- if (!operationDefinition.project.apolloProjectService.apolloVersion.isAtLeastV3) return false
- val ktClasses = findKotlinOperationDefinitions(operationDefinition).ifEmpty {
- // Didn't find any generated class: maybe in the middle of writing a new operation, let's not report an error yet.
- return false
- }
- val kotlinFindUsagesHandlerFactory = KotlinFindUsagesHandlerFactoryCompat(operationDefinition.project)
- val hasUsageProcessor = HasUsageProcessor()
- for (kotlinDefinition in ktClasses) {
- if (kotlinFindUsagesHandlerFactory.canFindUsages(kotlinDefinition)) {
- val kotlinFindUsagesHandler = kotlinFindUsagesHandlerFactory.createFindUsagesHandler(kotlinDefinition, false)
- ?: return false
- val findUsageOptions = kotlinFindUsagesHandlerFactory.findClassOptions ?: return false
- kotlinFindUsagesHandler.processElementUsages(kotlinDefinition, hasUsageProcessor, findUsageOptions)
- if (hasUsageProcessor.foundUsage) return false
- }
- }
- return true
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/DeleteElementQuickFix.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/DeleteElementQuickFix.kt
deleted file mode 100644
index 391aad514ee..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/DeleteElementQuickFix.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.codeInspection.LocalQuickFix
-import com.intellij.codeInspection.ProblemDescriptor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-
-class DeleteElementQuickFix(
- private val label: String,
-
- @SafeFieldForPreview
- private val telemetryEvent: () -> TelemetryEvent,
-
- @SafeFieldForPreview
- private val elementToDelete: (PsiElement) -> PsiElement,
-) : LocalQuickFix {
- override fun getName() = ApolloBundle.message(label)
-
- override fun getFamilyName() = name
-
- override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(telemetryEvent())
- elementToDelete(descriptor.psiElement).delete()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLInspectionSuppressor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLInspectionSuppressor.kt
deleted file mode 100644
index 82f5495d814..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLInspectionSuppressor.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.intellij.codeInspection.InspectionSuppressor
-import com.intellij.codeInspection.SuppressQuickFix
-import com.intellij.codeInspection.SuppressionUtil
-import com.intellij.lang.jsgraphql.ide.validation.fixes.GraphQLSuppressByCommentFix
-import com.intellij.lang.jsgraphql.psi.GraphQLField
-import com.intellij.psi.PsiComment
-import com.intellij.psi.PsiElement
-import com.intellij.psi.util.PsiTreeUtil
-import java.util.regex.Pattern
-
-private val SUPPRESS_IN_LINE_COMMENT_PATTERN = Pattern.compile("#" + SuppressionUtil.COMMON_SUPPRESS_REGEXP)
-
-class GraphQLInspectionSuppressor : InspectionSuppressor {
- override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean {
- return element.isSuppressedOnSelfOrParent(toolId, SUPPRESS_IN_LINE_COMMENT_PATTERN)
- }
-
- override fun getSuppressActions(
- element: PsiElement?,
- toolId: String,
- ): Array {
- return if (element == null) {
- SuppressQuickFix.EMPTY_ARRAY
- } else {
- arrayOf(
- GraphQLSuppressByCommentFix(toolId, GraphQLField::class.java, ApolloBundle.message("inspection.suppress.field")),
- )
- }
- }
-}
-
-fun PsiElement.isSuppressedOnSelfOrParent(
- toolId: String,
- suppressInLineCommentPattern: Pattern,
-): Boolean {
- var element: PsiElement? = this
- while (element != null) {
- val prev = PsiTreeUtil.skipWhitespacesBackward(element)
- if (prev is PsiComment) {
- val text = prev.getText()
- val matcher = suppressInLineCommentPattern.matcher(text)
- if (matcher.matches() && SuppressionUtil.isInspectionToolIdMentioned(matcher.group(1), toolId)) {
- return true
- }
- }
- element = element.parent
- }
- return false
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLUnresolvedReferenceInspectionSuppressor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLUnresolvedReferenceInspectionSuppressor.kt
deleted file mode 100644
index aadefabec30..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/GraphQLUnresolvedReferenceInspectionSuppressor.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.apollo.annotations.ApolloInternal
-import com.apollographql.apollo.ast.GQLDirectiveDefinition
-import com.apollographql.apollo.ast.linkDefinitions
-import com.apollographql.ijplugin.util.KOTLIN_LABS_DEFINITIONS
-import com.apollographql.ijplugin.util.NULLABILITY_DEFINITIONS
-import com.apollographql.ijplugin.util.NULLABILITY_URL
-import com.apollographql.ijplugin.util.directives
-import com.apollographql.ijplugin.util.isImported
-import com.apollographql.ijplugin.util.nameWithoutPrefix
-import com.intellij.codeInspection.InspectionSuppressor
-import com.intellij.codeInspection.SuppressQuickFix
-import com.intellij.lang.jsgraphql.psi.GraphQLArgument
-import com.intellij.lang.jsgraphql.psi.GraphQLDirective
-import com.intellij.lang.jsgraphql.psi.GraphQLDirectivesAware
-import com.intellij.psi.PsiElement
-
-@OptIn(ApolloInternal::class)
-private val KNOWN_DIRECTIVES: List by lazy {
- linkDefinitions().directives() + NULLABILITY_DEFINITIONS.directives() + KOTLIN_LABS_DEFINITIONS.directives()
-}
-
-/**
- * Do not highlight certain known directives as unresolved references.
- *
- * Note: we'll need this workaround until there is a way for a plugin to provide their own known definitions to the GraphQL plugin.
- * See https://github.com/JetBrains/js-graphql-intellij-plugin/issues/697.
- */
-class GraphQLUnresolvedReferenceInspectionSuppressor : InspectionSuppressor {
- override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean {
- val parent = element.parent ?: return false
- return when (toolId) {
- "GraphQLUnresolvedReference" -> parent.isKnownDirective() || parent.isKnownDirectiveArgument()
-
- "GraphQLMissingType" -> element is GraphQLDirectivesAware && element.directives.all { it.isKnownDirective() }
-
- // We need to suppress this one too because the plugin doesn't know that certain directives (e.g. @link) are repeatable
- "GraphQLDuplicateDirective" -> element is GraphQLDirective &&
- KNOWN_DIRECTIVES.any { it.name == element.name && it.repeatable }
-
- else -> false
- }
- }
-
- override fun getSuppressActions(psiElement: PsiElement?, s: String): Array = SuppressQuickFix.EMPTY_ARRAY
-}
-
-private fun PsiElement.isKnownDirective(): Boolean {
- return this is GraphQLDirective && (name in KNOWN_DIRECTIVES.map { it.name } || this.isImported(NULLABILITY_URL))
-}
-
-private fun PsiElement.isKnownDirectiveArgument(): Boolean {
- return this is GraphQLArgument &&
- parent?.parent?.isKnownDirective() == true &&
- name in KNOWN_DIRECTIVES.firstOrNull { it.name == (parent.parent as GraphQLDirective).nameWithoutPrefix }?.arguments?.map { it.name }
- .orEmpty()
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/HasUsageProcessor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/HasUsageProcessor.kt
deleted file mode 100644
index 906240551b8..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/inspection/HasUsageProcessor.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.apollographql.ijplugin.inspection
-
-import com.apollographql.ijplugin.util.isGenerated
-import com.intellij.usageView.UsageInfo
-import com.intellij.util.Processor
-
-class HasUsageProcessor : Processor {
- var foundUsage = false
- private set
-
- override fun process(usageInfo: UsageInfo): Boolean {
- if (usageInfo.virtualFile?.isGenerated(usageInfo.project) == false) {
- foundUsage = true
- return false
- }
- return true
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/intention/ApolloInputConstructorChangeToBuilderIntention.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/intention/ApolloInputConstructorChangeToBuilderIntention.kt
deleted file mode 100644
index 65c6c785281..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/intention/ApolloInputConstructorChangeToBuilderIntention.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.apollographql.ijplugin.intention
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.inspection.ChangeToBuilderQuickFix
-import com.apollographql.ijplugin.navigation.isApolloInputClassReference
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.getParameterNames
-import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
-import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.impl.source.tree.LeafPsiElement
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-
-class ApolloInputConstructorChangeToBuilderIntention : PsiElementBaseIntentionAction() {
- override fun getText() = ApolloBundle.message("intention.InputConstructorChangeToBuilder.name.editor")
- override fun getFamilyName() = ApolloBundle.message("intention.InputConstructorChangeToBuilder.name.settings")
-
- override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
- if (!element.project.apolloProjectService.apolloVersion.isAtLeastV4) return false
- val callExpression = (element as? LeafPsiElement)?.parent?.parent as? KtCallExpression ?: return false
- val reference = callExpression.calleeExpression.cast() ?: return false
- return reference.isApolloInputClassReference()
- }
-
- override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
- if (!IntentionPreviewUtils.isIntentionPreviewActive()) project.telemetryService.logEvent(TelemetryEvent.ApolloIjInputConstructorChangeToBuilderIntentionApply())
- val callExpression = element.parent.parent as KtCallExpression
- val parameterNames = callExpression.getParameterNames() ?: return
- ChangeToBuilderQuickFix(parameterNames).applyFix(project, callExpression)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lang/ApolloGraphQLLanguage.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lang/ApolloGraphQLLanguage.kt
deleted file mode 100644
index 60a87e09511..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lang/ApolloGraphQLLanguage.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.apollographql.ijplugin.lang
-
-import com.intellij.lang.Language
-
-class ApolloGraphQLLanguage : Language("ApolloGraphQL") {
- companion object {
- @JvmField
- val INSTANCE: ApolloGraphQLLanguage = ApolloGraphQLLanguage()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspAppService.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspAppService.kt
deleted file mode 100644
index 6f99081391a..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspAppService.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.apollographql.ijplugin.lsp
-
-import com.apollographql.ijplugin.settings.AppSettingsListener
-import com.apollographql.ijplugin.settings.AppSettingsState
-import com.apollographql.ijplugin.settings.ProjectSettingsListener
-import com.apollographql.ijplugin.settings.ProjectSettingsState
-import com.apollographql.ijplugin.settings.appSettingsState
-import com.apollographql.ijplugin.settings.projectSettingsState
-import com.apollographql.ijplugin.util.logd
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.runWriteAction
-import com.intellij.openapi.components.Service
-import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.guessProjectDir
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.openapi.vfs.newvfs.BulkFileListener
-import com.intellij.openapi.vfs.newvfs.events.VFileEvent
-import com.intellij.util.application
-
-@Service(Service.Level.APP)
-class ApolloLspAppService : Disposable {
- init {
- logd()
- startObserveSettings()
- }
-
- private fun startObserveSettings() {
- logd()
- application.messageBus.connect(this).subscribe(AppSettingsListener.TOPIC, object : AppSettingsListener {
- var lspModeEnabled = appSettingsState.lspModeEnabled
- override fun settingsChanged(appSettingsState: AppSettingsState) {
- val lspModeEnabledChanged = lspModeEnabled != appSettingsState.lspModeEnabled
- lspModeEnabled = appSettingsState.lspModeEnabled
- logd("lspModeEnabledChanged=$lspModeEnabledChanged")
- if (lspModeEnabledChanged) {
- runWriteAction {
- FileTypeManagerEx.getInstanceEx().makeFileTypesChange("Apollo GraphQL file type change", {})
- }
- restartApolloLsp()
- }
- }
- })
- }
-
- override fun dispose() {
- logd()
- }
-}
-
-@Service(Service.Level.PROJECT)
-class ApolloLspProjectService(private val project: Project) : Disposable {
- init {
- logd()
- startObserveSettings()
- startObserveVfsChanges()
- }
-
- private fun startObserveSettings() {
- logd()
- project.messageBus.connect(this).subscribe(ProjectSettingsListener.TOPIC, object : ProjectSettingsListener {
- var lspPassPathToSuperGraphYaml = project.projectSettingsState.lspPassPathToSuperGraphYaml
- var lspPathToSuperGraphYaml = project.projectSettingsState.lspPathToSuperGraphYaml
- var lspPassAdditionalArguments = project.projectSettingsState.lspPassAdditionalArguments
- var lspAdditionalArguments = project.projectSettingsState.lspAdditionalArguments
-
- override fun settingsChanged(projectSettingsState: ProjectSettingsState) {
- val lspPassPathToSuperGraphYamlChanged = lspPassPathToSuperGraphYaml != projectSettingsState.lspPassPathToSuperGraphYaml
- val lspPathToSuperGraphYamlChanged = lspPathToSuperGraphYaml != projectSettingsState.lspPathToSuperGraphYaml
- val lspPassAdditionalArgumentsChanged = lspPassAdditionalArguments != projectSettingsState.lspPassAdditionalArguments
- val lspAdditionalArgumentsChanged = lspAdditionalArguments != projectSettingsState.lspAdditionalArguments
- lspPassPathToSuperGraphYaml = projectSettingsState.lspPassPathToSuperGraphYaml
- lspPathToSuperGraphYaml = projectSettingsState.lspPathToSuperGraphYaml
- lspPassAdditionalArguments = projectSettingsState.lspPassAdditionalArguments
- lspAdditionalArguments = projectSettingsState.lspAdditionalArguments
- logd("lspPassPathToSuperGraphYamlChanged=$lspPassPathToSuperGraphYamlChanged lspPathToSuperGraphYamlChanged=$lspPathToSuperGraphYamlChanged lspPassAdditionalArgumentsChanged=$lspPassAdditionalArgumentsChanged lspAdditionalArgumentsChanged=$lspAdditionalArgumentsChanged")
- if (lspPassPathToSuperGraphYamlChanged || lspPathToSuperGraphYamlChanged || lspPassAdditionalArgumentsChanged || lspAdditionalArgumentsChanged) {
- restartApolloLsp()
- }
- }
- })
- }
-
- private fun startObserveVfsChanges() {
- project.messageBus.connect(this).subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
- override fun after(events: MutableList) {
- for (event in events) {
- val vFile = event.file!!
- val isSupergraphYaml = vFile == project.guessProjectDir()?.findChild("supergraph.yaml") ||
- vFile.path == project.projectSettingsState.lspPathToSuperGraphYaml
- if (isSupergraphYaml) {
- logd("supergraph.yaml changed: restarting Apollo LSP")
- restartApolloLsp()
- }
- }
- }
- })
- }
-
- override fun dispose() {
- logd()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspServerSupportProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspServerSupportProvider.kt
deleted file mode 100644
index 38ab99451cf..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/lsp/ApolloLspServerSupportProvider.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-@file:Suppress("UnstableApiUsage")
-
-package com.apollographql.ijplugin.lsp
-
-import com.apollographql.ijplugin.file.ApolloGraphQLFileType
-import com.apollographql.ijplugin.icons.ApolloIcons
-import com.apollographql.ijplugin.rover.RoverHelper
-import com.apollographql.ijplugin.settings.appSettingsState
-import com.apollographql.ijplugin.settings.lsp.LspSettingsConfigurable
-import com.intellij.openapi.application.runInEdt
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.ProjectManager
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.platform.lsp.api.LspServer
-import com.intellij.platform.lsp.api.LspServerManager
-import com.intellij.platform.lsp.api.LspServerSupportProvider
-import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor
-import com.intellij.platform.lsp.api.lsWidget.LspServerWidgetItem
-
-internal class ApolloLspServerSupportProvider : LspServerSupportProvider {
- override fun fileOpened(project: Project, file: VirtualFile, serverStarter: LspServerSupportProvider.LspServerStarter) {
- if (appSettingsState.lspModeEnabled && file.extension in ApolloGraphQLFileType.SUPPORTED_EXTENSIONS) {
- serverStarter.ensureServerStarted(ApolloLspServerDescriptor(project))
- }
- }
-
- override fun createLspServerWidgetItem(lspServer: LspServer, currentFile: VirtualFile?): LspServerWidgetItem {
- return LspServerWidgetItem(
- lspServer = lspServer,
- currentFile = currentFile,
- icon = ApolloIcons.StatusBar.Apollo,
- settingsPageClass = LspSettingsConfigurable::class.java,
- )
- }
-}
-
-private class ApolloLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Apollo") {
- override fun isSupportedFile(file: VirtualFile) = file.extension in ApolloGraphQLFileType.SUPPORTED_EXTENSIONS
- override fun createCommandLine() = RoverHelper.getLspCommandLine(project)
-
- override fun getLanguageId(file: VirtualFile): String {
- return "graphql"
- }
-}
-
-fun restartApolloLsp() {
- runInEdt {
- for (project in ProjectManager.getInstance().openProjects) {
- LspServerManager.getInstance(project).stopAndRestartIfNeeded(ApolloLspServerSupportProvider::class.java)
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLCustomUsageSearcher.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLCustomUsageSearcher.kt
deleted file mode 100644
index 98466a4400d..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLCustomUsageSearcher.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.navigation.compat.KotlinFindUsagesHandlerFactoryCompat
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.util.isGenerated
-import com.intellij.find.findUsages.CustomUsageSearcher
-import com.intellij.find.findUsages.FindUsagesOptions
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumValue
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypeNameDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.openapi.application.runReadAction
-import com.intellij.psi.PsiElement
-import com.intellij.usageView.UsageInfo
-import com.intellij.usages.Usage
-import com.intellij.usages.UsageInfo2UsageAdapter
-import com.intellij.util.Processor
-
-/**
- * Allows to find usages of the corresponding Kotlin generated code when invoking 'Find Usages' on GraphQL elements:
- * - operation definition
- * - fragment definition
- * - enum type/value
- * - input type/field
- *
- * TODO: operation/fragment field is missing for now because the GraphQL PSI doesn't provide the necessary information
- */
-class GraphQLCustomUsageSearcher : CustomUsageSearcher() {
- override fun processElementUsages(element: PsiElement, processor: Processor, options: FindUsagesOptions) {
- if (element !is GraphQLElement) return
-
- runReadAction {
- if (!element.project.apolloProjectService.apolloVersion.isAtLeastV3) return@runReadAction
-
- var isProperty = false
- val kotlinDefinitions = when (val parent = element.parent) {
- is GraphQLTypedOperationDefinition -> {
- findKotlinOperationDefinitions(parent)
- }
-
- is GraphQLFragmentDefinition -> {
- findKotlinFragmentClassDefinitions(parent)
- }
-
- is GraphQLTypeNameDefinition -> {
- when (val grandParent = parent.parent) {
- is GraphQLEnumTypeDefinition -> findKotlinEnumClassDefinitions(grandParent)
- is GraphQLInputObjectTypeDefinition -> findKotlinInputClassDefinitions(grandParent)
- else -> emptyList()
- }
- }
-
- is GraphQLEnumValue -> {
- findKotlinEnumValueDefinitions(parent)
- }
-
- is GraphQLInputValueDefinition -> {
- isProperty = true
- findKotlinInputFieldDefinitions(parent)
- }
-
- else -> emptyList()
-
- }.ifEmpty { return@runReadAction }
- val kotlinFindUsagesHandlerFactory = KotlinFindUsagesHandlerFactoryCompat(element.project)
- val ignoreGeneratedFilesProcessor = IgnoreGeneratedFilesProcessor(processor)
- for (kotlinDefinition in kotlinDefinitions) {
- if (kotlinFindUsagesHandlerFactory.canFindUsages(kotlinDefinition)) {
- val kotlinFindUsagesHandler = kotlinFindUsagesHandlerFactory.createFindUsagesHandler(kotlinDefinition, false)
- ?: return@runReadAction
- val findUsageOptions = if (isProperty) {
- kotlinFindUsagesHandlerFactory.findPropertyOptions
- } else {
- kotlinFindUsagesHandlerFactory.findClassOptions
- } ?: return@runReadAction
- kotlinFindUsagesHandler.processElementUsages(kotlinDefinition, ignoreGeneratedFilesProcessor, findUsageOptions)
- }
- }
- }
- }
-}
-
-private class IgnoreGeneratedFilesProcessor(private val processor: Processor) : Processor {
- override fun process(usageInfo: UsageInfo): Boolean {
- if (usageInfo.virtualFile?.isGenerated(usageInfo.project) != true) {
- processor.process(UsageInfo2UsageAdapter(usageInfo))
- }
- return true
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLGotoDeclarationHandler.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLGotoDeclarationHandler.kt
deleted file mode 100644
index b17ec7c1984..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLGotoDeclarationHandler.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumValue
-import com.intellij.lang.jsgraphql.psi.GraphQLField
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypeNameDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.options.advanced.AdvancedSettings
-import com.intellij.psi.PsiElement
-
-/**
- * Allows to navigate to the corresponding Kotlin generated code when middle-clicking/cmd-clicking/cmd-b on GraphQL elements:
- * - operation
- * - fragment
- * - field
- * - enum type/value
- * - input type/field
- */
-class GraphQLGotoDeclarationHandler : GotoDeclarationHandler {
- override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array? {
- val gqlElement = sourceElement?.parent?.parent as? GraphQLElement ?: return null
- if (!gqlElement.project.apolloProjectService.apolloVersion.isAtLeastV3) return null
- val enabledInAdvancedSettings = AdvancedSettings.getBoolean("apollo.graphQLGoToDeclarationGeneratedCode")
-
- val kotlinDefinitions = when (gqlElement) {
- is GraphQLTypedOperationDefinition -> {
- findKotlinOperationDefinitions(gqlElement)
- }
-
- is GraphQLFragmentDefinition -> {
- findKotlinFragmentClassDefinitions(gqlElement)
- }
-
- is GraphQLFragmentSpread -> {
- if (!enabledInAdvancedSettings) return null
- findKotlinFragmentClassDefinitions(gqlElement)
- }
-
- is GraphQLField -> {
- if (!enabledInAdvancedSettings) return null
- findKotlinFieldDefinitions(gqlElement)
- }
-
- is GraphQLTypeNameDefinition -> {
- if (!enabledInAdvancedSettings) return null
- when (val parent = gqlElement.parent) {
- is GraphQLEnumTypeDefinition -> findKotlinEnumClassDefinitions(parent)
- is GraphQLInputObjectTypeDefinition -> findKotlinInputClassDefinitions(parent)
- else -> return null
- }
- }
-
- is GraphQLEnumValue -> {
- if (!enabledInAdvancedSettings) return null
- findKotlinEnumValueDefinitions(gqlElement)
- }
-
- is GraphQLInputValueDefinition -> {
- if (!enabledInAdvancedSettings) return null
- findKotlinInputFieldDefinitions(gqlElement)
- }
-
- else -> return null
- }
-
- return buildList {
- // Add the original referred to element
- val resolvedElement = sourceElement.parent?.reference?.resolve()
- if (resolvedElement != null) {
- add(resolvedElement)
- } else {
- // Special case for Fragment declaration: we switch to the Fragment's usages
- if (gqlElement is GraphQLFragmentDefinition) {
- addAll(findFragmentSpreads(gqlElement.project) { it.nameIdentifier.reference?.resolve() == gqlElement.nameIdentifier })
- }
- }
-
- // Add Kotlin definition(s)
- addAll(kotlinDefinitions.map { it.logNavigation { TelemetryEvent.ApolloIjNavigateToKotlin() } })
- }.toTypedArray()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLNavigation.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLNavigation.kt
deleted file mode 100644
index 0bdf0517047..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/GraphQLNavigation.kt
+++ /dev/null
@@ -1,389 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.util.allSuperTypes
-import com.apollographql.ijplugin.util.apollo3
-import com.apollographql.ijplugin.util.apollo4
-import com.apollographql.ijplugin.util.asKtClass
-import com.apollographql.ijplugin.util.capitalizeFirstLetter
-import com.apollographql.ijplugin.util.className
-import com.apollographql.ijplugin.util.containingKtFile
-import com.apollographql.ijplugin.util.findChildrenOfType
-import com.apollographql.ijplugin.util.resolveKtName
-import com.apollographql.ijplugin.util.shortName
-import com.apollographql.ijplugin.util.typeArgumentClassName
-import com.intellij.lang.jsgraphql.GraphQLFileType
-import com.intellij.lang.jsgraphql.psi.GraphQLDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumValue
-import com.intellij.lang.jsgraphql.psi.GraphQLField
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread
-import com.intellij.lang.jsgraphql.psi.GraphQLInlineFragment
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLOperationDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLRecursiveVisitor
-import com.intellij.lang.jsgraphql.psi.GraphQLSelectionSet
-import com.intellij.lang.jsgraphql.psi.GraphQLTypeNameDefinition
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiComment
-import com.intellij.psi.PsiManager
-import com.intellij.psi.PsiNamedElement
-import com.intellij.psi.search.FileTypeIndex
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.descendantsOfType
-import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtElement
-import org.jetbrains.kotlin.psi.KtEnumEntry
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtProperty
-import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
-import org.jetbrains.kotlin.psi.psiUtil.containingClass
-
-private val APOLLO_OPERATION_TYPES = setOf(
- FqName("$apollo3.api.Query"),
- FqName("$apollo3.api.Mutation"),
- FqName("$apollo3.api.Subscription"),
-
- FqName("$apollo4.api.Query"),
- FqName("$apollo4.api.Mutation"),
- FqName("$apollo4.api.Subscription"),
-)
-
-private val APOLLO_FRAGMENT_TYPE = setOf(
- FqName("$apollo3.api.Fragment.Data"),
- FqName("$apollo4.api.Fragment.Data"),
-)
-
-private val APOLLO_ENUM_TYPE = setOf(
- "$apollo3.api.EnumType",
- "$apollo4.api.EnumType",
-)
-
-fun KtNameReferenceExpression.isApolloOperationOrFragmentReference(): Boolean {
- return resolveKtName()?.asKtClass()?.isApolloOperationOrFragment() == true
-}
-
-fun KtNameReferenceExpression.isApolloModelFieldReference(): Boolean {
- val resolved = resolveKtName()
- // Parameter is for data classes, property is for interfaces
- return (resolved is KtParameter || resolved is KtProperty) &&
- (resolved as KtElement).isApolloModelField()
-}
-
-fun KtElement.isApolloModelField() = topMostContainingClass()
- ?.isApolloOperationOrFragment() == true
-
-
-fun KtClass.isApolloOperation(): Boolean {
- return superTypeListEntries.any {
- val superType = it.typeAsUserType?.referenceExpression?.resolveKtName()?.kotlinFqName
- superType in APOLLO_OPERATION_TYPES
- }
-}
-
-fun KtClass.isApolloFragment(): Boolean {
- return allSuperTypes().any {
- it.fqName in APOLLO_FRAGMENT_TYPE
- } ||
- // Fallback for fragments in responseBased codegen: they are interfaces generated in a .fragment package.
- // This can lead to false positives, but consequences are not dire.
- isInterface() && kotlinFqName?.parent()?.shortName == "fragment" && hasGeneratedByApolloComment()
-}
-
-fun KtClass.isApolloOperationOrFragment(): Boolean {
- return allSuperTypes().any {
- it.fqName in APOLLO_OPERATION_TYPES || it.fqName in APOLLO_FRAGMENT_TYPE
- } ||
- // Fallback for fragments in responseBased codegen: they are interfaces generated in a .fragment package.
- // This can lead to false positives, but consequences are not dire.
- isInterface() && kotlinFqName?.parent()?.shortName == "fragment" && hasGeneratedByApolloComment()
-}
-
-fun KtNameReferenceExpression.isApolloEnumClassReference(): Boolean {
- val ktClass = resolveKtName() as? KtClass ?: return false
- return ktClass.isApolloEnumClass()
-}
-
-fun KtClass.isApolloEnumClass() = isEnum() &&
- // Apollo enums have a companion object that has a property named "type" of type EnumType
- isEnum() && companionObjects.any { companion ->
- companion.declarations.filterIsInstance().any { property ->
- property.name == "type" &&
- property.className() in APOLLO_ENUM_TYPE
- }
-}
-
-fun KtNameReferenceExpression.isApolloEnumValueReference(): Boolean {
- val ktEnumEntry = resolveKtName() as? KtEnumEntry ?: return false
- return ktEnumEntry.containingClass()?.isApolloEnumClass() == true
-}
-
-fun KtNameReferenceExpression.isApolloInputClassReference(): Boolean {
- return resolveKtName()?.asKtClass()?.isApolloInputClass() == true
-}
-
-fun KtClass.isApolloInputClass(): Boolean {
- // Apollo input classes are data classes, generated in a package named "type", and we also look at the header comment.
- // This can lead to false positives, but consequences are not dire.
- return isData() &&
- kotlinFqName?.parent()?.shortName == "type" &&
- hasGeneratedByApolloComment()
-}
-
-fun KtNameReferenceExpression.isApolloInputFieldReference(): Boolean {
- val resolved = resolveKtName()
- // Parameter is for data classes, property is for interfaces
- return (resolved is KtParameter || resolved is KtProperty) &&
- (resolved as KtElement).topMostContainingClass()
- ?.isApolloInputClass() == true
-}
-
-private fun KtElement.hasGeneratedByApolloComment() =
- containingKtFile()?.descendantsOfType()?.any { it.text.contains("generated by Apollo GraphQL") } == true
-
-private fun KtElement.topMostContainingClass(): KtClass? {
- return if (containingClass() == null) {
- this as? KtClass
- } else {
- containingClass()!!.topMostContainingClass()
- }
-}
-
-private fun findGraphQLDefinitions(project: Project, predicate: (GraphQLDefinition) -> Boolean): List {
- return FileTypeIndex.getFiles(GraphQLFileType.INSTANCE, GlobalSearchScope.allScope(project)).flatMap { virtualFile ->
- PsiManager.getInstance(project).findFile(virtualFile)
- ?.findChildrenOfType()
- ?.filter { predicate(it) }
- ?: emptyList()
- }
-}
-
-fun findOperationOrFragmentGraphQLDefinitions(project: Project, name: String): List {
- return findGraphQLDefinitions(project) { graphQLDefinition ->
- // Look for operation definitions
- graphQLDefinition is GraphQLOperationDefinition && (graphQLDefinition.name?.capitalizeFirstLetter() == name || graphQLDefinition.name?.capitalizeFirstLetter() == name.minusOperationTypeSuffix()) ||
- // Fallback: look for fragment definitions
- graphQLDefinition is GraphQLFragmentDefinition && graphQLDefinition.name?.capitalizeFirstLetter() == name
- }
-}
-
-fun findEnumTypeGraphQLDefinitions(project: Project, name: String): List {
- return findGraphQLDefinitions(project) {
- it is GraphQLEnumTypeDefinition && it.typeNameDefinition?.name?.capitalizeFirstLetter() == name.capitalizeFirstLetter()
- }
- .mapNotNull { (it as GraphQLEnumTypeDefinition).typeNameDefinition }
-}
-
-fun findEnumValueGraphQLDefinitions(nameReferenceExpression: KtNameReferenceExpression): List {
- val project = nameReferenceExpression.project
- val resolved = nameReferenceExpression.resolveKtName()
- val ktEnumEntry = resolved as? KtEnumEntry ?: return emptyList()
- // First argument (rawValue) of the super call is the original enum value name
- val enumValueName = (ktEnumEntry.initializerList?.initializers?.first() as? KtSuperTypeCallEntry)
- ?.valueArgumentList?.arguments?.first()
- ?.stringTemplateExpression?.entries?.first()?.text
- val enumTypeName = ktEnumEntry.containingClass()?.name ?: return emptyList()
- val enumTypeGqlDefinitions = findEnumTypeGraphQLDefinitions(project, enumTypeName)
- return enumTypeGqlDefinitions.flatMap { enumTypeDefinition ->
- (enumTypeDefinition.parent as GraphQLEnumTypeDefinition)
- .enumValueDefinitions?.enumValueDefinitionList
- ?.map { it.enumValue }
- ?.filter {
- it.name == enumValueName
- }
- ?: emptyList()
- }
-}
-
-fun findInputTypeGraphQLDefinitions(project: Project, name: String): List {
- return findGraphQLDefinitions(project) {
- it is GraphQLInputObjectTypeDefinition && it.typeNameDefinition?.name?.capitalizeFirstLetter() == name
- }
- .mapNotNull { (it as GraphQLInputObjectTypeDefinition).typeNameDefinition }
-}
-
-fun findInputFieldGraphQLDefinitions(nameReferenceExpression: KtNameReferenceExpression): List {
- val project = nameReferenceExpression.project
- val resolved = nameReferenceExpression.resolveKtName()
- val ktElement = if (resolved is KtParameter || resolved is KtProperty) resolved as KtElement else return emptyList()
- val inputClassName = ktElement.containingClass()?.name ?: return emptyList()
- return findInputTypeGraphQLDefinitions(project, inputClassName).flatMap {
- val inputObjectTypeDefinition = it.parent as GraphQLInputObjectTypeDefinition
- inputObjectTypeDefinition.inputObjectValueDefinitions?.inputValueDefinitionList?.filter {
- it.name == ktElement.name
- } ?: emptyList()
- }
-}
-
-fun findGraphQLElements(nameReferenceExpression: KtNameReferenceExpression): List {
- val resolved = nameReferenceExpression.resolveKtName()
- // Parameter is for data classes, property is for interfaces
- val ktElement = if (resolved is KtParameter || resolved is KtProperty) resolved as KtElement else return emptyList()
- return findGraphQLElements(ktElement)
-}
-
-/**
- * 'Element' here means either a field, a fragment spread, or an inline fragment.
- */
-fun findGraphQLElements(ktElement: KtElement): List {
- val elements = mutableListOf()
- val operationOrFragmentClass = ktElement.topMostContainingClass() ?: return emptyList()
- val fieldPath = operationOrFragmentClass.elementPath(ktElement)
- val operationOrFragmentDefinitions = findOperationOrFragmentGraphQLDefinitions(ktElement.project, operationOrFragmentClass.name!!)
- for (operationOrFragmentDefinition in operationOrFragmentDefinitions) {
- val elementsAtPath = operationOrFragmentDefinition.findElementAtPath(fieldPath)
- if (elementsAtPath != null) {
- elements += elementsAtPath
- } else {
- // 'Best effort' fallback for responseBased codegen: all fields with the name
- elements += operationOrFragmentDefinition.findElementsNamed(ktElement.name!!)
- }
- }
- return elements
-}
-
-
-/**
- * For a given [element], return its path in the given operation class.
- *
- * For instance if the operation class is:
- * ```
- * class MyQuery : Query {
- * data class Data(val user: User)
- * ↖
- * data class User(val address: Address)
- * ↖
- * data class Address(val street: String)
- * }
- * ```
- *
- * the path for `Address.street` will be `["user", "address", "street"]`.
- */
-private fun KtClass.elementPath(element: KtElement): List {
- var modelClass = element.containingClass()!!
- val parameterPath = mutableListOf(element.name!!)
- while (true) {
- var found = false
- findClass@ for (candidateModelClass in findChildrenOfType(withSelf = true)) {
- // Look for the parameter in the constructor (for data classes) and in the properties (for interfaces)
- for (property in candidateModelClass.primaryConstructor?.valueParameters.orEmpty() + candidateModelClass.getProperties()) {
- if (property.className() == modelClass.fqName?.asString() ||
- // For lists
- property.typeArgumentClassName(0) == modelClass.fqName?.asString()
- ) {
- parameterPath.add(0, (property as PsiNamedElement).name!!)
- modelClass = candidateModelClass
- found = true
- break@findClass
- }
- }
- }
- if (!found) break
- }
- return parameterPath
-}
-
-/**
- * Get the element (field, fragment spread, or inline fragment type condition) at the given path.
- */
-private fun GraphQLDefinition.findElementAtPath(path: List): GraphQLElement? {
- var element: GraphQLElement? = null
- var selectionSet = findChildrenOfType(recursive = false).firstOrNull() ?: return null
- for (pathElement in path) {
- var found = false
- for (selection in selectionSet.selectionList) {
- if (selection.field != null) {
- // Field
- val field = selection.field!!
- if (field.name == pathElement ||
- field.alias?.identifier?.referenceName == pathElement
- ) {
- element = field
- field.selectionSet?.let { selectionSet = it }
- found = true
- break
- }
- } else if (selection.fragmentSelection != null) {
- // Fragment
- if (selection.fragmentSelection!!.inlineFragment != null) {
- // Inline
- val inlineFragment = selection.fragmentSelection!!.inlineFragment!!
- if (inlineFragment.typeCondition?.typeName?.name?.let { "on${it.capitalizeFirstLetter()}" } == pathElement) {
- // Point to the type condition
- element = inlineFragment.typeCondition
- inlineFragment.selectionSet?.let { selectionSet = it }
- found = true
- break
- }
- } else if (selection.fragmentSelection!!.fragmentSpread != null) {
- // Spread
- val fragmentSpread = selection.fragmentSelection!!.fragmentSpread!!
- if (fragmentSpread.name.equals(pathElement, ignoreCase = true)) {
- element = fragmentSpread
- found = true
- break
- }
- }
- }
- }
- if (!found) {
- element = null
- break
- }
- }
- return element
-}
-
-/**
- * Get all elements (field, fragment spread, or inline fragment type condition) with the given name.
- */
-private fun GraphQLDefinition.findElementsNamed(name: String): List {
- // Fields
- return findChildrenOfType { field ->
- field.name == name || field.alias?.identifier?.referenceName == name
- } +
- // Fragment spreads
- findChildrenOfType { fragmentSpread ->
- fragmentSpread.name.equals(name, ignoreCase = true)
- } +
- // Inline fragments
- findChildrenOfType { inlineFragment ->
- inlineFragment.typeCondition?.typeName?.name?.let { "on${it.capitalizeFirstLetter()}" } == name
- }
- .map { inlineFragment ->
- // Point to the type condition
- inlineFragment.typeCondition!!
- }
-}
-
-
-// Remove "Query", "Mutation", or "Subscription" from the end of the operation name
-private fun String.minusOperationTypeSuffix(): String {
- return when {
- endsWith("Query") -> substringBeforeLast("Query")
- endsWith("Mutation") -> substringBeforeLast("Mutation")
- endsWith("Subscription") -> substringBeforeLast("Subscription")
- else -> this
- }
-}
-
-fun findFragmentSpreads(project: Project, predicate: (GraphQLFragmentSpread) -> Boolean): List {
- return FileTypeIndex.getFiles(GraphQLFileType.INSTANCE, GlobalSearchScope.allScope(project)).flatMap { virtualFile ->
- val fragmentSpreads = mutableListOf()
- val visitor = object : GraphQLRecursiveVisitor() {
- override fun visitFragmentSpread(o: GraphQLFragmentSpread) {
- super.visitFragmentSpread(o)
- if (predicate(o)) {
- fragmentSpreads += o
- }
- }
- }
- PsiManager.getInstance(project).findFile(virtualFile)?.accept(visitor)
- fragmentSpreads
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinDefinitionMarkerProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinDefinitionMarkerProvider.kt
deleted file mode 100644
index 4598a9611fa..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinDefinitionMarkerProvider.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.icons.ApolloIcons
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.originalClassName
-import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
-import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider
-import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
-import com.intellij.codeInsight.navigation.getPsiElementPopup
-import com.intellij.ide.util.DefaultPsiElementCellRenderer
-import com.intellij.ide.util.EditSourceUtil
-import com.intellij.psi.PsiElement
-import com.intellij.psi.util.PsiTreeUtil
-import com.intellij.ui.awt.RelativePoint
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-
-/**
- * Adds a gutter icon to Apollo operation/fragment references in Kotlin code, allowing to navigate to the corresponding GraphQL definition.
- */
-class KotlinDefinitionMarkerProvider : RelatedItemLineMarkerProvider() {
-
- override fun getName() = ApolloBundle.message("navigation.GraphQLDefinitionMarkerProvider.name")
-
- override fun getIcon() = ApolloIcons.Gutter.GraphQL
-
- override fun collectNavigationMarkers(element: PsiElement, result: MutableCollection>) {
- if (!element.project.apolloProjectService.apolloVersion.isAtLeastV3) return
-
- val nameReferenceExpression = element as? KtNameReferenceExpression ?: return
- val psiLeaf = PsiTreeUtil.getDeepestFirst(element)
- val graphQLDefinitions = when {
- nameReferenceExpression.isApolloOperationOrFragmentReference() -> {
- findOperationOrFragmentGraphQLDefinitions(element.project, nameReferenceExpression.originalClassName() ?: psiLeaf.text)
- }
-
- else -> return
- }
-
- if (graphQLDefinitions.isEmpty()) return
- val markerInfo = NavigationGutterIconBuilder.create(ApolloIcons.Gutter.GraphQL)
- .setTargets(graphQLDefinitions)
- .setTooltipText(ApolloBundle.message("navigation.GraphQLDefinitionMarkerProvider.tooltip", psiLeaf.text))
- .createLineMarkerInfo(psiLeaf) { e, _ ->
- // This behavior is already handled by NavigationGutterIcon, but we re-implement it here in order to log the telemetry event
- element.project.telemetryService.logEvent(TelemetryEvent.ApolloIjMarkerToGraphQl())
- if (graphQLDefinitions.size == 1) {
- graphQLDefinitions[0].navigate()
- } else {
- val popup = getPsiElementPopup(graphQLDefinitions.toTypedArray(), DefaultPsiElementCellRenderer(), "") { element: PsiElement ->
- element.navigate()
- true
- }
- popup.show(RelativePoint(e))
- }
- }
- result.add(markerInfo)
- }
-}
-
-private fun PsiElement.navigate() {
- val descriptor = EditSourceUtil.getDescriptor(this)
- if (descriptor != null && descriptor.canNavigate()) {
- descriptor.navigate(true)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinGotoDeclarationHandler.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinGotoDeclarationHandler.kt
deleted file mode 100644
index d374cdd95a2..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinGotoDeclarationHandler.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.util.originalClassName
-import com.apollographql.ijplugin.util.resolveKtName
-import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler
-import com.intellij.openapi.editor.Editor
-import com.intellij.psi.PsiElement
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-
-/**
- * Allows to navigate to the corresponding GraphQL definition when middle-clicking/cmd-clicking/cmd-b on an Apollo element in Kotlin code:
- * - operation/fragment class
- * - model field
- * - enum class / value
- * - input class / field
- */
-class KotlinGotoDeclarationHandler : GotoDeclarationHandler {
- override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array? {
- if (sourceElement == null) return null
- if (!sourceElement.project.apolloProjectService.apolloVersion.isAtLeastV3) return null
-
- val nameReferenceExpression = sourceElement.parent as? KtNameReferenceExpression ?: return null
- val psiLeaf = PsiTreeUtil.getDeepestFirst(sourceElement)
-
- val graphQLDefinitions = when {
- nameReferenceExpression.isApolloOperationOrFragmentReference() -> {
- findOperationOrFragmentGraphQLDefinitions(sourceElement.project, nameReferenceExpression.originalClassName() ?: psiLeaf.text)
- }
-
- nameReferenceExpression.isApolloModelFieldReference() -> {
- findGraphQLElements(nameReferenceExpression)
- }
-
- nameReferenceExpression.isApolloEnumClassReference() -> {
- findEnumTypeGraphQLDefinitions(sourceElement.project, psiLeaf.text)
- }
-
- nameReferenceExpression.isApolloEnumValueReference() -> {
- findEnumValueGraphQLDefinitions(nameReferenceExpression)
- }
-
- nameReferenceExpression.isApolloInputClassReference() -> {
- findInputTypeGraphQLDefinitions(sourceElement.project, psiLeaf.text)
- }
-
- nameReferenceExpression.isApolloInputFieldReference() -> {
- findInputFieldGraphQLDefinitions(nameReferenceExpression)
- }
-
- else -> return null
- }
-
- return buildList {
- // Add GraphQL definition(s)
- addAll(graphQLDefinitions.map { it.logNavigation { TelemetryEvent.ApolloIjNavigateToGraphQl() } })
-
- // Add the original referred to element
- val resolvedElement = nameReferenceExpression.resolveKtName()
- if (resolvedElement != null) {
- add(resolvedElement)
- }
- }.toTypedArray()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinNavigation.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinNavigation.kt
deleted file mode 100644
index 609a6c306f0..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinNavigation.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.util.capitalizeFirstLetter
-import com.apollographql.ijplugin.util.className
-import com.apollographql.ijplugin.util.decapitalizeFirstLetter
-import com.apollographql.ijplugin.util.findChildrenOfType
-import com.apollographql.ijplugin.util.ktClass
-import com.apollographql.ijplugin.util.typeArgumentClassName
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLEnumValue
-import com.intellij.lang.jsgraphql.psi.GraphQLField
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread
-import com.intellij.lang.jsgraphql.psi.GraphQLInlineFragment
-import com.intellij.lang.jsgraphql.psi.GraphQLInputObjectTypeDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiNamedElement
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.search.PsiShortNamesCache
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtEnumEntry
-import org.jetbrains.kotlin.psi.KtNamedDeclaration
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtProperty
-
-fun findKotlinOperationDefinitions(operationDefinition: GraphQLTypedOperationDefinition): List {
- val operationName = operationDefinition.name ?: return emptyList()
- val operationType = operationDefinition.operationType.text.capitalizeFirstLetter()
- val project = operationDefinition.project
- // Search for classes with the operation name suffix (the default)
- return findKotlinClass(project, operationName + operationType)
- // Fallback to no suffix
- .ifEmpty {
- findKotlinClass(project, operationName)
- }
- // Discard any classes with the same name but not generated by Apollo
- .filter { it.isApolloOperation() }
-}
-
-fun findKotlinFieldDefinitions(graphQLField: GraphQLField): List {
- val path = graphQLField.pathFromRoot()
- val ktClasses = findKotlinClassOfParent(graphQLField)
- return ktClasses?.mapNotNull { ktClass ->
- // Try Data class first (operations)
- var c = ktClass.findChildrenOfType { (it as PsiNamedElement).name == "Data" }.firstOrNull()
- // Fallback to class itself (fragments)
- ?: ktClass
- var ktFieldDefinition: KtNamedDeclaration? = null
- for ((i, pathElement) in path.withIndex()) {
- // Look for the element in the constructor parameters (for data classes) and in the properties (for interfaces)
- val properties = c.primaryConstructor?.valueParameters.orEmpty() + c.getProperties()
- ktFieldDefinition = properties.firstOrNull { (it as PsiNamedElement).name == pathElement } ?: continue
- val parameterTypeFqName =
- // Try Lists first
- ktFieldDefinition.typeArgumentClassName(0)
- // Fallback to regular type
- ?: ktFieldDefinition.className()
- ?: break
- if (i != path.lastIndex) {
- c = ktClass.findChildrenOfType { it.fqName?.asString() == parameterTypeFqName }.firstOrNull() ?: return@mapNotNull null
- }
- }
- ktFieldDefinition
- }
- // Fallback to just finding any property with the name (for responseBased)
- ?: ktClasses?.flatMap { ktClass ->
- ktClass.findChildrenOfType { it.name == graphQLField.name }
- }
- ?: emptyList()
-}
-
-/**
- * Ex:
- * ```graphql
- * a {
- * b
- * ... on MyType {
- * c
- * }
- * }
- * ```
- * returns `["a", "b", "onMyType", "c"]`
- */
-private fun GraphQLField.pathFromRoot(): List {
- val path = mutableListOf()
- var element: GraphQLElement = this
- while (true) {
- element = when (element) {
- is GraphQLInlineFragment -> {
- path.add(0, element.kotlinFieldName() ?: break)
- element.parent?.parent?.parent?.parent as? GraphQLElement ?: break
- }
-
- is GraphQLField -> {
- path.add(0, element.name!!)
- element.parent?.parent?.parent as? GraphQLElement ?: break
- }
-
- else -> break
- }
- if (element !is GraphQLField && element !is GraphQLInlineFragment) break
- }
- return path
-}
-
-fun findKotlinFragmentSpreadDefinitions(graphQLFragmentSpread: GraphQLFragmentSpread): List {
- return findKotlinClassOfParent(graphQLFragmentSpread)
- ?.flatMap { psiClass ->
- psiClass.findChildrenOfType { it.name == graphQLFragmentSpread.name?.decapitalizeFirstLetter() }
- }
- ?: emptyList()
-}
-
-fun findKotlinInlineFragmentDefinitions(graphQLFragmentSpread: GraphQLInlineFragment): List {
- return findKotlinClassOfParent(graphQLFragmentSpread)
- ?.flatMap { psiClass ->
- psiClass.findChildrenOfType { it.name == graphQLFragmentSpread.kotlinFieldName() }
- }
- ?: emptyList()
-}
-
-private fun GraphQLInlineFragment.kotlinFieldName() = typeCondition?.typeName?.name?.capitalizeFirstLetter()?.let { "on$it" }
-
-private fun findKotlinClassOfParent(gqlElement: GraphQLElement): List? {
- // Try operation first
- return gqlElement.parentOfType()?.let { operationDefinition ->
- findKotlinOperationDefinitions(operationDefinition)
- }
- // Fallback to fragment
- ?: gqlElement.parentOfType()?.let { fragmentDefinition ->
- findKotlinFragmentClassDefinitions(fragmentDefinition)
- }
-}
-
-
-fun findKotlinFragmentClassDefinitions(fragmentSpread: GraphQLFragmentSpread): List {
- val fragmentName = fragmentSpread.nameIdentifier.referenceName ?: return emptyList()
- return findKotlinClass(fragmentSpread.project, fragmentName) { it.isApolloFragment() }
-}
-
-fun findKotlinFragmentClassDefinitions(fragmentDefinition: GraphQLFragmentDefinition): List {
- val fragmentName = fragmentDefinition.nameIdentifier?.referenceName ?: return emptyList()
- return findKotlinClass(fragmentDefinition.project, fragmentName) { it.isApolloFragment() }
-}
-
-fun findKotlinEnumClassDefinitions(enumTypeDefinition: GraphQLEnumTypeDefinition): List {
- val enumName = enumTypeDefinition.typeNameDefinition?.nameIdentifier?.referenceName ?: return emptyList()
- return findKotlinClass(enumTypeDefinition.project, enumName) { it.isApolloEnumClass() }
-}
-
-fun findKotlinEnumValueDefinitions(enumValue: GraphQLEnumValue): List {
- val enumTypeDefinition = enumValue.parentOfType() ?: return emptyList()
- return findKotlinEnumClassDefinitions(enumTypeDefinition).flatMap { psiClass ->
- psiClass.findChildrenOfType { it.name == enumValue.name }
- }
-}
-
-fun findKotlinInputClassDefinitions(inputTypeDefinition: GraphQLInputObjectTypeDefinition): List {
- val inputName = inputTypeDefinition.typeNameDefinition?.nameIdentifier?.referenceName ?: return emptyList()
- return findKotlinClass(inputTypeDefinition.project, inputName) { it.isApolloInputClass() }
-}
-
-fun findKotlinInputFieldDefinitions(inputValue: GraphQLInputValueDefinition): List {
- val inputTypeDefinition = inputValue.parentOfType() ?: return emptyList()
- return findKotlinInputClassDefinitions(inputTypeDefinition).flatMap { psiClass ->
- psiClass.findChildrenOfType { it.name == inputValue.name }
- }
-}
-
-private fun findKotlinClass(project: Project, name: String, filter: ((KtClass) -> Boolean)? = null): List {
- return PsiShortNamesCache.getInstance(project).getClassesByName(
- // All Apollo generated classes ara capitalized
- name.capitalizeFirstLetter(),
- GlobalSearchScope.allScope(project)
- )
- .mapNotNull {
- it.ktClass
- }
- .let { if (filter != null) it.filter(filter) else it }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinTypeDeclarationProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinTypeDeclarationProvider.kt
deleted file mode 100644
index 5ae05d4fd99..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/KotlinTypeDeclarationProvider.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.project.apolloProjectService
-import com.intellij.codeInsight.navigation.actions.TypeDeclarationProvider
-import com.intellij.lang.jsgraphql.psi.GraphQLNamedElement
-import com.intellij.psi.PsiElement
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtElement
-
-/**
- * Allows to navigate to the corresponding GraphQL type definition when shift-middle-clicking/shift-cmd-clicking/shift-cmd-b on a Kotlin
- * symbol whose type is an Apollo enum, input type or model field.
- */
-class KotlinTypeDeclarationProvider : TypeDeclarationProvider {
- override fun getSymbolTypeDeclarations(symbol: PsiElement): Array? {
- if (!symbol.project.apolloProjectService.apolloVersion.isAtLeastV3) return null
-
- // Only care about Kotlin
- if (symbol !is KtElement) return null
-
- // Get the original declaration(s)
- val ktTypeDeclarations = TypeDeclarationProvider.EP_NAME.extensionList.filterNot { it is KotlinTypeDeclarationProvider }
- .map { it.getSymbolTypeDeclarations(symbol) }.filterNotNull().firstOrNull()
- val ktTypeDeclaration = ktTypeDeclarations?.firstOrNull() ?: return null
-
- val gqlElements = when {
- ktTypeDeclaration is KtClass && ktTypeDeclaration.isApolloOperationOrFragment() -> {
- findOperationOrFragmentGraphQLDefinitions(ktTypeDeclaration.project, ktTypeDeclaration.name!!)
- }
-
- ktTypeDeclaration is KtClass && ktTypeDeclaration.isApolloEnumClass() -> {
- findEnumTypeGraphQLDefinitions(ktTypeDeclaration.project, ktTypeDeclaration.name!!)
- }
-
- ktTypeDeclaration is KtClass && ktTypeDeclaration.isApolloInputClass() -> {
- findInputTypeGraphQLDefinitions(ktTypeDeclaration.project, ktTypeDeclaration.name!!)
- }
-
- // For model fields, we want to navigate to the type declaration in the schema
- symbol.isApolloModelField() -> {
- findGraphQLElements(symbol).mapNotNull {
- (it as? GraphQLNamedElement)?.nameIdentifier?.reference?.resolve()
- }
- }
-
- else -> return null
- }
-
- return buildList {
- // Add GraphQL definition(s)
- addAll(gqlElements)
-
- // Add the original Kotlin declaration(s)
- addAll(ktTypeDeclarations)
- }.toTypedArray()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/LogNavigationPsiElement.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/LogNavigationPsiElement.kt
deleted file mode 100644
index 9c50fa63b91..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/LogNavigationPsiElement.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.apollographql.ijplugin.navigation
-
-import com.apollographql.ijplugin.telemetry.TelemetryEvent
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.intellij.navigation.ItemPresentation
-import com.intellij.navigation.NavigationItem
-import com.intellij.platform.backend.navigation.NavigationRequest
-import com.intellij.pom.Navigatable
-import com.intellij.psi.PsiElement
-import javax.swing.Icon
-
-private class LogNavigationPsiElement(
- private val wrapped: PsiElement,
- private val telemetryEvent: () -> TelemetryEvent,
-) : PsiElement by wrapped, NavigationItem, Navigatable {
- private var hasLogged = false
-
- override fun equals(other: Any?): Boolean = wrapped == other
-
- override fun hashCode(): Int = wrapped.hashCode()
-
- override fun toString(): String = wrapped.toString()
-
- override fun getName(): String? {
- return (wrapped as? NavigationItem)?.name
- }
-
- override fun getPresentation(): ItemPresentation {
- return (wrapped as? NavigationItem)?.presentation ?: object : ItemPresentation {
- // We don't want the presentation to be too wide: fallback to the first line of text, truncated to 80 characters
- override fun getPresentableText(): String? = wrapped.text.split('\n').firstOrNull()?.take(80)
-
- override fun getIcon(unused: Boolean): Icon? = null
- }
- }
-
- @Suppress("UnstableApiUsage")
- override fun navigationRequest(): NavigationRequest? {
- logTelemetryEvent()
- return (wrapped as? Navigatable)?.navigationRequest()
- }
-
- override fun navigate(requestFocus: Boolean) {
- (wrapped as? Navigatable)?.navigate(requestFocus)
- }
-
- override fun canNavigate(): Boolean {
- return (wrapped as? Navigatable)?.canNavigate() ?: false
- }
-
- override fun canNavigateToSource(): Boolean {
- return (wrapped as? Navigatable)?.canNavigateToSource() ?: false
- }
-
- private fun logTelemetryEvent() {
- if (!hasLogged) {
- hasLogged = true
- wrapped.project.telemetryService.logEvent(telemetryEvent())
- }
- }
-}
-
-fun PsiElement.logNavigation(telemetryEvent: () -> TelemetryEvent): PsiElement {
- return LogNavigationPsiElement(this, telemetryEvent)
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/compat/KotlinFindUsagesHandlerFactoryCompat.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/compat/KotlinFindUsagesHandlerFactoryCompat.kt
deleted file mode 100644
index ee36b5ecac6..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/navigation/compat/KotlinFindUsagesHandlerFactoryCompat.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.apollographql.ijplugin.navigation.compat
-
-import com.apollographql.ijplugin.util.logw
-import com.intellij.find.findUsages.FindUsagesHandler
-import com.intellij.find.findUsages.FindUsagesHandlerFactory
-import com.intellij.find.findUsages.FindUsagesOptions
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-
-private const val POST_231_CLASS_NAME = "org.jetbrains.kotlin.idea.base.searching.usages.KotlinFindUsagesHandlerFactory"
-private const val PRE_231_CLASS_NAME = "org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory"
-
-class KotlinFindUsagesHandlerFactoryCompat(project: Project) : FindUsagesHandlerFactory() {
- private val delegateClass = runCatching {
- // Try with the recent version first (changed package since platform 231)
- Class.forName(POST_231_CLASS_NAME)
- }
- .recoverCatching {
- // Fallback to the old version
- Class.forName(PRE_231_CLASS_NAME)
- }
- .onFailure { logw(it, "Could not load either $POST_231_CLASS_NAME nor $PRE_231_CLASS_NAME") }
- .getOrNull()
-
- private val delegate: FindUsagesHandlerFactory? = try {
- delegateClass?.let { it.getConstructor(Project::class.java).newInstance(project) as FindUsagesHandlerFactory }
- } catch (e: Exception) {
- // ProcessCanceledException can sometimes happen here
- logw(e, "Could not instantiate KotlinFindUsagesHandlerFactory")
- null
- }
-
-
- override fun canFindUsages(element: PsiElement): Boolean {
- return delegate?.canFindUsages(element) ?: false
- }
-
- override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler? {
- return delegate?.createFindUsagesHandler(element, forHighlightUsages)
- }
-
- val findPropertyOptions: FindUsagesOptions?
- get() = delegateClass?.getDeclaredMethod("getFindPropertyOptions")
- ?.invoke(this.delegate) as? FindUsagesOptions
-
- val findClassOptions: FindUsagesOptions?
- get() = delegateClass?.getDeclaredMethod("getFindClassOptions")
- ?.invoke(this.delegate) as? FindUsagesOptions
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/History.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/History.kt
deleted file mode 100644
index 12781ce17ed..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/History.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-class History {
- private var history = mutableListOf()
- private var pointer = -1
-
- fun current(): T? {
- return if (pointer >= 0) {
- history[pointer]
- } else {
- null
- }
- }
-
- fun push(element: T) {
- if (current() == element) return
- history = history.subList(0, pointer + 1)
- history.add(element)
- pointer = history.lastIndex
- }
-
- fun back(): T? {
- if (pointer > 0) {
- pointer--
- }
- return current()
- }
-
- fun forward(): T? {
- if (pointer < history.lastIndex) {
- pointer++
- }
- return current()
- }
-
- fun canGoBack(): Boolean {
- return pointer > 0
- }
-
- fun canGoForward(): Boolean {
- return pointer < history.lastIndex
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCache.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCache.kt
deleted file mode 100644
index a7ef523260a..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCache.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-data class NormalizedCache(
- val records: List,
-) {
- data class Record(
- val key: String,
- val fields: List,
- val sizeInBytes: Int,
- )
-
- data class Field(
- val key: String,
- val value: FieldValue,
- )
-
- sealed interface FieldValue {
- data class StringValue(val value: String) : FieldValue
- data class NumberValue(val value: String) : FieldValue
- data class BooleanValue(val value: Boolean) : FieldValue
- data class ListValue(val value: List) : FieldValue
-
- /** For custom scalars. */
- data class CompositeValue(val value: List) : FieldValue
- data object Null : FieldValue
- data class Reference(val key: String) : FieldValue
- data class ErrorValue(val message: String) : FieldValue
- }
-
- fun sorted() = NormalizedCache(
- records.sortedWith(RecordKeyComparator)
- )
-
- companion object {
- /**
- * Compares records by key, with `QUERY_ROOT` first, then by alphabetical order, taking numbers into account.
- * E.g. `person.1` < `person.2` < `person.10` < `person.10.friend.1` < `person.10.friend.2`
- */
- val RecordKeyComparator = Comparator { o1, o2 ->
- val key1 = o1.key
- val key2 = o2.key
- when {
- key1 == "QUERY_ROOT" -> if (key2 == "QUERY_ROOT") 0 else -1
- key2 == "QUERY_ROOT" -> 1
- else -> {
- var idx1 = 0
- var idx2 = 0
- while (true) {
- val c1 = key1[idx1]
- val c2 = key2[idx2]
- if (c1.isDigit() && c2.isDigit()) {
- var number1 = 0
- var number2 = 0
- while (idx1 < key1.length && key1[idx1].isDigit()) {
- number1 = number1 * 10 + key1[idx1].digitToInt()
- idx1++
- }
- while (idx2 < key2.length && key2[idx2].isDigit()) {
- number2 = number2 * 10 + key2[idx2].digitToInt()
- idx2++
- }
- val comparison = number1.compareTo(number2)
- if (comparison != 0) {
- return@Comparator comparison
- }
- } else {
- val comparison = c1.lowercaseChar().compareTo(c2.lowercaseChar())
- if (comparison != 0) {
- return@Comparator comparison
- }
- idx1++
- idx2++
- }
- if (idx1 == key1.length || idx2 == key2.length) {
- break
- }
- }
- // If we're here, everything was equal up to the size of the smallest string. The smallest one should go first.
- key1.length.compareTo(key2.length)
- }
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheSource.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheSource.kt
deleted file mode 100644
index 287c81d5b56..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheSource.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-import com.android.ddmlib.IDevice
-import com.apollographql.ijplugin.apollodebugserver.ApolloDebugClient
-import java.io.File
-
-sealed interface NormalizedCacheSource {
- data class LocalFile(val file: File) : NormalizedCacheSource
-
- data class DeviceFile(
- val device: IDevice,
- val packageName: String,
- val remoteDirName: String,
- val remoteFileName: String,
- ) : NormalizedCacheSource
-
- data class ApolloDebugServer(
- val apolloDebugClient: ApolloDebugClient,
- val apolloClientId: String,
- val normalizedCacheId: String,
- ) : NormalizedCacheSource
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheToolWindowFactory.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheToolWindowFactory.kt
deleted file mode 100644
index a207040e022..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/NormalizedCacheToolWindowFactory.kt
+++ /dev/null
@@ -1,400 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.apollodebugserver.normalizedCacheSimpleName
-import com.apollographql.ijplugin.normalizedcache.NormalizedCacheSource.ApolloDebugServer
-import com.apollographql.ijplugin.normalizedcache.NormalizedCacheSource.DeviceFile
-import com.apollographql.ijplugin.normalizedcache.NormalizedCacheSource.LocalFile
-import com.apollographql.ijplugin.normalizedcache.provider.ApolloDebugNormalizedCacheProvider
-import com.apollographql.ijplugin.normalizedcache.provider.DatabaseNormalizedCacheProvider
-import com.apollographql.ijplugin.normalizedcache.ui.FieldTreeTable
-import com.apollographql.ijplugin.normalizedcache.ui.RecordSearchTextField
-import com.apollographql.ijplugin.normalizedcache.ui.RecordTable
-import com.apollographql.ijplugin.telemetry.TelemetryEvent.ApolloIjNormalizedCacheOpenApolloDebugCache
-import com.apollographql.ijplugin.telemetry.TelemetryEvent.ApolloIjNormalizedCacheOpenDeviceFile
-import com.apollographql.ijplugin.telemetry.TelemetryEvent.ApolloIjNormalizedCacheOpenLocalFile
-import com.apollographql.ijplugin.telemetry.telemetryService
-import com.apollographql.ijplugin.util.isAndroidPluginPresent
-import com.apollographql.ijplugin.util.logw
-import com.apollographql.ijplugin.util.showNotification
-import com.intellij.icons.AllIcons
-import com.intellij.ide.CommonActionsManager
-import com.intellij.ide.dnd.FileCopyPasteUtil
-import com.intellij.notification.NotificationType
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.actionSystem.ActionManager
-import com.intellij.openapi.actionSystem.ActionPlaces
-import com.intellij.openapi.actionSystem.ActionUpdateThread
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.DefaultActionGroup
-import com.intellij.openapi.actionSystem.IdeActions
-import com.intellij.openapi.actionSystem.ex.ActionUtil
-import com.intellij.openapi.application.invokeLater
-import com.intellij.openapi.fileChooser.FileChooser
-import com.intellij.openapi.fileChooser.FileChooserDescriptor
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.SimpleToolWindowPanel
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.openapi.wm.ToolWindowFactory
-import com.intellij.openapi.wm.ex.ToolWindowEx
-import com.intellij.openapi.wm.ex.ToolWindowManagerListener
-import com.intellij.ui.OnePixelSplitter
-import com.intellij.ui.ScrollPaneFactory
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.components.JBPanelWithEmptyText
-import com.intellij.ui.content.ContentFactory
-import com.intellij.ui.content.ContentManager
-import com.intellij.util.ui.JBUI
-import kotlinx.coroutines.runBlocking
-import org.sqlite.SQLiteException
-import java.awt.BorderLayout
-import java.awt.dnd.DnDConstants
-import java.awt.dnd.DropTarget
-import java.awt.dnd.DropTargetAdapter
-import java.awt.dnd.DropTargetDragEvent
-import java.awt.dnd.DropTargetDropEvent
-import java.awt.dnd.DropTargetEvent
-import java.awt.event.KeyEvent
-import java.io.File
-import javax.swing.JComponent
-import javax.swing.JPanel
-import javax.swing.SwingUtilities
-
-class NormalizedCacheToolWindowFactory : ToolWindowFactory, DumbAware, Disposable {
- override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- val newTabAction = object : DumbAwareAction(ApolloBundle.messagePointer("normalizedCacheViewer.newTab"), AllIcons.General.Add) {
- override fun actionPerformed(e: AnActionEvent) {
- createNewTab(project, toolWindow.contentManager)
- }
- }.apply {
- registerCustomShortcutSet(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK, toolWindow.component)
- }
- (toolWindow as ToolWindowEx).setTabActions(newTabAction)
-
- // Open a new tab if all tabs were closed
- project.messageBus.connect().subscribe(
- ToolWindowManagerListener.TOPIC,
- object : ToolWindowManagerListener {
- override fun toolWindowShown(shownToolWindow: ToolWindow) {
- if (toolWindow === shownToolWindow && toolWindow.isVisible && toolWindow.contentManager.isEmpty) {
- createNewTab(project, toolWindow.contentManager)
- }
- }
- }
- )
-
- createNewTab(project, toolWindow.contentManager)
- }
-
- private fun createNewTab(project: Project, contentManager: ContentManager) {
- contentManager.addContent(
- ContentFactory.getInstance().createContent(
- NormalizedCacheWindowPanel(project) { tabName -> contentManager.selectedContent?.displayName = tabName },
- ApolloBundle.message("normalizedCacheViewer.tabName.empty"),
- false
- )
- )
- contentManager.setSelectedContent(contentManager.contents.last())
- }
-
- override fun dispose() {}
-}
-
-class NormalizedCacheWindowPanel(
- private val project: Project,
- private val setTabName: (tabName: String) -> Unit,
-) : SimpleToolWindowPanel(false, true), Disposable {
- private lateinit var normalizedCache: NormalizedCache
-
- private lateinit var recordTable: RecordTable
- private lateinit var recordSearchTextField: RecordSearchTextField
-
- private lateinit var fieldTreeTable: FieldTreeTable
-
- private val history = History()
- private var updateHistory = true
-
- private var cacheSource: NormalizedCacheSource? = null
- private var isRefreshing = false
-
- init {
- setContent(createEmptyContent())
- }
-
- private fun createEmptyContent(): JComponent {
- return JBPanelWithEmptyText().apply {
- emptyText.text = ApolloBundle.message("normalizedCacheViewer.empty.message")
- emptyText.appendLine(ApolloBundle.message("normalizedCacheViewer.empty.openFile"), SimpleTextAttributes.LINK_PLAIN_ATTRIBUTES) {
- pickFile()
- }
- if (isAndroidPluginPresent) {
- emptyText.appendLine(ApolloBundle.message("normalizedCacheViewer.empty.pullFromDevice"), SimpleTextAttributes.LINK_PLAIN_ATTRIBUTES) {
- PullFromDeviceDialog(
- project = project,
- onSourceSelected = ::openNormalizedCache,
- ).show()
- }
- }
-
- val defaultBackground = background
- dropTarget = DropTarget(this, DnDConstants.ACTION_COPY, object : DropTargetAdapter() {
- override fun dragEnter(e: DropTargetDragEvent) {
- if (FileCopyPasteUtil.isFileListFlavorAvailable(e.currentDataFlavors)) {
- e.acceptDrag(DnDConstants.ACTION_COPY)
- background = JBUI.CurrentTheme.DragAndDrop.Area.BACKGROUND
- } else {
- e.rejectDrag()
- }
- }
-
- override fun dragOver(e: DropTargetDragEvent) {
- dragEnter(e)
- }
-
- override fun dropActionChanged(e: DropTargetDragEvent) {
- dragEnter(e)
- }
-
- override fun dragExit(dte: DropTargetEvent?) {
- background = defaultBackground
- }
-
- override fun drop(e: DropTargetDropEvent) {
- e.acceptDrop(DnDConstants.ACTION_COPY)
- val paths = FileCopyPasteUtil.getFileList(e.transferable)
- if (!paths.isNullOrEmpty()) {
- val file = paths.first()
- openNormalizedCache(LocalFile(file))
- e.dropComplete(true)
- } else {
- e.dropComplete(false)
- }
- background = defaultBackground
- }
- })
- }
- }
-
- private fun createLoadingContent(): JComponent {
- return JBPanelWithEmptyText().apply {
- emptyText.text = ApolloBundle.message("normalizedCacheViewer.loading.message")
- }
- }
-
- private fun createToolbar(): JComponent {
- val group = DefaultActionGroup().apply {
- add(object : DumbAwareAction(ApolloBundle.messagePointer("normalizedCacheViewer.toolbar.back"), AllIcons.Actions.Back) {
- init {
- ActionUtil.copyFrom(this, IdeActions.ACTION_GOTO_BACK)
- registerCustomShortcutSet(this.shortcutSet, this@NormalizedCacheWindowPanel)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val record = history.back() ?: return
- updateHistory = false
- selectRecord(record.key)
- }
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabled = history.canGoBack()
- }
-
- override fun getActionUpdateThread() = ActionUpdateThread.BGT
- })
- add(object : DumbAwareAction(ApolloBundle.messagePointer("normalizedCacheViewer.toolbar.forward"), AllIcons.Actions.Forward) {
- init {
- ActionUtil.copyFrom(this, IdeActions.ACTION_GOTO_FORWARD)
- registerCustomShortcutSet(this.shortcutSet, this@NormalizedCacheWindowPanel)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val record = history.forward() ?: return
- updateHistory = false
- selectRecord(record.key)
- }
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabled = history.canGoForward()
- }
-
- override fun getActionUpdateThread() = ActionUpdateThread.BGT
- })
- addSeparator()
- add(CommonActionsManager.getInstance().createExpandAllAction(fieldTreeTable.treeExpander, this@NormalizedCacheWindowPanel).apply {
- getTemplatePresentation().setDescription(ApolloBundle.message("normalizedCacheViewer.toolbar.expandAll"))
- })
- add(CommonActionsManager.getInstance().createCollapseAllAction(fieldTreeTable.treeExpander, this@NormalizedCacheWindowPanel).apply {
- getTemplatePresentation().setDescription(ApolloBundle.message("normalizedCacheViewer.toolbar.collapseAll"))
- })
- addSeparator()
- add(object : DumbAwareAction(ApolloBundle.messagePointer("normalizedCacheViewer.toolbar.refresh"), AllIcons.Actions.Refresh) {
- init {
- ActionUtil.copyFrom(this, IdeActions.ACTION_REFRESH)
- registerCustomShortcutSet(this.shortcutSet, this@NormalizedCacheWindowPanel)
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- cacheSource?.let { openNormalizedCache(it) }
- }
-
- override fun update(e: AnActionEvent) {
- e.presentation.isVisible = cacheSource != null
- e.presentation.isEnabled = !isRefreshing
- }
-
- override fun getActionUpdateThread() = ActionUpdateThread.BGT
- })
-
- }
-
- val actionToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.TOOLBAR, group, false)
- actionToolBar.targetComponent = this
- return actionToolBar.component
- }
-
- private fun createNormalizedCacheContent(): JComponent {
- fieldTreeTable = FieldTreeTable(::selectRecord)
- val recordTableWithFilter = createRecordTableWithFilter()
- val splitter = OnePixelSplitter(false, .25F).apply {
- firstComponent = recordTableWithFilter
- secondComponent = fieldTreeTable
- setResizeEnabled(true)
- splitterProportionKey = "${NormalizedCacheToolWindowFactory::class.java}.splitterProportionKey"
- }
- SwingUtilities.invokeLater {
- recordTable.requestFocusInWindow()
- }
- return splitter
- }
-
- private fun createRecordTableWithFilter(): JComponent {
- recordTable = RecordTable(normalizedCache).apply {
- selectionModel.addListSelectionListener {
- if (selectedRow == -1) return@addListSelectionListener
- val selectedRowAfterSort = convertRowIndexToModel(selectedRow)
- model.getRecordAt(selectedRowAfterSort)?.let { record ->
- fieldTreeTable.setRecord(record)
- if (!updateHistory) {
- updateHistory = true
- } else {
- history.push(record)
- }
- }
- }
- selectionModel.setSelectionInterval(0, 0)
- }
-
- recordSearchTextField = RecordSearchTextField(recordTable)
- recordTable.addKeyListener(recordSearchTextField)
-
- val tableWithFilter = JPanel(BorderLayout()).apply {
- add(recordSearchTextField, BorderLayout.NORTH)
- add(ScrollPaneFactory.createScrollPane(recordTable), BorderLayout.CENTER)
- }
-
- return tableWithFilter
- }
-
- private fun selectRecord(key: String) {
- if (!recordTable.model.isRecordShowing(key)) {
- // Filtered list doesn't contain the record, so clear the filter
- recordSearchTextField.text = ""
- }
- recordTable.selectRecord(key)
- recordTable.requestFocusInWindow()
- }
-
- private fun pickFile() {
- val virtualFile = FileChooser.chooseFiles(
- FileChooserDescriptor(true, false, false, false, false, false),
- project,
- null
- ).firstOrNull() ?: return
- openNormalizedCache(LocalFile(File(virtualFile.path)))
- }
-
- private fun openNormalizedCache(cacheSource: NormalizedCacheSource) {
- project.telemetryService.logEvent(when (cacheSource) {
- is ApolloDebugServer -> ApolloIjNormalizedCacheOpenApolloDebugCache()
- is DeviceFile -> ApolloIjNormalizedCacheOpenDeviceFile()
- is LocalFile -> ApolloIjNormalizedCacheOpenLocalFile()
- })
- setContent(createLoadingContent())
- object : Task.Backgroundable(
- project,
- ApolloBundle.message("normalizedCacheViewer.loading.message"),
- false,
- ) {
- override fun run(indicator: ProgressIndicator) {
- isRefreshing = true
- var tabName = ""
- val normalizedCacheResult = when (cacheSource) {
- is LocalFile -> {
- runBlocking {
- DatabaseNormalizedCacheProvider().provide(cacheSource.file).also {
- tabName = cacheSource.file.name
- }
- }
- }
-
- is DeviceFile -> {
- runBlocking {
- pullFile(
- device = cacheSource.device,
- appPackageName = cacheSource.packageName,
- remoteDirName = cacheSource.remoteDirName,
- remoteFileName = cacheSource.remoteFileName,
- ).mapCatching { file ->
- tabName = cacheSource.remoteFileName
- DatabaseNormalizedCacheProvider().provide(file).getOrThrow()
- }
- }
- }
-
- is ApolloDebugServer -> {
- runBlocking {
- cacheSource.apolloDebugClient.getNormalizedCache(apolloClientId = cacheSource.apolloClientId, normalizedCacheId = cacheSource.normalizedCacheId)
- }.mapCatching { apolloDebugNormalizedCache ->
- val tabNamePrefix = cacheSource.apolloClientId.takeIf { it != "client" }?.let { "$it - " } ?: ""
- tabName = tabNamePrefix + apolloDebugNormalizedCache.displayName.normalizedCacheSimpleName
- ApolloDebugNormalizedCacheProvider().provide(apolloDebugNormalizedCache).getOrThrow()
- }
- }
- }
- isRefreshing = false
- invokeLater {
- if (normalizedCacheResult.isFailure) {
- showOpenFileError(normalizedCacheResult.exceptionOrNull()!!)
- if (this@NormalizedCacheWindowPanel.cacheSource == null) {
- setContent(createEmptyContent())
- }
- return@invokeLater
- }
- this@NormalizedCacheWindowPanel.cacheSource = cacheSource
- normalizedCache = normalizedCacheResult.getOrThrow().sorted()
- setContent(createNormalizedCacheContent())
- if (toolbar != null) toolbar = null
- toolbar = createToolbar()
- setTabName(tabName)
- }
- }
- }.queue()
- }
-
- private fun showOpenFileError(exception: Throwable) {
- logw(exception, "Could not open file")
- val details = when (exception) {
- is SQLiteException -> exception.resultCode.message
- else -> exception.message ?: exception.javaClass.simpleName
- }
- showNotification(project, title = ApolloBundle.message("normalizedCacheViewer.openFileError.title"), content = details, type = NotificationType.ERROR)
- }
-
- override fun dispose() {
- (cacheSource as? ApolloDebugServer)?.apolloDebugClient?.close()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDevice.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDevice.kt
deleted file mode 100644
index f7501a93196..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDevice.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-import com.android.adblib.DeviceSelector
-import com.android.adblib.syncRecv
-import com.android.ddmlib.AndroidDebugBridge
-import com.android.ddmlib.IDevice
-import com.android.tools.idea.adb.AdbShellCommandsUtil
-import com.android.tools.idea.adblib.AdbLibApplicationService
-import com.apollographql.ijplugin.util.execute
-import com.apollographql.ijplugin.util.executeCatching
-import com.apollographql.ijplugin.util.logd
-import com.apollographql.ijplugin.util.logw
-import java.io.File
-import java.nio.file.Paths
-import java.util.concurrent.TimeUnit
-
-fun getConnectedDevices(): List {
- return AndroidDebugBridge.createBridge(1, TimeUnit.SECONDS).devices.sortedBy { it.name }
-}
-
-fun IDevice.getDebuggablePackageList(): Result> {
- val commandResult = AdbShellCommandsUtil.create(this).executeCatching(
- // List all packages, and try run-as on them - if it succeeds, the package is debuggable
- "for p in \$(pm list packages -3 | cut -d : -f 2); do (run-as \$p true >/dev/null 2>&1 && echo \$p); done; true"
- )
- if (commandResult.isFailure) {
- val e = commandResult.exceptionOrNull()!!
- logw(e, "Could not list debuggable packages")
- return Result.failure(e)
- }
- val result = commandResult.getOrThrow()
- if (result.isError) {
- val message = "Could not list debuggable packages: ${result.output.joinToString()}"
- logw(message)
- return Result.failure(Exception(message))
- }
- return Result.success(result.output.filterNot { it.isEmpty() }.sorted())
-}
-
-fun IDevice.getDatabaseList(packageName: String, databasesDir: String): Result> {
- val commandResult = AdbShellCommandsUtil.create(this).executeCatching("run-as $packageName ls -1 $databasesDir")
- if (commandResult.isFailure) {
- val e = commandResult.exceptionOrNull()!!
- logw(e, "Could not list databases")
- return Result.failure(e)
- }
- val result = commandResult.getOrThrow()
- if (result.isError) {
- if (result.output.any { it.contains("No such file or directory") }) {
- return Result.success(emptyList())
- }
- val message = "Could not list databases: ${result.output.joinToString()}"
- logw(message)
- return Result.failure(Exception(message))
- }
- return Result.success(result.output.filter { it.isDatabaseFileName() }.sorted())
-}
-
-suspend fun pullFile(device: IDevice, appPackageName: String, remoteDirName: String, remoteFileName: String): Result {
- val remoteFilePath = "$remoteDirName/$remoteFileName"
- val localFile = File.createTempFile(remoteFileName.substringBeforeLast(".") + "-tmp", ".db")
- logd("Pulling $remoteFilePath to ${localFile.absolutePath}")
- val intermediateRemoteFilePath = "/data/local/tmp/${localFile.name}"
- val shellCommandsUtil = AdbShellCommandsUtil.create(device)
- return runCatching {
- var commandResult = shellCommandsUtil.execute("touch $intermediateRemoteFilePath")
- if (commandResult.isError) {
- throw Exception("'touch' command failed")
- }
- commandResult = shellCommandsUtil.execute("run-as $appPackageName sh -c 'cp $remoteFilePath $intermediateRemoteFilePath'")
- if (commandResult.isError) {
- throw Exception("'copy' command failed")
- }
- try {
- val adbLibSession = AdbLibApplicationService.instance.session
- val fileChannel = adbLibSession.channelFactory.createFile(Paths.get(localFile.absolutePath))
- fileChannel.use {
- adbLibSession.deviceServices.syncRecv(DeviceSelector.fromSerialNumber(device.serialNumber), intermediateRemoteFilePath, fileChannel)
- }
- } finally {
- commandResult = shellCommandsUtil.execute("rm $intermediateRemoteFilePath")
- if (commandResult.isError) {
- logw("'rm' command failed")
- }
- }
- localFile
- }
-}
-
-// See https://www.sqlite.org/tempfiles.html
-fun String.isDatabaseFileName() = isNotEmpty() && !endsWith("-journal") && !endsWith("-wal") && !endsWith("-shm")
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDeviceDialog.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDeviceDialog.kt
deleted file mode 100644
index dd80314ff2c..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/PullFromDeviceDialog.kt
+++ /dev/null
@@ -1,417 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-import android.annotation.SuppressLint
-import com.android.ddmlib.Client
-import com.android.ddmlib.IDevice
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.apollodebugserver.ApolloDebugClient
-import com.apollographql.ijplugin.apollodebugserver.ApolloDebugClient.Companion.getApolloDebugClients
-import com.apollographql.ijplugin.apollodebugserver.GetApolloClientsQuery
-import com.apollographql.ijplugin.apollodebugserver.normalizedCacheSimpleName
-import com.apollographql.ijplugin.icons.ApolloIcons
-import com.apollographql.ijplugin.ui.tree.DynamicNode
-import com.apollographql.ijplugin.ui.tree.RootDynamicNode
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.logw
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.ModalityState
-import com.intellij.openapi.application.invokeLater
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.DialogPanel
-import com.intellij.openapi.ui.DialogWrapper
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.TreeSpeedSearch
-import com.intellij.ui.TreeUIHelper
-import com.intellij.ui.dsl.builder.AlignX
-import com.intellij.ui.dsl.builder.panel
-import com.intellij.ui.tree.AsyncTreeModel
-import com.intellij.ui.tree.StructureTreeModel
-import com.intellij.ui.treeStructure.AutoExpandSimpleNodeListener
-import com.intellij.ui.treeStructure.NullNode
-import com.intellij.ui.treeStructure.SimpleTree
-import com.intellij.ui.treeStructure.SimpleTreeStructure
-import com.intellij.util.ui.tree.TreeUtil
-import icons.StudioIcons
-import kotlinx.coroutines.runBlocking
-import java.awt.event.InputEvent
-import javax.swing.event.TreeExpansionEvent
-import javax.swing.event.TreeExpansionListener
-import javax.swing.tree.DefaultMutableTreeNode
-import javax.swing.tree.TreeModel
-import javax.swing.tree.TreeSelectionModel
-
-class PullFromDeviceDialog(
- private val project: Project,
- private val onSourceSelected: (normalizedCacheSource: NormalizedCacheSource) -> Unit,
-) : DialogWrapper(project, true), Disposable {
- private lateinit var tree: SimpleTree
- private lateinit var model: StructureTreeModel
-
- private val apolloDebugClientsToClose = mutableListOf()
-
- init {
- title = ApolloBundle.message("normalizedCacheViewer.pullFromDevice.title")
- init()
- okAction.isEnabled = false
- }
-
- override fun createCenterPanel(): DialogPanel = panel {
- row {
- scrollCell(createTree())
- .align(AlignX.FILL)
- }
-
- }.withPreferredWidth(450)
-
- override fun getDimensionServiceKey(): String? {
- return PullFromDeviceDialog::class.java.simpleName
- }
-
- private fun createTree(): SimpleTree {
- tree = object : SimpleTree() {
- override fun configureUiHelper(helper: TreeUIHelper?) {
- TreeSpeedSearch(this).apply {
- setCanExpand(true)
- }
- }
- }.apply {
- emptyText.setText(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.loading"))
- selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
- isRootVisible = false
- showsRootHandles = true
- isLargeModel = true
- TreeUtil.installActions(this)
-
- model = createModel(this)
-
- addTreeExpansionListener(object : TreeExpansionListener {
- override fun treeExpanded(event: TreeExpansionEvent) {
- event.path.lastPathComponent.cast()?.userObject?.cast()?.onExpanded()
- }
-
- override fun treeCollapsed(event: TreeExpansionEvent) {}
- })
-
- addTreeSelectionListener {
- val selectedNode = it.path.lastPathComponent.cast()?.userObject
- okAction.isEnabled = selectedNode is DatabaseNode || selectedNode is ApolloDebugNormalizedCacheNode
- }
- }
- return tree
- }
-
- private fun createModel(tree: SimpleTree): TreeModel {
- val structure = PullFromDeviceTreeStructure(project, invalidate = {
- invokeLater(ModalityState.any()) {
- model.invalidateAsync()
- }
- })
- model = StructureTreeModel(structure, this)
- return AsyncTreeModel(model, this).apply {
- addTreeModelListener(AutoExpandSimpleNodeListener(tree))
- }
- }
-
- override fun doOKAction() {
- when (val selectedNode = tree.selectionPath?.lastPathComponent.cast()?.userObject) {
- is DatabaseNode -> {
- onSourceSelected(
- NormalizedCacheSource.DeviceFile(
- device = selectedNode.device,
- packageName = selectedNode.packageName,
- remoteDirName = selectedNode.databasesDir,
- remoteFileName = selectedNode.databaseFileName,
- )
- )
- }
-
- is ApolloDebugNormalizedCacheNode -> {
- // Don't close the apolloClient, it will be closed later by the caller
- apolloDebugClientsToClose.remove(selectedNode.apolloDebugClient)
- onSourceSelected(
- NormalizedCacheSource.ApolloDebugServer(
- apolloDebugClient = selectedNode.apolloDebugClient,
- apolloClientId = selectedNode.apolloClient.id,
- normalizedCacheId = selectedNode.normalizedCache.id
- )
- )
- }
- }
- super.doOKAction()
- }
-
- override fun dispose() {
- super.dispose()
- apolloDebugClientsToClose.forEach { runCatching { it.close() } }
- }
-
- private inner class PullFromDeviceTreeStructure(project: Project, invalidate: () -> Unit) : SimpleTreeStructure() {
- private val root = PullFromDeviceRootNode(project, invalidate)
- override fun getRootElement() = root
- }
-
- private inner class PullFromDeviceRootNode(project: Project, invalidate: () -> Unit) : RootDynamicNode(project, invalidate) {
- override fun computeChildren() {
- try {
- val connectedDevices = getConnectedDevices()
- if (connectedDevices.isEmpty()) {
- updateChild(EmptyNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDevices.empty")))
- } else {
- updateChildren(
- connectedDevices
- .map { device ->
- DeviceNode(project, this, device)
- }
- )
- }
- } catch (e: Exception) {
- logw(e, "Could not list devices")
- updateChild(ErrorNode(
- ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDevices.error", e.message?.let { ": $it" } ?: "")
- ))
- }
- }
- }
-
- private inner class DeviceNode(project: Project, parent: DynamicNode, private val device: IDevice) : DynamicNode(project, parent) {
- init {
- myName = device.name
- icon = if (device.isEmulator) StudioIcons.DeviceExplorer.VIRTUAL_DEVICE_PHONE else StudioIcons.DeviceExplorer.PHYSICAL_DEVICE_PHONE
- }
-
- override fun computeChildren() {
- val apolloDebugClients: List = device.getApolloDebugClients().getOrDefault(emptyList())
- apolloDebugClientsToClose.addAll(apolloDebugClients)
- val clients: List = device.clients
- .filter { client ->
- client.isValid &&
- client.clientData.packageName != null &&
- // If a package has the Apollo Debug running, don't show it as a database package
- client.clientData.packageName !in apolloDebugClients.map { it.packageName }
- }
- .sortedBy { it.clientData.packageName }
-
- val allClients = (apolloDebugClients + clients).sortedBy {
- when (it) {
- is ApolloDebugClient -> it.packageName
- is Client -> it.clientData.packageName
- else -> throw IllegalStateException()
- }
- }
-
- updateChildren(
- buildList {
- val autoExpand = allClients.size <= 4
-
- // Add running apps
- addAll(
- allClients.map { client ->
- when (client) {
- is ApolloDebugClient -> ApolloDebugPackageNode(
- project = project,
- parent = this@DeviceNode,
- apolloDebugClient = client,
- computeChildrenOn = ComputeChildrenOn.INIT,
- autoExpand = autoExpand,
- )
-
- is Client -> {
- val packageName = client.clientData.packageName
- val databasesDir = client.clientData.dataDir + "/databases"
- DatabasePackageNode(
- project = project,
- parent = this@DeviceNode,
- device = device,
- packageName = packageName,
- databasesDir = databasesDir,
- computeChildrenOn = ComputeChildrenOn.INIT,
- autoExpand = autoExpand,
- )
- }
-
- else -> throw IllegalStateException()
- }
- }
- )
-
- // Add other debuggable apps
- add(DebuggablePackagesNode(project, this@DeviceNode, device))
- }
- )
- }
-
- override fun isAutoExpandNode(): Boolean {
- return true
- }
- }
-
- private inner class DebuggablePackagesNode(
- project: Project,
- parent: DynamicNode,
- private val device: IDevice,
- ) : DynamicNode(project, parent) {
- init {
- myName = ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDebuggablePackages.title")
- }
-
- @SuppressLint("SdCardPath")
- override fun computeChildren() {
- device.getDebuggablePackageList().onFailure {
- logw(it, "Could not list debuggable packages")
- updateChild(ErrorNode((ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDebuggablePackages.error"))))
- }.onSuccess {
- if (it.isEmpty()) {
- updateChild(EmptyNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDebuggablePackages.empty")))
- } else {
- updateChildren(
- it.map { packageName ->
- DatabasePackageNode(
- project = project,
- parent = this,
- device = device,
- packageName = packageName,
- databasesDir = "/data/data/$packageName/databases",
- computeChildrenOn = ComputeChildrenOn.EXPANDED,
- autoExpand = false,
- )
- }
- )
- }
- }
- }
- }
-
- private inner class DatabasePackageNode(
- project: Project,
- parent: DynamicNode,
- private val device: IDevice,
- private val packageName: String,
- private val databasesDir: String,
- computeChildrenOn: ComputeChildrenOn,
- private val autoExpand: Boolean,
- ) : DynamicNode(project, parent, computeChildrenOn) {
- init {
- myName = packageName
- icon = ApolloIcons.Node.Package
- }
-
- override fun computeChildren() {
- device.getDatabaseList(packageName, databasesDir).onFailure {
- logw(it, "Could not list databases")
- updateChild(ErrorNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDatabases.error")))
- }.onSuccess {
- if (it.isEmpty()) {
- updateChild(EmptyNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listDatabases.empty")))
- } else {
- updateChildren(
- it
- .map { databaseFileName ->
- DatabaseNode(
- device = device,
- packageName = packageName,
- databasesDir = databasesDir,
- databaseFileName = databaseFileName,
- )
- }
- )
- }
- }
- }
-
- override fun isAutoExpandNode(): Boolean {
- return autoExpand
- }
- }
-
- private inner class ApolloDebugPackageNode(
- project: Project,
- parent: DynamicNode,
- private val apolloDebugClient: ApolloDebugClient,
- computeChildrenOn: ComputeChildrenOn,
- private val autoExpand: Boolean,
- ) : DynamicNode(project, parent, computeChildrenOn) {
- init {
- myName = apolloDebugClient.packageName
- icon = ApolloIcons.Node.Package
- }
-
- override fun computeChildren() {
- runBlocking { apolloDebugClient.getApolloClients() }.onFailure {
- logw(it, "Could not list Apollo clients")
- updateChild(ErrorNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listApolloClients.error")))
- }.onSuccess { apolloClients ->
- if (apolloClients.isEmpty()) {
- updateChild(EmptyNode(ApolloBundle.message("normalizedCacheViewer.pullFromDevice.listApolloClients.empty")))
- } else {
- val showClientName = apolloClients.size > 1
- updateChildren(
- apolloClients
- .flatMap { apolloClient -> apolloClient.normalizedCaches.map { normalizedCache -> apolloClient to normalizedCache } }
- .filter { (_, normalizedCacheInfo) -> normalizedCacheInfo.recordCount != 0 }
- .map { (apolloClient, normalizedCache) ->
- ApolloDebugNormalizedCacheNode(
- apolloDebugClient = apolloDebugClient,
- apolloClient = apolloClient,
- normalizedCache = normalizedCache,
- showClientName = showClientName,
- )
- }
- )
- }
- }
- }
-
- override fun isAutoExpandNode(): Boolean {
- return autoExpand
- }
- }
-
- private inner class DatabaseNode(
- val device: IDevice,
- val packageName: String,
- val databasesDir: String,
- val databaseFileName: String,
- ) : NullNode() {
- init {
- myName = databaseFileName
- icon = StudioIcons.DatabaseInspector.DATABASE
- }
-
- override fun handleDoubleClickOrEnter(tree: SimpleTree, inputEvent: InputEvent) {
- doOKAction()
- }
- }
-
- private inner class ApolloDebugNormalizedCacheNode(
- val apolloDebugClient: ApolloDebugClient,
- val apolloClient: GetApolloClientsQuery.ApolloClient,
- val normalizedCache: GetApolloClientsQuery.NormalizedCach,
- showClientName: Boolean,
- ) : NullNode() {
- init {
- myName = if (showClientName) {
- "${apolloClient.displayName} - ${normalizedCache.displayName.normalizedCacheSimpleName}"
- } else {
- normalizedCache.displayName.normalizedCacheSimpleName
- }
- presentation.locationString = ApolloBundle.message("normalizedCacheViewer.pullFromDevice.apolloDebugNormalizedCache.records", normalizedCache.recordCount)
- icon = StudioIcons.DatabaseInspector.DATABASE
- }
-
- override fun handleDoubleClickOrEnter(tree: SimpleTree, inputEvent: InputEvent) {
- doOKAction()
- }
- }
-
- private class ErrorNode(message: String) : NullNode() {
- init {
- presentation.addText(message, SimpleTextAttributes.GRAYED_ATTRIBUTES)
- }
- }
-
- private class EmptyNode(message: String) : NullNode() {
- init {
- presentation.addText(message, SimpleTextAttributes.GRAYED_ATTRIBUTES)
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ShowNormalizedCacheToolWindowAction.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ShowNormalizedCacheToolWindowAction.kt
deleted file mode 100644
index 2a457788d23..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ShowNormalizedCacheToolWindowAction.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache
-
-import com.apollographql.ijplugin.util.logd
-import com.intellij.openapi.actionSystem.ActionUpdateThread
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.project.DumbAwareAction
-import com.intellij.openapi.wm.ToolWindowManager
-
-class ShowNormalizedCacheToolWindowAction : DumbAwareAction() {
- override fun actionPerformed(e: AnActionEvent) {
- logd()
- e.project?.let { ToolWindowManager.getInstance(it).getToolWindow("NormalizedCacheViewer") }?.show()
- }
-
- override fun getActionUpdateThread() = ActionUpdateThread.BGT
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/ApolloDebugNormalizedCacheProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/ApolloDebugNormalizedCacheProvider.kt
deleted file mode 100644
index 6d7cf8e9769..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/ApolloDebugNormalizedCacheProvider.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.provider
-
-import com.apollographql.apollo.api.json.JsonNumber
-import com.apollographql.ijplugin.apollodebugserver.GetNormalizedCacheQuery
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.Field
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.BooleanValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.CompositeValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.ErrorValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.ListValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.Null
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.NumberValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.Reference
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.StringValue
-
-class ApolloDebugNormalizedCacheProvider : NormalizedCacheProvider {
- override fun provide(parameters: GetNormalizedCacheQuery.NormalizedCache): Result {
- return runCatching {
- NormalizedCache(
- parameters.records.map { record ->
- NormalizedCache.Record(
- key = record.key,
- fields = record.fields.toFields(),
- sizeInBytes = record.sizeInBytes,
- )
- }
- )
- }
- }
-}
-
-@Suppress("UNCHECKED_CAST")
-private fun Any.toFields(): List {
- this as Map
- return map { (name, value) ->
- Field(
- name,
- value.toFieldValue()
- )
- }
-}
-
-private fun Any?.toFieldValue(): FieldValue {
- return when (this) {
- null -> Null
- is String -> when {
- this.startsWith(APOLLO_CACHE_REFERENCE_PREFIX) -> {
- Reference(this.removePrefix(APOLLO_CACHE_REFERENCE_PREFIX).removeSuffix("}"))
- }
-
- this.startsWith(APOLLO_CACHE_ERROR_PREFIX) -> {
- ErrorValue(this.removePrefix(APOLLO_CACHE_ERROR_PREFIX).removeSuffix("}"))
- }
-
- else -> {
- StringValue(this)
- }
- }
-
- is Number -> NumberValue(this.toString())
- is JsonNumber -> NumberValue(this.value)
- is Boolean -> BooleanValue(this)
- is List<*> -> ListValue(map { it.toFieldValue() })
- is Map<*, *> -> CompositeValue(map { Field(it.key as String, it.value.toFieldValue()) })
- else -> error("Unsupported type ${this::class}")
- }
-}
-
-private const val APOLLO_CACHE_REFERENCE_PREFIX = "ApolloCacheReference{"
-private const val APOLLO_CACHE_ERROR_PREFIX = "ApolloCacheError{"
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/DatabaseNormalizedCacheProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/DatabaseNormalizedCacheProvider.kt
deleted file mode 100644
index cb8fcb394a7..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/DatabaseNormalizedCacheProvider.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.provider
-
-import com.apollographql.apollo.api.Error
-import com.apollographql.apollo.api.json.JsonNumber
-import com.apollographql.cache.normalized.api.CacheKey
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.Field
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.BooleanValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.CompositeValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.ErrorValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.ListValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.Null
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.NumberValue
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.Reference
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache.FieldValue.StringValue
-import java.io.File
-import java.sql.DriverManager
-import com.apollographql.apollo.cache.normalized.api.CacheKey as ApolloClassicCacheKey
-import com.apollographql.apollo.cache.normalized.api.NormalizedCache as ApolloClassicNormalizedCache
-import com.apollographql.apollo.cache.normalized.api.Record as ApolloClassicRecord
-import com.apollographql.apollo.cache.normalized.sql.SqlNormalizedCacheFactory as ApolloClassicSqlNormalizedCacheFactory
-import com.apollographql.cache.normalized.api.CacheKey as ApolloModernCacheKey
-import com.apollographql.cache.normalized.api.NormalizedCache as ApolloModernNormalizedCache
-import com.apollographql.cache.normalized.api.Record as ApolloModernRecord
-import com.apollographql.cache.normalized.sql.SqlNormalizedCacheFactory as ApolloModernSqlNormalizedCacheFactory
-
-class DatabaseNormalizedCacheProvider : NormalizedCacheProvider {
- private enum class DbFormat {
- /**
- * Classic format with records containing JSON text, implemented in
- * `com.apollographql.apollo:apollo-normalized-cache-sqlite`.
- */
- CLASSIC,
-
- /**
- * Modern format with records containing a binary format, implemented in
- * `com.apollographql.cache:normalized-cache-sqlite-incubating`.
- */
- MODERN,
-
- UNKNOWN_OR_ERROR,
- }
-
- private fun checkDatabase(url: String): DbFormat {
- Class.forName("org.sqlite.JDBC")
-
- DriverManager.getConnection(url).use { connection ->
- runCatching {
- connection.createStatement().executeQuery("SELECT key, record FROM records").use { resultSet ->
- if (resultSet.next()) {
- return DbFormat.CLASSIC
- }
- }
- }
- runCatching {
- connection.createStatement().executeQuery("SELECT key, record FROM record").use { resultSet ->
- if (resultSet.next()) {
- return DbFormat.MODERN
- }
- }
- }
- }
- return DbFormat.UNKNOWN_OR_ERROR
- }
-
- override fun provide(parameters: File): Result {
- val url = "jdbc:sqlite:${parameters.absolutePath}"
- return runCatching {
- val format = checkDatabase(url)
- when (format) {
- DbFormat.CLASSIC -> readClassicDb(url)
- DbFormat.MODERN -> readModernDb(url)
- DbFormat.UNKNOWN_OR_ERROR -> error("Empty cache: no records were found")
- }
- }
- }
-
- private fun readClassicDb(url: String): NormalizedCache {
- val apolloNormalizedCache: ApolloClassicNormalizedCache = ApolloClassicSqlNormalizedCacheFactory(url).create()
- val apolloRecords: Map = apolloNormalizedCache.dump().values.first()
- return NormalizedCache(
- apolloRecords.map { (key, apolloRecord) ->
- NormalizedCache.Record(
- key = key,
- fields = apolloRecord.map { (fieldKey, fieldValue) ->
- Field(fieldKey, fieldValue.toFieldValue())
- },
- sizeInBytes = apolloRecord.sizeInBytes
- )
- }
- )
- }
-
- private fun readModernDb(url: String): NormalizedCache {
- val apolloNormalizedCache: ApolloModernNormalizedCache = ApolloModernSqlNormalizedCacheFactory(url).create()
- val apolloRecords: Map = apolloNormalizedCache.dump().values.first()
- return NormalizedCache(
- apolloRecords.map { (key, apolloRecord) ->
- NormalizedCache.Record(
- key = key.key,
- fields = apolloRecord.map { (fieldKey, fieldValue) ->
- Field(fieldKey, fieldValue.toFieldValue())
- },
- sizeInBytes = apolloRecord.sizeInBytes
- )
- }
- )
- }
-}
-
-private fun Any?.toFieldValue(): FieldValue {
- return when (this) {
- null -> Null
- is String -> StringValue(this)
- is Number -> NumberValue(this.toString())
- is JsonNumber -> NumberValue(this.value)
- is Boolean -> BooleanValue(this)
- is List<*> -> ListValue(map { it.toFieldValue() })
- is Map<*, *> -> CompositeValue(map { Field(it.key as String, it.value.toFieldValue()) })
- is ApolloClassicCacheKey -> Reference(this.key)
- is ApolloModernCacheKey -> Reference(this.key)
- is Error -> ErrorValue(this.message)
- else -> error("Unsupported type ${this::class}")
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/NormalizedCacheProvider.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/NormalizedCacheProvider.kt
deleted file mode 100644
index d0a0f3c5c8f..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/provider/NormalizedCacheProvider.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.provider
-
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-
-interface NormalizedCacheProvider {
- fun provide(parameters: P): Result
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTable.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTable.kt
deleted file mode 100644
index 61ef46e2311..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTable.kt
+++ /dev/null
@@ -1,174 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.intellij.ide.DefaultTreeExpander
-import com.intellij.ide.TreeExpander
-import com.intellij.openapi.application.invokeLater
-import com.intellij.openapi.ide.CopyPasteManager
-import com.intellij.openapi.ui.JBMenuItem
-import com.intellij.openapi.ui.JBPopupMenu
-import com.intellij.ui.ColoredTableCellRenderer
-import com.intellij.ui.SimpleTextAttributes
-import com.intellij.ui.components.JBTreeTable
-import com.intellij.util.ui.UIUtil
-import java.awt.Color
-import java.awt.Component
-import java.awt.Cursor
-import java.awt.Point
-import java.awt.datatransfer.StringSelection
-import java.awt.event.MouseAdapter
-import java.awt.event.MouseEvent
-import javax.swing.JTable
-import javax.swing.SwingUtilities
-import javax.swing.event.PopupMenuEvent
-import javax.swing.event.PopupMenuListener
-import javax.swing.tree.TreePath
-
-@Suppress("UnstableApiUsage")
-class FieldTreeTable(selectRecord: (String) -> Unit) : JBTreeTable(FieldTreeTableModel()) {
- val treeExpander: TreeExpander = DefaultTreeExpander { tree }
-
- init {
- columnProportion = .8F
- setDefaultRenderer(
- NormalizedCache.Field::class.java,
- object : ColoredTableCellRenderer() {
- override fun customizeCellRenderer(table: JTable, value: Any?, selected: Boolean, hasFocus: Boolean, row: Int, column: Int) {
- value as NormalizedCache.Field
- when (val v = value.value) {
- is NormalizedCache.FieldValue.StringValue -> append("\"${v.value}\"")
- is NormalizedCache.FieldValue.NumberValue -> append(v.value)
- is NormalizedCache.FieldValue.BooleanValue -> append(v.value.toString())
- is NormalizedCache.FieldValue.ListValue -> append(
- when (val size = v.value.size) {
- 0 -> ApolloBundle.message("normalizedCacheViewer.fields.list.empty")
- 1 -> ApolloBundle.message("normalizedCacheViewer.fields.list.single")
- else -> ApolloBundle.message("normalizedCacheViewer.fields.list.multiple", size)
- },
- SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES
- )
-
- is NormalizedCache.FieldValue.CompositeValue -> append("{...}", SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES)
- NormalizedCache.FieldValue.Null -> append("null")
- is NormalizedCache.FieldValue.Reference -> {
- append("→ ", SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES)
- append(v.key, SimpleTextAttributes.LINK_PLAIN_ATTRIBUTES)
- }
- is NormalizedCache.FieldValue.ErrorValue -> {
- append("Error: '${v.message}'", SimpleTextAttributes.ERROR_ATTRIBUTES)
- }
- }
- }
- }
- )
-
- // Handle reference clicks and cursor changes
- val mouseAdapter = object : MouseAdapter() {
- override fun mouseClicked(e: MouseEvent) {
- if (e.button != MouseEvent.BUTTON1) return
- table.cursor = Cursor(Cursor.DEFAULT_CURSOR)
- val field = getFieldAtPoint(e) ?: return
- if (field.value is NormalizedCache.FieldValue.Reference) {
- selectRecord(field.value.key)
- }
- }
-
- override fun mouseMoved(e: MouseEvent) {
- table.cursor = Cursor(
- if (getFieldAtPoint(e)?.value is NormalizedCache.FieldValue.Reference) {
- Cursor.HAND_CURSOR
- } else {
- Cursor.DEFAULT_CURSOR
- }
- )
- }
-
- override fun mouseExited(e: MouseEvent) {
- table.cursor = Cursor(Cursor.DEFAULT_CURSOR)
- }
- }
- table.addMouseListener(mouseAdapter)
- table.addMouseMotionListener(mouseAdapter)
-
- table.isStriped = true
-
- installPopupMenu()
- }
-
- override fun getPathBackground(path: TreePath, row: Int): Color? {
- return if (row % 2 == 0) {
- UIUtil.getDecoratedRowColor()
- } else {
- null
- }
- }
-
- override fun getModel(): FieldTreeTableModel = super.getModel() as FieldTreeTableModel
-
- fun setRecord(record: NormalizedCache.Record) {
- model.setRecord(record)
- }
-
- private fun installPopupMenu() {
- val popupMenu = object : JBPopupMenu() {
- override fun show(invoker: Component, x: Int, y: Int) {
- when (getFieldAtPoint(x, y)?.value) {
- is NormalizedCache.FieldValue.StringValue,
- is NormalizedCache.FieldValue.NumberValue,
- is NormalizedCache.FieldValue.BooleanValue,
- is NormalizedCache.FieldValue.Reference,
- NormalizedCache.FieldValue.Null,
- -> {
- super.show(invoker, x, y)
- }
-
- else -> {}
- }
- }
- }
- popupMenu.add(JBMenuItem(ApolloBundle.message("normalizedCacheViewer.fields.popupMenu.copyValue")).apply {
- addActionListener {
- val field = table.getValueAt(table.selectedRow, table.selectedColumn) as NormalizedCache.Field
- val valueStr = when (val value = field.value) {
- is NormalizedCache.FieldValue.StringValue -> value.value
- is NormalizedCache.FieldValue.NumberValue -> value.value
- is NormalizedCache.FieldValue.BooleanValue -> value.value.toString()
- is NormalizedCache.FieldValue.Reference -> value.key
- NormalizedCache.FieldValue.Null -> "null"
- else -> return@addActionListener
- }
- CopyPasteManager.getInstance().setContents(StringSelection(valueStr))
- }
- })
-
- // Select the row under the popup menu
- popupMenu.addPopupMenuListener(object : PopupMenuListener {
- override fun popupMenuWillBecomeVisible(e: PopupMenuEvent) {
- invokeLater {
- val row = table.rowAtPoint(SwingUtilities.convertPoint(popupMenu, Point(0, 0), table))
- val column = table.columnAtPoint(SwingUtilities.convertPoint(popupMenu, Point(0, 0), table))
- table.setRowSelectionInterval(row, row)
- table.setColumnSelectionInterval(column, column)
- }
- }
-
- override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent) {}
-
- override fun popupMenuCanceled(e: PopupMenuEvent) {}
- })
- table.componentPopupMenu = popupMenu
- }
-
- private fun getFieldAtPoint(x: Int, y: Int): NormalizedCache.Field? {
- val point = Point(x, y)
- val row = table.rowAtPoint(point)
- // Add 1 to account for the tree column
- val column = table.columnAtPoint(point) + 1
- return table.model.getValueAt(row, column) as NormalizedCache.Field?
- }
-
- private fun getFieldAtPoint(e: MouseEvent): NormalizedCache.Field? {
- return getFieldAtPoint(e.x, e.y)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTableModel.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTableModel.kt
deleted file mode 100644
index da8c84ac059..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FieldTreeTableModel.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.intellij.ui.treeStructure.treetable.ListTreeTableModel
-import com.intellij.ui.treeStructure.treetable.TreeTableModel
-import com.intellij.util.ui.ColumnInfo
-import javax.swing.tree.DefaultMutableTreeNode
-
-class FieldTreeTableModel : ListTreeTableModel(
- DefaultMutableTreeNode(),
- arrayOf(
- object : ColumnInfo(ApolloBundle.message("normalizedCacheViewer.fields.column.key")) {
- override fun getColumnClass() = TreeTableModel::class.java
- override fun valueOf(item: Unit) = Unit
- },
- object :
- ColumnInfo(ApolloBundle.message("normalizedCacheViewer.fields.column.value")) {
- override fun getColumnClass() = NormalizedCache.Field::class.java
- override fun valueOf(item: NormalizedCacheFieldTreeNode) = item.field
- },
- ),
-) {
- fun setRecord(record: NormalizedCache.Record) {
- setRoot(getRootNodeForRecord(record))
- }
-
- private fun getRootNodeForRecord(record: NormalizedCache.Record) = DefaultMutableTreeNode().apply {
- addFields(record.fields)
- }
-
- private fun DefaultMutableTreeNode.addFields(fields: List) {
- for (field in fields) {
- val childNode = NormalizedCacheFieldTreeNode(field)
- add(childNode)
- when (val value = field.value) {
- is NormalizedCache.FieldValue.ListValue -> childNode.addFields(value.value.mapIndexed { i, v -> NormalizedCache.Field(i.toString(), v) })
- is NormalizedCache.FieldValue.CompositeValue -> childNode.addFields(value.value)
- else -> {}
- }
- }
- }
-
- class NormalizedCacheFieldTreeNode(val field: NormalizedCache.Field) : DefaultMutableTreeNode() {
- init {
- userObject = field.key
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FilterHighlightTableCellRenderer.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FilterHighlightTableCellRenderer.kt
deleted file mode 100644
index 7c40cab61cf..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/FilterHighlightTableCellRenderer.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.intellij.openapi.util.TextRange
-import com.intellij.ui.ColoredTableCellRenderer
-import com.intellij.ui.speedSearch.SpeedSearchUtil
-import javax.swing.JTable
-
-class FilterHighlightTableCellRenderer : ColoredTableCellRenderer() {
- var filter: String? = null
-
- override fun customizeCellRenderer(
- table: JTable,
- value: Any?,
- selected: Boolean,
- hasFocus: Boolean,
- row: Int,
- column: Int,
- ) {
- append(value as String)
-
- filter?.let { filter ->
- if (filter.isEmpty()) return
- val matchIndex = value.indexOf(filter, ignoreCase = true)
- if (matchIndex == -1) return
- val textRange = TextRange(matchIndex, matchIndex + filter.length)
- SpeedSearchUtil.applySpeedSearchHighlighting(this, listOf(textRange), selected)
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordSearchTextField.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordSearchTextField.kt
deleted file mode 100644
index d8738f0b0a5..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordSearchTextField.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.intellij.ui.DocumentAdapter
-import com.intellij.ui.IdeBorderFactory
-import com.intellij.ui.SearchTextField
-import com.intellij.ui.SideBorder
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import java.awt.event.KeyEvent
-import java.awt.event.KeyListener
-import javax.swing.InputMap
-import javax.swing.JTable
-import javax.swing.KeyStroke
-import javax.swing.event.DocumentEvent
-import javax.swing.event.DocumentListener
-
-/**
- * Allows to delegate typing a filter to this text field when the table is focused, and to delegate up/down events to the table when this
- * text field is focused.
- * Inspired by [com.intellij.openapi.options.newEditor.SettingsSearch].
- */
-class RecordSearchTextField(private val recordTable: RecordTable) : SearchTextField(false), KeyListener {
- init {
- border = IdeBorderFactory.createBorder(SideBorder.BOTTOM)
- textEditor.border = JBUI.Borders.empty()
- textEditor.background = recordTable.background
- UIUtil.setBackgroundRecursively(this, recordTable.background)
-
- addDocumentListener(object : DocumentAdapter() {
- override fun textChanged(e: DocumentEvent) {
- recordTable.setFilter(text.trim())
- }
- })
- }
-
- override fun addDocumentListener(listener: DocumentListener?) = super.addDocumentListener(listener)
-
- private var isDelegatingNow = false
-
- override fun preprocessEventForTextField(event: KeyEvent): Boolean {
- if (!isDelegatingNow) {
- val stroke = KeyStroke.getKeyStrokeForEvent(event)
- val strokeString = stroke.toString()
- // Reset filter on ESC
- if ("pressed ESCAPE" == strokeString && text.isNotEmpty()) {
- text = ""
- return true
- }
- if (textEditor.isFocusOwner) {
- try {
- isDelegatingNow = true
- val code = stroke.keyCode
- val tableNavigation = stroke.modifiers == 0 && (code == KeyEvent.VK_UP || code == KeyEvent.VK_DOWN)
- if (tableNavigation || !hasAction(stroke, textEditor.inputMap)) {
- recordTable.processKeyEvent(event)
- return true
- }
- } finally {
- isDelegatingNow = false
- }
- }
- }
- return false
- }
-
- override fun keyPressed(event: KeyEvent) = keyTyped(event)
-
- override fun keyReleased(event: KeyEvent) = keyTyped(event)
-
- override fun keyTyped(event: KeyEvent) {
- val source = event.source
- if (source is JTable) {
- if (!hasAction(KeyStroke.getKeyStrokeForEvent(event), source.inputMap)) {
- keyEventToTextField(event)
- }
- }
- }
-
- companion object {
- private fun hasAction(stroke: KeyStroke, map: InputMap?): Boolean {
- return map != null && map[stroke] != null
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTable.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTable.kt
deleted file mode 100644
index 77cf9197b27..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTable.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.intellij.ui.ScrollingUtil
-import com.intellij.ui.table.JBTable
-import com.intellij.util.ui.JBFont
-import com.intellij.util.ui.NamedColorUtil
-import java.awt.Component
-import java.awt.event.KeyEvent
-import javax.swing.JTable
-import javax.swing.ListSelectionModel
-import javax.swing.SwingConstants
-import javax.swing.table.DefaultTableCellRenderer
-
-class RecordTable(normalizedCache: NormalizedCache) : JBTable(RecordTableModel(normalizedCache)) {
- private val filterHighlightTableCellRenderer = FilterHighlightTableCellRenderer()
-
- init {
- columnModel.getColumn(0).cellRenderer = filterHighlightTableCellRenderer
- columnModel.getColumn(1).cellRenderer = object : DefaultTableCellRenderer() {
- override fun getTableCellRendererComponent(
- table: JTable?,
- value: Any?,
- isSelected: Boolean,
- hasFocus: Boolean,
- row: Int,
- column: Int,
- ): Component {
- super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column)
- font = JBFont.small()
- return this
- }
- }.apply {
- horizontalAlignment = SwingConstants.RIGHT
- foreground = NamedColorUtil.getInactiveTextColor()
- }
-
- columnModel.getColumn(1).maxWidth = 50
-
- selectionModel.selectionMode = ListSelectionModel.SINGLE_SELECTION
- ScrollingUtil.installActions(this)
- setShowGrid(false)
- setShowColumns(true)
- setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
- columnSelectionAllowed = false
- tableHeader.reorderingAllowed = false
- }
-
- public override fun processKeyEvent(e: KeyEvent) {
- super.processKeyEvent(e)
- }
-
- override fun getModel(): RecordTableModel = super.getModel() as RecordTableModel
-
- fun selectRecord(key: String) {
- val index = model.indexOfRecord(key)
- if (index != -1) {
- val indexAfterSort = convertRowIndexToView(index)
- selectionModel.setSelectionInterval(indexAfterSort, indexAfterSort)
- scrollRectToVisible(getCellRect(selectedRow, 0, true).apply {
- y -= height / 2
- height *= 2
- })
- }
- }
-
- fun setFilter(filter: String) {
- model.setFilter(filter)
- filterHighlightTableCellRenderer.filter = filter
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTableModel.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTableModel.kt
deleted file mode 100644
index 46663c4aaf0..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/normalizedcache/ui/RecordTableModel.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.apollographql.ijplugin.normalizedcache.ui
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.normalizedcache.NormalizedCache
-import com.intellij.openapi.util.text.StringUtil
-import com.intellij.util.ui.ColumnInfo
-import com.intellij.util.ui.ListTableModel
-
-class RecordTableModel(private val normalizedCache: NormalizedCache) : ListTableModel(
- object : ColumnInfo(ApolloBundle.message("normalizedCacheViewer.records.table.key")) {
- override fun valueOf(item: NormalizedCache.Record) = item.key
- override fun getComparator(): Comparator = NormalizedCache.RecordKeyComparator
- },
- object : ColumnInfo(ApolloBundle.message("normalizedCacheViewer.records.table.size")) {
- override fun valueOf(item: NormalizedCache.Record) = StringUtil.formatFileSize(item.sizeInBytes.toLong())
- override fun getComparator(): Comparator = Comparator.comparingInt { it.sizeInBytes }
- },
-) {
- init {
- setItems(normalizedCache.records)
- }
-
- fun getRecordAt(row: Int): NormalizedCache.Record? {
- if (row < 0 || row >= rowCount) return null
- return getValueAt(row, 0)?.let { selectedKey ->
- normalizedCache.records.first { it.key == selectedKey }
- }
- }
-
- fun isRecordShowing(key: String): Boolean {
- return indexOfRecord(key) != -1
- }
-
- fun indexOfRecord(key: String): Int {
- for (i in 0 until rowCount) {
- val value = getValueAt(i, 0)
- if (value == key) {
- return i
- }
- }
- return -1
- }
-
- fun setFilter(filter: String) {
- setItems(normalizedCache.records.filter { it.key.contains(filter, ignoreCase = true) })
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectListener.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectListener.kt
deleted file mode 100644
index 2a14d29fbb3..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectListener.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.apollographql.ijplugin.project
-
-import com.intellij.util.messages.Topic
-
-interface ApolloProjectListener {
- companion object {
- @Topic.ProjectLevel
- val TOPIC: Topic = Topic.create("Apollo project", ApolloProjectListener::class.java)
- }
-
- fun apolloProjectChanged(apolloVersion: ApolloProjectService.ApolloVersion)
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectManagerListener.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectManagerListener.kt
deleted file mode 100644
index 3ba45f6ead4..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectManagerListener.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.apollographql.ijplugin.project
-
-import com.apollographql.ijplugin.codegen.ApolloCodegenService
-import com.apollographql.ijplugin.gradle.GradleToolingModelService
-import com.apollographql.ijplugin.graphql.GraphQLConfigService
-import com.apollographql.ijplugin.lsp.ApolloLspAppService
-import com.apollographql.ijplugin.lsp.ApolloLspProjectService
-import com.apollographql.ijplugin.settings.ProjectSettingsService
-import com.apollographql.ijplugin.studio.fieldinsights.FieldInsightsService
-import com.apollographql.ijplugin.studio.sandbox.SandboxService
-import com.apollographql.ijplugin.telemetry.TelemetryService
-import com.apollographql.ijplugin.util.isGradlePluginPresent
-import com.apollographql.ijplugin.util.isKotlinPluginPresent
-import com.apollographql.ijplugin.util.isLspAvailable
-import com.apollographql.ijplugin.util.logd
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.DumbService
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.ProjectManagerListener
-import com.intellij.util.application
-
-internal class ApolloProjectManagerListener : ProjectManagerListener {
- override fun projectOpened(project: Project) {
- logd()
-
- // Initialize all services on project open.
- // But wait for 'smart mode' to do it.
- // Most of these services can't operate without the Kotlin and Gradle plugins (e.g. in RustRover).
- DumbService.getInstance(project).runWhenSmart {
- logd("apolloVersion=" + project.apolloProjectService.apolloVersion)
- if (isKotlinPluginPresent && isGradlePluginPresent) {
- project.service()
- project.service()
- project.service()
- project.service()
- project.service()
- project.service()
- project.service()
- }
- if (isLspAvailable) {
- project.service()
- application.service()
- }
-
- project.apolloProjectService.isInitialized = true
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectService.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectService.kt
deleted file mode 100644
index 9861b7a761f..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectService.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.apollographql.ijplugin.project
-
-import com.intellij.openapi.components.service
-import com.intellij.openapi.project.Project
-
-interface ApolloProjectService {
- var isInitialized: Boolean
-
- enum class ApolloVersion {
- NONE,
- V2,
- V3,
- V4,
- V5,
- ;
- val isAtLeastV3 get() = this >= V3
- val isAtLeastV4 get() = this >= V4
- val isAtLeastV5 get() = this >= V5
- }
-
- val apolloVersion: ApolloVersion
-}
-
-val Project.apolloProjectService get() = service()
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectServiceImpl.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectServiceImpl.kt
deleted file mode 100644
index 4a9067e09a2..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/project/ApolloProjectServiceImpl.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.apollographql.ijplugin.project
-
-import com.apollographql.ijplugin.project.ApolloProjectService.ApolloVersion
-import com.apollographql.ijplugin.util.getApolloVersion
-import com.apollographql.ijplugin.util.logd
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.ModuleRootEvent
-import com.intellij.openapi.roots.ModuleRootListener
-
-class ApolloProjectServiceImpl(
- private val project: Project,
-) : ApolloProjectService, Disposable {
-
- override var apolloVersion: ApolloVersion = ApolloVersion.NONE
- override var isInitialized: Boolean = false
-
- init {
- logd("project=${project.name}")
- onLibrariesChanged()
- startObserveLibraries()
- }
-
- private fun startObserveLibraries() {
- logd()
- project.messageBus.connect(this).subscribe(ModuleRootListener.TOPIC, object : ModuleRootListener {
- override fun rootsChanged(event: ModuleRootEvent) {
- logd("event=$event")
- onLibrariesChanged()
- }
- })
- }
-
- private fun onLibrariesChanged() {
- logd()
- val previousApolloVersion = apolloVersion
- synchronized(this) {
- apolloVersion = project.getApolloVersion()
- }
- logd("apolloVersion=$apolloVersion")
- if (previousApolloVersion != apolloVersion) {
- project.messageBus.syncPublisher(ApolloProjectListener.TOPIC).apolloProjectChanged(apolloVersion = apolloVersion)
- }
- }
-
- override fun dispose() {
- logd("project=${project.name}")
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLElementTypes.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLElementTypes.kt
deleted file mode 100644
index 29c557ab8f0..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLElementTypes.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.apollographql.ijplugin.psi
-
-import com.intellij.psi.tree.IElementType
-
-object ApolloGraphQLElementTypes {
- @JvmField
- val AMP: IElementType = ApolloGraphQLTokenType("&")
-
- @JvmField
- val AT: IElementType = ApolloGraphQLTokenType("@")
-
- @JvmField
- val BANG: IElementType = ApolloGraphQLTokenType("!")
-
- @JvmField
- val BRACE_L: IElementType = ApolloGraphQLTokenType("{")
-
- @JvmField
- val BRACE_R: IElementType = ApolloGraphQLTokenType("}")
-
- @JvmField
- val BRACKET_L: IElementType = ApolloGraphQLTokenType("[")
-
- @JvmField
- val BRACKET_R: IElementType = ApolloGraphQLTokenType("]")
-
- @JvmField
- val CLOSING_QUOTE: IElementType = ApolloGraphQLTokenType("CLOSING_QUOTE")
-
- @JvmField
- val CLOSING_TRIPLE_QUOTE: IElementType = ApolloGraphQLTokenType("CLOSING_TRIPLE_QUOTE")
-
- @JvmField
- val COLON: IElementType = ApolloGraphQLTokenType(":")
-
- @JvmField
- val DIRECTIVE_KEYWORD: IElementType = ApolloGraphQLTokenType("directive")
-
- @JvmField
- val DOLLAR: IElementType = ApolloGraphQLTokenType("$")
-
- @JvmField
- val ENUM_KEYWORD: IElementType = ApolloGraphQLTokenType("enum")
-
- @JvmField
- val EOL_COMMENT: IElementType = ApolloGraphQLTokenType("EOL_COMMENT")
-
- @JvmField
- val EQUALS: IElementType = ApolloGraphQLTokenType("=")
-
- @JvmField
- val EXTEND_KEYWORD: IElementType = ApolloGraphQLTokenType("extend")
-
- @JvmField
- val FLOAT: IElementType = ApolloGraphQLTokenType("FLOAT")
-
- @JvmField
- val FRAGMENT_KEYWORD: IElementType = ApolloGraphQLTokenType("fragment")
-
- @JvmField
- val IMPLEMENTS_KEYWORD: IElementType = ApolloGraphQLTokenType("implements")
-
- @JvmField
- val INPUT_KEYWORD: IElementType = ApolloGraphQLTokenType("input")
-
- @JvmField
- val INTERFACE_KEYWORD: IElementType = ApolloGraphQLTokenType("interface")
-
- @JvmField
- val MUTATION_KEYWORD: IElementType = ApolloGraphQLTokenType("mutation")
-
- @JvmField
- val NAME: IElementType = ApolloGraphQLTokenType("NAME")
-
- @JvmField
- val NUMBER: IElementType = ApolloGraphQLTokenType("NUMBER")
-
- @JvmField
- val ON_KEYWORD: IElementType = ApolloGraphQLTokenType("on")
-
- @JvmField
- val OPEN_QUOTE: IElementType = ApolloGraphQLTokenType("OPEN_QUOTE")
-
- @JvmField
- val OPEN_TRIPLE_QUOTE: IElementType = ApolloGraphQLTokenType("OPEN_TRIPLE_QUOTE")
-
- @JvmField
- val PAREN_L: IElementType = ApolloGraphQLTokenType("(")
-
- @JvmField
- val PAREN_R: IElementType = ApolloGraphQLTokenType(")")
-
- @JvmField
- val PIPE: IElementType = ApolloGraphQLTokenType("|")
-
- @JvmField
- val QUERY_KEYWORD: IElementType = ApolloGraphQLTokenType("query")
-
- @JvmField
- val REGULAR_STRING_PART: IElementType = ApolloGraphQLTokenType("REGULAR_STRING_PART")
-
- @JvmField
- val REPEATABLE_KEYWORD: IElementType = ApolloGraphQLTokenType("repeatable")
-
- @JvmField
- val SCALAR_KEYWORD: IElementType = ApolloGraphQLTokenType("scalar")
-
- @JvmField
- val SCHEMA_KEYWORD: IElementType = ApolloGraphQLTokenType("schema")
-
- @JvmField
- val SPREAD: IElementType = ApolloGraphQLTokenType("...")
-
- @JvmField
- val SUBSCRIPTION_KEYWORD: IElementType = ApolloGraphQLTokenType("subscription")
-
- @JvmField
- val TEMPLATE_CHAR: IElementType = ApolloGraphQLTokenType("TEMPLATE_CHAR")
-
- @JvmField
- val TYPE_KEYWORD: IElementType = ApolloGraphQLTokenType("type")
-
- @JvmField
- val UNION_KEYWORD: IElementType = ApolloGraphQLTokenType("union")
-
- @JvmField
- val VARIABLE_NAME: IElementType = ApolloGraphQLTokenType("VARIABLE_NAME")
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLExtendedElementTypes.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLExtendedElementTypes.kt
deleted file mode 100644
index 84012f4b4a2..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLExtendedElementTypes.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.apollographql.ijplugin.psi
-
-import com.intellij.psi.tree.TokenSet
-
-interface ApolloGraphQLExtendedElementTypes {
- companion object {
- val KEYWORDS: TokenSet = TokenSet.create(
- ApolloGraphQLElementTypes.QUERY_KEYWORD,
- ApolloGraphQLElementTypes.MUTATION_KEYWORD,
- ApolloGraphQLElementTypes.SUBSCRIPTION_KEYWORD,
- ApolloGraphQLElementTypes.FRAGMENT_KEYWORD,
- ApolloGraphQLElementTypes.ON_KEYWORD,
- ApolloGraphQLElementTypes.SCHEMA_KEYWORD,
- ApolloGraphQLElementTypes.TYPE_KEYWORD,
- ApolloGraphQLElementTypes.SCALAR_KEYWORD,
- ApolloGraphQLElementTypes.INTERFACE_KEYWORD,
- ApolloGraphQLElementTypes.IMPLEMENTS_KEYWORD,
- ApolloGraphQLElementTypes.ENUM_KEYWORD,
- ApolloGraphQLElementTypes.UNION_KEYWORD,
- ApolloGraphQLElementTypes.EXTEND_KEYWORD,
- ApolloGraphQLElementTypes.INPUT_KEYWORD,
- ApolloGraphQLElementTypes.DIRECTIVE_KEYWORD,
- ApolloGraphQLElementTypes.REPEATABLE_KEYWORD
- )
-
- val SINGLE_QUOTES: TokenSet = TokenSet.create(ApolloGraphQLElementTypes.OPEN_QUOTE, ApolloGraphQLElementTypes.CLOSING_QUOTE)
- val TRIPLE_QUOTES: TokenSet =
- TokenSet.create(ApolloGraphQLElementTypes.OPEN_TRIPLE_QUOTE, ApolloGraphQLElementTypes.CLOSING_TRIPLE_QUOTE)
- val QUOTES: TokenSet = TokenSet.orSet(SINGLE_QUOTES, TRIPLE_QUOTES)
- val STRING_TOKENS: TokenSet = TokenSet.orSet(QUOTES, TokenSet.create(ApolloGraphQLElementTypes.REGULAR_STRING_PART))
- val NUMBER_LITERALS: TokenSet = TokenSet.create(ApolloGraphQLElementTypes.NUMBER, ApolloGraphQLElementTypes.FLOAT)
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLTokenType.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLTokenType.kt
deleted file mode 100644
index ce95407544c..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/psi/ApolloGraphQLTokenType.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.apollographql.ijplugin.psi
-
-import com.apollographql.ijplugin.lang.ApolloGraphQLLanguage
-import com.intellij.psi.tree.IElementType
-import org.jetbrains.annotations.NonNls
-
-class ApolloGraphQLTokenType(debugName: @NonNls String) :
- IElementType(debugName, ApolloGraphQLLanguage.INSTANCE)
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/GraphQLDefinitionRenameProcessor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/GraphQLDefinitionRenameProcessor.kt
deleted file mode 100644
index ea453216072..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/GraphQLDefinitionRenameProcessor.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.apollographql.ijplugin.refactoring
-
-import com.apollographql.ijplugin.navigation.findKotlinFragmentClassDefinitions
-import com.apollographql.ijplugin.navigation.findKotlinOperationDefinitions
-import com.apollographql.ijplugin.util.apolloKotlinService
-import com.apollographql.ijplugin.util.capitalizeFirstLetter
-import com.apollographql.ijplugin.util.cast
-import com.intellij.lang.jsgraphql.psi.GraphQLElement
-import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition
-import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier
-import com.intellij.lang.jsgraphql.psi.GraphQLTypedOperationDefinition
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.refactoring.rename.RenameDialog
-import com.intellij.refactoring.rename.RenamePsiElementProcessor
-
-/**
- * Allows to rename the corresponding usage in Kotlin code when renaming a GraphQL operation or fragment definition.
- * The file name is also renamed if it matches the current operation or fragment name (as is customary).
- */
-class GraphQLDefinitionRenameProcessor : RenamePsiElementProcessor() {
- private var newName: String = ""
-
- override fun canProcessElement(element: PsiElement): Boolean {
- return element is GraphQLIdentifier && (element.parent is GraphQLTypedOperationDefinition || element.parent is GraphQLFragmentDefinition)
- }
-
- override fun createRenameDialog(
- project: Project,
- element: PsiElement,
- nameSuggestionContext: PsiElement?,
- editor: Editor?,
- ): RenameDialog {
- if (element.parent !is GraphQLTypedOperationDefinition) {
- return super.createRenameDialog(project, element, nameSuggestionContext, editor)
- }
- return object : RenameDialog(project, element, nameSuggestionContext, editor) {
- override fun getFullName(): String {
- val definition = element.parent as GraphQLTypedOperationDefinition
- val type = definition.operationType.text
- return "$type '${definition.name}'"
- }
-
-
- }
- }
-
- override fun prepareRenaming(element: PsiElement, newName: String, allRenames: MutableMap) {
- prepareRenamingFile(element, newName, allRenames)
- prepareRenamingKotlinClasses(element, newName, allRenames)
- this.newName = newName
- }
-
- private fun prepareRenamingFile(
- element: PsiElement,
- newName: String,
- allRenames: MutableMap,
- ) {
- val file = element.containingFile ?: return
- val virtualFile = file.virtualFile ?: return
- val elementCurrentName = (element as GraphQLIdentifier).referenceName
- // Only rename the file if it previously had the same name as the element
- if (virtualFile.nameWithoutExtension == elementCurrentName) {
- allRenames[file] = newName + "." + virtualFile.extension
- }
- }
-
- private fun prepareRenamingKotlinClasses(
- element: PsiElement,
- newName: String,
- allRenames: MutableMap,
- ) {
- when (val parent = element.parent) {
- is GraphQLTypedOperationDefinition -> {
- val kotlinDefinitions = findKotlinOperationDefinitions(parent)
- val useSemanticNaming = element.cast()!!.apolloKotlinService()?.useSemanticNaming ?: true
- for (kotlinDefinition in kotlinDefinitions) {
- allRenames[kotlinDefinition] =
- newName.capitalizeFirstLetter() + if (useSemanticNaming) {
- val suffix = parent.operationType.text.capitalizeFirstLetter()
- if (!newName.endsWith(suffix)) {
- suffix
- } else {
- ""
- }
- } else {
- ""
- }
- }
- }
-
- is GraphQLFragmentDefinition -> {
- val kotlinDefinitions = findKotlinFragmentClassDefinitions(parent)
- for (kotlinDefinition in kotlinDefinitions) {
- allRenames[kotlinDefinition] = newName.capitalizeFirstLetter()
- }
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/Refactoring.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/Refactoring.kt
deleted file mode 100644
index 26d3e4dd3bb..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/Refactoring.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.apollographql.ijplugin.refactoring
-
-import com.apollographql.ijplugin.util.findFunctionsByName
-import com.apollographql.ijplugin.util.ktClassOrObject
-import com.apollographql.ijplugin.util.logw
-import com.intellij.openapi.application.WriteAction
-import com.intellij.openapi.project.Project
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiClassType
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMethod
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.PsiPackage
-import com.intellij.psi.PsiReference
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.search.searches.AllClassesSearch
-import com.intellij.psi.search.searches.ClassInheritorsSearch
-import com.intellij.psi.search.searches.ReferencesSearch
-import org.jetbrains.kotlin.psi.psiUtil.findPropertyByName
-
-fun findOrCreatePackage(project: Project, migration: PsiMigration, qName: String): PsiPackage {
- val aPackage = JavaPsiFacade.getInstance(project).findPackage(qName)
- return aPackage ?: WriteAction.compute {
- migration.createPackage(qName)
- }
-}
-
-fun findOrCreateClass(project: Project, migration: PsiMigration, qName: String): PsiClass {
- val classes = JavaPsiFacade.getInstance(project).findClasses(qName, GlobalSearchScope.allScope(project))
- return classes.firstOrNull() ?: WriteAction.compute {
- migration.createClass(qName)
- }
-}
-
-fun PsiElement.bindReferencesToElement(element: PsiElement): PsiElement? {
- for (reference in references) {
- try {
- return reference.bindToElement(element)
- } catch (t: Throwable) {
- logw(t, "bindToElement failed: ignoring")
- }
- }
- return null
-}
-
-fun findReferences(psiElement: PsiElement, project: Project): Collection {
- return runCatching {
- // We sometimes get KotlinExceptionWithAttachments: Unsupported reference
- ReferencesSearch.search(psiElement, GlobalSearchScope.projectScope(project), false).findAll()
- }
- .onFailure { e ->
- logw(e, "findReferences failed")
- }
- .getOrDefault(emptyList())
-}
-
-fun findMethodReferences(
- project: Project,
- className: String,
- methodName: String,
- extensionTargetClassName: String? = null,
- methodPredicate: (PsiMethod) -> Boolean = { true },
-): Collection {
- val psiLookupClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
- val methods =
- // Try Kotlin first
- psiLookupClass.ktClassOrObject?.findFunctionsByName(methodName)?.takeIf { it.isNotEmpty() }
- // Fallback to Java
- ?: psiLookupClass.findMethodsByName(methodName, false)
- .filter { method ->
- if (extensionTargetClassName == null) return@filter methodPredicate(method)
- // In Kotlin extensions, the target is passed to the first parameter
- if (method.parameterList.parametersCount < 1) return@filter false
- val firstParameter = method.parameterList.parameters.first()
- val firstParameterType = (firstParameter.type as? PsiClassType)?.rawType()?.canonicalText
- firstParameterType == extensionTargetClassName && methodPredicate(method)
- }
- return methods.flatMap { method ->
- findReferences(method, project)
- }
-}
-
-fun findFieldReferences(project: Project, className: String, fieldName: String): Collection {
- val psiLookupClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
- val field = psiLookupClass.findFieldByName(fieldName, true)
- // Fallback to Kotlin property
- ?: psiLookupClass.ktClassOrObject?.findPropertyByName(fieldName)
- ?: return emptyList()
- return findReferences(field, project)
-}
-
-fun findClassReferences(project: Project, className: String): Collection {
- val clazz = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
- return findReferences(clazz, project)
-}
-
-fun findPackageReferences(project: Project, packageName: String): Collection {
- val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName) ?: return emptyList()
- return findReferences(psiPackage, project)
-}
-
-fun findInheritorsOfClass(project: Project, className: String): Collection {
- val psiLookupClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)) ?: return emptyList()
- // Using allScope for the search so all inheritors are found even if some of them are not in the project
- return ClassInheritorsSearch.search(psiLookupClass, GlobalSearchScope.allScope(project), true).toList()
-}
-
-fun findAllClasses(project: Project): Collection {
- return AllClassesSearch.search(GlobalSearchScope.projectScope(project), project).findAll()
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/ApolloMigrationRefactoringProcessor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/ApolloMigrationRefactoringProcessor.kt
deleted file mode 100644
index 20e370bb20d..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/ApolloMigrationRefactoringProcessor.kt
+++ /dev/null
@@ -1,216 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.refactoring.migration.item.DeletesElements
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
-import com.apollographql.ijplugin.util.containingKtFile
-import com.apollographql.ijplugin.util.containingKtFileImportList
-import com.apollographql.ijplugin.util.isGenerated
-import com.apollographql.ijplugin.util.logd
-import com.apollographql.ijplugin.util.logw
-import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
-import com.intellij.history.LocalHistory
-import com.intellij.openapi.application.WriteAction
-import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
-import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.Messages
-import com.intellij.openapi.util.Ref
-import com.intellij.psi.PsiDocumentManager
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiManager
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.impl.migration.PsiMigrationManager
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.refactoring.BaseRefactoringProcessor
-import com.intellij.refactoring.ui.UsageViewDescriptorAdapter
-import com.intellij.usageView.UsageInfo
-import com.intellij.util.application
-import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
-import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.resolve.ImportPath
-import org.jetbrains.plugins.gradle.util.GradleConstants
-
-/**
- * Generic processor for migrations.
- *
- * Implementation is based on [com.intellij.refactoring.migration.MigrationProcessor] and
- * `org.jetbrains.android.refactoring.MigrateToAndroidxProcessor`.
- */
-abstract class ApolloMigrationRefactoringProcessor(project: Project) : BaseRefactoringProcessor(project) {
- abstract val refactoringName: String
- abstract val noUsageMessage: String
- abstract val migrationItems: List
-
- private val migrationManager = PsiMigrationManager.getInstance(myProject)
- private var migration: PsiMigration? = null
- private val searchScope = GlobalSearchScope.projectScope(project)
-
- override fun getCommandName() = refactoringName
-
- private val usageViewDescriptor = object : UsageViewDescriptorAdapter() {
- override fun getElements(): Array = PsiElement.EMPTY_ARRAY
-
- override fun getProcessedElementsHeader() = ApolloBundle.message("ApolloMigrationRefactoringProcessor.codeReferences")
- }
-
- override fun createUsageViewDescriptor(usages: Array) = usageViewDescriptor
-
- private fun startMigration(): PsiMigration {
- return migrationManager.startMigration()
- }
-
- private fun finishMigration() {
- migrationManager?.currentMigration?.finish()
- }
-
- override fun doRun() {
- logd()
- migration = startMigration()
- // This will create classes / packages that we're finding references to in case they don't exist.
- // It must be done in doRun() as this is called from the EDT whereas findUsages() is not.
- for (migrationItem in migrationItems) {
- migrationItem.prepare(myProject, migration!!)
- }
- super.doRun()
- }
-
- override fun findUsages(): Array {
- logd()
- try {
- val usageInfos = migrationItems
- .flatMap { migrationItem ->
- logd("Finding usages for $migrationItem")
- try {
- migrationItem.findUsages(myProject, migration!!, searchScope)
- .filter { usageInfo ->
- // Filter out all generated code usages. We don't want generated code to come up in findUsages.
- usageInfo.virtualFile?.isGenerated(myProject) != true &&
-
- // Also filter out usages outside of projects (see https://youtrack.jetbrains.com/issue/KTIJ-26411)
- usageInfo.virtualFile?.let { searchScope.contains(it) } == true
- }
- .also {
- logd("Found ${it.size} usages for $migrationItem")
- }
- } catch (t: Throwable) {
- logw(t, "Error while finding usages for $migrationItem")
- emptyList()
- }
- }
- .toMutableList()
- // If an element must be deleted, make sure we keep the UsageInfo and remove any other pointing to the same element.
- val iterator = usageInfos.listIterator()
- while (iterator.hasNext()) {
- val usageInfo = iterator.next()
- if (usageInfo.migrationItem !is DeletesElements) {
- if (usageInfos.any { it !== usageInfo && it.migrationItem is DeletesElements && it.smartPointer == usageInfo.smartPointer }) {
- iterator.remove()
- }
- }
- }
- return usageInfos.toTypedArray()
- } finally {
- application.invokeLater({ WriteAction.run(::finishMigration) }, myProject.disposed)
- }
- }
-
- override fun preprocessUsages(refUsages: Ref>): Boolean {
- logd()
- if (refUsages.get().isEmpty()) {
- Messages.showInfoMessage(
- myProject,
- noUsageMessage,
- refactoringName
- )
- return false
- }
- // Set to true to see the "preview usages" UI prior to refactoring.
- // isPreviewUsages = true
- return true
- }
-
- override fun performRefactoring(usages: Array) {
- logd()
- finishMigration()
- migration = startMigration()
- val action = LocalHistory.getInstance().startAction(commandName)
- try {
- for (usage in usages) {
- val migrationItem = (usage as MigrationItemUsageInfo).migrationItem
- try {
- if (!usage.isValid) continue
- val containingKtFile = usage.element.containingKtFile()
- maybeAddImports(usage, migrationItem)
- migrationItem.performRefactoring(myProject, migration!!, usage)
- if (containingKtFile != null) removeDuplicateImports(containingKtFile)
- } catch (t: Throwable) {
- logw(t, "Error while performing refactoring for $migrationItem")
- }
- }
- postRefactoring()
- } finally {
- action.finish()
- finishMigration()
- }
- }
-
- private fun maybeAddImports(
- usage: MigrationItemUsageInfo,
- migrationItem: MigrationItem,
- ) {
- val importsToAdd = migrationItem.importsToAdd()
- if (importsToAdd.isNotEmpty()) {
- val psiFactory = KtPsiFactory(myProject)
- usage.element.containingKtFileImportList()?.let { importList ->
- importsToAdd.forEach { importToAdd ->
- if (importList.imports.none { it.importPath?.pathStr == importToAdd }) {
- importList.add(psiFactory.createImportDirective(ImportPath.fromString(importToAdd)))
- }
- }
- }
- }
- }
-
- /**
- * Imports are automatically optimized in most cases, but some duplications are sometimes missed.
- */
- private fun removeDuplicateImports(ktFile: KtFile) {
- val importList = ktFile.importList ?: return
- val seenImports = mutableSetOf()
- for (importDirective in importList.imports) {
- val importPath = importDirective.importPath?.pathStr ?: continue
- if (seenImports.contains(importPath)) {
- importDirective.delete()
- } else {
- seenImports.add(importPath)
- }
- }
- }
-
- private fun postRefactoring() {
- logd()
- PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted {
- // Not sure if this is actually useful but IJ's editor sometimes has a hard time after the files have been touched
- PsiManager.getInstance(myProject).apply {
- dropResolveCaches()
- dropPsiCaches()
- }
- DaemonCodeAnalyzer.getInstance(myProject).restart()
-
- // Sync gradle
- if (!isUnitTestMode()) {
- ExternalSystemUtil.refreshProject(
- myProject,
- GradleConstants.SYSTEM_ID,
- myProject.basePath!!,
- false,
- ProgressExecutionMode.IN_BACKGROUND_ASYNC
- )
- }
- }
- }
-}
-
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/CompatToOperationBasedCodegenMigrationProcessor.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/CompatToOperationBasedCodegenMigrationProcessor.kt
deleted file mode 100644
index 1c6b51f9091..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/CompatToOperationBasedCodegenMigrationProcessor.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.compattooperationbased
-
-import com.apollographql.ijplugin.ApolloBundle
-import com.apollographql.ijplugin.refactoring.migration.ApolloMigrationRefactoringProcessor
-import com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item.RemoveFragmentsField
-import com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item.ReworkInlineFragmentFields
-import com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item.UpdateCodegenInBuildKts
-import com.intellij.openapi.project.Project
-
-/**
- * Migrations of using the compat codegen to using the operationBased one.
- */
-class CompatToOperationBasedCodegenMigrationProcessor(project: Project) : ApolloMigrationRefactoringProcessor(project) {
- override val refactoringName = ApolloBundle.message("CompatToOperationBasedCodegenMigrationProcessor.title")
-
- override val noUsageMessage = ApolloBundle.message("CompatToOperationBasedCodegenMigrationProcessor.noUsage")
-
- override val migrationItems = listOf(
- UpdateCodegenInBuildKts,
- ReworkInlineFragmentFields,
- RemoveFragmentsField,
- )
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/RemoveFragmentsField.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/RemoveFragmentsField.kt
deleted file mode 100644
index bcda8641691..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/RemoveFragmentsField.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item
-
-import com.apollographql.ijplugin.refactoring.findReferences
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.childrenOfType
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtQualifiedExpression
-import org.jetbrains.kotlin.psi.KtValueArgument
-import org.jetbrains.kotlin.psi.KtValueArgumentList
-import org.jetbrains.kotlin.psi.KtValueArgumentName
-import org.jetbrains.kotlin.psi.psiUtil.findPropertyByName
-
-object RemoveFragmentsField : MigrationItem() {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- val allModels: List = findAllModels(project)
- val fragmentsProperties = allModels.mapNotNull { model ->
- model.findPropertyByName("fragments")
- }
- val references = fragmentsProperties.flatMap { property ->
- findReferences(property, project).map { it.element }
- }
- return references
- .mapNotNull {
- when (val parent = it.parent) {
- is KtQualifiedExpression -> {
- when {
- // fragments.x
- parent.receiverExpression.text == "fragments" -> {
- parent.toMigrationItemUsageInfo(true)
- }
- // x.fragments
- parent.selectorExpression?.text == "fragments" -> {
- parent.toMigrationItemUsageInfo(false)
- }
-
- else -> null
- }
- }
-
- is KtValueArgumentName -> {
- // fragments = ...
- (parent.parent as? KtValueArgument)?.toMigrationItemUsageInfo()
- }
-
- else -> null
- }
- }
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- when (val element = usage.element) {
- is KtQualifiedExpression -> {
- if (usage.attachedData()) {
- // fragments.x -> x
- element.replace(element.selectorExpression!!)
- } else {
- // x.fragments -> x
- element.replace(element.receiverExpression)
- }
- }
-
- // fragments = Xxx.Fragments(yyy = ..., xxx = ...) -> yyy = ..., xxx = ...
- is KtValueArgument -> {
- // Xxx.Fragments(yyy = ..., xxx = ...)
- val callExpression = element.getArgumentExpression()?.childrenOfType()?.firstOrNull()
- // yyy = ..., xxx = ...
- val enclosedArguments = callExpression?.valueArgumentList ?: return
- val parentArgumentList = element.parent as KtValueArgumentList
- for (enclosedArgument in enclosedArguments.arguments) {
- parentArgumentList.addArgument(enclosedArgument)
- }
- parentArgumentList.removeArgument(element)
- }
-
- else -> {}
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/ReworkInlineFragmentFields.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/ReworkInlineFragmentFields.kt
deleted file mode 100644
index cf4b169fa1f..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/ReworkInlineFragmentFields.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item
-
-import com.apollographql.ijplugin.refactoring.findClassReferences
-import com.apollographql.ijplugin.refactoring.findReferences
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
-import com.apollographql.ijplugin.util.className
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.PsiReference
-import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.psi.KtClass
-import org.jetbrains.kotlin.psi.KtClassOrObject
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtPsiFactory
-
-object ReworkInlineFragmentFields : MigrationItem() {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- val usageInfo = mutableListOf()
- val allModels: List = findAllModels(project)
- val inlineFragmentProperties = allModels.flatMap { model ->
- model.inlineFragmentProperties()
- }
- val propertyReferences = inlineFragmentProperties.flatMap { property ->
- findReferences(property, project)
- }
- usageInfo.addAll(propertyReferences.map { PropertyUsageInfo(this, it) })
-
- val inlineFragmentTypes = inlineFragmentProperties.mapNotNull {
- it.className()
- }
- val typeReferences = inlineFragmentTypes.flatMap { type ->
- findClassReferences(project, type)
- }
- typeReferences.toMigrationItemUsageInfo()
- usageInfo.addAll(typeReferences.map { TypeUsageInfo(this, it) })
-
- return usageInfo
- }
-
- private class PropertyUsageInfo(migrationItem: MigrationItem, reference: PsiReference) :
- MigrationItemUsageInfo(migrationItem, reference)
-
- private class TypeUsageInfo(migrationItem: MigrationItem, reference: PsiReference) :
- MigrationItemUsageInfo(migrationItem, reference)
-
-
- private fun KtClassOrObject.inlineFragmentProperties(): List {
- return primaryConstructorParameters.filter {
- it.hasValOrVar() &&
- it.name?.isInlineFragmentPropertyName() == true &&
- it.docComment?.text?.contains("Synthetic field for inline fragment") == true
- }
- }
-
- private fun String.isInlineFragmentPropertyName(): Boolean {
- return startsWith("as") && this.getOrNull(2)?.isUpperCase() == true
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- val psiFactory = KtPsiFactory(project)
- when (usage) {
- is PropertyUsageInfo -> {
- usage.element.replace(psiFactory.createExpression(usage.element.text.replaceFirst("as", "on")))
- }
-
- is TypeUsageInfo -> {
- usage.element.replace(psiFactory.createExpression(usage.element.text.replaceFirst("As", "On")))
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/UpdateCodegenInBuildKts.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/UpdateCodegenInBuildKts.kt
deleted file mode 100644
index 9d32e465753..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/UpdateCodegenInBuildKts.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item
-
-import com.apollographql.ijplugin.refactoring.migration.item.DeletesElements
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItem
-import com.apollographql.ijplugin.refactoring.migration.item.MigrationItemUsageInfo
-import com.apollographql.ijplugin.util.cast
-import com.apollographql.ijplugin.util.findPsiFilesByName
-import com.apollographql.ijplugin.util.getMethodName
-import com.apollographql.ijplugin.util.unquoted
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.psi.KtNameReferenceExpression
-import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
-
-object UpdateCodegenInBuildKts : MigrationItem(), DeletesElements {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- val usages = mutableListOf()
- val buildGradleKtsFiles: List = project.findPsiFilesByName("build.gradle.kts", searchScope).filterIsInstance()
- for (file in buildGradleKtsFiles) {
- file.accept(object : KtTreeVisitorVoid() {
- override fun visitCallExpression(expression: KtCallExpression) {
- super.visitCallExpression(expression)
- if (expression.getMethodName() == "apollo") {
- expression.accept(object : KtTreeVisitorVoid() {
- override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
- super.visitDotQualifiedExpression(expression)
- if (expression.receiverExpression.cast()?.getReferencedName() == "codegenModels") {
- val argumentText = expression.selectorExpression.cast()?.valueArguments?.firstOrNull()?.text ?: return
- if (argumentText.unquoted() == "compat" || argumentText.contains("MODELS_COMPAT")) {
- usages.add(expression.toMigrationItemUsageInfo())
- }
- }
- }
- })
- }
- }
- })
- }
- return usages
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- usage.element.delete()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/findAllModels.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/findAllModels.kt
deleted file mode 100644
index c70064c04ca..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/compattooperationbased/item/findAllModels.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.compattooperationbased.item
-
-import com.apollographql.ijplugin.refactoring.findInheritorsOfClass
-import com.apollographql.ijplugin.util.apollo3
-import com.apollographql.ijplugin.util.ktClass
-import com.apollographql.ijplugin.util.logd
-import com.intellij.openapi.project.Project
-import org.jetbrains.kotlin.psi.KtClass
-
-fun findAllModels(project: Project): List {
- logd()
- val operationInheritors = findInheritorsOfClass(project, "$apollo3.api.Operation")
- val fragmentDataInheritors = findInheritorsOfClass(project, "$apollo3.api.Fragment.Data")
- val allModels: List = (operationInheritors + fragmentDataInheritors).flatMap {
- it.ktClass?.body?.declarations.orEmpty().filterIsInstance()
- } + fragmentDataInheritors.map { it.ktClass }.filterNotNull()
- logd("size=${allModels.size}")
- return allModels
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/CommentDependenciesInToml.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/CommentDependenciesInToml.kt
deleted file mode 100644
index 6a9b29562f3..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/CommentDependenciesInToml.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.util.findPsiFilesByExtension
-import com.apollographql.ijplugin.util.unquoted
-import com.intellij.codeInspection.SuppressionUtil.createComment
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import org.toml.lang.psi.TomlFile
-import org.toml.lang.psi.TomlLiteral
-import org.toml.lang.psi.TomlPsiFactory
-import org.toml.lang.psi.TomlRecursiveVisitor
-import org.toml.lang.psi.TomlTable
-import org.toml.lang.psi.ext.TomlLiteralKind
-import org.toml.lang.psi.ext.kind
-
-class CommentDependenciesInToml(
- private vararg val artifactId: String,
-) : MigrationItem() {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- val libsVersionTomlFiles: List = project.findPsiFilesByExtension("versions.toml", searchScope)
- val usages = mutableListOf()
- for (file in libsVersionTomlFiles) {
- if (file !is TomlFile) continue
- file.accept(object : TomlRecursiveVisitor() {
- override fun visitLiteral(element: TomlLiteral) {
- super.visitLiteral(element)
- if (element.kind is TomlLiteralKind.String) {
- val dependencyText = element.text.unquoted()
- if (artifactId.any { dependencyText.contains(it) }) {
- var elementToReplace: PsiElement = element
- while (elementToReplace.parent != null && elementToReplace.parent !is TomlTable) {
- elementToReplace = elementToReplace.parent
- }
- usages.add(elementToReplace.toMigrationItemUsageInfo())
- }
- }
- }
- })
- }
- return usages
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- val element = usage.element
- element.parent.addBefore(
- createComment(project, " TODO: remove this declaration and its uses in your gradle files", element.language),
- element
- )
- element.parent.addBefore(TomlPsiFactory(project).createWhitespace("\n"), element)
- element.replace(createComment(project, " " + element.text, element.language))
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/ConstructorInsteadOfBuilder.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/ConstructorInsteadOfBuilder.kt
deleted file mode 100644
index 57d7a6981af..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/ConstructorInsteadOfBuilder.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.refactoring.findMethodReferences
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-
-class ConstructorInsteadOfBuilder(
- private val containingDeclarationName: String,
- private val methodName: String,
-) : MigrationItem() {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- return findMethodReferences(
- project = project,
- className = containingDeclarationName,
- methodName = methodName,
- ).toMigrationItemUsageInfo()
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- val element = usage.element
- val dotQualifiedExpression = element.parentOfType()?: return
- // myObj.method(x, y) -> myObj.myObj(x, y)
- (dotQualifiedExpression.selectorExpression as? KtCallExpression)?.calleeExpression?.replace(dotQualifiedExpression.receiverExpression)
- // myObj.myObj(x, y) -> myObj(x, y)
- dotQualifiedExpression.selectorExpression?.let { dotQualifiedExpression.replace(it) }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/DeletesElements.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/DeletesElements.kt
deleted file mode 100644
index 35f4ee3f725..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/DeletesElements.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-/**
- * Marker interface for [MigrationItem]s that delete elements. Useful to sort them so they are executed at the end.
- */
-interface DeletesElements
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItem.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItem.kt
deleted file mode 100644
index 510774f7518..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItem.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.PsiReference
-import com.intellij.psi.search.GlobalSearchScope
-
-abstract class MigrationItem {
- open fun prepare(project: Project, migration: PsiMigration) {}
- abstract fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List
- abstract fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo)
- open fun importsToAdd(): Set = emptySet()
-
- fun PsiElement.toMigrationItemUsageInfo(attachedData: Any? = null) =
- MigrationItemUsageInfo(migrationItem = this@MigrationItem, element = this, attachedData = attachedData)
-
- fun Collection.toMigrationItemUsageInfo(): List {
- return map { it.toMigrationItemUsageInfo() }
- }
-
- fun PsiReference.toMigrationItemUsageInfo(attachedData: Any? = null) =
- MigrationItemUsageInfo(migrationItem = this@MigrationItem, reference = this, attachedData = attachedData)
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItemUsageInfo.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItemUsageInfo.kt
deleted file mode 100644
index a0589762f5d..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/MigrationItemUsageInfo.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiReference
-import com.intellij.usageView.UsageInfo
-
-open class MigrationItemUsageInfo : UsageInfo {
- val migrationItem: MigrationItem
- private val attachedData: Any?
-
- constructor(migrationItem: MigrationItem, reference: PsiReference, attachedData: Any? = null) : super(reference) {
- this.migrationItem = migrationItem
- this.attachedData = attachedData
- }
-
- constructor(migrationItem: MigrationItem, element: PsiElement, attachedData: Any? = null) : super(element) {
- this.migrationItem = migrationItem
- this.attachedData = attachedData
- }
-
- constructor(migrationItem: MigrationItem, source: UsageInfo, attachedData: Any? = null) : super(
- source.element!!,
- source.rangeInElement!!.startOffset,
- source.rangeInElement!!.endOffset
- ) {
- this.migrationItem = migrationItem
- this.attachedData = attachedData
- }
-
- fun attachedData(): T {
- @Suppress("UNCHECKED_CAST")
- return attachedData as T
- }
-
- override fun getElement(): PsiElement {
- return super.getElement()!!
- }
-
- override fun isValid(): Boolean {
- return super.getElement() != null && super.isValid()
- }
-
- /**
- * Taken from https://github.com/JetBrains/android/blob/b9cc41149734794ca6746711b1fb5a2fb6d06ec4/project-system-gradle/src/org/jetbrains/android/refactoring/MigrateToAndroidxProcessor.kt
- *
- * Verifies if one of the calls on the stack comes from the Optimize Imports Refactoring Helper.
- * We check the last 5 elements to allow for some future flow changes.
- *
- * This avoids the helper kicking as it can remove imports we're trying to add.
- */
- private fun isKotlinOptimizerCall(): Boolean = Thread.currentThread().stackTrace
- .take(5)
- .map { it.className }
- .any { it.contains("OptimizeImports", ignoreCase = true) }
-
- override fun getFile(): PsiFile? = if (isKotlinOptimizerCall()) {
- null
- } else {
- super.getFile()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveImport.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveImport.kt
deleted file mode 100644
index 667817197c8..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveImport.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.refactoring.findClassReferences
-import com.apollographql.ijplugin.refactoring.findOrCreateClass
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.psi.KtImportDirective
-
-class RemoveImport(
- private val import: String,
-) : MigrationItem(), DeletesElements {
-
- override fun prepare(project: Project, migration: PsiMigration) {
- findOrCreateClass(project, migration, import)
- }
-
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- return findClassReferences(project, import)
- .mapNotNull {
- it.element.parentOfType()?.toMigrationItemUsageInfo()
- }
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- usage.element.delete()
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodCall.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodCall.kt
deleted file mode 100644
index 866a1e122ae..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodCall.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.refactoring.findMethodReferences
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtImportDirective
-
-open class RemoveMethodCall(
- private val containingDeclarationName: String,
- private val methodName: String,
- private val extensionTargetClassName: String? = null,
- private val removeImportsOnly: Boolean = false,
-) : MigrationItem(), DeletesElements {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- return findMethodReferences(
- project = project,
- className = containingDeclarationName,
- methodName = methodName,
- extensionTargetClassName = extensionTargetClassName,
- )
- .filter {
- if (removeImportsOnly) {
- it.element.parentOfType() != null
- } else {
- true
- }
- }
- .toMigrationItemUsageInfo()
- }
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- val element = usage.element
- val importDirective = element.parentOfType()
- if (importDirective != null) {
- // Reference is an import
- importDirective.delete()
- } else {
- if (removeImportsOnly) return
- val dotQualifiedExpression = element.parentOfType()
- if (dotQualifiedExpression != null) {
- // Reference is a method call
- // . ->
- dotQualifiedExpression.replace(dotQualifiedExpression.receiverExpression)
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodImport.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodImport.kt
deleted file mode 100644
index 5ca04010efc..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/RemoveMethodImport.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-class RemoveMethodImport(
- containingDeclarationName: String,
- methodName: String,
-) : RemoveMethodCall(
- containingDeclarationName,
- methodName,
- removeImportsOnly = true,
-)
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateClassName.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateClassName.kt
deleted file mode 100644
index 1027e79ce96..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateClassName.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.refactoring.findClassReferences
-import com.apollographql.ijplugin.refactoring.findOrCreateClass
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.psi.util.parentOfType
-import org.jetbrains.kotlin.psi.KtImportDirective
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.resolve.ImportPath
-
-class UpdateClassName(
- private val oldName: String,
- private val newName: String,
-) : MigrationItem() {
- override fun prepare(project: Project, migration: PsiMigration) {
- findOrCreateClass(project, migration, newName)
- }
-
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- return findClassReferences(project, oldName)
- .toMigrationItemUsageInfo()
- .map {
- val element = it.element
- val importDirective = element.parentOfType()
- if (importDirective != null) {
- // Reference is an import
- ReplaceImportUsageInfo(this@UpdateClassName, importDirective)
- } else {
- it
- }
- }
- }
-
- private class ReplaceImportUsageInfo(migrationItem: MigrationItem, element: KtImportDirective) :
- MigrationItemUsageInfo(migrationItem, element)
-
-
- override fun performRefactoring(project: Project, migration: PsiMigration, usage: MigrationItemUsageInfo) {
- val element = usage.element
- val psiFactory = KtPsiFactory(project)
- when (usage) {
- is ReplaceImportUsageInfo -> {
- element.replace(psiFactory.createImportDirective(ImportPath.fromString(newName)))
- }
-
- else -> {
- element.replace(psiFactory.createExpression(newName.split('.').last()))
- }
- }
- }
-}
diff --git a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateCustomTypeMappingInBuildKts.kt b/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateCustomTypeMappingInBuildKts.kt
deleted file mode 100644
index 73b87df57ab..00000000000
--- a/intellij-plugin/src/main/kotlin/com/apollographql/ijplugin/refactoring/migration/item/UpdateCustomTypeMappingInBuildKts.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.apollographql.ijplugin.refactoring.migration.item
-
-import com.apollographql.ijplugin.util.addSiblingAfter
-import com.apollographql.ijplugin.util.findPsiFilesByName
-import com.apollographql.ijplugin.util.unquoted
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiMigration
-import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.psi.KtBinaryExpression
-import org.jetbrains.kotlin.psi.KtCallExpression
-import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.psi.KtQualifiedExpression
-import org.jetbrains.kotlin.psi.KtReferenceExpression
-import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
-import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
-
-object UpdateCustomTypeMappingInBuildKts : MigrationItem() {
- override fun findUsages(project: Project, migration: PsiMigration, searchScope: GlobalSearchScope): List {
- val buildGradleKtsFiles: List = project.findPsiFilesByName("build.gradle.kts", searchScope)
- val usages = mutableListOf()
- for (file in buildGradleKtsFiles) {
- if (file !is KtFile) continue
- file.accept(object : KtTreeVisitorVoid() {
- override fun visitReferenceExpression(expression: KtReferenceExpression) {
- super.visitReferenceExpression(expression)
- if (expression.text == "customTypeMapping" || expression.text == "customScalarsMapping") {
- // `customTypeMapping.set(mapOf(...))`
- val qualifiedExpression = expression.parent as? KtQualifiedExpression ?: return
- // `set(mapOf(...))`
- val setCallExpression = qualifiedExpression.selectorExpression
- ?.findDescendantOfType