vscode-apollo 1.20.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.circleci/config.yml +27 -18
  2. package/.git-blame-ignore-revs +2 -0
  3. package/.nvmrc +1 -1
  4. package/.vscode/launch.json +9 -4
  5. package/.vscode/tasks.json +58 -16
  6. package/.vscodeignore +12 -1
  7. package/CHANGELOG.md +84 -0
  8. package/CODEOWNERS +4 -0
  9. package/README.md +97 -48
  10. package/graphql.configuration.json +5 -1
  11. package/images/marketplace/apollo-wordmark.png +0 -0
  12. package/jest.config.ts +14 -4
  13. package/jest.e2e.config.js +17 -0
  14. package/package.json +67 -68
  15. package/renovate.json +7 -0
  16. package/sampleWorkspace/clientSchema/apollo.config.cjs +10 -0
  17. package/sampleWorkspace/clientSchema/src/clientSchema.js +16 -0
  18. package/sampleWorkspace/clientSchema/src/test.js +18 -0
  19. package/sampleWorkspace/fixtures/starwarsSchema.graphql +299 -0
  20. package/sampleWorkspace/httpSchema/apollo.config.ts +8 -0
  21. package/sampleWorkspace/httpSchema/src/test.js +9 -0
  22. package/sampleWorkspace/localSchema/apollo.config.js +8 -0
  23. package/sampleWorkspace/localSchema/src/test.js +8 -0
  24. package/sampleWorkspace/localSchemaArray/apollo.config.js +12 -0
  25. package/sampleWorkspace/localSchemaArray/planets.graphql +20 -0
  26. package/sampleWorkspace/localSchemaArray/src/test.js +12 -0
  27. package/sampleWorkspace/sampleWorkspace.code-workspace +20 -0
  28. package/sampleWorkspace/spotifyGraph/apollo.config.mjs +5 -0
  29. package/sampleWorkspace/spotifyGraph/src/test.js +11 -0
  30. package/src/__e2e__/mockServer.js +117 -0
  31. package/src/__e2e__/mocks.js +13094 -0
  32. package/src/__e2e__/run.js +23 -0
  33. package/src/__e2e__/runTests.js +44 -0
  34. package/src/__e2e__/setup.js +1 -0
  35. package/src/__e2e__/vscode-environment.js +16 -0
  36. package/src/__e2e__/vscode.js +1 -0
  37. package/src/build.js +57 -0
  38. package/src/env/index.ts +0 -3
  39. package/src/extension.ts +251 -225
  40. package/src/language-server/__e2e__/clientSchema.e2e.ts +147 -0
  41. package/src/language-server/__e2e__/httpSchema.e2e.ts +21 -0
  42. package/src/language-server/__e2e__/localSchema.e2e.ts +25 -0
  43. package/src/language-server/__e2e__/localSchemaArray.e2e.ts +31 -0
  44. package/src/language-server/__e2e__/studioGraph.e2e.ts +65 -0
  45. package/src/language-server/__e2e__/utils.ts +151 -0
  46. package/src/language-server/__tests__/diagnostics.test.ts +8 -8
  47. package/src/language-server/__tests__/fileSet.test.ts +1 -1
  48. package/src/language-server/__tests__/fixtures/starwarsSchema.ts +2 -2
  49. package/src/language-server/config/__tests__/config.ts +22 -96
  50. package/src/language-server/config/__tests__/loadConfig.ts +120 -220
  51. package/src/language-server/config/__tests__/utils.ts +22 -29
  52. package/src/language-server/config/config.ts +221 -156
  53. package/src/language-server/config/loadConfig.ts +32 -153
  54. package/src/language-server/config/loadTsConfig.ts +70 -0
  55. package/src/language-server/config/utils.ts +5 -16
  56. package/src/language-server/diagnostics.ts +17 -8
  57. package/src/language-server/document.ts +16 -16
  58. package/src/language-server/engine/index.ts +57 -39
  59. package/src/language-server/engine/operations/frontendUrlRoot.ts +9 -1
  60. package/src/language-server/engine/operations/schemaTagsAndFieldStats.ts +9 -1
  61. package/src/language-server/errors/__tests__/NoMissingClientDirectives.test.ts +10 -5
  62. package/src/language-server/errors/logger.ts +1 -1
  63. package/src/language-server/errors/validation.ts +20 -23
  64. package/src/language-server/fileSet.ts +10 -12
  65. package/src/language-server/format.ts +1 -1
  66. package/src/language-server/graphqlTypes.ts +13020 -3455
  67. package/src/language-server/index.ts +0 -1
  68. package/src/language-server/languageProvider.ts +29 -32
  69. package/src/language-server/loadingHandler.ts +10 -27
  70. package/src/language-server/project/base.ts +32 -25
  71. package/src/language-server/project/client.ts +80 -114
  72. package/src/language-server/project/defaultClientSchema.ts +29 -4
  73. package/src/language-server/providers/schema/__tests__/file.ts +60 -19
  74. package/src/language-server/providers/schema/base.ts +2 -2
  75. package/src/language-server/providers/schema/endpoint.ts +15 -34
  76. package/src/language-server/providers/schema/engine.ts +25 -18
  77. package/src/language-server/providers/schema/file.ts +41 -32
  78. package/src/language-server/providers/schema/index.ts +5 -21
  79. package/src/language-server/server.ts +72 -50
  80. package/src/language-server/typings/graphql.d.ts +3 -3
  81. package/src/language-server/utilities/__tests__/graphql.test.ts +42 -54
  82. package/src/language-server/utilities/debouncer.ts +1 -1
  83. package/src/language-server/utilities/debug.ts +6 -5
  84. package/src/language-server/utilities/graphql.ts +17 -16
  85. package/src/language-server/utilities/source.ts +16 -16
  86. package/src/language-server/utilities/uri.ts +2 -2
  87. package/src/language-server/workspace.ts +29 -37
  88. package/src/languageServerClient.ts +4 -4
  89. package/src/messages.ts +38 -47
  90. package/src/tools/__tests__/buildServiceDefinition.test.ts +2 -2
  91. package/src/tools/buildServiceDefinition.ts +11 -11
  92. package/src/tools/schema/resolveObject.ts +1 -1
  93. package/src/tools/utilities/predicates.ts +1 -1
  94. package/src/utils.ts +7 -6
  95. package/syntaxes/graphql.dart.json +2 -4
  96. package/syntaxes/graphql.ex.json +1 -4
  97. package/tsconfig.build.json +8 -1
  98. package/tsconfig.json +5 -3
  99. package/src/env/fetch/fetch.ts +0 -32
  100. package/src/env/fetch/global.ts +0 -30
  101. package/src/env/fetch/index.d.ts +0 -2
  102. package/src/env/fetch/index.ts +0 -2
  103. package/src/env/fetch/url.ts +0 -9
  104. package/src/env/polyfills/array.ts +0 -17
  105. package/src/env/polyfills/index.ts +0 -2
  106. package/src/env/polyfills/object.ts +0 -7
  107. package/src/language-server/engine/GraphQLDataSource.ts +0 -124
  108. package/src/language-server/project/service.ts +0 -48
  109. package/src/language-server/typings/codemirror.d.ts +0 -4
