Add createProgram on WatchCompilerHost

This commit is contained in:
Sheetal Nandi 2018-01-19 14:59:35 -08:00
parent bd43e45075
commit 2be231d339
8 changed files with 178 additions and 133 deletions

View File

@ -220,9 +220,30 @@ namespace ts {
EmitAndSemanticDiagnosticsBuilderProgram
}
export function createBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram: BuilderProgram | undefined, kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram: BuilderProgram | undefined, kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram: BuilderProgram | undefined, kind: BuilderProgramKind) {
export interface BuilderCreationParameters {
newProgram: Program;
host: BuilderProgramHost;
oldProgram: BuilderProgram | undefined;
}
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderCreationParameters {
let host: BuilderProgramHost;
let newProgram: Program;
if (isArray(newProgramOrRootNames)) {
newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram());
host = oldProgramOrHost as CompilerHost;
}
else {
newProgram = newProgramOrRootNames as Program;
host = hostOrOptions as BuilderProgramHost;
oldProgram = oldProgramOrHost as BuilderProgram;
}
return { host, newProgram, oldProgram };
}
export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram }: BuilderCreationParameters) {
// Return same program if underlying program doesnt change
let oldState = oldProgram && oldProgram.getState();
if (oldState && newProgram === oldState.program) {
@ -518,15 +539,43 @@ namespace ts {
/**
* Create the builder to manage semantic diagnostics and cache them
*/
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram {
return createBuilderProgram(newProgram, host, oldProgram, BuilderProgramKind.SemanticDiagnosticsBuilderProgram);
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, oldProgram?: SemanticDiagnosticsBuilderProgram) {
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram));
}
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram {
return createBuilderProgram(newProgram, host, oldProgram, BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram);
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram) {
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram));
}
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram): BuilderProgram;
export function createAbstractBuilder(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram): BuilderProgram;
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, oldProgram?: BuilderProgram): BuilderProgram {
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, oldProgram);
return {
// Only return program, all other methods are not implemented
getProgram: () => program,
getState: notImplemented,
getCompilerOptions: notImplemented,
getSourceFile: notImplemented,
getSourceFiles: notImplemented,
getOptionsDiagnostics: notImplemented,
getGlobalDiagnostics: notImplemented,
getSyntacticDiagnostics: notImplemented,
getSemanticDiagnostics: notImplemented,
emit: notImplemented,
getAllDependencies: notImplemented,
getCurrentDirectory: notImplemented
};
}
}

View File

@ -149,12 +149,16 @@ namespace ts {
return sys.exit(exitStatus);
}
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost) {
const compileUsingBuilder = watchCompilerHost.afterProgramCreate;
watchCompilerHost.beforeProgramCreate = enableStatistics;
watchCompilerHost.afterProgramCreate = program => {
compileUsingBuilder(program);
reportStatistics(program);
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>) {
const compileUsingBuilder = watchCompilerHost.createProgram;
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram) => {
enableStatistics(options);
return compileUsingBuilder(rootNames, options, host, oldProgram);
};
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate;
watchCompilerHost.afterProgramCreate = builderProgram => {
emitFilesUsingBuilder(builderProgram);
reportStatistics(builderProgram.getProgram());
};
}
@ -163,7 +167,7 @@ namespace ts {
}
function createWatchOfConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions) {
const watchCompilerHost = ts.createWatchCompilerHostOfConfigFile(configParseResult.options.configFilePath, optionsToExtend, sys, reportDiagnostic, createWatchStatusReporter(configParseResult.options));
const watchCompilerHost = ts.createWatchCompilerHostOfConfigFile(configParseResult.options.configFilePath, optionsToExtend, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(configParseResult.options));
updateWatchCompilationHost(watchCompilerHost);
watchCompilerHost.rootFiles = configParseResult.fileNames;
watchCompilerHost.options = configParseResult.options;
@ -173,7 +177,7 @@ namespace ts {
}
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], options: CompilerOptions) {
const watchCompilerHost = ts.createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, sys, reportDiagnostic, createWatchStatusReporter(options));
const watchCompilerHost = ts.createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(options));
updateWatchCompilationHost(watchCompilerHost);
createWatchProgram(watchCompilerHost);
}

View File

@ -4471,6 +4471,7 @@ namespace ts {
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
createHash?(data: string): string;
}
/* @internal */

View File

