Skip to content

Commit 7eb38cf

Browse files
committed
Fixed source location deltas as part of upgrade to graphql-java 12.0 (#238)
1 parent ce949bc commit 7eb38cf

File tree

10 files changed

+120
-25
lines changed

10 files changed

+120
-25
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,14 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
186186
// store the editor since we need to translate graphql-java source locations to psi elements
187187
Editor editor = session.getUserData(EDITOR);
188188
if (editor == null) {
189-
final FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(containingFile.getVirtualFile());
189+
FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(containingFile.getVirtualFile());
190+
if (fileEditor == null && containingFile.getContext() != null) {
191+
// injected PsiFile so try to get the editor from the hosting/context file
192+
final PsiFile contextFile = containingFile.getContext().getContainingFile();
193+
if (contextFile != null) {
194+
fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(contextFile.getVirtualFile());
195+
}
196+
}
190197
if (fileEditor instanceof TextEditor) {
191198
editor = ((TextEditor) fileEditor).getEditor();
192199
session.putUserData(EDITOR, editor);

src/main/com/intellij/lang/jsgraphql/ide/injection/javascript/GraphQLTemplateFragmentLanguageInjector.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.intellij.lang.javascript.JSTokenTypes;
1515
import com.intellij.lang.javascript.psi.ecma6.JSStringTemplateExpression;
1616
import com.intellij.lang.jsgraphql.GraphQLLanguage;
17+
import com.intellij.openapi.application.ApplicationManager;
1718
import com.intellij.openapi.util.TextRange;
1819
import com.intellij.openapi.vfs.VirtualFile;
1920
import com.intellij.psi.PsiElement;
@@ -66,7 +67,7 @@ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull
6667

6768
// update graphql config notifications
6869
final VirtualFile virtualFile = context.getContainingFile().getVirtualFile();
69-
if(virtualFile != null) {
70+
if(virtualFile != null && !ApplicationManager.getApplication().isUnitTestMode()) {
7071
EditorNotifications.getInstance(context.getProject()).updateNotifications(virtualFile);
7172
}
7273
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,9 @@ public TypeDefinitionRegistryWithErrors getRegistryWithErrors(PsiElement scopedE
201201
if(e.getCause() instanceof RecognitionException) {
202202
final Token offendingToken = ((RecognitionException) e.getCause()).getOffendingToken();
203203
if(offendingToken != null) {
204-
final List<SourceLocation> sourceLocation = Collections.singletonList(new SourceLocation(
205-
offendingToken.getLine(),
206-
offendingToken.getCharPositionInLine() + 1,
207-
GraphQLPsiSearchHelper.getFileName(psiFile)
208-
));
204+
final List<SourceLocation> sourceLocation = Collections.singletonList(
205+
GraphQLUtil.createSourceLocationFromDelta(offendingToken, lineDelta.get() + injectionLineDelta, injectedFirstLineColumnDelta)
206+
);
209207
errors.add(new SchemaProblem(Collections.singletonList(new InvalidSyntaxError(sourceLocation, "Unexpected token: \"" + offendingToken.getText() + "\""))));
210208
}
211209
}

src/main/com/intellij/lang/jsgraphql/utils/GraphQLUtil.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,31 @@ public static Document parseDocument(String input, int lineDelta, int firstLineC
4242
return parseDocument(input, null, lineDelta, firstLineColumnDelta);
4343
}
4444

45+
/**
46+
*
47+
* Creates a source location based on a token and line/column offsets
48+
* @param token the token to create a location for
49+
* @param lineDelta the delta line to apply to the document and all child nodes
50+
* @param firstLineColumnDelta the column delta for the first line
51+
* @return the offset location for the token
52+
*/
53+
public static SourceLocation createSourceLocationFromDelta(Token token, int lineDelta, int firstLineColumnDelta) {
54+
String sourceName = token.getTokenSource().getSourceName();
55+
if (IntStream.UNKNOWN_SOURCE_NAME.equals(sourceName)) {
56+
// UNKNOWN_SOURCE_NAME is Antrl's way of indicating that no source name was given during parsing --
57+
// which is the case when queries and other operations are parsed. We don't want this hardcoded
58+
// '<unknown>' sourceName to leak to clients when the response is serialized as JSON, so we null it.
59+
sourceName = null;
60+
}
61+
int line = token.getLine();
62+
int column = token.getCharPositionInLine() + 1;
63+
if(line == 0 && firstLineColumnDelta > 0) {
64+
column += firstLineColumnDelta;
65+
}
66+
line += lineDelta;
67+
return new SourceLocation(line, column, sourceName);
68+
}
69+
4570
/**
4671
* Parses GraphQL string input into a graphql-java Document, shifting the source locations in the specified document with the specified line delta.
4772
* Shifting of the sourceLocation is required for proper error reporting locations for GraphQL language injections, e.g. GraphQL in a JavaScript file.
@@ -77,21 +102,12 @@ public static Document parseDocument(String input, String sourceName, int lineDe
77102
GraphqlAntlrToLanguage antlrToLanguage = new GraphqlAntlrToLanguage(tokens, multiSourceReader) {
78103
@Override
79104
protected SourceLocation getSourceLocation(ParserRuleContext parserRuleContext) {
80-
Token startToken = parserRuleContext.getStart();
81-
String sourceName = startToken.getTokenSource().getSourceName();
82-
if (IntStream.UNKNOWN_SOURCE_NAME.equals(sourceName)) {
83-
// UNKNOWN_SOURCE_NAME is Antrl's way of indicating that no source name was given during parsing --
84-
// which is the case when queries and other operations are parsed. We don't want this hardcoded
85-
// '<unknown>' sourceName to leak to clients when the response is serialized as JSON, so we null it.
86-
sourceName = null;
87-
}
88-
int line = startToken.getLine();
89-
int column = startToken.getCharPositionInLine() + 1;
90-
if(line == 1 && firstLineColumnDelta > 0) {
91-
column += firstLineColumnDelta;
92-
}
93-
line += lineDelta;
94-
return new SourceLocation(line, column, sourceName);
105+
return createSourceLocationFromDelta(parserRuleContext.getStart(), lineDelta, firstLineColumnDelta);
106+
}
107+
108+
@Override
109+
protected SourceLocation getSourceLocation(Token token) {
110+
return createSourceLocationFromDelta(token, lineDelta, firstLineColumnDelta);
95111
}
96112
};
97113
Document doc = antlrToLanguage.createDocument(documentContext);

src/test/com/intellij/lang/jsgraphql/injection/GraphQLInjectionCodeInsightTest.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ public class GraphQLInjectionCodeInsightTest extends LightCodeInsightFixtureTest
2121
@Override
2222
public void setUp() throws Exception {
2323
super.setUp();
24-
myFixture.configureByFiles(".graphqlconfig", "schema.graphql");
24+
myFixture.configureByFiles(
25+
"schema.graphql",
26+
".graphqlconfig",
27+
"lines-1/.graphqlconfig",
28+
"lines-2/.graphqlconfig"
29+
);
2530
// use the synchronous method of building the configuration for the unit test
2631
GraphQLConfigManager.getService(getProject()).doBuildConfigurationModel(null);
2732
}
@@ -34,11 +39,29 @@ protected String getTestDataPath() {
3439
// ---- highlighting -----
3540

3641
@Test
37-
public void testErrorAnnotator() {
42+
public void testErrorAnnotatorOnFragments() {
3843
myFixture.configureByFiles("injection-comment.js");
3944
final List<HighlightInfo> highlighting = myFixture.doHighlighting(HighlightSeverity.ERROR);
4045
assertEquals("Expected just one error", 1, highlighting.size());
4146
assertEquals("Unknown fragment name should be the error", "OnlyTheUnknownFragmentShouldBeHighlightedAsError", highlighting.get(0).getText());
4247
}
4348

49+
@Test
50+
public void testErrorAnnotatorSourceLines1() {
51+
myFixture.configureByFiles("lines-1/injection-source-lines-1.js");
52+
final List<HighlightInfo> highlighting = myFixture.doHighlighting(HighlightSeverity.ERROR);
53+
assertEquals("Expected just one error", 1, highlighting.size());
54+
assertEquals("Should mark ServerType with an error", "ServerType", highlighting.get(0).getText());
55+
assertEquals("Should mark ServerType in the right injected position", 201, highlighting.get(0).getStartOffset());
56+
}
57+
58+
@Test
59+
public void testErrorAnnotatorSourceLines2() {
60+
myFixture.configureByFiles("lines-2/injection-source-lines-2.js");
61+
final List<HighlightInfo> highlighting = myFixture.doHighlighting(HighlightSeverity.ERROR);
62+
assertEquals("Expected just one error", 1, highlighting.size());
63+
assertEquals("Should mark OutputType with an error", "OutputType", highlighting.get(0).getText());
64+
assertEquals("Should mark OutputType in the right injected position", 209, highlighting.get(0).getStartOffset());
65+
}
66+
4467
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"name": "Injection Test GraphQL Schema"
2+
"name": "Injection Test GraphQL Schema",
3+
"includes": ["*"]
34
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "Injection Test GraphQL Schema"
3+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// line deltas
3+
//
4+
5+
const schema1 = gql`
6+
7+
scalar Foo
8+
9+
type ServerType {
10+
valueFromServer: Foo!
11+
}
12+
13+
type Query {
14+
hello: Foo
15+
}
16+
17+
query Foo {
18+
... on ServerType {
19+
valueFromServer
20+
}
21+
}
22+
`;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "Injection Test GraphQL Schema"
3+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// line deltas
3+
//
4+
5+
const schema2 = gql`
6+
7+
scalar Foo
8+
9+
type OutputType {
10+
someField: Foo!
11+
}
12+
13+
type Query {
14+
hello: Foo
15+
}
16+
17+
type SchemaError {
18+
argument(foo: OutputType): Foo
19+
}
20+
21+
`;

0 commit comments

Comments
 (0)