Skip to content

Commit bc23037

Browse files
authored
Merge pull request #27438 from Microsoft/failedLookupNotMatchingPath
Handle the case of failed lookup location being not normalized in resolutionCache to watch the path
2 parents 7c87546 + ee04b8c commit bc23037

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)