vscode-apollo 1.19.3 → 1.20.0
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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.circleci/config.yml +82 -0
- package/.eslintrc.js +10 -0
- package/.gitattributes +1 -0
- package/.github/workflows/release.yml +95 -0
- package/.gitleaks.toml +26 -0
- package/.nvmrc +1 -0
- package/.prettierrc +5 -0
- package/.vscode/launch.json +61 -0
- package/.vscode/settings.json +16 -0
- package/.vscode/tasks.json +18 -0
- package/.vscodeignore +17 -1
- package/CHANGELOG.md +172 -1
- package/LICENSE +2 -2
- package/README.md +9 -9
- package/codegen.yml +12 -0
- package/images/IconRun.svg +8 -0
- package/jest.config.ts +11 -0
- package/package.json +102 -22
- package/renovate.json +23 -0
- package/src/__mocks__/fs.js +3 -0
- package/src/__tests__/statusBar.test.ts +8 -7
- package/src/debug.ts +2 -5
- package/src/env/fetch/fetch.ts +32 -0
- package/src/env/fetch/global.ts +30 -0
- package/src/env/fetch/index.d.ts +2 -0
- package/src/env/fetch/index.ts +2 -0
- package/src/env/fetch/url.ts +9 -0
- package/src/env/index.ts +4 -0
- package/src/env/polyfills/array.ts +17 -0
- package/src/env/polyfills/index.ts +2 -0
- package/src/env/polyfills/object.ts +7 -0
- package/src/env/typescript-utility-types.ts +2 -0
- package/src/extension.ts +106 -37
- package/src/language-server/__tests__/diagnostics.test.ts +86 -0
- package/src/language-server/__tests__/document.test.ts +187 -0
- package/src/language-server/__tests__/fileSet.test.ts +46 -0
- package/src/language-server/__tests__/fixtures/starwarsSchema.ts +1917 -0
- package/src/language-server/config/__tests__/config.ts +128 -0
- package/src/language-server/config/__tests__/loadConfig.ts +508 -0
- package/src/language-server/config/__tests__/utils.ts +106 -0
- package/src/language-server/config/config.ts +219 -0
- package/src/language-server/config/index.ts +3 -0
- package/src/language-server/config/loadConfig.ts +228 -0
- package/src/language-server/config/utils.ts +56 -0
- package/src/language-server/diagnostics.ts +109 -0
- package/src/language-server/document.ts +277 -0
- package/src/language-server/engine/GraphQLDataSource.ts +124 -0
- package/src/language-server/engine/index.ts +105 -0
- package/src/language-server/engine/operations/frontendUrlRoot.ts +7 -0
- package/src/language-server/engine/operations/schemaTagsAndFieldStats.ts +24 -0
- package/src/language-server/errors/__tests__/NoMissingClientDirectives.test.ts +220 -0
- package/src/language-server/errors/logger.ts +58 -0
- package/src/language-server/errors/validation.ts +277 -0
- package/src/language-server/fileSet.ts +65 -0
- package/src/language-server/format.ts +48 -0
- package/src/language-server/graphqlTypes.ts +7176 -0
- package/src/language-server/index.ts +29 -0
- package/src/language-server/languageProvider.ts +798 -0
- package/src/language-server/loadingHandler.ts +64 -0
- package/src/language-server/project/base.ts +399 -0
- package/src/language-server/project/client.ts +602 -0
- package/src/language-server/project/defaultClientSchema.ts +45 -0
- package/src/language-server/project/service.ts +48 -0
- package/src/language-server/providers/schema/__tests__/file.ts +150 -0
- package/src/language-server/providers/schema/base.ts +15 -0
- package/src/language-server/providers/schema/endpoint.ts +157 -0
- package/src/language-server/providers/schema/engine.ts +197 -0
- package/src/language-server/providers/schema/file.ts +167 -0
- package/src/language-server/providers/schema/index.ts +75 -0
- package/src/language-server/server.ts +252 -0
- package/src/language-server/typings/codemirror.d.ts +4 -0
- package/src/language-server/typings/graphql.d.ts +27 -0
- package/src/language-server/utilities/__tests__/graphql.test.ts +411 -0
- package/src/language-server/utilities/__tests__/uri.ts +55 -0
- package/src/language-server/utilities/debouncer.ts +8 -0
- package/src/language-server/utilities/debug.ts +89 -0
- package/src/language-server/utilities/graphql.ts +432 -0
- package/src/language-server/utilities/index.ts +3 -0
- package/src/language-server/utilities/source.ts +182 -0
- package/src/language-server/utilities/uri.ts +19 -0
- package/src/language-server/workspace.ts +262 -0
- package/src/languageServerClient.ts +19 -12
- package/src/messages.ts +84 -0
- package/src/statusBar.ts +5 -5
- package/src/tools/__tests__/buildServiceDefinition.test.ts +491 -0
- package/src/tools/__tests__/snapshotSerializers/astSerializer.ts +19 -0
- package/src/tools/__tests__/snapshotSerializers/graphQLTypeSerializer.ts +14 -0
- package/src/tools/buildServiceDefinition.ts +241 -0
- package/src/tools/index.ts +6 -0
- package/src/tools/schema/index.ts +2 -0
- package/src/tools/schema/resolveObject.ts +18 -0
- package/src/tools/schema/resolverMap.ts +23 -0
- package/src/tools/utilities/graphql.ts +22 -0
- package/src/tools/utilities/index.ts +3 -0
- package/src/tools/utilities/invariant.ts +5 -0
- package/src/tools/utilities/predicates.ts +5 -0
- package/src/utils.ts +1 -16
- package/syntaxes/graphql.js.json +3 -3
- package/syntaxes/graphql.json +13 -9
- package/syntaxes/graphql.lua.json +51 -0
- package/syntaxes/graphql.rb.json +1 -1
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +20 -7
- package/create-server-symlink.js +0 -8
- package/lib/debug.d.ts +0 -11
- package/lib/debug.d.ts.map +0 -1
- package/lib/debug.js +0 -48
- package/lib/debug.js.map +0 -1
- package/lib/extension.d.ts +0 -4
- package/lib/extension.d.ts.map +0 -1
- package/lib/extension.js +0 -187
- package/lib/extension.js.map +0 -1
- package/lib/languageServerClient.d.ts +0 -4
- package/lib/languageServerClient.d.ts.map +0 -1
- package/lib/languageServerClient.js +0 -57
- package/lib/languageServerClient.js.map +0 -1
- package/lib/statusBar.d.ts +0 -24
- package/lib/statusBar.d.ts.map +0 -1
- package/lib/statusBar.js +0 -46
- package/lib/statusBar.js.map +0 -1
- package/lib/testRunner/index.d.ts +0 -3
- package/lib/testRunner/index.d.ts.map +0 -1
- package/lib/testRunner/index.js +0 -49
- package/lib/testRunner/index.js.map +0 -1
- package/lib/testRunner/jest-config.d.ts +0 -14
- package/lib/testRunner/jest-config.d.ts.map +0 -1
- package/lib/testRunner/jest-config.js +0 -18
- package/lib/testRunner/jest-config.js.map +0 -1
- package/lib/testRunner/jest-vscode-environment.d.ts +0 -2
- package/lib/testRunner/jest-vscode-environment.d.ts.map +0 -1
- package/lib/testRunner/jest-vscode-environment.js +0 -19
- package/lib/testRunner/jest-vscode-environment.js.map +0 -1
- package/lib/testRunner/jest-vscode-framework-setup.d.ts +0 -1
- package/lib/testRunner/jest-vscode-framework-setup.d.ts.map +0 -1
- package/lib/testRunner/jest-vscode-framework-setup.js +0 -3
- package/lib/testRunner/jest-vscode-framework-setup.js.map +0 -1
- package/lib/testRunner/vscode-test-script.d.ts +0 -2
- package/lib/testRunner/vscode-test-script.d.ts.map +0 -1
- package/lib/testRunner/vscode-test-script.js +0 -23
- package/lib/testRunner/vscode-test-script.js.map +0 -1
- package/lib/utils.d.ts +0 -18
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js +0 -52
- package/lib/utils.js.map +0 -1
- package/src/testRunner/README.md +0 -23
- package/src/testRunner/index.ts +0 -72
- package/src/testRunner/jest-config.ts +0 -17
- package/src/testRunner/jest-vscode-environment.ts +0 -25
- package/src/testRunner/jest-vscode-framework-setup.ts +0 -10
- package/src/testRunner/jest.d.ts +0 -37
- package/src/testRunner/vscode-test-script.ts +0 -38
- package/tsconfig.test.json +0 -4
- package/tsconfig.tsbuildinfo +0 -2486
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { IConnection, NotificationType } from "vscode-languageserver";
|
|
2
|
+
|
|
3
|
+
// XXX I think we want to combine this into an interface
|
|
4
|
+
// with the errors tooling as well
|
|
5
|
+
|
|
6
|
+
export interface LoadingHandler {
|
|
7
|
+
handle<T>(message: string, value: Promise<T>): Promise<T>;
|
|
8
|
+
handleSync<T>(message: string, value: () => T): T;
|
|
9
|
+
showError(message: string): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class LanguageServerLoadingHandler implements LoadingHandler {
|
|
13
|
+
constructor(private connection: IConnection) {}
|
|
14
|
+
private latestLoadingToken = 0;
|
|
15
|
+
async handle<T>(message: string, value: Promise<T>): Promise<T> {
|
|
16
|
+
const token = this.latestLoadingToken;
|
|
17
|
+
this.latestLoadingToken += 1;
|
|
18
|
+
this.connection.sendNotification(
|
|
19
|
+
new NotificationType<any, void>("apollographql/loading"),
|
|
20
|
+
{ message, token }
|
|
21
|
+
);
|
|
22
|
+
try {
|
|
23
|
+
const ret = await value;
|
|
24
|
+
this.connection.sendNotification(
|
|
25
|
+
new NotificationType<any, void>("apollographql/loadingComplete"),
|
|
26
|
+
token
|
|
27
|
+
);
|
|
28
|
+
return ret;
|
|
29
|
+
} catch (e) {
|
|
30
|
+
this.connection.sendNotification(
|
|
31
|
+
new NotificationType<any, void>("apollographql/loadingComplete"),
|
|
32
|
+
token
|
|
33
|
+
);
|
|
34
|
+
this.showError(`Error in "${message}": ${e}`);
|
|
35
|
+
throw e;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
handleSync<T>(message: string, value: () => T): T {
|
|
39
|
+
const token = this.latestLoadingToken;
|
|
40
|
+
this.latestLoadingToken += 1;
|
|
41
|
+
this.connection.sendNotification(
|
|
42
|
+
new NotificationType<any, void>("apollographql/loading"),
|
|
43
|
+
{ message, token }
|
|
44
|
+
);
|
|
45
|
+
try {
|
|
46
|
+
const ret = value();
|
|
47
|
+
this.connection.sendNotification(
|
|
48
|
+
new NotificationType<any, void>("apollographql/loadingComplete"),
|
|
49
|
+
token
|
|
50
|
+
);
|
|
51
|
+
return ret;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
this.connection.sendNotification(
|
|
54
|
+
new NotificationType<any, void>("apollographql/loadingComplete"),
|
|
55
|
+
token
|
|
56
|
+
);
|
|
57
|
+
this.showError(`Error in "${message}": ${e}`);
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
showError(message: string) {
|
|
62
|
+
this.connection.window.showErrorMessage(message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import path, { extname } from "path";
|
|
2
|
+
import { lstatSync, readFileSync } from "fs";
|
|
3
|
+
import URI from "vscode-uri";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
TypeSystemDefinitionNode,
|
|
7
|
+
isTypeSystemDefinitionNode,
|
|
8
|
+
TypeSystemExtensionNode,
|
|
9
|
+
isTypeSystemExtensionNode,
|
|
10
|
+
DefinitionNode,
|
|
11
|
+
GraphQLSchema,
|
|
12
|
+
Kind,
|
|
13
|
+
} from "graphql";
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
TextDocument,
|
|
17
|
+
NotificationHandler,
|
|
18
|
+
PublishDiagnosticsParams,
|
|
19
|
+
Position,
|
|
20
|
+
} from "vscode-languageserver";
|
|
21
|
+
|
|
22
|
+
import { GraphQLDocument, extractGraphQLDocuments } from "../document";
|
|
23
|
+
|
|
24
|
+
import type { LoadingHandler } from "../loadingHandler";
|
|
25
|
+
import { FileSet } from "../fileSet";
|
|
26
|
+
import {
|
|
27
|
+
ApolloConfig,
|
|
28
|
+
ClientConfig,
|
|
29
|
+
isClientConfig,
|
|
30
|
+
isLocalServiceConfig,
|
|
31
|
+
isServiceConfig,
|
|
32
|
+
keyEnvVar,
|
|
33
|
+
ServiceConfig,
|
|
34
|
+
} from "../config";
|
|
35
|
+
import {
|
|
36
|
+
schemaProviderFromConfig,
|
|
37
|
+
GraphQLSchemaProvider,
|
|
38
|
+
SchemaResolveConfig,
|
|
39
|
+
} from "../providers/schema";
|
|
40
|
+
import { ApolloEngineClient, ClientIdentity } from "../engine";
|
|
41
|
+
import type { ProjectStats } from "src/messages";
|
|
42
|
+
|
|
43
|
+
export type DocumentUri = string;
|
|
44
|
+
|
|
45
|
+
const fileAssociations: { [extension: string]: string } = {
|
|
46
|
+
".graphql": "graphql",
|
|
47
|
+
".gql": "graphql",
|
|
48
|
+
".js": "javascript",
|
|
49
|
+
".ts": "typescript",
|
|
50
|
+
".jsx": "javascriptreact",
|
|
51
|
+
".tsx": "typescriptreact",
|
|
52
|
+
".vue": "vue",
|
|
53
|
+
".svelte": "svelte",
|
|
54
|
+
".py": "python",
|
|
55
|
+
".rb": "ruby",
|
|
56
|
+
".dart": "dart",
|
|
57
|
+
".re": "reason",
|
|
58
|
+
".ex": "elixir",
|
|
59
|
+
".exs": "elixir",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
interface GraphQLProjectConfig {
|
|
63
|
+
clientIdentity?: ClientIdentity;
|
|
64
|
+
config: ClientConfig | ServiceConfig;
|
|
65
|
+
configFolderURI: URI;
|
|
66
|
+
loadingHandler: LoadingHandler;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export abstract class GraphQLProject implements GraphQLSchemaProvider {
|
|
70
|
+
public schemaProvider: GraphQLSchemaProvider;
|
|
71
|
+
protected _onDiagnostics?: NotificationHandler<PublishDiagnosticsParams>;
|
|
72
|
+
|
|
73
|
+
private _isReady: boolean;
|
|
74
|
+
private readyPromise: Promise<void>;
|
|
75
|
+
protected engineClient?: ApolloEngineClient;
|
|
76
|
+
|
|
77
|
+
private needsValidation = false;
|
|
78
|
+
|
|
79
|
+
protected documentsByFile: Map<DocumentUri, GraphQLDocument[]> = new Map();
|
|
80
|
+
|
|
81
|
+
public config: ApolloConfig;
|
|
82
|
+
public schema?: GraphQLSchema;
|
|
83
|
+
private fileSet: FileSet;
|
|
84
|
+
private rootURI: URI;
|
|
85
|
+
protected loadingHandler: LoadingHandler;
|
|
86
|
+
|
|
87
|
+
protected lastLoadDate?: number;
|
|
88
|
+
|
|
89
|
+
constructor({
|
|
90
|
+
config,
|
|
91
|
+
configFolderURI,
|
|
92
|
+
loadingHandler,
|
|
93
|
+
clientIdentity,
|
|
94
|
+
}: GraphQLProjectConfig) {
|
|
95
|
+
this.config = config;
|
|
96
|
+
this.loadingHandler = loadingHandler;
|
|
97
|
+
// the URI of the folder _containing_ the apollo.config.js is the true project's root.
|
|
98
|
+
// if a config doesn't have a uri associated, we can assume the `rootURI` is the project's root.
|
|
99
|
+
this.rootURI = config.configDirURI || configFolderURI;
|
|
100
|
+
|
|
101
|
+
const { includes, excludes } = config.isClient
|
|
102
|
+
? config.client
|
|
103
|
+
: config.service;
|
|
104
|
+
const fileSet = new FileSet({
|
|
105
|
+
rootURI: this.rootURI,
|
|
106
|
+
includes: [...includes, ".env", "apollo.config.js", "apollo.config.cjs"],
|
|
107
|
+
// We do not want to include the local schema file in our list of documents
|
|
108
|
+
excludes: [...excludes, ...this.getRelativeLocalSchemaFilePaths()],
|
|
109
|
+
configURI: config.configURI,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
this.fileSet = fileSet;
|
|
113
|
+
this.schemaProvider = schemaProviderFromConfig(config, clientIdentity);
|
|
114
|
+
const { engine } = config;
|
|
115
|
+
if (engine.apiKey) {
|
|
116
|
+
this.engineClient = new ApolloEngineClient(
|
|
117
|
+
engine.apiKey!,
|
|
118
|
+
engine.endpoint,
|
|
119
|
+
clientIdentity
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this._isReady = false;
|
|
124
|
+
// FIXME: Instead of `Promise.all`, we should catch individual promise rejections
|
|
125
|
+
// so we can show multiple errors.
|
|
126
|
+
this.readyPromise = Promise.all(this.initialize())
|
|
127
|
+
.then(() => {
|
|
128
|
+
this._isReady = true;
|
|
129
|
+
})
|
|
130
|
+
.catch((error) => {
|
|
131
|
+
console.error(error);
|
|
132
|
+
this.loadingHandler.showError(
|
|
133
|
+
`Error initializing Apollo GraphQL project "${this.displayName}": ${error}`
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
abstract get displayName(): string;
|
|
139
|
+
|
|
140
|
+
protected abstract initialize(): Promise<void>[];
|
|
141
|
+
|
|
142
|
+
abstract getProjectStats(): ProjectStats;
|
|
143
|
+
|
|
144
|
+
get isReady(): boolean {
|
|
145
|
+
return this._isReady;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
get engine(): ApolloEngineClient {
|
|
149
|
+
// handle error states for missing engine config
|
|
150
|
+
// all in the same place :tada:
|
|
151
|
+
if (!this.engineClient) {
|
|
152
|
+
throw new Error(`Unable to find ${keyEnvVar}`);
|
|
153
|
+
}
|
|
154
|
+
return this.engineClient!;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
get whenReady(): Promise<void> {
|
|
158
|
+
return this.readyPromise;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public updateConfig(config: ApolloConfig) {
|
|
162
|
+
this.config = config;
|
|
163
|
+
return this.initialize();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public resolveSchema(config: SchemaResolveConfig): Promise<GraphQLSchema> {
|
|
167
|
+
this.lastLoadDate = +new Date();
|
|
168
|
+
return this.schemaProvider.resolveSchema(config);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public resolveFederatedServiceSDL() {
|
|
172
|
+
return this.schemaProvider.resolveFederatedServiceSDL();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public onSchemaChange(handler: NotificationHandler<GraphQLSchema>) {
|
|
176
|
+
this.lastLoadDate = +new Date();
|
|
177
|
+
return this.schemaProvider.onSchemaChange(handler);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onDiagnostics(handler: NotificationHandler<PublishDiagnosticsParams>) {
|
|
181
|
+
this._onDiagnostics = handler;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
includesFile(uri: DocumentUri) {
|
|
185
|
+
return this.fileSet.includesFile(uri);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
allIncludedFiles() {
|
|
189
|
+
return this.fileSet.allFiles();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async scanAllIncludedFiles() {
|
|
193
|
+
await this.loadingHandler.handle(
|
|
194
|
+
`Loading queries for ${this.displayName}`,
|
|
195
|
+
(async () => {
|
|
196
|
+
for (const filePath of this.allIncludedFiles()) {
|
|
197
|
+
const uri = URI.file(filePath).toString();
|
|
198
|
+
|
|
199
|
+
// If we already have query documents for this file, that means it was either
|
|
200
|
+
// opened or changed before we got a chance to read it.
|
|
201
|
+
if (this.documentsByFile.has(uri)) continue;
|
|
202
|
+
|
|
203
|
+
this.fileDidChange(uri);
|
|
204
|
+
}
|
|
205
|
+
})()
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fileDidChange(uri: DocumentUri) {
|
|
210
|
+
const filePath = URI.parse(uri).fsPath;
|
|
211
|
+
const extension = extname(filePath);
|
|
212
|
+
const languageId = fileAssociations[extension];
|
|
213
|
+
|
|
214
|
+
// Don't process files of an unsupported filetype
|
|
215
|
+
if (!languageId) return;
|
|
216
|
+
|
|
217
|
+
// Don't process directories. Directories might be named like files so
|
|
218
|
+
// we have to explicitly check.
|
|
219
|
+
if (!lstatSync(filePath).isFile()) return;
|
|
220
|
+
|
|
221
|
+
const contents = readFileSync(filePath, "utf8");
|
|
222
|
+
const document = TextDocument.create(uri, languageId, -1, contents);
|
|
223
|
+
this.documentDidChange(document);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
fileWasDeleted(uri: DocumentUri) {
|
|
227
|
+
this.removeGraphQLDocumentsFor(uri);
|
|
228
|
+
this.checkForDuplicateOperations();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
documentDidChange(document: TextDocument) {
|
|
232
|
+
const documents = extractGraphQLDocuments(
|
|
233
|
+
document,
|
|
234
|
+
this.config.client && this.config.client.tagName
|
|
235
|
+
);
|
|
236
|
+
if (documents) {
|
|
237
|
+
this.documentsByFile.set(document.uri, documents);
|
|
238
|
+
this.invalidate();
|
|
239
|
+
} else {
|
|
240
|
+
this.removeGraphQLDocumentsFor(document.uri);
|
|
241
|
+
}
|
|
242
|
+
this.checkForDuplicateOperations();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
checkForDuplicateOperations(): void {
|
|
246
|
+
const filePathForOperationName: Record<string, string> = {};
|
|
247
|
+
for (const [fileUri, documentsForFile] of this.documentsByFile.entries()) {
|
|
248
|
+
const filePath = URI.parse(fileUri).fsPath;
|
|
249
|
+
for (const document of documentsForFile) {
|
|
250
|
+
if (!document.ast) continue;
|
|
251
|
+
for (const definition of document.ast.definitions) {
|
|
252
|
+
if (
|
|
253
|
+
definition.kind === Kind.OPERATION_DEFINITION &&
|
|
254
|
+
definition.name
|
|
255
|
+
) {
|
|
256
|
+
const operationName = definition.name.value;
|
|
257
|
+
if (operationName in filePathForOperationName) {
|
|
258
|
+
const conflictingFilePath =
|
|
259
|
+
filePathForOperationName[operationName];
|
|
260
|
+
throw new Error(
|
|
261
|
+
`️️There are multiple definitions for the \`${definition.name.value}\` operation. Please fix all naming conflicts before continuing.\nConflicting definitions found at ${filePath} and ${conflictingFilePath}.`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
filePathForOperationName[operationName] = filePath;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private removeGraphQLDocumentsFor(uri: DocumentUri) {
|
|
272
|
+
if (this.documentsByFile.has(uri)) {
|
|
273
|
+
this.documentsByFile.delete(uri);
|
|
274
|
+
|
|
275
|
+
if (this._onDiagnostics) {
|
|
276
|
+
this._onDiagnostics({ uri: uri, diagnostics: [] });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
this.invalidate();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
protected invalidate() {
|
|
284
|
+
if (!this.needsValidation && this.isReady) {
|
|
285
|
+
setTimeout(() => {
|
|
286
|
+
this.validateIfNeeded();
|
|
287
|
+
}, 0);
|
|
288
|
+
this.needsValidation = true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private validateIfNeeded() {
|
|
293
|
+
if (!this.needsValidation || !this.isReady) return;
|
|
294
|
+
|
|
295
|
+
this.validate();
|
|
296
|
+
|
|
297
|
+
this.needsValidation = false;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private getRelativeLocalSchemaFilePaths(): string[] {
|
|
301
|
+
const serviceConfig = isServiceConfig(this.config)
|
|
302
|
+
? this.config.service
|
|
303
|
+
: isClientConfig(this.config) &&
|
|
304
|
+
typeof this.config.client.service === "object" &&
|
|
305
|
+
isLocalServiceConfig(this.config.client.service)
|
|
306
|
+
? this.config.client.service
|
|
307
|
+
: undefined;
|
|
308
|
+
const localSchemaFile = serviceConfig?.localSchemaFile;
|
|
309
|
+
return (
|
|
310
|
+
localSchemaFile === undefined
|
|
311
|
+
? []
|
|
312
|
+
: Array.isArray(localSchemaFile)
|
|
313
|
+
? localSchemaFile
|
|
314
|
+
: [localSchemaFile]
|
|
315
|
+
).map((filePath) =>
|
|
316
|
+
path.relative(this.rootURI.fsPath, path.join(process.cwd(), filePath))
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
abstract validate(): void;
|
|
321
|
+
|
|
322
|
+
clearAllDiagnostics() {
|
|
323
|
+
if (!this._onDiagnostics) return;
|
|
324
|
+
|
|
325
|
+
for (const uri of this.documentsByFile.keys()) {
|
|
326
|
+
this._onDiagnostics({ uri, diagnostics: [] });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
documentsAt(uri: DocumentUri): GraphQLDocument[] | undefined {
|
|
331
|
+
return this.documentsByFile.get(uri);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
documentAt(
|
|
335
|
+
uri: DocumentUri,
|
|
336
|
+
position: Position
|
|
337
|
+
): GraphQLDocument | undefined {
|
|
338
|
+
const queryDocuments = this.documentsByFile.get(uri);
|
|
339
|
+
if (!queryDocuments) return undefined;
|
|
340
|
+
|
|
341
|
+
return queryDocuments.find((document) =>
|
|
342
|
+
document.containsPosition(position)
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
get documents(): GraphQLDocument[] {
|
|
347
|
+
const documents: GraphQLDocument[] = [];
|
|
348
|
+
for (const documentsForFile of this.documentsByFile.values()) {
|
|
349
|
+
documents.push(...documentsForFile);
|
|
350
|
+
}
|
|
351
|
+
return documents;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
get definitions(): DefinitionNode[] {
|
|
355
|
+
const definitions = [];
|
|
356
|
+
|
|
357
|
+
for (const document of this.documents) {
|
|
358
|
+
if (!document.ast) continue;
|
|
359
|
+
|
|
360
|
+
definitions.push(...document.ast.definitions);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return definitions;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
definitionsAt(uri: DocumentUri): DefinitionNode[] {
|
|
367
|
+
const documents = this.documentsAt(uri);
|
|
368
|
+
if (!documents) return [];
|
|
369
|
+
|
|
370
|
+
const definitions = [];
|
|
371
|
+
|
|
372
|
+
for (const document of documents) {
|
|
373
|
+
if (!document.ast) continue;
|
|
374
|
+
|
|
375
|
+
definitions.push(...document.ast.definitions);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return definitions;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
get typeSystemDefinitionsAndExtensions(): (
|
|
382
|
+
| TypeSystemDefinitionNode
|
|
383
|
+
| TypeSystemExtensionNode
|
|
384
|
+
)[] {
|
|
385
|
+
const definitionsAndExtensions = [];
|
|
386
|
+
for (const document of this.documents) {
|
|
387
|
+
if (!document.ast) continue;
|
|
388
|
+
for (const definition of document.ast.definitions) {
|
|
389
|
+
if (
|
|
390
|
+
isTypeSystemDefinitionNode(definition) ||
|
|
391
|
+
isTypeSystemExtensionNode(definition)
|
|
392
|
+
) {
|
|
393
|
+
definitionsAndExtensions.push(definition);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return definitionsAndExtensions;
|
|
398
|
+
}
|
|
399
|
+
}
|