Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port of #51626 and #51689 to release-4.9 #51627

Merged
merged 4 commits into from Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/compiler/tsbuildPublic.ts
Expand Up @@ -292,7 +292,7 @@ namespace ts {
// 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 Expand Up @@ -1655,7 +1655,7 @@ namespace ts {
if (!buildInfoVersionMap) buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host);
version = buildInfoVersionMap.get(toPath(state, inputFile));
const text = version ? state.readFileWithCache(inputFile) : undefined;
currentVersion = text && (host.createHash || generateDjb2Hash)(text);
currentVersion = text !== undefined ? (host.createHash || generateDjb2Hash)(text) : undefined;
if (version && version === currentVersion) pseudoInputUpToDate = true;
}

Expand Down
10 changes: 6 additions & 4 deletions src/compiler/watch.ts
Expand Up @@ -595,12 +595,13 @@ namespace ts {
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: (fileName, languageVersionOrOptions, onError) => {
let text: string | undefined;
try {
performance.mark("beforeIORead");
text = host.readFile(fileName, getCompilerOptions().charset);
const encoding = getCompilerOptions().charset;
text = !encoding ? compilerHost.readFile(fileName) : host.readFile(fileName, encoding);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
Expand Down Expand Up @@ -632,6 +633,7 @@ namespace ts {
disableUseFileVersionAsSignature: host.disableUseFileVersionAsSignature,
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
};
return compilerHost;

function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, onError: (message: string) => void) {
try {
Expand Down Expand Up @@ -659,9 +661,9 @@ namespace ts {
}
}

export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost, host: { createHash?(data: string): string; }) {
export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost) {
const originalGetSourceFile = compilerHost.getSourceFile;
const computeHash = maybeBind(host, host.createHash) || generateDjb2Hash;
const computeHash = maybeBind(compilerHost, compilerHost.createHash) || generateDjb2Hash;
compilerHost.getSourceFile = (...args) => {
const result = originalGetSourceFile.call(compilerHost, ...args);
if (result) {
Expand Down
16 changes: 10 additions & 6 deletions src/compiler/watchPublic.ts
Expand Up @@ -28,7 +28,7 @@ namespace ts {
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 @@ -330,7 +330,7 @@ namespace ts {
}

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 @@ -452,9 +452,9 @@ namespace ts {
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 @@ -609,9 +609,13 @@ namespace ts {
}
}

function getSourceVersion(path: Path): string | undefined {
function getSourceVersion(path: Path, readFileWithCache: (fileName: 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 !== undefined ? (compilerHost.createHash || generateDjb2Hash)(text) : undefined;
}

function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) {
Expand Down
2 changes: 1 addition & 1 deletion src/harness/virtualFileSystemWithWatch.ts
Expand Up @@ -730,7 +730,7 @@ interface Array<T> { length: number; [n: number]: T; }`
}
}

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
32 changes: 32 additions & 0 deletions src/testRunner/unittests/tscWatch/watchEnvironment.ts
Expand Up @@ -687,5 +687,37 @@ namespace ts.tscWatch {
]
});
});

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 => replaceFileText(sys, "/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(),
},
{
caption: "change main.ts to empty text",
change: sys => sys.writeFile("/user/username/projects/project/main.ts", ""),
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(),
}
]
});
});
}
Expand Up @@ -132,25 +132,11 @@ Output::
>> Screen clear
[12:00:36 AM] File change detected. Starting incremental compilation...

[12:00:37 AM] Project 'tsconfig.json' is out of date because output 'tsconfig.tsbuildinfo' is older than input 'a.js'
[12:00:37 AM] Project 'tsconfig.json' is up to date but needs to update timestamps of output files that are older than input files

[12:00:38 AM] Building project '/user/username/projects/myproject/tsconfig.json'...
[12:00:38 AM] Found 0 errors. Watching for file changes.

[12:00:39 AM] Found 0 errors. Watching for file changes.



Program root files: ["/user/username/projects/myproject/a.js","/user/username/projects/myproject/b.ts"]
Program options: {"allowJs":true,"noEmit":true,"watch":true,"incremental":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.d.ts
/user/username/projects/myproject/a.js
/user/username/projects/myproject/b.ts

Semantic diagnostics in builder refreshed for::

No shapes updated in the builder::

PolledWatches::

Expand Down Expand Up @@ -178,13 +164,13 @@ const x = 10;

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

[12:00:44 AM] Project 'tsconfig.json' is out of date because output 'tsconfig.tsbuildinfo' is older than input 'a.js'
[12:00:43 AM] Project 'tsconfig.json' is out of date because output 'tsconfig.tsbuildinfo' is older than input 'a.js'

[12:00:45 AM] Building project '/user/username/projects/myproject/tsconfig.json'...
[12:00:44 AM] Building project '/user/username/projects/myproject/tsconfig.json'...

[12:00:53 AM] Found 0 errors. Watching for file changes.
[12:00:52 AM] Found 0 errors. Watching for file changes.



Expand Down
Expand Up @@ -179,30 +179,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 @@ -239,9 +215,9 @@ const a = {

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

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



Expand Down Expand Up @@ -370,14 +346,14 @@ const a: string = 10;

Output::
>> Screen clear
[12:01:13 AM] File change detected. Starting incremental compilation...
[12:01:11 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:17 AM] Found 1 error. Watching for file changes.
[12:01:15 AM] Found 1 error. Watching for file changes.



Expand Down Expand Up @@ -501,30 +477,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 @@ -559,9 +511,9 @@ const a: string = "hello";

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

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



Expand Down Expand Up @@ -673,25 +625,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