TypeScript/src/compiler/watchedProgram.ts

674 lines
32 KiB
TypeScript

/// <reference path="program.ts" />
/// <reference path="builder.ts" />
/// <reference path="resolutionCache.ts"/>
namespace ts {
export type DiagnosticReporter = (diagnostic: Diagnostic) => void;
export type ParseConfigFile = (configFileName: string, optionsToExtend: CompilerOptions, system: PartialSystem, reportDiagnostic: DiagnosticReporter, reportWatchDiagnostic: DiagnosticReporter) => ParsedCommandLine;
export interface WatchingSystemHost {
// FS system to use
system: System;
// parse config file
parseConfigFile: ParseConfigFile;
// Reporting errors
reportDiagnostic: DiagnosticReporter;
reportWatchDiagnostic: DiagnosticReporter;
// Callbacks to do custom action before creating program and after creating program
beforeCompile(compilerOptions: CompilerOptions): void;
afterCompile(host: PartialSystem, program: Program, builder: Builder): void;
}
const defaultFormatDiagnosticsHost: FormatDiagnosticsHost = sys ? {
getCurrentDirectory: () => sys.getCurrentDirectory(),
getNewLine: () => sys.newLine,
getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames)
} : undefined;
export function createDiagnosticReporter(system = sys, worker = reportDiagnosticSimply, formatDiagnosticsHost?: FormatDiagnosticsHost): DiagnosticReporter {
return diagnostic => worker(diagnostic, getFormatDiagnosticsHost(), system);
function getFormatDiagnosticsHost() {
return formatDiagnosticsHost || (formatDiagnosticsHost = system === sys ? defaultFormatDiagnosticsHost : {
getCurrentDirectory: () => system.getCurrentDirectory(),
getNewLine: () => system.newLine,
getCanonicalFileName: createGetCanonicalFileName(system.useCaseSensitiveFileNames),
});
}
}
export function createWatchDiagnosticReporter(system = sys): DiagnosticReporter {
return diagnostic => {
let output = new Date().toLocaleTimeString() + " - ";
output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${system.newLine + system.newLine + system.newLine}`;
system.write(output);
};
}
export function reportDiagnostics(diagnostics: Diagnostic[], reportDiagnostic: DiagnosticReporter): void {
for (const diagnostic of diagnostics) {
reportDiagnostic(diagnostic);
}
}
export function reportDiagnosticSimply(diagnostic: Diagnostic, host: FormatDiagnosticsHost, system: System): void {
system.write(ts.formatDiagnostic(diagnostic, host));
}
export function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost, system: System): void {
system.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine());
}
export function parseConfigFile(configFileName: string, optionsToExtend: CompilerOptions, system: PartialSystem, reportDiagnostic: DiagnosticReporter, reportWatchDiagnostic: DiagnosticReporter): ParsedCommandLine {
let configFileText: string;
try {
configFileText = system.readFile(configFileName);
}
catch (e) {
const error = createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, configFileName, e.message);
reportWatchDiagnostic(error);
system.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
if (!configFileText) {
const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName);
reportDiagnostics([error], reportDiagnostic);
system.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const result = parseJsonText(configFileName, configFileText);
reportDiagnostics(result.parseDiagnostics, reportDiagnostic);
const cwd = system.getCurrentDirectory();
const configParseResult = parseJsonSourceFileConfigFileContent(result, system, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
reportDiagnostics(configParseResult.errors, reportDiagnostic);
return configParseResult;
}
function reportEmittedFiles(files: string[], system: PartialSystem): void {
if (!files || files.length === 0) {
return;
}
const currentDir = system.getCurrentDirectory();
for (const file of files) {
const filepath = getNormalizedAbsolutePath(file, currentDir);
system.write(`TSFILE: ${filepath}${system.newLine}`);
}
}
export function handleEmitOutputAndReportErrors(system: PartialSystem, program: Program,
emittedFiles: string[], emitSkipped: boolean,
diagnostics: Diagnostic[], reportDiagnostic: DiagnosticReporter
): ExitStatus {
reportDiagnostics(sortAndDeduplicateDiagnostics(diagnostics), reportDiagnostic);
reportEmittedFiles(emittedFiles, system);
if (program.getCompilerOptions().listFiles) {
forEach(program.getSourceFiles(), file => {
system.write(file.fileName + system.newLine);
});
}
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;
}
export function createWatchingSystemHost(pretty?: DiagnosticStyle, system = sys,
parseConfigFile?: ParseConfigFile, reportDiagnostic?: DiagnosticReporter,
reportWatchDiagnostic?: DiagnosticReporter
): WatchingSystemHost {
reportDiagnostic = reportDiagnostic || createDiagnosticReporter(system, pretty ? reportDiagnosticWithColorAndContext : reportDiagnosticSimply);
reportWatchDiagnostic = reportWatchDiagnostic || createWatchDiagnosticReporter(system);
parseConfigFile = parseConfigFile || ts.parseConfigFile;
return {
system,
parseConfigFile,
reportDiagnostic,
reportWatchDiagnostic,
beforeCompile: noop,
afterCompile: compileWatchedProgram,
};
function compileWatchedProgram(host: PartialSystem, program: Program, builder: Builder) {
// First get and report any syntactic errors.
let diagnostics = program.getSyntacticDiagnostics();
let reportSemanticDiagnostics = false;
// 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) {
reportSemanticDiagnostics = true;
}
}
// Emit and report any errors we ran into.
const emittedFiles: string[] = program.getCompilerOptions().listEmittedFiles ? [] : undefined;
let sourceMaps: SourceMapData[];
let emitSkipped: boolean;
const result = builder.emitChangedFiles(program);
if (result.length === 0) {
emitSkipped = true;
}
else {
for (const emitOutput of result) {
if (emitOutput.emitSkipped) {
emitSkipped = true;
}
diagnostics = concatenate(diagnostics, emitOutput.diagnostics);
sourceMaps = concatenate(sourceMaps, emitOutput.sourceMaps);
writeOutputFiles(emitOutput.outputFiles);
}
}
if (reportSemanticDiagnostics) {
diagnostics = diagnostics.concat(builder.getSemanticDiagnostics(program));
}
return handleEmitOutputAndReportErrors(host, program, emittedFiles, emitSkipped,
diagnostics, reportDiagnostic);
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, data: string, writeByteOrderMark: boolean) {
try {
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
host.writeFile(fileName, data, writeByteOrderMark);
performance.mark("afterIOWrite");
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
}
catch (e) {
return createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, e);
}
}
function writeOutputFiles(outputFiles: OutputFile[]) {
if (outputFiles) {
for (const outputFile of outputFiles) {
const error = writeFile(outputFile.name, outputFile.text, outputFile.writeByteOrderMark);
if (error) {
diagnostics.push(error);
}
if (emittedFiles) {
emittedFiles.push(outputFile.name);
}
}
}
}
}
}
export function createWatchModeWithConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions = {}, watchingHost?: WatchingSystemHost) {
return createWatchMode(configParseResult.fileNames, configParseResult.options, watchingHost, configParseResult.options.configFilePath, configParseResult.configFileSpecs, configParseResult.wildcardDirectories, optionsToExtend);
}
export function createWatchModeWithoutConfigFile(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost) {
return createWatchMode(rootFileNames, compilerOptions, watchingHost);
}
interface HostFileInfo {
version: number;
sourceFile: SourceFile;
fileWatcher: FileWatcher;
}
function createWatchMode(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost, configFileName?: string, configFileSpecs?: ConfigFileSpecs, configFileWildCardDirectories?: MapLike<WatchDirectoryFlags>, optionsToExtendForConfigFile?: CompilerOptions) {
let program: Program;
let needsReload: boolean; // true if the config file changed and needs to reload it from the disk
let missingFilesMap: Map<FileWatcher>; // Map of file watchers for the missing files
let configFileWatcher: FileWatcher; // watcher for the config file
let watchedWildcardDirectories: Map<WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
let timerToUpdateProgram: any; // timer callback to recompile the program
const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations
let changedAutomaticTypeDirectiveNames = false; // True if the automatic type directives have changed
const loggingEnabled = compilerOptions.diagnostics || compilerOptions.extendedDiagnostics;
const writeLog: (s: string) => void = loggingEnabled ? s => system.write(s) : noop;
const watchFile = loggingEnabled ? ts.addFileWatcherWithLogging : ts.addFileWatcher;
const watchFilePath = loggingEnabled ? ts.addFilePathWatcherWithLogging : ts.addFilePathWatcher;
const watchDirectoryWorker = loggingEnabled ? ts.addDirectoryWatcherWithLogging : ts.addDirectoryWatcher;
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
const partialSystem = configFileName ? createCachedPartialSystem(system) : system;
if (configFileName) {
configFileWatcher = watchFile(system, configFileName, scheduleProgramReload, writeLog);
}
const getCurrentDirectory = memoize(() => partialSystem.getCurrentDirectory());
const realpath = system.realpath && ((path: string) => system.realpath(path));
const getCachedPartialSystem = configFileName && (() => partialSystem as CachedPartialSystem);
const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames);
let newLine = getNewLineCharacter(compilerOptions, system);
const compilerHost: CompilerHost & ResolutionCacheHost = {
// Members for CompilerHost
getSourceFile: getVersionedSourceFile,
getSourceFileByPath: getVersionedSourceFileByPath,
getDefaultLibLocation,
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
writeFile: (_fileName, _data, _writeByteOrderMark, _onError?, _sourceFiles?) => { },
getCurrentDirectory,
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
getCanonicalFileName,
getNewLine: () => newLine,
fileExists,
readFile,
trace,
directoryExists,
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
getDirectories,
realpath,
resolveTypeReferenceDirectives,
resolveModuleNames,
onReleaseOldSourceFile,
hasChangedAutomaticTypeDirectiveNames,
// Members for ResolutionCacheHost
toPath,
getCompilationSettings: () => compilerOptions,
watchDirectoryOfFailedLookupLocation: watchDirectory,
watchTypeRootsDirectory: watchDirectory,
getCachedPartialSystem,
onInvalidatedResolution: scheduleProgramUpdate,
onChangedAutomaticTypeDirectiveNames,
writeLog
};
// Cache for the module resolution
const resolutionCache = createResolutionCache(compilerHost);
resolutionCache.setRootDirectory(configFileName ?
getDirectoryPath(getNormalizedAbsolutePath(configFileName, getCurrentDirectory())) :
getCurrentDirectory()
);
// There is no extra check needed since we can just rely on the program to decide emit
const builder = createBuilder(getCanonicalFileName, getFileEmitOutput, computeHash, _sourceFile => true);
synchronizeProgram();
// Update the wild card directory watch
watchConfigFileWildCardDirectories();
return () => program;
function synchronizeProgram() {
writeLog(`Synchronizing program`);
if (hasChangedCompilerOptions) {
newLine = getNewLineCharacter(compilerOptions, system);
}
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution();
if (isProgramUptoDate(program, rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
return;
}
if (hasChangedCompilerOptions && changesAffectModuleResolution(program && program.getCompilerOptions(), compilerOptions)) {
resolutionCache.clear();
}
const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !program;
hasChangedCompilerOptions = false;
beforeCompile(compilerOptions);
// Compile the program
resolutionCache.startCachingPerDirectoryResolution();
compilerHost.hasInvalidatedResolution = hasInvalidatedResolution;
program = createProgram(rootFileNames, compilerOptions, compilerHost, program);
resolutionCache.finishCachingPerDirectoryResolution();
builder.onProgramUpdateGraph(program, hasInvalidatedResolution);
// Update watches
updateMissingFilePathsWatch(program, missingFilesMap || (missingFilesMap = createMap()), watchMissingFilePath);
if (needsUpdateInTypeRootWatch) {
resolutionCache.updateTypeRootsWatch();
}
if (missingFilePathsRequestedForRelease) {
// These are the paths that program creater told us as not in use any more but were missing on the disk.
// We didnt remove the entry for them from sourceFiles cache so that we dont have to do File IO,
// if there is already watcher for it (for missing files)
// At this point our watches were updated, hence now we know that these paths are not tracked and need to be removed
// so that at later time we have correct result of their presence
for (const missingFilePath of missingFilePathsRequestedForRelease) {
if (!missingFilesMap.has(missingFilePath)) {
sourceFilesCache.delete(missingFilePath);
}
}
missingFilePathsRequestedForRelease = undefined;
}
afterCompile(partialSystem, program, builder);
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
}
function toPath(fileName: string) {
return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName);
}
function fileExists(fileName: string) {
const path = toPath(fileName);
const hostSourceFileInfo = sourceFilesCache.get(path);
if (hostSourceFileInfo !== undefined) {
return !isString(hostSourceFileInfo);
}
return partialSystem.fileExists(fileName);
}
function directoryExists(directoryName: string) {
return partialSystem.directoryExists(directoryName);
}
function readFile(fileName: string) {
return system.readFile(fileName);
}
function trace(s: string) {
return system.write(s + newLine);
}
function getDirectories(path: string) {
return partialSystem.getDirectories(path);
}
function resolveModuleNames(moduleNames: string[], containingFile: string) {
return resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ false);
}
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) {
return resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
}
function getDefaultLibLocation(): string {
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
}
function getVersionedSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile {
return getVersionedSourceFileByPath(fileName, toPath(fileName), languageVersion, onError, shouldCreateNewSourceFile);
}
function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile {
const hostSourceFile = sourceFilesCache.get(path);
// No source file on the host
if (isString(hostSourceFile)) {
return undefined;
}
// Create new source file if requested or the versions dont match
if (!hostSourceFile || shouldCreateNewSourceFile || hostSourceFile.version.toString() !== hostSourceFile.sourceFile.version) {
const sourceFile = getNewSourceFile();
if (hostSourceFile) {
if (shouldCreateNewSourceFile) {
hostSourceFile.version++;
}
if (sourceFile) {
hostSourceFile.sourceFile = sourceFile;
sourceFile.version = hostSourceFile.version.toString();
if (!hostSourceFile.fileWatcher) {
hostSourceFile.fileWatcher = watchFilePath(system, fileName, onSourceFileChange, path, writeLog);
}
}
else {
// There is no source file on host any more, close the watch, missing file paths will track it
hostSourceFile.fileWatcher.close();
sourceFilesCache.set(path, hostSourceFile.version.toString());
}
}
else {
let fileWatcher: FileWatcher;
if (sourceFile) {
sourceFile.version = "0";
fileWatcher = watchFilePath(system, fileName, onSourceFileChange, path, writeLog);
sourceFilesCache.set(path, { sourceFile, version: 0, fileWatcher });
}
else {
sourceFilesCache.set(path, "0");
}
}
return sourceFile;
}
return hostSourceFile.sourceFile;
function getNewSourceFile() {
let text: string;
try {
performance.mark("beforeIORead");
text = system.readFile(fileName, compilerOptions.charset);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
catch (e) {
if (onError) {
onError(e.message);
}
}
return text !== undefined ? createSourceFile(fileName, text, languageVersion) : undefined;
}
}
function removeSourceFile(path: Path) {
const hostSourceFile = sourceFilesCache.get(path);
if (hostSourceFile !== undefined) {
if (!isString(hostSourceFile)) {
hostSourceFile.fileWatcher.close();
resolutionCache.invalidateResolutionOfFile(path);
}
sourceFilesCache.delete(path);
}
}
function getSourceVersion(path: Path): string {
const hostSourceFile = sourceFilesCache.get(path);
return !hostSourceFile || isString(hostSourceFile) ? undefined : hostSourceFile.version.toString();
}
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions) {
const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.path);
// If this is the source file thats in the cache and new program doesnt need it,
// remove the cached entry.
// Note we arent deleting entry if file became missing in new program or
// there was version update and new source file was created.
if (hostSourceFileInfo) {
// record the missing file paths so they can be removed later if watchers arent tracking them
if (isString(hostSourceFileInfo)) {
(missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path);
}
else if (hostSourceFileInfo.sourceFile === oldSourceFile) {
sourceFilesCache.delete(oldSourceFile.path);
resolutionCache.invalidateResolutionOfFile(oldSourceFile.path);
}
}
}
// Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch
// operations (such as saving all modified files in an editor) a chance to complete before we kick
// off a new compilation.
function scheduleProgramUpdate() {
if (!system.setTimeout || !system.clearTimeout) {
return;
}
if (timerToUpdateProgram) {
system.clearTimeout(timerToUpdateProgram);
}
timerToUpdateProgram = system.setTimeout(updateProgram, 250);
}
function scheduleProgramReload() {
Debug.assert(!!configFileName);
needsReload = true;
scheduleProgramUpdate();
}
function updateProgram() {
timerToUpdateProgram = undefined;
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
if (needsReload) {
reloadConfigFile();
}
else {
synchronizeProgram();
}
}
function reloadConfigFile() {
writeLog(`Reloading config file: ${configFileName}`);
needsReload = false;
const cachedHost = partialSystem as CachedPartialSystem;
cachedHost.clearCache();
const configParseResult = parseConfigFile(configFileName, optionsToExtendForConfigFile, cachedHost, reportDiagnostic, reportWatchDiagnostic);
rootFileNames = configParseResult.fileNames;
compilerOptions = configParseResult.options;
hasChangedCompilerOptions = true;
configFileSpecs = configParseResult.configFileSpecs;
configFileWildCardDirectories = configParseResult.wildcardDirectories;
synchronizeProgram();
// Update the wild card directory watch
watchConfigFileWildCardDirectories();
}
function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) {
updateCachedSystemWithFile(fileName, path, eventKind);
const hostSourceFile = sourceFilesCache.get(path);
if (hostSourceFile) {
// Update the cache
if (eventKind === FileWatcherEventKind.Deleted) {
resolutionCache.invalidateResolutionOfFile(path);
if (!isString(hostSourceFile)) {
hostSourceFile.fileWatcher.close();
sourceFilesCache.set(path, (hostSourceFile.version++).toString());
}
}
else {
// Deleted file created
if (isString(hostSourceFile)) {
sourceFilesCache.delete(path);
}
else {
// file changed - just update the version
hostSourceFile.version++;
}
}
}
// Update the program
scheduleProgramUpdate();
}
function updateCachedSystemWithFile(fileName: string, path: Path, eventKind: FileWatcherEventKind) {
if (configFileName) {
(partialSystem as CachedPartialSystem).addOrDeleteFile(fileName, path, eventKind);
}
}
function watchDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
return watchDirectoryWorker(system, directory, cb, flags, writeLog);
}
function onChangedAutomaticTypeDirectiveNames() {
changedAutomaticTypeDirectiveNames = true;
scheduleProgramUpdate();
}
function hasChangedAutomaticTypeDirectiveNames() {
return changedAutomaticTypeDirectiveNames;
}
function watchMissingFilePath(missingFilePath: Path) {
return watchFilePath(system, missingFilePath, onMissingFileChange, missingFilePath, writeLog);
}
function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) {
updateCachedSystemWithFile(fileName, missingFilePath, eventKind);
if (eventKind === FileWatcherEventKind.Created && missingFilesMap.has(missingFilePath)) {
missingFilesMap.get(missingFilePath).close();
missingFilesMap.delete(missingFilePath);
// Delete the entry in the source files cache so that new source file is created
removeSourceFile(missingFilePath);
// When a missing file is created, we should update the graph.
scheduleProgramUpdate();
}
}
function watchConfigFileWildCardDirectories() {
updateWatchingWildcardDirectories(
watchedWildcardDirectories || (watchedWildcardDirectories = createMap()),
createMapFromTemplate(configFileWildCardDirectories),
watchWildcardDirectory
);
}
function watchWildcardDirectory(directory: string, flags: WatchDirectoryFlags) {
return watchDirectory(
directory,
fileOrFolder => {
Debug.assert(!!configFileName);
const fileOrFolderPath = toPath(fileOrFolder);
// Since the file existance changed, update the sourceFiles cache
(partialSystem as CachedPartialSystem).addOrDeleteFileOrFolder(fileOrFolder, fileOrFolderPath);
removeSourceFile(fileOrFolderPath);
// If the the added or created file or folder is not supported file name, ignore the file
// But when watched directory is added/removed, we need to reload the file list
if (fileOrFolderPath !== directory && !isSupportedSourceFileName(fileOrFolder, compilerOptions)) {
writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrFolder}`);
return;
}
// Reload is pending, do the reload
if (!needsReload) {
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, partialSystem);
if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) {
reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
}
rootFileNames = result.fileNames;
// Schedule Update the program
scheduleProgramUpdate();
}
},
flags
);
}
function computeHash(data: string) {
return system.createHash ? system.createHash(data) : data;
}
}
}