@mrclrchtr/supi-lsp 11.0.1 → 11.2.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/README.md +43 -6
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +41 -1
- package/node_modules/ignore/README.md +36 -10
- package/node_modules/ignore/index.d.ts +3 -2
- package/node_modules/ignore/index.js +57 -53
- package/node_modules/ignore/legacy.js +50 -46
- package/node_modules/ignore/package.json +1 -1
- package/node_modules/semver/LICENSE +15 -0
- package/node_modules/semver/README.md +680 -0
- package/node_modules/semver/bin/semver.js +195 -0
- package/node_modules/semver/classes/comparator.js +143 -0
- package/node_modules/semver/classes/index.js +7 -0
- package/node_modules/semver/classes/range.js +577 -0
- package/node_modules/semver/classes/semver.js +350 -0
- package/node_modules/semver/functions/clean.js +8 -0
- package/node_modules/semver/functions/cmp.js +54 -0
- package/node_modules/semver/functions/coerce.js +62 -0
- package/node_modules/semver/functions/compare-build.js +9 -0
- package/node_modules/semver/functions/compare-loose.js +5 -0
- package/node_modules/semver/functions/compare.js +7 -0
- package/node_modules/semver/functions/diff.js +60 -0
- package/node_modules/semver/functions/eq.js +5 -0
- package/node_modules/semver/functions/gt.js +5 -0
- package/node_modules/semver/functions/gte.js +5 -0
- package/node_modules/semver/functions/inc.js +21 -0
- package/node_modules/semver/functions/lt.js +5 -0
- package/node_modules/semver/functions/lte.js +5 -0
- package/node_modules/semver/functions/major.js +5 -0
- package/node_modules/semver/functions/minor.js +5 -0
- package/node_modules/semver/functions/neq.js +5 -0
- package/node_modules/semver/functions/parse.js +18 -0
- package/node_modules/semver/functions/patch.js +5 -0
- package/node_modules/semver/functions/prerelease.js +8 -0
- package/node_modules/semver/functions/rcompare.js +5 -0
- package/node_modules/semver/functions/rsort.js +5 -0
- package/node_modules/semver/functions/satisfies.js +12 -0
- package/node_modules/semver/functions/sort.js +5 -0
- package/node_modules/semver/functions/truncate.js +48 -0
- package/node_modules/semver/functions/valid.js +8 -0
- package/node_modules/semver/index.js +93 -0
- package/node_modules/semver/internal/constants.js +37 -0
- package/node_modules/semver/internal/debug.js +11 -0
- package/node_modules/semver/internal/identifiers.js +29 -0
- package/node_modules/semver/internal/lrucache.js +42 -0
- package/node_modules/semver/internal/parse-options.js +17 -0
- package/node_modules/semver/internal/re.js +223 -0
- package/node_modules/semver/package.json +78 -0
- package/node_modules/semver/preload.js +4 -0
- package/node_modules/semver/range.bnf +17 -0
- package/node_modules/semver/ranges/gtr.js +6 -0
- package/node_modules/semver/ranges/intersects.js +9 -0
- package/node_modules/semver/ranges/ltr.js +6 -0
- package/node_modules/semver/ranges/max-satisfying.js +27 -0
- package/node_modules/semver/ranges/min-satisfying.js +26 -0
- package/node_modules/semver/ranges/min-version.js +63 -0
- package/node_modules/semver/ranges/outside.js +82 -0
- package/node_modules/semver/ranges/simplify.js +49 -0
- package/node_modules/semver/ranges/subset.js +249 -0
- package/node_modules/semver/ranges/to-comparators.js +10 -0
- package/node_modules/semver/ranges/valid.js +13 -0
- package/node_modules/vscode-jsonrpc/README.md +5 -0
- package/node_modules/vscode-jsonrpc/lib/browser/ril.js +8 -0
- package/node_modules/vscode-jsonrpc/lib/common/connection.js +7 -2
- package/node_modules/vscode-jsonrpc/lib/common/ral.d.ts +8 -0
- package/node_modules/vscode-jsonrpc/lib/node/main.d.ts +14 -0
- package/node_modules/vscode-jsonrpc/lib/node/main.js +6 -4
- package/node_modules/vscode-jsonrpc/lib/node/ril.js +5 -1
- package/node_modules/vscode-jsonrpc/package.json +4 -2
- package/node_modules/vscode-languageserver-protocol/package.json +4 -3
- package/node_modules/vscode-languageserver-types/lib/esm/main.js +2 -2
- package/node_modules/vscode-languageserver-types/lib/umd/main.js +2 -2
- package/node_modules/vscode-languageserver-types/package.json +2 -1
- package/package.json +8 -6
- package/src/client/client.ts +44 -5
- package/src/config/config.ts +53 -2
- package/src/config/operation-support.ts +19 -4
- package/src/config/server-config.ts +22 -0
- package/src/config/typescript-launch.ts +276 -0
- package/src/manager/manager-project-info.ts +22 -10
- package/src/manager/manager.ts +53 -20
- package/src/provider/refactor-planning.ts +4 -3
- package/src/session/runtime-controller.ts +2 -2
- package/src/session/scanner.ts +27 -15
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-jsonrpc",
|
|
3
3
|
"description": "A json rpc implementation over streams",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.0",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/jsonrpc",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"url": "https://github.com/Microsoft/vscode-languageserver-node/issues"
|
|
14
15
|
},
|
|
15
16
|
"engines": {
|
|
16
|
-
"node": ">=14.
|
|
17
|
+
"node": ">=14.17.0"
|
|
17
18
|
},
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/msgpack-lite": "^0.1.12",
|
|
35
|
+
"@types/node": "22.13.14",
|
|
34
36
|
"msgpack-lite": "^0.1.26"
|
|
35
37
|
},
|
|
36
38
|
"scripts": {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-protocol",
|
|
3
3
|
"description": "VSCode Language Server Protocol implementation",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.5",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/protocol",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"vscode-jsonrpc": "
|
|
31
|
-
"vscode-languageserver-types": "3.18.
|
|
31
|
+
"vscode-jsonrpc": "10.0.0",
|
|
32
|
+
"vscode-languageserver-types": "3.18.5"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
35
|
"prepublishOnly": "npm run all:publish",
|
|
@@ -222,7 +222,7 @@ export var ColorPresentation;
|
|
|
222
222
|
function is(value) {
|
|
223
223
|
const candidate = value;
|
|
224
224
|
return Is.objectLiteral(candidate) && Is.string(candidate.label)
|
|
225
|
-
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate))
|
|
225
|
+
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate.textEdit))
|
|
226
226
|
&& (Is.undefined(candidate.additionalTextEdits) || Is.typedArray(candidate.additionalTextEdits, TextEdit.is));
|
|
227
227
|
}
|
|
228
228
|
ColorPresentation.is = is;
|
|
@@ -279,7 +279,7 @@ export var FoldingRange;
|
|
|
279
279
|
*/
|
|
280
280
|
function is(value) {
|
|
281
281
|
const candidate = value;
|
|
282
|
-
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.
|
|
282
|
+
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.endLine)
|
|
283
283
|
&& (Is.undefined(candidate.startCharacter) || Is.uinteger(candidate.startCharacter))
|
|
284
284
|
&& (Is.undefined(candidate.endCharacter) || Is.uinteger(candidate.endCharacter))
|
|
285
285
|
&& (Is.undefined(candidate.kind) || Is.string(candidate.kind));
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
function is(value) {
|
|
234
234
|
var candidate = value;
|
|
235
235
|
return Is.objectLiteral(candidate) && Is.string(candidate.label)
|
|
236
|
-
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate))
|
|
236
|
+
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate.textEdit))
|
|
237
237
|
&& (Is.undefined(candidate.additionalTextEdits) || Is.typedArray(candidate.additionalTextEdits, TextEdit.is));
|
|
238
238
|
}
|
|
239
239
|
ColorPresentation.is = is;
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
*/
|
|
291
291
|
function is(value) {
|
|
292
292
|
var candidate = value;
|
|
293
|
-
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.
|
|
293
|
+
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.endLine)
|
|
294
294
|
&& (Is.undefined(candidate.startCharacter) || Is.uinteger(candidate.startCharacter))
|
|
295
295
|
&& (Is.undefined(candidate.endCharacter) || Is.uinteger(candidate.endCharacter))
|
|
296
296
|
&& (Is.undefined(candidate.kind) || Is.string(candidate.kind));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-types",
|
|
3
3
|
"description": "Types used by the Language server for node",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.5",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/types",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-lsp",
|
|
3
|
-
"version": "11.0
|
|
3
|
+
"version": "11.2.0",
|
|
4
4
|
"description": "Language Server Protocol runtime for SuPi code intelligence",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,17 +33,19 @@
|
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"ignore": "^7.0.5",
|
|
36
|
+
"semver": "^7.8.5",
|
|
36
37
|
"typescript": "6.0.3",
|
|
37
|
-
"vscode-jsonrpc": "^
|
|
38
|
-
"vscode-languageserver-protocol": "^3.18.
|
|
39
|
-
"vscode-languageserver-types": "^3.18.
|
|
40
|
-
"@mrclrchtr/supi-core": "11.0
|
|
41
|
-
"@mrclrchtr/supi-code-runtime": "11.0
|
|
38
|
+
"vscode-jsonrpc": "^10.0.0",
|
|
39
|
+
"vscode-languageserver-protocol": "^3.18.5",
|
|
40
|
+
"vscode-languageserver-types": "^3.18.5",
|
|
41
|
+
"@mrclrchtr/supi-core": "11.2.0",
|
|
42
|
+
"@mrclrchtr/supi-code-runtime": "11.2.0"
|
|
42
43
|
},
|
|
43
44
|
"bundledDependencies": [
|
|
44
45
|
"@mrclrchtr/supi-code-runtime",
|
|
45
46
|
"@mrclrchtr/supi-core",
|
|
46
47
|
"ignore",
|
|
48
|
+
"semver",
|
|
47
49
|
"typescript",
|
|
48
50
|
"vscode-jsonrpc",
|
|
49
51
|
"vscode-languageserver-protocol",
|
package/src/client/client.ts
CHANGED
|
@@ -51,6 +51,7 @@ import type {
|
|
|
51
51
|
WorkspaceEdit,
|
|
52
52
|
WorkspaceSymbol,
|
|
53
53
|
} from "../config/types.ts";
|
|
54
|
+
import { resolveTypeScriptLaunch, type TypeScriptLaunch } from "../config/typescript-launch.ts";
|
|
54
55
|
import { boundCwd } from "../debug-telemetry.ts";
|
|
55
56
|
import type { DiagnosticEvidenceSummary } from "../diagnostics/evidence.ts";
|
|
56
57
|
import { raceRequestControl } from "../session/readiness.ts";
|
|
@@ -82,6 +83,9 @@ import { SemanticInputSynchronizationError } from "./client-semantic-input-error
|
|
|
82
83
|
import { JsonRpcClient, JsonRpcRequestError } from "./transport.ts";
|
|
83
84
|
|
|
84
85
|
const SHUTDOWN_TIMEOUT_MS = 5_000;
|
|
86
|
+
// ContentModified can outlive the server's progress notifications. Yield before
|
|
87
|
+
// spending the single retry instead of immediately racing the same analysis.
|
|
88
|
+
const CONTENT_MODIFIED_RETRY_DELAY_MS = 100;
|
|
85
89
|
|
|
86
90
|
/** Bounded stderr tail kept for startup-failure error messages. */
|
|
87
91
|
const STDERR_TAIL_MAX_CHARS = 4_000;
|
|
@@ -588,6 +592,13 @@ export class LspClient {
|
|
|
588
592
|
});
|
|
589
593
|
}
|
|
590
594
|
|
|
595
|
+
private launchSelection: TypeScriptLaunch | undefined;
|
|
596
|
+
|
|
597
|
+
/** Compiler used by this generation, never re-probed while it is healthy. */
|
|
598
|
+
get typescriptSelection() {
|
|
599
|
+
return this.launchSelection?.typescript;
|
|
600
|
+
}
|
|
601
|
+
|
|
591
602
|
get status(): ClientStatus {
|
|
592
603
|
return this._status;
|
|
593
604
|
}
|
|
@@ -667,8 +678,14 @@ export class LspClient {
|
|
|
667
678
|
// ── Lifecycle ───────────────────────────────────────────────────────
|
|
668
679
|
/** Spawn the server process and perform the initialize handshake. */
|
|
669
680
|
async start(): Promise<void> {
|
|
670
|
-
|
|
671
|
-
|
|
681
|
+
try {
|
|
682
|
+
this.launchSelection = resolveTypeScriptLaunch(this.name, this.config, this.root);
|
|
683
|
+
} catch (error) {
|
|
684
|
+
this.handleProcessFailure(error instanceof Error ? error : new Error(String(error)));
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
const { command: cmd = this.config.command, args = this.config.args ?? [] } =
|
|
688
|
+
this.launchSelection;
|
|
672
689
|
this.startedAt = Date.now();
|
|
673
690
|
|
|
674
691
|
try {
|
|
@@ -738,7 +755,7 @@ export class LspClient {
|
|
|
738
755
|
},
|
|
739
756
|
],
|
|
740
757
|
capabilities: CLIENT_CAPABILITIES,
|
|
741
|
-
initializationOptions: this.
|
|
758
|
+
initializationOptions: this.launchSelection.initializationOptions,
|
|
742
759
|
})) as InitializeResult;
|
|
743
760
|
|
|
744
761
|
const positionEncoding = result.capabilities.positionEncoding ?? "utf-16";
|
|
@@ -1270,8 +1287,10 @@ export class LspClient {
|
|
|
1270
1287
|
context: CodeActionContext,
|
|
1271
1288
|
control?: CodeRequestControl,
|
|
1272
1289
|
): Promise<CodeQueryResult<CodeAction[] | null>> {
|
|
1290
|
+
const backend = this.typescriptSelection?.backend;
|
|
1291
|
+
const server = `LSP server "${this.name}"${backend ? ` (${backend} backend)` : ""}`;
|
|
1273
1292
|
if (!this.supportsCodeActions) {
|
|
1274
|
-
return unavailableCodeQuery(
|
|
1293
|
+
return unavailableCodeQuery(`${server} does not advertise textDocument/codeAction.`);
|
|
1275
1294
|
}
|
|
1276
1295
|
if (typeof filePath !== "string" || filePath.length === 0 || !isRange(range)) {
|
|
1277
1296
|
return unavailableCodeQuery("Code actions require a valid file and range.");
|
|
@@ -1280,7 +1299,9 @@ export class LspClient {
|
|
|
1280
1299
|
return unavailableCodeQuery("Code actions require a valid context.");
|
|
1281
1300
|
}
|
|
1282
1301
|
if (context.only && !this.supportsCodeActionKinds(context.only)) {
|
|
1283
|
-
return unavailableCodeQuery(
|
|
1302
|
+
return unavailableCodeQuery(
|
|
1303
|
+
`${server} does not advertise the requested code-action kind: ${context.only.join(", ")}.`,
|
|
1304
|
+
);
|
|
1284
1305
|
}
|
|
1285
1306
|
|
|
1286
1307
|
const requestContext: CodeActionContext = {
|
|
@@ -1498,6 +1519,9 @@ export class LspClient {
|
|
|
1498
1519
|
for (;;) {
|
|
1499
1520
|
const attempt: SemanticRequestAttemptState = { inputRevision: undefined };
|
|
1500
1521
|
try {
|
|
1522
|
+
if (retryGuard.retryReason === "content-modified") {
|
|
1523
|
+
await this.waitForContentModifiedRetry(control);
|
|
1524
|
+
}
|
|
1501
1525
|
const data = await this.runSemanticRequestAttempt<T>({
|
|
1502
1526
|
method,
|
|
1503
1527
|
params,
|
|
@@ -1515,6 +1539,21 @@ export class LspClient {
|
|
|
1515
1539
|
}
|
|
1516
1540
|
}
|
|
1517
1541
|
|
|
1542
|
+
/** Pause only the protocol retry, without extending the caller's deadline. */
|
|
1543
|
+
private async waitForContentModifiedRetry(control?: CodeRequestControl): Promise<void> {
|
|
1544
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1545
|
+
try {
|
|
1546
|
+
await raceRequestControl(
|
|
1547
|
+
new Promise<void>((resolve) => {
|
|
1548
|
+
timer = setTimeout(resolve, CONTENT_MODIFIED_RETRY_DELAY_MS);
|
|
1549
|
+
}),
|
|
1550
|
+
control,
|
|
1551
|
+
);
|
|
1552
|
+
} finally {
|
|
1553
|
+
if (timer) clearTimeout(timer);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1518
1557
|
/** Return only when another attempt is permitted; retain the cause when retry stops. */
|
|
1519
1558
|
private prepareSemanticRetry(options: {
|
|
1520
1559
|
method: string;
|
package/src/config/config.ts
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getSupiConfigPath,
|
|
8
|
+
loadSupiConfigForScope,
|
|
9
|
+
loadSupiConfigSectionForScope,
|
|
10
|
+
} from "@mrclrchtr/supi-core/config";
|
|
7
11
|
import { truncateDebugIdentity } from "@mrclrchtr/supi-core/debug";
|
|
8
12
|
import type { JsonObject, JsonValue, LspConfig, ServerConfig } from "./types.ts";
|
|
9
13
|
|
|
14
|
+
import { isManualTypeScriptLaunch, isTypeScriptPackageName } from "./typescript-launch.ts";
|
|
15
|
+
|
|
10
16
|
const CONFIG_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
11
17
|
|
|
12
18
|
// Load defaults at module level — resolve relative to this file.
|
|
@@ -65,11 +71,47 @@ export function loadConfig(cwd: string, options?: LoadConfigOptions): LspConfig
|
|
|
65
71
|
{ scope: "project" },
|
|
66
72
|
);
|
|
67
73
|
|
|
74
|
+
const fields: NonNullable<ServerConfig["typescriptExplicitFields"]> = {};
|
|
75
|
+
for (const [scope, servers] of [
|
|
76
|
+
["global", globalLsp.servers],
|
|
77
|
+
["project", projectLsp.servers],
|
|
78
|
+
] as const) {
|
|
79
|
+
captureTypeScriptOrigins(fields, servers?.typescript, getSupiConfigPath(scope, cwd, options));
|
|
80
|
+
}
|
|
68
81
|
const merged = mergeServerConfigs(defaults.servers, globalLsp.servers, projectLsp.servers);
|
|
69
|
-
|
|
82
|
+
if (merged.typescript) {
|
|
83
|
+
merged.typescript = { ...merged.typescript, typescriptExplicitFields: fields };
|
|
84
|
+
isManualTypeScriptLaunch(merged.typescript, cwd);
|
|
85
|
+
}
|
|
70
86
|
return { servers: merged };
|
|
71
87
|
}
|
|
72
88
|
|
|
89
|
+
/** Retain only effective explicit launch fields; initializationOptions replaces its inherited object. */
|
|
90
|
+
function captureTypeScriptOrigins(
|
|
91
|
+
fields: NonNullable<ServerConfig["typescriptExplicitFields"]>,
|
|
92
|
+
value: unknown,
|
|
93
|
+
origin: string,
|
|
94
|
+
): void {
|
|
95
|
+
if (!isRecord(value)) return;
|
|
96
|
+
if (
|
|
97
|
+
Object.hasOwn(value, "typescriptPackage") &&
|
|
98
|
+
!isTypeScriptPackageName(value.typescriptPackage)
|
|
99
|
+
) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Invalid lsp.servers.typescript.typescriptPackage in ${origin}: use an installed package name or alias, not a path.`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const { override } = validateServerOverride(value);
|
|
105
|
+
for (const field of ["command", "args", "typescriptPackage"] as const) {
|
|
106
|
+
if (Object.hasOwn(override, field)) fields[field] = origin;
|
|
107
|
+
}
|
|
108
|
+
if (!Object.hasOwn(override, "initializationOptions")) return;
|
|
109
|
+
delete fields.tsserverPath;
|
|
110
|
+
const init = override.initializationOptions;
|
|
111
|
+
if (isRecord(init) && isRecord(init.tsserver) && Object.hasOwn(init.tsserver, "path"))
|
|
112
|
+
fields.tsserverPath = origin;
|
|
113
|
+
}
|
|
114
|
+
|
|
73
115
|
/**
|
|
74
116
|
* Read effective explicit language disablement for the active LSP snapshot.
|
|
75
117
|
* Project values override global values, including an explicit re-enable.
|
|
@@ -205,6 +247,10 @@ function mergeSingleServer(options: {
|
|
|
205
247
|
}): ServerConfig | null {
|
|
206
248
|
const { name, base, value, builtIn, reportWarning } = options;
|
|
207
249
|
const { override, invalidFields } = validateServerOverride(value);
|
|
250
|
+
if (name !== "typescript" && override.typescriptPackage !== undefined) {
|
|
251
|
+
delete override.typescriptPackage;
|
|
252
|
+
invalidFields.push("typescriptPackage");
|
|
253
|
+
}
|
|
208
254
|
const missingFields = base
|
|
209
255
|
? []
|
|
210
256
|
: [
|
|
@@ -232,6 +278,11 @@ function mergeSingleServer(options: {
|
|
|
232
278
|
type ServerOverrideSetter = (override: Partial<ServerConfig>, candidate: unknown) => boolean;
|
|
233
279
|
|
|
234
280
|
const SERVER_OVERRIDE_SETTERS: Record<string, ServerOverrideSetter> = {
|
|
281
|
+
typescriptPackage(override, candidate) {
|
|
282
|
+
if (!isTypeScriptPackageName(candidate)) return false;
|
|
283
|
+
override.typescriptPackage = candidate;
|
|
284
|
+
return true;
|
|
285
|
+
},
|
|
235
286
|
command(override, candidate) {
|
|
236
287
|
if (typeof candidate !== "string" || candidate.trim().length === 0) return false;
|
|
237
288
|
override.command = candidate;
|
|
@@ -26,12 +26,15 @@ export type ServerOperationSupportMap = Partial<
|
|
|
26
26
|
Record<ServerOperationName, ServerOperationSupport>
|
|
27
27
|
>;
|
|
28
28
|
|
|
29
|
+
const REMOVE_UNUSED_KIND = "source.removeUnused";
|
|
30
|
+
const REMOVE_UNUSED_IMPORTS_KIND = "source.removeUnusedImports";
|
|
31
|
+
|
|
29
32
|
/** Code-action kinds requested by each operation-specific planner. */
|
|
30
33
|
export const REFACTOR_CODE_ACTION_KINDS = {
|
|
31
34
|
extract_function: ["refactor.extract.function"],
|
|
32
35
|
extract_variable: ["refactor.extract.constant", "refactor.extract.variable"],
|
|
33
36
|
update_imports: ["source.organizeImports"],
|
|
34
|
-
delete_dead_code: [
|
|
37
|
+
delete_dead_code: [REMOVE_UNUSED_KIND, REMOVE_UNUSED_IMPORTS_KIND],
|
|
35
38
|
} as const satisfies Record<
|
|
36
39
|
"extract_function" | "extract_variable" | "update_imports" | "delete_dead_code",
|
|
37
40
|
readonly string[]
|
|
@@ -143,6 +146,20 @@ function supportedOperation(
|
|
|
143
146
|
return { server, supi, ...(reason ? { reason } : {}) };
|
|
144
147
|
}
|
|
145
148
|
|
|
149
|
+
function deleteDeadCodeSupport(capabilities: ServerCapabilities | null): ServerOperationSupport {
|
|
150
|
+
const server = codeActionAdvertisement(capabilities, REFACTOR_CODE_ACTION_KINDS.delete_dead_code);
|
|
151
|
+
const importsOnly =
|
|
152
|
+
codeActionAdvertisement(capabilities, [REMOVE_UNUSED_KIND]) !== "advertised" &&
|
|
153
|
+
codeActionAdvertisement(capabilities, [REMOVE_UNUSED_IMPORTS_KIND]) === "advertised";
|
|
154
|
+
return importsOnly
|
|
155
|
+
? supportedOperation(
|
|
156
|
+
server,
|
|
157
|
+
"limited",
|
|
158
|
+
"Only unused-import removal is supported by this mapping, not arbitrary unused declarations.",
|
|
159
|
+
)
|
|
160
|
+
: supportedOperation(server);
|
|
161
|
+
}
|
|
162
|
+
|
|
146
163
|
/** Build the honest operation-support projection for one negotiated server. */
|
|
147
164
|
export function getServerOperationSupport(
|
|
148
165
|
capabilities: ServerCapabilities | null,
|
|
@@ -181,9 +198,7 @@ export function getServerOperationSupport(
|
|
|
181
198
|
update_imports: supportedOperation(
|
|
182
199
|
codeActionAdvertisement(capabilities, REFACTOR_CODE_ACTION_KINDS.update_imports),
|
|
183
200
|
),
|
|
184
|
-
delete_dead_code:
|
|
185
|
-
codeActionAdvertisement(capabilities, REFACTOR_CODE_ACTION_KINDS.delete_dead_code),
|
|
186
|
-
),
|
|
201
|
+
delete_dead_code: deleteDeadCodeSupport(capabilities),
|
|
187
202
|
code_action_resolve: supportedOperation(resolveServer),
|
|
188
203
|
};
|
|
189
204
|
}
|
|
@@ -26,6 +26,20 @@ export interface ServerConfig {
|
|
|
26
26
|
initializationOptions?: unknown;
|
|
27
27
|
/** Maximum time to wait for a single $/progress cycle, in ms. Default: 10_000. */
|
|
28
28
|
readinessTimeoutMs?: number;
|
|
29
|
+
/** TypeScript compiler package name or installed alias, resolved from the route root. */
|
|
30
|
+
typescriptPackage?: string;
|
|
31
|
+
/** @internal Effective explicit-field origins for TypeScript launch policy, not user configuration. */
|
|
32
|
+
typescriptExplicitFields?: Partial<
|
|
33
|
+
Record<"command" | "args" | "tsserverPath" | "typescriptPackage", string>
|
|
34
|
+
>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Compiler selection facts; absent versions are unknown, not inferred from the wrapper. */
|
|
38
|
+
export interface TypeScriptSelection {
|
|
39
|
+
backend: "tsserver" | "native";
|
|
40
|
+
packageName: string;
|
|
41
|
+
compilerVersion?: string;
|
|
42
|
+
wrapperVersion?: string;
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
/** LSP configuration keyed by language name (e.g. `typescript`, `python`). */
|
|
@@ -37,6 +51,10 @@ export interface DetectedProjectServer {
|
|
|
37
51
|
name: string;
|
|
38
52
|
root: string;
|
|
39
53
|
fileTypes: string[];
|
|
54
|
+
/** Resolved automatic compiler selection, when available. */
|
|
55
|
+
typescript?: TypeScriptSelection;
|
|
56
|
+
/** Actionable launch-selection failure, including its root and package. */
|
|
57
|
+
failureMessage?: string;
|
|
40
58
|
}
|
|
41
59
|
|
|
42
60
|
/** Structured reason for a route-level process-crash recovery state. */
|
|
@@ -64,4 +82,8 @@ export interface MissingServer {
|
|
|
64
82
|
command: string;
|
|
65
83
|
/** File extensions found in the project (subset of server.fileTypes). */
|
|
66
84
|
foundExtensions: string[];
|
|
85
|
+
/** Route root when a compiler-selection failure prevents launch. */
|
|
86
|
+
root?: string;
|
|
87
|
+
/** Compiler selection failure, distinct from a missing executable. */
|
|
88
|
+
failureMessage?: string;
|
|
67
89
|
}
|