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