Skip to content

Commit

Permalink
When there is no change in file text for program, no need to update p…
Browse files Browse the repository at this point in the history
…rogram (#51626)

* When fsEvent for change is repeated

* When trying to check if program is uptodate, read the files from disk to determine the version instead of delaying so that new program is not created if file contents have not changed
  • Loading branch information
sheetalkamat committed Nov 29, 2022
1 parent af36a85 commit c2519bb
Show file tree
Hide file tree
Showing 19 changed files with 264 additions and 911 deletions.
2 changes: 1 addition & 1 deletion src/compiler/tsbuildPublic.ts
Expand Up @@ -436,7 +436,7 @@ function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, ho
// State of the solution
const baseCompilerOptions = getCompilerOptionsOfBuildOptions(options);
const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions) as CompilerHost & ReadBuildProgramHost;
setGetSourceFileAsHashVersioned(compilerHost, host);
setGetSourceFileAsHashVersioned(compilerHost);
compilerHost.getParsedCommandLine = fileName => parseConfigFile(state, fileName as ResolvedConfigFileName, toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName));
compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames);
compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives);
Expand Down
9 changes: 5 additions & 4 deletions src/compiler/watch.ts
Expand Up @@ -739,9 +739,9 @@ export function createWatchFactory<Y = undefined>(host: WatchFactoryHost & { tra
export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCompilerOptions: () => CompilerOptions, directoryStructureHost: DirectoryStructureHost = host): CompilerHost {
const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames();
const hostGetNewLine = memoize(() => host.getNewLine());
return {
const compilerHost: CompilerHost = {
getSourceFile: createGetSourceFile(
(fileName, encoding) => host.readFile(fileName, encoding),
(fileName, encoding) => !encoding ? compilerHost.readFile(fileName) : host.readFile(fileName, encoding),
getCompilerOptions,
/*setParentNodes*/ undefined
),
Expand All @@ -768,6 +768,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCom
disableUseFileVersionAsSignature: host.disableUseFileVersionAsSignature,
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
};
return compilerHost;
}

/** @internal */
Expand Down Expand Up @@ -810,12 +811,12 @@ export function getSourceFileVersionAsHashFromText(host: Pick<CompilerHost, "cre
}

/** @internal */
export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost, host: { createHash?(data: string): string; }) {
export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost) {
const originalGetSourceFile = compilerHost.getSourceFile;
compilerHost.getSourceFile = (...args) => {
const result = originalGetSourceFile.call(compilerHost, ...args);
if (result) {
result.version = getSourceFileVersionAsHashFromText(host, result.text);
result.version = getSourceFileVersionAsHashFromText(compilerHost, result.text);
}
return result;
};
Expand Down
17 changes: 11 additions & 6 deletions src/compiler/watchPublic.ts
Expand Up @@ -48,6 +48,7 @@ import {
getNewLineCharacter,
getNormalizedAbsolutePath,
getParsedCommandLineOfConfigFile,
getSourceFileVersionAsHashFromText,
getTsBuildInfoEmitOutputFilePath,
HasInvalidatedResolutions,
isArray,
Expand Down Expand Up @@ -121,7 +122,7 @@ export function createIncrementalCompilerHost(options: CompilerOptions, system =
host.createHash = maybeBind(system, system.createHash);
host.disableUseFileVersionAsSignature = system.disableUseFileVersionAsSignature;
host.storeFilesChangingSignatureDuringEmit = system.storeFilesChangingSignatureDuringEmit;
setGetSourceFileAsHashVersioned(host, system);
setGetSourceFileAsHashVersioned(host);
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName));
return host;
}
Expand Down Expand Up @@ -429,7 +430,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
}

const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as CompilerHost & ResolutionCacheHost;
setGetSourceFileAsHashVersioned(compilerHost, host);
setGetSourceFileAsHashVersioned(compilerHost);
// Members for CompilerHost
const getNewSourceFile = compilerHost.getSourceFile;
compilerHost.getSourceFile = (fileName, ...args) => getVersionedSourceFileByPath(fileName, toPath(fileName), ...args);
Expand Down Expand Up @@ -551,9 +552,9 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
const hasInvalidatedResolutions = resolutionCache.createHasInvalidatedResolutions(customHasInvalidatedResolutions);
const {
originalReadFile, originalFileExists, originalDirectoryExists,
originalCreateDirectory, originalWriteFile,
originalCreateDirectory, originalWriteFile, readFileWithCache
} = changeCompilerHostLikeToUseCache(compilerHost, toPath);
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileName => compilerHost.fileExists(fileName), hasInvalidatedResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) {
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, path => getSourceVersion(path, readFileWithCache), fileName => compilerHost.fileExists(fileName), hasInvalidatedResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) {
if (hasChangedConfigFileParsingErrors) {
if (reportFileChangeDetectedOnCreateProgram) {
reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation);
Expand Down Expand Up @@ -708,9 +709,13 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
}
}