@ -176,16 +176,14 @@ namespace ts {
/**
* Creates the watch compiler host that can be extended with config file or root file names and options host
*/
function createWatchCompilerHost(system = sys, reportDiagnostic: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHost {
function createWatchCompilerHost<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(system = sys, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHost<T> {
if (!createProgram) {
createProgram = createEmitAndSemanticDiagnosticsBuilderProgram as any;
}
let host: DirectoryStructureHost = system;
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
const writeFileName = (s: string) => system.write(s + system.newLine);
const builderProgramHost: BuilderProgramHost = {
useCaseSensitiveFileNames,
createHash: system.createHash && (s => system.createHash(s)),
writeFile
};
let builderProgram: EmitAndSemanticDiagnosticsBuilderProgram | undefined;
return {
useCaseSensitiveFileNames,
getNewLine: () => system.newLine,
@ -208,42 +206,18 @@ namespace ts {
createDirectory: path => system.createDirectory(path),
writeFile: (path, data, writeByteOrderMark) => system.writeFile(path, data, writeByteOrderMark),
onCachedDirectoryStructureHostCreate: cacheHost => host = cacheHost || system,
afterProgramCreate: emitFilesAndReportErrorUsingBuilder,
createHash: system.createHash && (s => system.createHash(s)),
createProgram,
afterProgramCreate: emitFilesAndReportErrorUsingBuilder
};
function getDefaultLibLocation() {
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
}
function emitFilesAndReportErrorUsingBuilder(program: Program) {
builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram(program, builderProgramHost, builderProgram);
function emitFilesAndReportErrorUsingBuilder(builderProgram: BuilderProgram) {
emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName);
}
function ensureDirectoriesExist(directoryPath: string) {
if (directoryPath.length > getRootLength(directoryPath) && !host.directoryExists(directoryPath)) {
const parentDirectory = getDirectoryPath(directoryPath);
ensureDirectoriesExist(parentDirectory);
host.createDirectory(directoryPath);
}
}
function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, onError: (message: string) => void) {
try {
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
host.writeFile(fileName, text, writeByteOrderMark);
performance.mark("afterIOWrite");
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
}
catch (e) {
if (onError) {
onError(e.message);
}
}
}
}
/**
@ -257,9 +231,9 @@ namespace ts {
/**
* Creates the watch compiler host from system for config file in watch mode
*/
export function createWatchCompilerHostOfConfigFile(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile {
export function createWatchCompilerHostOfConfigFile<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T> {
reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system);
const host = createWatchCompilerHost(system, reportDiagnostic, reportWatchStatus) as WatchCompilerHostOfConfigFile;
const host = createWatchCompilerHost(system, createProgram, reportDiagnostic, reportWatchStatus) as WatchCompilerHostOfConfigFile<T>;
host.onConfigFileDiagnostic = reportDiagnostic;
host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic);
host.configFileName = configFileName;
@ -270,8 +244,8 @@ namespace ts {
/**
* Creates the watch compiler host from system for compiling root files and options in watch mode
*/
export function createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles: string[], options: CompilerOptions, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions {
const host = createWatchCompilerHost(system, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions;
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> {
const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions<T>;
host.rootFiles = rootFiles;
host.options = options;
return host;
@ -281,12 +255,14 @@ namespace ts {
namespace ts {
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string) => void;
export interface WatchCompilerHost {
/** If provided, callback to invoke before each program creation */
beforeProgramCreate?(compilerOptions: CompilerOptions): void;
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T;
export interface WatchCompilerHost<T extends BuilderProgram> {
/**
* Used to create the program when need for program creation or recreation detected
*/
createProgram: CreateProgram<T>;
/** If provided, callback to invoke after every new program creation */
afterProgramCreate?(program: Program): void;
afterProgramCreate?(program: T): void;
/** If provided, called with Diagnostic message that informs about change in watch status */
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void;
@ -300,6 +276,7 @@ namespace ts {
getCurrentDirectory(): string;
getDefaultLibFileName(options: CompilerOptions): string;
getDefaultLibLocation?(): string;
createHash?(data: string): string;
/**
* Use to check file presence for source files and
@ -343,7 +320,7 @@ namespace ts {
/** Internal interface used to wire emit through same host */
/*@internal*/
export interface WatchCompilerHost {
export interface WatchCompilerHost<T extends BuilderProgram> {
createDirectory?(path: string): void;
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
onCachedDirectoryStructureHostCreate?(host: CachedDirectoryStructureHost): void;
@ -352,7 +329,7 @@ namespace ts {
/**
* Host to create watch with root files and options
*/
export interface WatchCompilerHostOfFilesAndCompilerOptions extends WatchCompilerHost {
export interface WatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram> extends WatchCompilerHost<T> {
/** root files to use to generate program */
rootFiles: string[];
@ -378,7 +355,7 @@ namespace ts {
/**
* Host to create watch with config file
*/
export interface WatchCompilerHostOfConfigFile extends WatchCompilerHost, ConfigFileDiagnosticsReporter {
export interface WatchCompilerHostOfConfigFile<T extends BuilderProgram> extends WatchCompilerHost<T>, ConfigFileDiagnosticsReporter {
/** Name of the config file to compile */
configFileName: string;
@ -396,7 +373,7 @@ namespace ts {
* Host to create watch with config file that is already parsed (from tsc)
*/
/*@internal*/
export interface WatchCompilerHostOfConfigFile extends WatchCompilerHost {
export interface WatchCompilerHostOfConfigFile<T extends BuilderProgram> extends WatchCompilerHost<T> {
rootFiles?: string[];
options?: CompilerOptions;
optionsToExtend?: CompilerOptions;
@ -429,33 +406,33 @@ namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
export function createWatchCompilerHost(rootFiles: string[], options: CompilerOptions, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions;
export function createWatchCompilerHost(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile;
export function createWatchCompilerHost(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions | WatchCompilerHostOfConfigFile {
export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
export function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> {
if (isArray(rootFilesOrConfigFileName)) {
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options, system, reportDiagnostic, reportWatchStatus);
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options, system, createProgram, reportDiagnostic, reportWatchStatus);
}
else {
return createWatchCompilerHostOfConfigFile(rootFilesOrConfigFileName, options, system, reportDiagnostic, reportWatchStatus);
return createWatchCompilerHostOfConfigFile(rootFilesOrConfigFileName, options, system, createProgram, reportDiagnostic, reportWatchStatus);
}
}
/**
* Creates the watch from the host for root files and compiler options
*/
export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions): WatchOfFilesAndCompilerOptions<Program>;
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T>): WatchOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for config file
*/
export function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile<Program>;
export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions & WatchCompilerHostOfConfigFile): WatchOfFilesAndCompilerOptions<Program> | WatchOfConfigFile<Program> {
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T> & WatchCompilerHostOfConfigFile<T>): WatchOfFilesAndCompilerOptions<T> | WatchOfConfigFile<T> {
interface HostFileInfo {
version: number;
sourceFile: SourceFile;
fileWatcher: FileWatcher;
}
let program: Program;
let builderProgram: T;
let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
let missingFilesMap: Map<FileWatcher>; // Map of file watchers for the missing files
let watchedWildcardDirectories: Map<WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
@ -470,7 +447,7 @@ namespace ts {
const currentDirectory = host.getCurrentDirectory();
const getCurrentDirectory = () => currentDirectory;
const readFile: (path: string, encoding?: string) => string | undefined = (path, encoding) => host.readFile(path, encoding);
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {} } = host;
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, createProgram } = host;
let { rootFiles: rootFileNames, options: compilerOptions, configFileSpecs, configFileWildCardDirectories } = host;
const cachedDirectoryStructureHost = configFileName && createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames);
@ -513,7 +490,7 @@ namespace ts {
getSourceFileByPath: getVersionedSourceFileByPath,
getDefaultLibLocation: host.getDefaultLibLocation && (() => host.getDefaultLibLocation()),
getDefaultLibFileName: options => host.getDefaultLibFileName(options),
writeFile: notImplemented,
writeFile,
getCurrentDirectory,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getCanonicalFileName,
@ -526,6 +503,7 @@ namespace ts {
realpath: host.realpath && (s => host.realpath(s)),
getEnvironmentVariable: host.getEnvironmentVariable ? (name => host.getEnvironmentVariable(name)) : (() => ""),
onReleaseOldSourceFile,
createHash: host.createHash && (data => host.createHash(data)),
// Members for ResolutionCacheHost
toPath,
getCompilationSettings: () => compilerOptions,
@ -563,16 +541,21 @@ namespace ts {
watchConfigFileWildCardDirectories();
return configFileName ?
{ getCurrentProgram, getProgram: synchronizeProgram } :
{ getCurrentProgram, getProgram: synchronizeProgram, updateRootFileNames };
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: synchronizeProgram } :
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: synchronizeProgram, updateRootFileNames };
function getCurrentProgram() {
return program;
function getCurrentBuilderProgram() {
return builderProgram;
}
function synchronizeProgram(): Program {
function getCurrentProgram() {
return builderProgram && builderProgram.getProgram();
}
function synchronizeProgram() {
writeLog(`Synchronizing program`);
const program = getCurrentProgram();
if (hasChangedCompilerOptions) {
newLine = updateNewLine();
if (program && changesAffectModuleResolution(program.getCompilerOptions(), compilerOptions)) {
@ -582,12 +565,8 @@ namespace ts {
// All resolutions are invalid if user provided resolutions
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution);
if (isProgramUptoDate(program, rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
return program;
}
if (host.beforeProgramCreate) {
host.beforeProgramCreate(compilerOptions);
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
return builderProgram;
}
// Compile the program
@ -596,11 +575,11 @@ namespace ts {
resolutionCache.startCachingPerDirectoryResolution();
compilerHost.hasInvalidatedResolution = hasInvalidatedResolution;
compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
program = createProgram(rootFileNames, compilerOptions, compilerHost, program);
builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram);
resolutionCache.finishCachingPerDirectoryResolution();
// Update watches
updateMissingFilePathsWatch(program, missingFilesMap || (missingFilesMap = createMap()), watchMissingFilePath);
updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = createMap()), watchMissingFilePath);
if (needsUpdateInTypeRootWatch) {
resolutionCache.updateTypeRootsWatch();
}
@ -620,10 +599,10 @@ namespace ts {
}
if (host.afterProgramCreate) {
host.afterProgramCreate(program);
host.afterProgramCreate(builderProgram);
}
reportWatchDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes);
return program;
return builderProgram;
}
function updateRootFileNames(files: string[]) {
@ -928,23 +907,30 @@ namespace ts {
flags
);
}
}
/**
* Creates the watch from the host for root files and compiler options
*/
export function createWatchBuilderProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions & BuilderProgramHost, createBuilderProgram: (newProgram: Program, host: BuilderProgramHost, oldProgram?: T) => T): WatchOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for config file
*/
export function createWatchBuilderProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile & BuilderProgramHost, createBuilderProgram: (newProgram: Program, host: BuilderProgramHost, oldProgram?: T) => T): WatchOfConfigFile<T>;
export function createWatchBuilderProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions & WatchCompilerHostOfConfigFile & BuilderProgramHost, createBuilderProgram: (newProgram: Program, host: BuilderProgramHost, oldProgram?: T) => T): WatchOfFilesAndCompilerOptions<T> | WatchOfConfigFile<T> {
const watch = createWatchProgram(host);
let builderProgram: T | undefined;
return {
getProgram: () => builderProgram = createBuilderProgram(watch.getProgram(), host, builderProgram),
getCurrentProgram: () => builderProgram = createBuilderProgram(watch.getCurrentProgram(), host, builderProgram),
updateRootFileNames: watch.updateRootFileNames && (fileNames => watch.updateRootFileNames(fileNames))
};
function ensureDirectoriesExist(directoryPath: string) {
if (directoryPath.length > getRootLength(directoryPath) && !host.directoryExists(directoryPath)) {
const parentDirectory = getDirectoryPath(directoryPath);
ensureDirectoriesExist(parentDirectory);
host.createDirectory(directoryPath);
}
}
function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, onError: (message: string) => void) {
try {
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
host.writeFile(fileName, text, writeByteOrderMark);
performance.mark("afterIOWrite");
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
}
catch (e) {
if (onError) {
onError(e.message);
}
}
}
}
}

View File

@ -910,12 +910,12 @@ namespace ts {
}
function verifyProgramWithoutConfigFile(system: System, rootFiles: string[], options: CompilerOptions) {
const program = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, system)).getCurrentProgram();
const program = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, system)).getCurrentProgram().getProgram();
verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options));
}
function verifyProgramWithConfigFile(system: System, configFileName: string) {
const program = createWatchProgram(createWatchCompilerHostOfConfigFile(configFileName, {}, system)).getCurrentProgram();
const program = createWatchProgram(createWatchCompilerHostOfConfigFile(configFileName, {}, system)).getCurrentProgram().getProgram();
const { fileNames, options } = parseConfigFileWithSystem(configFileName, {}, system, notImplemented);
verifyProgramIsUptoDate(program, fileNames, options);
}

View File

@ -25,13 +25,13 @@ namespace ts.tscWatch {
function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const compilerHost = ts.createWatchCompilerHostOfConfigFile(configFileName, {}, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const watch = ts.createWatchProgram(compilerHost);
return () => watch.getCurrentProgram();
const watch = createWatchProgram(compilerHost);
return () => watch.getCurrentProgram().getProgram();
}
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}) {
const watch = ts.createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, host));
return () => watch.getCurrentProgram();
const watch = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, host));
return () => watch.getCurrentProgram().getProgram();
}
function getEmittedLineForMultiFileOutput(file: FileOrFolder, host: WatchedSystem) {
@ -264,10 +264,10 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([configFile, libFile, file1, file2, file3]);
const watch = createWatchProgram(createWatchCompilerHostOfConfigFile(configFile.path, {}, host, notImplemented));
const watch = createWatchProgram(createWatchCompilerHostOfConfigFile(configFile.path, {}, host, /*createProgram*/ undefined, notImplemented));
checkProgramActualFiles(watch.getCurrentProgram(), [file1.path, libFile.path, file2.path]);
checkProgramRootFiles(watch.getCurrentProgram(), [file1.path, file2.path]);
checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file1.path, libFile.path, file2.path]);
checkProgramRootFiles(watch.getCurrentProgram().getProgram(), [file1.path, file2.path]);
checkWatchedFiles(host, [configFile.path, file1.path, file2.path, libFile.path]);
const configDir = getDirectoryPath(configFile.path);
checkWatchedDirectories(host, [configDir, combinePaths(configDir, projectSystem.nodeModulesAtTypes)], /*recursive*/ true);

View File

@ -2506,6 +2506,7 @@ declare namespace ts {
*/
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): (ResolvedTypeReferenceDirective | undefined)[];
getEnvironmentVariable?(name: string): string;
createHash?(data: string): string;
}
interface SourceMapRange extends TextRange {
source?: SourceMapSource;

View File

@ -2506,6 +2506,7 @@ declare namespace ts {
*/
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): (ResolvedTypeReferenceDirective | undefined)[];
getEnvironmentVariable?(name: string): string;
createHash?(data: string): string;
}
interface SourceMapRange extends TextRange {
source?: SourceMapSource;
@ -3960,20 +3961,30 @@ declare namespace ts {
* Create the builder to manage semantic diagnostics and cache them
*/
function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram): SemanticDiagnosticsBuilderProgram;
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram): EmitAndSemanticDiagnosticsBuilderProgram;
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram): BuilderProgram;
}
declare namespace ts {
type DiagnosticReporter = (diagnostic: Diagnostic) => void;
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string) => void;
interface WatchCompilerHost {
/** If provided, callback to invoke before each program creation */
beforeProgramCreate?(compilerOptions: CompilerOptions): void;
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T;
interface WatchCompilerHost<T extends BuilderProgram> {
/**
* Used to create the program when need for program creation or recreation detected
*/
createProgram: CreateProgram<T>;
/** If provided, callback to invoke after every new program creation */
afterProgramCreate?(program: Program): void;
afterProgramCreate?(program: T): void;
/** If provided, called with Diagnostic message that informs about change in watch status */
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void;
useCaseSensitiveFileNames(): boolean;
@ -3981,6 +3992,7 @@ declare namespace ts {
getCurrentDirectory(): string;
getDefaultLibFileName(options: CompilerOptions): string;
getDefaultLibLocation?(): string;
createHash?(data: string): string;
/**
* Use to check file presence for source files and
* if resolveModuleNames is not provided (complier is in charge of module resolution) then module files as well
@ -4019,7 +4031,7 @@ declare namespace ts {
/**
* Host to create watch with root files and options
*/
interface WatchCompilerHostOfFilesAndCompilerOptions extends WatchCompilerHost {
interface WatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram> extends WatchCompilerHost<T> {
/** root files to use to generate program */
rootFiles: string[];
/** Compiler options */
@ -4041,7 +4053,7 @@ declare namespace ts {
/**
* Host to create watch with config file
*/
interface WatchCompilerHostOfConfigFile extends WatchCompilerHost, ConfigFileDiagnosticsReporter {
interface WatchCompilerHostOfConfigFile<T extends BuilderProgram> extends WatchCompilerHost<T>, ConfigFileDiagnosticsReporter {
/** Name of the config file to compile */
configFileName: string;
/** Options to extend */
@ -4071,24 +4083,16 @@ declare namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
function createWatchCompilerHost(rootFiles: string[], options: CompilerOptions, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions;
function createWatchCompilerHost(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile;
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
/**
* Creates the watch from the host for root files and compiler options
*/
function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions): WatchOfFilesAndCompilerOptions<Program>;
function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T>): WatchOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for config file
*/
function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile<Program>;
/**
* Creates the watch from the host for root files and compiler options
*/
function createWatchBuilderProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions & BuilderProgramHost, createBuilderProgram: (newProgram: Program, host: BuilderProgramHost, oldProgram?: T) => T): WatchOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for config file
*/
function createWatchBuilderProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile & BuilderProgramHost, createBuilderProgram: (newProgram: Program, host: BuilderProgramHost, oldProgram?: T) => T): WatchOfConfigFile<T>;
function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
}
declare namespace ts {
function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine;