Skip to content

Commit

Permalink
Add watchOptions to tsconfig and allow supplying them on command line…
Browse files Browse the repository at this point in the history
… as well (#35615)

* Create different watch options in compiler options

* Thread through the new watch options

* Actually use the options passed through for watch strategy

* Support delay on updating child directory watches

* Make watchOptions separate from compilerOptions

* Support passing watch options from command line

* Handle displaying of watchOptions
  • Loading branch information
sheetalkamat authored Dec 11, 2019
1 parent 4212484 commit 236012e
Show file tree
Hide file tree
Showing 40 changed files with 2,416 additions and 719 deletions.
4 changes: 2 additions & 2 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ namespace ts {

function convertToReusableCompilerOptions(options: CompilerOptions, relativeToBuildInfo: (path: string) => string) {
const result: CompilerOptions = {};
const optionsNameMap = getOptionNameMap().optionNameMap;
const { optionsNameMap } = getOptionsNameMap();

for (const name in options) {
if (hasProperty(options, name)) {
Expand Down Expand Up @@ -1194,4 +1194,4 @@ namespace ts {
return Debug.assertDefined(state.program);
}
}
}
}
457 changes: 305 additions & 152 deletions src/compiler/commandLineParser.ts

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3313,6 +3313,18 @@
"category": "Error",
"code": 5077
},
"Unknown watch option '{0}'.": {
"category": "Error",
"code": 5078
},
"Unknown watch option '{0}'. Did you mean '{1}'?": {
"category": "Error",
"code": 5079
},
"Watch option '{0}' requires a value of type {1}.": {
"category": "Error",
"code": 5080
},

"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
Expand Down Expand Up @@ -4160,6 +4172,22 @@
"category": "Message",
"code": 6224
},
"Specify strategy for watching file: 'FixedPollingInterval' (default), 'PriorityPollingInterval', 'DynamicPriorityPolling', 'UseFsEvents', 'UseFsEventsOnParentDirectory'.": {
"category": "Message",
"code": 6225
},
"Specify strategy for watching directory on platforms that don't support recursive watching natively: 'UseFsEvents' (default), 'FixedPollingInterval', 'DynamicPriorityPolling'.": {
"category": "Message",
"code": 6226
},
"Specify strategy for creating a polling watch when it fails to create using file system events: 'FixedInterval' (default), 'PriorityInterval', 'DynamicPriority'.": {
"category": "Message",
"code": 6227
},
"Synchronously call callbacks and update the state of directory watchers on platforms that don't support recursive watching natively.": {
"category": "Message",
"code": 6228
},

