vscode-apollo 2.3.6 → 2.5.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/.github/workflows/E2E.yml +42 -5
- package/.nvmrc +1 -1
- package/.vscodeignore +3 -0
- package/CHANGELOG.md +16 -0
- package/images/apollo.svg +16 -0
- package/package.json +54 -3
- package/sampleWorkspace/sampleWorkspace.code-workspace +4 -1
- package/src/build.js +4 -0
- package/src/debug.ts +39 -0
- package/src/devtools/DevToolsViewProvider.ts +182 -0
- package/src/devtools/server.ts +86 -0
- package/src/extension.ts +80 -1
- package/src/language-server/__e2e__/rover.e2e.ts +5 -0
- package/src/language-server/__e2e__/studioGraph.e2e.ts +2 -2
- package/src/language-server/fileSet.ts +3 -3
- package/src/language-server/project/internal.ts +1 -0
- package/src/language-server/server.ts +5 -6
- package/src/language-server/utilities/uri.ts +1 -1
- package/src/tools/utilities/languageInformation.ts +1 -1
- package/start-ac.mjs +60 -0
|
@@ -7,26 +7,63 @@ on:
|
|
|
7
7
|
jobs:
|
|
8
8
|
test:
|
|
9
9
|
name: Run E2E tests
|
|
10
|
-
runs-on:
|
|
10
|
+
runs-on: "${{ matrix.os }}"
|
|
11
11
|
strategy:
|
|
12
12
|
matrix:
|
|
13
13
|
version: ["1.90.0", "stable", "insiders"]
|
|
14
|
+
os: [ubuntu-latest]
|
|
15
|
+
include:
|
|
16
|
+
- version: "stable"
|
|
17
|
+
os: "windows-latest"
|
|
14
18
|
steps:
|
|
15
|
-
- run: sudo apt update && sudo apt install -y
|
|
19
|
+
- run: sudo apt update && sudo apt install -y libasound2t64 libgbm1 libgtk-3-0 libnss3 xvfb expect
|
|
20
|
+
if: runner.os == 'Linux'
|
|
16
21
|
- uses: actions/checkout@v4
|
|
17
22
|
- uses: actions/setup-node@v4
|
|
18
23
|
with:
|
|
19
24
|
cache: "npm"
|
|
20
25
|
- run: npm install
|
|
21
|
-
- run: npm run build:production
|
|
22
26
|
- run: echo 'APOLLO_KEY="service:bob-123:489fhseo4"' > ./sampleWorkspace/spotifyGraph/.env
|
|
23
|
-
|
|
27
|
+
shell: bash
|
|
28
|
+
- name: Install & Configure Rover (Linux)
|
|
29
|
+
run: |
|
|
24
30
|
expect <<EOF
|
|
25
31
|
spawn ./node_modules/.bin/rover config auth --profile VSCode-E2E
|
|
26
32
|
expect "Copy the key and paste it into the prompt below."
|
|
27
33
|
send -- "test\n"
|
|
28
34
|
expect eof
|
|
29
35
|
EOF
|
|
30
|
-
|
|
36
|
+
if: runner.os == 'Linux'
|
|
37
|
+
- name: Install Rover (Windows)
|
|
38
|
+
run: ./node_modules/.bin/rover.cmd --version
|
|
39
|
+
if: runner.os == 'Windows'
|
|
40
|
+
- name: Configure Rover (Windows)
|
|
41
|
+
run: |
|
|
42
|
+
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
|
43
|
+
Start-Process -FilePath ./node_modules/.bin/rover.cmd -ArgumentList "config","auth","--profile","VSCode-E2E"
|
|
44
|
+
|
|
45
|
+
Start-Sleep -m 1000
|
|
46
|
+
|
|
47
|
+
[System.Windows.Forms.SendKeys]::SendWait("test")
|
|
48
|
+
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
|
|
49
|
+
if: runner.os == 'Windows'
|
|
50
|
+
shell: powershell
|
|
51
|
+
- name: Adjust configuration (Windows)
|
|
52
|
+
run: |
|
|
53
|
+
sed -i -e 's/\(bin:.*\)/\1.exe/' sampleWorkspace/rover/apollo.config.yaml
|
|
54
|
+
cat sampleWorkspace/rover/apollo.config.yaml
|
|
55
|
+
# for some reason, windows seems to ignore the jest.e2e.config.js file
|
|
56
|
+
echo "module.exports = require('./jest.e2e.config')" > jest.config.ts
|
|
57
|
+
shell: bash
|
|
58
|
+
if: runner.os == 'Windows'
|
|
59
|
+
- run: npm run build:production
|
|
60
|
+
- name: "Run Extension E2E tests (Linux)"
|
|
61
|
+
run: xvfb-run -a npm run test:extension
|
|
62
|
+
env:
|
|
63
|
+
VSCODE_VERSION: "${{ matrix.version }}"
|
|
64
|
+
if: runner.os == 'Linux'
|
|
65
|
+
- name: "Run Extension E2E tests (Windows)"
|
|
66
|
+
run: npm run test:extension
|
|
31
67
|
env:
|
|
32
68
|
VSCODE_VERSION: "${{ matrix.version }}"
|
|
69
|
+
if: runner.os == 'Windows'
|
package/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
22
|
package/.vscodeignore
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 2.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#188](https://github.com/apollographql/vscode-graphql/pull/188) [`595784f0`](https://github.com/apollographql/vscode-graphql/commit/595784f057de18d987768fa1aaa8c37a5fa802c7) Thanks [@phryneas](https://github.com/phryneas)! - Adds experimental integration of the Apollo Client DevTools
|
|
8
|
+
|
|
9
|
+
## 2.4.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#236](https://github.com/apollographql/vscode-graphql/pull/236) [`9a4403db`](https://github.com/apollographql/vscode-graphql/commit/9a4403db7b8f9cb03638d83a7e3c29dd3c3077b7) Thanks [@pubmodmatt](https://github.com/pubmodmatt)! - Add support for GraphQL in Notebook cells
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#240](https://github.com/apollographql/vscode-graphql/pull/240) [`3dfd9ac0`](https://github.com/apollographql/vscode-graphql/commit/3dfd9ac08a20ff92cafb398f1a8c71e5f7d03519) Thanks [@phryneas](https://github.com/phryneas)! - Fix a bug handling windows path separators in `FileSet` instances.
|
|
18
|
+
|
|
3
19
|
## 2.3.6
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<style>
|
|
3
|
+
g {
|
|
4
|
+
fill: black;
|
|
5
|
+
}
|
|
6
|
+
@media (prefers-color-scheme: dark) {
|
|
7
|
+
g {
|
|
8
|
+
fill: white;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
</style>
|
|
12
|
+
<g>
|
|
13
|
+
<polygon points="112.246 49 88.003 49 53 139.848 74.927 139.848 80.648 124.455 113.724 124.455 107.735 107.431 85.961 107.431 100.125 68.34 125.324 139.848 147.252 139.848"></polygon>
|
|
14
|
+
<path d="M196.313,73.038 C196.254,72.728 196.17,72.428 196.057,72.141 C196.03,72.041 195.937,71.856 195.937,71.856 C195.148,70.138 193.414,68.942 191.399,68.942 C188.637,68.942 186.399,71.181 186.399,73.942 C186.399,74.504 186.497,75.042 186.667,75.545 L186.653,75.55 C188.859,83.407 189.999,91.615 189.999,100.001 C189.999,124.04 180.637,146.642 163.64,163.641 C146.641,180.641 124.04,190.001 100,190.001 C75.961,190.001 53.358,180.639 36.361,163.641 C19.36,146.642 10,124.04 10,100.001 C10,75.961 19.362,53.36 36.361,36.361 C53.358,19.361 75.961,10.001 100,10.001 C121.466,10.001 141.781,17.471 157.987,31.174 C157.443,32.56 157.139,34.068 157.139,35.648 C157.139,42.399 162.611,47.869 169.363,47.869 C176.113,47.869 181.586,42.399 181.586,35.648 C181.586,28.897 176.113,23.424 169.363,23.424 C167.89,23.424 166.479,23.684 165.171,24.161 C147.666,9.107 124.9,0 100,0 C44.771,0 0,44.772 0,100.001 C0,155.23 44.771,200.002 100,200.002 C155.229,200.002 200,155.231 200,100.001 C200,90.659 198.709,81.617 196.313,73.038 Z"></path>
|
|
15
|
+
</g>
|
|
16
|
+
</svg>
|
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.
|
|
5
|
+
"version": "2.5.0",
|
|
6
6
|
"referenceID": "87197759-7617-40d0-b32e-46d378e907c7",
|
|
7
7
|
"author": "Apollo GraphQL <opensource@apollographql.com>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"vscode": "^1.90.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@apollo/client": "3.
|
|
40
|
+
"@apollo/client": "3.12.2",
|
|
41
|
+
"@apollo/client-devtools-vscode": "^4.19.0",
|
|
41
42
|
"@apollo/subgraph": "2.9.1",
|
|
42
43
|
"@graphql-tools/schema": "10.0.6",
|
|
43
44
|
"@wry/equality": "0.5.7",
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"vscode-languageserver-textdocument": "1.0.12",
|
|
63
64
|
"vscode-uri": "3.0.8",
|
|
64
65
|
"which": "4.0.0",
|
|
66
|
+
"ws": "8.18.0",
|
|
65
67
|
"zod": "3.23.8",
|
|
66
68
|
"zod-validation-error": "3.4.0"
|
|
67
69
|
},
|
|
@@ -138,6 +140,23 @@
|
|
|
138
140
|
"default": true,
|
|
139
141
|
"markdownDescription": "Show a \"Run in Studio\" button to the right of Operation Signatures.",
|
|
140
142
|
"scope": "window"
|
|
143
|
+
},
|
|
144
|
+
"apollographql.devTools.showPanel": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": [
|
|
147
|
+
"always",
|
|
148
|
+
"never",
|
|
149
|
+
"detect"
|
|
150
|
+
],
|
|
151
|
+
"default": "never",
|
|
152
|
+
"markdownDescription": "[Experimental Feature] If the Apollo Client DevTools panel should be shown. If set to `detect`, the panel will only be shown if a configuration file with a client project is found in the workspace.",
|
|
153
|
+
"scope": "window"
|
|
154
|
+
},
|
|
155
|
+
"apollographql.devTools.serverPort": {
|
|
156
|
+
"type": "number",
|
|
157
|
+
"default": 7095,
|
|
158
|
+
"markdownDescription": "The Apollo Client DevTools server port. The server will be started as soon as you start using the DevTools panels.",
|
|
159
|
+
"scope": "window"
|
|
141
160
|
}
|
|
142
161
|
}
|
|
143
162
|
},
|
|
@@ -279,8 +298,40 @@
|
|
|
279
298
|
"command": "apollographql/showStats",
|
|
280
299
|
"title": "Show Status",
|
|
281
300
|
"category": "Apollo"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"command": "apollographql/startDevToolsServer",
|
|
304
|
+
"title": "Start Apollo Client DevTools Server",
|
|
305
|
+
"category": "Apollo",
|
|
306
|
+
"when": "config.apollographql.devTools.showPanel=='always' || (config.apollographql.devTools.showPanel=='detect' && vscode-apollo.hasClientProject)"
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"command": "apollographql/stopDevToolsServer",
|
|
310
|
+
"title": "Stop Apollo Client DevTools Server",
|
|
311
|
+
"category": "Apollo",
|
|
312
|
+
"when": "config.apollographql.devTools.showPanel=='always' || (config.apollographql.devTools.showPanel=='detect' && vscode-apollo.hasClientProject)"
|
|
282
313
|
}
|
|
283
|
-
]
|
|
314
|
+
],
|
|
315
|
+
"viewsContainers": {
|
|
316
|
+
"panel": [
|
|
317
|
+
{
|
|
318
|
+
"id": "client-devtools",
|
|
319
|
+
"title": "Apollo Client DevTools",
|
|
320
|
+
"icon": "images/apollo.svg"
|
|
321
|
+
}
|
|
322
|
+
]
|
|
323
|
+
},
|
|
324
|
+
"views": {
|
|
325
|
+
"client-devtools": [
|
|
326
|
+
{
|
|
327
|
+
"type": "webview",
|
|
328
|
+
"id": "vscode-apollo-client-devtools",
|
|
329
|
+
"name": "Apollo Client DevTools",
|
|
330
|
+
"icon": "images/apollo.svg",
|
|
331
|
+
"when": "config.apollographql.devTools.showPanel=='always' || (config.apollographql.devTools.showPanel=='detect' && vscode-apollo.hasClientProject)"
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
}
|
|
284
335
|
},
|
|
285
336
|
"galleryBanner": {
|
|
286
337
|
"color": "#1d127d",
|
package/src/build.js
CHANGED
|
@@ -11,6 +11,10 @@ async function main() {
|
|
|
11
11
|
entryPoints: [
|
|
12
12
|
"src/extension.ts",
|
|
13
13
|
"src/language-server/server.ts",
|
|
14
|
+
{
|
|
15
|
+
in: require.resolve("@apollo/client-devtools-vscode/panel"),
|
|
16
|
+
out: "panel",
|
|
17
|
+
},
|
|
14
18
|
"src/language-server/config/config.ts",
|
|
15
19
|
"src/language-server/config/cache-busting-resolver.js",
|
|
16
20
|
],
|
package/src/debug.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { OutputChannel } from "vscode";
|
|
2
|
+
import { TraceValues } from "vscode-languageclient";
|
|
3
|
+
import { format } from "node:util";
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* for errors (and other logs in debug mode) we want to print
|
|
@@ -21,6 +23,21 @@ export class Debug {
|
|
|
21
23
|
this.outputConsole = outputConsole;
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
private static _traceLevel: Exclude<TraceValues, "compact"> = "off";
|
|
27
|
+
public static get traceLevel(): TraceValues {
|
|
28
|
+
return Debug._traceLevel;
|
|
29
|
+
}
|
|
30
|
+
public static set traceLevel(value: TraceValues | undefined) {
|
|
31
|
+
console.log("setting trace level to", value);
|
|
32
|
+
if (value === "compact") {
|
|
33
|
+
// we do not handle "compact" and it's not possible to set in settings, but it doesn't hurt to at least map
|
|
34
|
+
// it to another value
|
|
35
|
+
this._traceLevel = "messages";
|
|
36
|
+
} else {
|
|
37
|
+
this._traceLevel = value || "off";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
24
41
|
/**
|
|
25
42
|
* Displays an info message prefixed with [INFO]
|
|
26
43
|
*/
|
|
@@ -55,6 +72,28 @@ export class Debug {
|
|
|
55
72
|
this.outputConsole.appendLine(`[WARN] ${message}`);
|
|
56
73
|
}
|
|
57
74
|
|
|
75
|
+
public static traceMessage(
|
|
76
|
+
short: string,
|
|
77
|
+
verbose = short,
|
|
78
|
+
...verboseParams: any[]
|
|
79
|
+
) {
|
|
80
|
+
if (!this.outputConsole) return;
|
|
81
|
+
if (Debug.traceLevel === "verbose") {
|
|
82
|
+
this.outputConsole.appendLine(
|
|
83
|
+
`[Trace] ${format(verbose, ...verboseParams)}`,
|
|
84
|
+
);
|
|
85
|
+
} else if (Debug.traceLevel === "messages") {
|
|
86
|
+
this.outputConsole.appendLine(`[Trace] ${short}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public static traceVerbose(message: string, ...params: any[]) {
|
|
91
|
+
if (!this.outputConsole) return;
|
|
92
|
+
if (Debug.traceLevel === "verbose") {
|
|
93
|
+
this.outputConsole.appendLine(`[Trace] ${format(message, ...params)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
58
97
|
/**
|
|
59
98
|
* TODO: enable error reporting and telemetry
|
|
60
99
|
*/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as vscode from "vscode";
|
|
2
|
+
import { devtoolsEvents, sendToDevTools, serverState } from "./server";
|
|
3
|
+
|
|
4
|
+
type ActorMessage = { type: "actor"; message: unknown };
|
|
5
|
+
|
|
6
|
+
export function isActorMessage(message: any): message is ActorMessage {
|
|
7
|
+
return message && message.type === "actor";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type DevToolsOpenCommandMessage = {
|
|
11
|
+
type: "vscode:executeCommand";
|
|
12
|
+
command: string;
|
|
13
|
+
arguments?: unknown[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function isDevToolsExecuteCommandMessage(
|
|
17
|
+
message: any,
|
|
18
|
+
): message is DevToolsOpenCommandMessage {
|
|
19
|
+
return message && message.type === "vscode:executeCommand";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type DevToolsOpenExternalMessage = {
|
|
23
|
+
type: "vscode:openExternal";
|
|
24
|
+
uri: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function isDevToolsOpenExternalMessage(
|
|
28
|
+
message: any,
|
|
29
|
+
): message is DevToolsOpenExternalMessage {
|
|
30
|
+
return message && message.type === "vscode:openExternal";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class DevToolsViewProvider implements vscode.WebviewViewProvider {
|
|
34
|
+
public static readonly viewType = "vscode-apollo-client-devtools";
|
|
35
|
+
|
|
36
|
+
constructor(private readonly _extensionUri: vscode.Uri) {}
|
|
37
|
+
|
|
38
|
+
async resolveWebviewView(
|
|
39
|
+
panel: vscode.WebviewView,
|
|
40
|
+
context: vscode.WebviewViewResolveContext,
|
|
41
|
+
token: vscode.CancellationToken,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
vscode.commands.executeCommand("apollographql/startDevToolsServer");
|
|
44
|
+
panel.webview.options = {
|
|
45
|
+
enableScripts: true,
|
|
46
|
+
localResourceRoots: [this._extensionUri],
|
|
47
|
+
};
|
|
48
|
+
panel.webview.html = DevToolsViewProvider._getHtmlForWebview(
|
|
49
|
+
panel.webview,
|
|
50
|
+
this._extensionUri,
|
|
51
|
+
);
|
|
52
|
+
const panelDisposables: vscode.Disposable[] = [];
|
|
53
|
+
panel.webview.onDidReceiveMessage(
|
|
54
|
+
(data) => {
|
|
55
|
+
if (data.source === "apollo-client-devtools") {
|
|
56
|
+
devtoolsEvents.emit("fromDevTools", data);
|
|
57
|
+
}
|
|
58
|
+
if (data.source === "vscode-panel") {
|
|
59
|
+
if (data.type === "mounted") {
|
|
60
|
+
sendToDevTools({
|
|
61
|
+
type: "initializePanel",
|
|
62
|
+
initialContext: {
|
|
63
|
+
port:
|
|
64
|
+
serverState?.port ||
|
|
65
|
+
vscode.workspace
|
|
66
|
+
.getConfiguration("apollographql")
|
|
67
|
+
.get("devTools.serverPort", 0),
|
|
68
|
+
listening: !!serverState?.port,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
this,
|
|
75
|
+
panelDisposables,
|
|
76
|
+
);
|
|
77
|
+
function forwardToDevTools(data: unknown) {
|
|
78
|
+
panel.webview.postMessage(data);
|
|
79
|
+
}
|
|
80
|
+
devtoolsEvents.addListener("toDevTools", forwardToDevTools);
|
|
81
|
+
panel.onDidDispose(() => {
|
|
82
|
+
devtoolsEvents.removeListener("toDevTools", forwardToDevTools);
|
|
83
|
+
for (const disposable of panelDisposables) {
|
|
84
|
+
disposable.dispose();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private static _getHtmlForWebview(
|
|
90
|
+
webview: vscode.Webview,
|
|
91
|
+
extensionUri: vscode.Uri,
|
|
92
|
+
) {
|
|
93
|
+
// Get the local path to main script run in the webview, then convert it to a uri we can use in the webview.
|
|
94
|
+
const scriptUri = webview.asWebviewUri(
|
|
95
|
+
vscode.Uri.joinPath(extensionUri, "lib", "panel.js"),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Use a nonce to only allow a specific script to be run.
|
|
99
|
+
const nonce = getNonce();
|
|
100
|
+
|
|
101
|
+
return `
|
|
102
|
+
<!doctype html>
|
|
103
|
+
<html lang="en">
|
|
104
|
+
<head>
|
|
105
|
+
<meta charset="utf-8" />
|
|
106
|
+
|
|
107
|
+
<!--
|
|
108
|
+
Use a content security policy to only allow loading images from https or from our extension directory,
|
|
109
|
+
and only allow scripts that have a specific nonce.
|
|
110
|
+
-->
|
|
111
|
+
<meta http-equiv="Content-Security-Policy" content="
|
|
112
|
+
default-src 'none';
|
|
113
|
+
style-src ${webview.cspSource} https://fonts.googleapis.com 'unsafe-inline';
|
|
114
|
+
font-src ${webview.cspSource} https://fonts.gstatic.com;
|
|
115
|
+
img-src ${webview.cspSource} https:;
|
|
116
|
+
connect-src ${webview.cspSource} https://*.github.com;
|
|
117
|
+
script-src 'nonce-${nonce}';
|
|
118
|
+
frame-src https://*.apollographql.com/;
|
|
119
|
+
">
|
|
120
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
121
|
+
|
|
122
|
+
<title>Apollo Client DevTools</title>
|
|
123
|
+
<style>
|
|
124
|
+
html,
|
|
125
|
+
body {
|
|
126
|
+
overflow: hidden;
|
|
127
|
+
font-size: var(--vscode-font-size);
|
|
128
|
+
}
|
|
129
|
+
::-webkit-scrollbar {
|
|
130
|
+
display: none;
|
|
131
|
+
}
|
|
132
|
+
#devtools {
|
|
133
|
+
width: 100vw;
|
|
134
|
+
height: 100vh;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
138
|
+
<link
|
|
139
|
+
href="https://fonts.googleapis.com/css2?family=Fira+Code&family=Inter:wght@400;500;600;700&display=swap"
|
|
140
|
+
rel="stylesheet"
|
|
141
|
+
/>
|
|
142
|
+
</head>
|
|
143
|
+
<body class="text-primary dark:text-primary-dark">
|
|
144
|
+
<div id="devtools"></div>
|
|
145
|
+
<script nonce="${nonce}">
|
|
146
|
+
const vscode = acquireVsCodeApi();
|
|
147
|
+
try {
|
|
148
|
+
// remove VSCode default styles
|
|
149
|
+
_defaultStyles.remove();
|
|
150
|
+
} catch {}
|
|
151
|
+
window.originalPostMessage = window.postMessage;
|
|
152
|
+
window.postMessage = function wrapPostMessage (...args) {
|
|
153
|
+
if (args.length>1 && args[1].startsWith("vscode-webview://")) {
|
|
154
|
+
return window.originalPostMessage(...args);
|
|
155
|
+
}
|
|
156
|
+
return vscode.postMessage(...args);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// window.addEventListener("message", (event) => { console.debug(event); });
|
|
160
|
+
</script>
|
|
161
|
+
<script nonce="${nonce}" src="${scriptUri}"></script>
|
|
162
|
+
<script nonce="${nonce}">
|
|
163
|
+
window.postMessage({
|
|
164
|
+
source: "vscode-panel",
|
|
165
|
+
type: "mounted",
|
|
166
|
+
});
|
|
167
|
+
</script>
|
|
168
|
+
</body>
|
|
169
|
+
</html>
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function getNonce() {
|
|
175
|
+
let text = "";
|
|
176
|
+
const possible =
|
|
177
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
178
|
+
for (let i = 0; i < 32; i++) {
|
|
179
|
+
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
180
|
+
}
|
|
181
|
+
return text;
|
|
182
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { WebSocketServer } from "ws";
|
|
2
|
+
import { Disposable } from "vscode";
|
|
3
|
+
import { runServer } from "@apollo/client-devtools-vscode/vscode-server";
|
|
4
|
+
import { Debug } from "../debug";
|
|
5
|
+
import { EventEmitter } from "node:events";
|
|
6
|
+
|
|
7
|
+
export const devtoolsEvents = new EventEmitter<{
|
|
8
|
+
toDevTools: [unknown];
|
|
9
|
+
fromDevTools: [unknown];
|
|
10
|
+
}>();
|
|
11
|
+
devtoolsEvents.addListener("toDevTools", (msg) => {
|
|
12
|
+
Debug.traceMessage(
|
|
13
|
+
`WS > DevTools: ${
|
|
14
|
+
msg && typeof msg === "object" && "type" in msg ? msg.type : "unknown"
|
|
15
|
+
}`,
|
|
16
|
+
"WS > DevTools: %o",
|
|
17
|
+
msg,
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
devtoolsEvents.addListener("fromDevTools", (msg) => {
|
|
21
|
+
Debug.traceMessage(
|
|
22
|
+
`DevTools > WS: ${
|
|
23
|
+
msg && typeof msg === "object" && "type" in msg ? msg.type : "unknown"
|
|
24
|
+
}`,
|
|
25
|
+
"DevTools > WS: %o",
|
|
26
|
+
msg,
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
let id = 1;
|
|
31
|
+
|
|
32
|
+
export function sendToDevTools(message: unknown) {
|
|
33
|
+
devtoolsEvents.emit("toDevTools", {
|
|
34
|
+
id: `vscode-${id++}`,
|
|
35
|
+
source: "apollo-client-devtools",
|
|
36
|
+
type: "actor",
|
|
37
|
+
message,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export let serverState:
|
|
42
|
+
| { port: false | number; disposable: Disposable }
|
|
43
|
+
| undefined = undefined;
|
|
44
|
+
|
|
45
|
+
export function startServer(port: number) {
|
|
46
|
+
const state = {
|
|
47
|
+
port: false as false | number,
|
|
48
|
+
disposable: new Disposable(() => {
|
|
49
|
+
if (wss) {
|
|
50
|
+
wss.close();
|
|
51
|
+
wss = null;
|
|
52
|
+
}
|
|
53
|
+
if (serverState === state) {
|
|
54
|
+
serverState = undefined;
|
|
55
|
+
}
|
|
56
|
+
sendToDevTools({ type: "port.changed", port, listening: false });
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (serverState?.port === port) {
|
|
61
|
+
// nothing to do
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// changing port, stop the old server
|
|
65
|
+
serverState?.disposable.dispose();
|
|
66
|
+
serverState = state;
|
|
67
|
+
let wss: WebSocketServer | null = new WebSocketServer({ port });
|
|
68
|
+
wss.on("listening", () => {
|
|
69
|
+
state.port = port;
|
|
70
|
+
sendToDevTools({ type: "port.changed", port, listening: true });
|
|
71
|
+
});
|
|
72
|
+
wss.on("close", () => {
|
|
73
|
+
state.disposable.dispose();
|
|
74
|
+
});
|
|
75
|
+
runServer(wss, {
|
|
76
|
+
addListener: (listener) => {
|
|
77
|
+
devtoolsEvents.addListener("fromDevTools", listener);
|
|
78
|
+
return () => {
|
|
79
|
+
devtoolsEvents.removeListener("fromDevTools", listener);
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
postMessage: (message) => {
|
|
83
|
+
devtoolsEvents.emit("toDevTools", message);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
package/src/extension.ts
CHANGED
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
DecorationOptions,
|
|
9
9
|
commands,
|
|
10
10
|
QuickPickItem,
|
|
11
|
-
Disposable,
|
|
12
11
|
OutputChannel,
|
|
13
12
|
MarkdownString,
|
|
14
13
|
Range,
|
|
14
|
+
env,
|
|
15
15
|
} from "vscode";
|
|
16
16
|
import StatusBar from "./statusBar";
|
|
17
17
|
import { getLanguageServerClient } from "./languageServerClient";
|
|
@@ -27,6 +27,13 @@ import {
|
|
|
27
27
|
printStatsToClientOutputChannel,
|
|
28
28
|
} from "./utils";
|
|
29
29
|
import { Debug } from "./debug";
|
|
30
|
+
import {
|
|
31
|
+
DevToolsViewProvider,
|
|
32
|
+
isActorMessage,
|
|
33
|
+
isDevToolsExecuteCommandMessage,
|
|
34
|
+
isDevToolsOpenExternalMessage,
|
|
35
|
+
} from "./devtools/DevToolsViewProvider";
|
|
36
|
+
import { devtoolsEvents, serverState, startServer } from "./devtools/server";
|
|
30
37
|
|
|
31
38
|
const { version } = require("../package.json");
|
|
32
39
|
|
|
@@ -157,6 +164,17 @@ export async function activate(
|
|
|
157
164
|
} else {
|
|
158
165
|
statusBar.showLoadedState({ hasActiveTextEditor });
|
|
159
166
|
}
|
|
167
|
+
|
|
168
|
+
const containsClientConfig = response.some(
|
|
169
|
+
(item) => item && !isError(item) && "client" in item,
|
|
170
|
+
);
|
|
171
|
+
if (containsClientConfig) {
|
|
172
|
+
commands.executeCommand(
|
|
173
|
+
"setContext",
|
|
174
|
+
"vscode-apollo.hasClientProject",
|
|
175
|
+
true,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
160
178
|
} else {
|
|
161
179
|
Debug.error(
|
|
162
180
|
`Invalid response type in message apollographql/configFilesFound:\n${JSON.stringify(
|
|
@@ -329,6 +347,67 @@ export async function activate(
|
|
|
329
347
|
},
|
|
330
348
|
});
|
|
331
349
|
|
|
350
|
+
const provider = new DevToolsViewProvider(context.extensionUri);
|
|
351
|
+
context.subscriptions.push(
|
|
352
|
+
window.registerWebviewViewProvider(DevToolsViewProvider.viewType, provider),
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
function devToolsEventListener(event: unknown) {
|
|
356
|
+
if (!isActorMessage(event)) return;
|
|
357
|
+
const message = event.message;
|
|
358
|
+
if (isDevToolsExecuteCommandMessage(message)) {
|
|
359
|
+
commands.executeCommand(message.command, ...(message.arguments || []));
|
|
360
|
+
}
|
|
361
|
+
if (isDevToolsOpenExternalMessage(message)) {
|
|
362
|
+
env.openExternal(
|
|
363
|
+
// if we `Uri.parse` here, we end up with something that somehow double-encodes some things like `#`
|
|
364
|
+
// interestingly enough, the implementation of `openExternal` also allows for strings to be passed in
|
|
365
|
+
// directly, and that works - so we just pass in the string directly
|
|
366
|
+
message.uri as any as Uri,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
devtoolsEvents.addListener("fromDevTools", devToolsEventListener);
|
|
371
|
+
context.subscriptions.push({
|
|
372
|
+
dispose: () =>
|
|
373
|
+
devtoolsEvents.removeListener("fromDevTools", devToolsEventListener),
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
context.subscriptions.push(
|
|
377
|
+
commands.registerCommand("apollographql/startDevToolsServer", () => {
|
|
378
|
+
const port = workspace
|
|
379
|
+
.getConfiguration("apollographql")
|
|
380
|
+
.get("devTools.serverPort", 0);
|
|
381
|
+
startServer(port);
|
|
382
|
+
}),
|
|
383
|
+
);
|
|
384
|
+
context.subscriptions.push({
|
|
385
|
+
dispose() {
|
|
386
|
+
if (serverState) {
|
|
387
|
+
serverState.disposable.dispose();
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
context.subscriptions.push(
|
|
392
|
+
commands.registerCommand("apollographql/stopDevToolsServer", () => {
|
|
393
|
+
serverState?.disposable.dispose();
|
|
394
|
+
}),
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
Debug.traceLevel = workspace
|
|
398
|
+
.getConfiguration("apollographql")
|
|
399
|
+
.get("trace.server");
|
|
400
|
+
context.subscriptions.push(
|
|
401
|
+
workspace.onDidChangeConfiguration((event) => {
|
|
402
|
+
const affected = event.affectsConfiguration("apollographql.trace.server");
|
|
403
|
+
if (affected) {
|
|
404
|
+
Debug.traceLevel = workspace
|
|
405
|
+
.getConfiguration("apollographql")
|
|
406
|
+
.get("trace.server");
|
|
407
|
+
}
|
|
408
|
+
}),
|
|
409
|
+
);
|
|
410
|
+
|
|
332
411
|
await client.start();
|
|
333
412
|
return {
|
|
334
413
|
outputChannel,
|
|
@@ -41,6 +41,11 @@ if (test === origTest.skip) {
|
|
|
41
41
|
);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
if (process.platform === "win32") {
|
|
45
|
+
console.info("Skipping rover E2E tests in Windows");
|
|
46
|
+
test = origTest.skip;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
let editor: TextEditor;
|
|
45
50
|
let getPosition: GetPositionFn;
|
|
46
51
|
beforeAll(async () => {
|
|
@@ -63,13 +63,13 @@ test("wrong token", async () => {
|
|
|
63
63
|
|
|
64
64
|
// currently, this logs twice, along with a full stracktrace, but no indication of where it came from
|
|
65
65
|
// this should be improved on.
|
|
66
|
-
expect(output).toContain(
|
|
66
|
+
expect(output.replace(/\s/g, "")).toContain(
|
|
67
67
|
`
|
|
68
68
|
[GraphQL error]: HTTP fetch failed from 'kotlin': 406: Not Acceptable
|
|
69
69
|
[GraphQL error]: Invalid credentials provided
|
|
70
70
|
ApolloError: HTTP fetch failed from 'kotlin': 406: Not Acceptable
|
|
71
71
|
Invalid credentials provided
|
|
72
|
-
at new ApolloError`.
|
|
72
|
+
at new ApolloError`.replace(/\s/g, ""),
|
|
73
73
|
);
|
|
74
74
|
} finally {
|
|
75
75
|
await mocks.loadDefaultMocks(baseUri);
|
|
@@ -2,7 +2,7 @@ import { minimatch } from "minimatch";
|
|
|
2
2
|
import { globSync } from "glob";
|
|
3
3
|
import { invariant } from "../tools";
|
|
4
4
|
import { URI } from "vscode-uri";
|
|
5
|
-
import { normalizeURI } from "./utilities";
|
|
5
|
+
import { normalizeURI, withUnixSeparator } from "./utilities";
|
|
6
6
|
import { resolve } from "path";
|
|
7
7
|
|
|
8
8
|
export class FileSet {
|
|
@@ -35,13 +35,13 @@ export class FileSet {
|
|
|
35
35
|
this.includes.some((include) => {
|
|
36
36
|
return minimatch(
|
|
37
37
|
normalizedFilePath,
|
|
38
|
-
resolve(this.rootURI.fsPath, include),
|
|
38
|
+
withUnixSeparator(resolve(this.rootURI.fsPath, include)),
|
|
39
39
|
);
|
|
40
40
|
}) &&
|
|
41
41
|
!this.excludes.some((exclude) => {
|
|
42
42
|
return minimatch(
|
|
43
43
|
normalizedFilePath,
|
|
44
|
-
resolve(this.rootURI.fsPath, exclude),
|
|
44
|
+
withUnixSeparator(resolve(this.rootURI.fsPath, exclude)),
|
|
45
45
|
);
|
|
46
46
|
})
|
|
47
47
|
);
|
|
@@ -157,13 +157,14 @@ connection.onInitialized(async () => {
|
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
const documents = new TextDocuments(TextDocument);
|
|
160
|
+
const schemes = ["file", "vscode-notebook-cell"];
|
|
160
161
|
|
|
161
162
|
// Make the text document manager listen on the connection
|
|
162
163
|
// for open, change and close text document events
|
|
163
164
|
documents.listen(connection);
|
|
164
165
|
|
|
165
|
-
function
|
|
166
|
-
return URI.parse(uri).scheme
|
|
166
|
+
function isEnabledDocument(uri: string) {
|
|
167
|
+
return schemes.includes(URI.parse(uri).scheme);
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
documents.onDidChangeContent((params) => {
|
|
@@ -173,8 +174,7 @@ documents.onDidChangeContent((params) => {
|
|
|
173
174
|
);
|
|
174
175
|
if (!project) return;
|
|
175
176
|
|
|
176
|
-
|
|
177
|
-
if (!isFile(params.document.uri)) {
|
|
177
|
+
if (!isEnabledDocument(params.document.uri)) {
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
@@ -213,8 +213,7 @@ connection.onDidChangeWatchedFiles((params) => {
|
|
|
213
213
|
continue;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
if (!isFile(uri)) {
|
|
216
|
+
if (!isEnabledDocument(uri)) {
|
|
218
217
|
continue;
|
|
219
218
|
}
|
|
220
219
|
|
package/start-ac.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// for testing, start a few of these, e.g. with
|
|
4
|
+
// while true; do echo "foo\nbar\nbaz" | parallel ./start-ac.mjs; sleep 1; done
|
|
5
|
+
|
|
6
|
+
import { connectApolloClientToVSCodeDevTools } from "@apollo/client-devtools-vscode";
|
|
7
|
+
import WebSocket from "ws";
|
|
8
|
+
import { ApolloClient, InMemoryCache } from "@apollo/client/core/index.js";
|
|
9
|
+
import { MockLink } from "@apollo/client/testing/core/index.js";
|
|
10
|
+
import gql from "graphql-tag";
|
|
11
|
+
|
|
12
|
+
globalThis.WebSocket ||= WebSocket;
|
|
13
|
+
|
|
14
|
+
const helloWorld = gql`
|
|
15
|
+
query {
|
|
16
|
+
hello
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
const link = new MockLink([
|
|
21
|
+
{
|
|
22
|
+
request: { query: helloWorld },
|
|
23
|
+
result: { data: { hello: "world" } },
|
|
24
|
+
maxUsageCount: 1000,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
request: {
|
|
28
|
+
query: gql`
|
|
29
|
+
query {
|
|
30
|
+
hi
|
|
31
|
+
}
|
|
32
|
+
`,
|
|
33
|
+
},
|
|
34
|
+
result: { data: { hi: "universe" } },
|
|
35
|
+
maxUsageCount: 1000,
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
const client = new ApolloClient({
|
|
39
|
+
link,
|
|
40
|
+
cache: new InMemoryCache(),
|
|
41
|
+
devtools: { name: process.argv[2] },
|
|
42
|
+
});
|
|
43
|
+
client.watchQuery({ query: helloWorld }).subscribe({ next() {} });
|
|
44
|
+
const { connectedPromise, disconnect, onCleanup } =
|
|
45
|
+
connectApolloClientToVSCodeDevTools(
|
|
46
|
+
client,
|
|
47
|
+
"ws://localhost:7095", // nosemgrep
|
|
48
|
+
);
|
|
49
|
+
console.log("connecting...");
|
|
50
|
+
onCleanup((reason) =>
|
|
51
|
+
console.log(
|
|
52
|
+
"disconnected",
|
|
53
|
+
reason,
|
|
54
|
+
/* referencing client here to prevent it from getting garbage connected */ client.version,
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
connectedPromise.then(() => {
|
|
58
|
+
console.log("connected");
|
|
59
|
+
// setTimeout(unregister, 5000, "USERLAND_TIMEOUT");
|
|
60
|
+
});
|