From c7091ab01b70fd3369979fb7bfe811e6dd07915f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 29 May 2018 13:45:20 -0700 Subject: [PATCH 1/2] Add test that verifies watched directories and files when resolution of module references sibling folder to root with symlLink --- src/harness/unittests/tscWatchMode.ts | 65 ++++++++++++++++--- .../unittests/tsserverProjectSystem.ts | 23 +++---- src/harness/virtualFileSystemWithWatch.ts | 32 ++++++--- 3 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 44b6c8ea887..bd157ac5763 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -10,9 +10,12 @@ namespace ts.tscWatch { import checkArray = TestFSWithWatch.checkArray; import libFile = TestFSWithWatch.libFile; import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles; + import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed; import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories; + import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed; import checkOutputContains = TestFSWithWatch.checkOutputContains; import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain; + import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory; export function checkProgramActualFiles(program: Program, expectedFiles: string[]) { checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles); @@ -2379,7 +2382,7 @@ declare module "fs" { }); describe("tsc-watch when watchDirectories implementation", () => { - function verifyRenamingFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) { + function verifyRenamingFileInSubFolder(tscWatchDirectory: Tsc_WatchDirectory) { const projectFolder = "/a/username/project"; const projectSrcFolder = `${projectFolder}/src`; const configFile: File = { @@ -2399,8 +2402,8 @@ declare module "fs" { const projectFolders = [projectFolder, projectSrcFolder, `${projectFolder}/node_modules/@types`]; // Watching files config file, file, lib file const expectedWatchedFiles = files.map(f => f.path); - const expectedWatchedDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray; - if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile) { + const expectedWatchedDirectories = tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray; + if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) { expectedWatchedFiles.push(...projectFolders); } @@ -2410,7 +2413,7 @@ declare module "fs" { file.path = file.path.replace("file1.ts", "file2.ts"); expectedWatchedFiles[0] = file.path; host.reloadFS(files); - if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling) { + if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) { // With dynamic polling the fs change would be detected only by running timeouts host.runQueuedTimeoutCallbacks(); } @@ -2429,21 +2432,21 @@ declare module "fs" { checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // Watching config file, file, lib file and directories - TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedFiles", host.watchedFiles, expectedWatchedFiles, 1); - TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories, 1); + checkWatchedFilesDetailed(host, expectedWatchedFiles, 1); + checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, 1, /*recursive*/ false); } } it("uses watchFile when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.WatchFile); }); it("uses non recursive watchDirectory when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.NonRecursiveWatchDirectory); }); it("uses non recursive dynamic polling when renaming file in subfolder", () => { - verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling); + verifyRenamingFileInSubFolder(Tsc_WatchDirectory.DynamicPolling); }); it("when there are symlinks to folders in recursive folders", () => { @@ -2482,7 +2485,7 @@ declare module "fs" { }; const files = [file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB]; const environmentVariables = createMap(); - environmentVariables.set("TSC_WATCHDIRECTORY", TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory); const host = createWatchedSystem(files, { environmentVariables, currentDirectory: cwd }); createWatchOfConfigFile("tsconfig.json", host); checkWatchedDirectories(host, emptyArray, /*recursive*/ true); @@ -2491,4 +2494,46 @@ declare module "fs" { }); }); }); + + describe("tsc-watch with modules linked to sibling folder", () => { + const projectRoot = "/user/username/projects/project"; + const mainPackageRoot = `${projectRoot}/main`; + const linkedPackageRoot = `${projectRoot}/linked-package`; + const mainFile: File = { + path: `${mainPackageRoot}/index.ts`, + content: "import { Foo } from '@scoped/linked-package'" + }; + const config: File = { + path: `${mainPackageRoot}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { module: "commonjs", moduleResolution: "node", baseUrl: ".", rootDir: "." }, + files: ["index.ts"] + }) + }; + const linkedPackageInMain: SymLink = { + path: `${mainPackageRoot}/node_modules/@scoped/linked-package`, + symLink: `${linkedPackageRoot}` + }; + const linkedPackageJson: File = { + path: `${linkedPackageRoot}/package.json`, + content: JSON.stringify({ name: "@scoped/linked-package", version: "0.0.1", types: "dist/index.d.ts", main: "dist/index.js" }) + }; + const linkedPackageIndex: File = { + path: `${linkedPackageRoot}/dist/index.d.ts`, + content: "export * from './other';" + }; + const linkedPackageOther: File = { + path: `${linkedPackageRoot}/dist/other.d.ts`, + content: 'export declare const Foo = "BAR";' + }; + + it("verify watched directories", () => { + const files = [libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther]; + const host = createWatchedSystem(files, { currentDirectory: mainPackageRoot }); + createWatchOfConfigFile("tsconfig.json", host); + checkWatchedFilesDetailed(host, [libFile.path, mainFile.path, config.path, linkedPackageIndex.path, linkedPackageOther.path], 1); + checkWatchedDirectories(host, emptyArray, /*recursive*/ false); + checkWatchedDirectoriesDetailed(host, [mainPackageRoot, projectRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true); + }); + }); } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index f6efe8b99dd..88fe374c398 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -19,6 +19,7 @@ namespace ts.projectSystem { export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories; export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed; import safeList = TestFSWithWatch.safeList; + import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory; export const customTypesMap = { path: "/typesMap.json", @@ -6259,7 +6260,7 @@ namespace ts.projectSystem { } function verifyCalledOnEachEntryNTimes(callback: CalledMaps, expectedKeys: ReadonlyArray, nTimes: number) { - TestFSWithWatch.checkMultiMapEachKeyWithCount(callback, calledMaps[callback], expectedKeys, nTimes); + TestFSWithWatch.checkMultiMapKeyCount(callback, calledMaps[callback], expectedKeys, nTimes); } function verifyNoHostCalls() { @@ -7813,14 +7814,10 @@ new C();` checkCompleteEvent(session, 2, expectedSequenceId); } - function createSingleWatchMap(paths: string[]) { - return arrayToMap(paths, p => p, () => 1); - } - function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], directories: string[]) { - checkWatchedFilesDetailed(host, createSingleWatchMap(files.filter(f => f !== recognizersDateTimeSrcFile.path))); + checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1); checkWatchedDirectories(host, emptyArray, /*recursive*/ false); - checkWatchedDirectoriesDetailed(host, createSingleWatchMap(directories), /*recursive*/ true); + checkWatchedDirectoriesDetailed(host, directories, 1, /*recursive*/ true); } function createSessionAndOpenFile(host: TestServerHost) { @@ -8315,7 +8312,7 @@ new C();` }); describe("tsserverProjectSystem watchDirectories implementation", () => { - function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) { + function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: Tsc_WatchDirectory) { const projectFolder = "/a/username/project"; const projectSrcFolder = `${projectFolder}/src`; const configFile: File = { @@ -8336,9 +8333,9 @@ new C();` // All closed files(files other than index), project folder, project/src folder and project/node_modules/@types folder const expectedWatchedFiles = arrayToMap(fileNames.slice(1), s => s, () => 1); const expectedWatchedDirectories = createMap(); - const mapOfDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? + const mapOfDirectories = tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory ? expectedWatchedDirectories : - tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile ? + tscWatchDirectory === Tsc_WatchDirectory.WatchFile ? expectedWatchedFiles : createMap(); // For failed resolution lookup and tsconfig files @@ -8385,15 +8382,15 @@ new C();` } it("uses watchFile when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.WatchFile); }); it("uses non recursive watchDirectory when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.NonRecursiveWatchDirectory); }); it("uses dynamic polling when file is added to subfolder, completion list has new file", () => { - verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling); + verifyCompletionListWithNewFileInSubFolder(Tsc_WatchDirectory.DynamicPolling); }); }); diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 0afa67880a4..484d3302c1b 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -175,7 +175,10 @@ interface Array {}` } } - export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: Map) { + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyMap): void; + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyArray, eachKeyCount: number): void; + export function checkMultiMapKeyCount(caption: string, actual: MultiMap, expectedKeysMapOrArray: ReadonlyMap | ReadonlyArray, eachKeyCount?: number) { + const expectedKeys = isArray(expectedKeysMapOrArray) ? arrayToMap(expectedKeysMapOrArray, s => s, () => eachKeyCount!) : expectedKeysMapOrArray; verifyMapSize(caption, actual, arrayFrom(expectedKeys.keys())); expectedKeys.forEach((count, name) => { assert.isTrue(actual.has(name), `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`); @@ -183,10 +186,6 @@ interface Array {}` }); } - export function checkMultiMapEachKeyWithCount(caption: string, actual: MultiMap, expectedKeys: ReadonlyArray, count: number) { - return checkMultiMapKeyCount(caption, actual, arrayToMap(expectedKeys, s => s, () => count)); - } - export function checkArray(caption: string, actual: ReadonlyArray, expected: ReadonlyArray) { assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`); for (const f of expected) { @@ -198,16 +197,31 @@ interface Array {}` checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles); } - export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: Map) { - checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles); + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyMap): void; + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyArray, eachFileWatchCount: number): void; + export function checkWatchedFilesDetailed(host: TestServerHost, expectedFiles: ReadonlyMap | ReadonlyArray, eachFileWatchCount?: number) { + if (isArray(expectedFiles)) { + checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles, eachFileWatchCount!); + } + else { + checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedFiles); + } } export function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[], recursive: boolean) { checkMapKeys(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); } - export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: Map, recursive: boolean) { - checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyMap, recursive: boolean): void; + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyArray, eachDirectoryWatchCount: number, recursive: boolean): void; + export function checkWatchedDirectoriesDetailed(host: TestServerHost, expectedDirectories: ReadonlyMap | ReadonlyArray, recursiveOrEachDirectoryWatchCount: boolean | number, recursive?: boolean) { + if (isArray(expectedDirectories)) { + checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories, recursiveOrEachDirectoryWatchCount as number); + } + else { + recursive = recursiveOrEachDirectoryWatchCount as boolean; + checkMultiMapKeyCount(`watchedDirectories${recursive ? " recursive" : ""}`, recursive ? host.watchedDirectoriesRecursive : host.watchedDirectories, expectedDirectories); + } } export function checkOutputContains(host: TestServerHost, expected: ReadonlyArray) { From 939e3e47804246574767e541becae6b6a729e920 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 29 May 2018 14:01:03 -0700 Subject: [PATCH 2/2] Instead of creating filter for subDirectories to watch in the ancestor directory of root, watch those subDirectories for failed lookup locations Before this change, when failed lookup location didnt fall in root directory, we tried to find the ancestor directory of the rootDirectory to watch. We also created subDirectory map for the directories that are being watched so we dont go through invalidation if path is unwanted directory With this change, we will watch those subdirectories instead of root. On windows node supports file system level recursive watching so the earlier approach was better because we reduced number of watches created But on other os, since node doesnt support it, we create the watches for existing folders outselves, so earlier approach becomes expensive. This should be better compromize to satisfy both types of OS. Fixes #24434 --- src/compiler/resolutionCache.ts | 60 +++++-------------- src/harness/unittests/tscWatchMode.ts | 2 +- .../unittests/tsserverProjectSystem.ts | 2 +- 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 8b48aa5c041..b4c428d5e5a 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -60,15 +60,12 @@ namespace ts { watcher: FileWatcher; /** ref count keeping this directory watch alive */ refCount: number; - /** map of refcount for the subDirectory */ - subDirectoryMap?: Map; } interface DirectoryOfFailedLookupWatch { dir: string; dirPath: Path; ignore?: true; - subDirectory?: Path; } export const maxNumberOfFilesToIterateForInvalidation = 256; @@ -403,20 +400,21 @@ namespace ts { } // Use some ancestor of the root directory - let subDirectory: Path | undefined; + let subDirectoryPath: Path | undefined, subDirectory: string | undefined; if (rootPath !== undefined) { while (!isInDirectoryPath(dirPath, rootPath)) { const parentPath = getDirectoryPath(dirPath); if (parentPath === dirPath) { break; } - subDirectory = dirPath.slice(parentPath.length + directorySeparator.length) as Path; + subDirectoryPath = dirPath; + subDirectory = dir; dirPath = parentPath; dir = getDirectoryPath(dir); } } - return filterFSRootDirectoriesToWatch({ dir, dirPath, subDirectory }, dirPath); + return filterFSRootDirectoriesToWatch({ dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath }, dirPath); } function isPathWithDefaultFailedLookupExtension(path: Path) { @@ -439,7 +437,7 @@ namespace ts { let setAtRoot = false; for (const failedLookupLocation of failedLookupLocations) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); if (!ignore) { // If the failed lookup location path is not one of the supported extensions, // store it in the custom path @@ -451,7 +449,7 @@ namespace ts { setAtRoot = true; } else { - setDirectoryWatcher(dir, dirPath, subDirectory); + setDirectoryWatcher(dir, dirPath); } } } @@ -461,20 +459,13 @@ namespace ts { } } - function setDirectoryWatcher(dir: string, dirPath: Path, subDirectory?: Path) { - let dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); + function setDirectoryWatcher(dir: string, dirPath: Path) { + const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); if (dirWatcher) { dirWatcher.refCount++; } else { - dirWatcher = { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }; - directoryWatchesOfFailedLookups.set(dirPath, dirWatcher); - } - - if (subDirectory) { - const subDirectoryMap = dirWatcher.subDirectoryMap || (dirWatcher.subDirectoryMap = createMap()); - const existing = subDirectoryMap.get(subDirectory) || 0; - subDirectoryMap.set(subDirectory, existing + 1); + directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }); } } @@ -492,7 +483,7 @@ namespace ts { let removeAtRoot = false; for (const failedLookupLocation of failedLookupLocations) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); if (!ignore) { const refCount = customFailedLookupPaths.get(failedLookupLocationPath); if (refCount) { @@ -509,7 +500,7 @@ namespace ts { removeAtRoot = true; } else { - removeDirectoryWatcher(dirPath, subDirectory); + removeDirectoryWatcher(dirPath); } } } @@ -518,30 +509,12 @@ namespace ts { } } - function removeDirectoryWatcher(dirPath: string, subDirectory?: Path) { + function removeDirectoryWatcher(dirPath: string) { const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!; - if (subDirectory) { - const existing = dirWatcher.subDirectoryMap!.get(subDirectory)!; - if (existing === 1) { - dirWatcher.subDirectoryMap!.delete(subDirectory); - } - else { - dirWatcher.subDirectoryMap!.set(subDirectory, existing - 1); - } - } // Do not close the watcher yet since it might be needed by other failed lookup locations. dirWatcher.refCount--; } - function inWatchedSubdirectory(dirPath: Path, fileOrDirectoryPath: Path) { - const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); - if (!dirWatcher || !dirWatcher.subDirectoryMap) return false; - return forEachKey(dirWatcher.subDirectoryMap, subDirectory => { - const fullSubDirectory = `${dirPath}/${subDirectory}` as Path; - return fullSubDirectory === fileOrDirectoryPath || isInDirectoryPath(fullSubDirectory, fileOrDirectoryPath); - }); - } - function createDirectoryWatcher(directory: string, dirPath: Path) { return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => { const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory); @@ -550,13 +523,8 @@ namespace ts { cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); } - // If the files are added to project root or node_modules directory, always run through the invalidation process - // Otherwise run through invalidation only if adding to the immediate directory - if (!allFilesHaveInvalidatedResolution && - (dirPath === rootPath || isNodeModulesDirectory(dirPath) || getDirectoryPath(fileOrDirectoryPath) === dirPath || inWatchedSubdirectory(dirPath, fileOrDirectoryPath))) { - if (invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) { - resolutionHost.onInvalidatedResolution(); - } + if (!allFilesHaveInvalidatedResolution && invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) { + resolutionHost.onInvalidatedResolution(); } }, WatchDirectoryFlags.Recursive); } diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index bd157ac5763..e6fffbc5e79 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -2533,7 +2533,7 @@ declare module "fs" { createWatchOfConfigFile("tsconfig.json", host); checkWatchedFilesDetailed(host, [libFile.path, mainFile.path, config.path, linkedPackageIndex.path, linkedPackageOther.path], 1); checkWatchedDirectories(host, emptyArray, /*recursive*/ false); - checkWatchedDirectoriesDetailed(host, [mainPackageRoot, projectRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true); + checkWatchedDirectoriesDetailed(host, [mainPackageRoot, linkedPackageRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true); }); }); } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 88fe374c398..4518a740a85 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -7839,7 +7839,7 @@ new C();` const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile]; const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, withPathMapping ? packages : recognizersDateTime, ...getTypeRootsFromLocation(recognizersDateTime)]; - const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)]; + const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...(withPathMapping ? [recognizersText] : emptyArray), ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)]; function verifyProjectWithResolvedModule(session: TestSession) { const projectService = session.getProjectService();