Skip to content

Commit e9cec66

Browse files
committed
Reworked introspection schema file creation
1 parent 1cf5f41 commit e9cec66

File tree

2 files changed

+108
-95
lines changed

2 files changed

+108
-95
lines changed

resources/messages/GraphQLMessages.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ graphql.notification.error.title=GraphQL error
88
graphql.notification.stack.trace=Stack trace
99
graphql.notification.retry.without.defaults=Retry (skip default values from now on)
1010
graphql.notification.retry=Retry
11-
graphql.notification.unable.to.open.editor=Unable to open an editor for '{0}'
12-
graphql.notification.unable.to.create.file=Unable to create file '{0}' in directory '{1}'.<br/>Error: {2}
11+
graphql.notification.unable.to.open.editor=Unable to open an editor for ''{0}''
12+
graphql.notification.unable.to.create.file=Unable to create file ''{0}'' in directory ''{1}''.<br/>Error: {2}
1313
graphql.notification.invalid.config.file=Invalid config file
1414
graphql.notification.empty.schema.path=Please set a non-empty `schemaPath` field in the config file.
1515
graphql.notification.empty.endpoint.url=Please set a non-empty endpoint `url` field in the config file.
1616
graphql.notification.unable.to.parse.file=Unable to parse {0}
1717
graphql.notification.load.schema.from.endpoint.title=Get GraphQL schema from endpoint now?
18-
graphql.notification.load.schema.from.endpoint.body=Introspect '{0}' to update the local schema file.
19-
graphql.notification.load.schema.from.endpoint.action=Introspect '{0}'
18+
graphql.notification.load.schema.from.endpoint.body=Introspect ''{0}'' to update the local schema file.
19+
graphql.notification.load.schema.from.endpoint.action=Introspect ''{0}''
2020

2121
# Introspection
2222
graphql.introspection.missing.data=Expected `data` key to be present in query result.

src/main/com/intellij/lang/jsgraphql/ide/editor/GraphQLIntrospectionService.java

