vscode-apollo 2.2.1 → 2.3.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 (37) hide show
  1. package/.circleci/config.yml +1 -17
  2. package/.github/workflows/E2E.yml +27 -0
  3. package/.github/workflows/build-prs.yml +1 -1
  4. package/CHANGELOG.md +22 -0
  5. package/README.md +71 -52
  6. package/jest.e2e.config.js +2 -0
  7. package/package.json +31 -3
  8. package/renovate.json +5 -5
  9. package/sampleWorkspace/localSchemaArray/apollo.config.json +9 -0
  10. package/sampleWorkspace/localSchemaArray/src/test.js +1 -1
  11. package/sampleWorkspace/rover/apollo.config.yaml +3 -0
  12. package/sampleWorkspace/rover/src/test.graphql +11 -10
  13. package/sampleWorkspace/rover/supergraph.yaml +0 -0
  14. package/schemas/apollo.config.schema.json +184 -0
  15. package/src/__e2e__/runTests.js +1 -0
  16. package/src/build.js +53 -1
  17. package/src/language-server/__e2e__/clientSchema.e2e.ts +58 -28
  18. package/src/language-server/__e2e__/httpSchema.e2e.ts +23 -4
  19. package/src/language-server/__e2e__/localSchema.e2e.ts +23 -4
  20. package/src/language-server/__e2e__/localSchemaArray.e2e.ts +31 -6
  21. package/src/language-server/__e2e__/rover.e2e.ts +150 -0
  22. package/src/language-server/__e2e__/studioGraph.e2e.ts +18 -6
  23. package/src/language-server/__e2e__/utils.ts +114 -13
  24. package/src/language-server/config/__tests__/loadConfig.ts +35 -2
  25. package/src/language-server/config/cache-busting-resolver.js +65 -0
  26. package/src/language-server/config/cache-busting-resolver.types.ts +45 -0
  27. package/src/language-server/config/config.ts +133 -57
  28. package/src/language-server/config/loadConfig.ts +27 -6
  29. package/src/language-server/config/loadTsConfig.ts +74 -38
  30. package/src/language-server/project/base.ts +8 -8
  31. package/src/language-server/project/rover/project.ts +6 -0
  32. package/src/language-server/server.ts +8 -7
  33. package/src/language-server/workspace.ts +2 -5
  34. package/src/languageServerClient.ts +3 -1
  35. package/sampleWorkspace/localSchemaArray/apollo.config.js +0 -12
  36. package/sampleWorkspace/rover/apollo.config.js +0 -3
  37. /package/sampleWorkspace/localSchema/{apollo.config.js → apollo.config.ts} +0 -0
@@ -1,56 +1,78 @@
1
- import { Loader, defaultLoaders } from "cosmiconfig";
1
+ import { Loader } from "cosmiconfig";
2
2
  import { dirname } from "node:path";
3
- import { rm, writeFile } from "node:fs/promises";
4
- import { existsSync } from "node:fs";
5
-
3
+ import typescript from "typescript";
4
+ import { pathToFileURL } from "node:url";
5
+ import { register } from "node:module";
6
+ import { ImportAttributes } from "./cache-busting-resolver.types";
6
7
  // implementation based on https://github.com/cosmiconfig/cosmiconfig/blob/a5a842547c13392ebb89a485b9e56d9f37e3cbd3/src/loaders.ts
7
8
  // Copyright (c) 2015 David Clark licensed MIT. Full license can be found here:
8
9
  // https://github.com/cosmiconfig/cosmiconfig/blob/a5a842547c13392ebb89a485b9e56d9f37e3cbd3/LICENSE
9
10
 
10
- let typescript: typeof import("typescript");
11
+ if (process.env.JEST_WORKER_ID === undefined) {
12
+ register(
13
+ pathToFileURL(require.resolve("./config/cache-busting-resolver.js")),
14
+ );
15
+ } else {
16
+ register(pathToFileURL(require.resolve("./cache-busting-resolver.js")));
17
+ }
18
+
11
19
  export const loadTs: Loader = async function loadTs(filepath, content) {
12
20
  try {
13
- return await defaultLoaders[".ts"](filepath, content);
21
+ return await load(filepath, content, "module", {
22
+ module: typescript.ModuleKind.ES2022,
23
+ });
14
24
  } catch (error) {
15
25
  if (
16
- !(error instanceof Error) ||
17
- !error.message.includes("module is not defined")
18
- )
26
+ error instanceof Error &&
27
+ // [ERROR] ReferenceError: module is not defined in ES module scope
28
+ error.message.includes("module is not defined")
29
+ ) {
30
+ return await load(filepath, content, "commonjs", {
31
+ module: typescript.ModuleKind.CommonJS,
32
+ });
33
+ } else {
19
34
  throw error;
35
+ }
20
36
  }
