vscode-apollo 1.19.3 → 2.0.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.
Files changed (179) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.circleci/config.yml +91 -0
  4. package/.eslintrc.js +10 -0
  5. package/.git-blame-ignore-revs +2 -0
  6. package/.gitattributes +1 -0
  7. package/.github/workflows/release.yml +95 -0
  8. package/.gitleaks.toml +26 -0
  9. package/.nvmrc +1 -0
  10. package/.prettierrc +5 -0
  11. package/.vscode/launch.json +66 -0
  12. package/.vscode/settings.json +16 -0
  13. package/.vscode/tasks.json +60 -0
  14. package/.vscodeignore +28 -1
  15. package/CHANGELOG.md +250 -1
  16. package/CODEOWNERS +4 -0
  17. package/LICENSE +2 -2
  18. package/README.md +104 -55
  19. package/codegen.yml +12 -0
  20. package/graphql.configuration.json +5 -1
  21. package/images/IconRun.svg +8 -0
  22. package/images/marketplace/apollo-wordmark.png +0 -0
  23. package/jest.config.ts +21 -0
  24. package/jest.e2e.config.js +17 -0
  25. package/package.json +102 -23
  26. package/renovate.json +30 -0
  27. package/sampleWorkspace/clientSchema/apollo.config.cjs +10 -0
  28. package/sampleWorkspace/clientSchema/src/clientSchema.js +16 -0
  29. package/sampleWorkspace/clientSchema/src/test.js +18 -0
  30. package/sampleWorkspace/fixtures/starwarsSchema.graphql +299 -0
  31. package/sampleWorkspace/httpSchema/apollo.config.ts +8 -0
  32. package/sampleWorkspace/httpSchema/src/test.js +9 -0
  33. package/sampleWorkspace/localSchema/apollo.config.js +8 -0
  34. package/sampleWorkspace/localSchema/src/test.js +8 -0
  35. package/sampleWorkspace/localSchemaArray/apollo.config.js +12 -0
  36. package/sampleWorkspace/localSchemaArray/planets.graphql +20 -0
  37. package/sampleWorkspace/localSchemaArray/src/test.js +12 -0
  38. package/sampleWorkspace/sampleWorkspace.code-workspace +20 -0
  39. package/sampleWorkspace/spotifyGraph/apollo.config.mjs +5 -0
  40. package/sampleWorkspace/spotifyGraph/src/test.js +11 -0
  41. package/src/__e2e__/mockServer.js +117 -0
  42. package/src/__e2e__/mocks.js +13094 -0
  43. package/src/__e2e__/run.js +23 -0
  44. package/src/__e2e__/runTests.js +44 -0
  45. package/src/__e2e__/setup.js +1 -0
  46. package/src/__e2e__/vscode-environment.js +16 -0
  47. package/src/__e2e__/vscode.js +1 -0
  48. package/src/__mocks__/fs.js +3 -0
  49. package/src/__tests__/statusBar.test.ts +8 -7
  50. package/src/build.js +57 -0
  51. package/src/debug.ts +2 -5
  52. package/src/env/index.ts +1 -0
  53. package/src/env/typescript-utility-types.ts +2 -0
  54. package/src/extension.ts +265 -170
  55. package/src/language-server/__e2e__/clientSchema.e2e.ts +147 -0
  56. package/src/language-server/__e2e__/httpSchema.e2e.ts +21 -0
  57. package/src/language-server/__e2e__/localSchema.e2e.ts +25 -0
  58. package/src/language-server/__e2e__/localSchemaArray.e2e.ts +31 -0
  59. package/src/language-server/__e2e__/studioGraph.e2e.ts +65 -0
  60. package/src/language-server/__e2e__/utils.ts +151 -0
  61. package/src/language-server/__tests__/diagnostics.test.ts +86 -0
  62. package/src/language-server/__tests__/document.test.ts +187 -0
  63. package/src/language-server/__tests__/fileSet.test.ts +46 -0
  64. package/src/language-server/__tests__/fixtures/starwarsSchema.ts +1917 -0
  65. package/src/language-server/config/__tests__/config.ts +54 -0
  66. package/src/language-server/config/__tests__/loadConfig.ts +384 -0
  67. package/src/language-server/config/__tests__/utils.ts +99 -0
  68. package/src/language-server/config/config.ts +284 -0
  69. package/src/language-server/config/index.ts +3 -0
  70. package/src/language-server/config/loadConfig.ts +101 -0
  71. package/src/language-server/config/utils.ts +45 -0
  72. package/src/language-server/diagnostics.ts +118 -0
  73. package/src/language-server/document.ts +277 -0
  74. package/src/language-server/engine/index.ts +123 -0
  75. package/src/language-server/engine/operations/frontendUrlRoot.ts +15 -0
  76. package/src/language-server/engine/operations/schemaTagsAndFieldStats.ts +32 -0
  77. package/src/language-server/errors/__tests__/NoMissingClientDirectives.test.ts +225 -0
  78. package/src/language-server/errors/logger.ts +58 -0
  79. package/src/language-server/errors/validation.ts +274 -0
  80. package/src/language-server/fileSet.ts +63 -0
  81. package/src/language-server/format.ts +48 -0
  82. package/src/language-server/graphqlTypes.ts +16741 -0
  83. package/src/language-server/index.ts +28 -0
  84. package/src/language-server/languageProvider.ts +795 -0
  85. package/src/language-server/loadingHandler.ts +47 -0
  86. package/src/language-server/project/base.ts +406 -0
  87. package/src/language-server/project/client.ts +568 -0
  88. package/src/language-server/project/defaultClientSchema.ts +70 -0
  89. package/src/language-server/providers/schema/__tests__/file.ts +191 -0
  90. package/src/language-server/providers/schema/base.ts +15 -0
  91. package/src/language-server/providers/schema/endpoint.ts +138 -0
  92. package/src/language-server/providers/schema/engine.ts +204 -0
  93. package/src/language-server/providers/schema/file.ts +176 -0
  94. package/src/language-server/providers/schema/index.ts +59 -0
  95. package/src/language-server/server.ts +274 -0
  96. package/src/language-server/typings/graphql.d.ts +27 -0
  97. package/src/language-server/utilities/__tests__/graphql.test.ts +399 -0
  98. package/src/language-server/utilities/__tests__/uri.ts +55 -0
  99. package/src/language-server/utilities/debouncer.ts +8 -0
  100. package/src/language-server/utilities/debug.ts +90 -0
  101. package/src/language-server/utilities/graphql.ts +433 -0
  102. package/src/language-server/utilities/index.ts +3 -0
  103. package/src/language-server/utilities/source.ts +182 -0
  104. package/src/language-server/utilities/uri.ts +19 -0
  105. package/src/language-server/workspace.ts +254 -0
  106. package/src/languageServerClient.ts +22 -15
  107. package/src/messages.ts +75 -0
  108. package/src/statusBar.ts +5 -5
  109. package/src/tools/__tests__/buildServiceDefinition.test.ts +491 -0
  110. package/src/tools/__tests__/snapshotSerializers/astSerializer.ts +19 -0
  111. package/src/tools/__tests__/snapshotSerializers/graphQLTypeSerializer.ts +14 -0
  112. package/src/tools/buildServiceDefinition.ts +241 -0
  113. package/src/tools/index.ts +6 -0
  114. package/src/tools/schema/index.ts +2 -0
  115. package/src/tools/schema/resolveObject.ts +18 -0
  116. package/src/tools/schema/resolverMap.ts +23 -0
  117. package/src/tools/utilities/graphql.ts +22 -0
  118. package/src/tools/utilities/index.ts +3 -0
  119. package/src/tools/utilities/invariant.ts +5 -0
  120. package/src/tools/utilities/predicates.ts +5 -0
  121. package/src/utils.ts +7 -21
  122. package/syntaxes/graphql.dart.json +2 -4
  123. package/syntaxes/graphql.ex.json +1 -4
  124. package/syntaxes/graphql.js.json +3 -3
  125. package/syntaxes/graphql.json +13 -9
  126. package/syntaxes/graphql.lua.json +51 -0
  127. package/syntaxes/graphql.rb.json +1 -1
  128. package/tsconfig.build.json +11 -0
  129. package/tsconfig.json +22 -7
  130. package/create-server-symlink.js +0 -8
  131. package/lib/debug.d.ts +0 -11
  132. package/lib/debug.d.ts.map +0 -1
  133. package/lib/debug.js +0 -48
  134. package/lib/debug.js.map +0 -1
  135. package/lib/extension.d.ts +0 -4
  136. package/lib/extension.d.ts.map +0 -1
  137. package/lib/extension.js +0 -187
  138. package/lib/extension.js.map +0 -1
  139. package/lib/languageServerClient.d.ts +0 -4
  140. package/lib/languageServerClient.d.ts.map +0 -1
  141. package/lib/languageServerClient.js +0 -57
  142. package/lib/languageServerClient.js.map +0 -1
  143. package/lib/statusBar.d.ts +0 -24
  144. package/lib/statusBar.d.ts.map +0 -1
  145. package/lib/statusBar.js +0 -46
  146. package/lib/statusBar.js.map +0 -1
  147. package/lib/testRunner/index.d.ts +0 -3
  148. package/lib/testRunner/index.d.ts.map +0 -1
  149. package/lib/testRunner/index.js +0 -49
  150. package/lib/testRunner/index.js.map +0 -1
  151. package/lib/testRunner/jest-config.d.ts +0 -14
  152. package/lib/testRunner/jest-config.d.ts.map +0 -1
  153. package/lib/testRunner/jest-config.js +0 -18
  154. package/lib/testRunner/jest-config.js.map +0 -1
  155. package/lib/testRunner/jest-vscode-environment.d.ts +0 -2
  156. package/lib/testRunner/jest-vscode-environment.d.ts.map +0 -1
  157. package/lib/testRunner/jest-vscode-environment.js +0 -19
  158. package/lib/testRunner/jest-vscode-environment.js.map +0 -1
  159. package/lib/testRunner/jest-vscode-framework-setup.d.ts +0 -1
  160. package/lib/testRunner/jest-vscode-framework-setup.d.ts.map +0 -1
  161. package/lib/testRunner/jest-vscode-framework-setup.js +0 -3
  162. package/lib/testRunner/jest-vscode-framework-setup.js.map +0 -1
  163. package/lib/testRunner/vscode-test-script.d.ts +0 -2
  164. package/lib/testRunner/vscode-test-script.d.ts.map +0 -1
  165. package/lib/testRunner/vscode-test-script.js +0 -23
  166. package/lib/testRunner/vscode-test-script.js.map +0 -1
  167. package/lib/utils.d.ts +0 -18
  168. package/lib/utils.d.ts.map +0 -1
  169. package/lib/utils.js +0 -52
  170. package/lib/utils.js.map +0 -1
  171. package/src/testRunner/README.md +0 -23
  172. package/src/testRunner/index.ts +0 -72
  173. package/src/testRunner/jest-config.ts +0 -17
  174. package/src/testRunner/jest-vscode-environment.ts +0 -25
  175. package/src/testRunner/jest-vscode-framework-setup.ts +0 -10
  176. package/src/testRunner/jest.d.ts +0 -37
  177. package/src/testRunner/vscode-test-script.ts +0 -38
  178. package/tsconfig.test.json +0 -4
  179. package/tsconfig.tsbuildinfo +0 -2486