"Projects to reference": {
"category": "Message",
Expand Down
689 changes: 479 additions & 210 deletions src/compiler/sys.ts

Large diffs are not rendered by default.

30 changes: 17 additions & 13 deletions src/compiler/tsbuildPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ namespace ts {
return createSolutionBuilderWorker(/*watch*/ false, host, rootNames, defaultOptions);
}

export function createSolutionBuilderWithWatch<T extends BuilderProgram>(host: SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder<T> {
return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions);
export function createSolutionBuilderWithWatch<T extends BuilderProgram>(host: SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder<T> {
return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions, baseWatchOptions);
}

type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic;
Expand All @@ -232,6 +232,7 @@ namespace ts {
readonly options: BuildOptions;
readonly baseCompilerOptions: CompilerOptions;
readonly rootNames: readonly string[];
readonly baseWatchOptions: WatchOptions | undefined;

readonly resolvedConfigFilePaths: Map<ResolvedConfigFilePath>;
readonly configFileCache: ConfigFileMap<ConfigFileCacheEntry>;
Expand Down Expand Up @@ -272,7 +273,7 @@ namespace ts {
writeLog: (s: string) => void;
}

function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost<T> | SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], options: BuildOptions): SolutionBuilderState<T> {
function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost<T> | SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], options: BuildOptions, baseWatchOptions: WatchOptions | undefined): SolutionBuilderState<T> {
const host = hostOrHostWithWatch as SolutionBuilderHost<T>;
const hostWithWatch = hostOrHostWithWatch as SolutionBuilderWithWatchHost<T>;
const currentDirectory = host.getCurrentDirectory();
Expand Down Expand Up @@ -306,6 +307,7 @@ namespace ts {
options,
baseCompilerOptions,
rootNames,
baseWatchOptions,

resolvedConfigFilePaths: createMap(),
configFileCache: createConfigFileMap(),
Expand Down Expand Up @@ -374,15 +376,15 @@ namespace ts {
}

let diagnostic: Diagnostic | undefined;
const { parseConfigFileHost, baseCompilerOptions, extendedConfigCache, host } = state;
const { parseConfigFileHost, baseCompilerOptions, baseWatchOptions, extendedConfigCache, host } = state;
let parsed: ParsedCommandLine | undefined;
if (host.getParsedCommandLine) {
parsed = host.getParsedCommandLine(configFileName);
if (!parsed) diagnostic = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
}
else {
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d;
parsed = getParsedCommandLineOfConfigFile(configFileName, baseCompilerOptions, parseConfigFileHost, extendedConfigCache);
parsed = getParsedCommandLineOfConfigFile(configFileName, baseCompilerOptions, parseConfigFileHost, extendedConfigCache, baseWatchOptions);
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop;
}
configFileCache.set(configFilePath, parsed || diagnostic!);
Expand Down Expand Up @@ -1147,7 +1149,7 @@ namespace ts {
}

if (reloadLevel === ConfigFileProgramReloadLevel.Full) {
watchConfigFile(state, project, projectPath);
watchConfigFile(state, project, projectPath, config);
watchWildCardDirectories(state, project, projectPath, config);
watchInputFiles(state, project, projectPath, config);
}
Expand Down Expand Up @@ -1751,7 +1753,7 @@ namespace ts {
reportErrorSummary(state, buildOrder);
}

function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath) {
function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) {
if (!state.watch || state.allWatchedConfigFiles.has(resolvedPath)) return;
state.allWatchedConfigFiles.set(resolvedPath, state.watchFile(
state.hostWithWatch,
Expand All @@ -1760,6 +1762,7 @@ namespace ts {
invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full);
},
PollingInterval.High,
parsed?.watchOptions,
WatchType.ConfigFile,
resolved
));
Expand Down Expand Up @@ -1820,6 +1823,7 @@ namespace ts {
invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial);
},
flags,
parsed?.watchOptions,
WatchType.WildcardDirectory,
resolved
)
Expand All @@ -1837,6 +1841,7 @@ namespace ts {
input,
() => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None),
PollingInterval.Low,
parsed?.watchOptions,
path as Path,
WatchType.SourceFile,
resolved
Expand All @@ -1851,10 +1856,9 @@ namespace ts {
state.watchAllProjectsPending = false;
for (const resolved of getBuildOrderFromAnyBuildOrder(buildOrder)) {
const resolvedPath = toResolvedConfigFilePath(state, resolved);
// Watch this file
watchConfigFile(state, resolved, resolvedPath);

const cfg = parseConfigFile(state, resolved, resolvedPath);
// Watch this file
watchConfigFile(state, resolved, resolvedPath, cfg);
if (cfg) {
// Update watchers for wildcard directories
watchWildCardDirectories(state, resolved, resolvedPath, cfg);
Expand All @@ -1870,9 +1874,9 @@ namespace ts {
* can dynamically add/remove other projects based on changes on the rootNames' references
*/
function createSolutionBuilderWorker<T extends BuilderProgram>(watch: false, host: SolutionBuilderHost<T>, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder<T>;
function createSolutionBuilderWorker<T extends BuilderProgram>(watch: true, host: SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder<T>;
function createSolutionBuilderWorker<T extends BuilderProgram>(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost<T> | SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], options: BuildOptions): SolutionBuilder<T> {
const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options);
function createSolutionBuilderWorker<T extends BuilderProgram>(watch: true, host: SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder<T>;
function createSolutionBuilderWorker<T extends BuilderProgram>(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost<T> | SolutionBuilderWithWatchHost<T>, rootNames: readonly string[], options: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder<T> {
const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options, baseWatchOptions);
return {
build: (project, cancellationToken) => build(state, project, cancellationToken),
clean: project => clean(state, project),
Expand Down
35 changes: 33 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4929,6 +4929,26 @@ namespace ts {
circular?: boolean;
}

export enum WatchFileKind {
FixedPollingInterval,
PriorityPollingInterval,
DynamicPriorityPolling,
UseFsEvents,
UseFsEventsOnParentDirectory,
}

export enum WatchDirectoryKind {
UseFsEvents,
FixedPollingInterval,
DynamicPriorityPolling,
}

export enum PollingWatchKind {
FixedInterval,
PriorityInterval,
DynamicPriority,
}

export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[] | ProjectReference[] | null | undefined;

export interface CompilerOptions {
Expand Down Expand Up @@ -5043,6 +5063,15 @@ namespace ts {
[option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined;
}

export interface WatchOptions {
watchFile?: WatchFileKind;
watchDirectory?: WatchDirectoryKind;
fallbackPolling?: PollingWatchKind;
synchronousWatchDirectory?: boolean;

[option: string]: CompilerOptionsValue | undefined;
}

export interface TypeAcquisition {
/**
* @deprecated typingOptions.enableAutoDiscovery
Expand Down Expand Up @@ -5130,6 +5159,7 @@ namespace ts {
typeAcquisition?: TypeAcquisition;
fileNames: string[];
projectReferences?: readonly ProjectReference[];
watchOptions?: WatchOptions;
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
Expand Down Expand Up @@ -5210,7 +5240,8 @@ namespace ts {
}

/* @internal */
export interface DidYouMeanOptionalDiagnostics {
export interface DidYouMeanOptionsDiagnostics {
optionDeclarations: CommandLineOption[];
unknownOptionDiagnostic: DiagnosticMessage,
unknownDidYouMeanDiagnostic: DiagnosticMessage,
}
Expand All @@ -5219,7 +5250,7 @@ namespace ts {
export interface TsConfigOnlyOption extends CommandLineOptionBase {
type: "object";
elementOptions?: Map<CommandLineOption>;
extraKeyDiagnostics?: DidYouMeanOptionalDiagnostics;
extraKeyDiagnostics?: DidYouMeanOptionsDiagnostics;
}

/* @internal */
Expand Down
10 changes: 6 additions & 4 deletions src/compiler/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ namespace ts {
}

/** Parses config file using System interface */
export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, system: System, reportDiagnostic: DiagnosticReporter) {
export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, watchOptionsToExtend: WatchOptions | undefined, system: System, reportDiagnostic: DiagnosticReporter) {
const host: ParseConfigFileHost = <any>system;
host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic);
const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host);
const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host, /*extendedConfigCache*/ undefined, watchOptionsToExtend);
host.onUnRecoverableConfigFileDiagnostic = undefined!; // TODO: GH#18217
return result;
}
Expand Down Expand Up @@ -419,22 +419,24 @@ namespace ts {
/**
* Creates the watch compiler host from system for config file in watch mode
*/
export function createWatchCompilerHostOfConfigFile<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T> {
export function createWatchCompilerHostOfConfigFile<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, watchOptionsToExtend: WatchOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T> {
const diagnosticReporter = reportDiagnostic || createDiagnosticReporter(system);
const host = createWatchCompilerHost(system, createProgram, diagnosticReporter, reportWatchStatus) as WatchCompilerHostOfConfigFile<T>;
host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, diagnosticReporter, diagnostic);
host.configFileName = configFileName;
host.optionsToExtend = optionsToExtend;
host.watchOptionsToExtend = watchOptionsToExtend;
return host;
}

/**
* Creates the watch compiler host from system for compiling root files and options in watch mode
*/
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: readonly ProjectReference[]): WatchCompilerHostOfFilesAndCompilerOptions<T> {
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, watchOptions: WatchOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: readonly ProjectReference[]): WatchCompilerHostOfFilesAndCompilerOptions<T> {
const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions<T>;
host.rootFiles = rootFiles;
host.options = options;
host.watchOptions = watchOptions;
host.projectReferences = projectReferences;
return host;
}
Expand Down
Loading

0 comments on commit 236012e

Please sign in to comment.