Skip to content

Commit 896947e

Browse files
TypeScript Botsheetalkamatjakebailey
authored
🤖 Pick PR #57938 (Directories dont check modified tim...) into release-5.4 (#57958)
Co-authored-by: Sheetal Nandi <[email protected]> Co-authored-by: Jake Bailey <[email protected]>
1 parent 521d3fb commit 896947e

File tree

285 files changed

+2042
-1682
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

285 files changed

+2042
-1682
lines changed

‎src/compiler/sys.ts

+29-7
Original file line numberDiff line numberDiff line change
@@ -378,16 +378,24 @@ function createDynamicPriorityPollingWatchFile(host: {
378378
}
379379
}
380380

381-
function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSensitiveFileNames: boolean): HostWatchFile {
381+
function createUseFsEventsOnParentDirectoryWatchFile(
382+
fsWatch: FsWatch,
383+
useCaseSensitiveFileNames: boolean,
384+
getModifiedTime: NonNullable<System["getModifiedTime"]>,
385+
fsWatchWithTimestamp: boolean | undefined,
386+
): HostWatchFile {
382387
// One file can have multiple watchers
383388
const fileWatcherCallbacks = createMultiMap<string, FileWatcherCallback>();
389+
const fileTimestamps = fsWatchWithTimestamp ? new Map<string, Date>() : undefined;
384390
const dirWatchers = new Map<string, DirectoryWatcher>();
385391
const toCanonicalName = createGetCanonicalFileName(useCaseSensitiveFileNames);
386392
return nonPollingWatchFile;
387393

388394
function nonPollingWatchFile(fileName: string, callback: FileWatcherCallback, _pollingInterval: PollingInterval, fallbackOptions: WatchOptions | undefined): FileWatcher {
389395
const filePath = toCanonicalName(fileName);
390-
fileWatcherCallbacks.add(filePath, callback);
396+
if (fileWatcherCallbacks.add(filePath, callback).length === 1 && fileTimestamps) {
397+
fileTimestamps.set(filePath, getModifiedTime(fileName) || missingFileModifiedTime);
398+
}
391399
const dirPath = getDirectoryPath(filePath) || ".";
392400
const watcher = dirWatchers.get(dirPath) ||
393401
createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions);
@@ -410,15 +418,29 @@ function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSe
410418
const watcher = fsWatch(
411419
dirName,
412420
FileSystemEntryKind.Directory,
413-
(_eventName: string, relativeFileName, modifiedTime) => {
421+
(eventName: string, relativeFileName) => {
414422
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
415423
if (!isString(relativeFileName)) return;
416424
const fileName = getNormalizedAbsolutePath(relativeFileName, dirName);
425+
const filePath = toCanonicalName(fileName);
417426
// Some applications save a working file via rename operations
418-
const callbacks = fileName && fileWatcherCallbacks.get(toCanonicalName(fileName));
427+
const callbacks = fileName && fileWatcherCallbacks.get(filePath);
419428
if (callbacks) {
429+
let currentModifiedTime;
430+
let eventKind = FileWatcherEventKind.Changed;
431+
if (fileTimestamps) {
432+
const existingTime = fileTimestamps.get(filePath)!;
433+
if (eventName === "change") {
434+
currentModifiedTime = getModifiedTime(fileName) || missingFileModifiedTime;
435+
if (currentModifiedTime.getTime() === existingTime.getTime()) return;
436+
}
437+
currentModifiedTime ||= getModifiedTime(fileName) || missingFileModifiedTime;
438+
fileTimestamps.set(filePath, currentModifiedTime);
439+
if (existingTime === missingFileModifiedTime) eventKind = FileWatcherEventKind.Created;
440+
else if (currentModifiedTime === missingFileModifiedTime) eventKind = FileWatcherEventKind.Deleted;
441+
}
420442
for (const fileCallback of callbacks) {
421-
fileCallback(fileName, FileWatcherEventKind.Changed, modifiedTime);
443+
fileCallback(fileName, eventKind, currentModifiedTime);
422444
}
423445
}
424446
},
@@ -974,7 +996,7 @@ export function createSystemWatchFunctions({
974996
);
975997
case WatchFileKind.UseFsEventsOnParentDirectory:
976998
if (!nonPollingWatchFile) {
977-
nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile(fsWatch, useCaseSensitiveFileNames);
999+
nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile(fsWatch, useCaseSensitiveFileNames, getModifiedTime, fsWatchWithTimestamp);
9781000
}
9791001
return nonPollingWatchFile(fileName, callback, pollingInterval, getFallbackOptions(options));
9801002
default:
@@ -1191,7 +1213,7 @@ export function createSystemWatchFunctions({
11911213
return watchPresentFileSystemEntryWithFsWatchFile();
11921214
}
11931215
try {
1194-
const presentWatcher = (!fsWatchWithTimestamp ? fsWatchWorker : fsWatchWorkerHandlingTimestamp)(
1216+
const presentWatcher = (entryKind === FileSystemEntryKind.Directory || !fsWatchWithTimestamp ? fsWatchWorker : fsWatchWorkerHandlingTimestamp)(
11951217
fileOrDirectory,
11961218
recursive,
11971219
inodeWatching ?

‎src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -501,12 +501,12 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost,
501501
else {
502502
currentEntry.content = content;
503503
currentEntry.modifiedTime = this.now();
504-
this.fs.get(getDirectoryPath(currentEntry.path))!.modifiedTime = this.now();
505504
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
506505
const directoryFullPath = getDirectoryPath(currentEntry.fullPath);
507-
this.invokeFileWatcher(directoryFullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime);
508-
this.invokeFsWatchesCallbacks(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName);
509-
this.invokeRecursiveFsWatches(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName);
506+
this.fs.get(getDirectoryPath(currentEntry.path))!.modifiedTime = this.now();
507+
this.invokeFileWatcher(directoryFullPath, FileWatcherEventKind.Changed, /*modifiedTime*/ undefined);
508+
this.invokeFsWatchesCallbacks(directoryFullPath, "rename", /*modifiedTime*/ undefined, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName);
509+
this.invokeRecursiveFsWatches(directoryFullPath, "rename", /*modifiedTime*/ undefined, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName);
510510
}
511511
else {
512512
this.invokeFileAndFsWatches(currentEntry.fullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName);
@@ -634,7 +634,7 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost,
634634
const inodeWatching = this.inodeWatching;
635635
if (options?.skipInodeCheckOnCreate) this.inodeWatching = false;
636636
this.invokeFileAndFsWatches(fileOrDirectory.fullPath, FileWatcherEventKind.Created, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName);
637-
this.invokeFileAndFsWatches(folder.fullPath, FileWatcherEventKind.Changed, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName);
637+
this.invokeFileAndFsWatches(folder.fullPath, FileWatcherEventKind.Changed, folder.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName);
638638
this.inodeWatching = inodeWatching;
639639
}
640640

@@ -741,13 +741,13 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost,
741741
this.invokeFsWatchesRecursiveCallbacks(fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix);
742742
const basePath = getDirectoryPath(fullPath);
743743
if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) {
744-
this.invokeRecursiveFsWatches(basePath, eventName, modifiedTime, entryFullPath || fullPath, useTildeSuffix);
744+
this.invokeRecursiveFsWatches(basePath, eventName, /*modifiedTime*/ undefined, entryFullPath || fullPath, useTildeSuffix);
745745
}
746746
}
747747

748748
invokeFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, useTildeSuffix: boolean | undefined) {
749749
this.invokeFsWatchesCallbacks(fullPath, eventName, modifiedTime, fullPath, useTildeSuffix);
750-
this.invokeFsWatchesCallbacks(getDirectoryPath(fullPath), eventName, modifiedTime, fullPath, useTildeSuffix);
750+
this.invokeFsWatchesCallbacks(getDirectoryPath(fullPath), eventName, /*modifiedTime*/ undefined, fullPath, useTildeSuffix);
751751
this.invokeRecursiveFsWatches(fullPath, eventName, modifiedTime, /*entryFullPath*/ undefined, useTildeSuffix);
752752
}
753753

‎src/testRunner/unittests/tscWatch/watchEnvironment.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -690,11 +690,11 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
690690
});
691691

692692
describe("with fsWatch with fsWatchWithTimestamp", () => {
693-
function verify(fsWatchWithTimestamp: boolean) {
693+
function verify(fsWatchWithTimestamp: boolean, watchFile?: "useFsEventsOnParentDirectory") {
694694
verifyTscWatch({
695695
scenario,
696-
subScenario: `fsWatch/fsWatchWithTimestamp ${fsWatchWithTimestamp}`,
697-
commandLineArgs: ["-w", "--extendedDiagnostics"],
696+
subScenario: `fsWatch/fsWatchWithTimestamp ${fsWatchWithTimestamp}${watchFile ? ` ${watchFile}` : ""}`,
697+
commandLineArgs: ["-w", "--extendedDiagnostics", ...(watchFile ? ["--watchFile", watchFile] : [])],
698698
sys: () =>
699699
createWatchedSystem(
700700
{
@@ -723,6 +723,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
723723
}
724724
verify(/*fsWatchWithTimestamp*/ true);
725725
verify(/*fsWatchWithTimestamp*/ false);
726+
verify(/*fsWatchWithTimestamp*/ true, "useFsEventsOnParentDirectory");
727+
verify(/*fsWatchWithTimestamp*/ false, "useFsEventsOnParentDirectory");
726728
});
727729

728730
verifyTscWatch({

‎tests/baselines/reference/tsbuildWatch/configFileErrors/reports-syntax-errors-in-config-file.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,14 @@ Before running Timeout callback:: count: 1
161161
After running Timeout callback:: count: 0
162162
Output::
163163
>> Screen clear
164-
[[90m12:00:33 AM[0m] File change detected. Starting incremental compilation...
164+
[[90m12:00:32 AM[0m] File change detected. Starting incremental compilation...
165165

166166
tsconfig.json:8:9 - error TS1005: ',' expected.
167167

168168
8 "b.ts"
169169
   ~~~~~~
170170

171-
[[90m12:00:34 AM[0m] Found 1 error. Watching for file changes.
171+
[[90m12:00:33 AM[0m] Found 1 error. Watching for file changes.
172172

173173

174174

@@ -212,14 +212,14 @@ Before running Timeout callback:: count: 1
212212
After running Timeout callback:: count: 0
213213
Output::
214214
>> Screen clear
215-
[[90m12:00:38 AM[0m] File change detected. Starting incremental compilation...
215+
[[90m12:00:36 AM[0m] File change detected. Starting incremental compilation...
216216

217217
tsconfig.json:8:9 - error TS1005: ',' expected.
218218

219219
8 "b.ts"
220220
   ~~~~~~
221221

222-
[[90m12:00:46 AM[0m] Found 1 error. Watching for file changes.
222+
[[90m12:00:42 AM[0m] Found 1 error. Watching for file changes.
223223

224224

225225

@@ -323,14 +323,14 @@ Before running Timeout callback:: count: 1
323323
After running Timeout callback:: count: 0
324324
Output::
325325
>> Screen clear
326-
[[90m12:00:50 AM[0m] File change detected. Starting incremental compilation...
326+
[[90m12:00:45 AM[0m] File change detected. Starting incremental compilation...
327327

328328
tsconfig.json:8:9 - error TS1005: ',' expected.
329329

330330
8 "b.ts"
331331
   ~~~~~~
332332

333-
[[90m12:00:51 AM[0m] Found 1 error. Watching for file changes.
333+
[[90m12:00:46 AM[0m] Found 1 error. Watching for file changes.
334334

335335

336336

@@ -383,9 +383,9 @@ Before running Timeout callback:: count: 1
383383
After running Timeout callback:: count: 0
384384
Output::
385385
>> Screen clear
386-
[[90m12:00:56 AM[0m] File change detected. Starting incremental compilation...
386+
[[90m12:00:50 AM[0m] File change detected. Starting incremental compilation...
387387

388-
[[90m12:01:12 AM[0m] Found 0 errors. Watching for file changes.
388+
[[90m12:01:04 AM[0m] Found 0 errors. Watching for file changes.
389389

390390

391391

‎tests/baselines/reference/tsbuildWatch/demo/updates-with-bad-reference.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,17 @@ declare const console: { log(msg: any): void; };
144144
/a/lib/tsc.js -b -w -verbose
145145
Output::
146146
>> Screen clear
147-
[[90m12:00:45 AM[0m] Starting compilation in watch mode...
147+
[[90m12:00:44 AM[0m] Starting compilation in watch mode...
148148

149-
[[90m12:00:46 AM[0m] Projects in this build:
149+
[[90m12:00:45 AM[0m] Projects in this build:
150150
* core/tsconfig.json
151151
* animals/tsconfig.json
152152
* zoo/tsconfig.json
153153
* tsconfig.json
154154

155-
[[90m12:00:47 AM[0m] Project 'core/tsconfig.json' is out of date because output file 'lib/core/tsconfig.tsbuildinfo' does not exist
155+
[[90m12:00:46 AM[0m] Project 'core/tsconfig.json' is out of date because output file 'lib/core/tsconfig.tsbuildinfo' does not exist
156156

157-
[[90m12:00:48 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
157+
[[90m12:00:47 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
158158

159159
animals/index.ts:1:20 - error TS6059: File '/user/username/projects/demo/animals/animal.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.
160160

@@ -207,15 +207,15 @@ Output::
207207
   ~~~
208208
File is included via import here.
209209

210-
[[90m12:00:59 AM[0m] Project 'animals/tsconfig.json' can't be built because its dependency 'core' has errors
210+
[[90m12:00:58 AM[0m] Project 'animals/tsconfig.json' can't be built because its dependency 'core' has errors
211211

212-
[[90m12:01:00 AM[0m] Skipping build of project '/user/username/projects/demo/animals/tsconfig.json' because its dependency '/user/username/projects/demo/core' has errors
212+
[[90m12:00:59 AM[0m] Skipping build of project '/user/username/projects/demo/animals/tsconfig.json' because its dependency '/user/username/projects/demo/core' has errors
213213

214-
[[90m12:01:01 AM[0m] Project 'zoo/tsconfig.json' can't be built because its dependency 'animals' was not built
214+
[[90m12:01:00 AM[0m] Project 'zoo/tsconfig.json' can't be built because its dependency 'animals' was not built
215215

216-
[[90m12:01:02 AM[0m] Skipping build of project '/user/username/projects/demo/zoo/tsconfig.json' because its dependency '/user/username/projects/demo/animals' was not built
216+
[[90m12:01:01 AM[0m] Skipping build of project '/user/username/projects/demo/zoo/tsconfig.json' because its dependency '/user/username/projects/demo/animals' was not built
217217

218-
[[90m12:01:03 AM[0m] Found 7 errors. Watching for file changes.
218+
[[90m12:01:02 AM[0m] Found 7 errors. Watching for file changes.
219219

220220

221221

@@ -469,11 +469,11 @@ Before running Timeout callback:: count: 1
469469
After running Timeout callback:: count: 0
470470
Output::
471471
>> Screen clear
472-
[[90m12:01:06 AM[0m] File change detected. Starting incremental compilation...
472+
[[90m12:01:04 AM[0m] File change detected. Starting incremental compilation...
473473

474-
[[90m12:01:07 AM[0m] Project 'core/tsconfig.json' is out of date because buildinfo file 'lib/core/tsconfig.tsbuildinfo' indicates that some of the changes were not emitted
474+
[[90m12:01:05 AM[0m] Project 'core/tsconfig.json' is out of date because buildinfo file 'lib/core/tsconfig.tsbuildinfo' indicates that some of the changes were not emitted
475475

476-
[[90m12:01:08 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
476+
[[90m12:01:06 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
477477

478478
animals/index.ts:1:20 - error TS6059: File '/user/username/projects/demo/animals/animal.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.
479479

@@ -526,7 +526,7 @@ Output::
526526
   ~~~
527527
File is included via import here.
528528

529-
[[90m12:01:16 AM[0m] Found 7 errors. Watching for file changes.
529+
[[90m12:01:12 AM[0m] Found 7 errors. Watching for file changes.
530530

531531

532532

‎tests/baselines/reference/tsbuildWatch/demo/updates-with-circular-reference.js

+11-11
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ declare const console: { log(msg: any): void; };
148148
/a/lib/tsc.js -b -w -verbose
149149
Output::
150150
>> Screen clear
151-
[[90m12:00:46 AM[0m] Starting compilation in watch mode...
151+
[[90m12:00:45 AM[0m] Starting compilation in watch mode...
152152

153-
[[90m12:00:47 AM[0m] Projects in this build:
153+
[[90m12:00:46 AM[0m] Projects in this build:
154154
* animals/tsconfig.json
155155
* zoo/tsconfig.json
156156
* core/tsconfig.json
@@ -161,7 +161,7 @@ Output::
161161
/user/username/projects/demo/zoo/tsconfig.json
162162
/user/username/projects/demo/animals/tsconfig.json
163163

164-
[[90m12:00:48 AM[0m] Found 1 error. Watching for file changes.
164+
[[90m12:00:47 AM[0m] Found 1 error. Watching for file changes.
165165

166166

167167

@@ -220,11 +220,11 @@ Before running Timeout callback:: count: 1
220220
After running Timeout callback:: count: 1
221221
Output::
222222
>> Screen clear
223-
[[90m12:00:52 AM[0m] File change detected. Starting incremental compilation...
223+
[[90m12:00:50 AM[0m] File change detected. Starting incremental compilation...
224224

225-
[[90m12:00:53 AM[0m] Project 'core/tsconfig.json' is out of date because output file 'lib/core/tsconfig.tsbuildinfo' does not exist
225+
[[90m12:00:51 AM[0m] Project 'core/tsconfig.json' is out of date because output file 'lib/core/tsconfig.tsbuildinfo' does not exist
226226

227-
[[90m12:00:54 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
227+
[[90m12:00:52 AM[0m] Building project '/user/username/projects/demo/core/tsconfig.json'...
228228

229229

230230

@@ -318,15 +318,15 @@ Before running Timeout callback:: count: 1
318318

319319
After running Timeout callback:: count: 0
320320
Output::
321-
[[90m12:01:09 AM[0m] Project 'animals/tsconfig.json' is out of date because output file 'lib/animals/tsconfig.tsbuildinfo' does not exist
321+
[[90m12:01:07 AM[0m] Project 'animals/tsconfig.json' is out of date because output file 'lib/animals/tsconfig.tsbuildinfo' does not exist
322322

323-
[[90m12:01:10 AM[0m] Building project '/user/username/projects/demo/animals/tsconfig.json'...
323+
[[90m12:01:08 AM[0m] Building project '/user/username/projects/demo/animals/tsconfig.json'...
324324

325-
[[90m12:01:31 AM[0m] Project 'zoo/tsconfig.json' is out of date because output file 'lib/zoo/tsconfig.tsbuildinfo' does not exist
325+
[[90m12:01:29 AM[0m] Project 'zoo/tsconfig.json' is out of date because output file 'lib/zoo/tsconfig.tsbuildinfo' does not exist
326326

327-
[[90m12:01:32 AM[0m] Building project '/user/username/projects/demo/zoo/tsconfig.json'...
327+
[[90m12:01:30 AM[0m] Building project '/user/username/projects/demo/zoo/tsconfig.json'...
328328

329-
[[90m12:01:45 AM[0m] Found 0 errors. Watching for file changes.
329+
[[90m12:01:43 AM[0m] Found 0 errors. Watching for file changes.
330330

331331

332332

0 commit comments

Comments
 (0)