• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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