@@ -0,0 +1,284 @@
1
+ import { dirname } from "path";
2
+ import { URI } from "vscode-uri";
3
+ import { getGraphIdFromConfig, parseServiceSpecifier } from "./utils";
4
+ import { Debug } from "../utilities";
5
+ import z, { ZodError } from "zod";
6
+ import { ValidationRule } from "graphql/validation/ValidationContext";
7
+ import { Slot } from "@wry/context";
8
+ import { fromZodError } from "zod-validation-error";
9
+
10
+ const ROVER_AVAILABLE = (process.env.APOLLO_FEATURE_FLAGS || "")
11
+ .split(",")
12
+ .includes("rover");
13
+
14
+ function ignoredFieldWarning(
15
+ getMessage = (path: string) =>
16
+ `The option ${path} is no longer supported, please remove it from your configuration file.`,
17
+ ) {
18
+ return z
19
+ .custom<unknown>(() => true)
20
+ .superRefine((val, ctx) => {
21
+ if (val) {
22
+ Debug.warning(getMessage(ctx.path.join(".")));
23
+ }
24
+ })
25
+ .optional();
26
+ }
27
+ export interface Context {
28
+ apiKey?: string;
29
+ serviceName?: string;
30
+ }
31
+ const context = new Slot<Context>();
32
+
33
+ const studioServiceConfig = z.string();
34
+
35
+ const remoteServiceConfig = z.object({
36
+ name: z.string().optional(),
37
+ url: z.string(),
38
+ headers: z.record(z.string()).default({}),
39
+ skipSSLValidation: z.boolean().default(false),
40
+ });
41
+ export type RemoteServiceConfig = z.infer<typeof remoteServiceConfig>;
42
+
43
+ const localServiceConfig = z.object({
44
+ name: z.string().optional(),
45
+ localSchemaFile: z.union([z.string(), z.array(z.string())]),
46
+ });
47
+ export type LocalServiceConfig = z.infer<typeof localServiceConfig>;
48
+
49
+ const clientServiceConfig = z.preprocess(
50
+ (value) => value || context.getValue()?.serviceName,
51
+ z.union([studioServiceConfig, remoteServiceConfig, localServiceConfig]),
52
+ );
53
+ export type ClientServiceConfig = z.infer<typeof clientServiceConfig>;
54
+
55
+ const clientConfig = z.object({
56
+ service: clientServiceConfig,
57
+ validationRules: z
58
+ .union([
59
+ z.array(z.custom<ValidationRule>()),
60
+ z.function().args(z.custom<ValidationRule>()).returns(z.boolean()),
61
+ ])
62
+ .optional(),
63
+ // maybe shared with rover?
64
+ includes: z
65
+ .array(z.string())
66
+ .default(["src/**/*.{ts,tsx,js,jsx,graphql,gql}"]),
67
+ // maybe shared with rover?
68
+ excludes: z.array(z.string()).default(["**/node_modules", "**/__tests__"]),
69
+ // maybe shared with rover?
70
+ tagName: z.string().default("gql"),
71
+ // removed:
72
+ clientOnlyDirectives: ignoredFieldWarning(),
73
+ clientSchemaDirectives: ignoredFieldWarning(),
74
+ statsWindow: ignoredFieldWarning(),
75
+ name: ignoredFieldWarning(),
76
+ referenceId: ignoredFieldWarning(),
77
+ version: ignoredFieldWarning(),
78
+ });
79
+ export type ClientConfigFormat = z.infer<typeof clientConfig>;
80
+
81
+ const roverConfig = z.object({
82
+ bin: z.string().optional(),
83
+ profile: z.string().optional(),
84
+ });
85
+ type RoverConfigFormat = z.infer<typeof roverConfig>;
86
+
87
+ const engineConfig = z.object({
88
+ endpoint: z
89
+ .string()
90
+ .default(
91
+ process.env.APOLLO_ENGINE_ENDPOINT ||
92
+ "https://graphql.api.apollographql.com/api/graphql",
93
+ ),
94
+ apiKey: z.preprocess(
95
+ (val) => val || context.getValue()?.apiKey,
96
+ z.string().optional(),
97
+ ),
98
+ });
99
+ export type EngineConfig = z.infer<typeof engineConfig>;
100
+
101
+ const baseConfig = z.object({
102
+ engine: engineConfig.default({}),
103
+ client: z.unknown().optional(),
104
+ rover: z.unknown().optional(),
105
+ service: ignoredFieldWarning(
106
+ (path) =>
107
+ `Service-type projects are no longer supported. Please remove the "${path}" field from your configuration file.`,
108
+ ),
109
+ });
110
+
111
+ export type FullClientConfigFormat = Extract<
112
+ ParsedApolloConfigFormat,
113
+ { client: {} }
114
+ >;
115
+
116
+ export type FullRoverConfigFormat = Extract<
117
+ ParsedApolloConfigFormat,
118
+ { rover: {} }
119
+ >;
120
+
121
+ /** Helper function for TypeScript - we just want the first type to make it into the types, not the "no feature flag" fallback */
122
+ function ifRoverAvailable<T>(yes: T, no: any): T {
123
+ return ROVER_AVAILABLE ? yes : no;
124
+ }
125
+
126
+ export const configSchema = baseConfig
127
+ .superRefine((val, ctx) => {
128
+ if (ROVER_AVAILABLE) {
129
+ if ("client" in val && "rover" in val) {
130
+ ctx.addIssue({
131
+ code: "custom",
132
+ message: "Config cannot contain both 'client' and 'rover' fields",
133
+ fatal: true,
134
+ });
135
+ }
136
+ if (!("client" in val) && !("rover" in val)) {
137
+ ctx.addIssue({
138
+ code: "custom",
139
+ message: "Config needs to contain either 'client' or 'rover' fields",
140
+ fatal: true,
141
+ });
142
+ }
143
+ } else {
144
+ if (!("client" in val)) {
145
+ ctx.addIssue({
146
+ code: "custom",
147
+ message: "Config needs to contain a 'client' field.",
148
+ fatal: true,
149
+ });
150
+ }
151
+ }
152
+ })
153
+ .and(
154
+ ifRoverAvailable(
155
+ z.union([
156
+ z
157
+ .object({
158
+ client: clientConfig,
159
+ })
160
+ .transform((val): typeof val & { rover?: never } => val),
161
+ z
162
+ .object({
163
+ rover: roverConfig,
164
+ })
165
+ .transform((val): typeof val & { client?: never } => val),
166
+ ]),
167
+ z.object({
168
+ client: clientConfig,
169
+ }),
170
+ ),
171
+ );
172
+ export type RawApolloConfigFormat = z.input<typeof configSchema>;
173
+ export type ParsedApolloConfigFormat = z.output<typeof configSchema>;
174
+
175
+ export function parseApolloConfig(
176
+ rawConfig: RawApolloConfigFormat,
177
+ configURI?: URI,
178
+ ctx: Context = {},
179
+ ) {
180
+ const parsed = context.withValue(ctx, () =>
181
+ configSchema.safeParse(rawConfig),
182
+ );
183
+ if (!parsed.success) {
184
+ // Remove "or Required at rover" errors when a client config is provided
185
+ // Remove "or Required at client" errors when a rover config is provided
186
+ for (const [index, error] of parsed.error.errors.entries()) {
187
+ if (error.code === z.ZodIssueCode.invalid_union) {
188
+ error.unionErrors = error.unionErrors.filter((e) => {
189
+ return !(
190
+ e instanceof ZodError &&
191
+ e.errors.length === 1 &&
192
+ e.errors[0].message === "Required" &&
193
+ e.errors[0].path.length === 1
194
+ );
195
+ });
196
+ }
197
+ }
198
+ throw fromZodError(parsed.error, {
199
+ prefix: `Error parsing config file ${configURI?.fsPath}:`,
200
+ prefixSeparator: "\n",
201
+ issueSeparator: ";\n",
202
+ unionSeparator: "\n or\n",
203
+ });
204
+ }
205
+ if (parsed.data.client) {
206
+ return new ClientConfig(parsed.data, configURI);
207
+ } else if (parsed.data.rover) {
208
+ return new RoverConfig(parsed.data, configURI);
209
+ } else {
210
+ // should never happen
211
+ throw new Error("Invalid config file format!");
212
+ }
213
+ }
214
+
215
+ export abstract class ApolloConfig {
216
+ public engine: EngineConfig;
217
+ public client?: ClientConfigFormat;
218
+ public rover?: RoverConfigFormat;
219
+ private _variant?: string;
220
+ private _graphId?: string;
221
+
222
+ protected constructor(
223
+ public rawConfig: ParsedApolloConfigFormat,
224
+ public configURI?: URI,
225
+ ) {
226
+ this.engine = rawConfig.engine!;
227
+ this._graphId = getGraphIdFromConfig(rawConfig);
228
+ }
229
+
230
+ get configDirURI() {
231
+ // if the filepath has a _file_ in it, then we get its dir
232
+ return this.configURI &&
233
+ this.configURI.fsPath.match(/\.(ts|js|cjs|mjs|json)$/i)
234
+ ? URI.parse(dirname(this.configURI.fsPath))
235
+ : this.configURI;
236
+ }
237
+
238
+ set variant(variant: string) {
239
+ this._variant = variant;
240
+ }
241
+
242
+ get variant(): string {
243
+ if (this._variant) return this._variant;
244
+ let tag: string = "current";
245
+ if (this.client && typeof this.client.service === "string") {
246
+ const parsedVariant = parseServiceSpecifier(this.client.service)[1];
247
+ if (parsedVariant) tag = parsedVariant;
248
+ }
249
+ return tag;
250
+ }
251
+
252
+ set graph(graphId: string | undefined) {
253
+ this._graphId = graphId;
254
+ }
255
+
256
+ get graph(): string | undefined {
257
+ if (this._graphId) return this._graphId;
258
+ return getGraphIdFromConfig(this.rawConfig);
259
+ }
260
+ }
261
+
262
+ export class ClientConfig extends ApolloConfig {
263
+ public client!: ClientConfigFormat;
264
+
265
+ constructor(
266
+ public rawConfig: FullClientConfigFormat,
267
+ public configURI?: URI,
268
+ ) {
269
+ super(rawConfig, configURI);
270
+ this.client = rawConfig.client;
271
+ }
272
+ }
273
+
274
+ export class RoverConfig extends ApolloConfig {
275
+ public rover!: RoverConfigFormat;
276
+
277
+ constructor(
278
+ public rawConfig: FullRoverConfigFormat,
279
+ public configURI?: URI,
280
+ ) {
281
+ super(rawConfig, configURI);
282
+ this.rover = rawConfig.rover;
283
+ }
284
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./utils";
2
+ export * from "./config";
3
+ export * from "./loadConfig";
@@ -0,0 +1,101 @@
1
+ import { cosmiconfig } from "cosmiconfig";
2
+ import { resolve } from "path";
3
+ import { readFileSync, existsSync, lstatSync } from "fs";
4
+ import {
5
+ ApolloConfig,
6
+ RawApolloConfigFormat,
7
+ parseApolloConfig,
8
+ } from "./config";
9
+ import { getServiceFromKey } from "./utils";
10
+ import { URI } from "vscode-uri";
11
+ import { Debug } from "../utilities";
12
+
13
+ // config settings
14
+ const MODULE_NAME = "apollo";
15
+ const defaultFileNames = [
16
+ "package.json",
17
+ `${MODULE_NAME}.config.js`,
18
+ `${MODULE_NAME}.config.ts`,
19
+ `${MODULE_NAME}.config.mjs`,
20
+ `${MODULE_NAME}.config.cjs`,
21
+ ];
22
+ const envFileNames = [".env", ".env.local"];
23
+
24
+ export const keyEnvVar = "APOLLO_KEY";
25
+
26
+ export interface LoadConfigSettings {
27
+ // the current working directory to start looking for the config
28
+ // config loading only works on node so we default to
29
+ // process.cwd()
30
+ configPath: string;
31
+ }
32
+
33
+ export type ConfigResult<T> = {
34
+ config: T;
35
+ filepath: string;
36
+ isEmpty?: boolean;
37
+ } | null;
38
+
39
+ // XXX load .env files automatically
40
+ export async function loadConfig({
41
+ configPath,
42
+ }: LoadConfigSettings): Promise<ApolloConfig | null> {
43
+ const explorer = cosmiconfig(MODULE_NAME, {
44
+ searchPlaces: defaultFileNames,
45
+ });
46
+
47
+ // search can fail if a file can't be parsed (ex: a nonsense js file) so we wrap in a try/catch
48
+ let loadedConfig: ConfigResult<RawApolloConfigFormat>;
49
+ try {
50
+ loadedConfig = (await explorer.search(
51
+ configPath,
52
+ )) as ConfigResult<RawApolloConfigFormat>;
53
+ } catch (error) {
54
+ throw new Error(`A config file failed to load with options: ${JSON.stringify(
55
+ arguments[0],
56
+ )}.
57
+ The error was: ${error}`);
58
+ }
59
+
60
+ if (!loadedConfig || loadedConfig.isEmpty) {
61
+ Debug.error(
62
+ `No Apollo config found for project or config file failed to load. For more information, please refer to: https://go.apollo.dev/t/config`,
63
+ );
64
+ // deliberately returning `null` here, but not throwing an error - the user may not have a config file and that's okay, it might just be a project without a graph
65
+ return null;
66
+ }
67
+
68
+ if (loadedConfig.filepath.endsWith("package.json")) {
69
+ Debug.warning(
70
+ 'The "apollo" package.json configuration key will no longer be supported in Apollo v3. Please use the apollo.config.js file for Apollo project configuration. For more information, see: https://go.apollo.dev/t/config',
71
+ );
72
+ }
73
+
74
+ // add API key from the env
75
+ let apiKey, nameFromKey;
76
+
77
+ // loop over the list of possible .env files and try to parse for key
78
+ // and service name. Files are scanned and found values are preferred
79
+ // in order of appearance in `envFileNames`.
80
+ envFileNames.forEach((envFile) => {
81
+ const dotEnvPath = resolve(configPath, envFile);
82
+
83
+ if (existsSync(dotEnvPath) && lstatSync(dotEnvPath).isFile()) {
84
+ const env: { [key: string]: string } = require("dotenv").parse(
85
+ readFileSync(dotEnvPath),
86
+ );
87
+ apiKey = env[keyEnvVar];
88
+ }
89
+ });
90
+
91
+ if (apiKey) {
92
+ nameFromKey = getServiceFromKey(apiKey);
93
+ }
94
+
95
+ let { config, filepath } = loadedConfig;
96
+
97
+ return parseApolloConfig(config, URI.file(resolve(filepath)), {
98
+ apiKey,
99
+ serviceName: nameFromKey,
100
+ });
101
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ ApolloConfig,
3
+ ClientConfig,
4
+ ClientServiceConfig,
5
+ LocalServiceConfig,
6
+ ParsedApolloConfigFormat,
7
+ } from "./config";
8
+ import { ServiceSpecifier, ServiceIDAndTag } from "../engine";
9
+
10
+ export function isClientConfig(config: ApolloConfig): config is ClientConfig {
11
+ return config instanceof ClientConfig;
12
+ }
13
+
14
+ // checks the `config.client.service` object for a localSchemaFile
15
+ export function isLocalServiceConfig(
16
+ config: ClientServiceConfig,
17
+ ): config is LocalServiceConfig {
18
+ return !!(config as LocalServiceConfig).localSchemaFile;
19
+ }
20
+
21
+ export function getServiceFromKey(key?: string) {
22
+ if (key) {
23
+ const [type, service] = key.split(":");
24
+ if (type === "service") return service;
25
+ }
26
+ return;
27
+ }
28
+
29
+ export function getGraphIdFromConfig(config: ParsedApolloConfigFormat) {
30
+ if (config.client) {
31
+ if (typeof config.client.service === "string") {
32
+ return parseServiceSpecifier(
33
+ config.client.service as ServiceSpecifier,
34
+ )[0];
35
+ }
36
+ return config.client.service && config.client.service.name;
37
+ } else {
38
+ return undefined;
39
+ }
40
+ }
41
+
42
+ export function parseServiceSpecifier(specifier: ServiceSpecifier) {
43
+ const [id, tag] = specifier.split("@").map((x) => x.trim());
44
+ return [id, tag] as ServiceIDAndTag;
45
+ }
@@ -0,0 +1,118 @@
1
+ import {
2
+ GraphQLSchema,
3
+ GraphQLError,
4
+ FragmentDefinitionNode,
5
+ isExecutableDefinitionNode,
6
+ DocumentNode,
7
+ validate,
8
+ NoDeprecatedCustomRule,
9
+ } from "graphql";
10
+
11
+ function findDeprecatedUsages(
12
+ schema: GraphQLSchema,
13
+ ast: DocumentNode,
14
+ ): ReadonlyArray<GraphQLError> {
15
+ return validate(schema, ast, [NoDeprecatedCustomRule]);
16
+ }
17
+
18
+ import { Diagnostic, DiagnosticSeverity } from "vscode-languageserver/node";
19
+
20
+ import { GraphQLDocument } from "./document";
21
+ import { highlightNodeForNode } from "./utilities/graphql";
22
+ import { rangeForASTNode } from "./utilities/source";
23
+
24
+ import { getValidationErrors } from "./errors/validation";
25
+ import { DocumentUri } from "./project/base";
26
+ import { ValidationRule } from "graphql/validation/ValidationContext";
27
+
28
+ /**
29
+ * Build an array of code diagnostics for all executable definitions in a document.
30
+ */
31
+ export function collectExecutableDefinitionDiagnositics(
32
+ schema: GraphQLSchema,
33
+ queryDocument: GraphQLDocument,
34
+ fragments: { [fragmentName: string]: FragmentDefinitionNode } = {},
35
+ rules?: ValidationRule[],
36
+ ): Diagnostic[] {
37
+ const ast = queryDocument.ast;
38
+ if (!ast) return queryDocument.syntaxErrors;
39
+
40
+ const astWithExecutableDefinitions = {
41
+ ...ast,
42
+ definitions: ast.definitions.filter(isExecutableDefinitionNode),
43
+ };
44
+
45
+ const diagnostics = [];
46
+
47
+ for (const error of getValidationErrors(
48
+ schema,
49
+ astWithExecutableDefinitions,
50
+ fragments,
51
+ rules,
52
+ )) {
53
+ diagnostics.push(
54
+ ...diagnosticsFromError(error, DiagnosticSeverity.Error, "Validation"),
55
+ );
56
+ }
57
+
58
+ for (const error of findDeprecatedUsages(
59
+ schema,
60
+ astWithExecutableDefinitions,
61
+ )) {
62
+ diagnostics.push(
63
+ ...diagnosticsFromError(error, DiagnosticSeverity.Warning, "Deprecation"),
64
+ );
65
+ }
66
+
67
+ return diagnostics;
68
+ }
69
+
70
+ export function diagnosticsFromError(
71
+ error: GraphQLError,
72
+ severity: DiagnosticSeverity,
73
+ type: string,
74
+ ): GraphQLDiagnostic[] {
75
+ if (!error.nodes) {
76
+ return [];
77
+ }
78
+
79
+ return error.nodes.map((node) => {
80
+ return {
81
+ source: `GraphQL: ${type}`,
82
+ message: error.message,
83
+ severity,
84
+ range: rangeForASTNode(highlightNodeForNode(node) || node),
85
+ error,
86
+ };
87
+ });
88
+ }
89
+
90
+ export interface GraphQLDiagnostic extends Diagnostic {
91
+ /**
92
+ * The GraphQLError that produced this Diagnostic
93
+ */
94
+ error: GraphQLError;
95
+ }
96
+
97
+ export namespace GraphQLDiagnostic {
98
+ export function is(diagnostic: Diagnostic): diagnostic is GraphQLDiagnostic {
99
+ return "error" in diagnostic;
100
+ }
101
+ }
102
+
103
+ export class DiagnosticSet {
104
+ private diagnosticsByFile = new Map<DocumentUri, Diagnostic[]>();
105
+
106
+ entries() {
107
+ return this.diagnosticsByFile.entries();
108
+ }
109
+
110
+ addDiagnostics(uri: DocumentUri, diagnostics: Diagnostic[]) {
111
+ const existingDiagnostics = this.diagnosticsByFile.get(uri);
112
+ if (!existingDiagnostics) {
113
+ this.diagnosticsByFile.set(uri, diagnostics);
114
+ } else {
115
+ existingDiagnostics.push(...diagnostics);
116
+ }
117
+ }
118
+ }