vscode-apollo 2.3.1 → 2.3.3
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/.circleci/config.yml +1 -1
- package/CHANGELOG.md +12 -0
- package/images/marketplace/federation-directive-hover.png +0 -0
- package/package.json +8 -7
- package/sampleWorkspace/configFileTypes/cjsConfig/apollo.config.cjs +8 -0
- package/sampleWorkspace/configFileTypes/cjsConfig/package.json +4 -0
- package/sampleWorkspace/configFileTypes/cjsConfig/src/test.js +8 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithCJS/apollo.config.js +8 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithCJS/package.json +4 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithCJS/src/test.js +8 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithESM/apollo.config.js +8 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithESM/package.json +4 -0
- package/sampleWorkspace/configFileTypes/jsConfigWithESM/src/test.js +8 -0
- package/sampleWorkspace/configFileTypes/mjsConfig/apollo.config.mjs +8 -0
- package/sampleWorkspace/configFileTypes/mjsConfig/package.json +4 -0
- package/sampleWorkspace/configFileTypes/mjsConfig/src/test.js +8 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithCJS/apollo.config.ts +8 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithCJS/package.json +4 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithCJS/src/test.js +8 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithESM/apollo.config.ts +8 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithESM/package.json +4 -0
- package/sampleWorkspace/configFileTypes/tsConfigWithESM/src/test.js +8 -0
- package/sampleWorkspace/sampleWorkspace.code-workspace +3 -0
- package/schemas/apollo.config.schema.json +57 -7
- package/src/__e2e__/runTests.js +0 -1
- package/src/build.js +2 -2
- package/src/language-server/__e2e__/configFileTypes.e2e.ts +37 -0
- package/src/language-server/__e2e__/utils.ts +2 -1
- package/src/language-server/config/__tests__/loadConfig.ts +28 -47
- package/src/language-server/config/cache-busting-resolver.js +4 -12
- package/src/language-server/config/cache-busting-resolver.types.ts +1 -1
- package/src/language-server/config/config.ts +122 -98
- package/src/language-server/config/loadConfig.ts +3 -1
- package/src/language-server/config/loadTsConfig.ts +33 -16
- package/src/language-server/project/rover/DocumentSynchronization.ts +2 -2
- package/src/language-server/project/rover/project.ts +47 -20
- package/src/language-server/server.ts +7 -1
- package/src/language-server/utilities/debug.ts +49 -8
package/.circleci/config.yml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 2.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#191](https://github.com/apollographql/vscode-graphql/pull/191) [`2e56f42d`](https://github.com/apollographql/vscode-graphql/commit/2e56f42d172a7ec8afd003f056aeabac9eab1789) Thanks [@svc-secops](https://github.com/svc-secops)! - Chores: update various dependencies (#181, #191, #217, #218)
|
|
8
|
+
|
|
9
|
+
## 2.3.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#211](https://github.com/apollographql/vscode-graphql/pull/211) [`9aa1fc1b`](https://github.com/apollographql/vscode-graphql/commit/9aa1fc1b9b419a5e72216f032e64aa5f86f15b59) Thanks [@phryneas](https://github.com/phryneas)! - Avoid detection if .js config file is ESM or CommonJs, just try both.
|
|
14
|
+
|
|
3
15
|
## 2.3.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
Binary file
|
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.3.
|
|
5
|
+
"version": "2.3.3",
|
|
6
6
|
"referenceID": "87197759-7617-40d0-b32e-46d378e907c7",
|
|
7
7
|
"author": "Apollo GraphQL <opensource@apollographql.com>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"vscode": "^1.90.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@apollo/client": "3.11.
|
|
41
|
-
"@apollo/subgraph": "2.
|
|
42
|
-
"@graphql-tools/schema": "10.0.
|
|
40
|
+
"@apollo/client": "3.11.8",
|
|
41
|
+
"@apollo/subgraph": "2.9.1",
|
|
42
|
+
"@graphql-tools/schema": "10.0.6",
|
|
43
43
|
"@wry/equality": "0.5.7",
|
|
44
44
|
"cosmiconfig": "9.0.0",
|
|
45
45
|
"dotenv": "16.4.5",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"lz-string": "1.5.0",
|
|
56
56
|
"minimatch": "10.0.1",
|
|
57
57
|
"moment": "2.30.1",
|
|
58
|
+
"semver": "7.6.3",
|
|
58
59
|
"undici": "6.19.8",
|
|
59
60
|
"vscode-languageclient": "9.0.1",
|
|
60
61
|
"vscode-languageserver": "9.0.1",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"vscode-uri": "3.0.8",
|
|
63
64
|
"which": "4.0.0",
|
|
64
65
|
"zod": "3.23.8",
|
|
65
|
-
"zod-validation-error": "3.
|
|
66
|
+
"zod-validation-error": "3.4.0"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@apollo/rover": "0.27.0-alpha.0",
|
|
@@ -70,7 +71,7 @@
|
|
|
70
71
|
"@changesets/cli": "2.26.2",
|
|
71
72
|
"@graphql-codegen/cli": "^5.0.2",
|
|
72
73
|
"@graphql-codegen/typescript-operations": "^4.2.3",
|
|
73
|
-
"@types/jest": "29.5.
|
|
74
|
+
"@types/jest": "29.5.13",
|
|
74
75
|
"@types/lodash.debounce": "4.0.9",
|
|
75
76
|
"@types/lodash.merge": "4.6.9",
|
|
76
77
|
"@types/lodash.throttle": "^4.1.9",
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
"import-fresh": "^3.3.0",
|
|
90
91
|
"jest": "29.7.0",
|
|
91
92
|
"jest-environment-node": "29.7.0",
|
|
92
|
-
"memfs": "4.11.
|
|
93
|
+
"memfs": "4.11.2",
|
|
93
94
|
"npm-run-all": "^4.1.5",
|
|
94
95
|
"prettier": "3.0.3",
|
|
95
96
|
"rimraf": "6.0.1",
|
|
@@ -4,14 +4,31 @@
|
|
|
4
4
|
"$ref": "#/definitions/baseConfig"
|
|
5
5
|
},
|
|
6
6
|
{
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
7
|
+
"anyOf": [
|
|
8
|
+
{
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"client": {
|
|
12
|
+
"$ref": "#/definitions/clientConfig"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"required": [
|
|
16
|
+
"client"
|
|
17
|
+
],
|
|
18
|
+
"additionalProperties": false
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"rover": {
|
|
24
|
+
"$ref": "#/definitions/roverConfig"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": [
|
|
28
|
+
"rover"
|
|
29
|
+
],
|
|
30
|
+
"additionalProperties": false
|
|
11
31
|
}
|
|
12
|
-
},
|
|
13
|
-
"required": [
|
|
14
|
-
"client"
|
|
15
32
|
]
|
|
16
33
|
}
|
|
17
34
|
],
|
|
@@ -146,6 +163,36 @@
|
|
|
146
163
|
"additionalProperties": false,
|
|
147
164
|
"description": "Configuration for a Client project."
|
|
148
165
|
},
|
|
166
|
+
"roverConfig": {
|
|
167
|
+
"type": "object",
|
|
168
|
+
"properties": {
|
|
169
|
+
"bin": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"description": "The path to your Rover binary. If omitted, will look in PATH."
|
|
172
|
+
},
|
|
173
|
+
"profile": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"description": "The name of the profile to use."
|
|
176
|
+
},
|
|
177
|
+
"supergraphConfig": {
|
|
178
|
+
"type": [
|
|
179
|
+
"string",
|
|
180
|
+
"null"
|
|
181
|
+
],
|
|
182
|
+
"description": "The path to your `supergraph.yaml` file. \nDefaults to a `supergraph.yaml` in the folder of your `apollo.config.json`, if there is one."
|
|
183
|
+
},
|
|
184
|
+
"extraArgs": {
|
|
185
|
+
"type": "array",
|
|
186
|
+
"items": {
|
|
187
|
+
"type": "string"
|
|
188
|
+
},
|
|
189
|
+
"default": [],
|
|
190
|
+
"description": "Extra arguments to pass to the Rover CLI."
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"additionalProperties": false,
|
|
194
|
+
"description": "Configuration for a federated project."
|
|
195
|
+
},
|
|
149
196
|
"engineConfig": {
|
|
150
197
|
"type": "object",
|
|
151
198
|
"properties": {
|
|
@@ -173,6 +220,9 @@
|
|
|
173
220
|
"client": {
|
|
174
221
|
"description": "Configuration for a Client project."
|
|
175
222
|
},
|
|
223
|
+
"rover": {
|
|
224
|
+
"description": "Configuration for a federated project."
|
|
225
|
+
},
|
|
176
226
|
"service": {
|
|
177
227
|
"description": "This option is no longer supported, please remove it from your configuration file."
|
|
178
228
|
}
|
package/src/__e2e__/runTests.js
CHANGED
|
@@ -18,7 +18,6 @@ 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
|
-
process.env.APOLLO_FEATURE_FLAGS = "rover";
|
|
22
21
|
disposables.push(
|
|
23
22
|
...(await Promise.all([
|
|
24
23
|
runMockServer(TEST_PORT, false, loadDefaultMocks),
|
package/src/build.js
CHANGED
|
@@ -68,7 +68,7 @@ const buildJsonSchemaPlugin = {
|
|
|
68
68
|
const {
|
|
69
69
|
configSchema,
|
|
70
70
|
clientConfig,
|
|
71
|
-
|
|
71
|
+
roverConfig,
|
|
72
72
|
engineConfig,
|
|
73
73
|
baseConfig,
|
|
74
74
|
// @ts-ignore
|
|
@@ -78,7 +78,7 @@ const buildJsonSchemaPlugin = {
|
|
|
78
78
|
errorMessages: true,
|
|
79
79
|
definitions: {
|
|
80
80
|
clientConfig,
|
|
81
|
-
|
|
81
|
+
roverConfig,
|
|
82
82
|
engineConfig,
|
|
83
83
|
baseConfig,
|
|
84
84
|
},
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { writeFile } from "fs/promises";
|
|
2
|
+
import {
|
|
3
|
+
reloadService,
|
|
4
|
+
waitForLSP,
|
|
5
|
+
resolveRelativeToSampleWorkspace,
|
|
6
|
+
} from "./utils";
|
|
7
|
+
|
|
8
|
+
test.each([
|
|
9
|
+
["cjsConfig", "commonjs"],
|
|
10
|
+
["cjsConfig", "module"],
|
|
11
|
+
["mjsConfig", "module"],
|
|
12
|
+
["mjsConfig", "commonjs"],
|
|
13
|
+
["jsConfigWithCJS", "commonjs"],
|
|
14
|
+
["jsConfigWithCJS", "module"],
|
|
15
|
+
["jsConfigWithESM", "module"],
|
|
16
|
+
["jsConfigWithESM", "commonjs"],
|
|
17
|
+
["tsConfigWithCJS", "commonjs"],
|
|
18
|
+
["tsConfigWithCJS", "module"],
|
|
19
|
+
["tsConfigWithESM", "module"],
|
|
20
|
+
["tsConfigWithESM", "commonjs"],
|
|
21
|
+
] as const)("%s with `type: '%s'`", async (project, moduleType) => {
|
|
22
|
+
await writeFile(
|
|
23
|
+
resolveRelativeToSampleWorkspace(`configFileTypes/${project}/package.json`),
|
|
24
|
+
JSON.stringify(
|
|
25
|
+
{
|
|
26
|
+
name: "test",
|
|
27
|
+
type: moduleType,
|
|
28
|
+
},
|
|
29
|
+
undefined,
|
|
30
|
+
2,
|
|
31
|
+
),
|
|
32
|
+
"utf-8",
|
|
33
|
+
);
|
|
34
|
+
await reloadService();
|
|
35
|
+
const stats = await waitForLSP(`configFileTypes/${project}/src/test.js`);
|
|
36
|
+
expect(stats.serviceId).toBe(project);
|
|
37
|
+
});
|
|
@@ -7,6 +7,7 @@ import { VSCodeGraphQLExtension } from "src/extension";
|
|
|
7
7
|
function resolve(file: string) {
|
|
8
8
|
return join(__dirname, "..", "..", "..", "sampleWorkspace", file);
|
|
9
9
|
}
|
|
10
|
+
export { resolve as resolveRelativeToSampleWorkspace };
|
|
10
11
|
|
|
11
12
|
export type GetPositionFn = ReturnType<typeof getPositionForEditor>;
|
|
12
13
|
export function getPositionForEditor(editor: vscode.TextEditor) {
|
|
@@ -65,7 +66,7 @@ export function waitForLSP(file: string) {
|
|
|
65
66
|
uri.toString(),
|
|
66
67
|
);
|
|
67
68
|
expect(stats.loaded).toBe(true);
|
|
68
|
-
return stats;
|
|
69
|
+
return stats as ProjectStats & { loaded: true };
|
|
69
70
|
});
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { loadConfig } from "../";
|
|
2
|
+
import { ClientConfig, RoverConfig } from "../config";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
|
|
6
|
-
async function withFeatureFlags(flags: string, fn: () => void) {
|
|
7
|
-
const FF = process.env.APOLLO_FEATURE_FLAGS;
|
|
8
|
-
try {
|
|
9
|
-
process.env.APOLLO_FEATURE_FLAGS = flags;
|
|
10
|
-
jest.resetModules();
|
|
11
|
-
({ loadConfig } = require("../"));
|
|
12
|
-
({ ClientConfig, RoverConfig } = require("../config"));
|
|
13
|
-
return await fn();
|
|
14
|
-
} finally {
|
|
15
|
-
process.env.APOLLO_FEATURE_FLAGS = FF;
|
|
16
|
-
jest.resetModules();
|
|
17
|
-
({ loadConfig } = require("../"));
|
|
18
|
-
({ ClientConfig, RoverConfig } = require("../config"));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
6
|
const makeNestedDir = (dir: string) => {
|
|
23
7
|
if (fs.existsSync(dir)) return;
|
|
24
8
|
|
|
@@ -109,25 +93,24 @@ Object {
|
|
|
109
93
|
`);
|
|
110
94
|
});
|
|
111
95
|
|
|
112
|
-
it("loads with rover defaults from different dir", () =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"apollo.config.js": `
|
|
96
|
+
it("loads with rover defaults from different dir", async () => {
|
|
97
|
+
writeFilesToDir(dir, {
|
|
98
|
+
"apollo.config.js": `
|
|
116
99
|
module.exports = {
|
|
117
100
|
rover: {
|
|
118
101
|
}
|
|
119
102
|
}
|
|
120
103
|
`,
|
|
104
|
+
});
|
|
105
|
+
fs.mkdirSync(`${dir}/bin`);
|
|
106
|
+
fs.writeFileSync(`${dir}/bin/rover`, "", { mode: 0o755 });
|
|
107
|
+
let oldPath = process.env.PATH;
|
|
108
|
+
process.env.PATH = `${dir}/bin:${oldPath}`;
|
|
109
|
+
try {
|
|
110
|
+
const config = await loadConfig({
|
|
111
|
+
configPath: dirPath,
|
|
121
112
|
});
|
|
122
|
-
|
|
123
|
-
fs.writeFileSync(`${dir}/bin/rover`, "", { mode: 0o755 });
|
|
124
|
-
let oldPath = process.env.PATH;
|
|
125
|
-
process.env.PATH = `${dir}/bin:${oldPath}`;
|
|
126
|
-
try {
|
|
127
|
-
const config = await loadConfig({
|
|
128
|
-
configPath: dirPath,
|
|
129
|
-
});
|
|
130
|
-
expect(config?.rawConfig).toMatchInlineSnapshot(`
|
|
113
|
+
expect(config?.rawConfig).toMatchInlineSnapshot(`
|
|
131
114
|
Object {
|
|
132
115
|
"engine": Object {
|
|
133
116
|
"endpoint": "https://graphql.api.apollographql.com/api/graphql",
|
|
@@ -138,10 +121,10 @@ Object {
|
|
|
138
121
|
},
|
|
139
122
|
}
|
|
140
123
|
`);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
124
|
+
} finally {
|
|
125
|
+
process.env.PATH = oldPath;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
145
128
|
|
|
146
129
|
it("[deprecated] loads config from package.json", async () => {
|
|
147
130
|
writeFilesToDir(dir, {
|
|
@@ -280,7 +263,6 @@ client:
|
|
|
280
263
|
|
|
281
264
|
await loadConfig({
|
|
282
265
|
configPath: dirPath,
|
|
283
|
-
requireConfig: true, // this is what we're testing
|
|
284
266
|
});
|
|
285
267
|
|
|
286
268
|
expect(spy).toHaveBeenCalledWith(
|
|
@@ -299,7 +281,7 @@ client:
|
|
|
299
281
|
}).catch((e: any) => e);
|
|
300
282
|
|
|
301
283
|
expect(error.message).toMatch(
|
|
302
|
-
/Config needs to contain
|
|
284
|
+
/Config needs to contain either 'client' or 'rover' fields/i,
|
|
303
285
|
);
|
|
304
286
|
});
|
|
305
287
|
});
|
|
@@ -374,18 +356,17 @@ client:
|
|
|
374
356
|
expect(config).toBeInstanceOf(ClientConfig);
|
|
375
357
|
});
|
|
376
358
|
|
|
377
|
-
it("infers rover projects from config", () =>
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
});
|
|
359
|
+
it("infers rover projects from config", async () => {
|
|
360
|
+
writeFilesToDir(dir, {
|
|
361
|
+
"apollo.config.js": `module.exports = { rover: { bin: "/usr/bin/env" } }`,
|
|
362
|
+
});
|
|
382
363
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
364
|
+
const config = await loadConfig({
|
|
365
|
+
configPath: dirPath,
|
|
366
|
+
});
|
|
386
367
|
|
|
387
|
-
|
|
388
|
-
|
|
368
|
+
expect(config).toBeInstanceOf(RoverConfig);
|
|
369
|
+
});
|
|
389
370
|
});
|
|
390
371
|
|
|
391
372
|
describe("service name", () => {
|
|
@@ -24,20 +24,12 @@ async function resolve(specifier, context, nextResolve) {
|
|
|
24
24
|
if (context.importAttributes.as !== "cachebust") {
|
|
25
25
|
return nextResolve(specifier, context);
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
// no need to resolve at all, we have all necessary information
|
|
29
|
-
return {
|
|
30
|
-
url: bustFileName(specifier),
|
|
31
|
-
format: context.importAttributes.format,
|
|
32
|
-
importAttributes: context.importAttributes,
|
|
33
|
-
shortCircuit: true,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
const result = await nextResolve(specifier, context);
|
|
27
|
+
// no need to resolve at all, we have all necessary information
|
|
37
28
|
return {
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
url: bustFileName(specifier),
|
|
30
|
+
format: context.importAttributes.format,
|
|
40
31
|
importAttributes: context.importAttributes,
|
|
32
|
+
shortCircuit: true,
|
|
41
33
|
};
|
|
42
34
|
}
|
|
43
35
|
|
|
@@ -9,10 +9,9 @@ import which from "which";
|
|
|
9
9
|
import { accessSync, constants as fsConstants, statSync } from "node:fs";
|
|
10
10
|
import { AsyncLocalStorage } from "async_hooks";
|
|
11
11
|
import { existsSync } from "fs";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.includes("rover");
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { text } from "node:stream/consumers";
|
|
14
|
+
import semver from "semver";
|
|
16
15
|
|
|
17
16
|
function ignoredFieldWarning(
|
|
18
17
|
getMessage = (path: string) =>
|
|
@@ -143,49 +142,53 @@ export const clientConfig = z
|
|
|
143
142
|
.describe("Configuration for a Client project.");
|
|
144
143
|
export type ClientConfigFormat = z.infer<typeof clientConfig>;
|
|
145
144
|
|
|
146
|
-
export const roverConfig = z
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
145
|
+
export const roverConfig = z
|
|
146
|
+
.object({
|
|
147
|
+
bin: z
|
|
148
|
+
.preprocess(
|
|
149
|
+
(val) => val || which.sync("rover", { nothrow: true }) || undefined,
|
|
150
|
+
z.string({
|
|
151
|
+
message:
|
|
152
|
+
"Rover binary not found. Please either install it system-wide in PATH, or provide the `bin` option. Also ensure that the binary is executable.",
|
|
153
|
+
}),
|
|
154
|
+
)
|
|
155
|
+
.refine(
|
|
156
|
+
(bin) => {
|
|
157
|
+
try {
|
|
158
|
+
// is executable?
|
|
159
|
+
accessSync(bin, fsConstants.X_OK);
|
|
160
|
+
// is a file and not a directory?
|
|
161
|
+
return statSync(bin).isFile();
|
|
162
|
+
} catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
message:
|
|
168
|
+
"Rover binary is not marked as an executable. If you are using OS X or Linux, ensure to set the executable bit.",
|
|
169
|
+
},
|
|
170
|
+
)
|
|
171
|
+
.describe(
|
|
172
|
+
"The path to your Rover binary. If omitted, will look in PATH.",
|
|
173
|
+
),
|
|
174
|
+
profile: z.string().optional().describe("The name of the profile to use."),
|
|
175
|
+
supergraphConfig: z
|
|
176
|
+
.preprocess((value) => {
|
|
177
|
+
if (value !== undefined) return value;
|
|
178
|
+
const configPath = contextStore.getStore()?.configPath || ".";
|
|
179
|
+
const supergraphConfig = join(configPath, "supergraph.yaml");
|
|
180
|
+
return existsSync(supergraphConfig) ? supergraphConfig : undefined;
|
|
181
|
+
}, z.string().nullable().optional())
|
|
182
|
+
.describe(
|
|
183
|
+
"The path to your `supergraph.yaml` file. \n" +
|
|
184
|
+
"Defaults to a `supergraph.yaml` in the folder of your `apollo.config.json`, if there is one.",
|
|
185
|
+
),
|
|
186
|
+
extraArgs: z
|
|
187
|
+
.array(z.string())
|
|
188
|
+
.default([])
|
|
189
|
+
.describe("Extra arguments to pass to the Rover CLI."),
|
|
190
|
+
})
|
|
191
|
+
.describe("Configuration for a federated project.");
|
|
189
192
|
type RoverConfigFormat = z.infer<typeof roverConfig>;
|
|
190
193
|
|
|
191
194
|
export const engineConfig = z
|
|
@@ -212,12 +215,7 @@ export type EngineConfig = z.infer<typeof engineConfig>;
|
|
|
212
215
|
export const baseConfig = z.object({
|
|
213
216
|
engine: engineConfig.default({}),
|
|
214
217
|
client: z.unknown().optional().describe(clientConfig.description!),
|
|
215
|
-
|
|
216
|
-
{
|
|
217
|
-
rover: z.unknown().optional(),
|
|
218
|
-
},
|
|
219
|
-
{},
|
|
220
|
-
),
|
|
218
|
+
rover: z.unknown().optional().describe(roverConfig.description!),
|
|
221
219
|
service: ignoredFieldWarning(
|
|
222
220
|
(path) =>
|
|
223
221
|
`Service-type projects are no longer supported. Please remove the "${path}" field from your configuration file.`,
|
|
@@ -234,56 +232,36 @@ export type FullRoverConfigFormat = Extract<
|
|
|
234
232
|
{ rover: {} }
|
|
235
233
|
>;
|
|
236
234
|
|
|
237
|
-
/** Helper function for TypeScript - we just want the first type to make it into the types, not the "no feature flag" fallback */
|
|
238
|
-
function ifRoverAvailable<T>(yes: T, no: any): T {
|
|
239
|
-
return ROVER_AVAILABLE ? yes : no;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
235
|
export const configSchema = baseConfig
|
|
243
236
|
.superRefine((val, ctx) => {
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
if (!("client" in val)) {
|
|
261
|
-
ctx.addIssue({
|
|
262
|
-
code: "custom",
|
|
263
|
-
message: "Config needs to contain a 'client' field.",
|
|
264
|
-
fatal: true,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
237
|
+
if ("client" in val && "rover" in val) {
|
|
238
|
+
ctx.addIssue({
|
|
239
|
+
code: "custom",
|
|
240
|
+
message: "Config cannot contain both 'client' and 'rover' fields",
|
|
241
|
+
fatal: true,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (!("client" in val) && !("rover" in val)) {
|
|
245
|
+
ctx.addIssue({
|
|
246
|
+
code: "custom",
|
|
247
|
+
message: "Config needs to contain either 'client' or 'rover' fields",
|
|
248
|
+
fatal: true,
|
|
249
|
+
});
|
|
267
250
|
}
|
|
268
251
|
})
|
|
269
252
|
.and(
|
|
270
|
-
|
|
271
|
-
z
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
]),
|
|
283
|
-
z.object({
|
|
284
|
-
client: clientConfig,
|
|
285
|
-
}),
|
|
286
|
-
),
|
|
253
|
+
z.union([
|
|
254
|
+
z
|
|
255
|
+
.object({
|
|
256
|
+
client: clientConfig,
|
|
257
|
+
})
|
|
258
|
+
.transform((val): typeof val & { rover?: never } => val),
|
|
259
|
+
z
|
|
260
|
+
.object({
|
|
261
|
+
rover: roverConfig,
|
|
262
|
+
})
|
|
263
|
+
.transform((val): typeof val & { client?: never } => val),
|
|
264
|
+
]),
|
|
287
265
|
);
|
|
288
266
|
export type RawApolloConfigFormat = z.input<typeof configSchema>;
|
|
289
267
|
export type ParsedApolloConfigFormat = z.output<typeof configSchema>;
|
|
@@ -371,6 +349,11 @@ export abstract class ApolloConfig {
|
|
|
371
349
|
if (this._graphId) return this._graphId;
|
|
372
350
|
return getGraphIdFromConfig(this.rawConfig);
|
|
373
351
|
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* execute some additional asynchronous verification steps that cannot be part of the sync parsing part
|
|
355
|
+
*/
|
|
356
|
+
async verify() {}
|
|
374
357
|
}
|
|
375
358
|
|
|
376
359
|
export class ClientConfig extends ApolloConfig {
|
|
@@ -395,4 +378,45 @@ export class RoverConfig extends ApolloConfig {
|
|
|
395
378
|
super(rawConfig, configURI);
|
|
396
379
|
this.rover = rawConfig.rover;
|
|
397
380
|
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* execute some additional asynchronous verification steps that cannot be part of the sync parsing part
|
|
384
|
+
*/
|
|
385
|
+
async verify() {
|
|
386
|
+
try {
|
|
387
|
+
const child = spawn(this.rover.bin, ["-V"], {
|
|
388
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
389
|
+
});
|
|
390
|
+
const output = await text(child.stdout);
|
|
391
|
+
const versionPrefix = "Rover ";
|
|
392
|
+
if (output.startsWith(versionPrefix)) {
|
|
393
|
+
const version = output.slice(versionPrefix.length).trim();
|
|
394
|
+
if (!semver.valid(version)) {
|
|
395
|
+
// not a valid version, we accept this and will try anyways
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (semver.gte(version, "0.27.0-alpha.0")) {
|
|
399
|
+
// this is a supported version
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const error = new Error(
|
|
403
|
+
`Rover version ${version} is not supported by the extension. Please upgrade to at least 0.27.0.`,
|
|
404
|
+
);
|
|
405
|
+
// @ts-expect-error would require a target of ES2022 in tsconfig
|
|
406
|
+
error.cause = "ROVER_TOO_OLD";
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
// we can't find out the version, but we'll try anyways
|
|
410
|
+
} catch (error) {
|
|
411
|
+
if (
|
|
412
|
+
error &&
|
|
413
|
+
error instanceof Error &&
|
|
414
|
+
// @ts-expect-error would require a target of ES2022 in tsconfig
|
|
415
|
+
error.cause === "ROVER_TOO_OLD"
|
|
416
|
+
) {
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
419
|
+
// we ignore all other errors and will handle that when we actually spawn the rover binary
|
|
420
|
+
}
|
|
421
|
+
}
|
|
398
422
|
}
|
|
@@ -121,9 +121,11 @@ export async function loadConfig({
|
|
|
121
121
|
|
|
122
122
|
let { config, filepath } = loadedConfig;
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
const finalConfig = parseApolloConfig(config, URI.file(resolve(filepath)), {
|
|
125
125
|
apiKey,
|
|
126
126
|
serviceName: nameFromKey,
|
|
127
127
|
configPath: dirname(filepath),
|
|
128
128
|
});
|
|
129
|
+
await finalConfig.verify();
|
|
130
|
+
return finalConfig;
|
|
129
131
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Loader } from "cosmiconfig";
|
|
2
|
-
import { dirname } from "node:path";
|
|
2
|
+
import { dirname, extname } from "node:path";
|
|
3
3
|
import typescript from "typescript";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { register } from "node:module";
|
|
@@ -59,19 +59,7 @@ async function load(
|
|
|
59
59
|
error.message = `TypeScript Error in ${filepath}:\n${error.message}`;
|
|
60
60
|
throw error;
|
|
61
61
|
}
|
|
62
|
-
|
|
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;
|
|
62
|
+
return loadCachebustedJs(filepath, transpiledContent, type);
|
|
75
63
|
}
|
|
76
64
|
|
|
77
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -92,15 +80,44 @@ function resolveTsConfig(directory: string): any {
|
|
|
92
80
|
}
|
|
93
81
|
|
|
94
82
|
export const loadJs: Loader = async function loadJs(filepath, contents) {
|
|
83
|
+
const extension = extname(filepath);
|
|
84
|
+
if (extension === ".mjs") {
|
|
85
|
+
return loadCachebustedJs(filepath, contents, "module");
|
|
86
|
+
}
|
|
87
|
+
if (extension === ".cjs") {
|
|
88
|
+
return loadCachebustedJs(filepath, contents, "commonjs");
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return await loadCachebustedJs(filepath, contents, "module");
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (
|
|
94
|
+
error instanceof Error &&
|
|
95
|
+
// [ERROR] ReferenceError: module is not defined in ES module scope
|
|
96
|
+
error.message.includes("module is not defined")
|
|
97
|
+
) {
|
|
98
|
+
return loadCachebustedJs(filepath, contents, "commonjs");
|
|
99
|
+
} else {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
async function loadCachebustedJs(
|
|
106
|
+
filename: string,
|
|
107
|
+
contents: string,
|
|
108
|
+
type: "module" | "commonjs",
|
|
109
|
+
) {
|
|
95
110
|
return (
|
|
96
111
|
await import(
|
|
97
|
-
|
|
112
|
+
filename,
|
|
113
|
+
// @ts-ignore
|
|
98
114
|
{
|
|
99
115
|
with: {
|
|
100
116
|
as: "cachebust",
|
|
101
117
|
contents,
|
|
118
|
+
format: type,
|
|
102
119
|
} satisfies ImportAttributes,
|
|
103
120
|
}
|
|
104
121
|
)
|
|
105
122
|
).default;
|
|
106
|
-
}
|
|
123
|
+
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
rangeInContainingDocument,
|
|
24
24
|
} from "../../utilities/source";
|
|
25
25
|
import { URI } from "vscode-uri";
|
|
26
|
-
import {
|
|
26
|
+
import { Debug } from "../../utilities";
|
|
27
27
|
|
|
28
28
|
export interface FilePart {
|
|
29
29
|
fractionalIndex: string;
|
|
@@ -285,7 +285,7 @@ export class DocumentSynchronization {
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
handlePartDiagnostics(params: PublishDiagnosticsParams) {
|
|
288
|
-
|
|
288
|
+
Debug.traceVerbose("Received diagnostics", params);
|
|
289
289
|
const uriDetails = splitUri(params.uri);
|
|
290
290
|
const found = this.knownFiles.get(uriDetails.uri);
|
|
291
291
|
if (!found || found.source === "lsp") {
|
|
@@ -36,8 +36,8 @@ import { VSCodeConnection } from "../../server";
|
|
|
36
36
|
import { getLanguageIdForExtension } from "../../utilities/languageIdForExtension";
|
|
37
37
|
import { extname } from "node:path";
|
|
38
38
|
import type { FileExtension } from "../../../tools/utilities/languageInformation";
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
import { Debug } from "../../utilities";
|
|
40
|
+
import { TraceLevel } from "src/language-server/utilities/debug";
|
|
41
41
|
|
|
42
42
|
export function isRoverConfig(config: ApolloConfig): config is RoverConfig {
|
|
43
43
|
return config instanceof RoverConfig;
|
|
@@ -115,11 +115,14 @@ export class RoverProject extends GraphQLProject {
|
|
|
115
115
|
params?: P,
|
|
116
116
|
): Promise<void> {
|
|
117
117
|
const connection = await this.getConnection();
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
Debug.traceMessage(
|
|
119
|
+
"[Rover] Sending notification: " + type.method,
|
|
120
|
+
"[Rover] Sending notification %o",
|
|
121
|
+
{
|
|
120
122
|
type: type.method,
|
|
121
123
|
params,
|
|
122
|
-
}
|
|
124
|
+
},
|
|
125
|
+
);
|
|
123
126
|
try {
|
|
124
127
|
return await connection.sendNotification(type, params);
|
|
125
128
|
} catch (error) {
|
|
@@ -136,10 +139,20 @@ export class RoverProject extends GraphQLProject {
|
|
|
136
139
|
token?: CancellationToken,
|
|
137
140
|
): Promise<R> {
|
|
138
141
|
const connection = await this.getConnection();
|
|
139
|
-
|
|
142
|
+
Debug.traceMessage(
|
|
143
|
+
"[Rover] Sending request: " + type.method,
|
|
144
|
+
"[Rover] Sending request %o",
|
|
145
|
+
{ type: type.method, params },
|
|
146
|
+
);
|
|
140
147
|
try {
|
|
141
148
|
const result = await connection.sendRequest(type, params, token);
|
|
142
|
-
|
|
149
|
+
Debug.traceMessage(
|
|
150
|
+
"[Rover] Received response: " + type.method,
|
|
151
|
+
"[Rover] Received response %s\nResult: %o",
|
|
152
|
+
type.method,
|
|
153
|
+
|
|
154
|
+
result,
|
|
155
|
+
);
|
|
143
156
|
return result;
|
|
144
157
|
} catch (error) {
|
|
145
158
|
if (error instanceof Error) {
|
|
@@ -166,27 +179,35 @@ export class RoverProject extends GraphQLProject {
|
|
|
166
179
|
if (this.config.rover.supergraphConfig) {
|
|
167
180
|
args.push("--supergraph-config", this.config.rover.supergraphConfig);
|
|
168
181
|
}
|
|
182
|
+
if (Debug.traceLevel >= TraceLevel.verbose) {
|
|
183
|
+
args.push("--log", "debug");
|
|
184
|
+
}
|
|
169
185
|
args.push(...this.config.rover.extraArgs);
|
|
170
186
|
|
|
171
|
-
|
|
172
|
-
|
|
187
|
+
Debug.traceVerbose(
|
|
188
|
+
`starting ${this.config.rover.bin} '${args.join("' '")}'`,
|
|
189
|
+
);
|
|
173
190
|
const child = cp.spawn(this.config.rover.bin, args, {
|
|
174
|
-
env:
|
|
175
|
-
stdio: [
|
|
191
|
+
env: { NO_COLOR: "1" },
|
|
192
|
+
stdio: [
|
|
193
|
+
"pipe",
|
|
194
|
+
"pipe",
|
|
195
|
+
Debug.traceLevel >= TraceLevel.verbose ? "inherit" : "ignore",
|
|
196
|
+
],
|
|
176
197
|
});
|
|
177
198
|
this.child = child;
|
|
178
199
|
const reader = new StreamMessageReader(child.stdout);
|
|
179
200
|
const writer = new StreamMessageWriter(child.stdin);
|
|
180
201
|
const connection = createProtocolConnection(reader, writer);
|
|
181
202
|
connection.onClose(() => {
|
|
182
|
-
|
|
203
|
+
Debug.traceMessage("[Rover] Connection closed");
|
|
183
204
|
child.kill();
|
|
184
205
|
source.cancel();
|
|
185
206
|
this._connection = undefined;
|
|
186
207
|
});
|
|
187
208
|
|
|
188
209
|
connection.onError((err) => {
|
|
189
|
-
|
|
210
|
+
Debug.error("%o", { err });
|
|
190
211
|
});
|
|
191
212
|
|
|
192
213
|
connection.onNotification(
|
|
@@ -195,11 +216,14 @@ export class RoverProject extends GraphQLProject {
|
|
|
195
216
|
);
|
|
196
217
|
|
|
197
218
|
connection.onUnhandledNotification((notification) => {
|
|
198
|
-
|
|
219
|
+
Debug.traceVerbose(
|
|
220
|
+
"[Rover] unhandled notification from LSP",
|
|
221
|
+
notification,
|
|
222
|
+
);
|
|
199
223
|
});
|
|
200
224
|
|
|
201
225
|
connection.listen();
|
|
202
|
-
|
|
226
|
+
Debug.traceMessage("[Rover] Initializing connection");
|
|
203
227
|
|
|
204
228
|
const source = new CancellationTokenSource();
|
|
205
229
|
try {
|
|
@@ -213,7 +237,11 @@ export class RoverProject extends GraphQLProject {
|
|
|
213
237
|
source.token,
|
|
214
238
|
);
|
|
215
239
|
this.roverCapabilities = status.capabilities;
|
|
216
|
-
|
|
240
|
+
Debug.traceMessage(
|
|
241
|
+
"[Rover] Connection initialized",
|
|
242
|
+
"[Rover] Connection initialized %o",
|
|
243
|
+
status,
|
|
244
|
+
);
|
|
217
245
|
|
|
218
246
|
await this.connectionStorage.run(
|
|
219
247
|
connection,
|
|
@@ -222,7 +250,7 @@ export class RoverProject extends GraphQLProject {
|
|
|
222
250
|
|
|
223
251
|
return connection;
|
|
224
252
|
} catch (error) {
|
|
225
|
-
|
|
253
|
+
Debug.error("Connection with Rover failed to initialize", error);
|
|
226
254
|
throw error;
|
|
227
255
|
}
|
|
228
256
|
}
|
|
@@ -295,7 +323,7 @@ export class RoverProject extends GraphQLProject {
|
|
|
295
323
|
if (isRequestType(SemanticTokensRequest.type, type, params)) {
|
|
296
324
|
return this.documents.getFullSemanticTokens(params, token);
|
|
297
325
|
} else {
|
|
298
|
-
|
|
326
|
+
Debug.traceVerbose("unhandled request from VSCode", { type, params });
|
|
299
327
|
return undefined;
|
|
300
328
|
}
|
|
301
329
|
};
|
|
@@ -304,8 +332,7 @@ export class RoverProject extends GraphQLProject {
|
|
|
304
332
|
type,
|
|
305
333
|
params,
|
|
306
334
|
) => {
|
|
307
|
-
|
|
308
|
-
console.info("unhandled notification from VSCode", { type, params });
|
|
335
|
+
Debug.traceVerbose("unhandled notification from VSCode", { type, params });
|
|
309
336
|
};
|
|
310
337
|
|
|
311
338
|
async onVSCodeConnectionInitialized(connection: VSCodeConnection) {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
TextDocumentSyncKind,
|
|
8
8
|
SymbolInformation,
|
|
9
9
|
FileEvent,
|
|
10
|
+
SetTraceNotification,
|
|
10
11
|
} from "vscode-languageserver/node";
|
|
11
12
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
12
13
|
import { type QuickPickItem } from "vscode";
|
|
@@ -92,11 +93,16 @@ workspace.onConfigFilesFound(async (params) => {
|
|
|
92
93
|
);
|
|
93
94
|
});
|
|
94
95
|
|
|
96
|
+
connection.onNotification(SetTraceNotification.type, ({ value }) => {
|
|
97
|
+
Debug.traceLevel = value;
|
|
98
|
+
});
|
|
99
|
+
|
|
95
100
|
connection.onInitialize(
|
|
96
|
-
async ({ capabilities, workspaceFolders, initializationOptions }) => {
|
|
101
|
+
async ({ capabilities, workspaceFolders, initializationOptions, trace }) => {
|
|
97
102
|
const { languageIdExtensionMap } =
|
|
98
103
|
initializationOptions as InitializationOptions;
|
|
99
104
|
setLanguageIdExtensionMap(languageIdExtensionMap);
|
|
105
|
+
Debug.traceLevel = trace;
|
|
100
106
|
|
|
101
107
|
hasWorkspaceFolderCapability = !!(
|
|
102
108
|
capabilities.workspace && capabilities.workspace.workspaceFolders
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LanguageServerNotifications as Notifications } from "../../messages";
|
|
2
|
-
import { Connection } from "vscode-languageserver/node";
|
|
2
|
+
import { Connection, TraceValues } from "vscode-languageserver/node";
|
|
3
|
+
import { format } from "util";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* for errors (and other logs in debug mode) we want to print
|
|
@@ -15,9 +16,27 @@ const createAndTrimStackTrace = () => {
|
|
|
15
16
|
: stack;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
type Logger = (message?: any) => void;
|
|
19
|
+
type Logger = (message?: any, minLevel?: TraceLevel) => void;
|
|
20
|
+
export enum TraceLevel {
|
|
21
|
+
"off" = 0,
|
|
22
|
+
"messages" = 1,
|
|
23
|
+
"verbose" = 2,
|
|
24
|
+
}
|
|
19
25
|
|
|
20
26
|
export class Debug {
|
|
27
|
+
private static _traceLevel: TraceLevel = TraceLevel.off;
|
|
28
|
+
public static get traceLevel(): TraceLevel {
|
|
29
|
+
return Debug._traceLevel;
|
|
30
|
+
}
|
|
31
|
+
public static set traceLevel(value: TraceValues | undefined) {
|
|
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 = TraceLevel.messages;
|
|
36
|
+
} else {
|
|
37
|
+
this._traceLevel = TraceLevel[value || "off"];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
21
40
|
private static connection?: Connection;
|
|
22
41
|
private static infoLogger: Logger = (message) =>
|
|
23
42
|
console.log("[INFO] " + message);
|
|
@@ -67,17 +86,39 @@ export class Debug {
|
|
|
67
86
|
if (error) Debug.errorLogger = error;
|
|
68
87
|
}
|
|
69
88
|
|
|
70
|
-
public static info(message: string) {
|
|
71
|
-
Debug.infoLogger(message);
|
|
89
|
+
public static info(message: string, ...param: any[]) {
|
|
90
|
+
Debug.infoLogger(format(message, ...param));
|
|
72
91
|
}
|
|
73
92
|
|
|
74
|
-
public static error(message: string) {
|
|
93
|
+
public static error(message: string, ...param: any[]) {
|
|
75
94
|
const stack = createAndTrimStackTrace();
|
|
76
|
-
Debug.errorLogger(`${message}\n${stack}`);
|
|
95
|
+
Debug.errorLogger(`${format(message, ...param)}\n${stack}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public static warning(message: string, ...param: any[]) {
|
|
99
|
+
Debug.warningLogger(format(message, ...param));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public static traceMessage(
|
|
103
|
+
short: string,
|
|
104
|
+
verbose = short,
|
|
105
|
+
...verboseParams: any[]
|
|
106
|
+
) {
|
|
107
|
+
if (Debug.traceLevel >= TraceLevel.verbose) {
|
|
108
|
+
// directly logging to `console` because
|
|
109
|
+
// we don't want to send yet another notification that will be traced
|
|
110
|
+
console.info(verbose, ...verboseParams);
|
|
111
|
+
} else if (Debug.traceLevel >= TraceLevel.messages) {
|
|
112
|
+
console.info(short);
|
|
113
|
+
}
|
|
77
114
|
}
|
|
78
115
|
|
|
79
|
-
public static
|
|
80
|
-
Debug.
|
|
116
|
+
public static traceVerbose(message: string, ...params: any[]) {
|
|
117
|
+
if (Debug.traceLevel >= TraceLevel.verbose) {
|
|
118
|
+
// directly logging to `console` because
|
|
119
|
+
// we don't want to send yet another notification that will be traced
|
|
120
|
+
console.info(message, ...params);
|
|
121
|
+
}
|
|
81
122
|
}
|
|
82
123
|
|
|
83
124
|
public static sendErrorTelemetry(message: string) {
|