Skip to content

Commit 40a30a0

Browse files
committed
Simplified schema discovery to only support graphql-config and introduced new schema discovery UI (#164)
1 parent a0f4305 commit 40a30a0

32 files changed

+1335
-849
lines changed

resources/META-INF/.graphqlconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2+
"name": "Untitled GraphQL Schema",
3+
"schemaPath": "schema.graphql",
24
"extensions": {
35
"endpoints": {
46
"Default GraphQL Endpoint": {

resources/META-INF/plugin.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
<projectService serviceInterface="com.intellij.lang.jsgraphql.GraphQLSettings" serviceImplementation="com.intellij.lang.jsgraphql.GraphQLSettings" />
6363
<projectService serviceInterface="com.intellij.lang.jsgraphql.ide.project.graphqlconfig.GraphQLConfigManager" serviceImplementation="com.intellij.lang.jsgraphql.ide.project.graphqlconfig.GraphQLConfigManager" />
6464
<projectService serviceInterface="com.intellij.lang.jsgraphql.ide.project.graphqlconfig.GraphQLConfigGlobMatcher" serviceImplementation="com.intellij.lang.jsgraphql.ide.project.graphqlconfig.GraphQLConfigGlobMatcherImpl" />
65-
<projectService serviceInterface="com.intellij.lang.jsgraphql.ide.project.scopes.GraphQLProjectScopesManager" serviceImplementation="com.intellij.lang.jsgraphql.ide.project.scopes.GraphQLProjectScopesManager" />
6665
<projectService serviceInterface="com.intellij.lang.jsgraphql.ide.GraphQLRelayModernAnnotationFilter" serviceImplementation="com.intellij.lang.jsgraphql.ide.GraphQLRelayModernAnnotationFilter" />
6766

6867
<!-- Startup -->

src/main/com/intellij/lang/jsgraphql/GraphQLSettings.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ public void loadState(@NotNull GraphQLSettings.GraphQLSettingsState state) {
3838
this.myState = state;
3939
}
4040

41-
public GraphQLScopeResolution getScopeResolution() {
42-
return myState.scopeResolution;
43-
}
44-
45-
public void setScopeResolution(GraphQLScopeResolution scopeResolution) {
46-
myState.scopeResolution = scopeResolution;
47-
}
48-
4941
public String getIntrospectionQuery() {
5042
return myState.introspectionQuery;
5143
}
@@ -68,7 +60,6 @@ public void setEnableRelayModernFrameworkSupport(boolean enableRelayModernFramew
6860
* NOTE!!!: 1. Class must be static, and 2. Fields must be public for settings serialization to work
6961
*/
7062
static class GraphQLSettingsState {
71-
public GraphQLScopeResolution scopeResolution = GraphQLScopeResolution.ENTIRE_PROJECT;
7263
public String introspectionQuery = "";
7364
public boolean enableRelayModernFrameworkSupport;
7465
}

src/main/com/intellij/lang/jsgraphql/ide/GraphQLValidationAnnotator.java

Lines changed: 14 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import com.intellij.codeInsight.daemon.impl.quickfix.RenameElementFix;
1212
import com.intellij.codeInspection.InspectionManager;
1313
import com.intellij.codeInspection.LocalQuickFix;
14-
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
1514
import com.intellij.codeInspection.ProblemDescriptor;
1615
import com.intellij.codeInspection.ProblemHighlightType;
1716
import com.intellij.lang.annotation.Annotation;
@@ -20,26 +19,9 @@
2019
import com.intellij.lang.annotation.Annotator;
2120
import com.intellij.lang.jsgraphql.ide.project.GraphQLPsiSearchHelper;
2221
import com.intellij.lang.jsgraphql.psi.GraphQLArgument;
23-
import com.intellij.lang.jsgraphql.psi.GraphQLArgumentsDefinition;
24-
import com.intellij.lang.jsgraphql.psi.GraphQLDefinition;
2522
import com.intellij.lang.jsgraphql.psi.GraphQLDirective;
26-
import com.intellij.lang.jsgraphql.psi.GraphQLDirectiveLocation;
27-
import com.intellij.lang.jsgraphql.psi.GraphQLElementTypes;
28-
import com.intellij.lang.jsgraphql.psi.GraphQLField;
2923
import com.intellij.lang.jsgraphql.psi.GraphQLFieldDefinition;
30-
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentDefinition;
31-
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSelection;
32-
import com.intellij.lang.jsgraphql.psi.GraphQLFragmentSpread;
33-
import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier;
34-
import com.intellij.lang.jsgraphql.psi.GraphQLObjectField;
35-
import com.intellij.lang.jsgraphql.psi.GraphQLOperationDefinition;
36-
import com.intellij.lang.jsgraphql.psi.GraphQLTemplateDefinition;
37-
import com.intellij.lang.jsgraphql.psi.GraphQLTemplateSelection;
38-
import com.intellij.lang.jsgraphql.psi.GraphQLTemplateVariable;
39-
import com.intellij.lang.jsgraphql.psi.GraphQLTypeCondition;
40-
import com.intellij.lang.jsgraphql.psi.GraphQLTypeName;
41-
import com.intellij.lang.jsgraphql.psi.GraphQLTypeSystemDefinition;
42-
import com.intellij.lang.jsgraphql.psi.GraphQLVisitor;
24+
import com.intellij.lang.jsgraphql.psi.*;
4325
import com.intellij.lang.jsgraphql.schema.GraphQLSchemaWithErrors;
4426
import com.intellij.lang.jsgraphql.schema.GraphQLTypeDefinitionRegistryServiceImpl;
4527
import com.intellij.lang.jsgraphql.schema.GraphQLTypeScopeProvider;
@@ -55,38 +37,22 @@
5537
import com.intellij.openapi.util.Pair;
5638
import com.intellij.openapi.util.Ref;
5739
import com.intellij.openapi.util.TextRange;
58-
import com.intellij.openapi.vfs.LocalFileSystem;
59-
import com.intellij.openapi.vfs.VirtualFile;
60-
import com.intellij.psi.NavigatablePsiElement;
61-
import com.intellij.psi.PsiElement;
62-
import com.intellij.psi.PsiFile;
63-
import com.intellij.psi.PsiManager;
64-
import com.intellij.psi.PsiNamedElement;
65-
import com.intellij.psi.PsiRecursiveElementVisitor;
66-
import com.intellij.psi.PsiReference;
67-
import com.intellij.psi.PsiWhiteSpace;
40+
import com.intellij.psi.*;
6841
import com.intellij.psi.tree.IElementType;
69-
import com.intellij.psi.util.PsiEditorUtil;
7042
import com.intellij.psi.util.PsiTreeUtil;
7143
import com.intellij.util.text.EditDistance;
7244
import graphql.AssertException;
7345
import graphql.GraphQLError;
7446
import graphql.language.Document;
7547
import graphql.language.SourceLocation;
7648
import graphql.parser.Parser;
77-
import graphql.schema.GraphQLFieldsContainer;
78-
import graphql.schema.GraphQLInputFieldsContainer;
79-
import graphql.schema.GraphQLInputObjectField;
80-
import graphql.schema.GraphQLInterfaceType;
81-
import graphql.schema.GraphQLObjectType;
82-
import graphql.schema.SchemaUtil;
49+
import graphql.schema.*;
8350
import graphql.schema.idl.errors.SchemaProblem;
8451
import graphql.schema.validation.InvalidSchemaException;
8552
import graphql.validation.ValidationError;
8653
import graphql.validation.ValidationErrorType;
8754
import graphql.validation.Validator;
8855
import org.apache.commons.lang.StringUtils;
89-
import org.jetbrains.annotations.Nls;
9056
import org.jetbrains.annotations.NotNull;
9157

9258
import java.util.Collections;
@@ -179,7 +145,7 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
179145
}
180146
if (message != null) {
181147
final Optional<Annotation> annotation = createErrorAnnotation(annotationHolder, psiElement, message);
182-
if(annotation.isPresent()) {
148+
if (annotation.isPresent()) {
183149
annotation.get().setTextAttributes(CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES);
184150
if (!fixes.isEmpty()) {
185151
final InspectionManager inspectionManager = InspectionManager.getInstance(psiElement.getProject());
@@ -223,7 +189,7 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
223189
editor = ((TextEditor) fileEditor).getEditor();
224190
session.putUserData(EDITOR, editor);
225191
}
226-
if(editor == null) {
192+
if (editor == null) {
227193
// no compatible editor found to annotate
228194
return;
229195
}
@@ -236,9 +202,9 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
236202
final Document document = parser.parseDocument(replacePlaceholdersWithValidGraphQL(containingFile));
237203

238204
// adjust source locations for injected GraphQL since the annotator works on the entire editor buffer (e.g. tsx with graphql tagged templates)
239-
if(containingFile.getContext() != null) {
205+
if (containingFile.getContext() != null) {
240206
final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(containingFile.getContext().getTextOffset());
241-
if(logicalPosition.line > 0 || logicalPosition.column > 0) {
207+
if (logicalPosition.line > 0 || logicalPosition.column > 0) {
242208
// logical positions can be used as deltas between graphql-java and intellij since graphql-java is 1-based and intellij is 0-based
243209
GraphQLUtil.adjustSourceLocations(document, logicalPosition.line, logicalPosition.column);
244210
}
@@ -253,15 +219,15 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
253219
for (GraphQLError error : schema.getErrors()) {
254220
errorMessages.add(error.getMessage() + formatLocation(error.getLocations()));
255221
SourceLocation firstSourceLocation = error.getLocations().stream().findFirst().orElse(null);
256-
if(firstSourceLocation != null && firstSchemaError.isNull()) {
222+
if (firstSourceLocation != null && firstSchemaError.isNull()) {
257223
firstSchemaError.set(firstSourceLocation);
258224
}
259225
if (firstSourceLocation != null && currentFileName.equals(firstSourceLocation.getSourceName())) {
260226
final int positionToOffset = getOffsetFromSourceLocation(editor, firstSourceLocation);
261227
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset);
262228
if (errorPsiElement != null) {
263229
PsiElement nextLeaf = PsiTreeUtil.nextVisibleLeaf(errorPsiElement);
264-
if(nextLeaf != null && nextLeaf.getParent() instanceof GraphQLIdentifier) {
230+
if (nextLeaf != null && nextLeaf.getParent() instanceof GraphQLIdentifier) {
265231
// graphql-errors typically point to the keywords of definitions, so
266232
// use the definition identifier in that case
267233
errorPsiElement = nextLeaf.getParent();
@@ -271,70 +237,6 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
271237
}
272238
}
273239

274-
// schema errors are present, so mark operations and fragments with a message that type information is incomplete
275-
final List<? extends GraphQLDefinition> operations = PsiTreeUtil.getChildrenOfAnyType(psiElement.getContainingFile(), GraphQLOperationDefinition.class, GraphQLFragmentDefinition.class);
276-
final String fullErrorMessage = StringUtils.join(errorMessages, "\n");
277-
for (GraphQLDefinition definition : operations) {
278-
Optional<Annotation> errorAnnotation = createErrorAnnotation(annotationHolder, definition, "No type information available due to schema errors: \n" + fullErrorMessage);
279-
if(!errorAnnotation.isPresent()) {
280-
continue;
281-
}
282-
errorAnnotation.get().setTextAttributes(CodeInsightColors.WEAK_WARNING_ATTRIBUTES);
283-
284-
if(!firstSchemaError.isNull()) {
285-
final InspectionManager inspectionManager = InspectionManager.getInstance(psiElement.getProject());
286-
final ProblemDescriptor problemDescriptor = inspectionManager.createProblemDescriptor(
287-
definition,
288-
definition,
289-
"Navigate to GraphQL schema error",
290-
ProblemHighlightType.ERROR,
291-
true,
292-
LocalQuickFix.EMPTY_ARRAY
293-
);
294-
295-
// help the user navigate to the schema error
296-
errorAnnotation.get().registerFix(new LocalQuickFixOnPsiElement(definition) {
297-
298-
@NotNull
299-
@Override
300-
public String getText() {
301-
return "Navigate to GraphQL schema error";
302-
}
303-
304-
@Nls
305-
@NotNull
306-
@Override
307-
public String getFamilyName() {
308-
return "GraphQL schema errors";
309-
}
310-
311-
@Override
312-
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
313-
final SourceLocation sourceLocation = firstSchemaError.get();
314-
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(sourceLocation.getSourceName());
315-
if(virtualFile != null) {
316-
final PsiFile schemaPsiFile = PsiManager.getInstance(project).findFile(virtualFile);
317-
if(schemaPsiFile != null) {
318-
schemaPsiFile.navigate(true);
319-
final Editor schemaEditor = PsiEditorUtil.Service.getInstance().findEditorByPsiElement(schemaPsiFile);
320-
if(schemaEditor != null) {
321-
final int positionToOffset = getOffsetFromSourceLocation(schemaEditor, sourceLocation);
322-
final NavigatablePsiElement navigatablePsiElement = PsiTreeUtil.getNonStrictParentOfType(
323-
schemaPsiFile.findElementAt(positionToOffset),
324-
NavigatablePsiElement.class
325-
);
326-
if(navigatablePsiElement != null) {
327-
navigatablePsiElement.navigate(true);
328-
}
329-
}
330-
}
331-
}
332-
}
333-
}, null, null, problemDescriptor);
334-
}
335-
336-
}
337-
338240
userData = Collections.emptyList();
339241
}
340242
session.putUserData(ERRORS, userData);
@@ -372,7 +274,7 @@ public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull Psi
372274
for (SourceLocation location : validationError.getLocations()) {
373275
final int positionToOffset = getOffsetFromSourceLocation(editor, location);
374276
int injectionOffset = 0;
375-
if(containingFile.getContext() != null) {
277+
if (containingFile.getContext() != null) {
376278
injectionOffset = containingFile.getContext().getTextOffset();
377279
}
378280
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset - injectionOffset);
@@ -393,10 +295,10 @@ public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull Psi
393295
}
394296
} else if (elementType == GraphQLElementTypes.AT) {
395297
// mark the directive and not only the '@'
396-
if(validationErrorType == ValidationErrorType.MisplacedDirective) {
298+
if (validationErrorType == ValidationErrorType.MisplacedDirective) {
397299
// graphql-java KnownDirectives rule only recognizes executable directive locations, so ignore
398300
// the error if we're inside a type definition
399-
if(PsiTreeUtil.getTopmostParentOfType(errorPsiElement, GraphQLTypeSystemDefinition.class) != null) {
301+
if (PsiTreeUtil.getTopmostParentOfType(errorPsiElement, GraphQLTypeSystemDefinition.class) != null) {
400302
continue;
401303
}
402304
}
@@ -439,15 +341,14 @@ boolean isInsideTemplateElement(PsiElement psiElement) {
439341

440342
/**
441343
* Replaces template placeholders in a GraphQL operation to produce valid GraphQL.
442-
*
344+
* <p>
443345
* Positions of tokens are preserved by using replacements that fit within the ${} placeholder token.
444-
*
346+
* <p>
445347
* Note that the replacement needs to be filtered for variables and selections, specifically:
446348
* - Variables: '$__'
447349
* - Selection '___'
448350
*
449351
* @param graphqlPsiFile the file to transform to valid GraphQL by replacing placeholders
450-
*
451352
* @return the transformed valid GraphQL as a string
452353
*/
453354
private String replacePlaceholdersWithValidGraphQL(PsiFile graphqlPsiFile) {

0 commit comments

Comments
 (0)