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

Add watchOptions to tsconfig and allow supplying them on command line as well #35615

Merged
merged 8 commits into from
Dec 11, 2019
4 changes: 2 additions & 2 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,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 @@ -1183,4 +1183,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.

30 changes: 29 additions & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3309,6 +3309,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 @@ -4064,7 +4076,7 @@
"category": "Message",
"code": 6201
},
"Project references may not form a circular graph. Cycle detected: {0}": {
"Project references may not form a circular graph. Cycle detected: {0}": {
"category": "Error",
"code": 6202
},
Expand Down Expand Up @@ -4152,6 +4164,22 @@
"category": "Message",
"code": 6223
},
"Specify strategy for watching file: 'FixedPollingInterval' (default), 'PriorityPollingInterval', 'DynamicPriorityPolling', 'UseFsEvents', 'UseFsEventsOnParentDirectory'.": {
"category": "Message",
"code": 6224
},
"Specify strategy for watching directory on platforms that don't support recursive watching natively: 'UseFsEvents' (default), 'FixedPollingInterval', 'DynamicPriorityPolling'.": {
"category": "Message",
"code": 6225
},
"Specify strategy for creating a polling watch when it fails to create using file system events: 'FixedInterval' (default), 'PriorityInterval', 'DynamicPriority'.": {
"category": "Message",
"code": 6226
},
"Synchronously call callbacks and update the state of directory watchers on platforms that don't support recursive watching natively.": {
"category": "Message",
"code": 6227
},

"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 @@ -4917,6 +4917,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 @@ -5030,6 +5050,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 @@ -5117,6 +5146,7 @@ namespace ts {
typeAcquisition?: TypeAcquisition;
fileNames: string[];
projectReferences?: readonly ProjectReference[];
watchOptions?: WatchOptions;
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
Expand Down Expand Up @@ -5197,7 +5227,8 @@ namespace ts {
}

/* @internal */
export interface DidYouMeanOptionalDiagnostics {
export interface DidYouMeanOptionsDiagnostics {
optionDeclarations: CommandLineOption[];
unknownOptionDiagnostic: DiagnosticMessage,
unknownDidYouMeanDiagnostic: DiagnosticMessage,
}
Expand All @@ -5206,7 +5237,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