Skip to content

Commit 97017ee

Browse files
authored
Delay "File change detected" reporting until createProgram (microsoft#47427)
1 parent 4e689bc commit 97017ee

12 files changed

+327
-28
lines changed

Diff for: src/compiler/watchPublic.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ namespace ts {
273273
let sharedExtendedConfigFileWatchers: ESMap<Path, SharedExtendedConfigFileWatcher<Path>>; // Map of file watchers for extended files, shared between different referenced projects
274274
let extendedConfigCache = host.extendedConfigCache; // Cache for extended config evaluation
275275
let changesAffectResolution = false; // Flag for indicating non-config changes affect module resolution
276+
let reportFileChangeDetectedOnCreateProgram = false; // True if synchronizeProgram should report "File change detected..." when a new program is created
276277

277278
const sourceFilesCache = new Map<string, HostFileInfo>(); // Cache that stores the source file and version info
278279
let missingFilePathsRequestedForRelease: Path[] | undefined; // These paths are held temporarily so that we can remove the entry from source file cache if the file is not tracked by missing files
@@ -434,15 +435,22 @@ namespace ts {
434435
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution || changesAffectResolution);
435436
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) {
436437
if (hasChangedConfigFileParsingErrors) {
438+
if (reportFileChangeDetectedOnCreateProgram) {
439+
reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation);
440+
}
437441
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences);
438442
hasChangedConfigFileParsingErrors = false;
439443
}
440444
}
441445
else {
446+
if (reportFileChangeDetectedOnCreateProgram) {
447+
reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation);
448+
}
442449
createNewProgram(hasInvalidatedResolution);
443450
}
444451

445452
changesAffectResolution = false; // reset for next sync
453+
reportFileChangeDetectedOnCreateProgram = false;
446454

447455
if (host.afterProgramCreate && program !== builderProgram) {
448456
host.afterProgramCreate(builderProgram);
@@ -665,7 +673,7 @@ namespace ts {
665673

666674
function updateProgramWithWatchStatus() {
667675
timerToUpdateProgram = undefined;
668-
reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation);
676+
reportFileChangeDetectedOnCreateProgram = true;
669677
updateProgram();
670678
}
671679

Diff for: src/testRunner/unittests/tscWatch/programUpdates.ts

+52
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,34 @@ export class A {
638638
]
639639
});
640640