37
+ };
21
38
 
22
- if (typescript === undefined) {
23
- typescript = await import("typescript");
24
- }
25
- const compiledFilepath = `${filepath.slice(0, -2)}cjs`;
39
+ async function load(
40
+ filepath: string,
41
+ content: string,
42
+ type: "module" | "commonjs",
43
+ compilerOptions: Partial<import("typescript").CompilerOptions>,
44
+ ) {
26
45
  let transpiledContent;
46
+
27
47
  try {
28
- try {
29
- const config = resolveTsConfig(dirname(filepath)) ?? {};
30
- config.compilerOptions = {
31
- ...config.compilerOptions,
32
- module: typescript.ModuleKind.CommonJS,
33
- moduleResolution: typescript.ModuleResolutionKind.Bundler,
34
- target: typescript.ScriptTarget.ES2022,
35
- noEmit: false,
36
- };
37
- transpiledContent = typescript.transpileModule(
38
- content,
39
- config,
40
- ).outputText;
41
- await writeFile(compiledFilepath, transpiledContent);
42
- } catch (error: any) {
43
- error.message = `TypeScript Error in ${filepath}:\n${error.message}`;
44
- throw error;
45
- }
46
- // eslint-disable-next-line @typescript-eslint/return-await
47
- return await defaultLoaders[".js"](compiledFilepath, transpiledContent);
48
- } finally {
49
- if (existsSync(compiledFilepath)) {
50
- await rm(compiledFilepath);
51
- }
48
+ const config = resolveTsConfig(dirname(filepath)) ?? {};
49
+ config.compilerOptions = {
50
+ ...config.compilerOptions,
51
+
52
+ moduleResolution: typescript.ModuleResolutionKind.Bundler,
53
+ target: typescript.ScriptTarget.ES2022,
54
+ noEmit: false,
55
+ ...compilerOptions,
56
+ };
57
+ transpiledContent = typescript.transpileModule(content, config).outputText;
58
+ } catch (error: any) {
59
+ error.message = `TypeScript Error in ${filepath}:\n${error.message}`;
60
+ throw error;
52
61
  }
53
- };
62
+ // eslint-disable-next-line @typescript-eslint/return-await
63
+ const imported = await import(
64
+ filepath,
65
+ //@ts-ignore
66
+ {
67
+ with: {
68
+ as: "cachebust",
69
+ contents: transpiledContent,
70
+ format: type,
71
+ } satisfies ImportAttributes,
72
+ }
73
+ );
74
+ return imported.default;
75
+ }
54
76
 
55
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
78
  function resolveTsConfig(directory: string): any {
@@ -68,3 +90,17 @@ function resolveTsConfig(directory: string): any {
68
90
  }
69
91
  return;
70
92
  }
93
+
94
+ export const loadJs: Loader = async function loadJs(filepath, contents) {
95
+ return (
96
+ await import(
97
+ filepath, // @ts-ignore
98
+ {
99
+ with: {
100
+ as: "cachebust",
101
+ contents,
102
+ } satisfies ImportAttributes,
103
+ }
104
+ )
105
+ ).default;
106
+ };
@@ -18,7 +18,13 @@ import { TextDocument } from "vscode-languageserver-textdocument";
18
18
 
19
19
  import type { LoadingHandler } from "../loadingHandler";
20
20
  import { FileSet } from "../fileSet";
21
- import { ApolloConfig, ClientConfig, RoverConfig } from "../config";
21
+ import {
22
+ ApolloConfig,
23
+ ClientConfig,
24
+ envFileNames,
25
+ RoverConfig,
26
+ supportedConfigFileNames,
27
+ } from "../config";
22
28
  import type { ProjectStats } from "../../messages";
23
29
 
24
30
  export type DocumentUri = string;
