Skip to content
38 changes: 30 additions & 8 deletions _extension/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,19 +349,31 @@ interface DetectedVersion {
label: string;
version: string;
tsdkPath: string;
relativeTsdkPath: string;
exePath: string;
}

async function findWorkspaceNativePreviewPackages(): Promise<DetectedVersion[]> {
const results: DetectedVersion[] = [];
for (const folder of vscode.workspace.workspaceFolders ?? []) {
const packagePath = vscode.Uri.joinPath(folder.uri, "node_modules", "@typescript", "native-preview");
const folders = vscode.workspace.workspaceFolders ?? [];
const relativeWorkspacePath = "node_modules/@typescript/native-preview";
const pathSegments = relativeWorkspacePath.split("/");
for (let i = 0; i < folders.length; i++) {
const folder = folders[i];
const packagePath = vscode.Uri.joinPath(folder.uri, ...pathSegments);
const resolved = await resolveTsdkPathToExe(path.normalize(packagePath.fsPath));
if (!resolved) continue;
// Use a relative path only for the first workspace folder since
// workspaceResolve anchors relative paths there. For other folders,
// fall back to the absolute path so the setting resolves correctly.
Comment on lines +366 to +368

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic seems to be hacks on hacks. Why not just funnel along the workspace path and calculate the relative path from that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted relativeWorkspacePath as a constant above the loop. It's now used both as the argument to joinPath (split on /) and to construct the relative tsdk path (prepending ./). This eliminates the duplication and makes the relationship clear.

const relativeTsdkPath = i === 0
? `./${relativeWorkspacePath}`
: path.normalize(packagePath.fsPath);
results.push({
label: folder.name,
version: resolved?.version ?? "unknown",
tsdkPath: path.normalize(packagePath.fsPath),
relativeTsdkPath,
exePath: resolved?.path ?? "",
});
}
Expand All @@ -383,22 +395,25 @@ async function promptSelectVersion(context: vscode.ExtensionContext, client: Cli
detail: builtinExe.path,
run: async () => {
await context.workspaceState.update(useWorkspaceTsdkStorageKey, false);
await config.update("tsdk", undefined, vscode.ConfigurationTarget.Workspace);
// Suppress the workspace-version prompt so it doesn't re-fire
// after the user explicitly chose bundled.
await context.workspaceState.update("typescript.native-preview.suppressPromptWorkspaceTsdk", true);
outputChannel.appendLine("Switched to bundled tsgo version.");
},
});

// Workspace versions
if (vscode.workspace.isTrusted) {
for (const wsVersion of workspaceVersions) {
const isActive = currentExePath === wsVersion.tsdkPath;
const isActive = currentExePath === wsVersion.exePath;
items.push({
label: (isActive ? "• " : "") + "Use Workspace Version",
description: wsVersion.version,
detail: wsVersion.tsdkPath,
detail: wsVersion.relativeTsdkPath,
run: async () => {
await context.workspaceState.update(useWorkspaceTsdkStorageKey, true);
await config.update("tsdk", wsVersion.tsdkPath, vscode.ConfigurationTarget.Workspace);
await context.workspaceState.update("typescript.native-preview.suppressPromptWorkspaceTsdk", false);
await config.update("tsdk", wsVersion.relativeTsdkPath, vscode.ConfigurationTarget.Workspace);
outputChannel.appendLine(`Switched to workspace tsgo version (${wsVersion.version}).`);
},
});
Expand Down Expand Up @@ -473,6 +488,7 @@ export async function promptUseWorkspaceVersion(context: vscode.ExtensionContext
const workspaceVersions = await findWorkspaceNativePreviewPackages();
if (workspaceVersions.length === 0) return;

const config = vscode.workspace.getConfiguration("typescript.native-preview");
const wsVersion = workspaceVersions[0];
const allow = "Allow";
const dismiss = "Dismiss";
Expand All @@ -488,8 +504,14 @@ export async function promptUseWorkspaceVersion(context: vscode.ExtensionContext
if (result === allow) {
if (!vscode.workspace.isTrusted) return;
await context.workspaceState.update(useWorkspaceTsdkStorageKey, true);
const config = vscode.workspace.getConfiguration("typescript.native-preview");
await config.update("tsdk", wsVersion.tsdkPath, vscode.ConfigurationTarget.Workspace);
// Only write tsdk if it isn't already pointing at the workspace install,
// so we don't overwrite a committed relative path with a new value.
const currentTsdk = config.get<string>("tsdk");
const resolvedCurrent = currentTsdk ? await resolveTsdkPathToExe(currentTsdk) : undefined;
const alreadyResolved = resolvedCurrent && workspaceVersions.some(ws => ws.exePath === resolvedCurrent.path);
if (!alreadyResolved) {
await config.update("tsdk", wsVersion.relativeTsdkPath, vscode.ConfigurationTarget.Workspace);
}
await vscode.commands.executeCommand("typescript.native-preview.restart");
}
else if (result === suppress) {
Expand Down