vscode-apollo 2.1.0 → 2.2.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 (31) hide show
  1. package/.github/workflows/build-prs.yml +55 -0
  2. package/.github/workflows/release.yml +1 -1
  3. package/.gitleaks.toml +10 -3
  4. package/.vscode/launch.json +1 -0
  5. package/.vscodeignore +0 -1
  6. package/CHANGELOG.md +24 -0
  7. package/package.json +2 -2
  8. package/sampleWorkspace/httpSchema/apollo.config.ts +2 -0
  9. package/sampleWorkspace/httpSchema/self-signed.crt +22 -0
  10. package/sampleWorkspace/httpSchema/self-signed.key +28 -0
  11. package/src/__e2e__/mockServer.js +37 -11
  12. package/src/__e2e__/mocks.js +11 -7
  13. package/src/__e2e__/runTests.js +8 -6
  14. package/src/language-server/__e2e__/studioGraph.e2e.ts +4 -3
  15. package/src/language-server/config/__tests__/loadConfig.ts +9 -6
  16. package/src/language-server/config/config.ts +24 -11
  17. package/src/language-server/config/loadConfig.ts +2 -1
  18. package/src/language-server/fileSet.ts +8 -13
  19. package/src/language-server/project/base.ts +24 -17
  20. package/src/language-server/project/client.ts +1 -14
  21. package/src/language-server/project/internal.ts +18 -13
  22. package/src/language-server/project/rover/DocumentSynchronization.ts +120 -21
  23. package/src/language-server/project/rover/project.ts +84 -19
  24. package/src/language-server/providers/schema/endpoint.ts +15 -8
  25. package/src/language-server/server.ts +70 -48
  26. package/src/language-server/utilities/languageIdForExtension.ts +39 -0
  27. package/src/language-server/workspace.ts +27 -3
  28. package/src/languageServerClient.ts +13 -15
  29. package/src/tools/utilities/getLanguageInformation.ts +41 -0
  30. package/src/tools/utilities/languageInformation.ts +41 -0
  31. package/syntaxes/graphql.json +2 -2
@@ -0,0 +1,55 @@
1
+ name: Bundle Extension as Artifact Download
2
+ on:
3
+ pull_request:
4
+ jobs:
5
+ test:
6
+ name: Bundle Extension as Artifact Download
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - uses: actions/setup-node@v4
11
+ with:
12
+ cache: "npm"
13
+ - run: npm install
14
+ - run: echo PKG_VERSION="$(git show --no-patch --format=0.0.0-build.%ct.pr.${{ github.event.pull_request.number }}.commit.%h)" >> $GITHUB_ENV
15
+ - run: npm pkg set "version=${{ env.PKG_VERSION }}"
16
+ - run: npx -y @vscode/vsce package --out vscode-apollo-${{ env.PKG_VERSION }}.vsix
17
+
18
+ - uses: actions/upload-artifact@v4
19
+ id: artifact-upload-step
20
+ with:
21
+ name: vscode-apollo-${{ env.PKG_VERSION }}
22
+ path: vscode-apollo-${{ env.PKG_VERSION }}.vsix
23
+ retention-days: 14
24
+
25
+ - name: Output artifact URL
26
+ run: echo 'Artifact URL is ${{ steps.artifact-upload-step.outputs.artifact-url }}'
27
+
28
+ - name: Find Comment
29
+ uses: peter-evans/find-comment@v3
30
+ id: fc
31
+ with:
32
+ issue-number: ${{ github.event.pull_request.number }}
33
+ comment-author: "github-actions[bot]"
34
+ body-includes: <!-- ARTIFACT-DOWNLOAD -->
35
+
36
+ - name: Create comment
37
+ uses: peter-evans/create-or-update-comment@v4
38
+ with:
39
+ issue-number: ${{ github.event.pull_request.number }}
40
+ comment-id: ${{ steps.fc.outputs.comment-id }}
41
+ edit-mode: replace
42
+ body: |
43
+ <!-- ARTIFACT-DOWNLOAD -->
44
+ You can download the latest build of the extension for this PR here:
45
+ [vscode-apollo-${{ env.PKG_VERSION }}.zip](${{ steps.artifact-upload-step.outputs.artifact-url }}).
46
+
47
+ To install the extension, download the file, unzip it and install it in VS Code by selecting "Install from VSIX..." in the Extensions view.
48
+
49
+ Alternatively, run
50
+ ```sh
51
+ code --install-extension vscode-apollo-${{ env.PKG_VERSION }}.vsix --force
52
+ ```
53
+ from the command line.
54
+
55
+ For older builds, please see the edit history of this comment.
@@ -86,7 +86,7 @@ jobs:
86
86
  "type": "section",
