From b66d51a362fa436ec511682fa2baa92cd6f2e17b Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Tue, 27 Sep 2022 11:42:21 -0700 Subject: [PATCH] fix(server): resolve tsdk correctly when settings specify a relative location (#1765) Previously, we only supported absolute paths for `tsdk` specified in the settings.json. However, with Yarn PnP, this might instead be a path relative to the project/workspace. For example, in a a project using Yarn PnP, the tsdk setting might be ``` "typescript.tsdk": ".yarn/sdks/typescript/lib", ``` The user would then run `yarn dlx @yarnpkg/sdks vscode` and the typescript modules would then exist in the project folder `.yarn/sdks/typescript/...`. We should then resolve tsdk as a relative path from the given probe locations, just like we do when looking for other packages in a regular project (in the `node_modules`, relative to the given probe locations). Fixes #1748 (cherry picked from commit 05ef44eb84b6971cc9932cbe5f275b3f7cc6f490) --- server/src/version_provider.ts | 49 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/server/src/version_provider.ts b/server/src/version_provider.ts index ba78142e18..1860ac880b 100644 --- a/server/src/version_provider.ts +++ b/server/src/version_provider.ts @@ -50,7 +50,7 @@ function resolveWithMinVersion( export function resolveTsServer(probeLocations: string[]): NodeModule { if (probeLocations.length > 0) { // The first probe location is `typescript.tsdk` if it is specified. - const resolvedFromTsdk = resolveTsServerFromTsdk(probeLocations[0]); + const resolvedFromTsdk = resolveTsServerFromTsdk(probeLocations[0], probeLocations.slice(1)); if (resolvedFromTsdk !== undefined) { return resolvedFromTsdk; } @@ -58,31 +58,38 @@ export function resolveTsServer(probeLocations: string[]): NodeModule { return resolveWithMinVersion(TSSERVERLIB, MIN_TS_VERSION, probeLocations, 'typescript'); } -function resolveTsServerFromTsdk(tsdk: string): NodeModule|undefined { +function resolveTsServerFromTsdk(tsdk: string, probeLocations: string[]): NodeModule|undefined { // `tsdk` is the folder path to the tsserver and lib*.d.ts files under a // TypeScript install, for example // - /google/src/head/depot/google3/third_party/javascript/node_modules/typescript/stable/lib - if (!path.isAbsolute(tsdk)) { - return undefined; + // When the `tsdk` is an absolute path, we only look there for TS Server. + // When it is a relative path, we look for that tsdk relative to the rest of the probe locations. + if (path.isAbsolute(tsdk)) { + probeLocations = [tsdk]; + } else { + probeLocations = probeLocations.map(location => path.join(location, tsdk)); } - const tsserverlib = path.join(tsdk, 'tsserverlibrary.js'); - if (!fs.existsSync(tsserverlib)) { - return undefined; - } - const packageJson = path.resolve(tsserverlib, '../../package.json'); - if (!fs.existsSync(packageJson)) { - return undefined; - } - try { - const json = JSON.parse(fs.readFileSync(packageJson, 'utf8')); - return { - name: TSSERVERLIB, - resolvedPath: tsserverlib, - version: new Version(json.version), - }; - } catch { - return undefined; + for (const location of probeLocations) { + const tsserverlib = path.join(location, 'tsserverlibrary.js'); + if (!fs.existsSync(tsserverlib)) { + continue; + } + const packageJson = path.resolve(tsserverlib, '../../package.json'); + if (!fs.existsSync(packageJson)) { + continue; + } + try { + const json = JSON.parse(fs.readFileSync(packageJson, 'utf8')); + return { + name: TSSERVERLIB, + resolvedPath: tsserverlib, + version: new Version(json.version), + }; + } catch { + continue; + } } + return undefined; } /**