package/src/extension.ts CHANGED
@@ -15,8 +15,13 @@ import {
15
15
  } from "vscode";
16
16
  import StatusBar from "./statusBar";
17
17
  import { getLanguageServerClient } from "./languageServerClient";
18
- import { NotificationType } from "vscode-languageclient";
19
- import type { EngineDecoration, LanguageClient } from "./messages";
18
+ import { LanguageClient } from "vscode-languageclient/node";
19
+ import {
20
+ type EngineDecoration,
21
+ LanguageServerCommands as LSCommands,
22
+ LanguageServerNotifications as LSNotifications,
23
+ LanguageServerRequests as LSRequests,
24
+ } from "./messages";
20
25
  import {
21
26
  printNoFileOpenMessage,
22
27
  printStatsToClientOutputChannel,
@@ -25,8 +30,7 @@ import { Debug } from "./debug";
25
30
 
26
31
  const { version } = require("../package.json");
27
32
 
28
- let client: LanguageClient;
29
- let clientDisposable: Disposable;
33
+ let globalClient: LanguageClient | null = null;
30
34
  let statusBar: StatusBar;
31
35
  let outputChannel: OutputChannel;
32
36
  let schemaTagItems: QuickPickItem[] = [];
@@ -44,86 +48,97 @@ function isError(response: any): response is ErrorShape {
44
48
  );
45
49
  }
