Skip to content

Commit ee04b8c

Browse files
committed
Handle the case of failed lookup location being not normalized.
Also fixed issue where type defs with relative name didnt resolve when directoryExists is present on the host Fixes #27405
1 parent 6d92a29 commit ee04b8c

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,14 @@ namespace ts {
337337
if (traceEnabled) {
338338
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
339339
}
340-
const result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined);
340+
let result: SearchResult<Resolved> | undefined;
341+
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
342+
result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined);
343+
}
344+
else {
345+
const { path: candidate } = normalizePathAndParts(combinePaths(initialLocationForSecondaryLookup, typeReferenceDirectiveName));
346+
result = toSearchResult(nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true));
347+
}
341348
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
342349
if (!resolvedFile && traceEnabled) {
343350
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);

src/compiler/resolutionCache.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,8 @@ namespace ts {
398398

399399
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
400400
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
401-
failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? failedLookupLocation : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory());
401+
// Ensure failed look up is normalized path
402+
failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory());
402403
Debug.assert(failedLookupLocation.length === failedLookupLocationPath.length, `FailedLookup: ${failedLookupLocation} failedLookupLocationPath: ${failedLookupLocationPath}`); // tslint:disable-line
403404
const subDirectoryInRoot = failedLookupLocationPath.indexOf(directorySeparator, rootPath.length + 1);
404405
if (subDirectoryInRoot !== -1) {

src/testRunner/unittests/moduleResolution.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,14 +1104,18 @@ import b = require("./moduleB");
11041104
});
11051105

