Skip to content

Commit a0f4305

Browse files
committed
Adjust source locations in graphql-java document based on injection text offset in the editor (e.g. TSX file with graphql tagged template) (#164)
1 parent 2e3cb6f commit a0f4305

File tree

3 files changed

+83
-36
lines changed

3 files changed

+83
-36
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.intellij.lang.jsgraphql.schema.GraphQLSchemaWithErrors;
4444
import com.intellij.lang.jsgraphql.schema.GraphQLTypeDefinitionRegistryServiceImpl;
4545
import com.intellij.lang.jsgraphql.schema.GraphQLTypeScopeProvider;
46+
import com.intellij.lang.jsgraphql.utils.GraphQLUtil;
4647
import com.intellij.openapi.editor.Editor;
4748
import com.intellij.openapi.editor.LogicalPosition;
4849
import com.intellij.openapi.editor.colors.CodeInsightColors;
@@ -233,6 +234,16 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
233234
final GraphQLSchemaWithErrors schema = GraphQLTypeDefinitionRegistryServiceImpl.getService(project).getSchemaWithErrors(psiElement);
234235
if (!schema.isErrorsPresent()) {
235236
final Document document = parser.parseDocument(replacePlaceholdersWithValidGraphQL(containingFile));
237+
238+
// 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) {
240+
final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(containingFile.getContext().getTextOffset());
241+
if(logicalPosition.line > 0 || logicalPosition.column > 0) {
242+
// logical positions can be used as deltas between graphql-java and intellij since graphql-java is 1-based and intellij is 0-based
243+
GraphQLUtil.adjustSourceLocations(document, logicalPosition.line, logicalPosition.column);
244+
}
245+
}
246+
236247
userData = new Validator().validateDocument(schema.getSchema(), document);
237248
} else {
238249

@@ -360,7 +371,11 @@ public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull Psi
360371
case LoneAnonymousOperationViolation:
361372
for (SourceLocation location : validationError.getLocations()) {
362373
final int positionToOffset = getOffsetFromSourceLocation(editor, location);
363-
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset);
374+
int injectionOffset = 0;
375+
if(containingFile.getContext() != null) {
376+
injectionOffset = containingFile.getContext().getTextOffset();
377+
}
378+
PsiElement errorPsiElement = containingFile.findElementAt(positionToOffset - injectionOffset);
364379
if (errorPsiElement != null) {
365380
final IElementType elementType = errorPsiElement.getNode().getElementType();
366381
if (elementType == GraphQLElementTypes.SPREAD) {

src/main/com/intellij/lang/jsgraphql/schema/SchemaIDLTypeDefinitionRegistry.java

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
import com.google.common.collect.Lists;
1111
import com.google.common.collect.Maps;
12-
import com.google.common.collect.Sets;
1312
import com.intellij.lang.jsgraphql.GraphQLFileType;
1413
import com.intellij.lang.jsgraphql.endpoint.ide.project.JSGraphQLEndpointNamedTypeRegistry;
1514
import com.intellij.lang.jsgraphql.ide.project.GraphQLPsiSearchHelper;
1615
import com.intellij.lang.jsgraphql.psi.GraphQLDirective;
1716
import com.intellij.lang.jsgraphql.psi.GraphQLTypeSystemDefinition;
17+
import com.intellij.lang.jsgraphql.utils.GraphQLUtil;
1818
import com.intellij.openapi.components.ServiceManager;
1919
import com.intellij.openapi.project.Project;
2020
import com.intellij.openapi.util.Ref;
@@ -30,18 +30,14 @@
3030
import com.intellij.psi.search.GlobalSearchScope;
3131
import com.intellij.psi.util.PsiTreeUtil;
3232
import graphql.GraphQLException;
33-
import graphql.language.AbstractNode;
3433
import graphql.language.Document;
35-
import graphql.language.Node;
36-
import graphql.language.SourceLocation;
3734
import graphql.parser.Parser;
3835
import graphql.schema.idl.SchemaParser;
3936
import graphql.schema.idl.TypeDefinitionRegistry;
4037
import org.jetbrains.annotations.NotNull;
4138

4239
import java.util.List;
4340
import java.util.Map;
44-
import java.util.Set;
4541
import java.util.concurrent.CancellationException;
4642
import java.util.function.Consumer;
4743

@@ -162,36 +158,8 @@ public TypeDefinitionRegistryWithErrors getRegistryWithErrors(PsiElement scopedE
162158

163159
// adjust line numbers in source locations if there's a line delta compared to the original file buffer
164160
if (lineDelta.get() > 0) {
165-
final Ref<Consumer<Node>> adjustSourceLines = new Ref<>();
166-
final Set<Node> visitedNodes = Sets.newHashSet();
167-
adjustSourceLines.set((Node node) -> {
168-
if(node == null || !visitedNodes.add(node)) {
169-
return;
170-
}
171-
if(node instanceof AbstractNode) {
172-
final SourceLocation sourceLocation = node.getSourceLocation();
173-
if (sourceLocation != null) {
174-
final SourceLocation newSourceLocation = new SourceLocation(
175-
sourceLocation.getLine() + lineDelta.get(),
176-
sourceLocation.getColumn(),
177-
sourceLocation.getSourceName()
178-
);
179-
((AbstractNode) node).setSourceLocation(newSourceLocation);
180-
}
181-
182-
}
183-
//noinspection unchecked
184-
final List<Node> children = node.getChildren();
185-
if(children != null) {
186-
//noinspection unchecked
187-
children.forEach(child -> {
188-
if(child != null) {
189-
adjustSourceLines.get().accept(child);
190-
}
191-
});
192-
}
193-
});
194-
adjustSourceLines.get().accept(document);
161+
final Integer lineDeltaToApply = lineDelta.get();
162+
GraphQLUtil.adjustSourceLocations(document, lineDeltaToApply, 0);
195163
}
196164

197165
typeRegistry.merge(new SchemaParser().buildRegistry(document));
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2018-present, Jim Kynde Meyer
3+
* All rights reserved.
4+
* <p>
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
package com.intellij.lang.jsgraphql.utils;
9+
10+
import com.google.common.collect.Sets;
11+
import com.intellij.openapi.util.Ref;
12+
import graphql.language.AbstractNode;
13+
import graphql.language.Document;
14+
import graphql.language.Node;
15+
import graphql.language.SourceLocation;
16+
17+
import java.util.List;
18+
import java.util.Set;
19+
import java.util.function.Consumer;
20+
21+
public final class GraphQLUtil {
22+
23+
24+
/**
25+
* Shifts the source locations in the specified document with the specified line detla
26+
* @param document a GraphQL document from graphql-java
27+
* @param lineDelta the delta line to apply to the document and all child nodes
28+
* @param firstLineColumnDelta the column delta for the first line
29+
*/
30+
public static void adjustSourceLocations(Document document, int lineDelta, int firstLineColumnDelta) {
31+
final Ref<Consumer<Node>> adjustSourceLines = new Ref<>();
32+
final Set<Node> visitedNodes = Sets.newHashSet();
33+
adjustSourceLines.set((Node node) -> {
34+
if(node == null || !visitedNodes.add(node)) {
35+
return;
36+
}
37+
if(node instanceof AbstractNode) {
38+
final SourceLocation sourceLocation = node.getSourceLocation();
39+
if (sourceLocation != null) {
40+
final int currentLine = sourceLocation.getLine();
41+
final int columnDelta = currentLine == 1 ? firstLineColumnDelta : 0;
42+
final SourceLocation newSourceLocation = new SourceLocation(
43+
currentLine + lineDelta,
44+
sourceLocation.getColumn() + columnDelta,
45+
sourceLocation.getSourceName()
46+
);
47+
((AbstractNode) node).setSourceLocation(newSourceLocation);
48+
}
49+
50+
}
51+
//noinspection unchecked
52+
final List<Node> children = node.getChildren();
53+
if(children != null) {
54+
//noinspection unchecked
55+
children.forEach(child -> {
56+
if(child != null) {
57+
adjustSourceLines.get().accept(child);
58+
}
59+
});
60+
}
61+
});
62+
adjustSourceLines.get().accept(document);
63+
}
64+
}

0 commit comments

Comments
 (0)