46
50
 
47
- export function activate(context: ExtensionContext) {
51
+ export interface VSCodeGraphQLExtension {
52
+ outputChannel: OutputChannel;
53
+ client: LanguageClient;
54
+ LanguageServerCommands: typeof LSCommands;
55
+ LanguageServerNotifications: typeof LSNotifications;
56
+ LanguageServerRequests: typeof LSRequests;
57
+ }
58
+
59
+ export async function activate(
60
+ context: ExtensionContext,
61
+ ): Promise<VSCodeGraphQLExtension> {
48
62
  const serverModule = context.asAbsolutePath(
49
- join("lib/language-server", "server.js")
63
+ join("lib/language-server", "server.js"),
50
64
  );
51
-
52
- // Initialize language client
53
- client = getLanguageServerClient(serverModule, outputChannel);
65
+ outputChannel ||= window.createOutputChannel("Apollo GraphQL");
66
+ const client = getLanguageServerClient(serverModule, outputChannel);
67
+ globalClient = client;
54
68
  client.registerProposedFeatures();
55
69
 
56
70
  // Initialize disposables
57
71
  statusBar = new StatusBar({
58
72
  hasActiveTextEditor: Boolean(window.activeTextEditor),
59
73
  });
60
- outputChannel = window.createOutputChannel("Apollo GraphQL");
61
74
  Debug.SetOutputConsole(outputChannel);
62
- clientDisposable = client.start();
63
-
64
75
  // Handoff disposables for cleanup
65
- context.subscriptions.push(statusBar, outputChannel, clientDisposable);
66
-
67
- var serverDebugMessage: NotificationType<
68
- { type: string; message: string; stack?: string },
69
- any
70
- > = new NotificationType("serverDebugMessage");
71
-
72
- // Once client is ready, we can send messages and add listeners for various notifications
73
- client.onReady().then(() => {
74
- client.onNotification(serverDebugMessage, (message) => {
75
- switch (message.type) {
76
- case "info":
77
- Debug.info(message.message, message.stack);
78
- break;
79
- case "error":
80
- Debug.error(message.message, message.stack);
81
- break;
82
- case "warning":
83
- Debug.warning(message.message, message.stack);
84
- break;
85
- default:
86
- Debug.info(message.message, message.stack);
87
- break;
88
- }
89
- });
76
+ context.subscriptions.push(statusBar, outputChannel);
77
+
78
+ client.onNotification(LSNotifications.ServerDebugMessage, (message) => {
79
+ switch (message.type) {
80
+ case "info":
81
+ Debug.info(message.message, message.stack);
82
+ break;
83
+ case "error":
84
+ Debug.error(message.message, message.stack);
85
+ break;
86
+ case "warning":
87
+ Debug.warning(message.message, message.stack);
88
+ break;
89
+ default:
90
+ Debug.info(message.message, message.stack);
91
+ break;
92
+ }
93
+ });
90
94
 
91
- commands.registerCommand("apollographql/showStats", () => {
92
- const fileUri = window.activeTextEditor
93
- ? window.activeTextEditor.document.uri.fsPath
94
- : null;
95
+ commands.registerCommand("apollographql/showStats", () => {
96
+ const fileUri = window.activeTextEditor
97
+ ? window.activeTextEditor.document.uri.fsPath
98
+ : null;
95
99
 
96
- // if no editor is open, but an output channel is, vscode returns something like
97
- // output:extension-output-%234. If an editor IS open, this is something like file://Users/...
98
- // This check is just for either a / or a \ anywhere in a fileUri
99
- const fileOpen = fileUri && /[\/\\]/.test(fileUri);
100
+ // if no editor is open, but an output channel is, vscode returns something like
101
+ // output:extension-output-%234. If an editor IS open, this is something like file://Users/...
102
+ // This check is just for either a / or a \ anywhere in a fileUri
103
+ // TODO: this should probably be `registerTextEditorCommand` instead of `registerCommand`
104
+ const fileOpen = fileUri && /[\/\\]/.test(fileUri);
100
105
 
101
- if (fileOpen) {
102
- client.sendNotification("apollographql/getStats", { uri: fileUri });
103
- return;
104
- }
105
- printNoFileOpenMessage(client, version);
106
- client.outputChannel.show();
107
- });
106
+ if (fileOpen) {
107
+ client.sendNotification(LSCommands.GetStats, {
108
+ uri: fileUri,
109
+ });
110
+ return;
111
+ }
112
+ printNoFileOpenMessage(client, version);
113
+ client.outputChannel.show();
114
+ });
108
115
 
109
- client.onNotification("apollographql/statsLoaded", (params) => {
110
- printStatsToClientOutputChannel(client, params, version);
111
- client.outputChannel.show();
112
- });
113
- // For some reason, non-strings can only be sent in one direction. For now, messages
114
- // coming from the language server just need to be stringified and parsed.
115
- client.onNotification(
116
- "apollographql/configFilesFound",
117
- (params: string) => {
118
- const response = JSON.parse(params) as Array<any> | ErrorShape;
119
-
120
- const hasActiveTextEditor = Boolean(window.activeTextEditor);
121
- if (isError(response)) {
116
+ client.onNotification(LSNotifications.StatsLoaded, (params) => {
117
+ printStatsToClientOutputChannel(client, params, version);
118
+ client.outputChannel.show();
119
+ });
120
+
121
+ commands.registerCommand("apollographql/fileStats", (uri: string) => {
122
+ // this has been introduced to check the LSP loading status in tests right now
123
+ // TODO: "apollographql/showStats" should use this request as well instead of notifications
124
+ return client.sendRequest(LSRequests.FileStats, { uri });
125
+ });
126
+
127
+ // For some reason, non-strings can only be sent in one direction. For now, messages
128
+ // coming from the language server just need to be stringified and parsed.
129
+ client.onNotification(LSNotifications.ConfigFilesFound, (params: string) => {
130
+ const response = JSON.parse(params) as Array<any> | ErrorShape;
131
+
132
+ const hasActiveTextEditor = Boolean(window.activeTextEditor);
133
+ if (Array.isArray(response)) {
134
+ const errors = response.filter((item) => isError(item));
135
+ if (errors.length) {
136
+ errors.forEach((response) => {
122
137
  statusBar.showWarningState({
123
138
  hasActiveTextEditor,
124
139
  tooltip: "Configuration Error",
125
140
  });
126
- outputChannel.append(response.stack);
141
+ outputChannel.appendLine("---\n" + response.stack + "\n---");
127
142
 
128
143
  const infoButtonText = "More Info";
129
144
  window
@@ -133,192 +148,203 @@ export function activate(context: ExtensionContext) {
133
148
  outputChannel.show();
134
149
  }
135
150
  });
136
- } else if (Array.isArray(response)) {
137
- if (response.length === 0) {
138
- statusBar.showWarningState({
139
- hasActiveTextEditor,
140
- tooltip: "No apollo.config.js file found",
141
- });
142
- } else {
143
- statusBar.showLoadedState({ hasActiveTextEditor });
144
- }
145
- } else {
146
- Debug.error(
147
- `Invalid response type in message apollographql/configFilesFound:\n${JSON.stringify(
148
- response
149
- )}`
150
- );
151
- }
151
+ });
152
+ } else if (response.length === 0) {
153
+ statusBar.showWarningState({
154
+ hasActiveTextEditor,
155
+ tooltip: "No apollo.config.js file found",
156
+ });
157
+ } else {
158
+ statusBar.showLoadedState({ hasActiveTextEditor });
152
159
  }
153
- );
154
-
155
- commands.registerCommand("apollographql/reloadService", () => {
156
- // wipe out tags when reloading
157
- // XXX we should clean up this handling
158
- schemaTagItems = [];
159
- client.sendNotification("apollographql/reloadService");
160
- });
160
+ } else {
161
+ Debug.error(
162
+ `Invalid response type in message apollographql/configFilesFound:\n${JSON.stringify(
163
+ response,
164
+ )}`,
165
+ );
166
+ }
167
+ });
161
168
 
162
- // For some reason, non-strings can only be sent in one direction. For now, messages
163
- // coming from the language server just need to be stringified and parsed.
164
- client.onNotification("apollographql/tagsLoaded", (params) => {
165
- const [serviceID, tags]: [string, string[]] = JSON.parse(params);
166
- const items = tags.map((tag) => ({
167
- label: tag,
168
- description: "",
169
- detail: serviceID,
170
- }));
171
-
172
- schemaTagItems = [...items, ...schemaTagItems];
173
- });
169
+ commands.registerCommand("apollographql/reloadService", () => {
170
+ // wipe out tags when reloading
171
+ // XXX we should clean up this handling
172
+ schemaTagItems = [];
173
+ client.sendNotification(LSCommands.ReloadService);
174
+ });
174
175
 
175
- commands.registerCommand("apollographql/selectSchemaTag", async () => {
176
- const selection = await window.showQuickPick(schemaTagItems);
177
- if (selection) {
178
- client.sendNotification("apollographql/tagSelected", selection);
179
- }
180
- });
176
+ // For some reason, non-strings can only be sent in one direction. For now, messages
177
+ // coming from the language server just need to be stringified and parsed.
178
+ client.onNotification(LSNotifications.TagsLoaded, (params) => {
179
+ const [serviceID, tags]: [string, string[]] = JSON.parse(params);
180
+ const items = tags.map((tag) => ({
181
+ label: tag,
182
+ description: "",
183
+ detail: serviceID,
184
+ }));
185
+
186
+ schemaTagItems = [...items, ...schemaTagItems];
187
+ });
181
188
 
182
- let currentLoadingResolve: Map<number, () => void> = new Map();
189
+ commands.registerCommand("apollographql/selectSchemaTag", async () => {
190
+ const selection = await window.showQuickPick(schemaTagItems);
191
+ if (selection) {
192
+ client.sendNotification(LSCommands.TagSelected, selection);
193
+ }
194
+ });
183
195
 
184
- client.onNotification("apollographql/loadingComplete", (token) => {
185
- statusBar.showLoadedState({
186
- hasActiveTextEditor: Boolean(window.activeTextEditor),
187
- });
188
- const inMap = currentLoadingResolve.get(token);
189
- if (inMap) {
190
- inMap();
191
- currentLoadingResolve.delete(token);
192
- }
193
- });
196
+ let currentLoadingResolve: Map<number, () => void> = new Map();
194
197
 
195
- client.onNotification("apollographql/loading", ({ message, token }) => {
196
- window.withProgress(
197
- {
198
- location: ProgressLocation.Notification,
199
- title: message,
200
- cancellable: false,
201
- },
202
- () => {
203
- return new Promise<void>((resolve) => {
204
- currentLoadingResolve.set(token, resolve);
205
- });
206
- }
207
- );
198
+ client.onNotification(LSNotifications.LoadingComplete, (token) => {
199
+ statusBar.showLoadedState({
200
+ hasActiveTextEditor: Boolean(window.activeTextEditor),
208
201
  });
202
+ const inMap = currentLoadingResolve.get(token);
203
+ if (inMap) {
204
+ inMap();
205
+ currentLoadingResolve.delete(token);
206
+ }
207
+ });
209
208
 
210
- const runIconOnDiskPath = Uri.file(
211
- join(context.extensionPath, "images", "IconRun.svg")
209
+ client.onNotification(LSNotifications.Loading, ({ message, token }) => {
210
+ window.withProgress(
211
+ {
212
+ location: ProgressLocation.Notification,
213
+ title: message,
214
+ cancellable: false,
215
+ },
216
+ () => {
217
+ return new Promise<void>((resolve) => {
218
+ currentLoadingResolve.set(token, resolve);
219
+ });
220
+ },
212
221
  );
222
+ });
213
223
 
214
- const textDecorationType = window.createTextEditorDecorationType({});
215
- const runGlyphDecorationType = window.createTextEditorDecorationType({});
216
- let latestDecorations: EngineDecoration[] | undefined = undefined;
224
+ const runIconOnDiskPath = Uri.file(
225
+ join(context.extensionPath, "images", "IconRun.svg"),
226
+ );
217
227
 
218
- const updateDecorations = () => {
219
- if (window.activeTextEditor && latestDecorations) {
220
- const editor = window.activeTextEditor!;
228
+ const textDecorationType = window.createTextEditorDecorationType({});
229
+ const runGlyphDecorationType = window.createTextEditorDecorationType({});
230
+ let latestDecorations: EngineDecoration[] | undefined = undefined;
221
231
 
222
- const decorationsForDocument = latestDecorations.filter(
223
- (decoration) =>
224
- decoration.document ===
225
- window.activeTextEditor!.document.uri.toString()
226
- );
232
+ const updateDecorations = () => {
233
+ if (window.activeTextEditor && latestDecorations) {
234
+ const editor = window.activeTextEditor!;
227
235
 
228
- const textDecorations = decorationsForDocument.flatMap(
229
- (decoration): DecorationOptions | DecorationOptions[] => {
230
- if (decoration.type !== "text") {
231
- return [];
232
- }
233
-
234
- return {
235
- range: editor.document.lineAt(decoration.range.start.line).range,
236
- renderOptions: {
237
- after: {
238
- contentText: decoration.message,
239
- textDecoration: "none; padding-left: 15px; opacity: .5",
240
- },
241
- },
242
- };
236
+ const decorationsForDocument = latestDecorations.filter(
237
+ (decoration) =>
238
+ decoration.document ===
239
+ window.activeTextEditor!.document.uri.toString(),
240
+ );
241
+
242
+ const textDecorations = decorationsForDocument.flatMap(
243
+ (decoration): DecorationOptions | DecorationOptions[] => {
244
+ if (decoration.type !== "text") {
245
+ return [];
243
246
  }
244
- );
245
247
 
246
- const runGlyphDecorations = decorationsForDocument.flatMap(
247
- (decoration): DecorationOptions | DecorationOptions[] => {
248
- if (decoration.type !== "runGlyph") {
249
- return [];
250
- }
251
-
252
- const hoverMessage =
253
- decoration.hoverMessage === undefined
254
- ? undefined
255
- : new MarkdownString(decoration.hoverMessage);
256
- if (hoverMessage) {
257
- hoverMessage.isTrusted = true;
258
- }
259
-
260
- const endOfLinePosition = editor.document.lineAt(
261
- decoration.range.start.line
262
- ).range.end;
263
- return {
264
- // Hover range of just the end of the line (and the icon) so the hover shows above the icon,
265
- // not over at the start of the line
266
- range: new Range(endOfLinePosition, endOfLinePosition),
267
- renderOptions: {
268
- after: {
269
- contentIconPath: runIconOnDiskPath,
270
- textDecoration:
271
- "none; border-radius: .20rem; margin-left: 8px; text-align: center;",
272
- backgroundColor: "#2075D6",
273
- width: "18px",
274
- height: "18px",
275
- },
248
+ return {
249
+ range: editor.document.lineAt(decoration.range.start.line).range,
250
+ renderOptions: {
251
+ after: {
252
+ contentText: decoration.message,
253
+ textDecoration: "none; padding-left: 15px; opacity: .5",
276
254
  },
277
- hoverMessage,
278
- };
255
+ },
256
+ };
257
+ },
258
+ );
259
+
260
+ const runGlyphDecorations = decorationsForDocument.flatMap(
261
+ (decoration): DecorationOptions | DecorationOptions[] => {
262
+ if (decoration.type !== "runGlyph") {
263
+ return [];
279
264
  }
280
- );
281
265
 
266
+ const hoverMessage =
267
+ decoration.hoverMessage === undefined
268
+ ? undefined
269
+ : new MarkdownString(decoration.hoverMessage);
270
+ if (hoverMessage) {
271
+ hoverMessage.isTrusted = true;
272
+ }
273
+
274
+ const endOfLinePosition = editor.document.lineAt(
275
+ decoration.range.start.line,
276
+ ).range.end;
277
+ return {
278
+ // Hover range of just the end of the line (and the icon) so the hover shows above the icon,
279
+ // not over at the start of the line
280
+ range: new Range(endOfLinePosition, endOfLinePosition),
281
+ renderOptions: {
282
+ after: {
283
+ contentIconPath: runIconOnDiskPath,
284
+ textDecoration:
285
+ "none; border-radius: .20rem; margin-left: 8px; text-align: center;",
286
+ backgroundColor: "#2075D6",
287
+ width: "18px",
288
+ height: "18px",
289
+ },
290
+ },
291
+ hoverMessage,
292
+ };
293
+ },
294
+ );
295
+
296
+ window.activeTextEditor!.setDecorations(
297
+ textDecorationType,
298
+ textDecorations,
299
+ );
300
+ if (
301
+ workspace
302
+ .getConfiguration("apollographql")
303
+ .get("display.showRunInStudioButton")
304
+ ) {
282
305
  window.activeTextEditor!.setDecorations(
283
- textDecorationType,
284
- textDecorations
306
+ runGlyphDecorationType,
307
+ runGlyphDecorations,
285
308
  );
286
- if (
287
- workspace
288
- .getConfiguration("apollographql")
289
- .get("display.showRunInStudioButton")
290
- ) {
291
- window.activeTextEditor!.setDecorations(
292
- runGlyphDecorationType,
293
- runGlyphDecorations
294
- );
295
- }
296
309
  }
297
- };
310
+ }
311
+ };
298
312
 
299
- client.onNotification(
300
- "apollographql/engineDecorations",
301
- ({ decorations }) => {
302
- latestDecorations = decorations;
303
- updateDecorations();
304
- }
305
- );
306
-
307
- window.onDidChangeActiveTextEditor(() => {
313
+ client.onNotification(
314
+ LSNotifications.EngineDecorations,
315
+ ({ decorations }) => {
316
+ latestDecorations = decorations;
308
317
  updateDecorations();
309
- });
318
+ },
319
+ );
310
320
 
311
- workspace.registerTextDocumentContentProvider("graphql-schema", {
312
- provideTextDocumentContent(uri: Uri) {
313
- // the schema source is provided inside the URI, just return that here
314
- return uri.query;
315
- },
316
- });
321
+ window.onDidChangeActiveTextEditor(() => {
322
+ updateDecorations();
323
+ });
324
+
325
+ workspace.registerTextDocumentContentProvider("graphql-schema", {
326
+ provideTextDocumentContent(uri: Uri) {
327
+ // the schema source is provided inside the URI, just return that here
328
+ return uri.query;
329
+ },
317
330
  });
331
+
332
+ await client.start();
333
+ return {
334
+ outputChannel,
335
+ client,
336
+ LanguageServerCommands: LSCommands,
337
+ LanguageServerNotifications: LSNotifications,
338
+ LanguageServerRequests: LSRequests,
339
+ };
318
340
  }
319
341
 
320
342
  export function deactivate(): Thenable<void> | void {
321
- if (client) {
322
- return client.stop();
343
+ if (globalClient) {
344
+ try {
345
+ return globalClient.stop();
346
+ } finally {
347
+ globalClient = null;
348
+ }
323
349
  }
324
350
  }