641+
verifyTscWatch({
642+
scenario,
643+
subScenario: "file in files is deleted",
644+
commandLineArgs: ["-w", "-p", configFilePath],
645+
sys: () => {
646+
const file1 = {
647+
path: "/a/b/f1.ts",
648+
content: "let x = 1"
649+
};
650+
const file2 = {
651+
path: "/a/b/f2.ts",
652+
content: "let y = 1"
653+
};
654+
const configFile = {
655+
path: configFilePath,
656+
content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })
657+
};
658+
return createWatchedSystem([file1, file2, libFile, configFile]);
659+
},
660+
changes: [
661+
{
662+
caption: "Delete f2",
663+
change: sys => sys.deleteFile("/a/b/f2.ts"),
664+
timeouts: checkSingleTimeoutQueueLengthAndRun,
665+
}
666+
]
667+
});
668+
641669
verifyTscWatch({
642670
scenario,
643671
subScenario: "config file is deleted",
@@ -1815,5 +1843,29 @@ import { x } from "../b";`),
18151843
},
18161844
]
18171845
});
1846+
1847+
verifyTscWatch({
1848+
scenario,
1849+
subScenario: "when creating extensionless file",
1850+
commandLineArgs: ["-w", "-p", ".", "--extendedDiagnostics"],
1851+
sys: () => {
1852+
const module1: File = {
1853+
path: `${projectRoot}/index.ts`,
1854+
content: ``
1855+
};
1856+
const config: File = {
1857+
path: `${projectRoot}/tsconfig.json`,
1858+
content: `{}`
1859+
};
1860+
return createWatchedSystem([module1, config, libFile], { currentDirectory: projectRoot });
1861+
},
1862+
changes: [
1863+
{
1864+
caption: "Create foo in project root",
1865+
change: sys => sys.writeFile(`${projectRoot}/foo`, ``),
1866+
timeouts: checkSingleTimeoutQueueLengthAndRun,
1867+
},
1868+
]
1869+
});
18181870
});
18191871
}

Diff for: tests/baselines/reference/tscWatch/consoleClearing/with---diagnostics.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ Output::
7171
FileWatcher:: Triggered with /f.ts 1:: WatchInfo: /f.ts 250 undefined Source file
7272
Scheduling update
7373
Elapsed:: *ms FileWatcher:: Triggered with /f.ts 1:: WatchInfo: /f.ts 250 undefined Source file
74+
Synchronizing program
7475
[12:00:17 AM] File change detected. Starting incremental compilation...
7576

76-
Synchronizing program
7777
CreatingProgramWith::
7878
roots: ["/f.ts"]
7979
options: {"watch":true,"diagnostics":true}

Diff for: tests/baselines/reference/tscWatch/consoleClearing/with---extendedDiagnostics.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ Output::
7373
FileWatcher:: Triggered with /f.ts 1:: WatchInfo: /f.ts 250 undefined Source file
7474
Scheduling update
7575
Elapsed:: *ms FileWatcher:: Triggered with /f.ts 1:: WatchInfo: /f.ts 250 undefined Source file
76+
Synchronizing program
7677
[12:00:17 AM] File change detected. Starting incremental compilation...
7778

78-
Synchronizing program
7979
CreatingProgramWith::
8080
roots: ["/f.ts"]
8181
options: {"watch":true,"extendedDiagnostics":true}

Diff for: tests/baselines/reference/tscWatch/programUpdates/config-file-is-deleted.js

-3
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ Input::
8484
//// [/a/b/tsconfig.json] deleted
8585

8686
Output::
87-
>> Screen clear
88-
[12:00:24 AM] File change detected. Starting incremental compilation...
89-
9087
error TS5083: Cannot read file '/a/b/tsconfig.json'.
9188

9289

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Input::
2+
//// [/a/b/f1.ts]
3+
let x = 1
4+
5+
//// [/a/b/f2.ts]
6+
let y = 1
7+
8+
//// [/a/lib/lib.d.ts]
9+
/// <reference no-default-lib="true"/>
10+
interface Boolean {}
11+
interface Function {}
12+
interface CallableFunction {}
13+
interface NewableFunction {}
14+
interface IArguments {}
15+
interface Number { toExponential: any; }
16+
interface Object {}
17+
interface RegExp {}
18+
interface String { charAt: any; }
19+
interface Array<T> { length: number; [n: number]: T; }
20+
21+
//// [/a/b/tsconfig.json]
22+
{"compilerOptions":{},"files":["f1.ts","f2.ts"]}
23+
24+
25+
/a/lib/tsc.js -w -p /a/b/tsconfig.json
26+
Output::
27+
>> Screen clear
28+
[12:00:17 AM] Starting compilation in watch mode...
29+
30+
[12:00:22 AM] Found 0 errors. Watching for file changes.
31+
32+
33+
34+
Program root files: ["/a/b/f1.ts","/a/b/f2.ts"]
35+
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
36+
Program structureReused: Not
37+
Program files::
38+
/a/lib/lib.d.ts
39+
/a/b/f1.ts
40+
/a/b/f2.ts
41+
42+
Semantic diagnostics in builder refreshed for::
43+
/a/lib/lib.d.ts
44+
/a/b/f1.ts
45+
/a/b/f2.ts
46+
47+
Shape signatures in builder refreshed for::
48+
/a/lib/lib.d.ts (used version)
49+
/a/b/f1.ts (used version)
50+
/a/b/f2.ts (used version)
51+
52+
WatchedFiles::
53+
/a/b/tsconfig.json:
54+
{"fileName":"/a/b/tsconfig.json","pollingInterval":250}
55+
/a/b/f1.ts:
56+
{"fileName":"/a/b/f1.ts","pollingInterval":250}
57+
/a/b/f2.ts:
58+
{"fileName":"/a/b/f2.ts","pollingInterval":250}
59+
/a/lib/lib.d.ts:
60+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
61+
62+
FsWatches::
63+
64+
FsWatchesRecursive::
65+
/a/b/node_modules/@types:
66+
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
67+
68+
exitCode:: ExitStatus.undefined
69+
70+
//// [/a/b/f1.js]
71+
var x = 1;
72+
73+
74+
//// [/a/b/f2.js]
75+
var y = 1;
76+
77+
78+
79+
Change:: Delete f2
80+
81+
Input::
82+
//// [/a/b/f2.ts] deleted
83+
84+
Output::
85+
>> Screen clear
86+
[12:00:24 AM] File change detected. Starting incremental compilation...
87+
88+
error TS6053: File '/a/b/f2.ts' not found.
89+
The file is in the program because:
90+
Part of 'files' list in tsconfig.json
91+
92+
a/b/tsconfig.json:1:40
93+
1 {"compilerOptions":{},"files":["f1.ts","f2.ts"]}
94+
   ~~~~~~~
95+
File is matched by 'files' list specified here.
96+
97+
[12:00:28 AM] Found 1 error. Watching for file changes.
98+
99+
100+
101+
Program root files: ["/a/b/f1.ts","/a/b/f2.ts"]
102+
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
103+
Program structureReused: Not
104+
Program files::
105+
/a/lib/lib.d.ts
106+
/a/b/f1.ts
107+
108+
No cached semantic diagnostics in the builder::
109+
110+
Shape signatures in builder refreshed for::
111+
/a/b/f1.ts (computed .d.ts)
112+
113+
WatchedFiles::
114+
/a/b/tsconfig.json:
115+
{"fileName":"/a/b/tsconfig.json","pollingInterval":250}
116+
/a/b/f1.ts:
117+
{"fileName":"/a/b/f1.ts","pollingInterval":250}
118+
/a/lib/lib.d.ts:
119+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
120+
/a/b/f2.ts:
121+
{"fileName":"/a/b/f2.ts","pollingInterval":250}
122+
123+
FsWatches::
124+
125+
FsWatchesRecursive::
126+
/a/b/node_modules/@types:
127+
{"directoryName":"/a/b/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
128+
129+
exitCode:: ExitStatus.undefined
130+
131+
//// [/a/b/f1.js] file written with same contents
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
Input::
2+
//// [/user/username/projects/myproject/index.ts]
3+
4+
5+
//// [/user/username/projects/myproject/tsconfig.json]
6+
{}
7+
8+
//// [/a/lib/lib.d.ts]
9+
/// <reference no-default-lib="true"/>
10+
interface Boolean {}
11+
interface Function {}
12+
interface CallableFunction {}
13+
interface NewableFunction {}
14+
interface IArguments {}
15+
interface Number { toExponential: any; }
16+
interface Object {}
17+
interface RegExp {}
18+
interface String { charAt: any; }
19+
interface Array<T> { length: number; [n: number]: T; }
20+
21+
22+
/a/lib/tsc.js -w -p . --extendedDiagnostics
23+
Output::
24+
[12:00:21 AM] Starting compilation in watch mode...
25+
26+
Current directory: /user/username/projects/myproject CaseSensitiveFileNames: false
27+
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/tsconfig.json 2000 undefined Config file
28+
Synchronizing program
29+
CreatingProgramWith::
30+
roots: ["/user/username/projects/myproject/index.ts"]
31+
options: {"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"}
32+
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/index.ts 250 undefined Source file
33+
FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 250 undefined Source file
34+
DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Type roots
35+
Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Type roots
36+
[12:00:24 AM] Found 0 errors. Watching for file changes.
37+
38+
DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory
39+
Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory
40+
41+
42+
Program root files: ["/user/username/projects/myproject/index.ts"]
43+
Program options: {"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"}
44+
Program structureReused: Not
45+
Program files::
46+
/a/lib/lib.d.ts
47+
/user/username/projects/myproject/index.ts
48+
49+
Semantic diagnostics in builder refreshed for::
50+
/a/lib/lib.d.ts
51+
/user/username/projects/myproject/index.ts
52+
53+
Shape signatures in builder refreshed for::
54+
/a/lib/lib.d.ts (used version)
55+
/user/username/projects/myproject/index.ts (used version)
56+
57+
WatchedFiles::
58+
/user/username/projects/myproject/tsconfig.json:
59+
{"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250}
60+
/user/username/projects/myproject/index.ts:
61+
{"fileName":"/user/username/projects/myproject/index.ts","pollingInterval":250}
62+
/a/lib/lib.d.ts:
63+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
64+
65+
FsWatches::
66+
67+
FsWatchesRecursive::
68+
/user/username/projects/myproject/node_modules/@types:
69+
{"directoryName":"/user/username/projects/myproject/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
70+
/user/username/projects/myproject:
71+
{"directoryName":"/user/username/projects/myproject","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
72+
73+
exitCode:: ExitStatus.undefined
74+
75+
//// [/user/username/projects/myproject/index.js]
76+
77+
78+
79+
Change:: Create foo in project root
80+
81+
Input::
82+
//// [/user/username/projects/myproject/foo]
83+
84+
85+
86+
Output::
87+
DirectoryWatcher:: Triggered with /user/username/projects/myproject/foo :: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory
88+
Scheduling update
89+
Elapsed:: *ms DirectoryWatcher:: Triggered with /user/username/projects/myproject/foo :: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory
90+
Reloading new file names and options
91+
Synchronizing program
92+
93+
94+
WatchedFiles::
95+
/user/username/projects/myproject/tsconfig.json:
96+
{"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250}
97+
/user/username/projects/myproject/index.ts:
98+
{"fileName":"/user/username/projects/myproject/index.ts","pollingInterval":250}
99+
/a/lib/lib.d.ts:
100+
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
101+
102+
FsWatches::
103+
104+
FsWatchesRecursive::
105+
/user/username/projects/myproject/node_modules/@types:
106+
{"directoryName":"/user/username/projects/myproject/node_modules/@types","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
107+
/user/username/projects/myproject:
108+
{"directoryName":"/user/username/projects/myproject","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}}
109+
110+
exitCode:: ExitStatus.undefined
111+

Diff for: tests/baselines/reference/tscWatch/programUpdates/when-creating-new-file-in-symlinked-folder.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ Output::
115115
DirectoryWatcher:: Triggered with /user/username/projects/myproject/folder2/module3.ts :: WatchInfo: /user/username/projects/myproject/folder2 1 undefined Wild card directory
116116
Scheduling update
117117
Elapsed:: *ms DirectoryWatcher:: Triggered with /user/username/projects/myproject/folder2/module3.ts :: WatchInfo: /user/username/projects/myproject/folder2 1 undefined Wild card directory
118-
[12:00:41 AM] File change detected. Starting incremental compilation...
119-
120118
Reloading new file names and options
121119
Synchronizing program
120+
[12:00:41 AM] File change detected. Starting incremental compilation...
121+
122122
CreatingProgramWith::
123123
roots: ["/user/username/projects/myproject/client/folder1/module1.ts","/user/username/projects/myproject/client/linktofolder2/module2.ts","/user/username/projects/myproject/client/linktofolder2/module3.ts"]
124124
options: {"baseUrl":"/user/username/projects/myproject/client","paths":{"*":["*"]},"pathsBasePath":"/user/username/projects/myproject","watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"}

0 commit comments

Comments
 (0)