87
87
  "text": {
88
88
  "type": "mrkdwn",
89
- "text": "A new version of `vscode-apollo` was released: <https://github.com/apollographql/vscode-apollo/releases/tag/v${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}|v${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}> :rocket:"
89
+ "text": "A new version of `vscode-apollo` was released: <https://github.com/apollographql/vscode-graphql/releases/tag/v${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}|v${{ fromJson(steps.changesets.outputs.publishedPackages)[0].version }}> :rocket:"
90
90
  }
91
91
  }
92
92
  ]
package/.gitleaks.toml CHANGED
@@ -1,13 +1,13 @@
1
- # This file exists primarily to influence scheduled scans that Apollo runs of all repos in Apollo-managed orgs.
1
+ # This file exists primarily to influence scheduled scans that Apollo runs of all repos in Apollo-managed orgs.
2
2
  # This is an Apollo-Internal link, but more information about these scans is available here:
3
3
  # https://apollographql.atlassian.net/wiki/spaces/SecOps/pages/81330213/Everything+Static+Application+Security+Testing#Scheduled-Scans.1
4
- #
4
+ #
5
5
  # Apollo is using Gitleaks (https://github.com/gitleaks/gitleaks) to run these scans.
6
6
  # However, this file is not something that Gitleaks natively consumes. This file is an
7
7
  # Apollo-convention. Prior to scanning a repo, Apollo merges
8
8
  # our standard Gitleaks configuration (which is largely just the Gitleaks-default config) with
9
9
  # this file if it exists in a repo. The combined config is then used to scan a repo.
10
- #
10
+ #
11
11
  # We did this because the natively-supported allowlisting functionality in Gitleaks didn't do everything we wanted
12
12
  # or wasn't as robust as we needed. For example, one of the allowlisting options offered by Gitleaks depends on the line number
13
13
  # on which a false positive secret exists to allowlist it. (https://github.com/gitleaks/gitleaks#gitleaksignore).
@@ -24,3 +24,10 @@
24
24
  # See https://github.com/apollographql/vscode-graphql/blob/a905280c143991b3fd675f8b4c3a7da277ccf095/packages/apollo-language-server/src/engine/index.ts#L86
25
25
  "a905280c143991b3fd675f8b4c3a7da277ccf095"
26
26
  ]
27
+
28
+ [[ rules ]]
29
+ id = "private-key"
30
+ [ rules.allowlist ]
31
+ paths = [
32
+ '''sampleWorkspace/httpSchema/self-signed.key$''',
33
+ ]
@@ -17,6 +17,7 @@
17
17
  "env": {
18
18
  "APOLLO_ENGINE_ENDPOINT": "http://localhost:7096/apollo",
19
19
  "APOLLO_FEATURE_FLAGS": "rover"
20
+ //"APOLLO_ROVER_LANGUAGE_IDS": "graphql,javascript"
20
21
  },
21
22
  "outFiles": ["${workspaceRoot}/lib/**/*.js"]
22
23
  },
package/.vscodeignore CHANGED
@@ -10,7 +10,6 @@ src
10
10
  .prettierrc
11
11
  .gitattributes
12
12
  codegen.yml
13
- graphql.configuration.json
14
13
  jest.*.ts
15
14
  jest.*.js
