Update the emitting file, reporting errors part of the watch api

This commit is contained in:
Sheetal Nandi 2017-12-05 20:23:14 -08:00
parent c9a407e553
commit 14f66efcc5
8 changed files with 266 additions and 181 deletions

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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