Lines changed: 104 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import com.google.gson.Gson;
1212
import com.google.gson.JsonSyntaxException;
1313
import com.intellij.ide.actions.CreateFileAction;
14-
import com.intellij.ide.impl.DataManagerImpl;
1514
import com.intellij.ide.util.PropertiesComponent;
1615
import com.intellij.lang.jsgraphql.GraphQLBundle;
1716
import com.intellij.lang.jsgraphql.GraphQLSettings;
@@ -26,14 +25,12 @@
2625
import com.intellij.notification.NotificationType;
2726
import com.intellij.notification.Notifications;
2827
import com.intellij.openapi.Disposable;
29-
import com.intellij.openapi.actionSystem.ActionManager;
30-
import com.intellij.openapi.actionSystem.ActionPlaces;
3128
import com.intellij.openapi.actionSystem.AnAction;
3229
import com.intellij.openapi.actionSystem.AnActionEvent;
3330
import com.intellij.openapi.application.ApplicationManager;
3431
import com.intellij.openapi.application.WriteAction;
32+
import com.intellij.openapi.command.WriteCommandAction;
3533
import com.intellij.openapi.components.ServiceManager;
36-
import com.intellij.openapi.editor.Editor;
3734
import com.intellij.openapi.editor.EditorBundle;
3835
import com.intellij.openapi.fileEditor.FileEditor;
3936
import com.intellij.openapi.fileEditor.FileEditorManager;
@@ -49,8 +46,10 @@
4946
import com.intellij.openapi.util.text.StringUtil;
5047
import com.intellij.openapi.vfs.VirtualFile;
5148
import com.intellij.psi.PsiDirectory;
49+
import com.intellij.psi.PsiDocumentManager;
5250
import com.intellij.psi.PsiFile;
5351
import com.intellij.psi.PsiFileFactory;
52+
import com.intellij.psi.codeStyle.CodeStyleManager;
5453
import com.intellij.psi.impl.file.PsiDirectoryFactory;
5554
import com.intellij.util.Consumer;
5655
import com.intellij.util.ExceptionUtil;
@@ -245,45 +244,51 @@ public String printIntrospectionAsGraphQL(@NotNull Map<String, Object> introspec
245244
@SuppressWarnings("unchecked")
246245
@NotNull
247246
private Map<String, Object> getIntrospectionSchemaData(@NotNull Map<String, Object> introspection) {
248-
if (!introspection.containsKey("__schema")) {
249-
// possibly a full query result
250-
if (introspection.containsKey("errors")) {
251-
final Object errorsValue = introspection.get("errors");
252-
if (errorsValue instanceof List && ((List<?>) errorsValue).size() == 0) {
253-
if (!PropertiesComponent.getInstance().isTrueValue(DISABLE_EMPTY_ERRORS_WARNING_KEY)) {
254-
final Notification emptyErrorNotification = new Notification(
255-
GraphQLNotificationUtil.NOTIFICATION_GROUP_ID,
256-
GraphQLBundle.message("graphql.notification.introspection.error.title"),
257-
GraphQLBundle.message("graphql.notification.introspection.empty.errors"),
258-
NotificationType.WARNING
259-
);
260-
261-
final AnAction dontShowAgainAction = new NotificationAction(EditorBundle.message("notification.dont.show.again.message")) {
262-
@Override
263-
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
264-
PropertiesComponent.getInstance().setValue(DISABLE_EMPTY_ERRORS_WARNING_KEY, "true");
265-
notification.hideBalloon();
266-
}
267-
};
268-
269-
emptyErrorNotification.addAction(dontShowAgainAction);
270-
Notifications.Bus.notify(emptyErrorNotification, myProject);
271-
}
272-
} else {
273-
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.errors", new Gson().toJson(introspection.get("errors"))));
274-
}
275-
}
276-
if (!introspection.containsKey("data")) {
277-
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.missing.data"));
278-
}
279-
introspection = (Map<String, Object>) introspection.get("data");
280-
if (!introspection.containsKey("__schema")) {
281-
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.missing.schema"));
247+
if (introspection.containsKey("__schema")) {
248+
return introspection;
249+
}
250+
251+
// possibly a full query result
252+
if (introspection.containsKey("errors")) {
253+
final Object errorsValue = introspection.get("errors");
254+
if (errorsValue instanceof List && ((List<?>) errorsValue).size() == 0) {
255+
showEmptyErrorsNotification();
256+
} else {
257+
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.errors", new Gson().toJson(introspection.get("errors"))));
282258
}
283259
}
260+
if (!introspection.containsKey("data")) {
261+
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.missing.data"));
262+
}
263+
introspection = (Map<String, Object>) introspection.get("data");
264+
if (!introspection.containsKey("__schema")) {
265+
throw new IllegalArgumentException(GraphQLBundle.message("graphql.introspection.missing.schema"));
266+
}
284267
return introspection;
285268
}
286269

270+
private void showEmptyErrorsNotification() {
271+
if (!PropertiesComponent.getInstance().isTrueValue(DISABLE_EMPTY_ERRORS_WARNING_KEY)) {
272+
final Notification emptyErrorNotification = new Notification(
273+
GraphQLNotificationUtil.NOTIFICATION_GROUP_ID,
274+
GraphQLBundle.message("graphql.notification.introspection.error.title"),
275+
GraphQLBundle.message("graphql.notification.introspection.empty.errors"),
276+
NotificationType.WARNING
277+
);
278+
279+
final AnAction dontShowAgainAction = new NotificationAction(EditorBundle.message("notification.dont.show.again.message")) {
280+
@Override
281+
public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
282+
PropertiesComponent.getInstance().setValue(DISABLE_EMPTY_ERRORS_WARNING_KEY, "true");
283+
notification.hideBalloon();
284+
}
285+
};
286+
287+
emptyErrorNotification.addAction(dontShowAgainAction);
288+
Notifications.Bus.notify(emptyErrorNotification, myProject);
289+
}
290+
}
291+
287292
private GraphQLSchema buildIntrospectionSchema(TypeDefinitionRegistry registry) {
288293
final RuntimeWiring runtimeWiring = EchoingWiringFactory.newEchoingWiring(wiring -> {
289294
Map<String, ScalarTypeDefinition> scalars = registry.scalars();
@@ -340,64 +345,72 @@ void createOrUpdateIntrospectionOutputFile(@NotNull String schemaText,
340345
@NotNull IntrospectionOutputFormat format,
341346
@NotNull VirtualFile introspectionSourceFile,
342347
@NotNull String outputFileName) {
343-
WriteAction.run(() -> {
344-
try {
345-
final String header;
346-
switch (format) {
347-
case SDL:
348-
header = "# This file was generated based on \"" + introspectionSourceFile.getName() + "\". Do not edit manually.\n\n";
349-
break;
350-
case JSON:
351-
header = "";
352-
break;
353-
default:
354-
throw new IllegalArgumentException("unsupported output format: " + format);
355-
}
356-
String relativeOutputFileName = FileUtil.toSystemIndependentName(outputFileName);
357-
VirtualFile outputFile = introspectionSourceFile.getParent().findFileByRelativePath(relativeOutputFileName);
358-
if (outputFile == null) {
359-
PsiDirectory directory = PsiDirectoryFactory.getInstance(myProject).createDirectory(introspectionSourceFile.getParent());
360-
CreateFileAction.MkDirs dirs = new CreateFileAction.MkDirs(relativeOutputFileName, directory);
361-
outputFile = dirs.directory.getVirtualFile().createChildData(introspectionSourceFile, dirs.newName);
362-
}
363-
outputFile.putUserData(GraphQLSchemaKeys.IS_GRAPHQL_INTROSPECTION_JSON, true);
364-
final FileEditor[] fileEditors = FileEditorManager.getInstance(myProject).openFile(outputFile, true, true);
365-
if (fileEditors.length > 0) {
366-
final FileEditor fileEditor = fileEditors[0];
367-
setEditorTextAndFormatLines(header + schemaText, fileEditor);
368-
} else {
369-
Notifications.Bus.notify(new Notification(GraphQLNotificationUtil.NOTIFICATION_GROUP_ID, GraphQLBundle.message("graphql.notification.error.title"),
370-
GraphQLBundle.message("graphql.notification.unable.to.open.editor", outputFile.getPath()), NotificationType.ERROR));
371-
}
372-
} catch (IOException ioe) {
373-
Notifications.Bus.notify(new Notification(
374-
GraphQLNotificationUtil.NOTIFICATION_GROUP_ID,
375-
GraphQLBundle.message("graphql.notification.error.title"),
376-
GraphQLBundle.message("graphql.notification.unable.to.create.file",
377-
outputFileName, introspectionSourceFile.getParent().getPath(), GraphQLNotificationUtil.formatExceptionMessage(ioe)),
378-
NotificationType.ERROR
379-
));
348+
try {
349+
final String header;
350+
switch (format) {
351+
case SDL:
352+
header = "# This file was generated based on \"" + introspectionSourceFile.getName() + "\". Do not edit manually.\n\n";
353+
break;
354+
case JSON:
355+
header = "";
356+
break;
357+
default:
358+
throw new IllegalArgumentException("unsupported output format: " + format);
380359
}
381-
});
382-
}
383360

384-
private void setEditorTextAndFormatLines(String text, FileEditor fileEditor) {
385-
if (fileEditor instanceof TextEditor) {
386-
// IntelliJ only allows the \n linebreak inside editor documents.
387-
final String normalizedText = StringUtil.convertLineSeparators(text);
388-
final Editor editor = ((TextEditor) fileEditor).getEditor();
389-
editor.getDocument().setText(normalizedText);
390-
AnAction reformatCode = ActionManager.getInstance().getAction("ReformatCode");
391-
if (reformatCode != null) {
392-
final AnActionEvent actionEvent = AnActionEvent.createFromDataContext(
393-
ActionPlaces.UNKNOWN,
394-
null,
395-
new DataManagerImpl.MyDataContext(editor.getComponent())
396-
);
397-
reformatCode.actionPerformed(actionEvent);
361+
VirtualFile outputFile = createSchemaFile(introspectionSourceFile, FileUtil.toSystemIndependentName(outputFileName));
362+
363+
final FileEditor[] fileEditors = FileEditorManager.getInstance(myProject).openFile(outputFile, true, true);
364+
if (fileEditors.length == 0) {
365+
showUnableToOpenEditorNotification(outputFile);
366+
return;
398367
}
399368

369+
TextEditor textEditor = ObjectUtils.tryCast(fileEditors[0], TextEditor.class);
370+
if (textEditor == null) {
371+
showUnableToOpenEditorNotification(outputFile);
372+
return;
373+
}
374+
375+
WriteCommandAction.runWriteCommandAction(myProject, () -> {
376+
com.intellij.openapi.editor.Document document = textEditor.getEditor().getDocument();
377+
document.setText(StringUtil.convertLineSeparators(header + schemaText));
378+
PsiDocumentManager.getInstance(myProject).commitDocument(document);
379+
380+
PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
381+
if (psiFile != null) {
382+
CodeStyleManager.getInstance(myProject).reformat(psiFile);
383+
}
384+
});
385+
} catch (IOException ioe) {
386+
Notifications.Bus.notify(new Notification(
387+
GraphQLNotificationUtil.NOTIFICATION_GROUP_ID,
388+
GraphQLBundle.message("graphql.notification.error.title"),
389+
GraphQLBundle.message("graphql.notification.unable.to.create.file",
390+
outputFileName, introspectionSourceFile.getParent().getPath(), GraphQLNotificationUtil.formatExceptionMessage(ioe)),
391+
NotificationType.ERROR
392+
));
393+
}
394+
}
395+
396+
private void showUnableToOpenEditorNotification(@NotNull VirtualFile outputFile) {
397+
Notifications.Bus.notify(new Notification(GraphQLNotificationUtil.NOTIFICATION_GROUP_ID, GraphQLBundle.message("graphql.notification.error.title"),
398+
GraphQLBundle.message("graphql.notification.unable.to.open.editor", outputFile.getPath()), NotificationType.ERROR));
399+
}
400+
401+
@NotNull
402+
private VirtualFile createSchemaFile(@NotNull VirtualFile introspectionSourceFile,
403+
@NotNull String relativeOutputFileName) throws IOException {
404+
VirtualFile outputFile = introspectionSourceFile.getParent().findFileByRelativePath(relativeOutputFileName);
405+
if (outputFile == null) {
406+
outputFile = WriteAction.compute(() -> {
407+
PsiDirectory directory = PsiDirectoryFactory.getInstance(myProject).createDirectory(introspectionSourceFile.getParent());
408+
CreateFileAction.MkDirs dirs = new CreateFileAction.MkDirs(relativeOutputFileName, directory);
409+
return dirs.directory.getVirtualFile().createChildData(introspectionSourceFile, dirs.newName);
410+
});
400411
}
412+
outputFile.putUserData(GraphQLSchemaKeys.IS_GRAPHQL_INTROSPECTION_JSON, true);
413+
return outputFile;
401414
}
402415

403416
@Override

0 commit comments

Comments
 (0)