16
15
  package-lock.json
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#198](https://github.com/apollographql/vscode-graphql/pull/198) [`3bebbdc4`](https://github.com/apollographql/vscode-graphql/commit/3bebbdc40faf8f9d62d0709de3312d5cb629af15) Thanks [@phryneas](https://github.com/phryneas)! - Change syntax highlighting of graphql object fields from "string" to "variable".
8
+
9
+ - [#199](https://github.com/apollographql/vscode-graphql/pull/199) [`7c1172be`](https://github.com/apollographql/vscode-graphql/commit/7c1172be690488dbf0510c2d412cba502acd1468) Thanks [@phryneas](https://github.com/phryneas)! - Fix "Toggle Line Comment"
10
+
11
+ - [#190](https://github.com/apollographql/vscode-graphql/pull/190) [`ec1e9927`](https://github.com/apollographql/vscode-graphql/commit/ec1e9927a178e75cae21d795d47426f40bf9d27b) Thanks [@phryneas](https://github.com/phryneas)! - Fix a bug that prevented `skipSSLValidation` from working.
12
+
13
+ ## 2.2.0
14
+
15
+ ### Minor Changes
16
+
17
+ - [#184](https://github.com/apollographql/vscode-graphql/pull/184) [`9c53a11e`](https://github.com/apollographql/vscode-graphql/commit/9c53a11e3006dd69675af976ef3857212d8f9f43) Thanks [@phryneas](https://github.com/phryneas)! - Derive extensions for supported languages and monitored files from other installed extensions.
18
+ Adjust default `includes` for client projects.
19
+
20
+ This changes the default `includes` similar to (depending on additional extensions you might have installed):
21
+
22
+ ```diff
23
+ -'src/**/*.{ts,tsx,js,jsx,graphql,gql}',
24
+ +'src/**/*{.gql,.graphql,.graphqls,.js,.mjs,.cjs,.es6,.pac,.ts,.mts,.cts,.jsx,.tsx,.vue,.svelte,.py,.rpy,.pyw,.cpy,.gyp,.gypi,.pyi,.ipy,.pyt,.rb,.rbx,.rjs,.gemspec,.rake,.ru,.erb,.podspec,.rbi,.dart,.re,.ex,.exs}'
25
+ ```
26
+
3
27
  ## 2.1.0
4
28
 
5
29
  ### Minor Changes
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vscode-apollo",
3
3
  "displayName": "Apollo GraphQL",
4
4
  "description": "Rich editor support for GraphQL client and server development that seamlessly integrates with the Apollo platform",
5
- "version": "2.1.0",
5
+ "version": "2.2.1",
6
6
  "referenceID": "87197759-7617-40d0-b32e-46d378e907c7",
7
7
  "author": "Apollo GraphQL <opensource@apollographql.com>",
8
8
  "license": "MIT",
@@ -40,7 +40,6 @@
40
40
  "@apollo/client": "3.11.4",
41
41
  "@apollo/subgraph": "2.8.4",
42
42
  "@graphql-tools/schema": "10.0.5",
43
- "@wry/context": "0.7.4",
44
43
  "@wry/equality": "0.5.7",
45
44
  "cosmiconfig": "9.0.0",
46
45
  "dotenv": "16.4.5",
@@ -55,6 +54,7 @@
55
54
  "lz-string": "1.5.0",
56
55
  "minimatch": "10.0.1",
57
56
  "moment": "2.30.1",
57
+ "undici": "6.19.8",
58
58
  "vscode-languageclient": "9.0.1",
59
59
  "vscode-languageserver": "9.0.1",
60
60
  "vscode-languageserver-textdocument": "1.0.12",
@@ -3,6 +3,8 @@ export default {
3
3
  service: {
4
4
  name: "httpSchema",
5
5
  url: "http://localhost:7096/graphql",
6
+ // url: "https://localhost:7097/graphql",
7
+ // skipSSLValidation: true,
6
8
  },
7
9
  },
8
10
  };
@@ -0,0 +1,22 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDkzCCAnugAwIBAgIUVNlDGdat5znvwWhOEFQLq7BWzNwwDQYJKoZIhvcNAQEL
3
+ BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4
+ GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X
5
+ DTI0MDkwMjA4MTgwNloXDTM0MDgzMTA4MTgwNlowWTELMAkGA1UEBhMCQVUxEzAR
6
+ BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
7
+ IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
8
+ MIIBCgKCAQEAvHLw9Ey0WoRLxjVIajxVAT4za1pUQw3E9mtl57DPHDcdGWR56S9w
9
+ KPjmND5lrtALZ5K+EKqslJdPf6Uxzxpf6phVnwpFwq5hPeY/Gpm77HxpPiJ61Q9r
10
+ fsYnLtGXiZta0kbdrisALB+3QykEHOerDUF3wGiVYVcpDu7WF/WcLaF+zUlgf1gQ
11
+ RTa5B3HpdCk34LiKPm9IZpWRpgLC90ro+HP+nBo7FoLYwu+WiPxg49qWEUY8fk+d
12
+ TuJVdH7lf8GxcfM2oCzhBGpT5O/t6lqYBkgZvvY3YAERmAxg/OSeuUa6ChOMLK2T
13
+ +2MRLy7eLaaeTmPMFjjrzFODCA2/ekfGVwIDAQABo1MwUTAdBgNVHQ4EFgQUpEu/
14
+ mbpTwcOGdPZ8NhTl1e16G84wHwYDVR0jBBgwFoAUpEu/mbpTwcOGdPZ8NhTl1e16
15
+ G84wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAhfSAl9VFS+Fk
16
+ Wkmsl1ndoXvLWVDy36YepbNfXUeB+iwebIgdyZhNu6VdpcHsPNBuUV4wr4mgZ7PK
17
+ Ksp3kKdqTDTAfBzHNBiOK7QgGyrDQJa0/Nn8ifmS+TYYCOs4FnkOXCUFipXCCMaS
18
+ KzFYc9Ls4jtAxiSN58NmwxW9fqRHqwHW4o2Z/aNx4EnCEat0x4QcAqq/qfEodmjH
19
+ jI7/AKb4UE+yEcJnZSlUDdpM4zPM3FcjmY7JVyfd/CziywR7rHGbLz7XQcCkYyDv
20
+ 5xqz0Lvk0ZtOC73cFWS41qfh8lrt34CNPoG7EaPFf+tMwhvjNooDHMQCb8y1A0Y3
21
+ 2yaDZNbCbQ==
22
+ -----END CERTIFICATE-----
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8cvD0TLRahEvG
3
+ NUhqPFUBPjNrWlRDDcT2a2XnsM8cNx0ZZHnpL3Ao+OY0PmWu0Atnkr4QqqyUl09/
4
+ pTHPGl/qmFWfCkXCrmE95j8ambvsfGk+InrVD2t+xicu0ZeJm1rSRt2uKwAsH7dD
5
+ KQQc56sNQXfAaJVhVykO7tYX9ZwtoX7NSWB/WBBFNrkHcel0KTfguIo+b0hmlZGm
6
+ AsL3Suj4c/6cGjsWgtjC75aI/GDj2pYRRjx+T51O4lV0fuV/wbFx8zagLOEEalPk
7
+ 7+3qWpgGSBm+9jdgARGYDGD85J65RroKE4wsrZP7YxEvLt4tpp5OY8wWOOvMU4MI
8
+ Db96R8ZXAgMBAAECggEAGRrrnHLZi2jY2sDUyF5dlAr6zlWcKHYITtceSNWmXyO9
9
+ Ky8BChPen9QPgFdDCZ0VX94jQaooeqqGa0K71ijf2ADPq0ky46LX4+dYHHhC762K
10
+ rGiV2kDceROh5bFYvFAniHWWE8gOalJsAjT6eMqo4DJgEeXSPMO1UxQguSlofdrX
11
+ 9PIkRmsmQVmVh17V4RJhhW/qg8r75OwpM1uFTknikaXwd9Rw5/HZhW4hXP5EeM2x
12
+ rcaYtXudhUyG/AWCrRPpHdGGNpHPmpwKUw3uADYAb2Hicjswx34kmWAbcwVJMs8d
13
+ 3QR/4hyrJnVSgYAB8/5oiNsnvaF/sO6/9KkDFpF03QKBgQDxrVJznfA0xgeVTGxt
14
+ sLRhbsUyVn5tHteEdbvbTGLfl80Dayzlht9rTrjYXgQUevw40+chQW8LPEA8gmyM
15
+ oCyAMouk+DJ5rl75jQnQh1/pob+ReyFi7Jl4D6Ro8J6gP6nds+wZ/BN5WLNtd/KI
16
+ BMwi4fEyKjT7nKTVFNQlrZEG6wKBgQDHng2nFYbSEKv1lb5HabSxJ1bbTHld0lzI
17
+ tn5zEmZ9PW6jBM0UJMEmkPRAvzhGGnzbRM0hYhiZR1FBR9T6BCJb+1N0HfT0Xo2X
18
+ MTOuz8auLRtH73SCRbRoxVbz+TFmLVQuwAXdwIT+p4AgEqoJ+QyMKwuwr70AGZmm
19
+ SkL08Bp7RQKBgQDYZfOgJtmAx5jerFGiXkkFvSPBkQUfPDCKIMmW8WzO/KPL3dmT
20
+ pBLFiPWmd3h7xiu1zrf0ZRzDGK4EAFymBn4SRDAaBUtc/S95kDoriCvvjK912qTo
21
+ aSZ6BLeYZ2wB3T+CjqpoEfh1/WCcMnzuIi2PRnSsEHLkoTxOt5nGKwXjBQKBgDve
22
+ o6mhQzZt2aVmrBMvGQqpCdvsK9p/5WQtl+9bbXHSowQxxHBuNaAjiZ6Bu5cLCreZ
23
+ Aw0oJsiSI0S5Dp+N7eA4mOcStQ017rGSCDY+CxDiZnRE1WTdEyb5SQMTkkVbAwyi
24
+ ex/vRfQ6uKrl7infkGvZ3T+49a65/uNpEnv0J30hAoGBAJwhlCGf3BhMPrXjXGsp
25
+ qxtCAbnaARErq0cI/nP6EKv8U0zOte09j/KKqFhckzsN3Df+P7dSuciIbFEDFY8Y
26
+ aWVRMDF/owMo7qrb/Hyvt72gRtRAeypN1Zf7Uy7JtP7PMqdvMynK0xSdrGAl4UCV
27
+ 6AOSsKQotsgA2R1PKV89Rn2R
28
+ -----END PRIVATE KEY-----
@@ -1,19 +1,43 @@
1
1
  // @ts-check
2
- const http = require("http");
3
2
  const {
4
3
  parseRequestParams,
5
4
  createHandler,
6
5
  } = require("graphql-http/lib/use/http");
7
6
  const { buildSchema } = require("graphql");
8
7
  const { Trie } = require("@wry/trie");
8
+ const { readFileSync } = require("fs");
9
+ const { join } = require("path");
9
10
 
10
- function runMockServer(
11
+ async function runMockServer(
11
12
  /** @type {number} */ port,
12
- onStart = (/** @type {number} */ port) => {},
13
+ useSelfSignedCert = false,
14
+ onStart = (/** @type {string} */ baseUri) => {},
13
15
  ) {
14
16
  const mocks = new Trie(false);
15
17
 
16
- const server = http.createServer(async (req, res) => {
18
+ /**
19
+ *
20
+ * @param {import('node:http').RequestListener} listener
21
+ * @returns
22
+ */
23
+ function createServer(listener) {
24
+ if (useSelfSignedCert) {
25
+ return require("node:https").createServer(
26
+ {
27
+ key: readFileSync(
28
+ join(__dirname, "../../sampleWorkspace/httpSchema/self-signed.key"),
29
+ ),
30
+ cert: readFileSync(
31
+ join(__dirname, "../../sampleWorkspace/httpSchema/self-signed.crt"),
32
+ ),
33
+ },
34
+ listener,
35
+ );
36
+ }
37
+ return require("node:http").createServer(listener);
38
+ }
39
+
40
+ const server = createServer(async (req, res) => {
17
41
  if (req.url === "/apollo") {
18
42
  if (req.method === "POST") {
19
43
  await handleApolloPost(req, res);
@@ -33,8 +57,9 @@ function runMockServer(
33
57
 
34
58
  console.log("Starting server...");
35
59
  server.listen(port);
36
- onStart(port);
37
- console.log(`Server ready at: http://localhost:${port}`);
60
+ const baseUri = `${useSelfSignedCert ? "https" : "http"}://localhost:${port}`;
61
+ await onStart(baseUri);
62
+ console.log(`Server ready at: ${baseUri}`);
38
63
  return {
39
64
  [Symbol.dispose]() {
40
65
  console.log("Closing server...");
@@ -45,8 +70,8 @@ function runMockServer(
45
70
 
46
71
  /**
47
72
  * Mock GraphQL Endpoint Handler
48
- * @param {http.IncomingMessage} req
49
- * @param {http.ServerResponse} res
73
+ * @param {import('node:http').IncomingMessage} req
74
+ * @param {import('node:http').ServerResponse} res
50
75
  */
51
76
  async function handleApolloPost(req, res) {
52
77
  const { operationName, variables } =
@@ -79,8 +104,8 @@ function runMockServer(
79
104
 
80
105
  /**
81
106
  * Handler to accept new GraphQL Mocks
82
- * @param {http.IncomingMessage} req
83
- * @param {http.ServerResponse} res
107
+ * @param {import('node:http').IncomingMessage} req
108
+ * @param {import('node:http').ServerResponse} res
84
109
  */
85
110
  async function handleApolloPut(req, res) {
86
111
  const body = await new Promise((resolve) => {
@@ -111,7 +136,8 @@ const schemaHandler = createHandler({
111
136
  });
112
137
 
113
138
  if (require.main === module) {
114
- runMockServer(7096, require("./mocks.js").loadDefaultMocks);
139
+ runMockServer(7096, false, require("./mocks.js").loadDefaultMocks);
140
+ runMockServer(7097, true, require("./mocks.js").loadDefaultMocks);
115
141
  }
116
142
 
117
143
  module.exports.runMockServer = runMockServer;
@@ -1,26 +1,30 @@
1
1
  // @ts-check
2
-
3
- async function loadDefaultMocks(/** @type {number} */ port) {
4
- await sendMock(port, FrontendUrlRoot);
5
- await sendMock(port, SchemaTagsAndFieldStats);
6
- await sendMock(port, GetSchemaByTag);
2
+ async function loadDefaultMocks(/** @type {string} */ baseUri) {
3
+ await sendMock(baseUri, FrontendUrlRoot);
4
+ await sendMock(baseUri, SchemaTagsAndFieldStats);
5
+ await sendMock(baseUri, GetSchemaByTag);
7
6
  }
8
7
 
9
8
  function sendMock(
10
- /** @type {number} */ port,
9
+ /** @type {string} */ baseUri,
11
10
  /** @type { { operationName: string, variables: Record<string, string>, response: unknown }} */ {
12
11
  operationName,
13
12
  variables,
14
13
  response,
15
14
  },
16
15
  ) {
17
- return fetch(`http://localhost:${port}/apollo`, {
16
+ return require("undici").fetch(`${baseUri}/apollo`, {
18
17
  method: "PUT",
19
18
  body: JSON.stringify({
20
19
  operationName,
21
20
  variables,
22
21
  response,
23
22
  }),
23
+ dispatcher: new (require("undici").Agent)({
24
+ connect: {
25
+ rejectUnauthorized: false,
26
+ },
27
+ }),
24
28
  });
25
29
  }
26
30
 
@@ -5,7 +5,7 @@ const { runMockServer } = require("./mockServer.js");
5
5
  const { loadDefaultMocks } = require("./mocks.js");
6
6
 
7
7
  async function main() {
8
- let disposable;
8
+ const disposables = /**{@type Disposable[]}*/ [];
9
9
  try {
10
10
  // The folder containing the Extension Manifest package.json
11
11
  // Passed to `--extensionDevelopmentPath`
@@ -18,8 +18,12 @@ async function main() {
18
18
  const TEST_PORT = 7096;
19
19
  process.env.APOLLO_ENGINE_ENDPOINT = "http://localhost:7096/apollo";
20
20
  process.env.MOCK_SERVER_PORT = String(TEST_PORT);
21
- disposable = runMockServer(TEST_PORT);
22
- await loadDefaultMocks(TEST_PORT);
21
+ disposables.push(
22
+ ...(await Promise.all([
23
+ runMockServer(TEST_PORT, false, loadDefaultMocks),
24
+ runMockServer(TEST_PORT + 1, true, loadDefaultMocks),
25
+ ])),
26
+ );
23
27
  // Download VS Code, unzip it and run the integration test
24
28
  const exitCode = await runTests({
25
29
  extensionDevelopmentPath,
@@ -35,9 +39,7 @@ async function main() {
35
39
  console.error("Failed to run tests");
36
40
  process.exit(1);
37
41
  } finally {
38
- if (disposable) {
39
- disposable[Symbol.dispose]();
40
- }
42
+ disposables.forEach((d) => d[Symbol.dispose]());
41
43
  }
42
44
  }
43
45
 
@@ -37,9 +37,10 @@ Get detailed profile information about the current user (including the current u
37
37
  });
38
38
 
39
39
  test("wrong token", async () => {
40
+ const baseUri = `http://localhost:${mockPort}`;
40
41
  try {
41
- await mocks.sendMock(mockPort, mocks.GetSchemaByTag_WRONG_TOKEN);
42
- await mocks.sendMock(mockPort, mocks.SchemaTagsAndFieldStats_WRONG_TOKEN);
42
+ await mocks.sendMock(baseUri, mocks.GetSchemaByTag_WRONG_TOKEN);
43
+ await mocks.sendMock(baseUri, mocks.SchemaTagsAndFieldStats_WRONG_TOKEN);
43
44
 
44
45
  const ext = getExtension();
45
46
  ext.outputChannel.clear();
@@ -59,7 +60,7 @@ Invalid credentials provided
59
60
  at new ApolloError`.trim(),
60
61
  );
61
62
  } finally {
62
- await mocks.loadDefaultMocks(mockPort);
63
+ await mocks.loadDefaultMocks(baseUri);
63
64
  await reloadService();
64
65
  }
65
66
  });
@@ -99,9 +99,6 @@ Object {
99
99
  "**/node_modules",
100
100
  "**/__tests__",
101
101
  ],
102
- "includes": Array [
103
- "src/**/*.{ts,tsx,js,jsx,graphql,gql}",
104
- ],
105
102
  "service": "hello",
106
103
  "tagName": "gql",
107
104
  },
@@ -137,6 +134,7 @@ Object {
137
134
  },
138
135
  "rover": Object {
139
136
  "bin": "${dir}/bin/rover",
137
+ "extraArgs": Array [],
140
138
  },
141
139
  }
142
140
  `);
@@ -395,9 +393,14 @@ Object {
395
393
  configPath: dirPath,
396
394
  });
397
395
 
398
- expect((config?.rawConfig as any).client.includes).toEqual([
399
- "src/**/*.{ts,tsx,js,jsx,graphql,gql}",
400
- ]);
396
+ expect((config?.rawConfig as any).client.includes).toEqual(
397
+ /**
398
+ * This will be calculated in the `GraphQLInternalProject` constructor by calling `getSupportedExtensions()`
399
+ * which will have information about all the extensions added by other VSCode extensions for the language ids
400
+ * that Apollo supports.
401
+ */
402
+ undefined,
403
+ );
401
404
  });
402
405
 
403
406
  it("merges engine config defaults", async () => {
@@ -1,13 +1,14 @@
1
- import { dirname } from "path";
1
+ import { dirname, join } from "path";
2
2
  import { URI } from "vscode-uri";
3
3
  import { getGraphIdFromConfig, parseServiceSpecifier } from "./utils";
4
4
  import { Debug } from "../utilities";
5
5
  import z, { ZodError } from "zod";
6
6
  import { ValidationRule } from "graphql/validation/ValidationContext";
7
- import { Slot } from "@wry/context";
8
7
  import { fromZodError } from "zod-validation-error";
9
8
  import which from "which";
10
9
  import { accessSync, constants as fsConstants, statSync } from "node:fs";
10
+ import { AsyncLocalStorage } from "async_hooks";
11
+ import { existsSync } from "fs";
11
12
 
12
13
  const ROVER_AVAILABLE = (process.env.APOLLO_FEATURE_FLAGS || "")
13
14
  .split(",")
@@ -29,8 +30,9 @@ function ignoredFieldWarning(
29
30
  export interface Context {
30
31
  apiKey?: string;
31
32
  serviceName?: string;
33
+ configPath?: string;
32
34
  }
33
- const context = new Slot<Context>();
35
+ const contextStore = new AsyncLocalStorage<Context>();
34
36
 
35
37
  const studioServiceConfig = z.string();
36
38
 
@@ -49,7 +51,7 @@ const localServiceConfig = z.object({
49
51
  export type LocalServiceConfig = z.infer<typeof localServiceConfig>;
50
52
 
51
53
  const clientServiceConfig = z.preprocess(
52
- (value) => value || context.getValue()?.serviceName,
54
+ (value) => value || contextStore.getStore()?.serviceName,
53
55
  z.union([studioServiceConfig, remoteServiceConfig, localServiceConfig]),
54
56
  );
55
57
  export type ClientServiceConfig = z.infer<typeof clientServiceConfig>;
@@ -63,9 +65,7 @@ const clientConfig = z.object({
63
65
  ])
64
66
  .optional(),
65
67
  // maybe shared with rover?
66
- includes: z
67
- .array(z.string())
68
- .default(["src/**/*.{ts,tsx,js,jsx,graphql,gql}"]),
68
+ includes: z.array(z.string()).optional(),
69
69
  // maybe shared with rover?
70
70
  excludes: z.array(z.string()).default(["**/node_modules", "**/__tests__"]),
71
71
  // maybe shared with rover?
@@ -106,6 +106,21 @@ const roverConfig = z.object({
106
106
  },
107
107
  ),
108
108
  profile: z.string().optional(),
109
+ supergraphConfig: z
110
+ .preprocess((value) => {
111
+ if (value !== undefined) return value;
112
+ const configPath = contextStore.getStore()?.configPath!;
113
+ const supergraphConfig = join(configPath, "supergraph.yaml");
114
+ return existsSync(supergraphConfig) ? supergraphConfig : undefined;
115
+ }, z.string().nullable().optional())
116
+ .describe(
117
+ "The path to your `supergraph.yaml` file. \n" +
118
+ "Defaults to a `supergraph.yaml` in the folder of your `apollo.config.js`, if there is one.",
119
+ ),
120
+ extraArgs: z
121
+ .array(z.string())
122
+ .default([])
123
+ .describe("Extra arguments to pass to the Rover CLI."),
109
124
  });
110
125
  type RoverConfigFormat = z.infer<typeof roverConfig>;
111
126
 
@@ -117,7 +132,7 @@ const engineConfig = z.object({
117
132
  "https://graphql.api.apollographql.com/api/graphql",
118
133
  ),
119
134
  apiKey: z.preprocess(
120
- (val) => val || context.getValue()?.apiKey,
135
+ (val) => val || contextStore.getStore()?.apiKey,
121
136
  z.string().optional(),
122
137
  ),
123
138
  });
@@ -202,9 +217,7 @@ export function parseApolloConfig(
202
217
  configURI?: URI,
203
218
  ctx: Context = {},
204
219
  ) {
205
- const parsed = context.withValue(ctx, () =>
206
- configSchema.safeParse(rawConfig),
207
- );
220
+ const parsed = contextStore.run(ctx, () => configSchema.safeParse(rawConfig));
208
221
  if (!parsed.success) {
209
222
  // Remove "or Required at rover" errors when a client config is provided
210
223
  // Remove "or Required at client" errors when a rover config is provided
@@ -1,5 +1,5 @@
1
1
  import { cosmiconfig, defaultLoaders } from "cosmiconfig";
2
- import { resolve } from "path";
2
+ import { dirname, resolve } from "path";
3
3
  import { readFileSync, existsSync, lstatSync } from "fs";
4
4
  import {
5
5
  ApolloConfig,
@@ -103,5 +103,6 @@ export async function loadConfig({
103
103
  return parseApolloConfig(config, URI.file(resolve(filepath)), {
104
104
  apiKey,
105
105
  serviceName: nameFromKey,
106
+ configPath: dirname(filepath),
106
107
  });
107
108
  }
@@ -14,12 +14,10 @@ export class FileSet {
14
14
  rootURI,
15
15
  includes,
16
16
  excludes,
17
- configURI,
18
17
  }: {
19
18
  rootURI: URI;
20
19
  includes: string[];
21
20
  excludes: string[];
22
- configURI?: URI;
23
21
  }) {
24
22
  invariant(rootURI, `Must provide "rootURI".`);
25
23
  invariant(includes, `Must provide "includes".`);
@@ -30,13 +28,6 @@ export class FileSet {
30
28
  this.excludes = excludes;
31
29
  }
32
30
 
33
- pushIncludes(files: string[]) {
34
- this.includes.push(...files);
35
- }
36
- pushExcludes(files: string[]) {
37
- this.excludes.push(...files);
38
- }
39
-
40
31
  includesFile(filePath: string): boolean {
41
32
  const normalizedFilePath = normalizeURI(filePath);
42
33
 
@@ -57,10 +48,14 @@ export class FileSet {
57
48
  }
58
49
 
59
50
  allFiles(): string[] {
60
- // since glob.sync takes a single pattern, but we allow an array of `includes`, we can join all the
61
- // `includes` globs into a single pattern and pass to glob.sync. The `ignore` option does, however, allow
62
- // an array of globs to ignore, so we can pass it in directly
63
- const joinedIncludes = `{${this.includes.join(",")}}`;
51
+ const joinedIncludes =
52
+ this.includes.length == 1
53
+ ? this.includes[0]
54
+ : // since glob.sync takes a single pattern, but we allow an array of `includes`, we can join all the
55
+ // `includes` globs into a single pattern and pass to glob.sync. The `ignore` option does, however, allow
56
+ // an array of globs to ignore, so we can pass it in directly
57
+ `{${this.includes.join(",")}}`;
58
+
64
59
  return globSync(joinedIncludes, {
65
60
  cwd: this.rootURI.fsPath,
66
61
  absolute: true,