mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 05:17:43 -05:00
Update watchFile to take priority (which is currently polling interval being passed to the host)
This commit is contained in:
@@ -30,6 +30,23 @@ namespace ts {
|
||||
mtime?: Date;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export enum WatchPriority {
|
||||
High,
|
||||
Medium,
|
||||
Low
|
||||
}
|
||||
|
||||
const pollingIntervalsForPriority = [250, 1000, 4000];
|
||||
function pollingInterval(watchPriority: WatchPriority): number {
|
||||
return pollingIntervalsForPriority[watchPriority];
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function watchFileUsingPriorityPollingInterval(host: System, fileName: string, callback: FileWatcherCallback, watchPriority: WatchPriority): FileWatcher {
|
||||
return host.watchFile(fileName, callback, pollingInterval(watchPriority));
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial interface of the System thats needed to support the caching of directory structure
|
||||
*/
|
||||
|
||||
@@ -255,16 +255,13 @@ namespace ts {
|
||||
const watchLogLevel = compilerOptions.extendedDiagnostics ? WatchLogLevel.Verbose :
|
||||
compilerOptions.diagnostics ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
|
||||
const writeLog: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? s => { system.write(s); system.write(system.newLine); } : noop;
|
||||
const watchFile = createWatchFile(watchLogLevel, writeLog);
|
||||
const watchFilePath = createWatchFilePath(watchLogLevel, writeLog);
|
||||
const watchDirectoryWorker = createWatchDirectory(watchLogLevel, writeLog);
|
||||
|
||||
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
|
||||
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
|
||||
const { watchFile, watchFilePath, watchDirectory: watchDirectoryWorker } = getWatchFactory(system, watchLogLevel, writeLog);
|
||||
|
||||
const directoryStructureHost = configFileName ? createCachedDirectoryStructureHost(system) : system;
|
||||
if (configFileName) {
|
||||
watchFile(system, configFileName, scheduleProgramReload, /*pollingInterval*/ undefined);
|
||||
watchFile(system, configFileName, scheduleProgramReload, WatchPriority.Low);
|
||||
}
|
||||
|
||||
const getCurrentDirectory = memoize(() => directoryStructureHost.getCurrentDirectory());
|
||||
@@ -417,7 +414,7 @@ namespace ts {
|
||||
hostSourceFile.sourceFile = sourceFile;
|
||||
sourceFile.version = hostSourceFile.version.toString();
|
||||
if (!hostSourceFile.fileWatcher) {
|
||||
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, /*pollingInterval*/ undefined, path);
|
||||
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, WatchPriority.High, path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -430,7 +427,7 @@ namespace ts {
|
||||
let fileWatcher: FileWatcher;
|
||||
if (sourceFile) {
|
||||
sourceFile.version = "0";
|
||||
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, /*pollingInterval*/ undefined, path);
|
||||
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, WatchPriority.High, path);
|
||||
sourceFilesCache.set(path, { sourceFile, version: 0, fileWatcher });
|
||||
}
|
||||
else {
|
||||
@@ -604,7 +601,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function watchMissingFilePath(missingFilePath: Path) {
|
||||
return watchFilePath(system, missingFilePath, onMissingFileChange, /*pollingInterval*/ undefined, missingFilePath);
|
||||
return watchFilePath(system, missingFilePath, onMissingFileChange, WatchPriority.Medium, missingFilePath);
|
||||
}
|
||||
|
||||
function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) {
|
||||
|
||||
@@ -96,43 +96,63 @@ namespace ts {
|
||||
Verbose
|
||||
}
|
||||
|
||||
export type WatchFile<X, Y> = (host: System, file: string, callback: FileWatcherCallback, pollingInterval?: number, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchFile<X, Y> = (host: System, file: string, callback: FileWatcherCallback, watchPriority: WatchPriority, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
|
||||
export type WatchFilePath<X, Y> = (host: System, file: string, callback: FilePathWatcherCallback, pollingInterval: number | undefined, path: Path, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchFilePath<X, Y> = (host: System, file: string, callback: FilePathWatcherCallback, watchPriority: WatchPriority, path: Path, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
export type WatchDirectory<X, Y> = (host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
|
||||
|
||||
export function createWatchFile<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFile<X, Y> {
|
||||
const createFileWatcher: CreateFileWatcher<number | undefined, FileWatcherEventKind, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
|
||||
return (host, file, callback, pollingInterval, detailInfo1, detailInfo2) =>
|
||||
createFileWatcher(host, file, callback, pollingInterval, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo);
|
||||
export interface WatchFactory<X, Y> {
|
||||
watchFile: WatchFile<X, Y>;
|
||||
watchFilePath: WatchFilePath<X, Y>;
|
||||
watchDirectory: WatchDirectory<X, Y>;
|
||||
}
|
||||
|
||||
export function createWatchFilePath<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFilePath<X, Y> {
|
||||
const createFileWatcher: CreateFileWatcher<number | undefined, FileWatcherEventKind, Path, X, Y> = getCreateFileWatcher(watchLogLevel, watchFilePath);
|
||||
return (host, file, callback, pollingInterval, path, detailInfo1, detailInfo2) =>
|
||||
createFileWatcher(host, file, callback, pollingInterval, path, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo);
|
||||
export function getWatchFactory<X = undefined, Y = undefined>(host: System, watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
const value = host.getEnvironmentVariable("TSC_WATCHFILE");
|
||||
switch (value) {
|
||||
case "PriorityPollingInterval":
|
||||
// Use polling interval based on priority when create watch using host.watchFile
|
||||
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFileUsingPriorityPollingInterval, watchDirectory);
|
||||
default:
|
||||
return getDefaultWatchFactory(watchLogLevel, log, getDetailWatchInfo);
|
||||
}
|
||||
}
|
||||
|
||||
export function createWatchDirectory<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchDirectory<X, Y> {
|
||||
const createFileWatcher: CreateFileWatcher<WatchDirectoryFlags, undefined, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchDirectory);
|
||||
return (host, directory, callback, flags, detailInfo1, detailInfo2) =>
|
||||
createFileWatcher(host, directory, callback, flags, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchDirectory, log, "DirectoryWatcher", getDetailWatchInfo);
|
||||
export function getDefaultWatchFactory<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
|
||||
// Current behaviour in which polling interval is always 250 ms
|
||||
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFile, watchDirectory);
|
||||
}
|
||||
|
||||
function watchFile(host: System, file: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher {
|
||||
return host.watchFile(file, callback, pollingInterval);
|
||||
function getWatchFactoryWith<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined,
|
||||
watchFile: (host: System, file: string, callback: FileWatcherCallback, watchPriority: WatchPriority) => FileWatcher,
|
||||
watchDirectory: (host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags) => FileWatcher): WatchFactory<X, Y> {
|
||||
const createFileWatcher: CreateFileWatcher<WatchPriority, FileWatcherEventKind, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
|
||||
const createFilePathWatcher: CreateFileWatcher<WatchPriority, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
|
||||
const createDirectoryWatcher: CreateFileWatcher<WatchDirectoryFlags, undefined, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchDirectory);
|
||||
return {
|
||||
watchFile: (host, file, callback, pollingInterval, detailInfo1, detailInfo2) =>
|
||||
createFileWatcher(host, file, callback, pollingInterval, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo),
|
||||
watchFilePath: (host, file, callback, pollingInterval, path, detailInfo1, detailInfo2) =>
|
||||
createFilePathWatcher(host, file, callback, pollingInterval, path, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo),
|
||||
watchDirectory: (host, directory, callback, flags, detailInfo1, detailInfo2) =>
|
||||
createDirectoryWatcher(host, directory, callback, flags, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchDirectory, log, "DirectoryWatcher", getDetailWatchInfo)
|
||||
};
|
||||
|
||||
function watchFilePath(host: System, file: string, callback: FilePathWatcherCallback, watchPriority: WatchPriority, path: Path): FileWatcher {
|
||||
return watchFile(host, file, (fileName, eventKind) => callback(fileName, eventKind, path), watchPriority);
|
||||
}
|
||||
}
|
||||
|
||||
function watchFilePath(host: System, file: string, callback: FilePathWatcherCallback, pollingInterval: number | undefined, path: Path): FileWatcher {
|
||||
return host.watchFile(file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval);
|
||||
function watchFile(host: System, file: string, callback: FileWatcherCallback, _watchPriority: WatchPriority): FileWatcher {
|
||||
return host.watchFile(file, callback);
|
||||
}
|
||||
|
||||
function watchDirectory(host: System, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
|
||||
return host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0);
|
||||
}
|
||||
|
||||
export type WatchCallback<T, U> = (fileName: string, cbOptional?: T, passThrough?: U) => void;
|
||||
export type AddWatch<T, U, V> = (host: System, file: string, cb: WatchCallback<U, V>, flags: T, passThrough?: V, detailInfo1?: undefined, detailInfo2?: undefined) => FileWatcher;
|
||||
type WatchCallback<T, U> = (fileName: string, cbOptional?: T, passThrough?: U) => void;
|
||||
type AddWatch<T, U, V> = (host: System, file: string, cb: WatchCallback<U, V>, flags: T, passThrough?: V, detailInfo1?: undefined, detailInfo2?: undefined) => FileWatcher;
|
||||
export type GetDetailWatchInfo<X, Y> = (detailInfo1: X, detailInfo2: Y) => string;
|
||||
|
||||
type CreateFileWatcher<T, U, V, X, Y> = (host: System, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<T, U, V>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined) => FileWatcher;
|
||||
@@ -170,7 +190,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getWatchInfo<T, X, Y>(file: string, flags: T, detailInfo1: X | undefined, detailInfo2: Y | undefined, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined) {
|
||||
return `WatchInfo: ${file} ${flags} ${getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) : ""}`
|
||||
return `WatchInfo: ${file} ${flags} ${getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) : ""}`;
|
||||
}
|
||||
|
||||
export function closeFileWatcher(watcher: FileWatcher) {
|
||||
|
||||
@@ -410,11 +410,7 @@ namespace ts.server {
|
||||
private readonly seenProjects = createMap<true>();
|
||||
|
||||
/*@internal*/
|
||||
readonly watchFile: WatchFile;
|
||||
/*@internal*/
|
||||
readonly watchFilePath: WatchFilePath;
|
||||
/*@internal*/
|
||||
readonly watchDirectory: WatchDirectory;
|
||||
readonly watchFactory: WatchFactory<WatchType, Project>;
|
||||
|
||||
constructor(opts: ProjectServiceOptions) {
|
||||
this.host = opts.host;
|
||||
@@ -457,9 +453,7 @@ namespace ts.server {
|
||||
const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose :
|
||||
this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
|
||||
const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop;
|
||||
this.watchFile = createWatchFile(watchLogLevel, log, getDetailWatchInfo);
|
||||
this.watchFilePath = createWatchFilePath(watchLogLevel, log, getDetailWatchInfo);
|
||||
this.watchDirectory = createWatchDirectory(watchLogLevel, log, getDetailWatchInfo);
|
||||
this.watchFactory = getDefaultWatchFactory(watchLogLevel, log, getDetailWatchInfo);
|
||||
}
|
||||
|
||||
toPath(fileName: string) {
|
||||
@@ -792,7 +786,7 @@ namespace ts.server {
|
||||
*/
|
||||
/*@internal*/
|
||||
watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, project: ConfiguredProject) {
|
||||
return this.watchDirectory(
|
||||
return this.watchFactory.watchDirectory(
|
||||
this.host,
|
||||
directory,
|
||||
fileOrDirectory => {
|
||||
@@ -1122,11 +1116,11 @@ namespace ts.server {
|
||||
canonicalConfigFilePath: string,
|
||||
configFileExistenceInfo: ConfigFileExistenceInfo
|
||||
) {
|
||||
configFileExistenceInfo.configFileWatcherForRootOfInferredProject = this.watchFile(
|
||||
configFileExistenceInfo.configFileWatcherForRootOfInferredProject = this.watchFactory.watchFile(
|
||||
this.host,
|
||||
configFileName,
|
||||
(_filename, eventKind) => this.onConfigFileChangeForOpenScriptInfo(configFileName, eventKind),
|
||||
/*pollingInterval*/ undefined,
|
||||
WatchPriority.Low,
|
||||
WatchType.ConfigFileForInferredRoot
|
||||
);
|
||||
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.UpdatedCallback);
|
||||
@@ -1506,11 +1500,11 @@ namespace ts.server {
|
||||
|
||||
project.configFileSpecs = configFileSpecs;
|
||||
// TODO: We probably should also watch the configFiles that are extended
|
||||
project.configFileWatcher = this.watchFile(
|
||||
project.configFileWatcher = this.watchFactory.watchFile(
|
||||
this.host,
|
||||
configFileName,
|
||||
(_fileName, eventKind) => this.onConfigChangedForConfiguredProject(project, eventKind),
|
||||
/*pollingInterval*/ undefined,
|
||||
WatchPriority.Low,
|
||||
WatchType.ConfigFilePath,
|
||||
project
|
||||
);
|
||||
@@ -1733,11 +1727,11 @@ namespace ts.server {
|
||||
// do not watch files with mixed content - server doesn't know how to interpret it
|
||||
if (!info.isDynamicOrHasMixedContent()) {
|
||||
const { fileName } = info;
|
||||
info.fileWatcher = this.watchFilePath(
|
||||
info.fileWatcher = this.watchFactory.watchFilePath(
|
||||
this.host,
|
||||
fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
/*pollingInterval*/ undefined,
|
||||
WatchPriority.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
|
||||
@@ -376,7 +376,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
|
||||
return this.projectService.watchDirectory(
|
||||
return this.projectService.watchFactory.watchDirectory(
|
||||
this.projectService.host,
|
||||
directory,
|
||||
cb,
|
||||
@@ -393,7 +393,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
|
||||
return this.projectService.watchDirectory(
|
||||
return this.projectService.watchFactory.watchDirectory(
|
||||
this.projectService.host,
|
||||
directory,
|
||||
cb,
|
||||
@@ -916,7 +916,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private addMissingFileWatcher(missingFilePath: Path) {
|
||||
const fileWatcher = this.projectService.watchFile(
|
||||
const fileWatcher = this.projectService.watchFactory.watchFile(
|
||||
this.projectService.host,
|
||||
missingFilePath,
|
||||
(fileName, eventKind) => {
|
||||
@@ -932,7 +932,7 @@ namespace ts.server {
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
}
|
||||
},
|
||||
/*pollingInterval*/ undefined,
|
||||
WatchPriority.Medium,
|
||||
WatchType.MissingFilePath,
|
||||
this
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user