Skip to content

Commit f885cd9

Browse files
committed
Do not watch child directories of the sym link folders
Fixes #22668
1 parent e40f294 commit f885cd9

File tree

3 files changed

+70
-16
lines changed

3 files changed

+70
-16
lines changed

src/compiler/sys.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ namespace ts {
337337
getAccessileSortedChildDirectories(path: string): ReadonlyArray<string>;
338338
directoryExists(dir: string): boolean;
339339
filePathComparer: Comparer<string>;
340+
realpath(s: string): string;
340341
}
341342

342343
/**
@@ -392,9 +393,12 @@ namespace ts {
392393
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches, callback: DirectoryWatcherCallback): ChildWatches {
393394
let newChildWatches: DirectoryWatcher[] | undefined;
394395
enumerateInsertsAndDeletes<string, DirectoryWatcher>(
395-
host.directoryExists(parentDir) ? host.getAccessileSortedChildDirectories(parentDir) : emptyArray,
396+
host.directoryExists(parentDir) ? mapDefined(host.getAccessileSortedChildDirectories(parentDir), child => {
397+
const childFullName = getNormalizedAbsolutePath(child, parentDir);
398+
return host.filePathComparer(childFullName, host.realpath(childFullName)) === Comparison.EqualTo ? childFullName : undefined;
399+
}) : emptyArray,
396400
existingChildWatches,
397-
(child, childWatcher) => host.filePathComparer(getNormalizedAbsolutePath(child, parentDir), childWatcher.dirName),
401+
(child, childWatcher) => host.filePathComparer(child, childWatcher.dirName),
398402
createAndAddChildDirectoryWatcher,
399403
closeFileWatcher,
400404
addChildDirectoryWatcher
@@ -406,7 +410,7 @@ namespace ts {
406410
* Create new childDirectoryWatcher and add it to the new ChildDirectoryWatcher list
407411
*/
408412
function createAndAddChildDirectoryWatcher(childName: string) {
409-
const result = createDirectoryWatcher(getNormalizedAbsolutePath(childName, parentDir), callback);
413+
const result = createDirectoryWatcher(childName, callback);
410414
addChildDirectoryWatcher(result);
411415
}
412416

@@ -601,14 +605,7 @@ namespace ts {
601605
exit(exitCode?: number): void {
602606
process.exit(exitCode);
603607
},
604-
realpath(path: string): string {
605-
try {
606-
return _fs.realpathSync(path);
607-
}
608-
catch {
609-
return path;
610-
}
611-
},
608+
realpath,
612609
debugMode: some(<string[]>process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)),
613610
tryEnableSourceMapsForHost() {
614611
try {
@@ -700,7 +697,8 @@ namespace ts {
700697
filePathComparer: useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
701698
directoryExists,
702699
getAccessileSortedChildDirectories: path => getAccessibleFileSystemEntries(path).directories,
703-
watchDirectory
700+
watchDirectory,
701+
realpath
704702
});
705703

706704
return (directoryName, callback, recursive) => {
@@ -1043,6 +1041,15 @@ namespace ts {
10431041
return filter<string>(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory));
10441042
}
10451043

1044+
function realpath(path: string): string {
1045+
try {
1046+
return _fs.realpathSync(path);
1047+
}
1048+
catch {
1049+
return path;
1050+
}
1051+
}
1052+
10461053
function getModifiedTime(path: string) {
10471054
try {
10481055
return _fs.statSync(path).mtime;

src/harness/unittests/tscWatchMode.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,50 @@ declare module "fs" {
23582358
it("uses non recursive dynamic polling when renaming file in subfolder", () => {
23592359
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
23602360
});
2361+
2362+
it("when there are symlinks to folders in recursive folders", () => {
2363+
const cwd = "/home/user/projects/myproject";
2364+
const file1: FileOrFolder = {
2365+
path: `${cwd}/src/file.ts`,
2366+
content: `import * as a from "a"`
2367+
};
2368+
const tsconfig: FileOrFolder = {
2369+
path: `${cwd}/tsconfig.json`,
2370+
content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}`
2371+
};
2372+
const realA: FileOrFolder = {
2373+
path: `${cwd}/node_modules/reala/index.d.ts`,
2374+
content: `export {}`
2375+
};
2376+
const realB: FileOrFolder = {
2377+
path: `${cwd}/node_modules/realb/index.d.ts`,
2378+
content: `export {}`
2379+
};
2380+
const symLinkA: FileOrFolder = {
2381+
path: `${cwd}/node_modules/a`,
2382+
symLink: `${cwd}/node_modules/reala`
2383+
};
2384+
const symLinkB: FileOrFolder = {
2385+
path: `${cwd}/node_modules/b`,
2386+
symLink: `${cwd}/node_modules/realb`
2387+
};
2388+
const symLinkBInA: FileOrFolder = {
2389+
path: `${cwd}/node_modules/reala/node_modules/b`,
2390+
symLink: `${cwd}/node_modules/b`
2391+
};
2392+
const symLinkAInB: FileOrFolder = {
2393+
path: `${cwd}/node_modules/realb/node_modules/a`,
2394+
symLink: `${cwd}/node_modules/a`
2395+
};
2396+
const files = [file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
2397+
const environmentVariables = createMap<string>();
2398+
environmentVariables.set("TSC_WATCHDIRECTORY", TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
2399+
const host = createWatchedSystem(files, { environmentVariables, currentDirectory: cwd });
2400+
createWatchOfConfigFile("tsconfig.json", host);
2401+
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
2402+
checkWatchedDirectories(host, [cwd, `${cwd}/node_modules`, `${cwd}/node_modules/@types`, `${cwd}/node_modules/reala`, `${cwd}/node_modules/realb`,
2403+
`${cwd}/node_modules/reala/node_modules`, `${cwd}/node_modules/realb/node_modules`, `${cwd}/src`], /*recursive*/ false);
2404+
});
23612405
});
23622406
});
23632407
}

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,8 @@ interface Array<T> {}`
314314
directoryExists: path => this.directoryExists(path),
315315
getAccessileSortedChildDirectories: path => this.getDirectories(path),
316316
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
317-
watchDirectory
317+
watchDirectory,
318+
realpath: s => this.realpath(s)
318319
});
319320
}
320321
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
@@ -323,7 +324,8 @@ interface Array<T> {}`
323324
directoryExists: path => this.directoryExists(path),
324325
getAccessileSortedChildDirectories: path => this.getDirectories(path),
325326
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
326-
watchDirectory
327+
watchDirectory,
328+
realpath: s => this.realpath(s)
327329
});
328330
}
329331
else if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) {
@@ -333,7 +335,8 @@ interface Array<T> {}`
333335
directoryExists: path => this.directoryExists(path),
334336
getAccessileSortedChildDirectories: path => this.getDirectories(path),
335337
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
336-
watchDirectory
338+
watchDirectory,
339+
realpath: s => this.realpath(s)
337340
});
338341
}
339342
}
@@ -649,7 +652,7 @@ interface Array<T> {}`
649652

650653
const realpath = this.realpath(path);
651654
if (path !== realpath) {
652-
return this.getRealFsEntry(isFsEntry, realpath as Path);
655+
return this.getRealFsEntry(isFsEntry, this.toPath(realpath));
653656
}
654657

655658
return undefined;

0 commit comments

Comments
 (0)