11061106
describe("Type reference directive resolution: ", () => {
1107-
function test(typesRoot: string, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) {
1108-
const host = createModuleResolutionHost(/*hasDirectoryExists*/ false, ...[initialFile, targetFile].concat(...otherFiles));
1109-
const result = resolveTypeReferenceDirective(typeDirective, initialFile.name, { typeRoots: [typesRoot] }, host);
1107+
function testWorker(hasDirectoryExists: boolean, typesRoot: string | undefined, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) {
1108+
const host = createModuleResolutionHost(hasDirectoryExists, ...[initialFile, targetFile].concat(...otherFiles));
1109+
const result = resolveTypeReferenceDirective(typeDirective, initialFile.name, typesRoot ? { typeRoots: [typesRoot] } : {}, host);
11101110
assert(result.resolvedTypeReferenceDirective!.resolvedFileName !== undefined, "expected type directive to be resolved");
11111111
assert.equal(result.resolvedTypeReferenceDirective!.resolvedFileName, targetFile.name, "unexpected result of type reference resolution");
11121112
assert.equal(result.resolvedTypeReferenceDirective!.primary, primary, "unexpected 'primary' value");
11131113
}
11141114

1115+
function test(typesRoot: string, typeDirective: string, primary: boolean, initialFile: File, targetFile: File, ...otherFiles: File[]) {
1116+
testWorker(/*hasDirectoryExists*/ false, typesRoot, typeDirective, primary, initialFile, targetFile, ...otherFiles);
1117+
}
1118+
11151119
it("Can be resolved from primary location", () => {
11161120
{
11171121
const f1 = { name: "/root/src/app.ts" };
@@ -1194,7 +1198,7 @@ import b = require("./moduleB");
11941198
const names = map(files, f => f.name);
11951199
const sourceFiles = arrayToMap(map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES2015)), f => f.fileName);
11961200
const compilerHost: CompilerHost = {
1197-
fileExists : fileName => sourceFiles.has(fileName),
1201+
fileExists: fileName => sourceFiles.has(fileName),
11981202
getSourceFile: fileName => sourceFiles.get(fileName),
11991203
getDefaultLibFileName: () => "lib.d.ts",
12001204
writeFile: notImplemented,
@@ -1219,7 +1223,7 @@ import b = require("./moduleB");
12191223
assert.equal(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic");
12201224
});
12211225

1222-
it ("Modules in the same .d.ts file are preferred to external files", () => {
1226+
it("Modules in the same .d.ts file are preferred to external files", () => {
12231227
const f = {
12241228
name: "/a/b/c/c/app.d.ts",
12251229
content: `
@@ -1233,7 +1237,7 @@ import b = require("./moduleB");
12331237
};
12341238
const file = createSourceFile(f.name, f.content, ScriptTarget.ES2015);
12351239
const compilerHost: CompilerHost = {
1236-
fileExists : fileName => fileName === file.fileName,
1240+
fileExists: fileName => fileName === file.fileName,
12371241
getSourceFile: fileName => fileName === file.fileName ? file : undefined,
12381242
getDefaultLibFileName: () => "lib.d.ts",
12391243
writeFile: notImplemented,
@@ -1248,7 +1252,7 @@ import b = require("./moduleB");
12481252
createProgram([f.name], {}, compilerHost);
12491253
});
12501254

1251-
it ("Modules in .ts file are not checked in the same file", () => {
1255+
it("Modules in .ts file are not checked in the same file", () => {
12521256
const f = {
12531257
name: "/a/b/c/c/app.ts",
12541258
content: `
@@ -1262,7 +1266,7 @@ import b = require("./moduleB");
12621266
};
12631267
const file = createSourceFile(f.name, f.content, ScriptTarget.ES2015);
12641268
const compilerHost: CompilerHost = {
1265-
fileExists : fileName => fileName === file.fileName,
1269+
fileExists: fileName => fileName === file.fileName,
12661270
getSourceFile: fileName => fileName === file.fileName ? file : undefined,
12671271
getDefaultLibFileName: () => "lib.d.ts",
12681272
writeFile: notImplemented,
@@ -1279,5 +1283,15 @@ import b = require("./moduleB");
12791283
};
12801284
createProgram([f.name], {}, compilerHost);
12811285
});
1286+
describe("can be resolved when typeReferenceDirective is relative and in a sibling folder", () => {
1287+
const initialFile = { name: "/root/src/background/app.ts" };
1288+
const targetFile = { name: "/root/src/typedefs/filesystem.d.ts" };
1289+
it("when host doesnt have directoryExists", () => {
1290+
testWorker(/*hasDirectoryExists*/ false, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", /*primary*/ false, initialFile, targetFile);
1291+
});
1292+
it("when host has directoryExists", () => {
1293+
testWorker(/*hasDirectoryExists*/ true, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", /*primary*/ false, initialFile, targetFile);
1294+
});
1295+
});
12821296
});
12831297
}

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9688,6 +9688,32 @@ declare class TestLib {
96889688
host.writeFile(appLib.path, appLib.content.replace("test()", "test2()"));
96899689
host.checkTimeoutQueueLengthAndRun(2);
96909690
});
9691+
9692+
it("when typeReferenceDirective is relative path and in a sibling folder", () => {
9693+
const projectRootPath = "/user/username/projects/browser-addon";
9694+
const projectPath = `${projectRootPath}/background`;
9695+
const file: File = {
9696+
path: `${projectPath}/a.ts`,
9697+
content: "let x = 10;"
9698+
};
9699+
const tsconfig: File = {
9700+
path: `${projectPath}/tsconfig.json`,
9701+
content: JSON.stringify({
9702+
compilerOptions: {
9703+
types: [
9704+
"../typedefs/filesystem"
9705+
] }
9706+
})
9707+
};
9708+
const filesystem: File = {
9709+
path: `${projectRootPath}/typedefs/filesystem.d.ts`,
9710+
content: `interface LocalFileSystem { someProperty: string; }`
9711+
};
9712+
const files = [file, tsconfig, filesystem, libFile];
9713+
const host = createServerHost(files);
9714+
const service = createProjectService(host);
9715+
service.openClientFile(file.path);
9716+
});
96919717
});
96929718

96939719
describe("tsserverProjectSystem project references", () => {

0 commit comments

Comments
 (0)