function getSourceVersion(path: Path): string | undefined {
function getSourceVersion(path: Path, readFileWithCache: (file: string) => string | undefined): string | undefined {
const hostSourceFile = sourceFilesCache.get(path);
return !hostSourceFile || !hostSourceFile.version ? undefined : hostSourceFile.version;
if (!hostSourceFile) return undefined;
if (hostSourceFile.version) return hostSourceFile.version;
// Read file and get new version
const text = readFileWithCache(path);
return text ? getSourceFileVersionAsHashFromText(compilerHost, text) : undefined;
}

function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) {
Expand Down
22 changes: 22 additions & 0 deletions src/testRunner/unittests/tscWatch/watchEnvironment.ts
Expand Up @@ -702,4 +702,26 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
]
});
});

verifyTscWatch({
scenario,
subScenario: "fsEvent for change is repeated",
commandLineArgs: ["-w", "main.ts", "--extendedDiagnostics"],
sys: () => createWatchedSystem({
"/user/username/projects/project/main.ts": `let a: string = "Hello"`,
[libFile.path]: libFile.content,
}, { currentDirectory: "/user/username/projects/project" }),
changes: [
{
caption: "change main.ts",
change: sys => sys.replaceFileText("/user/username/projects/project/main.ts", "Hello", "Hello World"),
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
},
{
caption: "receive another change event without modifying the file",
change: sys => sys.invokeFsWatches("/user/username/projects/project/main.ts", "change", /*modifiedTime*/ undefined, /*useTildeSuffix*/ undefined),
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
}
]
});
});
2 changes: 1 addition & 1 deletion src/testRunner/unittests/virtualFileSystemWithWatch.ts
Expand Up @@ -686,7 +686,7 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost,
}
}

private invokeFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, useTildeSuffix: boolean | undefined) {
invokeFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, useTildeSuffix: boolean | undefined) {
this.invokeFsWatchesCallbacks(fullPath, eventName, modifiedTime, fullPath, useTildeSuffix);
this.invokeFsWatchesCallbacks(getDirectoryPath(fullPath), eventName, modifiedTime, fullPath, useTildeSuffix);
this.invokeRecursiveFsWatches(fullPath, eventName, modifiedTime, /*entryFullPath*/ undefined, useTildeSuffix);
Expand Down
Expand Up @@ -183,30 +183,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents

Output::
>> Screen clear
[12:00:43 AM] File change detected. Starting incremental compilation...

src/main.ts:4:1 - error TS1005: ',' expected.
4 ;
  ~
[12:00:44 AM] Found 1 error. Watching for file changes.
Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"incremental":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts
Semantic diagnostics in builder refreshed for::
No shapes updated in the builder::

PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down Expand Up @@ -243,9 +219,9 @@ const a = {

Output::
>> Screen clear
[[90m12:00:48 AM[0m] File change detected. Starting incremental compilation...
[[90m12:00:46 AM[0m] File change detected. Starting incremental compilation...

[[90m12:01:06 AM[0m] Found 0 errors. Watching for file changes.
[[90m12:01:04 AM[0m] Found 0 errors. Watching for file changes.



Expand Down Expand Up @@ -382,14 +358,14 @@ const a: string = 10;

Output::
>> Screen clear
[[90m12:01:13 AM[0m] File change detected. Starting incremental compilation...
[[90m12:01:11 AM[0m] File change detected. Starting incremental compilation...

src/main.ts:2:7 - error TS2322: Type 'number' is not assignable to type 'string'.

2 const a: string = 10;
   ~

[[90m12:01:17 AM[0m] Found 1 error. Watching for file changes.
[[90m12:01:15 AM[0m] Found 1 error. Watching for file changes.



Expand Down Expand Up @@ -521,30 +497,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents

Output::
>> Screen clear
[12:01:25 AM] File change detected. Starting incremental compilation...
src/main.ts:2:7 - error TS2322: Type 'number' is not assignable to type 'string'.

2 const a: string = 10;
   ~

[12:01:26 AM] Found 1 error. Watching for file changes.



Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"incremental":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::

PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down Expand Up @@ -579,9 +531,9 @@ const a: string = "hello";

Output::
>> Screen clear
[[90m12:01:30 AM[0m] File change detected. Starting incremental compilation...
[[90m12:01:26 AM[0m] File change detected. Starting incremental compilation...

[[90m12:01:37 AM[0m] Found 0 errors. Watching for file changes.
[[90m12:01:33 AM[0m] Found 0 errors. Watching for file changes.



Expand Down Expand Up @@ -701,25 +653,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents

Output::
>> Screen clear
[12:01:44 AM] File change detected. Starting incremental compilation...

[12:01:45 AM] Found 0 errors. Watching for file changes.



Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"incremental":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::

PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down
Expand Up @@ -103,30 +103,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents
Output::
>> Screen clear
[12:00:36 AM] File change detected. Starting incremental compilation...
src/main.ts:4:1 - error TS1005: ',' expected.
4 ;
  ~
[12:00:37 AM] Found 1 error. Watching for file changes.
Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts
Semantic diagnostics in builder refreshed for::
No shapes updated in the builder::
PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down Expand Up @@ -163,9 +139,9 @@ const a = {
Output::
>> Screen clear
[[90m12:00:41 AM[0m] File change detected. Starting incremental compilation...
[[90m12:00:39 AM[0m] File change detected. Starting incremental compilation...
[[90m12:00:58 AM[0m] Found 0 errors. Watching for file changes.
[[90m12:00:56 AM[0m] Found 0 errors. Watching for file changes.
Expand Down Expand Up @@ -236,14 +212,14 @@ const a: string = 10;
Output::
>> Screen clear
[[90m12:01:02 AM[0m] File change detected. Starting incremental compilation...
[[90m12:01:00 AM[0m] File change detected. Starting incremental compilation...
src/main.ts:2:7 - error TS2322: Type 'number' is not assignable to type 'string'.

2 const a: string = 10;
   ~

[[90m12:01:03 AM[0m] Found 1 error. Watching for file changes.
[[90m12:01:01 AM[0m] Found 1 error. Watching for file changes.



Expand Down Expand Up @@ -291,30 +267,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents

Output::
>> Screen clear
[12:01:08 AM] File change detected. Starting incremental compilation...
src/main.ts:2:7 - error TS2322: Type 'number' is not assignable to type 'string'.

2 const a: string = 10;
   ~

[12:01:09 AM] Found 1 error. Watching for file changes.



Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::

PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down Expand Up @@ -349,9 +301,9 @@ const a: string = "hello";

Output::
>> Screen clear
[[90m12:01:13 AM[0m] File change detected. Starting incremental compilation...
[[90m12:01:09 AM[0m] File change detected. Starting incremental compilation...

[[90m12:01:17 AM[0m] Found 0 errors. Watching for file changes.
[[90m12:01:13 AM[0m] Found 0 errors. Watching for file changes.



Expand Down Expand Up @@ -405,25 +357,6 @@ Input::
//// [/user/username/projects/noEmitOnError/src/main.ts] file written with same contents

Output::
>> Screen clear
[12:01:21 AM] File change detected. Starting incremental compilation...

[12:01:22 AM] Found 0 errors. Watching for file changes.



Program root files: ["/user/username/projects/noEmitOnError/shared/types/db.ts","/user/username/projects/noEmitOnError/src/main.ts","/user/username/projects/noEmitOnError/src/other.ts"]
Program options: {"outDir":"/user/username/projects/noEmitOnError/dev-build","noEmitOnError":true,"watch":true,"assumeChangesOnlyAffectDirectDependencies":true,"configFilePath":"/user/username/projects/noEmitOnError/tsconfig.json"}
Program structureReused: Completely
Program files::
/a/lib/lib.d.ts
/user/username/projects/noEmitOnError/shared/types/db.ts
/user/username/projects/noEmitOnError/src/main.ts
/user/username/projects/noEmitOnError/src/other.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::

PolledWatches::
/user/username/projects/noemitonerror/node_modules/@types:
Expand Down

0 comments on commit c2519bb

Please sign in to comment.