Skip to content

Commit 42bf5a2

Browse files
committed
Added intentions to add new missing types when authoring schemas as SDL (#164)
1 parent cc0daa7 commit 42bf5a2

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (c) 2019-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.ide;
9+
10+
import com.google.common.collect.Lists;
11+
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
12+
import com.intellij.lang.jsgraphql.GraphQLLanguage;
13+
import com.intellij.lang.jsgraphql.psi.GraphQLIdentifier;
14+
import com.intellij.lang.jsgraphql.psi.GraphQLInputValueDefinition;
15+
import com.intellij.lang.jsgraphql.psi.GraphQLTypeSystemDefinition;
16+
import com.intellij.openapi.editor.Document;
17+
import com.intellij.openapi.editor.Editor;
18+
import com.intellij.openapi.editor.EditorModificationUtil;
19+
import com.intellij.openapi.project.Project;
20+
import com.intellij.psi.PsiElement;
21+
import com.intellij.psi.PsiFile;
22+
import com.intellij.psi.PsiFileFactory;
23+
import com.intellij.psi.PsiWhiteSpace;
24+
import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl;
25+
import com.intellij.psi.util.PsiEditorUtil;
26+
import com.intellij.psi.util.PsiTreeUtil;
27+
import org.jetbrains.annotations.Nls;
28+
import org.jetbrains.annotations.NotNull;
29+
import org.jetbrains.annotations.Nullable;
30+
31+
import java.util.List;
32+
33+
/**
34+
* Fix to create a new type definition while authoring schemas as SDL.
35+
*/
36+
public class GraphQLMissingTypeFix extends LocalQuickFixAndIntentionActionOnPsiElement {
37+
38+
private final GraphQLTypeKind typeKind;
39+
private final String typeName;
40+
41+
enum GraphQLTypeKind {
42+
TYPE,
43+
INTERFACE,
44+
UNION,
45+
SCALAR,
46+
ENUM,
47+
INPUT
48+
}
49+
50+
private GraphQLMissingTypeFix(@NotNull GraphQLIdentifier element, GraphQLTypeKind typeKind) {
51+
super(element);
52+
typeName = element.getText();
53+
this.typeKind = typeKind;
54+
}
55+
56+
@NotNull
57+
@Override
58+
public String getText() {
59+
return "Add \"" + typeKind.name().toLowerCase() + ' ' + this.typeName + "\"";
60+
}
61+
62+
@Override
63+
public void invoke(@NotNull Project project, @NotNull PsiFile file, @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
64+
if (editor == null) {
65+
editor = PsiEditorUtil.Service.getInstance().findEditorByPsiElement(startElement);
66+
if (editor == null) {
67+
return;
68+
}
69+
}
70+
final GraphQLTypeSystemDefinition definition = PsiTreeUtil.getParentOfType(startElement, GraphQLTypeSystemDefinition.class);
71+
if (definition != null) {
72+
editor.getCaretModel().moveToOffset(definition.getTextRange().getEndOffset() + 1);
73+
String code = typeKind.name().toLowerCase() + " " + typeName;
74+
String caret = "__caret__";
75+
switch (typeKind) {
76+
case ENUM:
77+
case TYPE:
78+
case INTERFACE:
79+
case INPUT:
80+
code += " {\n" + caret + "\n}";
81+
break;
82+
case SCALAR:
83+
code += caret;
84+
break;
85+
case UNION:
86+
code += " = " + caret;
87+
break;
88+
}
89+
final PsiFile codeFile = PsiFileFactory.getInstance(project).createFileFromText("", GraphQLLanguage.INSTANCE, code);
90+
CodeStyleManagerImpl.getInstance(project).reformat(codeFile);
91+
assert codeFile.getViewProvider().getDocument() != null;
92+
CodeStyleManagerImpl.getInstance(project).reformat(codeFile);
93+
final Document document = codeFile.getViewProvider().getDocument();
94+
if (document != null) {
95+
code = document.getText();
96+
}
97+
int caretDelta = 0;
98+
if (code.contains(caret)) {
99+
caretDelta = code.indexOf(caret) + 1;
100+
code = code.replace(caret, "");
101+
}
102+
103+
final String lineBefore = definition.getNextSibling() instanceof PsiWhiteSpace ? "" : "\n";
104+
105+
EditorModificationUtil.insertStringAtCaret(editor, lineBefore + "\n" + code + "\n", false, caretDelta);
106+
}
107+
}
108+
109+
@Nls(capitalization = Nls.Capitalization.Sentence)
110+
@NotNull
111+
@Override
112+
public String getFamilyName() {
113+
return "Create missing type definition";
114+
}
115+
116+
static List<GraphQLMissingTypeFix> getApplicableFixes(GraphQLIdentifier typeName) {
117+
final List<GraphQLMissingTypeFix> fixes = Lists.newArrayList();
118+
final GraphQLInputValueDefinition inputValueDefinition = PsiTreeUtil.getParentOfType(typeName, GraphQLInputValueDefinition.class);
119+
if (inputValueDefinition != null) {
120+
// input types: input object, enum, scalar
121+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.INPUT));
122+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.ENUM));
123+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.SCALAR));
124+
} else {
125+
// output types: typeKind, interface, enum, union, scalar
126+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.TYPE));
127+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.INTERFACE));
128+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.ENUM));
129+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.SCALAR));
130+
fixes.add(new GraphQLMissingTypeFix(typeName, GraphQLTypeKind.UNION));
131+
}
132+
return fixes;
133+
}
134+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder a
143143
}
144144
} else if (parent instanceof GraphQLTypeName) {
145145
message = "Unknown type \"" + psiElement.getText() + "\"";
146+
fixes.addAll(GraphQLMissingTypeFix.getApplicableFixes((GraphQLIdentifier) psiElement));
146147
}
147148
if (message != null) {
148149
final Optional<Annotation> annotation = createErrorAnnotation(annotationHolder, psiElement, message);

0 commit comments

Comments
 (0)