mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-20 10:29:36 -06:00
Update the emitting file, reporting errors part of the watch api
This commit is contained in:
parent
c9a407e553
commit
14f66efcc5
@ -3000,8 +3000,4 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty
|
||||
|
||||
export function getBoundFunction<T extends Function>(method: T | undefined, methodOf: {}): T | undefined {
|
||||
return method && method.bind(methodOf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,17 +144,16 @@ namespace ts {
|
||||
enableStatistics(compilerOptions);
|
||||
|
||||
const program = createProgram(rootFileNames, compilerOptions, compilerHost);
|
||||
const exitStatus = compileProgram(program);
|
||||
|
||||
const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine));
|
||||
reportStatistics(program);
|
||||
return sys.exit(exitStatus);
|
||||
}
|
||||
|
||||
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost) {
|
||||
const compilerWithBuilderState = watchCompilerHost.afterProgramCreate;
|
||||
const compileUsingBuilder = watchCompilerHost.afterProgramCreate;
|
||||
watchCompilerHost.beforeProgramCreate = enableStatistics;
|
||||
watchCompilerHost.afterProgramCreate = (host, program) => {
|
||||
compilerWithBuilderState(host, program);
|
||||
watchCompilerHost.afterProgramCreate = program => {
|
||||
compileUsingBuilder(program);
|
||||
reportStatistics(program);
|
||||
};
|
||||
}
|
||||
@ -175,40 +174,6 @@ namespace ts {
|
||||
createWatch(watchCompilerHost);
|
||||
}
|
||||
|
||||
function compileProgram(program: Program): ExitStatus {
|
||||
let diagnostics: Diagnostic[];
|
||||
|
||||
// First get and report any syntactic errors.
|
||||
diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
diagnostics = program.getSemanticDiagnostics().slice();
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic);
|
||||
writeFileAndEmittedFileList(sys, program, emittedFiles);
|
||||
if (emitSkipped && diagnostics.length > 0) {
|
||||
// If the emitter didn't emit anything, then pass that value along.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
else if (diagnostics.length > 0) {
|
||||
// The emitter emitted something, inform the caller if that happened in the presence
|
||||
// of diagnostics or not.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsGenerated;
|
||||
}
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
function enableStatistics(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
performance.enable();
|
||||
|
||||
@ -78,30 +78,152 @@ namespace ts {
|
||||
return configParseResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Program structure needed to emit the files and report diagnostics
|
||||
*/
|
||||
export interface ProgramToEmitFilesAndReportErrors {
|
||||
getCurrentDirectory(): string;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
getSyntacticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getOptionsDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
emit(): EmitResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void) {
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
let reportSemanticDiagnostics = false;
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
addRange(diagnostics, program.getOptionsDiagnostics());
|
||||
addRange(diagnostics, program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
reportSemanticDiagnostics = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
addRange(diagnostics, program.getSemanticDiagnostics());
|
||||
}
|
||||
|
||||
sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic);
|
||||
if (writeFileName) {
|
||||
const currentDir = program.getCurrentDirectory();
|
||||
forEach(emittedFiles, file => {
|
||||
const filepath = getNormalizedAbsolutePath(file, currentDir);
|
||||
writeFileName(`TSFILE: ${filepath}`);
|
||||
});
|
||||
|
||||
if (program.getCompilerOptions().listFiles) {
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
writeFileName(file.fileName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (emitSkipped && diagnostics.length > 0) {
|
||||
// If the emitter didn't emit anything, then pass that value along.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
else if (diagnostics.length > 0) {
|
||||
// The emitter emitted something, inform the caller if that happened in the presence
|
||||
// of diagnostics or not.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsGenerated;
|
||||
}
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the function that emits files and reports errors when called with program
|
||||
*/
|
||||
function createEmitFilesAndReportErrorsWithBuilderUsingSystem(system: System, reportDiagnostic: DiagnosticReporter) {
|
||||
const emitErrorsAndReportErrorsWithBuilder = createEmitFilesAndReportErrorsWithBuilder({
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
createHash: system.createHash && (s => system.createHash(s)),
|
||||
writeFile,
|
||||
reportDiagnostic,
|
||||
writeFileName: s => system.write(s + system.newLine)
|
||||
});
|
||||
let host: CachedDirectoryStructureHost | undefined;
|
||||
return {
|
||||
emitFilesAndReportError: (program: Program) => emitErrorsAndReportErrorsWithBuilder(program),
|
||||
setHost: (cachedDirectoryStructureHost: CachedDirectoryStructureHost) => host = cachedDirectoryStructureHost
|
||||
};
|
||||
|
||||
function getHost() {
|
||||
return host || system;
|
||||
}
|
||||
|
||||
function ensureDirectoriesExist(directoryPath: string) {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !getHost().directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
getHost().createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, text: string, writeByteOrderMark: boolean, onError: (message: string) => void) {
|
||||
try {
|
||||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
getHost().writeFile(fileName, text, writeByteOrderMark);
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
/**
|
||||
* 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 | undefined): WatchCompilerHost {
|
||||
return {
|
||||
function createWatchCompilerHost(system = sys, reportDiagnostic: DiagnosticReporter): WatchCompilerHost {
|
||||
const { emitFilesAndReportError, setHost } = createEmitFilesAndReportErrorsWithBuilderUsingSystem(system, reportDiagnostic);
|
||||
const host: WatchCompilerHost = {
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getNewLine: () => system.newLine,
|
||||
getCurrentDirectory: getBoundFunction(system.getCurrentDirectory, system),
|
||||
getCurrentDirectory: () => system.getCurrentDirectory(),
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
fileExists: getBoundFunction(system.fileExists, system),
|
||||
readFile: getBoundFunction(system.readFile, system),
|
||||
directoryExists: getBoundFunction(system.directoryExists, system),
|
||||
getDirectories: getBoundFunction(system.getDirectories, system),
|
||||
readDirectory: getBoundFunction(system.readDirectory, system),
|
||||
realpath: getBoundFunction(system.realpath, system),
|
||||
watchFile: getBoundFunction(system.watchFile, system),
|
||||
watchDirectory: getBoundFunction(system.watchDirectory, system),
|
||||
setTimeout: getBoundFunction(system.setTimeout, system),
|
||||
clearTimeout: getBoundFunction(system.clearTimeout, system),
|
||||
trace: getBoundFunction(system.write, system),
|
||||
fileExists: path => system.fileExists(path),
|
||||
readFile: (path, encoding) => system.readFile(path, encoding),
|
||||
directoryExists: path => system.directoryExists(path),
|
||||
getDirectories: path => system.getDirectories(path),
|
||||
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
|
||||
realpath: system.realpath && (path => system.realpath(path)),
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout(timeoutId)) : noop,
|
||||
trace: s => system.write(s),
|
||||
onWatchStatusChange,
|
||||
afterProgramCreate: createProgramCompilerWithBuilderState(system, reportDiagnostic)
|
||||
createDirectory: path => system.createDirectory(path),
|
||||
writeFile: (path, data, writeByteOrderMark) => system.writeFile(path, data, writeByteOrderMark),
|
||||
onCachedDirectoryStructureHostCreate: host => setHost(host),
|
||||
afterProgramCreate: emitFilesAndReportError,
|
||||
};
|
||||
return host;
|
||||
|
||||
function getDefaultLibLocation() {
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
@ -140,7 +262,7 @@ 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 | undefined): WatchCompilerHostOfFilesAndCompilerOptions {
|
||||
const host = createWatchCompilerHost(system, reportDiagnostic) as WatchCompilerHostOfFilesAndCompilerOptions;
|
||||
const host = createWatchCompilerHost(system, reportDiagnostic || createDiagnosticReporter(system)) as WatchCompilerHostOfFilesAndCompilerOptions;
|
||||
host.rootFiles = rootFiles;
|
||||
host.options = options;
|
||||
return host;
|
||||
@ -150,99 +272,75 @@ namespace ts {
|
||||
namespace ts {
|
||||
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
|
||||
|
||||
/**
|
||||
* Writes emitted files, source files depending on options
|
||||
*/
|
||||
/*@internal*/
|
||||
export function writeFileAndEmittedFileList(system: System, program: Program, emittedFiles: string[]) {
|
||||
const currentDir = system.getCurrentDirectory();
|
||||
forEach(emittedFiles, file => {
|
||||
const filepath = getNormalizedAbsolutePath(file, currentDir);
|
||||
system.write(`TSFILE: ${filepath}${system.newLine}`);
|
||||
});
|
||||
interface BuilderProgram extends ProgramToEmitFilesAndReportErrors {
|
||||
updateProgram(program: Program): void;
|
||||
}
|
||||
|
||||
if (program.getCompilerOptions().listFiles) {
|
||||
forEach(program.getSourceFiles(), file => {
|
||||
system.write(file.fileName + system.newLine);
|
||||
});
|
||||
function createBuilderProgram(host: BuilderEmitHost): BuilderProgram {
|
||||
const builder = createEmitAndSemanticDiagnosticsBuilder({
|
||||
getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames()),
|
||||
computeHash: host.createHash ? host.createHash : identity
|
||||
});
|
||||
let program: Program;
|
||||
return {
|
||||
getCurrentDirectory: () => program.getCurrentDirectory(),
|
||||
getCompilerOptions: () => program.getCompilerOptions(),
|
||||
getSourceFiles: () => program.getSourceFiles(),
|
||||
getSyntacticDiagnostics: () => program.getSyntacticDiagnostics(),
|
||||
getOptionsDiagnostics: () => program.getOptionsDiagnostics(),
|
||||
getGlobalDiagnostics: () => program.getGlobalDiagnostics(),
|
||||
getSemanticDiagnostics: () => builder.getSemanticDiagnostics(program),
|
||||
emit,
|
||||
updateProgram
|
||||
};
|
||||
|
||||
function updateProgram(p: Program) {
|
||||
program = p;
|
||||
builder.updateProgram(p);
|
||||
}
|
||||
|
||||
function emit(): EmitResult {
|
||||
// Emit and report any errors we ran into.
|
||||
let sourceMaps: SourceMapData[];
|
||||
let emitSkipped: boolean;
|
||||
let diagnostics: Diagnostic[];
|
||||
let emittedFiles: string[];
|
||||
|
||||
let affectedEmitResult: AffectedFileResult<EmitResult>;
|
||||
while (affectedEmitResult = builder.emitNextAffectedFile(program, host.writeFile)) {
|
||||
emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped;
|
||||
diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics);
|
||||
emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles);
|
||||
sourceMaps = addRange(sourceMaps, affectedEmitResult.result.sourceMaps);
|
||||
}
|
||||
return {
|
||||
emitSkipped,
|
||||
diagnostics,
|
||||
emittedFiles,
|
||||
sourceMaps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the function that compiles the program by maintaining the builder for the program and reports the errors and emits files
|
||||
* Host needed to emit files and report errors using builder
|
||||
*/
|
||||
export function createProgramCompilerWithBuilderState(system = sys, reportDiagnostic?: DiagnosticReporter) {
|
||||
reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system);
|
||||
const builder = createEmitAndSemanticDiagnosticsBuilder({
|
||||
getCanonicalFileName: createGetCanonicalFileName(system.useCaseSensitiveFileNames),
|
||||
computeHash: getBoundFunction(system.createHash, system) || identity
|
||||
});
|
||||
export interface BuilderEmitHost {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
createHash?: (data: string) => string;
|
||||
writeFile: WriteFileCallback;
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
writeFileName?: (s: string) => void;
|
||||
}
|
||||
|
||||
return (host: DirectoryStructureHost, program: Program) => {
|
||||
builder.updateProgram(program);
|
||||
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getSyntacticDiagnostics().slice();
|
||||
let reportSemanticDiagnostics = false;
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === 0) {
|
||||
addRange(diagnostics, program.getOptionsDiagnostics());
|
||||
addRange(diagnostics, program.getGlobalDiagnostics());
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
reportSemanticDiagnostics = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const emittedFiles: string[] = program.getCompilerOptions().listEmittedFiles ? [] : undefined;
|
||||
let sourceMaps: SourceMapData[];
|
||||
let emitSkipped: boolean;
|
||||
|
||||
let affectedEmitResult: AffectedFileResult<EmitResult>;
|
||||
while (affectedEmitResult = builder.emitNextAffectedFile(program, writeFile)) {
|
||||
emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped;
|
||||
addRange(diagnostics, affectedEmitResult.result.diagnostics);
|
||||
sourceMaps = addRange(sourceMaps, affectedEmitResult.result.sourceMaps);
|
||||
}
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
addRange(diagnostics, builder.getSemanticDiagnostics(program));
|
||||
}
|
||||
|
||||
sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic);
|
||||
writeFileAndEmittedFileList(system, program, emittedFiles);
|
||||
|
||||
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");
|
||||
|
||||
if (emittedFiles) {
|
||||
emittedFiles.push(fileName);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates the function that reports the program errors and emit files every time it is called with argument as program
|
||||
*/
|
||||
export function createEmitFilesAndReportErrorsWithBuilder(host: BuilderEmitHost) {
|
||||
const builderProgram = createBuilderProgram(host);
|
||||
return (program: Program) => {
|
||||
builderProgram.updateProgram(program);
|
||||
emitFilesAndReportErrors(builderProgram, host.reportDiagnostic, host.writeFileName);
|
||||
};
|
||||
}
|
||||
|
||||
@ -250,7 +348,7 @@ namespace ts {
|
||||
/** If provided, callback to invoke before each program creation */
|
||||
beforeProgramCreate?(compilerOptions: CompilerOptions): void;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(host: DirectoryStructureHost, program: Program): void;
|
||||
afterProgramCreate?(program: Program): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void;
|
||||
|
||||
@ -297,6 +395,14 @@ namespace ts {
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
|
||||
/** Internal interface used to wire emit through same host */
|
||||
/*@internal*/
|
||||
export interface WatchCompilerHost {
|
||||
createDirectory?(path: string): void;
|
||||
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
onCachedDirectoryStructureHostCreate?(host: CachedDirectoryStructureHost): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
*/
|
||||
@ -315,12 +421,12 @@ namespace ts {
|
||||
/**
|
||||
* Reports the diagnostics in reading/writing or parsing of the config file
|
||||
*/
|
||||
onConfigFileDiagnostic(diagnostic: Diagnostic): void;
|
||||
onConfigFileDiagnostic: DiagnosticReporter;
|
||||
|
||||
/**
|
||||
* Reports unrecoverable error when parsing config file
|
||||
*/
|
||||
onUnRecoverableConfigFileDiagnostic(diagnostic: Diagnostic): void;
|
||||
onUnRecoverableConfigFileDiagnostic: DiagnosticReporter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,7 +451,6 @@ namespace ts {
|
||||
*/
|
||||
/*@internal*/
|
||||
export interface WatchCompilerHostOfConfigFile extends WatchCompilerHost {
|
||||
cachedDirectoryStructureHost?: CachedDirectoryStructureHost;
|
||||
rootFiles?: string[];
|
||||
options?: CompilerOptions;
|
||||
optionsToExtend?: CompilerOptions;
|
||||
@ -418,23 +523,23 @@ namespace ts {
|
||||
const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames();
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const getCurrentDirectory = () => currentDirectory;
|
||||
const onConfigFileDiagnostic = getBoundFunction(host.onConfigFileDiagnostic, host);
|
||||
const readFile = getBoundFunction(host.readFile, host);
|
||||
const readFile: (path: string, encoding?: string) => string | undefined = (path, encoding) => host.readFile(path, encoding);
|
||||
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {} } = host;
|
||||
const beforeProgramCreate = getBoundFunction(host.beforeProgramCreate, host) || noop;
|
||||
const afterProgramCreate = getBoundFunction(host.afterProgramCreate, host) || noop;
|
||||
let { rootFiles: rootFileNames, options: compilerOptions, configFileSpecs, configFileWildCardDirectories } = host;
|
||||
|
||||
const cachedDirectoryStructureHost = configFileName && createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames);
|
||||
if (cachedDirectoryStructureHost && host.onCachedDirectoryStructureHostCreate) {
|
||||
host.onCachedDirectoryStructureHostCreate(cachedDirectoryStructureHost);
|
||||
}
|
||||
const directoryStructureHost: DirectoryStructureHost = cachedDirectoryStructureHost || host;
|
||||
const parseConfigFileHost: ParseConfigFileHost = {
|
||||
useCaseSensitiveFileNames,
|
||||
readDirectory: getBoundFunction(directoryStructureHost.readDirectory, directoryStructureHost),
|
||||
fileExists: getBoundFunction(directoryStructureHost.fileExists, directoryStructureHost),
|
||||
readDirectory: (path, extensions, exclude, include, depth) => directoryStructureHost.readDirectory(path, extensions, exclude, include, depth),
|
||||
fileExists: path => host.fileExists(path),
|
||||
readFile,
|
||||
getCurrentDirectory,
|
||||
onConfigFileDiagnostic,
|
||||
onUnRecoverableConfigFileDiagnostic: getBoundFunction(host.onUnRecoverableConfigFileDiagnostic, host)
|
||||
onConfigFileDiagnostic: host.onConfigFileDiagnostic,
|
||||
onUnRecoverableConfigFileDiagnostic: host.onUnRecoverableConfigFileDiagnostic
|
||||
};
|
||||
|
||||
// From tsc we want to get already parsed result and hence check for rootFileNames
|
||||
@ -460,8 +565,8 @@ namespace ts {
|
||||
// Members for CompilerHost
|
||||
getSourceFile: (fileName, languageVersion, onError?, shouldCreateNewSourceFile?) => getVersionedSourceFileByPath(fileName, toPath(fileName), languageVersion, onError, shouldCreateNewSourceFile),
|
||||
getSourceFileByPath: getVersionedSourceFileByPath,
|
||||
getDefaultLibLocation: getBoundFunction(host.getDefaultLibLocation, host),
|
||||
getDefaultLibFileName: getBoundFunction(host.getDefaultLibFileName, host),
|
||||
getDefaultLibLocation: host.getDefaultLibLocation && (() => host.getDefaultLibLocation()),
|
||||
getDefaultLibFileName: options => host.getDefaultLibFileName(options),
|
||||
writeFile: notImplemented,
|
||||
getCurrentDirectory,
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
@ -470,9 +575,9 @@ namespace ts {
|
||||
fileExists,
|
||||
readFile,
|
||||
trace,
|
||||
directoryExists: getBoundFunction(directoryStructureHost.directoryExists, directoryStructureHost),
|
||||
getDirectories: getBoundFunction(directoryStructureHost.getDirectories, directoryStructureHost),
|
||||
realpath: getBoundFunction(host.realpath, host),
|
||||
directoryExists: directoryStructureHost.directoryExists && (path => directoryStructureHost.directoryExists(path)),
|
||||
getDirectories: directoryStructureHost.getDirectories && (path => directoryStructureHost.getDirectories(path)),
|
||||
realpath: host.realpath && (s => host.realpath(s)),
|
||||
onReleaseOldSourceFile,
|
||||
// Members for ResolutionCacheHost
|
||||
toPath,
|
||||
@ -495,8 +600,8 @@ namespace ts {
|
||||
);
|
||||
// Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names
|
||||
compilerHost.resolveModuleNames = host.resolveModuleNames ?
|
||||
host.resolveModuleNames.bind(host) :
|
||||
resolutionCache.resolveModuleNames.bind(resolutionCache);
|
||||
((moduleNames, containingFile, reusedNames) => host.resolveModuleNames(moduleNames, containingFile, reusedNames)) :
|
||||
((moduleNames, containingFile, reusedNames) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames));
|
||||
compilerHost.resolveTypeReferenceDirectives = resolutionCache.resolveTypeReferenceDirectives.bind(resolutionCache);
|
||||
|
||||
reportWatchDiagnostic(Diagnostics.Starting_compilation_in_watch_mode);
|
||||
@ -524,7 +629,9 @@ namespace ts {
|
||||
return program;
|
||||
}
|
||||
|
||||
beforeProgramCreate(compilerOptions);
|
||||
if (host.beforeProgramCreate) {
|
||||
host.beforeProgramCreate(compilerOptions);
|
||||
}
|
||||
|
||||
// Compile the program
|
||||
const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !program;
|
||||
@ -555,7 +662,9 @@ namespace ts {
|
||||
missingFilePathsRequestedForRelease = undefined;
|
||||
}
|
||||
|
||||
afterProgramCreate(directoryStructureHost, program);
|
||||
if (host.afterProgramCreate) {
|
||||
host.afterProgramCreate(program);
|
||||
}
|
||||
reportWatchDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes);
|
||||
return program;
|
||||
}
|
||||
@ -722,7 +831,7 @@ namespace ts {
|
||||
function reloadFileNamesFromConfigFile() {
|
||||
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, parseConfigFileHost);
|
||||
if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) {
|
||||
onConfigFileDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
host.onConfigFileDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
}
|
||||
rootFileNames = result.fileNames;
|
||||
|
||||
|
||||
@ -49,12 +49,12 @@ namespace ts {
|
||||
return {
|
||||
useCaseSensitiveFileNames,
|
||||
fileExists,
|
||||
readFile: getBoundFunction(host.readFile, host),
|
||||
readFile: (path, encoding) => host.readFile(path, encoding),
|
||||
directoryExists: host.directoryExists && directoryExists,
|
||||
getDirectories,
|
||||
readDirectory,
|
||||
createDirectory,
|
||||
writeFile,
|
||||
createDirectory: host.createDirectory && createDirectory,
|
||||
writeFile: host.writeFile && writeFile,
|
||||
addOrDeleteFileOrDirectory,
|
||||
addOrDeleteFile,
|
||||
clearCache
|
||||
|
||||
@ -1765,11 +1765,11 @@ namespace ts.server {
|
||||
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
|
||||
}
|
||||
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) {
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) {
|
||||
return this.getOrCreateScriptInfoWorker(fileName, this.currentDirectory, openedByClient, fileContent, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
|
||||
}
|
||||
|
||||
private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) {
|
||||
private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) {
|
||||
Debug.assert(fileContent === undefined || openedByClient, "ScriptInfo needs to be opened by client to be able to set its user defined content");
|
||||
const path = normalizedPathToPath(fileName, currentDirectory, this.toCanonicalFileName);
|
||||
let info = this.getScriptInfoForPath(path);
|
||||
|
||||
@ -201,6 +201,9 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
readonly currentDirectory: string;
|
||||
|
||||
/*@internal*/
|
||||
public directoryStructureHost: DirectoryStructureHost;
|
||||
|
||||
/*@internal*/
|
||||
constructor(
|
||||
/*@internal*/readonly projectName: string,
|
||||
@ -211,8 +214,9 @@ namespace ts.server {
|
||||
languageServiceEnabled: boolean,
|
||||
private compilerOptions: CompilerOptions,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
/*@internal*/public directoryStructureHost: DirectoryStructureHost,
|
||||
directoryStructureHost: DirectoryStructureHost,
|
||||
currentDirectory: string | undefined) {
|
||||
this.directoryStructureHost = directoryStructureHost;
|
||||
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || "");
|
||||
|
||||
this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds);
|
||||
|
||||
@ -7270,7 +7270,6 @@ declare namespace ts.server {
|
||||
private documentRegistry;
|
||||
private compilerOptions;
|
||||
compileOnSaveEnabled: boolean;
|
||||
directoryStructureHost: DirectoryStructureHost;
|
||||
private rootFiles;
|
||||
private rootFilesMap;
|
||||
private program;
|
||||
@ -7741,7 +7740,9 @@ declare namespace ts.server {
|
||||
getScriptInfo(uncheckedFileName: string): ScriptInfo;
|
||||
private watchClosedScriptInfo(info);
|
||||
private stopWatchingScriptInfo(info);
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost): ScriptInfo;
|
||||
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: {
|
||||
fileExists(path: string): boolean;
|
||||
}): ScriptInfo;
|
||||
private getOrCreateScriptInfoWorker(fileName, currentDirectory, openedByClient, fileContent?, scriptKind?, hasMixedContent?, hostToQueryFileExistsOn?);
|
||||
/**
|
||||
* This gets the script info for the normalized path. If the path is not rooted disk path then the open script info with project root context is preferred
|
||||
|
||||
22
tests/baselines/reference/api/typescript.d.ts
vendored
22
tests/baselines/reference/api/typescript.d.ts
vendored
@ -3811,14 +3811,24 @@ declare namespace ts {
|
||||
declare namespace ts {
|
||||
type DiagnosticReporter = (diagnostic: Diagnostic) => void;
|
||||
/**
|
||||
* Creates the function that compiles the program by maintaining the builder for the program and reports the errors and emits files
|
||||
* Host needed to emit files and report errors using builder
|
||||
*/
|
||||
function createProgramCompilerWithBuilderState(system?: System, reportDiagnostic?: DiagnosticReporter): (host: DirectoryStructureHost, program: Program) => void;
|
||||
interface BuilderEmitHost {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
createHash?: (data: string) => string;
|
||||
writeFile: WriteFileCallback;
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
writeFileName?: (s: string) => void;
|
||||
}
|
||||
/**
|
||||
* Creates the function that reports the program errors and emit files every time it is called with argument as program
|
||||
*/
|
||||
function createEmitFilesAndReportErrorsWithBuilder(host: BuilderEmitHost): (program: Program) => void;
|
||||
interface WatchCompilerHost {
|
||||
/** If provided, callback to invoke before each program creation */
|
||||
beforeProgramCreate?(compilerOptions: CompilerOptions): void;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(host: DirectoryStructureHost, program: Program): void;
|
||||
afterProgramCreate?(program: Program): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
@ -3852,7 +3862,7 @@ declare namespace ts {
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together*/
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
@ -3873,11 +3883,11 @@ declare namespace ts {
|
||||
/**
|
||||
* Reports the diagnostics in reading/writing or parsing of the config file
|
||||
*/
|
||||
onConfigFileDiagnostic(diagnostic: Diagnostic): void;
|
||||
onConfigFileDiagnostic: DiagnosticReporter;
|
||||
/**
|
||||
* Reports unrecoverable error when parsing config file
|
||||
*/
|
||||
onUnRecoverableConfigFileDiagnostic(diagnostic: Diagnostic): void;
|
||||
onUnRecoverableConfigFileDiagnostic: DiagnosticReporter;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with config file
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user