1namespace ts { 2 export interface ReadBuildProgramHost { 3 useCaseSensitiveFileNames(): boolean; 4 getCurrentDirectory(): string; 5 readFile(fileName: string): string | undefined; 6 /*@internal*/ 7 getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined; 8 getLastCompiledProgram?(): Program; 9 } 10 export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadBuildProgramHost) { 11 const buildInfoPath = getTsBuildInfoEmitOutputFilePath(compilerOptions); 12 if (!buildInfoPath) return undefined; 13 let buildInfo; 14 if (host.getBuildInfo) { 15 // host provides buildinfo, get it from there. This allows host to cache it 16 buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions.configFilePath); 17 } 18 else { 19 const content = host.readFile(buildInfoPath); 20 if (!content) return undefined; 21 buildInfo = getBuildInfo(buildInfoPath, content); 22 } 23 if (!buildInfo || buildInfo.version !== version || !buildInfo.program) return undefined; 24 return createBuilderProgramUsingProgramBuildInfo(buildInfo.program, buildInfoPath, host); 25 } 26 27 export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost { 28 const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, system); 29 host.createHash = maybeBind(system, system.createHash); 30 host.disableUseFileVersionAsSignature = system.disableUseFileVersionAsSignature; 31 host.storeFilesChangingSignatureDuringEmit = system.storeFilesChangingSignatureDuringEmit; 32 setGetSourceFileAsHashVersioned(host); 33 changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName)); 34 return host; 35 } 36 37 export interface IncrementalProgramOptions<T extends BuilderProgram> { 38 rootNames: readonly string[]; 39 options: CompilerOptions; 40 configFileParsingDiagnostics?: readonly Diagnostic[]; 41 projectReferences?: readonly ProjectReference[]; 42 host?: CompilerHost; 43 createProgram?: CreateProgram<T>; 44 } 45 46 export function createIncrementalProgram<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>({ 47 rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram 48 }: IncrementalProgramOptions<T>): T { 49 host = host || createIncrementalCompilerHost(options); 50 createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram<T>; 51 const oldProgram = readBuilderProgram(options, host) as any as T; 52 return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); 53 } 54 55 export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions, errorCount?: number) => void; 56 /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ 57 export type CreateProgram<T extends BuilderProgram> = (rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[] | undefined) => T; 58 59 /** Host that has watch functionality used in --watch mode */ 60 export interface WatchHost { 61 /** If provided, called with Diagnostic message that informs about change in watch status */ 62 onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions, errorCount?: number): void; 63 64 /** Used to watch changes in source files, missing files needed to update the program or config file */ 65 watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; 66 /** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */ 67 watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; 68 /** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */ 69 setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; 70 /** If provided, will be used to reset existing delayed compilation */ 71 clearTimeout?(timeoutId: any): void; 72 } 73 export interface ProgramHost<T extends BuilderProgram> { 74 /** 75 * Used to create the program when need for program creation or recreation detected 76 */ 77 createProgram: CreateProgram<T>; 78 79 // Sub set of compiler host methods to read and generate new program 80 useCaseSensitiveFileNames(): boolean; 81 getNewLine(): string; 82 getCurrentDirectory(): string; 83 getDefaultLibFileName(options: CompilerOptions): string; 84 getDefaultLibLocation?(): string; 85 createHash?(data: string): string; 86 87 /** 88 * Use to check file presence for source files and 89 * if resolveModuleNames is not provided (complier is in charge of module resolution) then module files as well 90 */ 91 fileExists(path: string): boolean; 92 /** 93 * Use to read file text for source files and 94 * if resolveModuleNames is not provided (complier is in charge of module resolution) then module files as well 95 */ 96 readFile(path: string, encoding?: string): string | undefined; 97 98 /** If provided, used for module resolution as well as to handle directory structure */ 99 directoryExists?(path: string): boolean; 100 /** If provided, used in resolutions as well as handling directory structure */ 101 getDirectories?(path: string): string[]; 102 /** If provided, used to cache and handle directory structure modifications */ 103 readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; 104 105 /** Symbol links resolution */ 106 realpath?(path: string): string; 107 /** If provided would be used to write log about compilation */ 108 trace?(s: string): void; 109 /** If provided is used to get the environment variable */ 110 getEnvironmentVariable?(name: string): string | undefined; 111 112 /** If provided, used to resolve the module names, otherwise typescript's default module resolution */ 113 resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; 114 /** If provided, used to resolve type reference directives, otherwise typescript's default resolution */ 115 resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[]; 116 /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ 117 hasInvalidatedResolutions?(filePath: Path): boolean; 118 /** 119 * Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it 120 */ 121 getModuleResolutionCache?(): ModuleResolutionCache | undefined; 122 } 123 /** Internal interface used to wire emit through same host */ 124 125 /*@internal*/ 126 export interface ProgramHost<T extends BuilderProgram> { 127 // TODO: GH#18217 Optional methods are frequently asserted 128 createDirectory?(path: string): void; 129 writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void; 130 // For testing 131 disableUseFileVersionAsSignature?: boolean; 132 storeFilesChangingSignatureDuringEmit?: boolean; 133 now?(): Date; 134 } 135 136 export interface WatchCompilerHost<T extends BuilderProgram> extends ProgramHost<T>, WatchHost { 137 /** Instead of using output d.ts file from project reference, use its source file */ 138 useSourceOfProjectReferenceRedirect?(): boolean; 139 140 /** If provided, use this method to get parsed command lines for referenced projects */ 141 getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; 142 143 /** If provided, callback to invoke after every new program creation */ 144 afterProgramCreate?(program: T): void; 145 } 146 147 /** 148 * Host to create watch with root files and options 149 */ 150 export interface WatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram> extends WatchCompilerHost<T> { 151 /** root files to use to generate program */ 152 rootFiles: string[]; 153 154 /** Compiler options */ 155 options: CompilerOptions; 156 157 watchOptions?: WatchOptions; 158 159 /** Project References */ 160 projectReferences?: readonly ProjectReference[]; 161 } 162 163 /** 164 * Host to create watch with config file 165 */ 166 export interface WatchCompilerHostOfConfigFile<T extends BuilderProgram> extends WatchCompilerHost<T>, ConfigFileDiagnosticsReporter { 167 /** Name of the config file to compile */ 168 configFileName: string; 169 170 /** Options to extend */ 171 optionsToExtend?: CompilerOptions; 172 173 watchOptionsToExtend?: WatchOptions; 174 175 extraFileExtensions?: readonly FileExtensionInfo[] 176 177 /** 178 * Used to generate source file names from the config file and its include, exclude, files rules 179 * and also to cache the directory stucture 180 */ 181 readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; 182 } 183 184 /** 185 * Host to create watch with config file that is already parsed (from tsc) 186 */ 187 /*@internal*/ 188 export interface WatchCompilerHostOfConfigFile<T extends BuilderProgram> extends WatchCompilerHost<T> { 189 configFileParsingResult?: ParsedCommandLine; 190 extendedConfigCache?: Map<ExtendedConfigCacheEntry>; 191 } 192 193 export interface Watch<T> { 194 /** Synchronize with host and get updated program */ 195 getProgram(): T; 196 /** Gets the existing program without synchronizing with changes on host */ 197 /*@internal*/ 198 getCurrentProgram(): T; 199 /** Closes the watch */ 200 close(): void; 201 } 202 203 /** 204 * Creates the watch what generates program using the config file 205 */ 206 export interface WatchOfConfigFile<T> extends Watch<T> { 207 } 208 209 /** 210 * Creates the watch that generates program using the root files and compiler options 211 */ 212 export interface WatchOfFilesAndCompilerOptions<T> extends Watch<T> { 213 /** Updates the root files in the program, only if this is not config file compilation */ 214 updateRootFileNames(fileNames: string[]): void; 215 } 216 217 /** 218 * Create the watch compiler host for either configFile or fileNames and its options 219 */ 220 export function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, watchOptionsToExtend?: WatchOptions, extraFileExtensions?: readonly FileExtensionInfo[]): WatchCompilerHostOfConfigFile<T>; 221 export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: readonly ProjectReference[], watchOptions?: WatchOptions): WatchCompilerHostOfFilesAndCompilerOptions<T>; 222 export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferencesOrWatchOptionsToExtend?: readonly ProjectReference[] | WatchOptions, watchOptionsOrExtraFileExtensions?: WatchOptions | readonly FileExtensionInfo[]): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> { 223 if (isArray(rootFilesOrConfigFileName)) { 224 return createWatchCompilerHostOfFilesAndCompilerOptions({ 225 rootFiles: rootFilesOrConfigFileName, 226 options: options!, 227 watchOptions: watchOptionsOrExtraFileExtensions as WatchOptions, 228 projectReferences: projectReferencesOrWatchOptionsToExtend as readonly ProjectReference[], 229 system, 230 createProgram, 231 reportDiagnostic, 232 reportWatchStatus, 233 }); 234 } 235 else { 236 return createWatchCompilerHostOfConfigFile({ 237 configFileName: rootFilesOrConfigFileName, 238 optionsToExtend: options, 239 watchOptionsToExtend: projectReferencesOrWatchOptionsToExtend as WatchOptions, 240 extraFileExtensions: watchOptionsOrExtraFileExtensions as readonly FileExtensionInfo[], 241 system, 242 createProgram, 243 reportDiagnostic, 244 reportWatchStatus, 245 }); 246 } 247 } 248 249 interface ParsedConfig { 250 /** ParsedCommandLine for the config file if present */ 251 parsedCommandLine: ParsedCommandLine | undefined; 252 /** File watcher of the config file */ 253 watcher?: FileWatcher; 254 /** Wild card directories watched from this config file */ 255 watchedDirectories?: Map<WildcardDirectoryWatcher>; 256 /** Reload to be done for this config file */ 257 reloadLevel?: ConfigFileProgramReloadLevel.Partial | ConfigFileProgramReloadLevel.Full; 258 } 259 260 /** 261 * Creates the watch from the host for root files and compiler options 262 */ 263 export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T>): WatchOfFilesAndCompilerOptions<T>; 264 /** 265 * Creates the watch from the host for config file 266 */ 267 export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>; 268 export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T> & WatchCompilerHostOfConfigFile<T>): WatchOfFilesAndCompilerOptions<T> | WatchOfConfigFile<T> { 269 interface FilePresentOnHost { 270 version: string; 271 sourceFile: SourceFile; 272 fileWatcher: FileWatcher; 273 } 274 type FileMissingOnHost = false; 275 interface FilePresenceUnknownOnHost { 276 version: false; 277 fileWatcher?: FileWatcher; 278 } 279 type FileMayBePresentOnHost = FilePresentOnHost | FilePresenceUnknownOnHost; 280 type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost; 281 282 let builderProgram: T; 283 let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc 284 let missingFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the missing files 285 let watchedWildcardDirectories: ESMap<string, WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file 286 let timerToUpdateProgram: any; // timer callback to recompile the program 287 let timerToInvalidateFailedLookupResolutions: any; // timer callback to invalidate resolutions for changes in failed lookup locations 288 let parsedConfigs: ESMap<Path, ParsedConfig> | undefined; // Parsed commandline and watching cached for referenced projects 289 let sharedExtendedConfigFileWatchers: ESMap<Path, SharedExtendedConfigFileWatcher<Path>>; // Map of file watchers for extended files, shared between different referenced projects 290 let extendedConfigCache = host.extendedConfigCache; // Cache for extended config evaluation 291 let reportFileChangeDetectedOnCreateProgram = false; // True if synchronizeProgram should report "File change detected..." when a new program is created 292 293 const sourceFilesCache = new Map<string, HostFileInfo>(); // Cache that stores the source file and version info 294 let missingFilePathsRequestedForRelease: Path[] | undefined; // These paths are held temporarily so that we can remove the entry from source file cache if the file is not tracked by missing files 295 let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations 296 297 const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); 298 const currentDirectory = host.getCurrentDirectory(); 299 const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, watchOptionsToExtend, extraFileExtensions, createProgram } = host; 300 let { rootFiles: rootFileNames, options: compilerOptions, watchOptions, projectReferences } = host; 301 let wildcardDirectories: MapLike<WatchDirectoryFlags> | undefined; 302 let configFileParsingDiagnostics: Diagnostic[] | undefined; 303 let canConfigFileJsonReportNoInputFiles = false; 304 let hasChangedConfigFileParsingErrors = false; 305 306 const cachedDirectoryStructureHost = configFileName === undefined ? undefined : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); 307 const directoryStructureHost: DirectoryStructureHost = cachedDirectoryStructureHost || host; 308 const parseConfigFileHost = parseConfigHostFromCompilerHostLike(host, directoryStructureHost); 309 310 // From tsc we want to get already parsed result and hence check for rootFileNames 311 let newLine = updateNewLine(); 312 if (configFileName && host.configFileParsingResult) { 313 setConfigFileParsingResult(host.configFileParsingResult); 314 newLine = updateNewLine(); 315 } 316 reportWatchDiagnostic(Diagnostics.Starting_compilation_in_watch_mode); 317 if (configFileName && !host.configFileParsingResult) { 318 newLine = getNewLineCharacter(optionsToExtendForConfigFile, () => host.getNewLine()); 319 Debug.assert(!rootFileNames); 320 parseConfigFile(); 321 newLine = updateNewLine(); 322 } 323 324 const { watchFile, watchDirectory, writeLog } = createWatchFactory(host, compilerOptions); 325 const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames); 326 327 writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`); 328 let configFileWatcher: FileWatcher | undefined; 329 if (configFileName) { 330 configFileWatcher = watchFile(configFileName, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile); 331 } 332 333 const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as CompilerHost & ResolutionCacheHost; 334 setGetSourceFileAsHashVersioned(compilerHost); 335 // Members for CompilerHost 336 const getNewSourceFile = compilerHost.getSourceFile; 337 compilerHost.getSourceFile = (fileName, ...args) => getVersionedSourceFileByPath(fileName, toPath(fileName), ...args); 338 compilerHost.getSourceFileByPath = getVersionedSourceFileByPath; 339 compilerHost.getNewLine = () => newLine; 340 compilerHost.fileExists = fileExists; 341 compilerHost.onReleaseOldSourceFile = onReleaseOldSourceFile; 342 compilerHost.onReleaseParsedCommandLine = onReleaseParsedCommandLine; 343 // Members for ResolutionCacheHost 344 compilerHost.toPath = toPath; 345 compilerHost.getCompilationSettings = () => compilerOptions; 346 compilerHost.useSourceOfProjectReferenceRedirect = maybeBind(host, host.useSourceOfProjectReferenceRedirect); 347 compilerHost.watchDirectoryOfFailedLookupLocation = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.FailedLookupLocations); 348 compilerHost.watchAffectingFileLocation = (file, cb) => watchFile(file, cb, PollingInterval.High, watchOptions, WatchType.AffectingFileLocation); 349 compilerHost.watchTypeRootsDirectory = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.TypeRoots); 350 compilerHost.getCachedDirectoryStructureHost = () => cachedDirectoryStructureHost; 351 compilerHost.scheduleInvalidateResolutionsOfFailedLookupLocations = scheduleInvalidateResolutionsOfFailedLookupLocations; 352 compilerHost.onInvalidatedResolution = scheduleProgramUpdate; 353 compilerHost.onChangedAutomaticTypeDirectiveNames = scheduleProgramUpdate; 354 compilerHost.fileIsOpen = returnFalse; 355 compilerHost.getCurrentProgram = getCurrentProgram; 356 compilerHost.writeLog = writeLog; 357 compilerHost.getParsedCommandLine = getParsedCommandLine; 358 359 // Cache for the module resolution 360 const resolutionCache = createResolutionCache(compilerHost, 361 configFileName ? 362 getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) : 363 currentDirectory, 364 /*logChangesWhenResolvingModule*/ false 365 ); 366 // Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names 367 compilerHost.resolveModuleNames = host.resolveModuleNames ? 368 ((...args) => host.resolveModuleNames!(...args)) : 369 ((moduleNames, containingFile, reusedNames, redirectedReference, _options, sourceFile) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, sourceFile)); 370 compilerHost.resolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives ? 371 ((...args) => host.resolveTypeReferenceDirectives!(...args)) : 372 ((typeDirectiveNames, containingFile, redirectedReference, _options, containingFileMode) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference, containingFileMode)); 373 compilerHost.getModuleResolutionCache = host.resolveModuleNames ? 374 maybeBind(host, host.getModuleResolutionCache) : 375 (() => resolutionCache.getModuleResolutionCache()); 376 const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; 377 // All resolutions are invalid if user provided resolutions and didnt supply hasInvalidatedResolutions 378 const customHasInvalidatedResolutions = userProvidedResolution ? 379 maybeBind(host, host.hasInvalidatedResolutions) || returnTrue : 380 returnFalse; 381 382 builderProgram = readBuilderProgram(compilerOptions, compilerHost) as any as T; 383 synchronizeProgram(); 384 385 // Update the wild card directory watch 386 watchConfigFileWildCardDirectories(); 387 388 // Update extended config file watch 389 if (configFileName) updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); 390 391 return configFileName ? 392 { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } : 393 { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; 394 395 function close() { 396 clearInvalidateResolutionsOfFailedLookupLocations(); 397 resolutionCache.clear(); 398 clearMap(sourceFilesCache, value => { 399 if (value && value.fileWatcher) { 400 value.fileWatcher.close(); 401 value.fileWatcher = undefined; 402 } 403 }); 404 if (configFileWatcher) { 405 configFileWatcher.close(); 406 configFileWatcher = undefined; 407 } 408 extendedConfigCache?.clear(); 409 extendedConfigCache = undefined; 410 if (sharedExtendedConfigFileWatchers) { 411 clearMap(sharedExtendedConfigFileWatchers, closeFileWatcherOf); 412 sharedExtendedConfigFileWatchers = undefined!; 413 } 414 if (watchedWildcardDirectories) { 415 clearMap(watchedWildcardDirectories, closeFileWatcherOf); 416 watchedWildcardDirectories = undefined!; 417 } 418 if (missingFilesMap) { 419 clearMap(missingFilesMap, closeFileWatcher); 420 missingFilesMap = undefined!; 421 } 422 if (parsedConfigs) { 423 clearMap(parsedConfigs, config => { 424 config.watcher?.close(); 425 config.watcher = undefined; 426 if (config.watchedDirectories) clearMap(config.watchedDirectories, closeFileWatcherOf); 427 config.watchedDirectories = undefined; 428 }); 429 parsedConfigs = undefined; 430 } 431 } 432 433 function getCurrentBuilderProgram() { 434 return builderProgram; 435 } 436 437 function getCurrentProgram() { 438 return builderProgram && builderProgram.getProgramOrUndefined(); 439 } 440 441 function synchronizeProgram() { 442 writeLog(`Synchronizing program`); 443 clearInvalidateResolutionsOfFailedLookupLocations(); 444 445 const program = getCurrentBuilderProgram(); 446 if (hasChangedCompilerOptions) { 447 newLine = updateNewLine(); 448 if (program && changesAffectModuleResolution(program.getCompilerOptions(), compilerOptions)) { 449 resolutionCache.clear(); 450 } 451 } 452 453 const hasInvalidatedResolutions = resolutionCache.createHasInvalidatedResolutions(customHasInvalidatedResolutions); 454 const { 455 originalReadFile, originalFileExists, originalDirectoryExists, 456 originalCreateDirectory, originalWriteFile, readFileWithCache, 457 } = changeCompilerHostLikeToUseCache(compilerHost, toPath); 458 if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, path => getSourceVersion(path, readFileWithCache), fileName => compilerHost.fileExists(fileName), hasInvalidatedResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { 459 if (hasChangedConfigFileParsingErrors) { 460 if (reportFileChangeDetectedOnCreateProgram) { 461 reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation); 462 } 463 builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); 464 hasChangedConfigFileParsingErrors = false; 465 } 466 } 467 else { 468 if (reportFileChangeDetectedOnCreateProgram) { 469 reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation); 470 } 471 createNewProgram(hasInvalidatedResolutions); 472 } 473 474 reportFileChangeDetectedOnCreateProgram = false; 475 if (host.afterProgramCreate && program !== builderProgram) { 476 host.afterProgramCreate(builderProgram); 477 } 478 479 compilerHost.readFile = originalReadFile; 480 compilerHost.fileExists = originalFileExists; 481 compilerHost.directoryExists = originalDirectoryExists; 482 compilerHost.createDirectory = originalCreateDirectory; 483 compilerHost.writeFile = originalWriteFile!; 484 485 return builderProgram; 486 } 487 488 function createNewProgram(hasInvalidatedResolutions: HasInvalidatedResolutions) { 489 // Compile the program 490 writeLog("CreatingProgramWith::"); 491 writeLog(` roots: ${JSON.stringify(rootFileNames)}`); 492 writeLog(` options: ${JSON.stringify(compilerOptions)}`); 493 if (projectReferences) writeLog(` projectReferences: ${JSON.stringify(projectReferences)}`); 494 495 const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !getCurrentProgram(); 496 hasChangedCompilerOptions = false; 497 hasChangedConfigFileParsingErrors = false; 498 resolutionCache.startCachingPerDirectoryResolution(); 499 compilerHost.hasInvalidatedResolutions = hasInvalidatedResolutions; 500 compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; 501 const oldProgram = getCurrentProgram(); 502 builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); 503 resolutionCache.finishCachingPerDirectoryResolution(builderProgram.getProgram(), oldProgram); 504 505 // Update watches 506 updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = new Map()), watchMissingFilePath); 507 if (needsUpdateInTypeRootWatch) { 508 resolutionCache.updateTypeRootsWatch(); 509 } 510 511 if (missingFilePathsRequestedForRelease) { 512 // These are the paths that program creater told us as not in use any more but were missing on the disk. 513 // We didnt remove the entry for them from sourceFiles cache so that we dont have to do File IO, 514 // if there is already watcher for it (for missing files) 515 // At this point our watches were updated, hence now we know that these paths are not tracked and need to be removed 516 // so that at later time we have correct result of their presence 517 for (const missingFilePath of missingFilePathsRequestedForRelease) { 518 if (!missingFilesMap.has(missingFilePath)) { 519 sourceFilesCache.delete(missingFilePath); 520 } 521 } 522 missingFilePathsRequestedForRelease = undefined; 523 } 524 } 525 526 function updateRootFileNames(files: string[]) { 527 Debug.assert(!configFileName, "Cannot update root file names with config file watch mode"); 528 rootFileNames = files; 529 scheduleProgramUpdate(); 530 } 531 532 function updateNewLine() { 533 return getNewLineCharacter(compilerOptions || optionsToExtendForConfigFile, () => host.getNewLine()); 534 } 535 536 function toPath(fileName: string) { 537 return ts.toPath(fileName, currentDirectory, getCanonicalFileName); 538 } 539 540 function isFileMissingOnHost(hostSourceFile: HostFileInfo | undefined): hostSourceFile is FileMissingOnHost { 541 return typeof hostSourceFile === "boolean"; 542 } 543 544 function isFilePresenceUnknownOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresenceUnknownOnHost { 545 return typeof (hostSourceFile as FilePresenceUnknownOnHost).version === "boolean"; 546 } 547 548 function fileExists(fileName: string) { 549 const path = toPath(fileName); 550 // If file is missing on host from cache, we can definitely say file doesnt exist 551 // otherwise we need to ensure from the disk 552 if (isFileMissingOnHost(sourceFilesCache.get(path))) { 553 return false; 554 } 555 556 return directoryStructureHost.fileExists(fileName); 557 } 558 559 function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { 560 const hostSourceFile = sourceFilesCache.get(path); 561 // No source file on the host 562 if (isFileMissingOnHost(hostSourceFile)) { 563 return undefined; 564 } 565 566 // Create new source file if requested or the versions dont match 567 if (hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile)) { 568 const sourceFile = getNewSourceFile(fileName, languageVersionOrOptions, onError); 569 if (hostSourceFile) { 570 if (sourceFile) { 571 // Set the source file and create file watcher now that file was present on the disk 572 (hostSourceFile as FilePresentOnHost).sourceFile = sourceFile; 573 hostSourceFile.version = sourceFile.version; 574 if (!hostSourceFile.fileWatcher) { 575 hostSourceFile.fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); 576 } 577 } 578 else { 579 // There is no source file on host any more, close the watch, missing file paths will track it 580 if (hostSourceFile.fileWatcher) { 581 hostSourceFile.fileWatcher.close(); 582 } 583 sourceFilesCache.set(path, false); 584 } 585 } 586 else { 587 if (sourceFile) { 588 const fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); 589 sourceFilesCache.set(path, { sourceFile, version: sourceFile.version, fileWatcher }); 590 } 591 else { 592 sourceFilesCache.set(path, false); 593 } 594 } 595 return sourceFile; 596 } 597 return hostSourceFile.sourceFile; 598 } 599 600 function nextSourceFileVersion(path: Path) { 601 const hostSourceFile = sourceFilesCache.get(path); 602 if (hostSourceFile !== undefined) { 603 if (isFileMissingOnHost(hostSourceFile)) { 604 // The next version, lets set it as presence unknown file 605 sourceFilesCache.set(path, { version: false }); 606 } 607 else { 608 (hostSourceFile as FilePresenceUnknownOnHost).version = false; 609 } 610 } 611 } 612 613 function getSourceVersion(path: Path, readFileWithCache: (fileName: string) => string | undefined): string | undefined { 614 const hostSourceFile = sourceFilesCache.get(path); 615 if (!hostSourceFile) return undefined; 616 if (hostSourceFile.version) return hostSourceFile.version; 617 // Read file and get new version 618 const text = readFileWithCache(path); 619 return text !== undefined ? (compilerHost.createHash || generateDjb2Hash)(text) : undefined; 620 } 621 622 function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) { 623 const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.resolvedPath); 624 // If this is the source file thats in the cache and new program doesnt need it, 625 // remove the cached entry. 626 // Note we arent deleting entry if file became missing in new program or 627 // there was version update and new source file was created. 628 if (hostSourceFileInfo !== undefined) { 629 // record the missing file paths so they can be removed later if watchers arent tracking them 630 if (isFileMissingOnHost(hostSourceFileInfo)) { 631 (missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path); 632 } 633 else if ((hostSourceFileInfo as FilePresentOnHost).sourceFile === oldSourceFile) { 634 if (hostSourceFileInfo.fileWatcher) { 635 hostSourceFileInfo.fileWatcher.close(); 636 } 637 sourceFilesCache.delete(oldSourceFile.resolvedPath); 638 if (!hasSourceFileByPath) { 639 resolutionCache.removeResolutionsOfFile(oldSourceFile.path); 640 } 641 } 642 } 643 } 644 645 function reportWatchDiagnostic(message: DiagnosticMessage) { 646 if (host.onWatchStatusChange) { 647 host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions || optionsToExtendForConfigFile); 648 } 649 } 650 651 function hasChangedAutomaticTypeDirectiveNames() { 652 return resolutionCache.hasChangedAutomaticTypeDirectiveNames(); 653 } 654 655 function clearInvalidateResolutionsOfFailedLookupLocations() { 656 if (!timerToInvalidateFailedLookupResolutions) return false; 657 host.clearTimeout!(timerToInvalidateFailedLookupResolutions); 658 timerToInvalidateFailedLookupResolutions = undefined; 659 return true; 660 } 661 662 function scheduleInvalidateResolutionsOfFailedLookupLocations() { 663 if (!host.setTimeout || !host.clearTimeout) { 664 return resolutionCache.invalidateResolutionsOfFailedLookupLocations(); 665 } 666 const pending = clearInvalidateResolutionsOfFailedLookupLocations(); 667 writeLog(`Scheduling invalidateFailedLookup${pending ? ", Cancelled earlier one" : ""}`); 668 timerToInvalidateFailedLookupResolutions = host.setTimeout(invalidateResolutionsOfFailedLookup, 250); 669 } 670 671 function invalidateResolutionsOfFailedLookup() { 672 timerToInvalidateFailedLookupResolutions = undefined; 673 if (resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { 674 scheduleProgramUpdate(); 675 } 676 } 677 678 // Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch 679 // operations (such as saving all modified files in an editor) a chance to complete before we kick 680 // off a new compilation. 681 function scheduleProgramUpdate() { 682 if (!host.setTimeout || !host.clearTimeout) { 683 return; 684 } 685 686 if (timerToUpdateProgram) { 687 host.clearTimeout(timerToUpdateProgram); 688 } 689 writeLog("Scheduling update"); 690 timerToUpdateProgram = host.setTimeout(updateProgramWithWatchStatus, 250); 691 } 692 693 function scheduleProgramReload() { 694 Debug.assert(!!configFileName); 695 reloadLevel = ConfigFileProgramReloadLevel.Full; 696 scheduleProgramUpdate(); 697 } 698 699 function updateProgramWithWatchStatus() { 700 timerToUpdateProgram = undefined; 701 reportFileChangeDetectedOnCreateProgram = true; 702 updateProgram(); 703 } 704 705 function updateProgram() { 706 switch (reloadLevel) { 707 case ConfigFileProgramReloadLevel.Partial: 708 perfLogger.logStartUpdateProgram("PartialConfigReload"); 709 reloadFileNamesFromConfigFile(); 710 break; 711 case ConfigFileProgramReloadLevel.Full: 712 perfLogger.logStartUpdateProgram("FullConfigReload"); 713 reloadConfigFile(); 714 break; 715 default: 716 perfLogger.logStartUpdateProgram("SynchronizeProgram"); 717 synchronizeProgram(); 718 break; 719 } 720 perfLogger.logStopUpdateProgram("Done"); 721 return getCurrentBuilderProgram(); 722 } 723 724 function reloadFileNamesFromConfigFile() { 725 writeLog("Reloading new file names and options"); 726 reloadLevel = ConfigFileProgramReloadLevel.None; 727 rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions); 728 if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) { 729 hasChangedConfigFileParsingErrors = true; 730 } 731 732 // Update the program 733 synchronizeProgram(); 734 } 735 736 function reloadConfigFile() { 737 writeLog(`Reloading config file: ${configFileName}`); 738 reloadLevel = ConfigFileProgramReloadLevel.None; 739 740 if (cachedDirectoryStructureHost) { 741 cachedDirectoryStructureHost.clearCache(); 742 } 743 parseConfigFile(); 744 hasChangedCompilerOptions = true; 745 synchronizeProgram(); 746 747 // Update the wild card directory watch 748 watchConfigFileWildCardDirectories(); 749 750 // Update extended config file watch 751 updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); 752 } 753 754 function parseConfigFile() { 755 setConfigFileParsingResult(getParsedCommandLineOfConfigFile( 756 configFileName, 757 optionsToExtendForConfigFile, 758 parseConfigFileHost, 759 extendedConfigCache ||= new Map(), 760 watchOptionsToExtend, 761 extraFileExtensions 762 )!); // TODO: GH#18217 763 } 764 765 function setConfigFileParsingResult(configFileParseResult: ParsedCommandLine) { 766 rootFileNames = configFileParseResult.fileNames; 767 compilerOptions = configFileParseResult.options; 768 watchOptions = configFileParseResult.watchOptions; 769 projectReferences = configFileParseResult.projectReferences; 770 wildcardDirectories = configFileParseResult.wildcardDirectories; 771 configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult).slice(); 772 canConfigFileJsonReportNoInputFiles = canJsonReportNoInputFiles(configFileParseResult.raw); 773 hasChangedConfigFileParsingErrors = true; 774 } 775 776 function getParsedCommandLine(configFileName: string): ParsedCommandLine | undefined { 777 const configPath = toPath(configFileName); 778 let config = parsedConfigs?.get(configPath); 779 if (config) { 780 if (!config.reloadLevel) return config.parsedCommandLine; 781 // With host implementing getParsedCommandLine we cant just update file names 782 if (config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial && !host.getParsedCommandLine) { 783 writeLog("Reloading new file names and options"); 784 const fileNames = getFileNamesFromConfigSpecs( 785 config.parsedCommandLine.options.configFile!.configFileSpecs!, 786 getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), 787 compilerOptions, 788 parseConfigFileHost, 789 ); 790 config.parsedCommandLine = { ...config.parsedCommandLine, fileNames }; 791 config.reloadLevel = undefined; 792 return config.parsedCommandLine; 793 } 794 } 795 796 writeLog(`Loading config file: ${configFileName}`); 797 const parsedCommandLine = host.getParsedCommandLine ? 798 host.getParsedCommandLine(configFileName) : 799 getParsedCommandLineFromConfigFileHost(configFileName); 800 if (config) { 801 config.parsedCommandLine = parsedCommandLine; 802 config.reloadLevel = undefined; 803 } 804 else { 805 (parsedConfigs ||= new Map()).set(configPath, config = { parsedCommandLine }); 806 } 807 watchReferencedProject(configFileName, configPath, config); 808 return parsedCommandLine; 809 } 810 811 function getParsedCommandLineFromConfigFileHost(configFileName: string) { 812 // Ignore the file absent errors 813 const onUnRecoverableConfigFileDiagnostic = parseConfigFileHost.onUnRecoverableConfigFileDiagnostic; 814 parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop; 815 const parsedCommandLine = getParsedCommandLineOfConfigFile( 816 configFileName, 817 /*optionsToExtend*/ undefined, 818 parseConfigFileHost, 819 extendedConfigCache ||= new Map(), 820 watchOptionsToExtend 821 ); 822 parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = onUnRecoverableConfigFileDiagnostic; 823 return parsedCommandLine; 824 } 825 826 function onReleaseParsedCommandLine(fileName: string) { 827 const path = toPath(fileName); 828 const config = parsedConfigs?.get(path); 829 if (!config) return; 830 831 parsedConfigs!.delete(path); 832 if (config.watchedDirectories) clearMap(config.watchedDirectories, closeFileWatcherOf); 833 config.watcher?.close(); 834 clearSharedExtendedConfigFileWatcher(path, sharedExtendedConfigFileWatchers); 835 } 836 837 function watchFilePath( 838 path: Path, 839 file: string, 840 callback: (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void, 841 pollingInterval: PollingInterval, 842 options: WatchOptions | undefined, 843 watchType: WatchType 844 ): FileWatcher { 845 return watchFile(file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval, options, watchType); 846 } 847 848 function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) { 849 updateCachedSystemWithFile(fileName, path, eventKind); 850 851 // Update the source file cache 852 if (eventKind === FileWatcherEventKind.Deleted && sourceFilesCache.has(path)) { 853 resolutionCache.invalidateResolutionOfFile(path); 854 } 855 nextSourceFileVersion(path); 856 857 // Update the program 858 scheduleProgramUpdate(); 859 } 860 861 function updateCachedSystemWithFile(fileName: string, path: Path, eventKind: FileWatcherEventKind) { 862 if (cachedDirectoryStructureHost) { 863 cachedDirectoryStructureHost.addOrDeleteFile(fileName, path, eventKind); 864 } 865 } 866 867 function watchMissingFilePath(missingFilePath: Path) { 868 // If watching missing referenced config file, we are already watching it so no need for separate watcher 869 return parsedConfigs?.has(missingFilePath) ? 870 noopFileWatcher : 871 watchFilePath(missingFilePath, missingFilePath, onMissingFileChange, PollingInterval.Medium, watchOptions, WatchType.MissingFile); 872 } 873 874 function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) { 875 updateCachedSystemWithFile(fileName, missingFilePath, eventKind); 876 877 if (eventKind === FileWatcherEventKind.Created && missingFilesMap.has(missingFilePath)) { 878 missingFilesMap.get(missingFilePath)!.close(); 879 missingFilesMap.delete(missingFilePath); 880 881 // Delete the entry in the source files cache so that new source file is created 882 nextSourceFileVersion(missingFilePath); 883 884 // When a missing file is created, we should update the graph. 885 scheduleProgramUpdate(); 886 } 887 } 888 889 function watchConfigFileWildCardDirectories() { 890 if (wildcardDirectories) { 891 updateWatchingWildcardDirectories( 892 watchedWildcardDirectories || (watchedWildcardDirectories = new Map()), 893 new Map(getEntries(wildcardDirectories)), 894 watchWildcardDirectory 895 ); 896 } 897 else if (watchedWildcardDirectories) { 898 clearMap(watchedWildcardDirectories, closeFileWatcherOf); 899 } 900 } 901 902 function watchWildcardDirectory(directory: string, flags: WatchDirectoryFlags) { 903 return watchDirectory( 904 directory, 905 fileOrDirectory => { 906 Debug.assert(!!configFileName); 907 908 const fileOrDirectoryPath = toPath(fileOrDirectory); 909 910 // Since the file existence changed, update the sourceFiles cache 911 if (cachedDirectoryStructureHost) { 912 cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); 913 } 914 nextSourceFileVersion(fileOrDirectoryPath); 915 916 if (isIgnoredFileFromWildCardWatching({ 917 watchedDirPath: toPath(directory), 918 fileOrDirectory, 919 fileOrDirectoryPath, 920 configFileName, 921 extraFileExtensions, 922 options: compilerOptions, 923 program: getCurrentBuilderProgram() || rootFileNames, 924 currentDirectory, 925 useCaseSensitiveFileNames, 926 writeLog, 927 toPath, 928 })) return; 929 930 // Reload is pending, do the reload 931 if (reloadLevel !== ConfigFileProgramReloadLevel.Full) { 932 reloadLevel = ConfigFileProgramReloadLevel.Partial; 933 934 // Schedule Update the program 935 scheduleProgramUpdate(); 936 } 937 }, 938 flags, 939 watchOptions, 940 WatchType.WildcardDirectory 941 ); 942 } 943 944 function updateExtendedConfigFilesWatches(forProjectPath: Path, options: CompilerOptions | undefined, watchOptions: WatchOptions | undefined, watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"]) { 945 updateSharedExtendedConfigFileWatcher( 946 forProjectPath, 947 options, 948 sharedExtendedConfigFileWatchers ||= new Map(), 949 (extendedConfigFileName, extendedConfigFilePath) => watchFile( 950 extendedConfigFileName, 951 (_fileName, eventKind) => { 952 updateCachedSystemWithFile(extendedConfigFileName, extendedConfigFilePath, eventKind); 953 // Update extended config cache 954 if (extendedConfigCache) cleanExtendedConfigCache(extendedConfigCache, extendedConfigFilePath, toPath); 955 // Update projects 956 const projects = sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects; 957 // If there are no referenced projects this extended config file watcher depend on ignore 958 if (!projects?.size) return; 959 projects.forEach(projectPath => { 960 if (toPath(configFileName) === projectPath) { 961 // If this is the config file of the project, reload completely 962 reloadLevel = ConfigFileProgramReloadLevel.Full; 963 } 964 else { 965 // Reload config for the referenced projects and remove the resolutions from referenced projects since the config file changed 966 const config = parsedConfigs?.get(projectPath); 967 if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; 968 resolutionCache.removeResolutionsFromProjectReferenceRedirects(projectPath); 969 } 970 scheduleProgramUpdate(); 971 }); 972 }, 973 PollingInterval.High, 974 watchOptions, 975 watchType 976 ), 977 toPath, 978 ); 979 } 980 981 function watchReferencedProject(configFileName: string, configPath: Path, commandLine: ParsedConfig) { 982 // Watch file 983 commandLine.watcher ||= watchFile( 984 configFileName, 985 (_fileName, eventKind) => { 986 updateCachedSystemWithFile(configFileName, configPath, eventKind); 987 const config = parsedConfigs?.get(configPath); 988 if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; 989 resolutionCache.removeResolutionsFromProjectReferenceRedirects(configPath); 990 scheduleProgramUpdate(); 991 }, 992 PollingInterval.High, 993 commandLine.parsedCommandLine?.watchOptions || watchOptions, 994 WatchType.ConfigFileOfReferencedProject 995 ); 996 // Watch Wild card 997 if (commandLine.parsedCommandLine?.wildcardDirectories) { 998 updateWatchingWildcardDirectories( 999 commandLine.watchedDirectories ||= new Map(), 1000 new Map(getEntries(commandLine.parsedCommandLine?.wildcardDirectories)), 1001 (directory, flags) => watchDirectory( 1002 directory, 1003 fileOrDirectory => { 1004 const fileOrDirectoryPath = toPath(fileOrDirectory); 1005 // Since the file existence changed, update the sourceFiles cache 1006 if (cachedDirectoryStructureHost) { 1007 cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); 1008 } 1009 nextSourceFileVersion(fileOrDirectoryPath); 1010 1011 const config = parsedConfigs?.get(configPath); 1012 if (!config?.parsedCommandLine) return; 1013 if (isIgnoredFileFromWildCardWatching({ 1014 watchedDirPath: toPath(directory), 1015 fileOrDirectory, 1016 fileOrDirectoryPath, 1017 configFileName, 1018 options: config.parsedCommandLine.options, 1019 program: config.parsedCommandLine.fileNames, 1020 currentDirectory, 1021 useCaseSensitiveFileNames, 1022 writeLog, 1023 toPath, 1024 })) return; 1025 1026 // Reload is pending, do the reload 1027 if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { 1028 config.reloadLevel = ConfigFileProgramReloadLevel.Partial; 1029 1030 // Schedule Update the program 1031 scheduleProgramUpdate(); 1032 } 1033 }, 1034 flags, 1035 commandLine.parsedCommandLine?.watchOptions || watchOptions, 1036 WatchType.WildcardDirectoryOfReferencedProject 1037 ) 1038 ); 1039 } 1040 else if (commandLine.watchedDirectories) { 1041 clearMap(commandLine.watchedDirectories, closeFileWatcherOf); 1042 commandLine.watchedDirectories = undefined; 1043 } 1044 // Watch extended config files 1045 updateExtendedConfigFilesWatches( 1046 configPath, 1047 commandLine.parsedCommandLine?.options, 1048 commandLine.parsedCommandLine?.watchOptions || watchOptions, 1049 WatchType.ExtendedConfigOfReferencedProject 1050 ); 1051 } 1052 } 1053} 1054