@@ -67,13 +73,7 @@ export abstract class GraphQLProject {
67
73
 
68
74
  this.configFileSet = new FileSet({
69
75
  rootURI: this.rootURI,
70
- includes: [
71
- ".env",
72
- "apollo.config.js",
73
- "apollo.config.cjs",
74
- "apollo.config.mjs",
75
- "apollo.config.ts",
76
- ],
76
+ includes: supportedConfigFileNames.concat(envFileNames),
77
77
  excludes: [],
78
78
  });
79
79
 
@@ -24,6 +24,7 @@ import {
24
24
  SemanticTokensRegistrationType,
25
25
  SemanticTokensOptions,
26
26
  SemanticTokensRegistrationOptions,
27
+ DefinitionRequest,
27
28
  } from "vscode-languageserver/node";
28
29
  import cp from "node:child_process";
29
30
  import { GraphQLProjectConfig } from "../base";
@@ -281,6 +282,11 @@ export class RoverProject extends GraphQLProject {
281
282
  this.sendRequest(HoverRequest.type, virtualParams, token),
282
283
  );
283
284
 
285
+ onDefinition: GraphQLProject["onDefinition"] = async (params, token) =>
286
+ this.documents.insideVirtualDocument(params, (virtualParams) =>
287
+ this.sendRequest(DefinitionRequest.type, virtualParams, token),
288
+ );
289
+
284
290
  onUnhandledRequest: GraphQLProject["onUnhandledRequest"] = async (
285
291
  type,
286
292
  params,
@@ -9,7 +9,8 @@ import {
9
9
  FileEvent,
10
10
  } from "vscode-languageserver/node";
11
11
  import { TextDocument } from "vscode-languageserver-textdocument";
12
- import type { QuickPickItem } from "vscode";
12
+ import { type QuickPickItem } from "vscode";
13
+ import { basename } from "node:path";
13
14
  import { GraphQLWorkspace } from "./workspace";
14
15
  import { LanguageServerLoadingHandler } from "./loadingHandler";
15
16
  import { debounceHandler, Debug } from "./utilities";
@@ -23,6 +24,7 @@ import { isValidationError } from "zod-validation-error";
23
24
  import { GraphQLProject } from "./project/base";
24
25
  import type { LanguageIdExtensionMap } from "../tools/utilities/languageInformation";
25
26
  import { setLanguageIdExtensionMap } from "./utilities/languageIdForExtension";
27
+ import { envFileNames, supportedConfigFileNames } from "./config";
26
28
 
27
29
  export type InitializationOptions = {
28
30
  languageIdExtensionMap: LanguageIdExtensionMap;
@@ -190,14 +192,13 @@ documents.onDidClose(
190
192
  connection.onDidChangeWatchedFiles((params) => {
191
193
  const handledByProject = new Map<GraphQLProject, FileEvent[]>();
192
194
  for (const { uri, type } of params.changes) {
195
+ const fsPath = URI.parse(uri).fsPath;
196
+ const fileName = basename(fsPath);
193
197
  if (
194
- uri.endsWith("apollo.config.js") ||
195
- uri.endsWith("apollo.config.cjs") ||
196
- uri.endsWith("apollo.config.mjs") ||
197
- uri.endsWith("apollo.config.ts") ||
198
- uri.endsWith(".env")
198
+ supportedConfigFileNames.includes(fileName) ||
199
+ envFileNames.includes(fileName)
199
200
  ) {
200
- workspace.reloadProjectForConfig(uri);
201
+ workspace.reloadProjectForConfigOrCompanionFile(uri);
201
202
  }
202
203
 
203
204
  // Don't respond to changes in files that are currently open,
@@ -125,7 +125,7 @@ export class GraphQLWorkspace {
125
125
 
126
126
  */
127
127
  const apolloConfigFiles: string[] = globSync(
128
- "**/apollo.config.@(js|ts|cjs|mjs)",
128
+ "**/apollo.config.@(js|ts|cjs|mjs|yaml|yml|json)",
129
129
  {
130
130
  cwd: URI.parse(folder.uri).fsPath,
131
131
  absolute: true,
@@ -197,7 +197,7 @@ export class GraphQLWorkspace {
197
197
  });
198
198
  }
199
199
 
200
- async reloadProjectForConfig(configUri: DocumentUri) {
200
+ async reloadProjectForConfigOrCompanionFile(configUri: DocumentUri) {
201
201
  const configPath = dirname(URI.parse(configUri).fsPath);
202
202
  let config: ApolloConfig | null;
203
203
  let error;
@@ -215,9 +215,6 @@ export class GraphQLWorkspace {
215
215
  }
216
216
  // If project exists, update the config
217
217
  if (project && config) {
218
- if (equal(project.config.rawConfig, config.rawConfig)) {
219
- return;
220
- }
221
218
  await Promise.all(project.updateConfig(config));
222
219
  this.reloadService();
223
220
  }
@@ -52,7 +52,9 @@ export function getLanguageServerClient(
52
52
  documentSelector: supportedLanguageIds,
53
53
  synchronize: {
54
54
  fileEvents: [
55
- workspace.createFileSystemWatcher("**/.env?(.local)"),
55
+ workspace.createFileSystemWatcher(
56
+ "**/{.env?(.local),apollo.config.{json,yml,yaml}}",
57
+ ),
56
58
  workspace.createFileSystemWatcher(
57
59
  "**/*{" + supportedExtensions.join(",") + "}",
58
60
  ),
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- client: {
3
- service: {
4
- name: "localMultiSchema",
5
- localSchemaFile: [
6
- "./starwarsSchema.graphql",
7
- // this documents an unfixed bug: in this multi-folder-workspace, this looks for files relative to the first folder in the .code-workspace file
8
- "./planets.graphql",
9
- ],
10
- },
11
- },
12
- };
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- rover: {},
3
- };